Documentation
¶
Index ¶
- Constants
- Variables
- func Exists(name string) bool
- func GroupByPhase() map[string][]string
- func IsCustomDeclaration(overrides map[string]any) bool
- func List() []string
- func ListByPhase(phase string) []string
- func NewerTag(currentTag string, available []string) string
- type Option
- type OptionTOML
- type Preset
- type PresetTOML
- type PresetsFile
- type PromotionDecision
- type ScanDecision
Constants ¶
const PromotionCooldown = 14 * 24 * time.Hour
PromotionCooldown is how long a newly published version must have been publicly available before the catalogue promotes it. The monitor runs weekly, so this is roughly two cycles.
It is deliberately not a user-facing setting: the policy governs cidx's own catalogue, not the projects that use cidx, which pin whatever they want in their own cidx.toml (guardrail 5). Shortening the window is a decision to argue for in a commit, not to bury in a config file.
Variables ¶
var GlobalRegistry map[string]Preset
GlobalRegistry contains all built-in presets Loaded from presets.yaml (dev) or embedded data (production)
Functions ¶
func GroupByPhase ¶
GroupByPhase returns presets grouped by phase
func IsCustomDeclaration ¶
IsCustomDeclaration reports whether the given override section declares a brand-new container (image field present) rather than overriding an existing preset. Used by validator and runner to decide between preset-override semantics and custom-container semantics.
func ListByPhase ¶
ListByPhase returns presets filtered by phase
func NewerTag ¶ added in v2.3.0
NewerTag returns the newest tag in available that is a strictly newer version of currentTag, or "" when nothing on offer qualifies.
Qualifying means the same shape as the tag the catalogue already pins:
Same variant family — same `v` prefix, same suffix after the version. `dhi.io/golang:1.23-alpine3.21-dev` must never be offered a plain `1.24`: that is a different image on a different base, and promoting it would silently change what every Go preset runs on. The same guard keeps `-dev`, `-fips`, `-cli` and `-alpine` variants in their own lane.
Same precision. A registry publishing `0.71` and `0.71.2` offers the first to an image pinned `0.68` and the second to one pinned `0.68.1`. The number of components is a choice the catalogue made about how closely it tracks upstream, and an update is not the place to revisit it.
A currentTag carrying no version (`latest`) qualifies nothing: there is no way to tell what would be newer, and claiming an update would be a guess.
Types ¶
type Option ¶
type Option struct {
Type string `yaml:"type" toml:"type"` // string, bool, int, array
Default any `yaml:"default" toml:"default"` // Default value
Description string `yaml:"description" toml:"description"` // Help text
EnvVar string `yaml:"env_var" toml:"env_var"` // Maps to environment variable
CommandFlag string `yaml:"command_flag" toml:"command_flag"` // Maps to command flag
}
Option defines a configurable parameter for a preset
type OptionTOML ¶
type OptionTOML struct {
Type string `toml:"type"`
Default interface{} `toml:"default"`
Description string `toml:"description"`
CommandFlag string `toml:"command_flag"`
EnvVar string `toml:"env_var"`
}
OptionTOML represents an option in TOML format
type Preset ¶
type Preset struct {
Name string `yaml:"name" toml:"name"`
Phase string `yaml:"phase" toml:"phase"`
Image string `yaml:"image" toml:"image"`
Description string `yaml:"description,omitempty" toml:"description,omitempty"` // Usage notes and constraints, shown by `preset info`
Hardened bool `yaml:"hardened,omitempty" toml:"hardened,omitempty"` // Uses Docker Hardened Image (dhi.io)
Command string `yaml:"command" toml:"command"`
Entrypoint []string `yaml:"entrypoint" toml:"entrypoint"`
Workdir string `yaml:"workdir" toml:"workdir"`
Volumes []string `yaml:"volumes" toml:"volumes"`
Env map[string]string `yaml:"env" toml:"env"`
ConfigFiles []string `yaml:"config_files" toml:"config_files"`
Options map[string]Option `yaml:"options" toml:"options"`
RequireCI bool `yaml:"require_ci" toml:"require_ci"` // Requires CI environment
LocalBehavior string `yaml:"local_behavior" toml:"local_behavior"` // draft, no-push, dry-run, disabled
Privileged bool `yaml:"privileged,omitempty" toml:"privileged,omitempty"` // Requires root privileges (skip user mapping)
PullPolicy string `yaml:"pull_policy,omitempty" toml:"pull_policy,omitempty"` // always, if-not-present, never (default: env-based)
Timeout string `yaml:"timeout,omitempty" toml:"timeout,omitempty"` // duration string (e.g., "5m", "45m"), default: 30m
}
Preset defines a complete tool configuration with sensible defaults
func PresetFromOverrides ¶
PresetFromOverrides constructs a Preset from a custom container declaration in cidx.toml. A declaration is a `[containers.NAME]` section that has an `image` field present — that signals a brand-new container, not an override of a known preset. The returned Preset is filled from the overrides map; fields absent from the map keep their zero value.
This implements the user-facing contract documented in examples/cidx-complete.toml (custom containers section) and closes #142.
type PresetTOML ¶
type PresetTOML struct {
Name string `toml:"name"`
Phase string `toml:"phase"`
Image string `toml:"image"`
Description string `toml:"description"`
Hardened bool `toml:"hardened"`
Command string `toml:"command"`
Entrypoint []string `toml:"entrypoint"`
Workdir string `toml:"workdir"`
Volumes []string `toml:"volumes"`
Env map[string]string `toml:"env"`
ConfigFiles []string `toml:"config_files"`
Options map[string]OptionTOML `toml:"options"`
RequireCI bool `toml:"require_ci"`
LocalBehavior string `toml:"local_behavior"`
Privileged bool `toml:"privileged"`
PullPolicy string `toml:"pull_policy"`
Timeout string `toml:"timeout"`
}
PresetTOML represents a preset in TOML format
type PresetsFile ¶
type PresetsFile struct {
Presets map[string]PresetTOML `toml:"presets"`
}
PresetsFile represents the structure of presets.toml
type PromotionDecision ¶ added in v2.2.0
type PromotionDecision struct {
// Promote reports whether the candidate may replace the running image.
Promote bool
// Reason states why. Always set, for promotions as much as for holds — a
// candidate held for another week has to say so somewhere, or the policy
// silently swallows it.
Reason string
// WaivedFor names the vulnerabilities that bought the candidate its way
// past the cooldown. Empty when no waiver was needed, so a promotion never
// claims a waiver that did nothing.
WaivedFor []string
// AgeDays is how long the candidate has been public, in whole days. Nil
// when the registry gave no date.
AgeDays *int
}
PromotionDecision is the verdict on one candidate version, in the words the workflow summary and the promotion PR print verbatim.
func EvaluatePromotion ¶ added in v2.2.0
func EvaluatePromotion(published, now time.Time, affectingUs []string) PromotionDecision
EvaluatePromotion applies the cooldown and its exception to one candidate.
published is when the candidate became publicly available; the zero time means the registry would not say. affectingUs are the HIGH/CRITICAL vulnerabilities already recorded against the image the catalogue runs today.
An undatable candidate is held. That mirrors rule 1's treatment of an unresolvable digest: the promotion is skipped rather than taken on an assumption, and the reason is reported so it does not vanish quietly.
The exception then overrides the hold — for a young candidate and an undatable one alike. Waiting out a date that will never arrive would just leave a known vulnerability in place, and deliberately running a known-vulnerable image to guard against a hypothetical one is the worse trade. A candidate that has served the cooldown claims no waiver: it did not need one.
type ScanDecision ¶ added in v2.3.0
type ScanDecision struct {
// Promote reports whether the findings leave the candidate promotable.
Promote bool
// Reason states why — for a pass as much as for a hold. A candidate the
// scan gate holds has to say so somewhere, or the promotion silently
// swallows it, which is the failure mode #247 was about in the first place.
Reason string
// Introduces names the findings that blocked the promotion: on the
// candidate, on neither the running image's record nor the candidate's own,
// and therefore new. Empty on a pass, so a promotion never implies findings
// it does not have.
Introduces []string
}
ScanDecision is the verdict on what the monitor's scanners found on one candidate, in the words the workflow summary and the promotion PR print verbatim.
func EvaluateScan ¶ added in v2.3.0
func EvaluateScan(found, accepted []string) ScanDecision
EvaluateScan decides whether what the scanners found on a candidate blocks its promotion.
found are the HIGH/CRITICAL vulnerabilities the monitor's scanners reported against the candidate. accepted are the ones already on record for the image the catalogue runs today and for the candidate's own reference (known-vulnerabilities.toml, the file the security audit maintains).
The verdict is differential on purpose. Several catalogue images are knowingly vulnerable — that is exactly what known-vulnerabilities.toml records — so "the candidate has findings" would hold every one of them for ever, and a gate that never passes is worth as little as the one that never failed (#247). What blocks a promotion is a finding that is *new*: reported on the candidate, not already accepted on what we run today.
It follows that a candidate carrying the same vulnerabilities as the running image is promotable. It is not a regression, and refusing it would strand the catalogue on an older image over a finding the candidate merely inherited — while the update it carries goes unapplied.
Comparison is case-insensitive: Trivy spells severities and identifiers in upper case, Grype does not, and the same CVE reported by both must count once.