holger — AI context (compact)
Read this file first. It is the primary context for reasoning about this repository. Use the companion ai-context-full.md only for exact public-API signatures and
file:linesource lookup — do not load it for routine work.Generated summaries never override active code. Before changing behavior, inspect the referenced implementation and its tests.
Snapshot
| Field | Value |
| Repository | holger |
| Source revision | a843b3260e016fc17d113ab42dba20344c5e832e |
| Working tree | Dirty |
| Reproducible snapshot | Non-reproducible |
| Generation mode | development |
| Generator version | kvasir 0.2.1 |
| Maintained metadata | .nornir/ai-context.toml |
| Generated at | 2026-08-13T21:41:29+02:00 (source: commit) |
⚠ Dirty working tree — this snapshot is NOT reproducible. It reflects uncommitted local changes, not commit
a843b3260e01.
| Category | Count | Included items |
| Cargo workspace packages | 42 | see the workspace dependency graph |
| Detached Rust packages | 0 | — |
| Packages with indexed API surface | 42 | 42 workspace + 0 detached |
| Binary targets | 19 | [[bin]] + src/main.rs + src/bin/* |
| Library targets | 39 | packages with src/lib.rs |
The indexed count (42) is the 42 workspace members that expose a src/ tree plus 0 detached package(s) (own [workspace], indexed for their API but outside the dependency graph). Detached packages are in the API index; they are not in the workspace dependency graph.
AI source-of-truth hierarchy
When sources disagree, trust the higher item. Strongest first:
- Executable tests (they assert real behavior)
- Active runtime wiring (what the daemon actually constructs and registers)
- Implementation (the code that runs)
- Configuration and feature definitions (what is switched on)
- Schemas and persisted data contracts
- Rustdoc (author intent — weaker than the code it describes)
- Current architecture documents
- Generated summaries (this pack included)
- Historical documents (design notes, superseded proposals)
- Inferred intent (weakest — a guess)
State explicitly:
- Exported code does not prove runtime registration.
- A configured feature may be disabled.
- A documented follow-up is not implemented.
- A model proposal is not an approved action.
- An
Okresult may still contain partial failures. - Degraded operation must not be mistaken for full operation.
System summary
| Field | Value |
| 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) |
| Major binaries | holger-server, holger-agent, holger-server-ui, holger-server-ui-embedded, holger-server-ui-mini, holger-server-ui-mikro, holger-mannequin, xtask |
| Primary 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 (explicit):
- Not a general object store — artifacts are ecosystem packages with coordinates, not arbitrary blobs (except the
rawbackend). - 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.
AI reasoning warnings
Short operational cautions for interpretation (one line each):
- A crate existing does not prove it is runtime-wired.
- A pure function may require a daemon caller before it becomes active.
- A configured detector may not be scheduled.
- Candidate data never means Trusted.
- Trusted normality never overrides an explicit deny.
- Monitoring means elevated attention, not guilt.
- An agent proposal is not approval.
- Action approval is not successful execution.
- Notification success is not incident truth.
- Missing Matrix/webhook/email means degraded delivery, not failed triage.
- Semantic search may be unavailable while structured/full-text search still works.
- MCP failure should not imply core agent failure.
- Audit append failure may intentionally block a protected action.
- Audit self-consistency is not authenticity without an out-of-band trust root.
- Generated docs are weaker evidence than code.
- Model output is untrusted until validated.
- Stateful detectors depend on persisted ordering and snapshot semantics.
- "follow-up" or "planned" rustdoc is not implementation.
- 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 benchdoes NOT work — there are no [[bench]] targets. Benchmarks run vianornir 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.
Runtime wiring map
A crate or function existing is not proof of wiring. Status uses the runtime vocabulary.
→ Runtime entry points & constructors: ai-context-full.md.
| Capability | Interface | Implementation | Runtime registration | Configuration | Tests | Status |
| Config load + graph wiring | RON Holger root |
server/lib/src/lib.rs:355 | server/lib/src/lib.rs:113 | --config <file.ron>; repositories/exposed_endpoints/storage_endpoints/auth/audit | server/lib/tests/graceful_backend_init.rs | Runtime wired |
| Repository backend registration | RepositoryBackendTrait | server/lib/src/repository.rs:207 | server/lib/src/repository.rs:186 | 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 | server/lib/tests/graceful_backend_init.rs | Runtime wired |
| gRPC services (8) | tonic services | server/lib/src/grpc/services.rs | server/lib/src/lib.rs:1084 | ExposedEndpoint.ron_url (bare SocketAddr); per-service body caps = ron_max_body_bytes — status note: Repository, Archive, Admin, Promotion, Search, Sbom, Property, Replication | server/lib/tests/integration_oci_tls.rs | Runtime wired |
| HTTP door (native package protocols + OCI) | package-client HTTP/2 | server/lib/src/exposed/http.rs | server/lib/src/lib.rs:889 | ExposedEndpoint.ron_http_url; /healthz /readyz /metrics open; /-/search /-/sbom /-/properties — status note: CLAUDE.md wrongly says 'No HTTP/REST API surface' | server/lib/tests/integration_oci_tls.rs | Runtime wired |
| Authentication | nornir_service::AuthProvider (edda) | server/lib/src/auth.rs | server/lib/src/auth.rs:445 | 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). | server/lib/src/auth.rs | Runtime wired |
| Authorization (RBAC) | Role floor (Denied<Reader<Writer<Admin) | server/lib/src/auth.rs | server/lib/src/grpc.rs:244 | 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 | server/lib/src/grpc.rs | Runtime wired |
| Audit logging | audit::AuditLog trait | server/lib/src/audit/arrow_ipc.rs | server/lib/src/grpc.rs:218 | 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). | server/lib/src/audit/arrow_ipc.rs | Runtime wired |
| Promotion (DEV→PROD seal) | PromotionEngine | server/lib/src/promote/mod.rs | server/lib/src/lib.rs:971 | HOLGER_PROMOTE_ENFORCE/_ADVISORY_DB/_DENY_LICENSES/_REQUIRE_PROPERTY; prod store <data_root>/holger-prod-store — status note: CLAUDE.md wrongly says 'not implemented' | server/lib/src/promote/mod.rs | Runtime wired |
| Retention / GC | retention policy scan | server/lib/src/lib.rs:637 | server/cli/src/main.rs | 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 | server/lib/tests/retention_executor.rs | Runtime wired |
| Replication | replication::replicate_pairs | server/lib/src/replication.rs:168 | server/lib/src/grpc/services.rs:1296 | 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. | server/lib/src/replication.rs | Runtime wired |
| Airgap populate | PopulateArgs plan | airgap/src/lib.rs | server/cli/src/main.rs | 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 | airgap/src/lib.rs | Runtime wired |
| UI local vs remote | HolgerObject | server/lib/src/object.rs | server/ui/src/data.rs | holger-server-ui ENDPOINT/--token/--ca/--cert/--key; --demo builds in-process LocalHolger — status note: RemoteHolger (tonic + bearer interceptor) or LocalHolger (direct backend calls | server/ui/tests/remote_grpc.rs | Runtime wired |
| Build tiers | cargo features | build-space/build-variants.toml | server/cli/src/main.rs | 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 | build-space/tests/build_variants_no_drift.rs | Runtime wired |
Capability matrix
Support and limitations only (the security rationale lives in the invariants).
| Plane | Capability | Read | Write/Act | Human approval | Runtime wired | Persistence | Main limitation | Evidence |
| Ecosystem | Cargo/Rust | Yes | Partial | No | Yes | native index: Synthesized; znippy backend: Yes; writable: Yes; proxy upstream: Feature-gated; generic-fetch: Yes; browse: Yes | 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 |
server/repository/znippy-rust/src/lib.rs; server/repository/file-rust/src/lib.rs |
| Ecosystem | Maven | Yes | No | No | Yes | native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | no timestamped unique-build snapshots; empty typed view falls back to .jar filename parse (non-jar files invisible to fallback) | server/repository/znippy-maven/src/lib.rs |
| Ecosystem | Python/PyPI | Yes | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | PEP 503 HTML + PEP 691 at explicit /simple/{name}/json (no Accept negotiation); layout fixed at packages/{norm}/{file} | server/repository/znippy-python/src/lib.rs |
| Ecosystem | npm | Partial | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Partial; browse: Partial | 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 |
server/repository/znippy-npm/src/lib.rs |
| Ecosystem | NuGet | Yes | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No | only PackageBaseAddress (flat container) — no Registrations/Search ⇒ exact-version pulls only; list() empty; no archive view | server/repository/znippy-nuget/src/lib.rs |
| Ecosystem | Go | Yes | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No | @v/list synthesized from .zip scan; versions with only .info/.mod are invisible in list; list() empty; no archive view | server/repository/znippy-go/src/lib.rs |
| Ecosystem | RPM | Yes | No | No | Yes | native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | 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 | server/repository/znippy-rpm/src/lib.rs |
| Ecosystem | Debian/APT | Yes | No | No | Yes | native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | 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 | server/repository/znippy-deb/src/lib.rs |
| Ecosystem | RubyGems | Yes | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | real compact-index (info/{name} checksum = real sha256); empty without the typed view; no legacy specs.4.8 API | server/repository/znippy-gem/src/lib.rs |
| Ecosystem | Conda | Yes | No | No | Yes | native index: Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Partial | repodata.json per subdir (real sha256 + blake3); .conda (v2) packages NOT in the synthesized index (packages.conda always {}) | server/repository/znippy-conda/src/lib.rs |
| Ecosystem | Helm | Yes | No | No | Yes | native index: Passthrough+Synthesized; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | classic (non-OCI) repo; index.yaml passthrough wins else generated; root-level tgz URLs only | server/repository/znippy-helm/src/lib.rs |
| Ecosystem | Docker/OCI | Yes | Yes | No | Yes | native index: Passthrough+Synthesized; znippy backend: Partial; writable: Yes; proxy upstream: —; generic-fetch: Yes; browse: Yes | 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) | server/repository/file-oci/src/lib.rs; server/repository/znippy-docker/src/lib.rs |
| Ecosystem | Composer | Yes | No | No | Yes | native index: Passthrough; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: No | pure passthrough — archive must already carry Composer v2 metadata; only packages.json emitted inline; no synthesis from bare zips; list() empty | server/repository/znippy-composer/src/lib.rs |
| Ecosystem | raw | Yes | Yes | No | Yes | native index: No; znippy backend: No; writable: Yes; proxy upstream: No; generic-fetch: Yes; browse: Yes | 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) | server/lib/src/raw.rs |
| Ecosystem | Znippy-native | Yes | No | No | Yes | native index: No; znippy backend: Yes; writable: No; proxy upstream: No; generic-fetch: Yes; browse: Yes | Holger-native surface (no ecosystem protocol); optional CMS provenance verify behind sign (ron_trusted_roots) — without sign a trusted-roots config fails wiring closed |
server/repository/znippy-package/src/lib.rs |
Non-negotiable invariants
The authoritative invariant list. Strength uses the invariant vocabulary.
→ Enforcement APIs: ai-context-full.md.
| Invariant | Contract | Strength | Enforced at | Tests |
connector-same-origin |
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. | Enforced | agent/connector/nexus/src/lib.rs:131; agent/connector/artifactory/src/lib.rs:125 | agent/connector/nexus/src/lib.rs; agent/connector/artifactory/src/lib.rs |
world-ssrf-allowlist |
The world connector downloads only https URLs whose host is in the CDN allowlist (crates.io, static.crates.io, pypi.org, files.pythonhosted.org). | Enforced | agent/connector/world/src/lib.rs:76 | agent/connector/world/src/lib.rs:220 |
no-traversal |
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. | Enforced | agent/lib/src/operations.rs:108; server/lib/src/raw.rs:60; server/lib/src/promote/mod.rs:214 | agent/lib/src/operations.rs; server/lib/src/raw.rs; server/lib/src/promote/mod.rs |
promote-seal-once |
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. | Enforced | server/lib/src/promote/mod.rs:578 | server/lib/src/promote/mod.rs |
withdraw-is-append |
Withdrawal appends a Withdrawn entry to the lineage log; the sealed blob and ref are never touched. Current state is derived by replaying history. | Enforced | server/lib/src/promote/stages.rs:289 | server/lib/src/promote/mod.rs |
format-version-pin |
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). | Enforced | traits/src/znippy_format.rs:61 | server/repository/znippy-rust/tests/format_version_gate.rs |
read-gate-opt-in-fail-closed |
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). | Enforced | server/lib/src/auth.rs; server/lib/src/grpc.rs:350 | server/lib/src/grpc.rs; server/lib/src/exposed/http.rs |
write-gate-fail-closed |
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. | Enforced | server/lib/src/grpc.rs:244; server/lib/src/exposed/http.rs | server/lib/src/grpc.rs |
audit-append-only |
The audit log is one fresh Arrow-IPC segment per process, only appended; replay skips a corrupt segment without losing intact ones. | Enforced | server/lib/src/audit/arrow_ipc.rs | server/lib/src/audit/arrow_ipc.rs |
transfer-partial-success |
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. | Enforced | agent/lib/src/operations.rs | agent/lib/src/operations.rs |
tier-mutual-exclusion |
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. | Enforced | server/cli/src/main.rs; build-space/build-variants.toml | build-space/tests/auth_ship_small.rs; build-space/tests/build_variants_no_drift.rs |
storage-endpoint-is-stub |
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. | Enforced | server/lib/src/storage/mod.rs; server/lib/src/repository.rs | — |
sec-ssrf-world-connector |
Download URLs from upstream JSON must be https + host-allowlisted before any request | Enforced | agent/connector/world/src/lib.rs:76 | agent/connector/world/src/lib.rs:220 |
sec-ssrf-credential-exfil-nexus-artifactory |
Registry-supplied downloadUrl must be same scheme+host+port as base before creds attach | Enforced | agent/connector/nexus/src/lib.rs:131; agent/connector/artifactory/src/lib.rs:125 | agent/connector/nexus/src/lib.rs; agent/connector/artifactory/src/lib.rs |
sec-redirect-disabling |
All connector HTTP clients use redirect::Policy::none() — only the initial URL is vetted | Enforced | agent/connector/world/src/lib.rs; agent/connector/nexus/src/lib.rs; agent/connector/artifactory/src/lib.rs | — |
sec-unbounded-read |
Response bodies capped (8 GiB artifact / 256 MiB JSON); tar entries capped 8 GiB (MAX_TAR_ENTRY_BYTES) | Enforced | agent/connector/world/src/lib.rs:38; agent/lib/src/operations.rs:30 | — |
sec-server-body-cap |
put payloads capped (default 1 GiB, ron_max_body_bytes; shared gRPC/HTTP knob) | Enforced | server/lib/src/grpc.rs:41; server/lib/src/exposed/http.rs:642 | server/lib/src/grpc.rs |
sec-path-traversal-agent |
Upstream asset + archive member paths reject absolute/Prefix/.. per-component | Enforced | agent/lib/src/operations.rs:108 | agent/lib/src/operations.rs |
sec-path-traversal-server |
Raw relpaths reject empty/./../backslash/NUL; sbom/property coords sanitized; promote to_repo sanitized to one segment | Enforced | server/lib/src/raw.rs:60; server/lib/src/promote/mod.rs:214 | server/lib/src/raw.rs; server/lib/src/promote/mod.rs |
sec-atomic-writes |
temp+rename for raw puts, promote blobs, properties, sbom | Enforced | server/lib/src/raw.rs:113; server/lib/src/promote/mod.rs:583 | server/lib/src/raw.rs |
sec-immutable-promote-seal |
A (to_repo, coord) seals exactly once via create_new; re-promote refused, race-safe | Enforced | server/lib/src/promote/mod.rs:578 | server/lib/src/promote/mod.rs |
sec-withdrawal-append |
Withdraw appends a Withdrawn lineage entry; blob+ref never touched; state is a history replay | Enforced | server/lib/src/promote/stages.rs:289 | server/lib/src/promote/mod.rs |
sec-content-hashing-integrity |
promote store blake3 (address + re-verify on fetch); cargo cksum + raw delete + replication dedup via nornir_hash::sha256_hex | Enforced | server/lib/src/promote/mod.rs:575; server/lib/src/replication.rs:40 | server/lib/src/promote/mod.rs |
sec-writable-znippy-locking |
Writable-archive put is read-modify-write under write_lock serializing contains-check + append | Enforced | server/repository/znippy-rust/src/lib.rs:59 | server/repository/znippy-rust/src/lib.rs |
sec-znippy-format-version-pin |
Archive recording version > MAX_SUPPORTED_ZNIPPY_FORMAT (=3) or non-numeric is refused at open and per-request (503) | Enforced | traits/src/znippy_format.rs:61 | server/repository/znippy-rust/tests/format_version_gate.rs |
sec-audit-permissions |
Audit dir 0700, segments 0600, never rewritten | Enforced | server/lib/src/audit/arrow_ipc.rs:71 | — |
sec-error-leak-prevention |
Backend errors laundered to opaque 'internal error'; detail only in server log; quarantine served as not_found | Enforced | server/lib/src/grpc.rs:47; server/lib/src/grpc/services.rs:90 | server/lib/src/grpc.rs |
sec-quarantine-gate |
A quarantined artifact is refused at every serve door as not_found (existence not leaked) | Enforced | server/lib/src/grpc/services.rs:90 | server/lib/src/grpc.rs |
Security-sensitive code map
Maps a concern to its authoritative invariant (above) — enforcement and tests are not restated here.
| Concern | Invariant | Security boundary | Consequence if broken |
| SSRF (world connector) | sec-ssrf-world-connector |
Download URLs from upstream JSON must be https + host-allowlisted before any request | Agent fetches attacker URLs (cloud metadata, internal services) |
| SSRF + credential exfil (nexus/artifactory) | sec-ssrf-credential-exfil-nexus-artifactory |
Registry-supplied downloadUrl must be same scheme+host+port as base before creds attach | Basic/Bearer creds leak to arbitrary hosts |
| Redirect disabling | sec-redirect-disabling |
All connector HTTP clients use redirect::Policy::none() — only the initial URL is vetted | A 3xx from a compromised allowlisted host bypasses the origin guard and smuggles creds (no redirect-following test exists — Unverified) |
| Unbounded read | sec-unbounded-read |
Response bodies capped (8 GiB artifact / 256 MiB JSON); tar entries capped 8 GiB (MAX_TAR_ENTRY_BYTES) | Malicious upstream/archive OOMs the agent (no direct cap-trip test — Unverified) |
| Server body cap | sec-server-body-cap |
put payloads capped (default 1 GiB, ron_max_body_bytes; shared gRPC/HTTP knob) | Upload DoS |
| Path traversal (agent) | sec-path-traversal-agent |
Upstream asset + archive member paths reject absolute/Prefix/.. per-component | RCE on the agent host via file drop outside the destination |
| Path traversal (server) | sec-path-traversal-server |
Raw relpaths reject empty/./../backslash/NUL; sbom/property coords sanitized; promote to_repo sanitized to one segment | Read/write outside the store roots |
| Atomic writes | sec-atomic-writes |
temp+rename for raw puts, promote blobs, properties, sbom | Torn files served as artifacts |
| Immutable promote seal | sec-immutable-promote-seal |
A (to_repo, coord) seals exactly once via create_new; re-promote refused, race-safe | PROD overwrite / supply-chain tamper |
| Withdrawal = append | sec-withdrawal-append |
Withdraw appends a Withdrawn lineage entry; blob+ref never touched; state is a history replay | Sealed history rewritten |
| Content hashing / integrity | sec-content-hashing-integrity |
promote store blake3 (address + re-verify on fetch); cargo cksum + raw delete + replication dedup via nornir_hash::sha256_hex | Tampered blob served |
| Writable znippy locking | sec-writable-znippy-locking |
Writable-archive put is read-modify-write under write_lock serializing contains-check + append | Two concurrent puts corrupt the .znippy |
| znippy format-version pin | sec-znippy-format-version-pin |
Archive recording version > MAX_SUPPORTED_ZNIPPY_FORMAT (=3) or non-numeric is refused at open and per-request (503) | 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. |
| Audit permissions | sec-audit-permissions |
Audit dir 0700, segments 0600, never rewritten | Local users read principal identities / access patterns (no perms-assertion test — Unverified) |
| Error-leak prevention | sec-error-leak-prevention |
Backend errors laundered to opaque 'internal error'; detail only in server log; quarantine served as not_found | Archive/file paths and internals leak to anonymous readers (redaction itself Unverified) |
| Quarantine gate | sec-quarantine-gate |
A quarantined artifact is refused at every serve door as not_found (existence not leaked) | Quarantined/withdrawn artifact still served; existence oracle |
Failure semantics
An Ok result may still contain partial failures; degraded operation is not full operation.
→ Error/Result types: ai-context-full.md.
| Operation | Fatal errors | Partial success | Retry | Cleanup/rollback | Degraded mode | Observable result | Evidence |
| Config parsing (RON) | yes — malformed RON aborts startup via ? | no | none | nothing written yet | — | stderr + non-zero exit | server/lib/src/lib.rs |
| Graph wiring (wire_holger) | yes on structural errors | no — the graph is built once, then frozen (raw pointers, never mutated) | none | n/a | — | startup error | server/lib/src/lib.rs |
| Backend initialization | only if ALL repos fail | yes — a failing repo is disabled + logged, the rest serve; the disabled repo is absent from FastRoutes (per-request not_found) | none | n/a | — | log::error per repo + warn summary | server/lib/tests/graceful_backend_init.rs |
| gRPC / HTTP bind | yes — a bind failure on an endpoint aborts that endpoint's task | endpoints are independent tasks | none | n/a | — | startup error / task log | server/lib/src/lib.rs |
| Authentication | no — per-request only | n/a | none | n/a | — | gRPC unauthenticated / HTTP 401; refusals audited as the attempted subject | server/lib/src/auth.rs |
| Authorization | no — per-request | n/a | none | n/a | — | gRPC permission_denied / HTTP 403; read-only repo write → 403 pre-body | server/lib/src/grpc.rs |
| Audit sink init | no — falls back to NoopAuditLog | audit silently off after a loud error (availability > audit) | none | n/a | — | log::error 'audit DISABLED' | server/lib/src/lib.rs |
| Audit event write | no — never fails the request | the event line is lost | none | n/a | — | log::warn 'audit record failed' | server/lib/src/grpc.rs |
| Connector repository/asset listing | yes — a list error aborts the operation (dump_all_repos: a repo task Err or list_assets Err is fatal) | no | none | n/a | — | CLI error | agent/lib/src/operations.rs |
| Connector download | no (in most transfer ops) | yes — a failed download is counted + skipped; the op still returns Ok with a nonzero failed tally | none (no backoff anywhere in connectors) | n/a | — | stdout tally 'N downloaded, M failed' | agent/lib/src/operations.rs |
| Agent archive creation (pack) | yes — a source read failure is fatal for pack_directory_to_znippy | transfer_to_* count download failures but a channel/tar-append failure is fatal | none | non-atomic (File::create directly, no temp+rename) | — | stdout tally / CLI error | agent/lib/src/operations.rs |
| Agent upload (push) | source-read fatal; decode over-cap short-circuits | yes — per-asset upload failure counted (UploadOutcome::Failed); unsafe member path counted-skipped; Ok(()) with a nonzero tally | none | n/a | — | per-item ✓/✗ + '✅ N succeeded, M failed' | agent/lib/src/operations.rs |
| Archive unpack | unpack_tar_zstd: read_capped over-cap is fatal | 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) | none | non-atomic writes; safe_join blocks traversal | — | stdout tally + non-zero exit for unpack_znippy | agent/lib/src/operations.rs |
| Archive conversion (znippy↔tar-zstd) | yes on decode/read error | staged through a tempdir | none | tempdir dropped | — | CLI error | agent/lib/src/operations.rs |
| Repository fetch | no — a miss is Ok((404,…)), never Err; backend errors are laundered to opaque 'internal error' | n/a | none | n/a | — | 404 / opaque 500 (detail only in server log); quarantined → not_found | server/lib/src/grpc.rs |
| Repository put | over body-cap → 413; unauthorized → 401/403 pre-body | no | none | atomic (temp+rename) for raw/file backends; writable-znippy append under write_lock | — | gRPC status / HTTP code | server/lib/src/grpc.rs; server/lib/src/raw.rs |
| Promotion | request-only; gates run BEFORE any write (advisory/property/license) | a lineage-append failure AFTER the seal is non-fatal + logged loudly | none | an illegal promotion writes nothing; seal is create_new (exclusive) | — | 412 failed_precondition, audited; job ledger records 'failed' | server/lib/src/promote/mod.rs |
| Withdrawal | request-only | no — appends a Withdrawn lineage entry; blob+ref untouched | none | append-only (OpenOptions::append) | — | state reduced from history replay | server/lib/src/promote/stages.rs |
| Retention planning | no — dry-run default plans without deleting | reports candidates + reclaimed bytes | none | n/a (no writes in dry-run) | — | plan output; --execute required to delete | server/lib/src/retention.rs |
| Retention execution | no | per-artifact delete; deletes historized as ident holger-retention-gc | none | sha256-verified delete on raw/file backends | — | audit Delete events + reclaimed bytes; job ledger 'retention-gc' | server/lib/tests/retention_executor.rs |
| Replication | no — per-artifact failures counted (Outcome::Failed) | yes — is_complete() false; read-only dest → Failed fail-closed | none; idempotent re-run (sha256 skip) | dry-run default writes nothing | — | copied/skipped/would_copy/failed tallies; admin-gated RPC, audited | server/lib/src/replication.rs |
| Airgap driver execution | a non-zero driver exit is captured into the Report (the one shell-out) | the driver has its own AIRGAP_DRY_RUN; --dry-run returns before driver discovery | none | n/a (external process) | — | captured stdout/stderr/exit in the Report | airgap/src/lib.rs |
| UI remote connection | no — connection error surfaced in the UI, not a crash | n/a | user-driven | n/a | — | error state in the egui view (block_on on a private runtime) | server/lib/src/object.rs; server/ui/src/data.rs |
Trust and lifecycle
State transitions and which states affect detection/enforcement (implementation locations live in the invariants).
(no entries)
Human gates (propose vs act):
(no entries)
State and persistence
→ Persistence types: ai-context-full.md.
(no entries)
Change-impact map
| Interface/type | Defined in | Implementers | Main consumers | Runtime significance | Required tests |
| RepositoryBackendTrait | traits/src/lib.rs:202 | ~21 production (16 backend crates + group/proxy/raw/upstream_rust/upstream) + ~22 test mocks | fast_routes, grpc + grpc/services, exposed/http, object.rs, search, replication, retention | central backend contract; ADDING a defaulted method is safe, changing fetch/put/handle_http2_request breaks every backend at compile | cargo test -p holger-server-lib |
| ConnectorTrait | traits/src/lib.rs:404 | Nexus / Artifactory / World connectors + a bench mock | agent/lib operations.rs, agent/cli main.rs, UI tools pane, airgap driver | the agent transfer contract; async; changing it touches every connector + the transfer matrix | cargo test -p holger-agent-cli |
| HolgerObject | traits/src/lib.rs:556 | LocalHolger + RemoteHolger (object.rs) + FakeHolger (UI test) | UI UiData (data.rs), holger-embed, holger-demo, server CLI | the in-process vs gRPC facade the UI is built on | cargo test -p holger-server-ui |
| ArtifactId / ArtifactFormat | traits/src/lib.rs | data types; ArtifactFormat has 15 variants, each with a backend; proto twin in generated/holger.v1.rs | everything; from_format_str parsing, znippy_type_id() discriminants | adding a format variant triggers non-exhaustive-match errors across backends + a proto round-trip test | cargo test -p holger-server-lib |
| znippy read/format seam (FormatGate, ensure_supported_format, plugin views as_rust/as_maven/…) | traits/src/znippy_format.rs | gate consumed ONLY by znippy-rust; typed views per-backend (maven/npm/python/conda/gem/rust) | all znippy backends open archives via znippy-common; writer seam used by znippy-rust dev-mode + agent pack | any znippy API change breaks the whole workspace via [patch.crates-io] | cargo test -p holger-rust-znippy-repository --test format_version_gate |
| AuditLog | server/lib/src/audit/mod.rs | Noop / Memory / ArrowIpc (arrow_ipc.rs) / Channel (UI lineage) | grpc + grpc/services fetch/put/promote, exposed/http, replication | the audit choke point; a new door that skips record_audit loses the audit trail | cargo test -p holger-server-lib audit |
| AuthProvider seam (nornir_service, edda) | server/lib/src/auth.rs | bearer / oidc / oauth2 / mtls providers (webauthn declared, unwired) | grpc.rs + exposed/http.rs validate_request; build-space tier link-audit | changing the seam affects every tier's pinned provider set; fail-closed when unpinned | cargo test -p holger-server-lib; cargo test -p holger-build-space --test auth_ship_small |
| PromotionEngine | server/lib/src/promote/mod.rs | single engine + stages.rs lineage | grpc/services PromotionService, lib.rs startup wiring, job ledger | seal-once + withdraw-is-append invariants live here; a File::create 'idempotence' change breaks immutability | cargo test -p holger-server-lib promote |
| replication::replicate_pairs | server/lib/src/replication.rs | one pure engine over RepositoryBackendTrait | grpc/services ReplicationService (admin-gated), CLI replicate verb | sha256-idempotent, dry-run-default; the admin gate + dry-run default are the safety rails | cargo test -p holger-server-lib replication |
| generated gRPC types (holger.v1) | server/lib/src/generated/holger.v1.rs | prost/tonic codegen (committed, not built at compile) | grpc.rs conversions, every service, the RemoteHolger client | edit proto/holger.proto then cargo xtask gen-proto; hand-editing the generated file drifts from the proto |
cargo test -p holger-server-lib |
| UI data/model contract (UiData, views) | server/ui/src/data.rs | UiData over HolgerObject; SearchView/SbomView/etc. | app.rs scene/command, panes, tier features | RepositoryInfo drives Browse off has_archive() — only znippy-rust overrides it, so most backends show empty Browse | cargo test -p holger-server-ui |
| build variant types | build-space/build-variants.toml | build-space crate + tier features on server-lib/server-cli/holger-server-ui | the compile_error! tier guard in server/cli/main.rs; auth_ship_small + tier_ladder audits | tiers are mutually exclusive; a cross-tier feature edge or a forbidden dep (openssl/webauthn) fails the link-audits | cargo test -p holger-build-space |
Task-to-file map
→ Crate/module map: ai-context-full.md.
| Task | Start here | Follow-up | Invariants | Fast test | Full test | Heavy/optional test |
| Add a repository backend / ecosystem | server/lib/src/repository.rs, traits/src/lib.rs |
server/repository/znippy-rust/src/lib.rs, server/repository/file-rust/src/lib.rs, server/lib/src/exposed/http.rs |
no-traversal, format-version-pin |
cargo test -p holger-rust-znippy-repository --test format_version_gate |
cargo test -p holger-server-lib && cargo test -p holger-rust-znippy-repository |
— |
| Add / change a connector | traits/src/lib.rs, agent/connector/nexus/src/lib.rs |
agent/lib/src/operations.rs, agent/cli/src/main.rs |
connector-same-origin, world-ssrf-allowlist, no-traversal |
cargo test -p holger-nexus-connector && cargo test -p holger-world-connector |
cargo test -p holger-agent-cli |
cargo test -p holger-agent-cli -- --ignored |
| Change agent transfer / partial-success | agent/lib/src/operations.rs |
agent/cli/src/main.rs |
transfer-partial-success, no-traversal |
cargo test -p holger-agent-lib |
cargo test -p holger-agent-cli |
— |
| Change HTTP routing / native protocols | server/lib/src/exposed/http.rs |
server/lib/src/lib.rs, server/repository/znippy-rust/src/lib.rs |
write-gate-fail-closed, read-gate-opt-in-fail-closed |
cargo test -p holger-server-lib --test integration_oci_tls |
cargo test -p holger-server-lib |
— |
| Change authentication / authorization | server/lib/src/auth.rs |
server/lib/src/grpc.rs, server/lib/src/exposed/http.rs |
write-gate-fail-closed, read-gate-opt-in-fail-closed, tier-mutual-exclusion |
cargo test -p holger-server-lib auth |
cargo test -p holger-server-lib && cargo test -p holger-build-space --test auth_ship_small |
— |
| Change audit logging | server/lib/src/audit/arrow_ipc.rs, server/lib/src/audit/mod.rs |
server/lib/src/grpc.rs, server/lib/src/exposed/http.rs |
audit-append-only |
cargo test -p holger-server-lib audit |
cargo test -p holger-server-lib |
— |
| Change promotion / retention | server/lib/src/promote/mod.rs, server/lib/src/promote/stages.rs |
server/lib/src/grpc/services.rs, server/lib/src/lib.rs |
promote-seal-once, withdraw-is-append |
cargo test -p holger-server-lib promote |
cargo test -p holger-server-lib && cargo test -p holger-server-lib --test retention_executor |
— |
| Change replication | server/lib/src/replication.rs |
server/lib/src/grpc/services.rs, server/cli/src/main.rs |
write-gate-fail-closed |
cargo test -p holger-server-lib replication |
cargo test -p holger-server-lib |
— |
| Change airgap behavior | airgap/src/lib.rs |
server/cli/src/main.rs |
— | cargo test -p holger-airgap |
— | — |
| Change the proto / gRPC surface | proto/holger.proto |
server/lib/src/generated/holger.v1.rs, server/lib/src/grpc.rs |
— | cargo test -p holger-server-lib |
cargo xtask gen-proto && cargo test -p holger-server-lib |
— |
| Change the UI | server/ui/src/data.rs, server/ui/src/main.rs |
server/lib/src/object.rs, server/ui/tests/tier_ladder.rs |
tier-mutual-exclusion |
cargo test -p holger-server-ui |
cargo test -p holger-server-ui --features gui |
cargo test -p holger-server-ui --test tier_ladder -- --ignored |
| Change a deployment tier / build variant | build-space/build-variants.toml, server/cli/src/main.rs |
server/lib/Cargo.toml, server/ui/Cargo.toml |
tier-mutual-exclusion |
cargo test -p holger-build-space |
— | cargo test -p holger-server-ui --test tier_ladder -- --ignored |
CLI inventory
→ CLI command enums / parsers: ai-context-full.md.
| Binary | Command/subcommand | Important flags | Calls into | Runtime/feature restrictions | Tests |
| holger-server | start | --config | server/lib/src/lib.rs | tier features embedded/mini/full (mutually exclusive) | cargo test -p holger --test tools_robot |
| holger-server | dev-pair | --data [--grpc 127.0.0.1:18443] [--http 127.0.0.1:18444] | server/lib/src/lib.rs | dev convenience — autogen RON + sparring archives | — |
| holger-server | install / service | add|update|remove|status|render; service install|start|stop|status|health|uninstall --scope user|system | server/cli/src/main.rs | none | — |
| holger-server | retention | --config [--repo --keep-last-n --max-age-secs --max-total-bytes --protect-property k=v --execute] | server/lib/src/retention.rs | dry-run default; --execute deletes | cargo test -p holger-server-lib --test retention_executor |
| holger-server | replicate | --from --to [--repo] [--execute] [--limit] | server/lib/src/replication.rs | dry-run default; pairs repos by identical name | — |
| holger-server | airgap | --stack --scale micro|small|large --target holger|nexus|artifactory --auth mtls [--dry-run --build-only --push-only] | airgap/src/lib.rs | --dry-run returns before driver discovery; needs distribution/airgap/populate on disk | — |
| holger-server | search / sbom / properties / scan / holger-ds | search --name/--sha256/--property; sbom attach|fetch; properties set|get; holger-ds --scale/--preset (bench) | server/lib/src/lib.rs | holger-ds requires bench (omitted by embedded/mini) |
— |
| holger-agent | (single verb) | --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 | agent/lib/src/operations.rs | same-type + identity + world→server combos bail (airgap first) | cargo test -p holger-agent-cli |
| holger-server-ui | (positional ENDPOINT) | ENDPOINT (default http://127.0.0.1:50051) --token --ca --cert --key [--demo (demo feature)] [--robot-remote (robot-remote feature)] | server/ui/src/main.rs | gui/gui-mini/gui-mikro tiers; --demo needs demo; tier binaries: holger-server-ui, holger-server-ui-mini, holger-server-ui-mikro |
cargo test -p holger-server-ui |
| holger-mannequin | serve / pki generate | [--gui] one-port mock PKI+OIDC+Nexus | mannequin/src/main.rs | TEST/DEV ONLY — never production | cargo test -p holger-mannequin |
| xtask | gen-proto / demo-wasm / deploy-pages | gen-proto (protox+tonic-build, pure Rust) | xtask/src/main.rs | dev tooling; gen-proto output is committed | cargo test -p xtask --test holger_matrix |
Configuration and environment
→ Config structs: ai-context-full.md.
Main config (secrets never appear in the config file — see environment):
| Config field | Type | Default | Required | Sensitive | Runtime consumer | Reloadable | Validation |
repositories[].ron_name |
String | — | Yes | — | server/lib/src/repository.rs | startup-only | — |
repositories[].ron_repo_type |
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) | — | Yes | — | server/lib/src/repository.rs | startup-only | *-remote need federation/online; unknown value = boot error |
repositories[].ron_upstreams |
Vec | [] | Yes | — | server/lib/src/lib.rs | startup-only | proxy chain, first-hit-wins; makes the repo a ProxyBackend |
repositories[].ron_archive_path |
Option | — | No | — | server/lib/src/repository.rs | startup-only | read-only znippy snapshot (required by znippy_backed! backends) |
repositories[].ron_writable_archive |
Option | — | No | — | server/repository/znippy-rust/src/lib.rs | startup-only | rust only; live seal-able archive; wins over archive_path/data_dir |
repositories[].ron_data_dir |
Option | /var/lib/holger/{ron_name} | No | — | server/repository/file-rust/src/lib.rs | startup-only | file/oci/raw backends |
repositories[].ron_trusted_roots |
Option (DER root) | — | No | No | server/lib/src/repository.rs | startup-only | znippy CMS provenance verify; needs sign, else wiring fails closed |
exposed_endpoints[].ron_url |
String (SocketAddr) | — | Yes | — | server/lib/src/lib.rs | startup-only | the gRPC listen address |
exposed_endpoints[].ron_http_url |
Option | — | No | — | server/lib/src/exposed/http.rs | startup-only | enables the native-protocol HTTP/OCI door + /healthz /readyz |
exposed_endpoints[].ron_tls |
Option<{cert, key, client_ca}> | — | No | Yes | server/lib/src/exposed/tls.rs | startup-only | client_ca present ⇒ mTLS; absent ⇒ cleartext (loud warning) |
exposed_endpoints[].ron_max_body_bytes |
Option | 1 GiB | No | — | server/lib/src/grpc.rs | startup-only | shared gRPC message + HTTP body cap |
auth.methods[] |
Vec<Oidc|OAuth2|Mtls|StaticToken> | — | No | Yes | server/lib/src/auth.rs | startup-only | provider must be feature-pinned by the tier or it authenticates nothing (fail-closed) |
auth.roles / default_role / repo_roles |
Map<subject,Role> (Denied|Reader|Writer|Admin) | {} (RBAC off) | No | — | server/lib/src/auth.rs | startup-only | empty + no default_role ⇒ RBAC disabled; set ⇒ fail-closed writes |
auth.require_auth_for_reads |
bool | false | No | — | server/lib/src/auth.rs | startup-only | opt-in read gate (fail-closed); health stays open |
audit.dir / audit.enabled |
String / bool | holger-audit (under $HOLGER_DATA) / true | No | — | server/lib/src/audit/arrow_ipc.rs | startup-only | relative dir anchors under $HOLGER_DATA; absolute wins |
Environment variables:
| Variable | Category | Default | Sensitive | Runtime/build/test | Consumer | Effect |
HOLGER_DATA |
path | — | — | runtime | server/lib/src/lib.rs; server/ui/src/data.rs | anchors relative audit dir; derives data_root for prod store / job ledger / sboms / props |
HOLGER_TOKEN |
secret | — | Yes | runtime | server/ui/src/main.rs | UI bearer token (alt to --token) |
HOLGER_PROMOTE_ENFORCE |
enum (block|warn|off) | — | — | runtime | server/lib/src/promote/mod.rs | promote policy enforcement; a bad value FAILS startup |
HOLGER_PROMOTE_ADVISORY_DB |
path | — | — | runtime | server/lib/src/promote/mod.rs | OSV/GHSA snapshot for promote gating; unreadable ⇒ serve refuses to start |
HOLGER_PROMOTE_DENY_LICENSES |
csv | — | — | runtime | server/lib/src/promote/mod.rs | SPDX ids denied at promote |
HOLGER_PROMOTE_REQUIRE_PROPERTY |
k=v | — | — | runtime | server/lib/src/lib.rs | RETIRED (2026-10-22): set ⇒ the promotion engine is refused; the requirement is promotion.require_property in the RON config |
HOLGER_QUARANTINE_PROPERTY |
k=v | — | — | runtime | server/lib/src/lib.rs | 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) |
HOLGER_WAREHOUSE |
path | — | — | runtime | server/ui/src/data.rs | opens the skade/modgunn Iceberg advisory warehouse in-process (warehouse-scan only) |
HOLGER_DEMO_BEAT_MS |
int | 2200 | — | dev | server/ui/src/main.rs | demo robot beat interval |
HOLGER_DEMO_IMAGE |
string | docker.io/library/registry:2.8.3 | — | dev | server/ui/src/infra.rs | demo appliance image |
HOLGER_BENCH_DIR |
path | $HOME/holger-bench-data | — | bench | bench-scenarios/src/lib.rs | bench fixture root |
HOLGER_BENCH_SCALE |
enum (quick|full|huge) | — | — | bench | bench-scenarios/src/lib.rs | bench preset; NORNIR_BENCH_QUICK=0 forces full |
HOLGER_REQUIRE_NETWORK |
flag | — | — | test | agent/cli/tests/integration_pip.rs | test-only: convert offline skip into a failure |
HOLGER_BENCH_BYTES |
int | — | — | bench | bench-scenarios/src/lib.rs | override synthetic artifact size |
HOLGER_BENCH_ENTRIES |
int | — | — | bench | bench-scenarios/src/lib.rs | override synthetic entry count |
HOLGER_BENCH_SECS |
int | — | — | bench | bench-scenarios/src/lib.rs | override bench run duration |
HOLGER_BENCH_REAL |
flag (REAL=0 opts out) | — | — | bench | bench-scenarios/src/lib.rs | use synthetic instead of real-artifact corpus |
HOLGER_BENCH_BOOT_SECS |
int | — | — | bench | bench-scenarios/src/lib.rs | JVM/container boot timeout for competitor twins |
NORNIR_BENCH_QUICK |
flag (=0 forces full) | — | — | bench | bench-scenarios/src/lib.rs | back-compat scale toggle |
DOCKER_HOST |
url | — | — | test | bench-scenarios/src/lib.rs | testcontainers socket autodetect (rootless podman) |
PIP_PROBE_MB |
int | — | — | bench | bench-scenarios/examples/pip_probe.rs | pip probe example sizing |
PIP_PROBE_SECS |
int | — | — | bench | bench-scenarios/examples/pip_probe.rs | pip probe example duration |
Precedence (verified):
- 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.
Dependencies (full workspace graph + external hotspots are in the full pack):
42 workspace crates, 99 deduplicated workspace edges, 95 external dependencies. External hotspots and full coupling are in ai-context-full.md.
| High-coupling crate | Incoming | Outgoing |
holger-traits |
28 | 0 |
holger-server-lib |
5 | 22 |
holger-bench-scenarios |
4 | 7 |
holger-agent-cli |
0 | 8 |
holger-plugin-host |
3 | 5 |
holger-agent-lib |
3 | 4 |
holger-rust-znippy-repository |
4 | 3 |
holger-server-ui |
0 | 7 |
Tests inventory
Derived totals: 658 unit test fns across 91 files, 239 integration test fns.
Incomplete work and current limitations
| Marker classification | Count |
| false-positive | 7 |
| heavy-test | 24 |
→ Full marker list: ai-context-full.md.
Documentation and wiring mismatches
None: no status contradictions, and every declared invariant has enforcement locations.
Size and generation metadata
Measured for the compact pack (excludes this footer):
| Metric | Value |
| Bytes | 54112 |
| Lines | 399 |
| Words | 7085 |
| Approx tokens (chars/4) | 13528 |
| Token budget | 45% of 30000 |
| Duplicate-sentence ratio | 0.000 (max 0.040) |
| Duplicate-row ratio | 0.000 (max 0.020) |