Configuration¶
fluxlint reads .fluxlint.yaml from the repository root, or the file you name with
--config. Every field is optional, and a missing file means defaults. An unknown key
is an error, so a misspelt setting cannot silently do nothing.
entrypoints:
- clusters/production
kubeVersion: "1.35.0"
repoSource: {kind: GitRepository, name: flux-system, namespace: flux-system}
externals:
namespaces: [tenant-a]
crdGroups: [example.internal]
secrets:
- {namespace: flux-system, name: sops-age, keys: [age.agekey]}
substitutions:
- kind: ConfigMap
name: cluster-info
variables: [cluster_name, region]
runtimeCRDs:
- group: infrastructure.cluster.x-k8s.io
providedBy: flux-system/capi-providers
sources:
cacheDir: .fluxlint-cache
overrides:
- {kind: GitRepository, name: my-operator, path: ../my-operator}
rules:
default: all
disable: [retry-cliff, timing]
enable: [critical-path]
severity:
positional-patch: error
assertions: []
timing:
maxBootstrapBound: 30m
dependencyRequeue: 30s
dominantShare: 0.4
entrypoints¶
The directories your bootstrap Kustomizations point at, relative to the repository root. Entrypoints on the command line replace this list.
Clusters in one repository differ. They run different Kubernetes versions, and a namespace that exists out of band in one does not exist in another. An entry can be an object that carries settings for that cluster alone:
kubeVersion: "1.35.0"
externals:
namespaces: [shared]
entrypoints:
- clusters/production
- path: clusters/staging
kubeVersion: "1.36.0" # staging upgrades first
externals:
namespaces: [sandbox] # added to the shared list
timing:
maxBootstrapBound: 45m
| Field | Effect |
|---|---|
kubeVersion, repoSource |
replace the top-level value |
externals |
added to the top-level externals |
timing |
each field that is set replaces the top-level one |
rules, assertions and sources are shared by every entrypoint. A path given on the
command line picks up the settings of the entry with the same path.
kubeVersion¶
The Kubernetes version charts are rendered for. Charts read it as
.Capabilities.KubeVersion and many refuse to render for a version they do not
support, so set it to what your clusters run. The default is 1.35.0.
It is also the release built-in objects are checked against (FL-V003). Each Kubernetes
release publishes the OpenAPI schema of its APIs, and fluxlint validates every
Deployment, Service, Job and so on against the schema of this release: a field that
release does not have is an error, and so is an API version it does not serve. Clusters
on different versions each get their own answer, because an
entrypoint can set its own kubeVersion.
To see what an upgrade will break, run the check once more with the version you are moving to:
entrypoints:
- path: clusters/production
kubeVersion: "1.36"
1.35, 1.35.2 and v1.35.2 are all accepted. Without a patch number .0 is used,
since a minor version's API does not change.
repoSource¶
The Flux source object that stands for this repository. A Kustomization whose
sourceRef names it is rendered from your working tree. Any other source is fetched.
The default is the GitRepository named flux-system in flux-system, which is what
flux bootstrap creates.
externals¶
Things that exist in the cluster but that nothing in Git creates. Keep the list short: everything on it is something fluxlint takes on trust.
| Field | Meaning |
|---|---|
namespaces |
namespaces that already exist |
crdGroups |
API groups whose CRDs are installed by something fluxlint cannot see. Objects in these groups are not validated and need no ordering. |
secrets |
Secrets created out of band. keys is optional. When you give it, key references are checked against it. |
substitutions |
ConfigMaps and Secrets read by postBuild.substituteFrom that Git does not contain, with the variables they provide |
runtimeCRDs |
API groups whose CRDs appear only once a component is running |
runtimeCRDs¶
Some CRDs are in no manifest. cluster-api-operator, for example, installs a provider's
CRDs when it reconciles an InfrastructureProvider. Name the group and the component
that causes the install:
externals:
runtimeCRDs:
- group: infrastructure.cluster.x-k8s.io
providedBy: flux-system/capi-providers # or HelmRelease/<namespace>/<name>
Unlike crdGroups, this keeps the ordering check. A consumer with no path from the
provider is reported as FL-T006.
sources¶
| Field | Meaning |
|---|---|
cacheDir |
where fetched sources are kept, relative to the repository root. The default is the user cache directory. --cache-dir wins over both. |
overrides |
use a local directory in place of a source, for example a sibling checkout in CI. path is relative to the repository root. namespace is optional. |
kubernetesSchemas |
where the API schemas of Kubernetes releases are read from: a URL prefix or a directory, laid out like the Kubernetes repository (<base>/v1.35.0/api/openapi-spec/v3/). The default is the Kubernetes repository on GitHub. A schema is fetched once per release and cached, so later runs and --offline runs need no network. Point it at a mirror or a checked-in directory when CI cannot reach GitHub. |
See What fluxlint renders for credentials and cache behaviour.
rules¶
Choose which rules run, the way golangci-lint chooses linters: start from all of them or none, then turn single rules on or off.
| Field | Meaning |
|---|---|
default |
all (the default) or none |
disable |
rules to turn off. Use it with default: all. |
enable |
rules to turn on. Use it with default: none. |
severity |
a rule's severity: error, warning or info |
Name a rule by its ID (FL-T007) or by its name (retry-cliff). In enable and
disable, a family name stands for every rule in the family: graph, substitution,
validation, runtime, contracts, assertions, transitions, sources or timing.
fluxlint rules lists each rule with its family.
A rule named on its own beats its family, so you can switch a family off and keep one rule from it:
rules:
disable: [timing]
enable: [critical-path]
Or run only what you choose:
rules:
default: none
enable: [graph, validation, FL-R001]
A name that is not a rule or a family is an error, so a typo cannot leave a rule running that you meant to turn off. The rules reference lists every rule and its default severity.
assertions¶
Your own rules, written in CEL. See Write your own rules.
contracts¶
contracts:
images:
- registry.example.com/platform/*
images lists patterns for container images that may carry a
contract. * matches any
run of characters. Only images that match are looked up. With no patterns, fluxlint
never asks a registry about an image.
kyverno¶
kyverno:
command: /usr/local/bin/kyverno
When the repository installs Kyverno policies that validate, fluxlint gives them and
every rendered object to the kyverno CLI and reports what an Enforce policy rejects
as FL-V007. command is the CLI to run, and defaults to kyverno on PATH.
The CLI is Kyverno's engine in one binary. Kyverno cannot be linked into fluxlint: it builds against its own forks of the Kubernetes libraries. Running the CLI also means the verdict comes from the version you install, which can be the version your clusters run.
fluxlint never downloads or starts anything. If the CLI is not there, the run says how
many policies were not evaluated (-v). Get the CLI from the
Kyverno releases.
ValidatingAdmissionPolicies need no setup. fluxlint evaluates them in process, with the
API server's own code (FL-V005).
images¶
images:
verify:
- registry.example.com/*
platforms: [linux/amd64]
verify lists patterns for container images that must exist in their registry. *
matches any run of characters, so "*" alone checks every image. For each match
fluxlint asks the registry whether the tag or digest is there, with the credentials in
your Docker config, and reports FL-X004 if it is not. This catches a version bump to a
tag that was never pushed, which a cluster would only show as ImagePullBackOff.
platforms names what your nodes run. A multi-platform image that lacks one of them is
reported too.
An image that was found is cached, so later runs and --offline runs do not ask again.
One that was missing is asked about on every run. If the registry cannot be reached or
refuses the credentials, the image is listed as not checked (-v), and is not a
finding. With no patterns, fluxlint never asks a registry about an image.
timing¶
| Field | Default | Meaning |
|---|---|---|
maxBootstrapBound |
none | fail with FL-T100 when the worst-case bound is longer than this |
dependencyRequeue |
30s |
how often a controller checks a dependency that is not ready. Set it to your controllers' --requeue-dependency. |
dominantShare |
0.4 |
the share of the bound above which one component is reported as dominant (FL-T002) |
Durations use Go syntax: 90s, 5m, 1h30m.