Skip to content

Commit ebfa55f

Browse files
committed
update
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
1 parent d54ede5 commit ebfa55f

File tree

3 files changed

+348
-153
lines changed

3 files changed

+348
-153
lines changed

pkg/linters/module/README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,22 +144,42 @@ Validates the `oss.yaml` file containing open-source software attribution.
144144
- ✅ Valid YAML structure
145145
- ✅ At least one project is described
146146
- ✅ Each project has required fields:
147-
- `name` - Project name
148-
- `description` - Project description
149-
- `link` - Valid project URL
150-
- `license` - Valid license identifier
151-
- `logo` (optional) - Valid logo URL
147+
- `id` - Project identifier (must not be empty)
148+
- `version` - Project version (must not be empty, should be valid semver)
149+
- `name` - Project name (must not be empty)
150+
- `description` - Project description (must not be empty)
151+
- `link` - Valid project URL (must not be empty, must be valid URL)
152+
- `license` - Valid license identifier (must not be empty)
153+
- `logo` (optional) - Valid logo URL (must be valid URL if provided)
154+
155+
**Error Messages:**
156+
- `Module should have oss.yaml` - File is missing from module root
157+
- `Invalid oss.yaml: <error>` - File exists but contains invalid YAML or structure
158+
- `no projects described` - File exists but contains an empty list
159+
- `id must not be empty` - Project entry is missing the `id` field
160+
- `version must not be empty. Please fill in the parameter and configure CI (werf files for module images) to use these setting. See ADR "platform-security/2026-01-21-oss-yaml-werf.md"` - Project entry is missing the `version` field
161+
- `version must be valid semver: <error>` (Warning) - Version is provided but not in valid semantic versioning format
162+
- `name must not be empty` - Project entry is missing the `name` field
163+
- `description must not be empty` - Project entry is missing the `description` field
164+
- `link must not be empty` - Project entry is missing the `link` field
165+
- `link URL is malformed ("<url>")` - Link is provided but is not a valid URL
166+
- `License must not be empty` - Project entry is missing the `license` field
167+
- `project logo URL is malformed ("<url>")` - Logo is provided but is not a valid URL
152168

153169
**Example:**
154170
```yaml
155171
# oss.yaml
156-
- name: nginx
172+
- id: nginx/nginx
173+
version: 1.25.3
174+
name: nginx
157175
description: High performance web server
158176
link: https://nginx.org/
159177
license: BSD-2-Clause
160178
logo: https://nginx.org/nginx.png
161179
162-
- name: prometheus
180+
- id: prometheus/prometheus
181+
version: 2.48.0
182+
name: prometheus
163183
description: Monitoring system and time series database
164184
link: https://prometheus.io/
165185
license: Apache-2.0

pkg/linters/module/rules/oss_library.go

Lines changed: 27 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"k8s.io/utils/ptr"
2727
"sigs.k8s.io/yaml"
2828

29+
"github.com/Masterminds/semver/v3"
2930
"github.com/deckhouse/dmt/pkg"
3031
"github.com/deckhouse/dmt/pkg/errors"
3132
)
@@ -59,11 +60,7 @@ func (r *OSSRule) OssModuleRule(moduleRoot string, errorList *errors.LintRuleErr
5960
errorList = errorList.WithMaxLevel(ptr.To(pkg.Ignored))
6061
}
6162

62-
if errs := verifyOssFile(moduleRoot); len(errs) > 0 {
63-
for _, err := range errs {
64-
errorList.WithFilePath(moduleRoot).Error(ossFileErrorMessage(err))
65-
}
66-
}
63+
verifyOssFile(moduleRoot, errorList)
6764
}
6865

6966
func ossFileErrorMessage(err error) string {
@@ -74,85 +71,74 @@ func ossFileErrorMessage(err error) string {
7471
return fmt.Sprintf("Invalid %s: %s", ossFilename, err.Error())
7572
}
7673

77-
func verifyOssFile(moduleRoot string) []error {
74+
func verifyOssFile(moduleRoot string, errorList *errors.LintRuleErrorsList) {
7875
projects, err := readOssFile(moduleRoot)
7976
if err != nil {
80-
return []error{err}
77+
errorList.Error(err.Error())
78+
79+
return
8180
}
8281

8382
if len(projects) == 0 {
84-
return []error{fmt.Errorf("no projects described")}
83+
errorList.Error("no projects described")
84+
85+
return
8586
}
8687

87-
var errs []error
8888
for i, p := range projects {
89-
err = assertOssProject(i+1, &p)
90-
if err != nil {
91-
errs = append(errs, err)
92-
}
89+
assertOssProject(i+1, &p, errorList)
9390
}
94-
95-
return errs
9691
}
9792

98-
func assertOssProject(i int, p *ossProject) error {
99-
var complaints []string
100-
93+
func assertOssProject(i int, p *ossProject, errorList *errors.LintRuleErrorsList) {
10194
// prefix to make it easier navigate among errors
10295
prefix := fmt.Sprintf("#%d", i)
10396

10497
// Id
105-
10698
if strings.TrimSpace(p.Id) == "" {
107-
complaints = append(complaints, "id must not be empty")
99+
errorList.WithObjectID("index=" + prefix + ";").Error("id must not be empty")
100+
} else {
101+
prefix = fmt.Sprintf("#%d (id=%s)", i, p.Id)
108102
}
109103

110104
// Version
111-
112105
if strings.TrimSpace(p.Version) == "" {
113-
complaints = append(complaints, "version must not be empty. Please fill in the parameter and configure CI (werf files for module images) to use these setting. See ADR \"platform-security/2026-01-21-oss-yaml-werf.md\"")
106+
errorList.WithObjectID("index=" + prefix + ";").Error("version must not be empty. Please fill in the parameter and configure CI (werf files for module images) to use these setting. See ADR \"platform-security/2026-01-21-oss-yaml-werf.md\"")
107+
} else {
108+
_, err := semver.NewVersion(p.Version)
109+
if err != nil {
110+
errorList.WithObjectID("index=" + prefix + ";").Warn(fmt.Sprintf("version must be valid semver: %v", err))
111+
}
114112
}
115-
// Name
116113

114+
// Name
117115
if strings.TrimSpace(p.Name) == "" {
118-
complaints = append(complaints, "name must not be empty")
119-
} else {
120-
prefix = fmt.Sprintf("#%d (name=%s)", i, p.Name)
116+
errorList.WithObjectID("index=" + prefix + ";").Error("name must not be empty")
121117
}
122118

123119
// Description
124-
125120
if strings.TrimSpace(p.Description) == "" {
126-
complaints = append(complaints, "description must not be empty")
121+
errorList.WithObjectID("index=" + prefix + ";").Error("description must not be empty")
127122
}
128123

129124
// Link
130-
131125
if strings.TrimSpace(p.Link) == "" {
132-
complaints = append(complaints, "link must not be empty")
126+
errorList.WithObjectID("index=" + prefix + ";").Error("link must not be empty")
133127
} else if _, err := url.ParseRequestURI(p.Link); err != nil {
134-
complaints = append(complaints, fmt.Sprintf("link URL is malformed (%q)", p.Link))
128+
errorList.WithObjectID("index=" + prefix + ";").Error(fmt.Sprintf("link URL is malformed (%q)", p.Link))
135129
}
136130

137131
// License
138-
139132
if strings.TrimSpace(p.License) == "" {
140-
complaints = append(complaints, "License must not be empty")
133+
errorList.WithObjectID("index=" + prefix + ";").Error("License must not be empty")
141134
}
142135

143136
// Logo
144-
145137
if strings.TrimSpace(p.Logo) != "" {
146138
if _, err := url.ParseRequestURI(p.Logo); err != nil {
147-
complaints = append(complaints, fmt.Sprintf("project logo URL is malformed (%q)", p.Logo))
139+
errorList.WithObjectID("index=" + prefix + ";").Error(fmt.Sprintf("project logo URL is malformed (%q)", p.Logo))
148140
}
149141
}
150-
151-
if len(complaints) > 0 {
152-
return fmt.Errorf("%s: %s", prefix, strings.Join(complaints, "; "))
153-
}
154-
155-
return nil
156142
}
157143

158144
func readOssFile(moduleRoot string) ([]ossProject, error) {

0 commit comments

Comments
 (0)