Documentation
¶
Overview ¶
CANARY: REQ=ENG-4317; FEATURE="ProjectConfig"; ASPECT=Storage; STATUS=IMPL; UPDATED=2026-09-01
Index ¶
Constants ¶
const DefaultStaleDays = 30
DefaultStaleDays is the staleness window (in days) used when verification.staleness_days is not configured. It lives here, in the single config type, so pkg/canaryscan can reference it without pkg/config having to import pkg/canaryscan.
Variables ¶
var SourceKeyPattern = regexp.MustCompile(`^[A-Z][A-Z0-9]*$`)
SourceKeyPattern is the required shape of a requirement-ID prefix: uppercase alphanumeric starting with a letter (e.g. "CBIN", "ENG", "GH2").
Functions ¶
func ValidateProjectKey ¶ added in v0.3.3
ValidateProjectKey enforces the project.key shape rule: empty (unset) is legal, a non-empty key must match SourceKeyPattern. It is the single implementation of that rule, called both by ProjectConfig.validate (the config.Load path) and by pkg/sources.FromProjectConfig, which validates a project.key of its own -- direct construction of a *ProjectConfig (used in tests and by any caller that builds one without going through Load) never runs validate(), so FromProjectConfig cannot rely on Load having already checked it.
func ValidateSources ¶ added in v0.3.3
func ValidateSources(specs []SourceSpec) error
ValidateSources enforces the source rules: every type must be known, every key well-formed and unique, and at most one source may be the ticket destination (which must not be a flatfile source).
Types ¶
type PeerConfig ¶ added in v0.3.1
type PeerConfig struct {
Name string `yaml:"name"`
// Root is the peer project's root directory, resolved relative to
// this project's own root when not absolute. Its status.json is read
// from <Root>/status.json.
Root string `yaml:"root"`
}
PeerConfig is one peer project this repo is inter-dependent with: a sibling repo whose own `canary scan --out status.json` this project reads (read-only, never written to) to resolve requirement ids that peer owns — including ids under a prefix this project's own `sources:` list doesn't recognize at all. See pkg/external's peer-resolution layer. CANARY: REQ=ENG-3961; FEATURE="PeerProjects"; ASPECT=Storage; STATUS=TESTED; TEST=TestCANARY_ENG_3961_LoadPeers,TestCANARY_ENG_3961_LoadPeers_AbsentIsEmpty; UPDATED=2026-08-29
type ProjectConfig ¶
type ProjectConfig struct {
Project struct {
Name string `yaml:"name"`
Description string `yaml:"description"`
Key string `yaml:"key"`
} `yaml:"project"`
Sources []SourceConfig `yaml:"sources"`
// Peers lists sibling projects consulted for requirement ids this
// project doesn't own itself. Optional; empty when unconfigured.
Peers []PeerConfig `yaml:"peers"`
Requirements struct {
IDPattern string `yaml:"id_pattern"`
} `yaml:"requirements"`
Verification struct {
StalenessDays int `yaml:"staleness_days"`
} `yaml:"verification"`
Agent struct {
DefaultModel string `yaml:"default_model"`
} `yaml:"agent"`
// Evidence optionally pins the Go toolchain `canary evidence
// run-go-test` resolves and runs. ToolchainPath, when set (or overridden
// by the --toolchain-path flag), is the ONLY source of trusted,
// origin:"executed" evidence (C6-01): it is operator-named, outside the
// caller's environment. Without it, run-go-test still resolves SOME `go`
// for convenience (GOROOT/bin/go, falling back to exec.LookPath("go")),
// but that resolution is always UNTRUSTED (origin "imported") -- both
// runtime.GOROOT() and PATH search honor values the caller controls via
// its own environment, so neither can mint executed trust. ToolchainDigest,
// when set (or overridden by --toolchain-digest), is a "sha256:"+64hex
// value the resolved toolchain's digest must match -- a mismatch is
// fatal (a pinned toolchain was replaced), regardless of trust.
// TrustedKeys and SignKey are Plan-8 Task 6 additions (C6-01b/C6-02):
// TrustedKeys names a file or directory of ed25519 public keys (see
// pkg/attest.LoadPublicKeys) that `canary verify --require-attestation`
// and `canary evidence ingest --require-attestation` accept attestation
// signatures against, and that `resolvePeer` (pkg/external) requires a
// peer's signed VerificationReceipt to verify against once configured.
// SignKey names a private key (see pkg/attest.LoadPrivateKey) `canary
// scan` uses to sign its own VerificationReceipt for peers to check
// against THEIR trusted_keys. Configuring either does not, by itself,
// change any default behavior -- see pkg/attest's package doc comment
// for the honesty boundary this rests on (the private key must live
// outside the workspace to mean anything against a workspace-local
// adversary).
Evidence struct {
ToolchainPath string `yaml:"toolchain_path"`
ToolchainDigest string `yaml:"toolchain_digest"`
TrustedKeys string `yaml:"trusted_keys"`
SignKey string `yaml:"sign_key"`
} `yaml:"evidence"`
}
ProjectConfig represents the .canary/project.yaml configuration
func Load ¶
func Load(rootDir string) (*ProjectConfig, error)
CANARY: REQ=ENG-4317; FEATURE="StrictProjectConfig"; ASPECT=Storage; STATUS=TESTED; TEST=TestLoadRejectsUnknownField,TestLoadRejectsDuplicateKey,TestLoadRejectsNegativeStaleness,TestLoadRejectsBadSourceType,TestLoadRejectsMultiDocumentYAML,TestAuditF19; UPDATED=2026-08-30 Load reads, strictly parses and validates <rootDir>/.canary/project.yaml. Unknown fields, duplicate mapping keys, and invalid values are errors: a config that does not mean what it says must never be silently downgraded to defaults. A missing file is legal and yields an empty (unconfigured) config.
func (*ProjectConfig) ProjectID ¶ added in v0.3.3
func (c *ProjectConfig) ProjectID() string
ProjectID is the resolved project identifier: project.key when set, else "default".
func (*ProjectConfig) StalenessDays ¶ added in v0.3.3
func (c *ProjectConfig) StalenessDays() int
StalenessDays is the resolved staleness window in days: the configured verification.staleness_days when set, else DefaultStaleDays.
type SourceConfig ¶
type SourceConfig struct {
Name string `yaml:"name"`
Type string `yaml:"type"` // flatfile | jira | github | gitlab
Key string `yaml:"key"` // ID prefix, e.g. "CBIN", "PLAT", "GH"
URL string `yaml:"url,omitempty"`
// API is the REST base URL used by `canary ticket sync` when it differs
// from URL (which is the human browse-link template). Precedence is
// env > source.API: if JIRA_BASE_URL is set, it always wins; API is
// only consulted as a fallback when JIRA_BASE_URL is unset. Email and
// Token have no config-file fallback — they must come from
// JIRA_EMAIL/JIRA_API_TOKEN regardless of what this field holds.
API string `yaml:"api,omitempty"`
// StatusMap overrides the default CANARY-status -> remote-status-name
// mapping (STUB/IMPL/TESTED/BENCHED keys) for this source only.
StatusMap map[string]string `yaml:"status_map,omitempty"`
// Project is the ticket-system project key this source creates issues
// in and fetches remote status for (e.g. a JIRA project key). Optional;
// when unset, this source contributes no project of its own to `canary
// ticket sync`.
Project string `yaml:"project,omitempty"`
// Destination marks this source as the target for create_issue actions
// promoting flatfile requirements. At most one source may set this; see
// Registry.DestinationSource in pkg/sources for the resolution rule
// when no source is marked.
Destination bool `yaml:"destination,omitempty"`
}
SourceConfig describes one requirement-ID source: a flatfile prefix or an external ticket system (jira, github, gitlab) whose keys appear in REQ= fields. CANARY: REQ=ENG-4322; FEATURE="TicketSources"; ASPECT=Storage; STATUS=TESTED; TEST=TestCANARY_CBIN_201_LoadSources; UPDATED=2026-08-28 CANARY: REQ=CP-279; FEATURE="TicketSync"; ASPECT=Storage; STATUS=TESTED; TEST=TestCANARY_CBIN_306_LoadSources_TicketSyncFields; UPDATED=2026-08-29 CANARY: REQ=ENG-3958; FEATURE="TicketDestination"; ASPECT=Storage; STATUS=TESTED; TEST=TestCANARY_ENG_3958_LoadSources_ProjectDestinationFields; UPDATED=2026-08-29
type SourceSpec ¶ added in v0.3.3
SourceSpec is the minimal source shape ValidateSources checks. It exists so the rules have exactly one implementation, shared by config parsing and by pkg/sources' registry construction (which validates its own Source type).