.nornir/ai-context.toml
# Maintained AI-context metadata for `kvasir` (docs/ai-context*.md).
# Migrated from the nornir-schema file (git history has the original).
# Facts derivable from code (crate list, deps, API, tests, markers) are NOT
# duplicated here; every file:line is validated at generation time.
config_precedence = ["Compiled defaults (constants: 1 GiB body cap, ports, page sizes).", "RON configuration file (`--config`): the authoritative graph of repositories/endpoints/auth/audit.", "Environment variables read at startup (e.g. HOLGER_DATA anchors audit/store paths; HOLGER_PROMOTE_* tune the promote engine) — override compiled defaults, NOT RON fields (they configure orthogonal knobs, not the same keys). Verified: no env var overrides a RON field.", "CLI arguments to the specific verb (e.g. holger-server-ui ENDPOINT/--token override HOLGER_TOKEN; holger-server retention/replicate/airgap flags). Unverified where a flag and an env var name the same knob — treat as `Unverified`."]
reasoning_warnings = [
"CLAUDE.md is partly stale: it says 'Promote workflow: not implemented' (it is fully wired) and 'No HTTP/REST API surface' (a full native-protocol HTTP door exists). Trust the code over CLAUDE.md on these.",
"`cargo bench` does NOT work — there are no [[bench]] targets. Benchmarks run via `nornir bench run holger` / xtask examples.",
"znippy backends return EMPTY Browse (list()) for npm/nuget/go/docker/composer in generic-reader mode — 'no results' is not 'no data'; RepositoryBackendTrait::list defaults to empty when a backend does not override it.",
"The security demo scanner (gui tier) uses a demo advisory DB; a PASS verdict may come from demo data unless the warehouse-scan feature + HOLGER_WAREHOUSE point at the real corpus.",
"auth-webauthn is a declared dependency with NO dispatch arm and is pinned by no tier — this is deliberate (2026-07-22); 'finishing' it reverses a removal and will RED the auth_ship_small link-audit.",
"Backend fetch/put are synchronous blocking I/O called directly from async handlers (no spawn_blocking) — a long archive rewrite stalls tokio workers.",
"'Immutable archives' is only true for the prod posture; znippy-rust has an opt-in writable dev-mode archive that appends under a write_lock.",
]
[output.compact]
max_tokens = 30000
max_duplicate_sentence_ratio = 0.04
max_duplicate_table_row_ratio = 0.02
[output.full]
max_tokens = 130000
max_duplicate_sentence_ratio = 0.08
max_duplicate_table_row_ratio = 0.05
[repository]
purpose = "Secure, airgap-first artifact registry (a Nexus/Artifactory replacement) whose system of record is immutable, content-addressed znippy archives. One server serves ~15 package ecosystems (Cargo, Maven, PyPI, npm, NuGet, Go, RPM, Deb, Gem, Conda, Helm, Docker/OCI, Composer, raw) over gRPC + a native-protocol HTTP door; a separate internet-side agent moves packages across the airgap as znippy archives."
system_role = "Artifact registry + airgap transfer agent + egui operator UI, feature-gated into embedded/mini/full server tiers and thin/fat UI tiers from one source tree."
language = "Rust (feature-gated workspace: embedded/mini/full server tiers, thin/fat UI tiers)"
binaries = ["holger-server", "holger-agent", "holger-server-ui", "holger-server-ui-embedded", "holger-server-ui-mini", "holger-server-ui-mikro", "holger-mannequin", "xtask"]
runtime_components = [
"Server (holger-server-lib): RON graph -> wire_holger -> 8 tonic gRPC services + a native-protocol HTTP door.",
"Repository backends (RepositoryBackendTrait) per ecosystem: znippy archives read-only; file-rust/file-oci/raw writable.",
"Agent (holger-agent-lib): Source x Target ConnectorTrait matrix with bounded upload pool and partial-success tallies.",
"Promotion: DEV->PROD content-addressed, blake3-verified seal (seal-once; withdrawal appends to lineage).",
"Airgap (holger-airgap): pure-Rust plan that shells out once to the populate driver.",
"UI (holger-server-ui, facett/egui): thin RemoteHolger gRPC client or in-process LocalHolger, sliced into gui/mini/mikro tiers.",
]
non_goals = [
"Not a general object store — artifacts are ecosystem packages with coordinates, not arbitrary blobs (except the `raw` backend).",
"Not multi-site/continuous replication — replication is a gated one-shot source→dest copy.",
"Not a mutable repository — the prod posture is append-only/immutable; only file-rust, file-oci, raw, and dev-mode writable-znippy accept writes.",
"The agent is not a proxy — it runs internet-side and produces archives; the server never reaches the internet unless a federation/online tier is built.",
"mannequin is test/dev infrastructure (mock PKI+OIDC+Nexus), never a production component.",
]
[[crate_summary]]
name = "holger-traits"
summary = "[contracts] RepositoryBackendTrait, ConnectorTrait, HolgerObject, ArtifactId/Format, znippy format-version pin. A znippy API change breaks the whole workspace via [patch.crates-io]."
[[crate_summary]]
name = "holger-server-lib"
summary = "[server-core] Wiring engine, 8 gRPC services, HTTP door, auth, audit, promote, retention, replication, raw. Central high-coupling crate."
[[crate_summary]]
name = "holger"
summary = "[server-core] The holger-server binary; tier compile_error! guard lives here. default-features=false on server-lib (the airgap keystone)."
[[crate_summary]]
name = "holger-rust-znippy-repository"
summary = "[storage-backends] Only backend that consumes the FormatGate reader pin and overrides has_archive; only one with a writable dev-mode archive."
[[crate_summary]]
name = "holger-znippy-npm-repository"
summary = "[storage-backends] packument is view-only — generic-reader ingestion 404s the packument (breaks `npm install`)."
[[crate_summary]]
name = "holger-znippy-package-repository"
summary = "[storage-backends] Holger-native znippy surface; opt-in CMS provenance verify behind `sign`."
[[crate_summary]]
name = "holger-agent-lib"
summary = "[agent-transfer] operations.rs: transfer/push/pull with bounded concurrency and partial-success tallies."
[[crate_summary]]
name = "holger-world-connector"
summary = "[connectors] External registries (crates.io/PyPI); SSRF host allowlist; list_assets bails (lockfile-driven)."
[[crate_summary]]
name = "holger-airgap"
summary = "[airgap] Pure-Rust plan/argv; one shell-out to distribution/airgap/populate."
[[crate_summary]]
name = "holger-server-ui"
summary = "[ui] facett/egui; thin RemoteHolger or in-process LocalHolger; gui/mini/mikro tiers guarded by tier_ladder.rs."
[[crate_summary]]
name = "holger-demo"
summary = "[ui] facett-wasm demo harness; NOT part of any server tier."
[[crate_summary]]
name = "holger-mannequin"
summary = "[test-infra] Mock PKI+OIDC+Nexus in one process. Test/dev only — never production."
[[crate_summary]]
name = "holger-bench-scenarios"
summary = "[benchmarks] No [[bench]] targets exist; real path is `nornir bench run holger` / xtask examples."
[[crate_summary]]
name = "holger-build-space"
summary = "[dev-tooling] build-variants.toml + tier link-audits (auth_ship_small: webauthn/openssl must NOT link)."
[[crate_summary]]
name = "xtask"
summary = "[dev-tooling] gen-proto (protox+tonic-build, committed output), demo-wasm/deploy-pages."
[[wiring]]
capability = "Config load + graph wiring"
interface = "RON `Holger` root"
implementation = "server/lib/src/lib.rs:355"
registration = "server/lib/src/lib.rs:113"
configuration = "--config <file.ron>; repositories/exposed_endpoints/storage_endpoints/auth/audit"
tests = "server/lib/tests/graceful_backend_init.rs"
status = "Runtime wired"
[[wiring]]
capability = "Repository backend registration"
interface = "RepositoryBackendTrait"
implementation = "server/lib/src/repository.rs:207"
registration = "server/lib/src/repository.rs:186"
configuration = "ron_repo_type match: rust|rust-remote|maven3|pip|npm|nuget|go|gem|deb|rpm|helm|docker|oci|raw|conda|composer|group|znippy|{nexus,artifactory,azure,aws}-remote — status note: one failing repo is disabled, hard-fail only if ALL fail"
tests = "server/lib/tests/graceful_backend_init.rs"
status = "Runtime wired"
[[wiring]]
capability = "gRPC services (8)"
interface = "tonic services"
implementation = "server/lib/src/grpc/services.rs"
registration = "server/lib/src/lib.rs:1084"
configuration = "ExposedEndpoint.ron_url (bare SocketAddr); per-service body caps = ron_max_body_bytes — status note: Repository, Archive, Admin, Promotion, Search, Sbom, Property, Replication"
tests = "server/lib/tests/integration_oci_tls.rs"
status = "Runtime wired"
[[wiring]]
capability = "HTTP door (native package protocols + OCI)"
interface = "package-client HTTP/2"
implementation = "server/lib/src/exposed/http.rs"
registration = "server/lib/src/lib.rs:889"
configuration = "ExposedEndpoint.ron_http_url; /healthz /readyz /metrics open; /-/search /-/sbom /-/properties — status note: CLAUDE.md wrongly says 'No HTTP/REST API surface'"
tests = "server/lib/tests/integration_oci_tls.rs"
status = "Runtime wired"
[[wiring]]
capability = "Authentication"
interface = "nornir_service::AuthProvider (edda)"
implementation = "server/lib/src/auth.rs"
registration = "server/lib/src/auth.rs:445"
configuration = "auth.methods: Oidc|OAuth2|Mtls|StaticToken; provider must be feature-pinned by the tier — status note: bearer+mTLS all tiers, OIDC/OAuth2 full+default only. WebAuthn dep present but NOT dispatched (deliberate)."
tests = "server/lib/src/auth.rs"
status = "Runtime wired"
[[wiring]]
capability = "Authorization (RBAC)"
interface = "Role floor (Denied<Reader<Writer<Admin)"
implementation = "server/lib/src/auth.rs"
registration = "server/lib/src/grpc.rs:244"
configuration = "auth.roles/default_role/repo_roles; require_auth_for_reads (default false) — status note: writes fail-closed when RBAC configured; reads open unless require_auth_for_reads; admin for promote/delete/replicate"
tests = "server/lib/src/grpc.rs"
status = "Runtime wired"
[[wiring]]
capability = "Audit logging"
interface = "audit::AuditLog trait"
implementation = "server/lib/src/audit/arrow_ipc.rs"
registration = "server/lib/src/grpc.rs:218"
configuration = "audit.dir (default holger-audit under $HOLGER_DATA); enabled (default true) — status note: append-only Arrow IPC, 0700/0600. Open failure ⇒ NoopAuditLog fallback (fail-open, loud)."
tests = "server/lib/src/audit/arrow_ipc.rs"
status = "Runtime wired"
[[wiring]]
capability = "Promotion (DEV→PROD seal)"
interface = "PromotionEngine"
implementation = "server/lib/src/promote/mod.rs"
registration = "server/lib/src/lib.rs:971"
configuration = "HOLGER_PROMOTE_ENFORCE/_ADVISORY_DB/_DENY_LICENSES/_REQUIRE_PROPERTY; prod store <data_root>/holger-prod-store — status note: CLAUDE.md wrongly says 'not implemented'"
tests = "server/lib/src/promote/mod.rs"
status = "Runtime wired"
[[wiring]]
capability = "Retention / GC"
interface = "retention policy scan"
implementation = "server/lib/src/lib.rs:637"
registration = "server/cli/src/main.rs"
configuration = "holger-server retention --keep-last-n/--max-age-secs/--max-total-bytes/--execute (dry-run default) — status note: deletes audited as ident holger-retention-gc"
tests = "server/lib/tests/retention_executor.rs"
status = "Runtime wired"
[[wiring]]
capability = "Replication"
interface = "replication::replicate_pairs"
implementation = "server/lib/src/replication.rs:168"
registration = "server/lib/src/grpc/services.rs:1296"
configuration = "holger-server replicate --from --to [--execute] (dry-run default); ReplicationService.Replicate (admin-gated) — status note: one-shot, sha256-idempotent skip, admin fail-closed. Continuous/multi-site NOT built."
tests = "server/lib/src/replication.rs"
status = "Runtime wired"
[[wiring]]
capability = "Airgap populate"
interface = "PopulateArgs plan"
implementation = "airgap/src/lib.rs"
registration = "server/cli/src/main.rs"
configuration = "holger-server airgap --stack/--scale/--target/--auth (mtls reuses connect cert); shells distribution/airgap/populate — status note: pure-Rust plan; single shell-out boundary; --dry-run returns before driver discovery"
tests = "airgap/src/lib.rs"
status = "Runtime wired"
[[wiring]]
capability = "UI local vs remote"
interface = "HolgerObject"
implementation = "server/lib/src/object.rs"
registration = "server/ui/src/data.rs"
configuration = "holger-server-ui ENDPOINT/--token/--ca/--cert/--key; --demo builds in-process LocalHolger — status note: RemoteHolger (tonic + bearer interceptor) or LocalHolger (direct backend calls"
tests = "server/ui/tests/remote_grpc.rs"
status = "Runtime wired"
[[wiring]]
capability = "Build tiers"
interface = "cargo features"
implementation = "holger-recipe/src/variants.rs"
registration = "server/cli/src/main.rs"
configuration = "server: --no-default-features --features embedded|mini|full; ui: gui|gui-embedded|gui-mini|gui-mikro — status note: mutually-exclusive server tiers (compile_error! guard); link-audited by auth_ship_small.rs"
tests = "holger-recipe/tests/toml_parity.rs"
status = "Runtime wired"
[[wiring]]
capability = "Cloud-marketplace fulfilment (landing + webhook)"
interface = "marketplace::FulfilmentApi (resolve/activate/get_subscription/get_operation/update_operation) + MarketplaceState (fulfil/lifecycle) + signin::{SsoConfig, WebhookAuth}"
implementation = "server/lib/src/marketplace/mod.rs:919"
registration = "server/lib/src/exposed/http.rs:552"
configuration = "RON `marketplace` block: publisher_tenant_id (alias tenant_id)/client_id/sso_client_id/console_url/public_url/require_buyer_sign_in(true)/webhook_require_jwt(true)/public_base_url({subscription} template)/tenants_dir(holger-tenants)/port_base(20000)/bind_host(127.0.0.1)/plans{planId: (display_name, repos:[RepoSpec])}/token_url/api_url/authorize_url/sso_token_url/sso_jwks(_uri)/webhook_jwks(_uri)/trusted_proxies/rate_limit_per_minute(30)/webhook_rate_limit_per_minute(300)/global_rate_limit_per_minute(600); + env HOLGER_MARKETPLACE_CLIENT_SECRET (the fulfilment app) and HOLGER_MARKETPLACE_SSO_CLIENT_SECRET (the SSO app; falls back to the first when the apps are one) — never RON; block present + a secret absent, a plan that does not validate, sign-in required without public_url, or a build without `online`/`auth-oidc` ⇒ boot error holger-marketplace-7 — status note (rewritten after the 2026-09-04 security review): doors GET /-/marketplace/landing (parks the token, 303 to Entra sign-in), GET /-/marketplace/callback (id_token verified — issuer = its own tid, aud = the SSO app, nonce — the signer's directory MUST be the subscription's beneficiary, then resolve · provision · activate; the signer is rendered Admin), POST /-/marketplace/landing (the API exchange, id_token required) and POST /-/marketplace/webhook (Microsoft's Entra bearer verified FIRST, then GET operation, then applied; Unsubscribe/Suspend/Reinstate/Renew reconciled with GET subscription and never PATCHed; ChangePlan/ChangeQuantity PATCH-acked BEFORE the row commits; applied_operations makes re-delivery idempotent; unknown subscription: Subscribe provisions, notify-only ignored 200, ack-required failed + 404) mounted ONLY with block + secrets; no block ⇒ 404. Purchase tokens single-use HERE (<tenants_dir>/.spent-tokens/<blake3>, checked before the marketplace is asked). One tenant = one rendered RON graph + storage roots + audit dir under <tenants_dir>/<subscription-id>/ (tenant.ron create-once + atomic via hard_link, holger.ron via provision::Manifest, auth pinned to the buyer's Entra issuer, reads gated, the row's admins as Admin). Rate-limited per door + globally BEFORE the body is read, keyed by X-Forwarded-For only behind declared trusted_proxies. Never starts a tenant process — the supervisor reads the ledger (NOT in tree). Listing/marketing page NOT built; metering NOT built."
tests = "server/lib/tests/marketplace_fulfilment.rs"
status = "Runtime wired"
[[capability]]
plane = "Ecosystem"
capability = "Cargo/Rust"
read = "Yes"
write_act = "Partial"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: Yes; proxy upstream: Feature-gated; generic-fetch: Yes; browse: Yes"
limitation = "cargo publish only on writable dev-mode znippy archive (static archive → 403); file backend has no publish (config.json api:null); rust-remote proxy needs `online`"
evidence = "server/repository/znippy-rust/src/lib.rs; server/repository/file-rust/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Maven"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "no timestamped unique-build snapshots; empty typed view falls back to .jar filename parse (non-jar files invisible to fallback)"
evidence = "server/repository/znippy-maven/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Python/PyPI"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "PEP 503 HTML + PEP 691 at explicit /simple/{name}/json (no Accept negotiation); layout fixed at packages/{norm}/{file}"
evidence = "server/repository/znippy-python/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "npm"
read = "Partial"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Partial; browse: Partial"
limitation = "packument is VIEW-ONLY: a generic-reader (flat-file ingested) archive 404s the packument, breaking `npm install`; tarball exact-path still serves; no archive_files/archive_info"
evidence = "server/repository/znippy-npm/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "NuGet"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No"
limitation = "only PackageBaseAddress (flat container) — no Registrations/Search ⇒ exact-version pulls only; list() empty; no archive view"
evidence = "server/repository/znippy-nuget/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Go"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No"
limitation = "@v/list synthesized from .zip scan; versions with only .info/.mod are invisible in list; list() empty; no archive view"
evidence = "server/repository/znippy-go/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "RPM"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "repomd.xml+primary.xml(.gz) synthesized (no filelists/other.xml); a chain view and an archive-backed repository sign repodata/repomd.xml.asc under the box's repository key (dnf repo_gpgcheck=1, gpgkey=/-/repo-key.asc); meta from typed view → native binary header parse (64 MiB cap) → filename NEVRA epoch=0"
evidence = "server/repository/znippy-rpm/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Debian/APT"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "Packages+Release synthesized (real SHA256); control from typed view → native ar+control.tar parse → filename; Packages.gz written once; a chain view and an archive-backed repository sign InRelease + Release.gpg under the box's repository key (holger repo-key create, public key at /-/repo-key.asc, apt signed-by=), unsigned without one"
evidence = "server/repository/znippy-deb/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "RubyGems"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "real compact-index (info/{name} checksum = real sha256); empty without the typed view; no legacy specs.4.8 API"
evidence = "server/repository/znippy-gem/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Conda"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Partial"
limitation = "repodata.json per subdir (real sha256 + blake3); .conda (v2) packages NOT in the synthesized index (packages.conda always {})"
evidence = "server/repository/znippy-conda/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Helm"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "classic (non-OCI) repo; index.yaml passthrough wins else generated; root-level tgz URLs only"
evidence = "server/repository/znippy-helm/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Docker/OCI"
read = "Yes"
write_act = "Yes"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough+Synthesized; znippy backend: Partial; writable: Yes; proxy upstream: —; generic-fetch: Yes; browse: Yes"
limitation = "file-oci is a full writable Distribution-v2 registry (chunked/monolithic push, digest-verified); the znippy-docker backend is READ-ONLY GET-only (no push/HEAD, list() empty, no referrers)"
evidence = "server/repository/file-oci/src/lib.rs; server/repository/znippy-docker/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "Composer"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: Passthrough; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No"
limitation = "pure passthrough — archive must already carry Composer v2 metadata; only packages.json emitted inline; no synthesis from bare zips; list() empty"
evidence = "server/repository/znippy-composer/src/lib.rs"
[[capability]]
plane = "Ecosystem"
capability = "raw"
read = "Yes"
write_act = "Yes"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: No; znippy backend: No; writable: Yes; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "path IS the address (version-less coords); PUT/POST/DELETE, sha256-verified delete; the ONLY backend implementing coordinate_for_path (so only raw HTTP serves are quarantine-gated by coordinate)"
evidence = "server/lib/src/raw.rs"
[[capability]]
plane = "Ecosystem"
capability = "Znippy-native"
read = "Yes"
write_act = "No"
human_approval = "No"
runtime_wired = "Yes"
persistence = "native index: No; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes"
limitation = "Holger-native surface (no ecosystem protocol); optional CMS provenance verify behind `sign` (ron_trusted_roots) — without `sign` a trusted-roots config fails wiring closed"
evidence = "server/repository/znippy-package/src/lib.rs"
[[invariant]]
id = "connector-same-origin"
statement = "nexus/artifactory credentials only ever attach to a request whose scheme+host+port equals the configured base; cross-origin downloadUrls are refused before any request is built."
strength = "Enforced"
enforced = ["agent/connector/nexus/src/lib.rs:131", "agent/connector/artifactory/src/lib.rs:125"]
tests = ["agent/connector/nexus/src/lib.rs", "agent/connector/artifactory/src/lib.rs"]
break_risk = "Adding 'helpful' CDN support that follows an off-origin downloadUrl, or recreating a client without Policy::none() (three copies exist, no shared constructor)."
[[invariant]]
id = "world-ssrf-allowlist"
statement = "The world connector downloads only https URLs whose host is in the CDN allowlist (crates.io, static.crates.io, pypi.org, files.pythonhosted.org)."
strength = "Enforced"
enforced = ["agent/connector/world/src/lib.rs:76"]
tests = ["agent/connector/world/src/lib.rs:220"]
break_risk = "Adding a mirror host without review, or moving the check after client.get()."
[[invariant]]
id = "no-traversal"
statement = "Untrusted paths (upstream asset paths, archive members, raw relpaths, sbom/property coords, promote to_repo) are component-validated or sanitized to a single segment before any filesystem join."
strength = "Enforced"
enforced = ["agent/lib/src/operations.rs:108", "server/lib/src/raw.rs:60", "server/lib/src/promote/mod.rs:214"]
tests = ["agent/lib/src/operations.rs", "server/lib/src/raw.rs", "server/lib/src/promote/mod.rs"]
break_risk = "A new coordinate→path join that skips the module-local sanitizer (each module has its own copy — there is no single choke point)."
[[invariant]]
id = "promote-seal-once"
statement = "A (to_repo, coord) is sealed into the PROD store exactly once via create_new; the loser of a race gets AlreadyPromoted and writes nothing."
strength = "Enforced"
enforced = ["server/lib/src/promote/mod.rs:578"]
tests = ["server/lib/src/promote/mod.rs"]
break_risk = "Switching to File::create/overwrite 'for idempotence'."
[[invariant]]
id = "withdraw-is-append"
statement = "Withdrawal appends a Withdrawn entry to the lineage log; the sealed blob and ref are never touched. Current state is derived by replaying history."
strength = "Enforced"
enforced = ["server/lib/src/promote/stages.rs:289"]
tests = ["server/lib/src/promote/mod.rs"]
break_risk = "An 'undo'/delete feature that removes refs instead of appending."
[[invariant]]
id = "format-version-pin"
statement = "A znippy archive recording a format version above MAX_SUPPORTED_ZNIPPY_FORMAT (=3) or non-numeric is refused — at open (repo disabled, server serves on) and per-request (503 + reason)."
strength = "Enforced"
enforced = ["traits/src/znippy_format.rs:61"]
tests = ["server/repository/znippy-rust/tests/format_version_gate.rs"]
break_risk = "Bumping the pin without a matching reader; only znippy-rust wires the gate, so a hostile archive in another backend relies on znippy-common's internal check instead."
[[invariant]]
id = "read-gate-opt-in-fail-closed"
statement = "require_auth_for_reads defaults false (open reads); when true, no identity ⇒ 401, denied role ⇒ 403, health stays open, and gate-with-no-auth-methods refuses everything (warned at boot)."
strength = "Enforced"
enforced = ["server/lib/src/auth.rs", "server/lib/src/grpc.rs:350"]
tests = ["server/lib/src/grpc.rs", "server/lib/src/exposed/http.rs"]
break_risk = "A new read door that skips authorize_read (the exact StreamArtifact-quarantine bug pattern)."
[[invariant]]
id = "write-gate-fail-closed"
statement = "Writes require authentication (plus RBAC when policy is configured) on BOTH gRPC and HTTP, checked before the body is collected; a read-only repo returns 403 pre-body."
strength = "Enforced"
enforced = ["server/lib/src/grpc.rs:244", "server/lib/src/exposed/http.rs"]
tests = ["server/lib/src/grpc.rs"]
break_risk = "Mounting a new write route before the gate, or collecting the body before authorizing."
[[invariant]]
id = "audit-append-only"
statement = "The audit log is one fresh Arrow-IPC segment per process, only appended; replay skips a corrupt segment without losing intact ones."
strength = "Enforced"
enforced = ["server/lib/src/audit/arrow_ipc.rs"]
tests = ["server/lib/src/audit/arrow_ipc.rs"]
break_risk = "A 'compaction' step that rewrites segments, or a replay that aborts on the first corrupt record."
[[invariant]]
id = "transfer-partial-success"
statement = "Agent transfer/push operations return Ok(()) even when individual assets failed to download or upload; the failure count is data (stdout tallies), not an error. Callers must inspect the tally, not just the Result."
strength = "Enforced"
enforced = ["agent/lib/src/operations.rs"]
tests = ["agent/lib/src/operations.rs"]
break_risk = "Assuming Ok means every asset transferred; or 'fixing' it to bail on first failure, which changes airgap dump semantics (one archive per repo exists to avoid truncation data-loss)."
[[invariant]]
id = "tier-mutual-exclusion"
statement = "The server tiers embedded/mini/full are mutually exclusive; a compile_error! guard enforces it, and link-audits assert forbidden crates (webauthn, openssl) never link into a tier."
strength = "Enforced"
enforced = ["server/cli/src/main.rs", "holger-recipe/src/lib.rs"]
tests = ["build-space/tests/auth_ship_small.rs", "holger-recipe/tests/toml_parity.rs"]
break_risk = "Adding a dependency that pulls egress/crypto into the zero-egress mini/embedded tiers; enabling a feature that crosses tiers."
[[invariant]]
id = "storage-endpoint-is-stub"
statement = "StorageEndpoint::backend_from_config is a documented no-op; the live backend hangs off Repository, not StorageEndpoint. Editing storage/mod.rs changes nothing at runtime."
strength = "Enforced"
enforced = ["server/lib/src/storage/mod.rs", "server/lib/src/repository.rs"]
tests = []
break_risk = "An agent 'implementing storage' in storage/mod.rs and expecting it to take effect."
[[invariant]]
id = "sec-ssrf-world-connector"
statement = "Download URLs from upstream JSON must be https + host-allowlisted before any request"
strength = "Enforced"
enforced = ["agent/connector/world/src/lib.rs:76"]
tests = ["agent/connector/world/src/lib.rs:220"]
break_risk = "Agent fetches attacker URLs (cloud metadata, internal services)"
[[invariant]]
id = "sec-ssrf-credential-exfil-nexus-artifactory"
statement = "Registry-supplied downloadUrl must be same scheme+host+port as base before creds attach"
strength = "Enforced"
enforced = ["agent/connector/nexus/src/lib.rs:131", "agent/connector/artifactory/src/lib.rs:125"]
tests = ["agent/connector/nexus/src/lib.rs", "agent/connector/artifactory/src/lib.rs"]
break_risk = "Basic/Bearer creds leak to arbitrary hosts"
[[invariant]]
id = "sec-redirect-disabling"
statement = "All connector HTTP clients use redirect::Policy::none() — only the initial URL is vetted"
strength = "Enforced"
enforced = ["agent/connector/world/src/lib.rs", "agent/connector/nexus/src/lib.rs", "agent/connector/artifactory/src/lib.rs"]
tests = []
break_risk = "A 3xx from a compromised allowlisted host bypasses the origin guard and smuggles creds (no redirect-following test exists — Unverified)"
[[invariant]]
id = "sec-unbounded-read"
statement = "Response bodies capped (8 GiB artifact / 256 MiB JSON); tar entries capped 8 GiB (MAX_TAR_ENTRY_BYTES)"
strength = "Enforced"
enforced = ["agent/connector/world/src/lib.rs:38", "agent/lib/src/operations.rs:30"]
tests = []
break_risk = "Malicious upstream/archive OOMs the agent (no direct cap-trip test — Unverified)"
[[invariant]]
id = "sec-server-body-cap"
statement = "put payloads capped (default 1 GiB, ron_max_body_bytes; shared gRPC/HTTP knob)"
strength = "Enforced"
enforced = ["server/lib/src/grpc.rs:41", "server/lib/src/exposed/http.rs:642"]
tests = ["server/lib/src/grpc.rs"]
break_risk = "Upload DoS"
[[invariant]]
id = "sec-path-traversal-agent"
statement = "Upstream asset + archive member paths reject absolute/Prefix/.. per-component"
strength = "Enforced"
enforced = ["agent/lib/src/operations.rs:108"]
tests = ["agent/lib/src/operations.rs"]
break_risk = "RCE on the agent host via file drop outside the destination"
[[invariant]]
id = "sec-path-traversal-server"
statement = "Raw relpaths reject empty/./../backslash/NUL; sbom/property coords sanitized; promote to_repo sanitized to one segment"
strength = "Enforced"
enforced = ["server/lib/src/raw.rs:60", "server/lib/src/promote/mod.rs:214"]
tests = ["server/lib/src/raw.rs", "server/lib/src/promote/mod.rs"]
break_risk = "Read/write outside the store roots"
[[invariant]]
id = "sec-atomic-writes"
statement = "temp+rename for raw puts, promote blobs, properties, sbom"
strength = "Enforced"
enforced = ["server/lib/src/raw.rs:113", "server/lib/src/promote/mod.rs:583"]
tests = ["server/lib/src/raw.rs"]
break_risk = "Torn files served as artifacts"
[[invariant]]
id = "sec-immutable-promote-seal"
statement = "A (to_repo, coord) seals exactly once via create_new; re-promote refused, race-safe"
strength = "Enforced"
enforced = ["server/lib/src/promote/mod.rs:578"]
tests = ["server/lib/src/promote/mod.rs"]
break_risk = "PROD overwrite / supply-chain tamper"
[[invariant]]
id = "sec-withdrawal-append"
statement = "Withdraw appends a Withdrawn lineage entry; blob+ref never touched; state is a history replay"
strength = "Enforced"
enforced = ["server/lib/src/promote/stages.rs:289"]
tests = ["server/lib/src/promote/mod.rs"]
break_risk = "Sealed history rewritten"
[[invariant]]
id = "sec-content-hashing-integrity"
statement = "promote store blake3 (address + re-verify on fetch); cargo cksum + raw delete + replication dedup via nornir_hash::sha256_hex"
strength = "Enforced"
enforced = ["server/lib/src/promote/mod.rs:575", "server/lib/src/replication.rs:40"]
tests = ["server/lib/src/promote/mod.rs"]
break_risk = "Tampered blob served"
[[invariant]]
id = "sec-writable-znippy-locking"
statement = "Writable-archive put is read-modify-write under write_lock serializing contains-check + append"
strength = "Enforced"
enforced = ["server/repository/znippy-rust/src/lib.rs:59"]
tests = ["server/repository/znippy-rust/src/lib.rs"]
break_risk = "Two concurrent puts corrupt the .znippy"
[[invariant]]
id = "sec-znippy-format-version-pin"
statement = "Archive recording version > MAX_SUPPORTED_ZNIPPY_FORMAT (=3) or non-numeric is refused at open and per-request (503)"
strength = "Enforced"
enforced = ["traits/src/znippy_format.rs:61"]
tests = ["server/repository/znippy-rust/tests/format_version_gate.rs"]
break_risk = "A future archive crashes/mis-parses the reader. NOTE: only znippy-rust consumes this gate; other znippy backends rely on znippy-common's internal check."
[[invariant]]
id = "sec-audit-permissions"
statement = "Audit dir 0700, segments 0600, never rewritten"
strength = "Enforced"
enforced = ["server/lib/src/audit/arrow_ipc.rs:71"]
tests = []
break_risk = "Local users read principal identities / access patterns (no perms-assertion test — Unverified)"
[[invariant]]
id = "sec-error-leak-prevention"
statement = "Backend errors laundered to opaque 'internal error'; detail only in server log; quarantine served as not_found"
strength = "Enforced"
enforced = ["server/lib/src/grpc.rs:47", "server/lib/src/grpc/services.rs:90"]
tests = ["server/lib/src/grpc.rs"]
break_risk = "Archive/file paths and internals leak to anonymous readers (redaction itself Unverified)"
[[invariant]]
id = "sec-quarantine-gate"
statement = "A quarantined artifact is refused at every serve door as not_found (existence not leaked)"
strength = "Enforced"
enforced = ["server/lib/src/grpc/services.rs:90"]
tests = ["server/lib/src/grpc.rs"]
break_risk = "Quarantined/withdrawn artifact still served; existence oracle"
[[security]]
concern = "SSRF (world connector)"
invariant_id = "sec-ssrf-world-connector"
boundary = "Download URLs from upstream JSON must be https + host-allowlisted before any request"
consequence = "Agent fetches attacker URLs (cloud metadata, internal services)"
[[security]]
concern = "SSRF + credential exfil (nexus/artifactory)"
invariant_id = "sec-ssrf-credential-exfil-nexus-artifactory"
boundary = "Registry-supplied downloadUrl must be same scheme+host+port as base before creds attach"
consequence = "Basic/Bearer creds leak to arbitrary hosts"
[[security]]
concern = "Redirect disabling"
invariant_id = "sec-redirect-disabling"
boundary = "All connector HTTP clients use redirect::Policy::none() — only the initial URL is vetted"
consequence = "A 3xx from a compromised allowlisted host bypasses the origin guard and smuggles creds (no redirect-following test exists — Unverified)"
[[security]]
concern = "Unbounded read"
invariant_id = "sec-unbounded-read"
boundary = "Response bodies capped (8 GiB artifact / 256 MiB JSON); tar entries capped 8 GiB (MAX_TAR_ENTRY_BYTES)"
consequence = "Malicious upstream/archive OOMs the agent (no direct cap-trip test — Unverified)"
[[security]]
concern = "Server body cap"
invariant_id = "sec-server-body-cap"
boundary = "put payloads capped (default 1 GiB, ron_max_body_bytes; shared gRPC/HTTP knob)"
consequence = "Upload DoS"
[[security]]
concern = "Path traversal (agent)"
invariant_id = "sec-path-traversal-agent"
boundary = "Upstream asset + archive member paths reject absolute/Prefix/.. per-component"
consequence = "RCE on the agent host via file drop outside the destination"
[[security]]
concern = "Path traversal (server)"
invariant_id = "sec-path-traversal-server"
boundary = "Raw relpaths reject empty/./../backslash/NUL; sbom/property coords sanitized; promote to_repo sanitized to one segment"
consequence = "Read/write outside the store roots"
[[security]]
concern = "Atomic writes"
invariant_id = "sec-atomic-writes"
boundary = "temp+rename for raw puts, promote blobs, properties, sbom"
consequence = "Torn files served as artifacts"
[[security]]
concern = "Immutable promote seal"
invariant_id = "sec-immutable-promote-seal"
boundary = "A (to_repo, coord) seals exactly once via create_new; re-promote refused, race-safe"
consequence = "PROD overwrite / supply-chain tamper"
[[security]]
concern = "Withdrawal = append"
invariant_id = "sec-withdrawal-append"
boundary = "Withdraw appends a Withdrawn lineage entry; blob+ref never touched; state is a history replay"
consequence = "Sealed history rewritten"
[[security]]
concern = "Content hashing / integrity"
invariant_id = "sec-content-hashing-integrity"
boundary = "promote store blake3 (address + re-verify on fetch); cargo cksum + raw delete + replication dedup via nornir_hash::sha256_hex"
consequence = "Tampered blob served"
[[security]]
concern = "Writable znippy locking"
invariant_id = "sec-writable-znippy-locking"
boundary = "Writable-archive put is read-modify-write under write_lock serializing contains-check + append"
consequence = "Two concurrent puts corrupt the .znippy"
[[security]]
concern = "znippy format-version pin"
invariant_id = "sec-znippy-format-version-pin"
boundary = "Archive recording version > MAX_SUPPORTED_ZNIPPY_FORMAT (=3) or non-numeric is refused at open and per-request (503)"
consequence = "A future archive crashes/mis-parses the reader. NOTE: only znippy-rust consumes this gate; other znippy backends rely on znippy-common's internal check."
[[security]]
concern = "Audit permissions"
invariant_id = "sec-audit-permissions"
boundary = "Audit dir 0700, segments 0600, never rewritten"
consequence = "Local users read principal identities / access patterns (no perms-assertion test — Unverified)"
[[security]]
concern = "Error-leak prevention"
invariant_id = "sec-error-leak-prevention"
boundary = "Backend errors laundered to opaque 'internal error'; detail only in server log; quarantine served as not_found"
consequence = "Archive/file paths and internals leak to anonymous readers (redaction itself Unverified)"
[[security]]
concern = "Quarantine gate"
invariant_id = "sec-quarantine-gate"
boundary = "A quarantined artifact is refused at every serve door as not_found (existence not leaked)"
consequence = "Quarantined/withdrawn artifact still served; existence oracle"
[[failure]]
operation = "Config parsing (RON)"
fatal = "yes — malformed RON aborts startup via ?"
partial = "no"
retry = "none"
cleanup = "nothing written yet"
degraded = ""
observable = "stderr + non-zero exit"
evidence = "server/lib/src/lib.rs"
[[failure]]
operation = "Graph wiring (wire_holger)"
fatal = "yes on structural errors"
partial = "no — the graph is built once, then frozen (raw pointers, never mutated)"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "startup error"
evidence = "server/lib/src/lib.rs"
[[failure]]
operation = "Backend initialization"
fatal = "only if ALL repos fail"
partial = "yes — a failing repo is disabled + logged, the rest serve; the disabled repo is absent from FastRoutes (per-request not_found)"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "log::error per repo + warn summary"
evidence = "server/lib/tests/graceful_backend_init.rs"
[[failure]]
operation = "gRPC / HTTP bind"
fatal = "yes — a bind failure on an endpoint aborts that endpoint's task"
partial = "endpoints are independent tasks"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "startup error / task log"
evidence = "server/lib/src/lib.rs"
[[failure]]
operation = "Authentication"
fatal = "no — per-request only"
partial = "n/a"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "gRPC unauthenticated / HTTP 401; refusals audited as the attempted subject"
evidence = "server/lib/src/auth.rs"
[[failure]]
operation = "Authorization"
fatal = "no — per-request"
partial = "n/a"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "gRPC permission_denied / HTTP 403; read-only repo write → 403 pre-body"
evidence = "server/lib/src/grpc.rs"
[[failure]]
operation = "Audit sink init"
fatal = "no — falls back to NoopAuditLog"
partial = "audit silently off after a loud error (availability > audit)"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "log::error 'audit DISABLED'"
evidence = "server/lib/src/lib.rs"
[[failure]]
operation = "Audit event write"
fatal = "no — never fails the request"
partial = "the event line is lost"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "log::warn 'audit record failed'"
evidence = "server/lib/src/grpc.rs"
[[failure]]
operation = "Connector repository/asset listing"
fatal = "yes — a list error aborts the operation (dump_all_repos: a repo task Err or list_assets Err is fatal)"
partial = "no"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "CLI error"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Connector download"
fatal = "no (in most transfer ops)"
partial = "yes — a failed download is counted + skipped; the op still returns Ok with a nonzero failed tally"
retry = "none (no backoff anywhere in connectors)"
cleanup = "n/a"
degraded = ""
observable = "stdout tally 'N downloaded, M failed'"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Agent archive creation (pack)"
fatal = "yes — a source read failure is fatal for pack_directory_to_znippy"
partial = "transfer_to_* count download failures but a channel/tar-append failure is fatal"
retry = "none"
cleanup = "non-atomic (File::create directly, no temp+rename)"
degraded = ""
observable = "stdout tally / CLI error"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Agent upload (push)"
fatal = "source-read fatal; decode over-cap short-circuits"
partial = "yes — per-asset upload failure counted (UploadOutcome::Failed); unsafe member path counted-skipped; Ok(()) with a nonzero tally"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "per-item ✓/✗ + '✅ N succeeded, M failed'"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Archive unpack"
fatal = "unpack_tar_zstd: read_capped over-cap is fatal"
partial = "unpack_znippy: hostile path/extract failure counted, but the op BAILS at the end if failed>0 (the one push/pull that surfaces failure as an error)"
retry = "none"
cleanup = "non-atomic writes; safe_join blocks traversal"
degraded = ""
observable = "stdout tally + non-zero exit for unpack_znippy"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Archive conversion (znippy↔tar-zstd)"
fatal = "yes on decode/read error"
partial = "staged through a tempdir"
retry = "none"
cleanup = "tempdir dropped"
degraded = ""
observable = "CLI error"
evidence = "agent/lib/src/operations.rs"
[[failure]]
operation = "Repository fetch"
fatal = "no — a miss is Ok((404,…)), never Err; backend errors are laundered to opaque 'internal error'"
partial = "n/a"
retry = "none"
cleanup = "n/a"
degraded = ""
observable = "404 / opaque 500 (detail only in server log); quarantined → not_found"
evidence = "server/lib/src/grpc.rs"
[[failure]]
operation = "Repository put"
fatal = "over body-cap → 413; unauthorized → 401/403 pre-body"
partial = "no"
retry = "none"
cleanup = "atomic (temp+rename) for raw/file backends; writable-znippy append under write_lock"
degraded = ""
observable = "gRPC status / HTTP code"
evidence = "server/lib/src/grpc.rs; server/lib/src/raw.rs"
[[failure]]
operation = "Promotion"
fatal = "request-only; gates run BEFORE any write (advisory/property/license)"
partial = "a lineage-append failure AFTER the seal is non-fatal + logged loudly"
retry = "none"
cleanup = "an illegal promotion writes nothing; seal is create_new (exclusive)"
degraded = ""
observable = "412 failed_precondition, audited; job ledger records 'failed'"
evidence = "server/lib/src/promote/mod.rs"
[[failure]]
operation = "Withdrawal"
fatal = "request-only"
partial = "no — appends a Withdrawn lineage entry; blob+ref untouched"
retry = "none"
cleanup = "append-only (OpenOptions::append)"
degraded = ""
observable = "state reduced from history replay"
evidence = "server/lib/src/promote/stages.rs"
[[failure]]
operation = "Retention planning"
fatal = "no — dry-run default plans without deleting"
partial = "reports candidates + reclaimed bytes"
retry = "none"
cleanup = "n/a (no writes in dry-run)"
degraded = ""
observable = "plan output; --execute required to delete"
evidence = "server/lib/src/retention.rs"
[[failure]]
operation = "Retention execution"
fatal = "no"
partial = "per-artifact delete; deletes historized as ident holger-retention-gc"
retry = "none"
cleanup = "sha256-verified delete on raw/file backends"
degraded = ""
observable = "audit Delete events + reclaimed bytes; job ledger 'retention-gc'"
evidence = "server/lib/tests/retention_executor.rs"
[[failure]]
operation = "Replication"
fatal = "no — per-artifact failures counted (Outcome::Failed)"
partial = "yes — is_complete() false; read-only dest → Failed fail-closed"
retry = "none; idempotent re-run (sha256 skip)"
cleanup = "dry-run default writes nothing"
degraded = ""
observable = "copied/skipped/would_copy/failed tallies; admin-gated RPC, audited"
evidence = "server/lib/src/replication.rs"
[[failure]]
operation = "Airgap driver execution"
fatal = "a non-zero driver exit is captured into the Report (the one shell-out)"
partial = "the driver has its own AIRGAP_DRY_RUN; --dry-run returns before driver discovery"
retry = "none"
cleanup = "n/a (external process)"
degraded = ""
observable = "captured stdout/stderr/exit in the Report"
evidence = "airgap/src/lib.rs"
[[failure]]
operation = "UI remote connection"
fatal = "no — connection error surfaced in the UI, not a crash"
partial = "n/a"
retry = "user-driven"
cleanup = "n/a"
degraded = ""
observable = "error state in the egui view (block_on on a private runtime)"
evidence = "server/lib/src/object.rs; server/ui/src/data.rs"
[[change_impact]]
interface = "RepositoryBackendTrait"
defined_in = "traits/src/lib.rs:202"
implementers = "~21 production (16 backend crates + group/proxy/raw/upstream_rust/upstream) + ~22 test mocks"
consumers = "fast_routes, grpc + grpc/services, exposed/http, object.rs, search, replication, retention"
significance = "central backend contract; ADDING a defaulted method is safe, changing fetch/put/handle_http2_request breaks every backend at compile"
tests = "cargo test -p holger-server-lib"
[[change_impact]]
interface = "ConnectorTrait"
defined_in = "traits/src/lib.rs:404"
implementers = "Nexus / Artifactory / World connectors + a bench mock"
consumers = "agent/lib operations.rs, agent/cli main.rs, UI tools pane, airgap driver"
significance = "the agent transfer contract; async; changing it touches every connector + the transfer matrix"
tests = "cargo test -p holger-agent-cli"
[[change_impact]]
interface = "HolgerObject"
defined_in = "traits/src/lib.rs:556"
implementers = "LocalHolger + RemoteHolger (object.rs) + FakeHolger (UI test)"
consumers = "UI UiData (data.rs), holger-embed, holger-demo, server CLI"
significance = "the in-process vs gRPC facade the UI is built on"
tests = "cargo test -p holger-server-ui"
[[change_impact]]
interface = "ArtifactId / ArtifactFormat"
defined_in = "traits/src/lib.rs"
implementers = "data types; ArtifactFormat has 15 variants, each with a backend; proto twin in generated/holger.v1.rs"
consumers = "everything; from_format_str parsing, znippy_type_id() discriminants"
significance = "adding a format variant triggers non-exhaustive-match errors across backends + a proto round-trip test"
tests = "cargo test -p holger-server-lib"
[[change_impact]]
interface = "znippy read/format seam (FormatGate, ensure_supported_format, plugin views as_rust/as_maven/…)"
defined_in = "traits/src/znippy_format.rs"
implementers = "gate consumed ONLY by znippy-rust; typed views per-backend (maven/npm/python/conda/gem/rust)"
consumers = "all znippy backends open archives via znippy-common; writer seam used by znippy-rust dev-mode + agent pack"
significance = "any znippy API change breaks the whole workspace via [patch.crates-io]"
tests = "cargo test -p holger-rust-znippy-repository --test format_version_gate"
[[change_impact]]
interface = "AuditLog"
defined_in = "server/lib/src/audit/mod.rs"
implementers = "Noop / Memory / ArrowIpc (arrow_ipc.rs) / Channel (UI lineage)"
consumers = "grpc + grpc/services fetch/put/promote, exposed/http, replication"
significance = "the audit choke point; a new door that skips record_audit loses the audit trail"
tests = "cargo test -p holger-server-lib audit"
[[change_impact]]
interface = "AuthProvider seam (nornir_service, edda)"
defined_in = "server/lib/src/auth.rs"
implementers = "bearer / oidc / oauth2 / mtls providers (webauthn declared, unwired)"
consumers = "grpc.rs + exposed/http.rs validate_request; build-space tier link-audit"
significance = "changing the seam affects every tier's pinned provider set; fail-closed when unpinned"
tests = "cargo test -p holger-server-lib; cargo test -p holger-build-space --test auth_ship_small"
[[change_impact]]
interface = "PromotionEngine"
defined_in = "server/lib/src/promote/mod.rs"
implementers = "single engine + stages.rs lineage"
consumers = "grpc/services PromotionService, lib.rs startup wiring, job ledger"
significance = "seal-once + withdraw-is-append invariants live here; a File::create 'idempotence' change breaks immutability"
tests = "cargo test -p holger-server-lib promote"
[[change_impact]]
interface = "replication::replicate_pairs"
defined_in = "server/lib/src/replication.rs"
implementers = "one pure engine over RepositoryBackendTrait"
consumers = "grpc/services ReplicationService (admin-gated), CLI replicate verb"
significance = "sha256-idempotent, dry-run-default; the admin gate + dry-run default are the safety rails"
tests = "cargo test -p holger-server-lib replication"
[[change_impact]]
interface = "generated gRPC types (holger.v1)"
defined_in = "server/lib/src/generated/holger.v1.rs"
implementers = "prost/tonic codegen (committed, not built at compile)"
consumers = "grpc.rs conversions, every service, the RemoteHolger client"
significance = "edit proto/holger.proto then `cargo xtask gen-proto`; hand-editing the generated file drifts from the proto"
tests = "cargo test -p holger-server-lib"
[[change_impact]]
interface = "UI data/model contract (UiData, views)"
defined_in = "server/ui/src/data.rs"
implementers = "UiData over HolgerObject; SearchView/SbomView/etc."
consumers = "app.rs scene/command, panes, tier features"
significance = "RepositoryInfo drives Browse off has_archive() — only znippy-rust overrides it, so most backends show empty Browse"
tests = "cargo test -p holger-server-ui"
[[change_impact]]
interface = "build variant types"
defined_in = "holger-recipe/src/variants.rs"
implementers = "build-space crate + tier features on server-lib/server-cli/holger-server-ui"
consumers = "the compile_error! tier guard in server/cli/main.rs; auth_ship_small + tier_ladder audits"
significance = "tiers are mutually exclusive; a cross-tier feature edge or a forbidden dep (openssl/webauthn) fails the link-audits"
tests = "cargo test -p holger-build-space"
[[task]]
name = "Add a repository backend / ecosystem"
start = ["server/lib/src/repository.rs", "traits/src/lib.rs"]
related = ["server/repository/znippy-rust/src/lib.rs", "server/repository/file-rust/src/lib.rs", "server/lib/src/exposed/http.rs"]
invariants = ["no-traversal", "format-version-pin"]
fast_test = "cargo test -p holger-rust-znippy-repository --test format_version_gate"
full_test = "cargo test -p holger-server-lib && cargo test -p holger-rust-znippy-repository"
heavy_test = ""
[[task]]
name = "Add / change a connector"
start = ["traits/src/lib.rs", "agent/connector/nexus/src/lib.rs"]
related = ["agent/lib/src/operations.rs", "agent/cli/src/main.rs"]
invariants = ["connector-same-origin", "world-ssrf-allowlist", "no-traversal"]
fast_test = "cargo test -p holger-nexus-connector && cargo test -p holger-world-connector"
full_test = "cargo test -p holger-agent-cli"
heavy_test = "cargo test -p holger-agent-cli -- --ignored"
[[task]]
name = "Change agent transfer / partial-success"
start = ["agent/lib/src/operations.rs"]
related = ["agent/cli/src/main.rs"]
invariants = ["transfer-partial-success", "no-traversal"]
fast_test = "cargo test -p holger-agent-lib"
full_test = "cargo test -p holger-agent-cli"
heavy_test = ""
[[task]]
name = "Change HTTP routing / native protocols"
start = ["server/lib/src/exposed/http.rs"]
related = ["server/lib/src/lib.rs", "server/repository/znippy-rust/src/lib.rs"]
invariants = ["write-gate-fail-closed", "read-gate-opt-in-fail-closed"]
fast_test = "cargo test -p holger-server-lib --test integration_oci_tls"
full_test = "cargo test -p holger-server-lib"
heavy_test = ""
[[task]]
name = "Change authentication / authorization"
start = ["server/lib/src/auth.rs"]
related = ["server/lib/src/grpc.rs", "server/lib/src/exposed/http.rs"]
invariants = ["write-gate-fail-closed", "read-gate-opt-in-fail-closed", "tier-mutual-exclusion"]
fast_test = "cargo test -p holger-server-lib auth"
full_test = "cargo test -p holger-server-lib && cargo test -p holger-build-space --test auth_ship_small"
heavy_test = ""
[[task]]
name = "Change audit logging"
start = ["server/lib/src/audit/arrow_ipc.rs", "server/lib/src/audit/mod.rs"]
related = ["server/lib/src/grpc.rs", "server/lib/src/exposed/http.rs"]
invariants = ["audit-append-only"]
fast_test = "cargo test -p holger-server-lib audit"
full_test = "cargo test -p holger-server-lib"
heavy_test = ""
[[task]]
name = "Change promotion / retention"
start = ["server/lib/src/promote/mod.rs", "server/lib/src/promote/stages.rs"]
related = ["server/lib/src/grpc/services.rs", "server/lib/src/lib.rs"]
invariants = ["promote-seal-once", "withdraw-is-append"]
fast_test = "cargo test -p holger-server-lib promote"
full_test = "cargo test -p holger-server-lib && cargo test -p holger-server-lib --test retention_executor"
heavy_test = ""
[[task]]
name = "Change replication"
start = ["server/lib/src/replication.rs"]
related = ["server/lib/src/grpc/services.rs", "server/cli/src/main.rs"]
invariants = ["write-gate-fail-closed"]
fast_test = "cargo test -p holger-server-lib replication"
full_test = "cargo test -p holger-server-lib"
heavy_test = ""
[[task]]
name = "Change airgap behavior"
start = ["airgap/src/lib.rs"]
related = ["server/cli/src/main.rs"]
invariants = []
fast_test = "cargo test -p holger-airgap"
full_test = ""
heavy_test = ""
[[task]]
name = "Change the proto / gRPC surface"
start = ["proto/holger.proto"]
related = ["server/lib/src/generated/holger.v1.rs", "server/lib/src/grpc.rs"]
invariants = []
fast_test = "cargo test -p holger-server-lib"
full_test = "cargo xtask gen-proto && cargo test -p holger-server-lib"
heavy_test = ""
[[task]]
name = "Change the UI"
start = ["server/ui/src/data.rs", "server/ui/src/main.rs"]
related = ["server/lib/src/object.rs", "server/ui/tests/tier_ladder.rs"]
invariants = ["tier-mutual-exclusion"]
fast_test = "cargo test -p holger-server-ui"
full_test = "cargo test -p holger-server-ui --features gui"
heavy_test = "cargo test -p holger-server-ui --test tier_ladder -- --ignored"
[[task]]
name = "Change a deployment tier / build variant"
start = ["holger-recipe/src/variants.rs", "server/cli/src/main.rs"]
related = ["server/lib/Cargo.toml", "server/ui/Cargo.toml"]
invariants = ["tier-mutual-exclusion"]
fast_test = "cargo test -p holger-build-space"
full_test = ""
heavy_test = "cargo test -p holger-server-ui --test tier_ladder -- --ignored"
[[cli]]
binary = "holger-server"
command = "start"
flags = "--config <ron>"
calls_into = "server/lib/src/lib.rs"
restrictions = "tier features embedded/mini/full (mutually exclusive)"
tests = "cargo test -p holger --test tools_robot"
[[cli]]
binary = "holger-server"
command = "dev-pair"
flags = "--data <dir> [--grpc 127.0.0.1:18443] [--http 127.0.0.1:18444]"
calls_into = "server/lib/src/lib.rs"
restrictions = "dev convenience — autogen RON + sparring archives"
tests = ""
[[cli]]
binary = "holger-server"
command = "install / service"
flags = "add|update|remove|status|render; service install|start|stop|status|health|uninstall --scope user|system"
calls_into = "server/cli/src/main.rs"
restrictions = "none"
tests = ""
[[cli]]
binary = "holger-server"
command = "retention"
flags = "--config [--repo --keep-last-n --max-age-secs --max-total-bytes --protect-property k=v --execute]"
calls_into = "server/lib/src/retention.rs"
restrictions = "dry-run default; --execute deletes"
tests = "cargo test -p holger-server-lib --test retention_executor"
[[cli]]
binary = "holger-server"
command = "replicate"
flags = "--from <ron> --to <ron> [--repo] [--execute] [--limit]"
calls_into = "server/lib/src/replication.rs"
restrictions = "dry-run default; pairs repos by identical name"
tests = ""
[[cli]]
binary = "holger-server"
command = "airgap"
flags = "--stack --scale micro|small|large --target holger|nexus|artifactory --auth mtls [--dry-run --build-only --push-only]"
calls_into = "airgap/src/lib.rs"
restrictions = "--dry-run returns before driver discovery; needs distribution/airgap/populate on disk"
tests = ""
[[cli]]
binary = "holger-server"
command = "search / sbom / properties / scan / holger-ds"
flags = "search --name/--sha256/--property; sbom attach|fetch; properties set|get; holger-ds --scale/--preset (bench)"
calls_into = "server/lib/src/lib.rs"
restrictions = "holger-ds requires `bench` (omitted by embedded/mini)"
tests = ""
[[cli]]
binary = "holger-agent"
command = "(single verb)"
flags = "--from world|nexus|artifactory|holger|znippy|tar-zst|directory --to znippy|tar-zst|directory|nexus|artifactory|holger --lockfile-kind cargo|requirements-txt|uv-lock --auth oidc|mtls"
calls_into = "agent/lib/src/operations.rs"
restrictions = "same-type + identity + world→server combos bail (airgap first)"
tests = "cargo test -p holger-agent-cli"
[[cli]]
binary = "holger-server-ui"
command = "(positional ENDPOINT)"
flags = "ENDPOINT (default http://127.0.0.1:50051) --token --ca --cert --key [--demo (demo feature)] [--robot-remote (robot-remote feature)]"
calls_into = "server/ui/src/main.rs"
restrictions = "gui/gui-mini/gui-mikro tiers; --demo needs `demo`; tier binaries: holger-server-ui, holger-server-ui-mini, holger-server-ui-mikro"
tests = "cargo test -p holger-server-ui"
[[cli]]
binary = "holger-mannequin"
command = "serve / pki generate"
flags = "[--gui] one-port mock PKI+OIDC+Nexus"
calls_into = "mannequin/src/main.rs"
restrictions = "TEST/DEV ONLY — never production"
tests = "cargo test -p holger-mannequin"
[[cli]]
binary = "xtask"
command = "gen-proto / demo-wasm / deploy-pages"
flags = "gen-proto (protox+tonic-build, pure Rust)"
calls_into = "xtask/src/main.rs"
restrictions = "dev tooling; gen-proto output is committed"
tests = "cargo test -p xtask --test holger_matrix"
[[config]]
field = "repositories[].ron_name"
kind = "String"
default = ""
required = "Yes"
sensitive = ""
consumer = "server/lib/src/repository.rs"
reloadable = "startup-only"
validation = ""
[[config]]
field = "repositories[].ron_repo_type"
kind = "String (rust|rust-remote|maven3|pip|npm|nuget|go|gem|deb|rpm|helm|docker|oci|raw|conda|composer|group|znippy|{nexus,artifactory,azure,aws}-remote)"
default = ""
required = "Yes"
sensitive = ""
consumer = "server/lib/src/repository.rs"
reloadable = "startup-only"
validation = "*-remote need `federation`/`online`; unknown value = boot error"
[[config]]
field = "repositories[].ron_upstreams"
kind = "Vec<String>"
default = "[]"
required = "Yes"
sensitive = ""
consumer = "server/lib/src/lib.rs"
reloadable = "startup-only"
validation = "proxy chain, first-hit-wins; makes the repo a ProxyBackend"
[[config]]
field = "repositories[].ron_archive_path"
kind = "Option<String>"
default = ""
required = "No"
sensitive = ""
consumer = "server/lib/src/repository.rs"
reloadable = "startup-only"
validation = "read-only znippy snapshot (required by znippy_backed! backends)"
[[config]]
field = "repositories[].ron_writable_archive"
kind = "Option<String>"
default = ""
required = "No"
sensitive = ""
consumer = "server/repository/znippy-rust/src/lib.rs"
reloadable = "startup-only"
validation = "rust only; live seal-able archive; wins over archive_path/data_dir"
[[config]]
field = "repositories[].ron_data_dir"
kind = "Option<String>"
default = "/var/lib/holger/{ron_name}"
required = "No"
sensitive = ""
consumer = "server/repository/file-rust/src/lib.rs"
reloadable = "startup-only"
validation = "file/oci/raw backends"
[[config]]
field = "repositories[].ron_trusted_roots"
kind = "Option<String> (DER root)"
default = ""
required = "No"
sensitive = "No"
consumer = "server/lib/src/repository.rs"
reloadable = "startup-only"
validation = "znippy CMS provenance verify; needs `sign`, else wiring fails closed"
[[config]]
field = "exposed_endpoints[].ron_url"
kind = "String (SocketAddr)"
default = ""
required = "Yes"
sensitive = ""
consumer = "server/lib/src/lib.rs"
reloadable = "startup-only"
validation = "the gRPC listen address"
[[config]]
field = "exposed_endpoints[].ron_http_url"
kind = "Option<String>"
default = ""
required = "No"
sensitive = ""
consumer = "server/lib/src/exposed/http.rs"
reloadable = "startup-only"
validation = "enables the native-protocol HTTP/OCI door + /healthz /readyz"
[[config]]
field = "exposed_endpoints[].ron_tls"
kind = "Option<{cert, key, client_ca}>"
default = ""
required = "No"
sensitive = "Yes"
consumer = "server/lib/src/exposed/tls.rs"
reloadable = "startup-only"
validation = "client_ca present ⇒ mTLS; absent ⇒ cleartext (loud warning)"
[[config]]
field = "exposed_endpoints[].ron_max_body_bytes"
kind = "Option<usize>"
default = "1 GiB"
required = "No"
sensitive = ""
consumer = "server/lib/src/grpc.rs"
reloadable = "startup-only"
validation = "shared gRPC message + HTTP body cap"
[[config]]
field = "auth.methods[]"
kind = "Vec<Oidc|OAuth2|Mtls|StaticToken>"
default = ""
required = "No"
sensitive = "Yes"
consumer = "server/lib/src/auth.rs"
reloadable = "startup-only"
validation = "provider must be feature-pinned by the tier or it authenticates nothing (fail-closed)"
[[config]]
field = "auth.roles / default_role / repo_roles"
kind = "Map<subject,Role> (Denied|Reader|Writer|Admin)"
default = "{} (RBAC off)"
required = "No"
sensitive = ""
consumer = "server/lib/src/auth.rs"
reloadable = "startup-only"
validation = "empty + no default_role ⇒ RBAC disabled; set ⇒ fail-closed writes"
[[config]]
field = "auth.require_auth_for_reads"
kind = "bool"
default = "false"
required = "No"
sensitive = ""
consumer = "server/lib/src/auth.rs"
reloadable = "startup-only"
validation = "opt-in read gate (fail-closed); health stays open"
[[config]]
field = "audit.dir / audit.enabled"
kind = "String / bool"
default = "holger-audit (under $HOLGER_DATA) / true"
required = "No"
sensitive = ""
consumer = "server/lib/src/audit/arrow_ipc.rs"
reloadable = "startup-only"
validation = "relative dir anchors under $HOLGER_DATA; absolute wins"
[[env]]
name = "HOLGER_DATA"
category = "path"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/lib.rs; server/ui/src/data.rs"
effect = "anchors relative audit dir; derives data_root for prod store / job ledger / sboms / props"
[[env]]
name = "HOLGER_TOKEN"
category = "secret"
default = ""
sensitive = "Yes"
scope = "runtime"
consumer = "server/ui/src/main.rs"
effect = "UI bearer token (alt to --token)"
[[env]]
name = "HOLGER_PROMOTE_ENFORCE"
category = "enum (block|warn|off)"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/promote/mod.rs"
effect = "promote policy enforcement; a bad value FAILS startup"
[[env]]
name = "HOLGER_PROMOTE_ADVISORY_DB"
category = "path"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/promote/mod.rs"
effect = "OSV/GHSA snapshot for promote gating; unreadable ⇒ serve refuses to start"
[[env]]
name = "HOLGER_PROMOTE_DENY_LICENSES"
category = "csv"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/promote/mod.rs"
effect = "SPDX ids denied at promote"
[[env]]
name = "HOLGER_PROMOTE_REQUIRE_PROPERTY"
category = "k=v"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/lib.rs"
effect = "source coord must carry the property to promote"
[[env]]
name = "HOLGER_QUARANTINE_PROPERTY"
category = "k=v"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/lib/src/lib.rs"
effect = "**RETIRED (W6)**: set ⇒ the boot is refused with `holger-intake-14`; the one hold is the intake chain's QUARANTINED state (`holger-server intake quarantine`)"
[[env]]
name = "HOLGER_WAREHOUSE"
category = "path"
default = ""
sensitive = ""
scope = "runtime"
consumer = "server/ui/src/data.rs"
effect = "opens the skade/modgunn Iceberg advisory warehouse in-process (warehouse-scan only)"
[[env]]
name = "HOLGER_DEMO_BEAT_MS"
category = "int"
default = "2200"
sensitive = ""
scope = "dev"
consumer = "server/ui/src/main.rs"
effect = "demo robot beat interval"
[[env]]
name = "HOLGER_DEMO_IMAGE"
category = "string"
default = "docker.io/library/registry:2.8.3"
sensitive = ""
scope = "dev"
consumer = "server/ui/src/infra.rs"
effect = "demo appliance image"
[[env]]
name = "HOLGER_BENCH_DIR"
category = "path"
default = "$HOME/holger-bench-data"
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "bench fixture root"
[[env]]
name = "HOLGER_BENCH_SCALE"
category = "enum (quick|full|huge)"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "bench preset; NORNIR_BENCH_QUICK=0 forces full"
[[env]]
name = "HOLGER_REQUIRE_NETWORK"
category = "flag"
default = ""
sensitive = ""
scope = "test"
consumer = "agent/cli/tests/integration_pip.rs"
effect = "test-only: convert offline skip into a failure"
[[env]]
name = "HOLGER_BENCH_BYTES"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "override synthetic artifact size"
[[env]]
name = "HOLGER_BENCH_ENTRIES"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "override synthetic entry count"
[[env]]
name = "HOLGER_BENCH_SECS"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "override bench run duration"
[[env]]
name = "HOLGER_BENCH_REAL"
category = "flag (REAL=0 opts out)"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "use synthetic instead of real-artifact corpus"
[[env]]
name = "HOLGER_BENCH_BOOT_SECS"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "JVM/container boot timeout for competitor twins"
[[env]]
name = "NORNIR_BENCH_QUICK"
category = "flag (=0 forces full)"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/src/lib.rs"
effect = "back-compat scale toggle"
[[env]]
name = "DOCKER_HOST"
category = "url"
default = ""
sensitive = ""
scope = "test"
consumer = "bench-scenarios/src/lib.rs"
effect = "testcontainers socket autodetect (rootless podman)"
[[env]]
name = "PIP_PROBE_MB"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/examples/pip_probe.rs"
effect = "pip probe example sizing"
[[env]]
name = "PIP_PROBE_SECS"
category = "int"
default = ""
sensitive = ""
scope = "bench"
consumer = "bench-scenarios/examples/pip_probe.rs"
effect = "pip probe example duration"
[[external_dep]]
name = "tokio"
effect = "multi-thread async runtime for gRPC + HTTP; UI uses private current-thread runtimes + block_on"
security = ""
impact = "always on server-side; backend fetch/put run blocking I/O directly on async workers (no spawn_blocking)"
[[external_dep]]
name = "tonic"
effect = "gRPC transport (HTTP/2); the only network API surface plus the HTTP door"
security = ""
impact = "all tiers; message size caps = ron_max_body_bytes"
[[external_dep]]
name = "rustls"
effect = "TLS + mTLS (client_ca ⇒ handshake-level mutual auth); no OpenSSL"
security = ""
impact = "auth_ship_small link-audit asserts openssl NEVER links into any tier"
[[external_dep]]
name = "reqwest / ureq"
effect = "outbound HTTP for agent connectors + federation/online; redirect::Policy::none() enforced"
security = ""
impact = "gated behind `online`/`federation`; ABSENT from embedded/mini (zero-egress). UI signin is the only client-tier reqwest source"
[[external_dep]]
name = "znippy / znippy-zoomies (znippy-common)"
effect = "the archive format + gatling parallel I/O; content-addressed blake3 chunks; format-version pin"
security = ""
impact = "resolved via [patch.crates-io] to sibling checkouts — a znippy API change breaks the whole workspace at compile"
[[external_dep]]
name = "arrow (arrow-ipc)"
effect = "append-only Arrow-IPC segments are the audit system of record"
security = ""
impact = "always on; segment files 0600, never rewritten"
[[external_dep]]
name = "jera (redb)"
effect = "embedded redb key-value store for the promote/retention job ledger (best-effort, bounded)"
security = ""
impact = "audit is the permanent record; the ledger is rebuildable"
[[external_dep]]
name = "skidbladnir"
effect = "federation harbour clients; also the identity/verify seam the CLI links"
security = ""
impact = "only via `full`/`federation`; *-remote repo types fail closed on mini/embedded"
[[external_dep]]
name = "eframe / egui / facett"
effect = "the operator UI toolkit (facett = the declarative scene shell)"
security = ""
impact = "gui tiers only; gui-mini/gui-mikro strip optional panes to zero-egress"
[[external_dep]]
name = "nornir-auth-* (edda)"
effect = "pluggable AuthProvider seam: bearer/oidc/oauth2/mtls (+webauthn declared, unwired)"
security = ""
impact = "feature-pinned per tier; an unpinned provider in config authenticates nothing (fail-closed)"
[[external_dep]]
name = "prost (+ tonic-build via xtask)"
effect = "protobuf message codegen; generated Rust is committed, not built at compile time"
security = ""
impact = "regenerate with `cargo xtask gen-proto` from proto/holger.proto"
[[external_dep]]
name = "ron"
effect = "the config format — a typed graph of repos/endpoints/storage/auth/audit"
security = ""
impact = "always; parse failure aborts startup"
[[document]]
path = "CLAUDE.md"
status = "Superseded documentation"
include_compact = "no"
include_full = "no"
note = "Contains known stale claims (promote 'not implemented', 'no HTTP/REST surface', `cargo bench`). Facts extracted into wiring/warnings instead."
[[document]]
path = ".nornir/README.md"
status = "Runtime wired"
include_compact = "no"
include_full = "full"
note = "Current top-level overview (the generated README source)."
[[document]]
path = ".nornir/holger-tiers.md"
status = "Runtime wired"
include_compact = "no"
include_full = "full"
note = "Current build-tier reference."
[[document]]
path = ".nornir/testing-guide.md"
status = "Runtime wired"
include_compact = "no"
include_full = "full"
note = "Current test-command reference; matches xtask/CI reality."
[[document]]
path = ".nornir/mini-holger-for-henrik.md"
status = "Runtime wired"
include_compact = "no"
include_full = "no"
note = "Verified build+run guide, but human-oriented; excluded from both to keep packs lean."
[[document]]
path = ".nornir/feature-complete-gaps.md"
status = "Historical documentation"
include_compact = "no"
include_full = "no"
note = "Gap tracker — snapshot in time, not current implementation truth."
[[document]]
path = ".nornir/for-idiots.md"
status = "Historical documentation"
include_compact = "no"
include_full = "no"
note = "Human tutorial ('for-idiots' series); never overrides code."