CLI Configuration File (AICRConfig)

View as MarkdownOpen in Claude

AICRConfig is a Kubernetes-style YAML/JSON document that captures the inputs to the five workflow commands — aicr snapshot, aicr recipe, aicr bundle, aicr validate, and aicr verify — so an end-to-end run version-controls as a single file instead of a shell script full of flags. Each command accepts it through the same --config flag:

$aicr snapshot --config aicr-config.yaml
$aicr recipe --config aicr-config.yaml
$aicr bundle --config aicr-config.yaml
$aicr validate --config aicr-config.yaml
$aicr verify ./my-bundle --config aicr-config.yaml # bundle dir is positional

The first four are the producer pipeline; spec.verify is the consumer side, so one document can carry both how an artifact is built and the trust floor a downstream consumer enforces against it.

This page documents the complete document schema in one place. The CLI Reference shows per-command usage in its Snapshot, Recipe, Validate, Bundle, and Verify config-file-mode sections. The schema’s source of truth is pkg/config.

Document Envelope

1kind: AICRConfig # required, exactly this value
2apiVersion: aicr.run/v1alpha2 # required, exactly this value
3metadata:
4 name: gke-h100-training # optional, identifying only
5spec:
6 snapshot: {} # each section optional —
7 recipe: {} # at least ONE must be present
8 bundle: {}
9 validate: {}
10 verify: {}

Each spec.* section is optional and each command reads only its own section, so a file may carry just one section or any combination. A document with none of the five sections is rejected.

Loading, Precedence, and Secrets

Sources. --config accepts a local file path or an HTTP/HTTPS URL (format detected from the extension; fetches are timeout- and size-bounded). ConfigMap cm:// URIs are intentionally rejected — extract the data with kubectl and pass the resulting file.

Precedence. A CLI flag always wins over the matching config field. For slice and map fields (tolerations, selectors, --set), a flag given on the command line replaces the file’s value; it does not append.

Nil vs. empty. For agent selectors and tolerations, omitting the field entirely (nil) inherits the compiled-in defaults (tolerations defaults to tolerate all taints), while an explicit empty value ({} / []) clears the default. Several booleans are tri-state for the same reason: absent means “inherit the CLI default”, an explicit false is an opt-out (spec.validate.execution.failOnError, failFast, spec.snapshot.execution.privileged, spec.recipe.criteriaStrict, spec.validate.evidence.*).

Secrets are never part of the schema. The cosign OIDC identity token used by attestation and evidence push is deliberately absent — supply it via the COSIGN_IDENTITY_TOKEN environment variable or the --identity-token flag.

Complete Example

1kind: AICRConfig
2apiVersion: aicr.run/v1alpha2
3metadata:
4 name: eks-h100-training
5spec:
6 snapshot:
7 output:
8 path: snapshot.yaml # same shape as -o
9 format: yaml # yaml | json | table
10 template: "" # optional Go template path
11 agent: # in-cluster snapshot Job pod
12 namespace: aicr-validation
13 image: "" # default: ghcr.io/nvidia/aicr:latest
14 imagePullSecrets: []
15 jobName: aicr
16 serviceAccountName: aicr
17 nodeSelector:
18 nodeGroup: gpu-worker
19 tolerations:
20 - dedicated=gpu-workload:NoSchedule
21 requireGpu: false
22 runtimeClassName: "" # mutually exclusive with requireGpu
23 os: "" # ubuntu | rhel | cos | amazonlinux | ol | talos
24 requests: "" # "cpu=500m,memory=1Gi"
25 limits: ""
26 execution:
27 timeout: 5m
28 noCleanup: false
29 privileged: true # false for PSS-restricted namespaces
30 maxNodesPerEntry: 0 # 0 = unlimited topology entries
31
32 recipe:
33 criteria: # mutually exclusive with input.snapshot
34 service: eks
35 accelerator: h100
36 intent: training
37 os: ubuntu
38 platform: kubeflow
39 nodes: 2
40 profile: "" # optional name=value; empty uses the declared default
41 # configuration: # typed desired-state inputs (not matched on)
42 # slurm: # only valid when the resolved recipe platform is slurm
43 # accounting:
44 # mode: disabled # disabled | customer-managed | aicr-provided
45 # input:
46 # snapshot: snapshot.yaml # derive criteria from a snapshot instead
47 output:
48 path: recipe.yaml
49 format: yaml # yaml | json | table
50 data: "" # optional data-overlay dir/archive
51 criteriaStrict: false # reject criteria outside the embedded catalog
52
53 bundle:
54 input:
55 recipe: recipe.yaml # must match recipe.output.path when both set
56 output:
57 target: ./bundles # local dir or oci:// URI
58 imageRefs: "" # external digest file; OCI output only
59 deployment:
60 deployer: helmfile # helm | helmfile | argocd | argocd-helm | flux | ...
61 repo: ""
62 set: [] # value overrides, "key:path=value"
63 dynamic: []
64 vendorCharts: false
65 appName: "" # argocd parent Application name override
66 scheduling:
67 systemNodeSelector: {}
68 systemNodeTolerations: []
69 acceleratedNodeSelector:
70 nodeGroup: gpu-worker
71 acceleratedNodeTolerations:
72 - nvidia.com/gpu=present:NoSchedule
73 workloadGate: ""
74 workloadSelector: {}
75 nodes: 2
76 storageClass: ""
77 sharedStorageClass: "" # RWX class for opt-in shared filesystems
78 attestation:
79 enabled: false
80 certificateIdentityRegexp: ""
81 oidcDeviceFlow: false
82 fulcioURL: "" # private Sigstore overrides; empty = public good
83 rekorURL: ""
84 signingKey: "" # KMS key ref (awskms:// | gcpkms:// | ...); empty = keyless OIDC
85 registry: # OCI transport for oci:// push
86 insecureTLS: false
87 plainHTTP: false
88
89 validate:
90 input:
91 recipe: recipe.yaml
92 snapshot: snapshot.yaml
93 agent: # same nil-vs-empty semantics as snapshot.agent
94 namespace: aicr-validation
95 image: ""
96 imagePullSecrets: []
97 jobName: aicr
98 serviceAccountName: aicr
99 nodeSelector:
100 nodeGroup: gpu-worker
101 tolerations:
102 - nvidia.com/gpu=present:NoSchedule
103 requireGpu: false
104 execution:
105 phases: [deployment, conformance, performance]
106 failOnError: true # tri-state; absent = CLI default (true)
107 failFast: false
108 noCluster: false
109 noCleanup: false
110 timeout: 40m
111 evidence:
112 cncf: # CNCF AI Conformance markdown
113 dir: ./evidence
114 cncfSubmission: false # requires dir
115 features: [] # empty = all features
116 attestation: # recipe-evidence bundle (ADR-007)
117 out: evidence-result.json # setting this enables the path
118 bom: ""
119 push: "" # OCI ref to push the signed bundle
120 plainHTTP: false
121 insecureTLS: false
122 verify: # consumer side: policy for `aicr verify`
123 policy: # assertions checked after verification
124 minTrustLevel: verified # unknown | unverified | attested | verified | max
125 requireCreator: ci@myorg.example.com
126 cliVersionConstraint: ">= 0.16.0"
127 trust: # material verification runs against
128 certificateIdentityRegexp: "" # when set, must BEGIN with https://github.com/NVIDIA/aicr/
129 key: "" # KMS URI or local PEM public-key path
130 trustRoot: "" # private Sigstore trusted_root.json

Field Reference

spec.snapshot

Inputs to aicr snapshot. There is no input section — the snapshot is produced from the live cluster.

FieldTypeNotes
output.pathstringOutput file path (same as -o)
output.formatstringyaml | json | table
output.templatestringOptional Go template path
agent.*objectIn-cluster capture Job pod: namespace, image, imagePullSecrets, jobName, serviceAccountName, nodeSelector, tolerations, requireGpu, runtimeClassName (mutually exclusive with requireGpu), os, requests, limits. Mirrors spec.validate.agent so one file pins matching placement for both
execution.timeoutduration stringe.g. 5m
execution.noCleanupboolKeep the capture Job after completion
execution.privilegedbool (tri-state)Set false for PSS-restricted namespaces
execution.maxNodesPerEntryint0 = unlimited topology entries

spec.recipe

Inputs to aicr recipe. criteria and input.snapshot are mutually exclusive — query by criteria or derive from a snapshot, not both.

FieldTypeNotes
criteria.service / .accelerator / .intent / .os / .platformstringSame names and values as the CLI flags
criteria.nodesintTarget GPU node count
profilestringOptional configuration profile selection in name=value form. Empty applies the resolved declaration’s default.
configuration.slurm.accounting.modestringSlurm accounting ownership: disabled (default) | customer-managed | aicr-provided; mirrors --slurm-accounting-mode. Only valid when the resolved recipe platform is slurm (whether from criteria.platform, a snapshot, or --platform) — an explicit mode (even disabled) on any other platform is rejected with INVALID_REQUEST
input.snapshotstringSnapshot path to derive the recipe from
output.pathstringRecipe output path
output.formatstringyaml | json | table
datastringData-overlay directory/archive (same as --data)
criteriaStrictbool (tri-state)Reject criteria values outside the embedded catalog; mirrors --criteria-strict / AICR_CRITERIA_STRICT (any of the three enables it)

spec.bundle

Inputs to aicr bundle.

FieldTypeNotes
input.recipestringRecipe to bundle
output.targetstringLocal directory or oci:// URI
output.imageRefsstringOptional external image-reference output file for an OCI output.target only. Local output is rejected. Its parent must be an existing real directory, and the target must be outside and not aliased to the planned or completed bundle.
deployment.deployerstringDeployer choice (same values as --deployer)
deployment.repostringGitOps repo for repo-shaped deployers
deployment.set / .dynamic[]stringValue overrides, key:path=value
deployment.vendorChartsboolVendor charts into the bundle
deployment.appNamestringArgo CD parent Application name override (multi-bundle installs sharing a namespace)
scheduling.*objectsystemNodeSelector/Tolerations, acceleratedNodeSelector/Tolerations, workloadGate, workloadSelector, nodes, storageClass, sharedStorageClass. Selectors are YAML maps; tolerations use the CLI’s key=value:effect strings
attestation.enabledboolEnable bundle attestation (signing); keyless OIDC by default, KMS-backed when signingKey is set
attestation.certificateIdentityRegexpstringExpected signer identity
attestation.oidcDeviceFlowboolDevice-code flow for headless signing
attestation.fulcioURL / .rekorURLstringPrivate Sigstore endpoints; empty = public-good defaults
attestation.signingKeystringKMS key reference for key-based signing (awskms:// | gcpkms:// | azurekms:// | hashivault://); empty = keyless OIDC. Mutually exclusive with the keyless-only inputs (oidcDeviceFlow, fulcioURL, --identity-token)
registry.insecureTLS / .plainHTTPboolOCI transport options for push

When output.imageRefs is set, AICR writes the published OCI digest through a mode-0600 temporary file and an anchored same-directory rename. The target may be absent or an existing retained regular file; directories, symlinks, other non-regular files, and bundle aliases are rejected. The final validation and rename are ordered but are not one atomic identity-conditioned filesystem operation, so no other process should mutate the target directory while the bundle command runs.

spec.validate

Inputs to aicr validate.

FieldTypeNotes
input.recipe / .snapshotstringRecipe + snapshot to validate
agent.*objectIn-cluster validation Job pod; same fields and nil-vs-empty semantics as spec.snapshot.agent (minus runtimeClassName/os/requests/limits)
execution.phases[]stringe.g. [deployment, conformance, performance]
execution.failOnErrorbool (tri-state)Absent = CLI default (true); explicit false opts out
execution.failFastbool (tri-state)Stop after the first failed phase
execution.noClusterboolTest mode: no cluster access, constraints evaluated inline
execution.noCleanupboolKeep validation Jobs after completion
execution.timeoutduration stringe.g. 40m
evidence.cncf.dirstringCNCF AI Conformance evidence directory (--evidence-dir)
evidence.cncf.cncfSubmissionbool (tri-state)Emit submission layout; requires dir
evidence.cncf.features[]stringEmpty = all features; honored only with cncfSubmission
evidence.attestation.outstringRecipe-evidence result path (v1 for unprofiled recipes, v2 for profiled ones) — setting it enables the attestation path
evidence.attestation.bom / .pushstringBOM input; OCI ref for the signed bundle push
evidence.attestation.plainHTTP / .insecureTLSbool (tri-state)Push transport options

spec.verify

Verification policy for aicr verify, the one consumer-side section. The two sub-sections mirror how the command consumes them: policy holds assertions checked after verification runs, trust holds the material it verifies against.

FieldTypeNotes
policy.minTrustLevelstringunknown | unverified | attested | verified, or max (the CLI default) to auto-detect the highest level the bundle can reach
policy.requireCreatorstringPins the OIDC identity in the bundle attestation’s signing certificate
policy.cliVersionConstraintstringConstrains the aicr version in the attestation predicate; supports >=, >, <=, <, ==, !=, and a bare version means >=
trust.certificateIdentityRegexpstringCertificate identity pattern for binary attestation verification; must begin with https://github.com/NVIDIA/aicr/ (leading ^ allowed) and must not use top-level alternation, so it stays confined to the repository
trust.keystringKMS key URI (awskms:// | gcpkms:// | azurekms:// | hashivault://) or local PEM public-key path; the verify counterpart to spec.bundle.attestation.signingKey
trust.trustRootstringPath to a private Sigstore trusted_root.json, additive to the built-in public-good root

policy.minTrustLevel sets operator policy, not an org-enforced guardrail. A committed value lowers the effective floor as readily as it raises it (unknown makes the trust check a no-op, since every level meets it), so treat it as a reviewable choice rather than a control that cannot be relaxed.

A lowered floor admits any bundle whose actual trust level reaches it, which is broader than unsigned bundles. It also covers chains that legitimately degraded: an attested bundle whose binary attestation is absent, or one carrying external --data, both report attested against a verified maximum, so the default max rejects them while a lowered floor does not.

What no policy value can wave through: checksum failures, and attestations that are present but fail verification. Those are rejected regardless of the floor.

aicr verify logs the floor at INFO when config is what supplies it: that is, when --min-trust-level is absent and the configured value is anything other than max. An explicit flag takes precedence instead, and that override is logged separately by the flag-precedence path.

Every field is a durable, non-secret reference or policy value; no private key material is part of the schema. Three aicr verify flags are deliberately excluded: the bundle directory (a positional argument), --format (presentation, not policy), and --insecure-ignore-tlog, which weakens the trust floor and so stays command-line-only rather than something a committed file can silently enable. It still composes with a config-supplied trust.key.

Cross-Section Rules

  • At least one of the five spec.* sections must be present.
  • spec.recipe.criteria and spec.recipe.input.snapshot are mutually exclusive.
  • When both spec.recipe.output.path and spec.bundle.input.recipe are set, they must reference the same file (compared after filepath.Clean; mixing absolute and relative forms is rejected). Mismatched paths in a workflow file are almost always a typo, so the loader fails up-front.
  • Enum-valued fields (criteria.*, output formats, phases) are validated with the same parsers the CLI flags use, so error messages match the CLI’s.

See Also

  • CLI Reference — per-command flags and config-file-mode examples
  • Validation — validation phases and evidence workflow
  • Bundling — deployers and bundle outputs