Skip to content

Add scorecard rules

Scorecard rules run while Kix evaluates a cluster. Every built-in rule set runs by default. Narrow the set when you want fewer checks, and add custom rules for policy specific to your packages or organization.

This guide assumes the cluster is defined with kix.buildCluster.

scorecard.rules defaults to kix.rules, the four built-in categories: security, reliability, governance, and architecture. Setting the option replaces that default, so name every set you want to keep:

cluster.nix
scorecard.rules = {
inherit (kix.rules) security reliability;
};

The attribute name becomes the rule category. For example, kix.rules.reliability.hasProbes is reported as reliability.hasProbes.

To keep the whole built-in set and change one rule, leave rules alone and use an override instead. See Disable scorecard rules and Override scorecard severity.

Place custom rules under a category of your own. This tested package-level rule applies only to packages that advertise the reverse-proxy capability, then checks their evaluated configuration:

tutorials/19-scorecards/scorecard.nix (L50–L74)
custom.proxyMaxBodySizeMustBeExplicit = {
description = "Reverse-proxy gateways must set maxBodySize explicitly (not the 1m default).";
level = "package";
severity = "error";
tags = [ "reliability" "kix-examples" ];
# Only run on reverse-proxy packages. `appliesTo` receives the
# package metadata directly, so this checks `meta.provides`.
appliesTo =
{ meta, ... }:
builtins.elem "reverse-proxy" (meta.provides or [ ]);
check =
{ config, instanceName, ... }:
if (config.maxBodySize or "") == "1m" then
[
{
message =
"instance '${instanceName}' uses the default maxBodySize '1m'. "
+ "nginx rejects larger request bodies — set this explicitly.";
}
]
else
[ ];
};

View source on GitHub ↗

Add the rule inside scorecard.rules. Its full name is custom.proxyMaxBodySizeMustBeExplicit. Because setting rules replaces the default, merge the custom category into the built-in set to keep both:

cluster.nix
scorecard.rules = kix.rules // {
custom.proxyMaxBodySizeMustBeExplicit = { /* the rule above */ };
};

Every rule declares a level that determines the value passed to its check:

  • manifest runs once for each rendered Kubernetes resource.
  • package runs once for each package instance.
  • namespace runs once for each namespace.
  • cluster runs once for the whole cluster.

Kix accepts only these four levels and three severities: info, warning, and error. Evaluation rejects any other value. This prevents misspelled levels from creating rules that never run, and misspelled severities from being treated as warnings.

The check returns one finding for each problem and an empty list when the input passes. Use appliesTo when a rule is meaningful only for a subset of its level.

Run the cluster checks after adding or changing a rule:

Run in kix-examples/
❱ kix check 19-scorecards
 TOOL         RESULT  DETAILS                                                       
 eval         pass    23 manifests evaluated                                        
 kubeconform  pass    skipped (this validation tool is not yet integrated with Kix) 
 pluto        pass    skipped (this validation tool is not yet integrated with Kix) 
 kyverno      pass    skipped (this validation tool is not yet integrated with Kix) 
 scorecard    pass    0 errors, 6 warnings, 4 info

Kix reports the number of scorecard errors, warnings, and informational findings. Every finding is capped at scorecard.maxSeverity, which defaults to warning, so a new cluster prints what the rules found and still builds. With the cap raised to error, an error-severity finding becomes a failed assertion: evaluation stops at the first error, the cluster does not build, and only that finding is reported. Warnings and informational findings are collected across the cluster and reported together. See Fail the build on scorecard findings for the cap.