Skip to content

Commit d6bcc38

Browse files
committed
linter/rules: add version-streamed-runtime-dependencies
Adds version-streamed-runtime-dependencies rule to check that given runtime dependencies are using the version-streamed subpackages rather than 'provides:'. Signed-off-by: Dentrax <furkan.turkal@chainguard.dev>
1 parent ffb7f8d commit d6bcc38

3 files changed

Lines changed: 106 additions & 0 deletions

File tree

pkg/lint/rules.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ var (
2727
// Be stricter than Go to promote consistency and avoid homograph attacks
2828
reValidHostname = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]+\.[a-z]{2,6}$`)
2929

30+
// This regex captures a string that ends with a semantic version (semver) suffix.
31+
// It returns two groups:
32+
// - Group 1: The prefix part of the string before the semver.
33+
// - Group 2: The semver (major.minor or major.minor.patch).
34+
// If there is no semver suffix, the string will not match.
35+
reVersionStream = regexp.MustCompile(`^(.*?)-(\d+\.\d+(?:\.\d+)?)$`)
36+
3037
forbiddenRepositories = []string{
3138
"https://packages.wolfi.dev/os",
3239
}
@@ -468,6 +475,37 @@ var AllRules = func(l *Linter) Rules { //nolint:gocyclo
468475
return err
469476
},
470477
},
478+
{
479+
Name: "version-streamed-runtime-dependencies",
480+
Description: "version-streamed packages must provide versioned runtime dependencies of its subpackage names instead of 'provides'",
481+
Severity: SeverityError,
482+
LintFunc: func(c config.Configuration) error {
483+
if !reVersionStream.MatchString(c.Package.Name) {
484+
return nil
485+
}
486+
providesSet := make(map[string]struct{})
487+
for _, subpkg := range c.Subpackages {
488+
for _, prov := range subpkg.Dependencies.Provides {
489+
namePart := strings.SplitN(prov, "=", 2)[0]
490+
providesSet[namePart] = struct{}{}
491+
}
492+
}
493+
var invalid []string
494+
for _, dep := range c.Package.Dependencies.Runtime {
495+
// Skip cases where the provides: might be like: ${{package.name}}-foo=${{package.full-version}}
496+
if strings.Contains(dep, c.Package.Name) {
497+
continue
498+
}
499+
if _, ok := providesSet[dep]; ok {
500+
invalid = append(invalid, dep)
501+
}
502+
}
503+
if len(invalid) > 0 {
504+
return fmt.Errorf("version-streamed package must use versioned runtime dependencies for its subpackages: %s", strings.Join(invalid, ", "))
505+
}
506+
return nil
507+
},
508+
},
471509
}
472510
}
473511

pkg/lint/rules_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,42 @@ func TestLinter_Rules(t *testing.T) {
451451
wantErr: false,
452452
matches: 1,
453453
},
454+
{
455+
file: "version-streamed-package-invalid-runtime-dependencies-1.2.yaml",
456+
minSeverity: SeverityWarning,
457+
want: EvalResult{
458+
File: "version-streamed-package-invalid-runtime-dependencies-1.2",
459+
Errors: EvalRuleErrors{
460+
{
461+
Rule: Rule{
462+
Name: "version-streamed-runtime-dependencies",
463+
Severity: SeverityError,
464+
},
465+
Error: fmt.Errorf("[version-streamed-runtime-dependencies]: version-streamed package must use versioned runtime dependencies for its subpackages: version-streamed-package-invalid-runtime-dependencies-foo (ERROR)"),
466+
},
467+
},
468+
},
469+
wantErr: false,
470+
matches: 1,
471+
},
472+
{
473+
file: "version-streamed-package-invalid-runtime-dependencies-1.2.yaml",
474+
minSeverity: SeverityWarning,
475+
want: EvalResult{
476+
File: "version-streamed-package-invalid-runtime-dependencies-1.2",
477+
Errors: EvalRuleErrors{
478+
{
479+
Rule: Rule{
480+
Name: "version-streamed-runtime-dependencies",
481+
Severity: SeverityError,
482+
},
483+
Error: fmt.Errorf("[version-streamed-runtime-dependencies]: version-streamed package must use versioned runtime dependencies for its subpackages: version-streamed-package-invalid-runtime-dependencies-foo (ERROR)"),
484+
},
485+
},
486+
},
487+
wantErr: false,
488+
matches: 1,
489+
},
454490
}
455491

456492
for _, tt := range tests {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package:
2+
name: version-streamed-package-invalid-runtime-dependencies-1.2
3+
version: 1.2.3
4+
epoch: 0
5+
description: "a version-package with non-streamed runtime dependencies"
6+
dependencies:
7+
runtime:
8+
- version-streamed-package-invalid-runtime-dependencies-foo # NOK
9+
- ${{package.name}}-bar # OK
10+
11+
pipeline:
12+
- runs: echo "test"
13+
14+
subpackages:
15+
- name: ${{package.name}}-foo
16+
description: "a subpackage with provides that doesn't contain the version stream"
17+
pipeline:
18+
- runs: echo "test"
19+
dependencies:
20+
provides:
21+
- version-streamed-package-invalid-runtime-dependencies-foo=${{package.full-version}}
22+
23+
- name: ${{package.name}}-bar
24+
description: "a subpackage with provides that does contain the version stream"
25+
pipeline:
26+
- runs: echo "test"
27+
dependencies:
28+
provides:
29+
- ${{package.name}}-bar=${{package.full-version}}
30+
31+
update:
32+
enabled: true

0 commit comments

Comments
 (0)