[dmt] add ingress/gw-api linters - #474
Merged
Merged
Conversation
miklezzzz
force-pushed
the
add-ingress-gateway-api-linters
branch
from
September 15, 2026 09:29
cb71ca0 to
c684b37
Compare
Signed-off-by: Mikhail Scherba <mikhail.scherba@flant.com>
miklezzzz
force-pushed
the
add-ingress-gateway-api-linters
branch
from
September 16, 2026 12:41
270035f to
8977a29
Compare
ldmonster
approved these changes
Sep 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pr adds Ingress / Gateway API linting rules:
Adds six rules to the templates linter that enforce ingress and Gateway API hygiene across Deckhouse modules. Every rule is severity-configurable (error/warn) and disable-/exclude-able via .dmtlint.yaml, and each is gated so it only runs on modules that actually render the resource kind it cares about — a module with no Ingress, HTTPRoute, or ListenerSet is never touched.
Enablement — a resource you ship must be switchable off
ingress-enablement flags any template that emits a kind: Ingress but never references helm_lib_module_ingress_enabled. Without that guard the Ingress renders unconditionally and can't be disabled through global.modules.ingress.enabled or the module's own .ingress.enabled override. The finding names the exact .Values paths and the {{- if eq (include …) "true" }} guard to add.
gateway-enablement is the Gateway API counterpart: a template emitting kind: HTTPRoute or kind: ListenerSet must reference helm_lib_module_gateway_enabled. Unlike Ingress there is no safe default gateway, so that helper checks both the enable flag and that a Gateway actually resolves.
Both use a same-file textual heuristic (does this file emit the kind and mention the helper?) rather than a full Helm control-flow parser — a deliberate trade-off documented in the code, since in practice the guard and the manifest it protects live in the same file.
Migration — stop using annotations the platform has replaced
deprecated-httproute-annotations flags banned annotation keys anywhere in a template (plain YAML or inside a Helm expression). It currently bans alb.network.deckhouse.io/response-headers-to-add, pointing authors at the native Gateway API ResponseHeaderModifier filter and including a ready-to-paste replacement snippet. The banned list is a single data structure — adding another annotation is one entry.
Certificate reuse — copy a CustomCertificate once, share it across flows
https-certificate-reuse applies to modules that serve HTTPS over both Ingress and Gateway API. In CustomCertificate mode the two flows must share one copied secret: the Ingress manifest references it with the plain helm_lib_module_https_secret_name form (list . "base"), and the HTTPRoute/ListenerSet manifest with the two-prefix form (list . "base" "override") that links back to the same base. The rule scans every template (splitting files on --- so a HTTPRoute bundled with its cert-manager Certificate is classified per-document) and reports five things: a prefix copied more than once, an Ingress using the two-prefix form, a Gateway API manifest using the plain form, an override that's also independently copied, and — from the copy calls alone — a -ingress-tls / -httproute-tls pair that should have been one copy.
HTTP → HTTPS redirect — the pair that guarantees redirects actually happen
These two complement each other so an HTTPS host can't silently refuse plain-HTTP requests:
listenerset-redirect requires every hostname a ListenerSet exposes over HTTPS to also have a plain-HTTP (port 80) listener, so HTTP traffic has somewhere to be redirected from.
httproute-redirect then requires each of those port-80 redirect sections to be backed by an HTTPRoute whose parentRef targets the section (by name/section, cross-namespace–aware) with a RequestRedirect filter to HTTPS (scheme: https or port: 443).
Because rendered hostnames come from publicDomainTemplate and aren't known at lint time, exclusions for both are keyed by listener section name ({name: , section:
Wiring & configuration
Registered in the templates linter (templates.go) and the static rule set; each has a mapstructure key matching its rule name.
Exclusions: the four file-scanning rules take PathRuleExclude (files: + directories:); the two redirect rules take a list of {name, section} entries.
Docs: every rule has a ### section with examples in pkg/linters/templates/README.md; coverage is unit tests per rule plus auto-discovered test/e2e fixtures (including a negative gating case proving the rules stay silent on modules with no ingress/Gateway objects).