From 2caada664a16b50b4cdbb4ce423419e0751c8368 Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 18 May 2022 23:41:40 -0700 Subject: [PATCH 1/5] Bump `go.bug.st/relaxed-semver` to v0.9.0 At the time the dependency on `go.bug.st/relaxed-semver` was added to the project, there was not a release version available, so it was necessary to use a "pseudo-version" instead. Since that time, the first release of `go.bug.st/relaxed-semver`, offering the opportunity for more effective management of the dependency: - Greater stability through the use of release versions - Automated update offers from Dependabot The relevant changes made to `go.bug.st/relaxed-semver` in the interim have been the expansion of the version constraints syntax, so it will be important for Arduino Lint to use the same version as `arduino/libraries-repository-engine` and Arduino CLI in order to correctly lint the constraints syntax used in the library.properties `depends` field. --- .licenses/go/go.bug.st/relaxed-semver.dep.yml | 4 ++-- docsgen/go.mod | 2 +- docsgen/go.sum | 3 ++- go.mod | 2 +- go.sum | 3 ++- ruledocsgen/go.mod | 2 +- ruledocsgen/go.sum | 3 ++- 7 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.licenses/go/go.bug.st/relaxed-semver.dep.yml b/.licenses/go/go.bug.st/relaxed-semver.dep.yml index c4767621..bc044af9 100644 --- a/.licenses/go/go.bug.st/relaxed-semver.dep.yml +++ b/.licenses/go/go.bug.st/relaxed-semver.dep.yml @@ -1,6 +1,6 @@ --- name: go.bug.st/relaxed-semver -version: v0.0.0-20190922224835-391e10178d18 +version: v0.9.0 type: go summary: homepage: https://pkg.go.dev/go.bug.st/relaxed-semver @@ -9,7 +9,7 @@ licenses: - sources: LICENSE text: |2+ - Copyright (c) 2018, Cristian Maglie. + Copyright (c) 2018-2022, Cristian Maglie. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/docsgen/go.mod b/docsgen/go.mod index 1f1c70bc..da9eb61c 100644 --- a/docsgen/go.mod +++ b/docsgen/go.mod @@ -76,7 +76,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect go.bug.st/cleanup v1.0.0 // indirect go.bug.st/downloader/v2 v2.1.0 // indirect - go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 // indirect + go.bug.st/relaxed-semver v0.9.0 // indirect go.opentelemetry.io/contrib v0.20.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.20.0 // indirect go.opentelemetry.io/otel v0.20.0 // indirect diff --git a/docsgen/go.sum b/docsgen/go.sum index 09509be8..1798370b 100644 --- a/docsgen/go.sum +++ b/docsgen/go.sum @@ -1248,8 +1248,9 @@ go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.0 h1:VqGOrJrjgz8c0c8ExvF9dvvcpcrbo2IrI+rOoXKD6nQ= go.bug.st/downloader/v2 v2.1.0/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98= go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0 h1:qt0T8W70VCurvsbxRK25fQwiTOFjkzwC/fDOpyPnchQ= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= diff --git a/go.mod b/go.mod index b9578604..ab876b98 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/stretchr/testify v1.7.1 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 - go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 + go.bug.st/relaxed-semver v0.9.0 ) require ( diff --git a/go.sum b/go.sum index 633f732a..00f12ba1 100644 --- a/go.sum +++ b/go.sum @@ -1278,8 +1278,9 @@ go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.0 h1:VqGOrJrjgz8c0c8ExvF9dvvcpcrbo2IrI+rOoXKD6nQ= go.bug.st/downloader/v2 v2.1.0/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98= go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0 h1:qt0T8W70VCurvsbxRK25fQwiTOFjkzwC/fDOpyPnchQ= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= diff --git a/ruledocsgen/go.mod b/ruledocsgen/go.mod index d58d334b..550deefd 100644 --- a/ruledocsgen/go.mod +++ b/ruledocsgen/go.mod @@ -72,7 +72,7 @@ require ( github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect go.bug.st/cleanup v1.0.0 // indirect go.bug.st/downloader/v2 v2.1.0 // indirect - go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 // indirect + go.bug.st/relaxed-semver v0.9.0 // indirect go.opentelemetry.io/contrib v0.20.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.20.0 // indirect go.opentelemetry.io/otel v0.20.0 // indirect diff --git a/ruledocsgen/go.sum b/ruledocsgen/go.sum index 27922ae4..b1bb73f0 100644 --- a/ruledocsgen/go.sum +++ b/ruledocsgen/go.sum @@ -1252,8 +1252,9 @@ go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= go.bug.st/cleanup v1.0.0/go.mod h1:EqVmTg2IBk4znLbPD28xne3abjsJftMdqqJEjhn70bk= go.bug.st/downloader/v2 v2.1.0 h1:VqGOrJrjgz8c0c8ExvF9dvvcpcrbo2IrI+rOoXKD6nQ= go.bug.st/downloader/v2 v2.1.0/go.mod h1:VZW2V1iGKV8rJL2ZEGIDzzBeKowYv34AedJz13RzVII= -go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18 h1:F1qxtaFuewctYc/SsHRn+Q7Dtwi+yJGPgVq8YLtQz98= go.bug.st/relaxed-semver v0.0.0-20190922224835-391e10178d18/go.mod h1:Cx1VqMtEhE9pIkEyUj3LVVVPkv89dgW8aCKrRPDR/uE= +go.bug.st/relaxed-semver v0.9.0 h1:qt0T8W70VCurvsbxRK25fQwiTOFjkzwC/fDOpyPnchQ= +go.bug.st/relaxed-semver v0.9.0/go.mod h1:ug0/W/RPYUjliE70Ghxg77RDHmPxqpo7SHV16ijss7Q= go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY= go.bug.st/serial.v1 v0.0.0-20180827123349-5f7892a7bb45/go.mod h1:dRSl/CVCTf56CkXgJMDOdSwNfo2g1orOGE/gBGdvjZw= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= From 10dd6a22fddf9dee44dcbd5de48d67cad0af0e78 Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 25 May 2022 20:17:45 -0700 Subject: [PATCH 2/5] Move library.properties `depends` field parsing code to utility function This will allow the code to be shared by additional rule functions which need this data. --- internal/rule/rulefunction/library.go | 74 ++++++++++++++++++--------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index 6c9beff9..25b1778a 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -1201,37 +1201,21 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s return ruleresult.Skip, "Field not present" } - dependsList := commaSeparatedToList(depends) + dependencies := libDependencies(depends) - var dependencyRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$") dependsNotInIndex := []string{} - for _, depend := range dependsList { - // Process raw depend string into a dependency object - if depend == "" { + for _, dependency := range dependencies { + if dependency.parseConstraintErr != nil { // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() continue } - dependencyData := dependencyRegexp.FindAllStringSubmatch(depend, -1) - if dependencyData == nil { - // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() - continue - } - dependencyConstraint, err := semver.ParseConstraint(dependencyData[0][2]) - if err != nil { - // This is the responsibility of LibraryPropertiesDependsFieldInvalidFormat() - continue - } - var dependency semver.Dependency = &librariesindex.Dependency{ - Name: dependencyData[0][1], - VersionConstraint: dependencyConstraint, - } - logrus.Tracef("Checking if dependency %s is in index.", depend) + logrus.Tracef("Checking if dependency %s is in index.", dependency.depend) // Get all releases of the dependency - library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: dependency.GetName()}) + library := projectdata.LibraryManagerIndex().Index.FindIndexedLibrary(&libraries.Library{Name: dependency.data.GetName()}) if library == nil { logrus.Tracef("Dependency is not in the index.") - dependsNotInIndex = append(dependsNotInIndex, depend) + dependsNotInIndex = append(dependsNotInIndex, dependency.depend) continue } // Convert the dependency's libraries.Library object to a semver.Releases object @@ -1240,10 +1224,10 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s releases = append(releases, release) } // Filter the dependency's releases according to the dependency's constraint - dependencyReleases := releases.FilterBy(dependency) + dependencyReleases := releases.FilterBy(&dependency.data) if len(dependencyReleases) == 0 { logrus.Tracef("No releases match dependency's constraint.") - dependsNotInIndex = append(dependsNotInIndex, depend) + dependsNotInIndex = append(dependsNotInIndex, dependency.depend) continue } } @@ -1552,3 +1536,45 @@ func commaSeparatedToList(commaSeparated string) []string { return list } + +// libDependency is a library dependency +type libDependency struct { + depend string // Raw element from depends field. + data librariesindex.Dependency // Dependency object. + parseConstraintErr error // Error produced by parsing the version constraint. +} + +var dependRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$") + +// libDependencies parses the library.properties `depends` field contents and returns an array of libDependency objects +func libDependencies(depends string) []libDependency { + dependList := commaSeparatedToList(depends) + + dependencies := []libDependency{} + for _, depend := range dependList { + // Process raw depend string into a dependency object + if depend == "" { + // This function is only concerned with the parseable depend elements. + // `depends` field data format is checked separately. + continue + } + dependencyData := dependRegexp.FindAllStringSubmatch(depend, -1) + if dependencyData == nil { + // This function is only concerned with the parseable depend elements. + // `depends` field data format is checked separately. + continue + } + dependencyConstraint, err := semver.ParseConstraint(dependencyData[0][2]) + dependencies = append(dependencies, libDependency{ + depend: depend, + data: librariesindex.Dependency{ + Name: dependencyData[0][1], + VersionConstraint: dependencyConstraint, + }, + parseConstraintErr: err, + }, + ) + } + + return dependencies +} From 1db094180aca62dcf03d37ab7533f1e4dda4bf50 Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 25 May 2022 21:40:18 -0700 Subject: [PATCH 3/5] Correct regular expression used to parse library.properties `depends` field elements Empty version constraints are supported by the Arduino library system (they match any version). Previously, the regular expression used to split the library name from the version constraint caused these empty constraints to incorrectly be considered invalid. --- internal/rule/rulefunction/library.go | 2 +- .../testdata/libraries/DependsIndexed/library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index 25b1778a..826bfa4f 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -1544,7 +1544,7 @@ type libDependency struct { parseConstraintErr error // Error produced by parsing the version constraint. } -var dependRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.+)\\))?$") +var dependRegexp = regexp.MustCompile("^([^()]+?) *(?:\\((.*)\\))?$") // libDependencies parses the library.properties `depends` field contents and returns an array of libDependency objects func libDependencies(depends string) []libDependency { diff --git a/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties index 06d2811f..52b9df86 100644 --- a/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties +++ b/internal/rule/rulefunction/testdata/libraries/DependsIndexed/library.properties @@ -7,4 +7,4 @@ paragraph=Supports HTTP1.1 and you can do GET and POST. category=Communication url=http://example.com/ architectures=avr -depends=,(foo),foo (bar),Adafruit NeoPixel,Servo (<1.1.4),Stepper (<=1.1.3),Mouse (=1.0.0),Keyboard (>=1.0.1),WiFiNINA (>1.0.0) +depends=,(foo),foo (bar),Adafruit NeoPixel,Servo (<1.1.4),Stepper (<=1.1.3),Mouse (=1.0.0),Keyboard (>=1.0.1),WiFiNINA (>1.0.0),Ethernet () From a915ba88730d928992f6251fd550ec208228aee8 Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 25 May 2022 20:31:42 -0700 Subject: [PATCH 4/5] Add rule for constraint syntax in library.properties `depends` field Arduino CLI and the Library Manager system have support for specifying version constraints in the library.properties `depends` field. This was previously validated as part of the general `depends` field data format check in LP047. The constraint system has recently been made much more capable through the addition of support for more syntax. The previous approach for validating the version constraint was a complex and lengthy regular expression in the library.properties JSON schema. Extending this to comprehensively validate the full range of constraint forms possible with the new syntax will not be feasible or maintainable. The new approach is to validate it using the same `go.bug.st/relaxed-semver` module used by Arduino CLI and `arduino/libraries-repository-engine` to handle the version constraints in this field. --- .../ruleconfiguration/ruleconfiguration.go | 17 +++++++++++ internal/rule/rulefunction/library.go | 28 +++++++++++++++++++ internal/rule/rulefunction/library_test.go | 14 ++++++++++ .../library.properties | 11 ++++++++ .../src/DependsConstraintInvalid.h | 0 .../DependsConstraintValid/library.properties | 11 ++++++++ .../src/DependsConstraintValid.h | 0 7 files changed, 81 insertions(+) create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/library.properties create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/src/DependsConstraintInvalid.h create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/library.properties create mode 100644 internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/src/DependsConstraintValid.h diff --git a/internal/rule/ruleconfiguration/ruleconfiguration.go b/internal/rule/ruleconfiguration/ruleconfiguration.go index e5099e7e..0df9b8bc 100644 --- a/internal/rule/ruleconfiguration/ruleconfiguration.go +++ b/internal/rule/ruleconfiguration/ruleconfiguration.go @@ -1113,6 +1113,23 @@ var configurations = []Type{ ErrorModes: nil, RuleFunction: rulefunction.LibraryPropertiesDependsFieldNotInIndex, }, + { + ProjectType: projecttype.Library, + SuperprojectType: projecttype.All, + Category: "library.properties", + Subcategory: "depends field", + ID: "LP058", + Brief: "invalid depends constraint syntax", + Description: "The `depends` field in the library's `library.properties` metadata file uses invalid version constraint syntax.", + MessageTemplate: "library.properties depends field item(s) {{.}} have invalid constraint syntax.", + Reference: "https://arduino.github.io/arduino-cli/latest/library-specification/#libraryproperties-file-format", + DisableModes: nil, + EnableModes: []rulemode.Type{rulemode.Default}, + InfoModes: nil, + WarningModes: nil, + ErrorModes: []rulemode.Type{rulemode.Default}, + RuleFunction: rulefunction.LibraryPropertiesDependsFieldConstraintInvalid, + }, { ProjectType: projecttype.Library, SuperprojectType: projecttype.All, diff --git a/internal/rule/rulefunction/library.go b/internal/rule/rulefunction/library.go index 826bfa4f..d57f9ef9 100644 --- a/internal/rule/rulefunction/library.go +++ b/internal/rule/rulefunction/library.go @@ -1239,6 +1239,34 @@ func LibraryPropertiesDependsFieldNotInIndex() (result ruleresult.Type, output s return ruleresult.Pass, "" } +// LibraryPropertiesDependsFieldConstraintInvalid checks whether the syntax of the version constraints in the +// library.properties `depends` field is valid. +func LibraryPropertiesDependsFieldConstraintInvalid() (result ruleresult.Type, output string) { + if projectdata.LibraryPropertiesLoadError() != nil { + return ruleresult.NotRun, "Couldn't load library.properties" + } + + depends, hasDepends := projectdata.LibraryProperties().GetOk("depends") + if !hasDepends { + return ruleresult.Skip, "Field not present" + } + + dependencies := libDependencies(depends) + + nonCompliant := []string{} + for _, dependency := range dependencies { + if dependency.parseConstraintErr != nil { + nonCompliant = append(nonCompliant, dependency.depend) + } + } + + if len(nonCompliant) > 0 { + return ruleresult.Fail, strings.Join(nonCompliant, ", ") + } + + return ruleresult.Pass, "" +} + // LibraryPropertiesDotALinkageFieldInvalid checks for invalid value in the library.properties "dot_a_linkage" field. func LibraryPropertiesDotALinkageFieldInvalid() (result ruleresult.Type, output string) { if projectdata.LibraryPropertiesLoadError() != nil { diff --git a/internal/rule/rulefunction/library_test.go b/internal/rule/rulefunction/library_test.go index b4199004..2b5b35f2 100644 --- a/internal/rule/rulefunction/library_test.go +++ b/internal/rule/rulefunction/library_test.go @@ -846,6 +846,20 @@ func TestLibraryPropertiesDependsFieldNotInIndex(t *testing.T) { checkLibraryRuleFunction(LibraryPropertiesDependsFieldNotInIndex, testTables, t) } +func TestLibraryPropertiesDependsFieldConstraintInvalid(t *testing.T) { + testTables := []libraryRuleFunctionTestTable{ + {"Unable to load", "InvalidLibraryProperties", ruleresult.NotRun, ""}, + {"Legacy", "Legacy", ruleresult.Skip, ""}, + {"No depends field", "NoDepends", ruleresult.Skip, ""}, + {"Depends field empty", "DependsEmpty", ruleresult.Pass, ""}, + {"Invalid depends field format", "DependsHasBadChars", ruleresult.Pass, ""}, + {"Invalid constraint syntax", "DependsConstraintInvalid", ruleresult.Fail, "^BarLib \\(nope\\), QuxLib \\(huh\\)$"}, + {"Valid constraint syntax", "DependsConstraintValid", ruleresult.Pass, ""}, + } + + checkLibraryRuleFunction(LibraryPropertiesDependsFieldConstraintInvalid, testTables, t) +} + func TestLibraryPropertiesDotALinkageFieldInvalid(t *testing.T) { testTables := []libraryRuleFunctionTestTable{ {"Invalid", "InvalidLibraryProperties", ruleresult.NotRun, ""}, diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/library.properties new file mode 100644 index 00000000..aa5769a4 --- /dev/null +++ b/internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/library.properties @@ -0,0 +1,11 @@ +name=DependsConstraintInvalid +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr +depends=FooLib (=0.0.1),BarLib (nope),BazLib (=1.2.3),QuxLib (huh) +includes=DependsConstraintInvalid.h diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/src/DependsConstraintInvalid.h b/internal/rule/rulefunction/testdata/libraries/DependsConstraintInvalid/src/DependsConstraintInvalid.h new file mode 100644 index 00000000..e69de29b diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/library.properties b/internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/library.properties new file mode 100644 index 00000000..4cef825b --- /dev/null +++ b/internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/library.properties @@ -0,0 +1,11 @@ +name=DependsConstraintValid +version=1.0.0 +author=Cristian Maglie , Pippo Pluto +maintainer=Cristian Maglie +sentence=A library that makes coding a web server a breeze. +paragraph=Supports HTTP1.1 and you can do GET and POST. +category=Communication +url=http://example.com/ +architectures=avr +depends=LibA (=0.0.1),LibB (>1.0.0),LibC (>=1.0.0),LibD (<2.0.0),LibE (<=2.0.0),LibF (!=1.0.0),LibG (<1.0.0 || >2.0.0),LibH ((>0.1.0 && <2.0.0) || >2.1.0),LibI (),LibJ +includes=DependsConstraintValid.h diff --git a/internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/src/DependsConstraintValid.h b/internal/rule/rulefunction/testdata/libraries/DependsConstraintValid/src/DependsConstraintValid.h new file mode 100644 index 00000000..e69de29b From 264f66accbdb0e808dafe68aa44ca62591838f4c Mon Sep 17 00:00:00 2001 From: per1234 Date: Wed, 25 May 2022 22:09:24 -0700 Subject: [PATCH 5/5] Remove outdated constraint validation from depends field pattern in library.properties schema A regular expression is employed in the library.properties JSON schemas to validate the format of the contents of the depends field. Previously, this regular expression was configured to validate the syntax of the optional version constraint. The constraint system has recently been made much more capable through the addition of support for more syntax. The regular expression did not have support for that syntax, which caused valid data to fail validation. Expanding the already complex and lengthy regular expression to comprehensively validate the full range of constraint forms possible with the new syntax would not be feasible or maintainable. The new approach is to validate it directly via Go code using the same `go.bug.st/relaxed-semver` module used by Arduino CLI and `arduino/libraries-repository-engine` to handle the version constraints in this field. The schema will continue to provide a general validation on the `depends` field format. --- ...rduino-library-properties-definitions-schema.json | 4 ++-- .../librarypropertiesschemas_test.go | 12 ++++++++---- internal/rule/schema/schemadata/bindata.go | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/etc/schemas/arduino-library-properties-definitions-schema.json b/etc/schemas/arduino-library-properties-definitions-schema.json index 3510e6a7..b7238e50 100644 --- a/etc/schemas/arduino-library-properties-definitions-schema.json +++ b/etc/schemas/arduino-library-properties-definitions-schema.json @@ -493,8 +493,8 @@ "type": "string" }, { - "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters and general-definitions-schema.json#/definitions/patternObjects/relaxedSemver", - "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$" + "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters", + "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\(.*\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\(.*\\) *)?))?$" } ] } diff --git a/internal/project/library/libraryproperties/librarypropertiesschemas_test.go b/internal/project/library/libraryproperties/librarypropertiesschemas_test.go index d6d7aaa4..96b69951 100644 --- a/internal/project/library/libraryproperties/librarypropertiesschemas_test.go +++ b/internal/project/library/libraryproperties/librarypropertiesschemas_test.go @@ -390,10 +390,6 @@ func TestPropertiesDependsPattern(t *testing.T) { {"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Specification, assert.False}, {"Pre-release version", "foo (=1.2.3-rc1)", compliancelevel.Strict, assert.False}, - {"Invalid version", "foo (bar)", compliancelevel.Permissive, assert.True}, - {"Invalid version", "foo (bar)", compliancelevel.Specification, assert.True}, - {"Invalid version", "foo (bar)", compliancelevel.Strict, assert.True}, - {"Version w/o space", "foo(>1.2.3)", compliancelevel.Permissive, assert.True}, {"Version w/o space", "foo(>1.2.3)", compliancelevel.Specification, assert.True}, {"Version w/o space", "foo(>1.2.3)", compliancelevel.Strict, assert.True}, @@ -401,6 +397,14 @@ func TestPropertiesDependsPattern(t *testing.T) { {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Permissive, assert.False}, {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Specification, assert.False}, {"Names w/ version", "foo (<=1.2.3),bar", compliancelevel.Strict, assert.False}, + + {"Names w/ parenthesized version constraints", "foo ((>0.1.0 && <2.0.0) || >2.1.0),bar", compliancelevel.Permissive, assert.False}, + {"Names w/ parenthesized version constraints", "foo ((>0.1.0 && <2.0.0) || >2.1.0),bar", compliancelevel.Specification, assert.False}, + {"Names w/ parenthesized version constraints", "foo ((>0.1.0 && <2.0.0) || >2.1.0),bar", compliancelevel.Strict, assert.False}, + + {"Names w/ empty version constraint", "foo (),bar", compliancelevel.Permissive, assert.False}, + {"Names w/ empty version constraint", "foo (),bar", compliancelevel.Specification, assert.False}, + {"Names w/ empty version constraint", "foo (),bar", compliancelevel.Strict, assert.False}, } checkPropertyPatternMismatch("depends", testTables, t) diff --git a/internal/rule/schema/schemadata/bindata.go b/internal/rule/schema/schemadata/bindata.go index 51bbf517..9281a852 100644 --- a/internal/rule/schema/schemadata/bindata.go +++ b/internal/rule/schema/schemadata/bindata.go @@ -1911,8 +1911,8 @@ var _arduinoLibraryPropertiesDefinitionsSchemaJson = []byte(`{ "type": "string" }, { - "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters and general-definitions-schema.json#/definitions/patternObjects/relaxedSemver", - "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\( *(<|<=|=|>=|>)(0|[1-9]\\d*)(\\.(0|[1-9]\\d*))?(\\.(0|[1-9]\\d*))?(-((0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*))? *\\) *)?))?$" + "$comment": "Based on #/definitions/propertiesObjects/name/base/definitions/patternObjects/allowedCharacters", + "pattern": "^((((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\(.*\\) *)?), *)*((([a-zA-Z][a-zA-Z0-9 _.\\-]*)|([0-9][a-zA-Z0-9 _.\\-]*[a-zA-Z][a-zA-Z0-9 _.\\-]*))+( \\(.*\\) *)?))?$" } ] }