Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ func mapModuleRules(linterSettings *pkg.LintersSettings, configSettings *config.
rules.HelmignoreRule.SetLevel(globalRules.HelmignoreRule.Impact, fallbackImpact)
rules.LicenseRule.SetLevel(globalRules.LicenseRule.Impact, fallbackImpact)
rules.RequarementsRule.SetLevel(globalRules.RequarementsRule.Impact, fallbackImpact)
rules.PackageYAMLRule.SetLevel(globalRules.PackageYAMLRule.Impact, fallbackImpact)
rules.LegacyReleaseFileRule.SetLevel(globalRules.LegacyReleaseFileRule.Impact, fallbackImpact)
}

Expand Down
1 change: 1 addition & 0 deletions pkg/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ type ModuleLinterRules struct {
HelmignoreRule RuleConfig
LicenseRule RuleConfig
RequarementsRule RuleConfig
PackageYAMLRule RuleConfig
LegacyReleaseFileRule RuleConfig
}
type OSSRuleSettings struct {
Expand Down
1 change: 1 addition & 0 deletions pkg/config/global/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ type ModuleLinterRules struct {
HelmignoreRule RuleConfig `mapstructure:"helmignore"`
LicenseRule RuleConfig `mapstructure:"license"`
RequarementsRule RuleConfig `mapstructure:"requarements"`
PackageYAMLRule RuleConfig `mapstructure:"package-yaml"`
LegacyReleaseFileRule RuleConfig `mapstructure:"legacy-release-file"`
}

Expand Down
85 changes: 84 additions & 1 deletion pkg/linters/module/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The Module linter performs automated checks on Deckhouse modules to validate con

## Rules

The Module linter includes **7 validation rules**:
The Module linter includes **8 validation rules**:

| Rule | Description | Configurable |
|------|-------------|--------------|
Expand All @@ -18,6 +18,7 @@ The Module linter includes **7 validation rules**:
| [**helmignore**](#helmignore) | Validates `.helmignore` file presence and content | ✅ Yes |
| [**license**](#license) | Validates license headers in source files | ✅ Yes |
| [**requirements**](#requirements) | Validates version requirements for features | ❌ No |
| [**package-yaml**](#package-yaml) | Validates `package.yaml` metadata and new requirements schema | ✅ Yes |
| [**legacy-release-file**](#legacy-release-file) | Checks for deprecated `release.yaml` file | ❌ No |

---
Expand Down Expand Up @@ -417,6 +418,70 @@ requirements:

---

### Package YAML

Validates the optional `package.yaml` file in the module root.

**Purpose:** Ensures modules that use the new package requirements schema declare a compatible Deckhouse version and keep dependency constraints parseable as plain semantic version constraints. This prevents modules from publishing v2 package metadata that older Deckhouse versions cannot read.

**Checks:**
- ✅ If `package.yaml` exists, it must be valid YAML
- ✅ `apiVersion` is required
- ✅ `name` is required
- ✅ All non-empty version constraints must be parsed as-is by the semver library
- ✅ The new requirements schema requires `requirements.deckhouse.constraint >= 1.77.0`
- ✅ Old markers such as `!optional` are rejected when placed inside a new `constraint` field

**New Requirements Schema Detection:**
The rule treats `package.yaml` as using the new requirements schema when any of these fields are present:
- `requirements.kubernetes.constraint`
- `requirements.modules.mandatory`
- `requirements.modules.conditional`
- `requirements.modules.anyOf`

**Example:**
```yaml
# package.yaml
apiVersion: v2
name: stronghold

requirements:
kubernetes:
constraint: ">= 1.26"
deckhouse:
constraint: ">= 1.77.0"
modules:
mandatory:
- name: cloud-provider-yandex
constraint: ">= 1.5.0"
conditional:
- name: observability
constraint: ">= 1.0.0"
anyOf:
- description: "One of the following cloud providers must be installed"
modules:
- name: cloud-provider-gcp
constraint: ">= 1.5.0"
- name: cloud-provider-aws
constraint: ">= 2.0.0"

subscribe:
apis:
- autoscaling.k8s.io/v1/VerticalPodAutoscaler
values:
- module: stronghold
value: .someValues.strField
```

**Error Examples:**
```
❌ package.yaml apiVersion is required
❌ Invalid package.yaml requirements.modules.conditional[0].constraint version constraint ">= 1.0.0 !optional"
❌ package.yaml requirements.deckhouse.constraint version range should start no lower than 1.77.0
```

---

### Legacy release file

Checks for the deprecated `release.yaml` file.
Expand Down Expand Up @@ -534,6 +599,24 @@ requirements:
deckhouse: ">= 1.68.0"
```

### ❌ package.yaml Uses New Requirements Without Deckhouse 1.77

**Error:** `package.yaml requirements.deckhouse.constraint version range should start no lower than 1.77.0`

**Solution:** Raise the package-level Deckhouse requirement:
```yaml
# package.yaml
apiVersion: v2
name: my-module
requirements:
deckhouse:
constraint: ">= 1.77.0"
modules:
mandatory:
- name: dependency-module
constraint: ">= 1.0.0"
```

### ❌ Update Versions Not Sorted

**Error:** `Update versions must be sorted`
Expand Down
1 change: 1 addition & 0 deletions pkg/linters/module/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func (l *Module) Run(m *module.Module) {
rules.NewLicenseRule(l.cfg.ExcludeRules.License.Files.Get(), l.cfg.ExcludeRules.License.Directories.Get()).
CheckFiles(m, errorList.WithMaxLevel(l.cfg.Rules.LicenseRule.GetLevel()))
rules.NewRequirementsRule().CheckRequirements(m.GetPath(), errorList.WithMaxLevel(l.cfg.Rules.RequarementsRule.GetLevel()))
rules.NewPackageYAMLRule().CheckPackageYAML(m.GetPath(), errorList.WithMaxLevel(l.cfg.Rules.PackageYAMLRule.GetLevel()))
rules.NewLegacyReleaseFileRule().CheckLegacyReleaseFile(m.GetPath(), errorList.WithMaxLevel(l.cfg.Rules.LegacyReleaseFileRule.GetLevel()))
}

Expand Down
Loading
Loading