Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
88 changes: 87 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,73 @@ 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
- ✅ `subscribe.apis` entries must use `<group>/<version>/<Kind>` with an explicit API group and UpperCamelCase `Kind`

**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
❌ package.yaml subscribe.apis[0] must use "<group>/<version>/<Kind>" format with a non-empty API group
❌ package.yaml subscribe.apis[0] kind must be UpperCamelCase and start with an uppercase letter
```

---

### Legacy release file

Checks for the deprecated `release.yaml` file.
Expand Down Expand Up @@ -534,6 +602,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