Backlog¶
Stable BL-NNN ids. Ids are never renumbered and resolved items are never
deleted (status moves to resolved). Each item cites its source ADR. Sizes:
XS, S, M, L.
| ID | Item | Size | Status | Source ADR |
|---|---|---|---|---|
| BL-001 | Add full Apache-2.0 LICENSE text and NOTICE | XS | resolved | 0001 |
| BL-002 | Write ADR-0002..0010 and complete pyproject.toml + Makefile |
S | resolved | 0002 |
| BL-003 | Complete STPA artifacts 01..07 (losses, hazards, constraints, control structure, UCAs, loss scenarios, security constraints) | M | resolved | 0009 |
| BL-004 | Execution core: patterns/policy/redaction/audit/contract/runner (vendored + fused), with invariant tests | L | resolved | 0004, 0005 |
| BL-005 | StoreProtocol + ladder; SQLite default backend (bitemporal, append-only trigger, active-fact constraint, sqlite-vec) | L | resolved | 0002, 0003 |
| BL-006 | Postgres+AGE+pgvector production backend behind the same Protocol | M | resolved | 0002, 0003 |
| BL-007 | Fact model + host_type; osquery and AIDE collectors (read-only) | M | resolved | 0007 |
| BL-008 | Drift engine: desired-state sources (tofu plan, ansible check, known-good) + findings | L | resolved | 0007 |
| BL-009 | Actuation adapters (ssh/opentofu/ansible/runbook/talosctl/redfish/cloud) with DRY_RUN -> approve -> execute | L | resolved | 0004, 0005 |
| BL-010 | Skills engine: manifest, registry, routing-chain dispatcher; eval gate + schema guard | M | resolved | 0010 |
| BL-011 | Tamper-evident audit + evidence: supervisor writer, Merkle, RFC 3161, optional Rekor | M | resolved | 0008 |
| BL-012 | MCP server surface: config, transport guards (stdio/http, SSRF egress, consent), tools with annotations | L | resolved | 0006, 0041 |
| BL-013 | CI workflows (codeql, sbom, dependency-review, fuzz; pinned SHAs; least-privilege) + ci-success aggregate | M | resolved | 0001 |
| BL-014 | Hardened deploy: Helm chart, systemd units, optional zarf | M | resolved | 0006 |
| BL-015 | Compliance map: complete EU AI Act / NIS2 / CRA / GDPR / ISO 27001 mapping to controls | S | resolved | 0009 |
| BL-016 | Migration note: import prototype host-knowledge and known-good baselines into the model | S | resolved | 0007 |
| BL-017 | Audit read and ingest tools through the single path (query_facts, fact_history, ingest_observation, drift_scan currently bypass run()) |
S | resolved | 0011, 0016 |
| BL-018 | Write an audit record for trifecta denials before raising TrifectaViolation (context + actuate) |
S | resolved | 0011, 0013 |
| BL-019 | Include the tool name in the classify/deny probe; document that any future stdin/env passthrough must be classified | S | resolved | 0011, 0016 |
| BL-020 | SSH adapter host-key policy (StrictHostKeyChecking accept-new/yes, BatchMode=yes, UserKnownHostsFile) |
S | resolved | 0011, 0013 |
| BL-021 | run_subprocess process-group isolation (start_new_session=True plus killpg on timeout) |
S | resolved | 0011, 0013 |
| BL-022 | Keep Talos snapshot hash verification on etcd-restore (never pass --recover-skip-hash-check; optional sidecar verify) |
S | resolved | 0011, 0016 |
| BL-023 | Pre-flight talosctl health HARD precondition before talosctl upgrade |
S | resolved | 0011, 0016 |
| BL-024 | Runbook actuation by registry id (preferred) or a canonicalised, base-dir-contained path | M | resolved | 0011, 0016 |
| BL-025 | Safe-default destructive scope for talosctl reset (no implicit --wipe-mode ALL; ALL is T3-confirmed) |
S | resolved | 0011, 0016 |
| BL-026 | Finite-or-default numeric parsing of collected host data at every collector site | S | resolved | 0011, 0016 |
| BL-027 | Additive store extension Protocols plus content-hash compare-and-set for supersede | M | resolved | 0011, 0021 |
| BL-028 | Postgres backend engine-level append-only (REVOKE plus BEFORE TRUNCATE trigger; optional RESTRICTIVE RLS floor) |
M | resolved | 0011, 0018 |
| BL-029 | Serialise audit hash-chain appends for concurrent writers (process lock now; pg_advisory_xact_lock for the PG path) |
S | resolved | 0011, 0016 |
| BL-030 | Stamp raw_snapshot_hash of each collected snapshot into the Merkle checkpoint |
M | resolved | 0011, 0019 |
| BL-031 | Machine-checkable compliance map (bidirectional code/control/article validator plus framework coverage) in CI | M | resolved | 0011, 0021 |
| BL-032 | helm-unittest chart assertions for the praxis chart, gated in CI | M | resolved | 0011, 0027 |
| BL-033 | Supply-chain parity: real zarf digest, CycloneDX SBOM, values/sbom/zarf CI parity, governance-as-code labels | M | resolved | 0011, 0032, 0035 |
| BL-034 | Multi-severity parse_ansible_check (FAILED to ERROR, unreachable to CRITICAL, ok to known-good) |
S | resolved | 0011, 0013 |
| BL-035 | Documented audit/evidence retention tiers bound in config (NIS2 Art. 23, ISO 27001 A.8.15) | S | resolved | 0011, 0023 |
| BL-036 | Governance hygiene bundle (module back-citation headers, agent hard-rules, values-prod overlay plus version-bump checklist, namespace default-deny NetworkPolicy, regulatory-deadline data, empty-string-not-loopback test) | M | resolved | 0011, 0034 |
| BL-037 | verify_evidence fail-closed (return, never raise) and require checkpoints to cover the full log; document LocalStamper forgeability |
M | resolved | 0012 |
| BL-038 | Postgres append-only trigger: guard all identity columns, split per-table (facts vs edges), correct the parity docstring | M | resolved | 0012 |
| BL-039 | Store triggers: block any t_invalid/t_superseded/superseded_actor mutation that leaves a row active (supersede-without-actor bypass) |
S | resolved | 0012 |
| BL-040 | Patterns: fix the chmod/chown -R / deny and the /etc/ write tier (\b-before-/ defect); bump PATTERNS_VERSION |
S | resolved | 0012 |
| BL-041 | Redaction: cover space-separated credential flags and URL/DSN credentials; redact the stdio server error path | S | resolved | 0012 |
| BL-042 | SSRF: normalise decimal/hex/octal/trailing-dot IP forms; assert_egress_allowed fail-closed on a non-IP host |
S | resolved | 0012 |
| BL-043 | OpenTofu DRY_RUN uses a full tofu plan so the preview scope matches the apply scope |
XS | resolved | 0012 |
| BL-044 | _bounded_error never raises, so run() always writes exactly one audit record |
XS | resolved | 0012 |
| BL-045 | Docs honesty: ADR-0006 consent audit note; qualify SECURITY.md/LIMITATIONS.md; fix STPA _ssrf.py path and read-tool audit claim |
S | resolved | 0012 |
| BL-046 | SSRF: resolve hostnames and check every resolved IP (rebinding-aware); wire the filter into the egress path | M | resolved | 0012, 0025, 0030 |
| BL-047 | talosctl: enforce the T3 single-target rule on host.nodes, not only host.name |
S | resolved | 0012, 0013 |
| BL-048 | talosctl: replace action.split() with a verb allowlist; pass structured params |
S | resolved | 0012, 0013 |
| BL-049 | Wire CredentialBroker into the actuation path (scoped, revocable enforcement) |
M | resolved | 0012, 0016 |
| BL-050 | Audit hash chain: anchored high-water-mark to detect tail truncation | M | resolved | 0012, 0019 |
| BL-051 | Helm NetworkPolicy: restrict ingress with a from: selector |
S | resolved | 0012, 0018 |
| BL-052 | CI: make CodeQL/fuzz/sbom/dependency-review required gates, not branch-protection-external | S | resolved | 0012, 0036 |
| BL-053 | Add coverage tooling and a cov-fail-under gate |
S | resolved | 0012, 0018 |
| BL-054 | Store: _cosine finite-input guard; seq uniqueness or identity column to remove the MAX(seq)+1 race |
S | resolved | 0012, 0013 |
| BL-055 | Audit logger: do not reopen the file after _degrade; close the sink on degraded close |
S | resolved | 0012, 0013 |
| BL-056 | stdio server: bound the per-line read; correct JSON-RPC notification and batch handling | S | resolved | 0012, 0016 |
| BL-057 | Manifest parser: exact --- fence, size cap, reject indented keys, reject duplicate keys |
S | resolved | 0012, 0013 |
| BL-058 | Collectors: AIDE empty output is not clean; per-collector size caps; finite numeric parse (with BL-026) | S | resolved | 0012, 0013 |
| BL-059 | Drift: escalate UNEXPECTED security-predicate findings; split multi-host Ansible subjects |
S | resolved | 0012, 0013 |
| BL-060 | Deploy and config: Helm health probes, systemd drop-in dedupe, pin cyclonedx-bom, strip whitespace HTTP_HOST, normalise compliance-map path citations |
M | resolved | 0012, 0026 |
| BL-061 | Test and fuzz wave: Postgres parity suite, evidence tamper matrix, host_type refusal per adapter, SSRF bypass tests, fuzz manifest/merkle/evidence | M | resolved | 0012, 0020 |
| BL-062 | Route read tools (query_facts, fact_history, collector/skill reads) through the audited path, or formally document the deliberate exclusion; reconcile with invariant 1 wording |
S | resolved | 0012, 0016 |
| BL-063 | Actuation subprocess hardening: scrub env (GIT_TERMINAL_PROMPT=0, DEBIAN_FRONTEND=noninteractive, neutralise *_ASKPASS) and detach stdin (DEVNULL) so a wrapped tool cannot read the MCP stdio stream or hang on a prompt |
S | resolved | 0013 |
| BL-064 | Audit log opened O_APPEND and owner-only (0o600, plus chmod of a pre-existing file) so redacted parameters are not world/group readable |
XS | resolved | 0013 |
| BL-065 | Redaction: add provider token shapes (github_pat_, glpat-, npm_, AIza, ya29., Stripe, OpenAI scoped) and make Authorization value-complete (no SigV4 signature leak) |
S | resolved | 0013 |
| BL-066 | Self-containment: remove the out-of-tree prototype reference from context.py (no sibling repo named in code or docs) |
XS | resolved | 0013 |
| BL-067 | Config: strip whitespace from PRAXIS_HTTP_HOST so a "127.0.0.1\n" value is recognised as loopback; empty defaults to loopback (residual of BL-060) |
XS | resolved | 0013 |
| BL-068 | Store: add a seq identity/uniqueness so the MAX(seq)+1 read cannot race across two store instances on one file (residual of BL-054) |
S | resolved | 0013, 0016 |
| BL-069 | Clarify the self-contained rule (no coupling to sibling fleet repos, not anti-PyPI); record ADR-0014 and an appended audit note on ADR-0001; correct the over-absolute "implements everything itself" wording across the docs | S | resolved | 0014 |
| BL-070 | Adopt pydantic at the external-input boundary (MCP tool arguments, config, SKILL.md frontmatter) as the single source of truth for the JSON Schema and the parse/validate step; keep the execution core dependency-free | M | resolved | 0014 |
| BL-071 | SBOM CI repair: correct the cyclonedx-py environment output flag (--outfile to --output-file; the job had failed on every push to main since it was added), pin cyclonedx-bom==7.3.0 so a future unpinned major bump cannot change the CLI surface, and align the SBOM runner to Python 3.12 (the requires-python floor and the ci.yml matrix), so the supply-chain job is reproducible and off a bleeding-edge interpreter (closes the cyclonedx-bom pin in BL-060; residual of BL-033) |
S | resolved | 0014 |
| BL-072 | Approval gate human-binding: replace the deterministic expected_token (and its echo in the DRY_RUN body) with a server-issued, single-use, TTL-bound nonce surfaced out-of-band, so an autonomous caller cannot self-approve T2/T3 |
L | resolved | 0015, 0016 |
| BL-073 | Floor free-form shell/runbook/exec actuation at T2 (SSHAdapter.base_tier T1 to T2); keep the denylist upgrade-only; add the missing destructive patterns (find -delete, iptables -F, nft flush ruleset, kubectl drain/cordon, mass DELETE/UPDATE, Windows Remove-Item -Recurse/Format-Volume/Stop-Computer) and bump PATTERNS_VERSION |
M | resolved | 0015, 0016 |
| BL-074 | Wire BudgetTracker into ExecutionContext/run() so a per-session action, cost, and wall-time ceiling is enforced on the audited path |
M | resolved | 0015, 0016 |
| BL-075 | Give the kill switch an operator actuator (an MCP kill/restore tool plus a signal or file sentinel) and a durable trip record, so SEC-8 emergency stop is engageable at runtime, not only via the unwired broker | S | resolved | 0015, 0016 |
| BL-076 | Wire runtime audit anchoring: invoke periodic make_checkpoint from the server (or a supervised sidecar), implement a non-forgeable stamper (real RFC 3161 or a transparency-log anchor), and make operating-system append-only (chattr +a/WORM) a required, documented deploy control until then |
L | resolved | 0015, 0019 |
| BL-077 | Bound redact_args recursion depth and size inside the audited path and move it under the runner's failure containment, so a deeply nested args payload audits-and-denies instead of raising out of run() unaudited |
S | resolved | 0015, 0016 |
| BL-078 | execution/audit.py::_canonical: add default=str (as action_id already does) so AuditLogger.record can never raise on a non-JSON-native arg value (logger-never-raises by construction) |
XS | resolved | 0015, 0016 |
| BL-079 | Open the SQLite store file (and WAL/SHM sidecars) 0o600 so restricted facts are not group/world readable (mirror BL-064 for the audit log) |
XS | resolved | 0015, 0016 |
| BL-080 | Scope the actuation subprocess environment to an allowlist (PATH, LANG, SSH_AUTH_SOCK, TALOSCONFIG, the prompt-suppression knobs) instead of copying the full server environment, so unrelated secrets do not reach wrapped tools and their plugins |
S | resolved | 0015, 0016 |
| BL-081 | Ansible adapter input validation: apply the _SAFE_TARGET host check to host.name before --limit, and confine the playbook action to a configured base directory (extends BL-024 from runbook to ansible) |
S | resolved | 0015, 0016 |
| BL-082 | talosctl: reject post-verb tokens beginning with - (take structured resource args), and validate each nodes/endpoints value as an IP or RFC 1123 host, closing the --talosconfig flag-injection residual of BL-047/BL-048 |
S | resolved | 0015, 0016 |
| BL-083 | Move trifecta containment into the single audited path keyed off request.untrusted/context (not only the run_action handler); arm the latch on any read of attacker-influenced facts, not just live collection; remove or wire the dead ExecutionRequest.untrusted field |
M | resolved | 0015, 0016 |
| BL-084 | Validate and consume the approval before guard_actuation for all tiers, so the trifecta audit cannot record a T2+ call as gated on token presence while the executor later denies it on token validity |
S | resolved | 0015, 0016 |
| BL-085 | Route ingest_observation through run() (or document the deliberate exclusion) and add its UCA row, so the one untrusted-driven state-writing tool is audited and STPA-covered (sharpens BL-017/BL-062) |
S | resolved | 0015, 0016 |
| BL-086 | Helm: move storeDsn to a secretKeyRef (existingSecret), mirroring the http-token pattern, and block an inline plaintext DSN in the Deployment env |
S | resolved | 0015, 0018 |
| BL-087 | Deploy hardening: systemd PrivateUsers/ProcSubset=pid/RemoveIPC added and base-unit/drop-in de-duplicated, Helm DNS egress scoped to kube-system, egressCIDRs carry an always-on 169.254.0.0/16 except (ADR-0020). RESIDUAL (open): IPAddressDeny/SocketBindDeny and a sandbox runtimeClassName are documented but operator-scoped (a deny-all default bricks SSH actuation), so they are not preset |
M | resolved | 0015, 0020, 0034 |
| BL-088 | Supply-chain: pin the fuzz interpreter to a stable Python, bound ruff/mypy/pytest/psycopg[binary]/hatchling versions, add a hash-locked dev requirements file for CI installs, and scope the SBOM to the production dependency graph |
S | resolved | 0015, 0018 |
| BL-089 | STPA traceability: add SEC "Prevents" coverage for UCA-4..7, UCA-10, UCA-12/13, UCA-23; mark act_cloud/act_redfish rows planned; add a set_mode escalation test |
S | resolved | 0015, 0022 |
| BL-090 | Annotate the aspirational compliance-map rows (NIS2 Art. 21 broker BL-049; CRA Annex I NetworkPolicy ingress BL-051 and digest-pin BL-033) with their tracking item; append audit notes to ADR-0004/0005/0008 per ADR-0015 Decision 6 | S | resolved | 0015, 0016 |
| BL-091 | Postgres seq race residual: the SQLite backend computes seq inside the INSERT under facts_seq_unique/edges_seq_unique (BL-068), but store/postgres.py still reads _next_seq as a separate SELECT MAX(seq)+1 with no unique index on seq, so the MAX(seq)+1 race BL-054 claimed closed is unmitigated on the Postgres path (reachable once replicaCount>1). Add CREATE UNIQUE INDEX IF NOT EXISTS {facts,edges}_seq_unique to _SCHEMA and a parity test in the Postgres suite. Schema change: proposal, not executed in the audit pass; implemented and live-verified in the 0018 wave. |
S | resolved | 0017, 0018 |
| BL-092 | Supply-chain reviewability: no Dockerfile/Containerfile exists, yet deploy/helm/praxis/values.yaml and deploy/zarf.yaml reference a digest-pinned ghcr.io/rmednitzer/praxis image, so the deployed container cannot be built or inspected from the repo (at odds with the ADR-0001 digest-pin posture; adjacent BL-033). Add a minimal non-root, pinned-base (distroless) Dockerfile that runs python -m praxis, or document the external build. |
S | resolved | 0017, 0032 |
| BL-093 | Deploy doc clarity: the Helm chart defaults transport: http, but the server refuses any non-stdio transport with NotImplementedError (server.py), so helm install with defaults yields CrashLoopBackOff until HTTP serving lands (BL-012). deploy/README.md already names stdio as the working path; add a values.yaml comment and a chart NOTES.txt warning so the staged-not-runnable state is visible at install time. |
XS | resolved | 0017, 0018 |
| BL-094 | Audit integrity: AuditLogger.record hashed the live args rendering while _write rendered the asdict() deep copy, and str() of a copy is not stable (a deepcopied set may iterate differently), so a record with non-JSON-native args could fail its own entry_hash and an honest log verified as tampered (invariant 3; found by the BL-053 coverage gate re-running the suite under fresh hash seeds, deterministic at PYTHONHASHSEED=24). Fixed by normalizing the payload through one canonical JSON round-trip before hashing, so the hash and the written line derive from one rendering; regression test uses a deterministic copy-sensitive str() probe. |
S | resolved | 0018 |
| BL-095 | Non-forgeable checkpoint stamper (residual of BL-076, split per the BL-054/BL-068 precedent): implement a real RFC 3161 TSP client (ASN.1 TimeStampReq/Resp behind an optional extra and the SSRF egress filter) or a transparency-log anchor (Rekor), replacing the keyless LocalStamper whose token anyone who can write the evidence file can forge; until then OS append-only storage on the audit, evidence, and anchor files is the documented required control (SECURITY.md, ADR-0019) |
M | resolved | 0019, 0029, 0030 |
| BL-096 | SSRF: block the deprecated 6to4 relay anycast 192.88.99.0/24 (RFC 7526) with a deterministic network constant rather than interpreter registry data, which varies across patch versions; add an IPv4-in-IPv6 (v4-mapped/NAT64/6to4) and userinfo/bracketed-host bypass test sweep (BL-061) | XS | resolved | 0020 |
| BL-097 | Redaction hardening: add the PyPI upload-token shape, run the npm and GitLab token bodies unbounded from their length floor so a longer token collapses whole (no audit-log tail), and add a context-gated compact MySQL -p<password> redaction that fires only when a MySQL-family client is present (no -p-as-port over-scrub). Strengthens SEC-9; no PATTERNS_VERSION change |
S | resolved | 0021 |
| BL-098 | Talos partition-scoped reset: an additive system_labels param mapping to talosctl reset --system-labels-to-wipe (allowlisted EPHEMERAL/STATE, normalised), preserving STATE so a node rejoins; mutually exclusive with --wipe-mode (both refused); the documented system-disk default (BL-025) is unchanged; the partition reset keeps T3 via the existing reset classifier match |
S | resolved | 0021 |
| BL-099 | CIS-Talos desired-state baseline as drift data: transcribe the CIS Kubernetes benchmark + Talos-defaults mapping into KNOWN_GOOD facts for the drift engine, with a false-positive suppression set. Needs a fact-predicate schema decision first (kubelet/API-server/sysctl predicates); open a dedicated ADR before implementing |
L | resolved | 0021, 0024, 0028 |
| BL-100 | Multi-sink audit fan-out with per-sink failure containment: when a second audit sink is wired (the Postgres audit path, a syslog target) introduce a MultiSink that contains a per-sink Exception so one failing sink cannot silence the others, with BaseException still propagating (the BL fan-out containment class applied to the audit write side). Latent until a second sink exists |
M | resolved | 0021, 0037 |
| BL-101 | Audit request_id/client_id correlation: thread the MCP request and client identifiers (optional, additive to the audit record) so concurrent calls can be correlated to audit entries without timestamp matching. Lower value for the stdio-default single-operator server; revisit when the HTTP transport (BL-012) serves multiple clients |
S | resolved | 0021, 0038 |
| BL-102 | Client-side-only talosctl pre-flight health probe: evaluate passing --server=false to the talosctl health gate (_health_ok) so a post-bootstrap cluster's server-side checks cannot spuriously block an upgrade. A behavioural change to a HARD safety precondition (SEC-5, BL-023); raised for an operator decision rather than changed unilaterally |
XS | resolved | 0021, 0031 |
| BL-103 | Live-PostgreSQL verification of the compare-and-set create-if-absent translation (BL-027): the Postgres put_fact_if translates a partial-unique-index IntegrityError on the create path to VersionConflict (the create-if-absent case cannot be FOR UPDATE-locked), matching the SQLite BEGIN IMMEDIATE serialization and the CAS contract. The translation is verified by reasoning against the psycopg API; add a concurrent-create-if-absent test gated on PRAXIS_TEST_PG_DSN (two writers, expected_version=None, exactly one wins with VersionConflict) and confirm against a live database |
S | resolved | 0021 |
| BL-104 | Per-session execution-context isolation for the multi-client HTTP transport: the server builds one ExecutionContext per process, so the SessionTaint latch and the ApprovalRegistry are process-global and ApprovalRegistry.validate-then-consume is not atomic. Correct and safe on the stdio transport (single process, single-threaded loop, one operator; the global latch fails safe by over-tainting). Becomes load-bearing only when HTTP serving (BL-012) multiplexes concurrent clients onto one context: give each client session its own taint (and context where appropriate) and make the single-use nonce check-and-burn atomic, so one client cannot observe another's taint or race an approval. #71 (BL-101) adds per-request correlation but not isolation. Latent until multi-client HTTP serving lands. |
M | resolved | 0039, 0041 |
| BL-105 | OpenTofu workspace selection via a confined chdir: re-add -chdir support to the OpenTofu adapter behind a PRAXIS_TOFU_ROOT confinement (parallel to playbook_root/runbook_root, confine_to_root), fail-closed when chdir is supplied without a configured root, and expose it as a RunActionArgs field. The unconfined passthrough was removed in the 2026-06-14 audit (F-003); this re-adds the capability safely when a workspace-selection feature is needed |
S | resolved | 0040 |
| BL-106 | Timing-safe approval-token comparison: switch ApprovalRegistry token lookup to secrets.compare_digest before any network-accessible submission path exists. Latent today (the approval nonce is a server-minted, single-use, TTL-bound value surfaced out-of-band, and HTTP serving is not wired), but constant-time comparison is the correct default and is a prerequisite of the HTTP transport (BL-012); complements BL-104 (atomic check-and-burn). Found in the 2026-06-14 audit |
S | resolved | 0040, 0041 |
| BL-107 | Total-message-byte cap for a multi-client transport: the stdio _drain_line is bounded per chunk but iterates unboundedly over a single hostile oversized line (a single-client stall only, acceptable for stdio). Add a total-message-byte cap before the HTTP transport (BL-012) serves untrusted clients. Found in the 2026-06-14 audit |
S | resolved | 0040, 0041 |
| BL-108 | Per-pair and per-value caps in CommandProbeCollector.parse: the 4 MiB tool-output ceiling bounds the raw string but not the number of key-value pairs or individual value lengths a hostile probe can produce. Add a _MAX_PAIRS and per-value cap (silent truncation, consistent with the never-raises collector contract). Defense-in-depth for untrusted collected data (invariant 8). Found in the 2026-06-14 audit |
S | resolved | 0040 |
| BL-109 | Make the compliance catalog proving-test lists exhaustive: docs/governance/compliance-controls.json cites the minimum one proving test per control (validator rule R9), but the STPA 07 tables name more per SEC constraint. Either expand the proving_tests arrays to the full set or add a header note that the catalog lists representative tests. Found in the 2026-06-14 audit |
XS | resolved | 0040 |
| BL-110 | Concurrent HTTP serving: the v1 HTTP transport (ADR-0041) is a single-threaded HTTPServer (one request at a time) so the single-connection SQLite store is never touched cross-thread; per-session isolation is already full. Make the store thread-safe (SQLite check_same_thread=False + a serialization lock or per-thread connections; PostgresStore likewise) and switch to ThreadingHTTPServer so requests execute in parallel (e.g. actuating several hosts at once) without weakening the bitemporal/append-only invariants. |
M | resolved | 0041, 0042 |
| BL-111 | First-class kubectl/helm actuation under the ADR-0043 scoped-static-kubeconfig contract: add HostType.KUBERNETES; KubectlAdapter/HelmAdapter wrapping the on-PATH tools (verb allowlist, no free-form options per BL-082, native --dry-run=server/helm --dry-run); pin --kubeconfig/--context from trusted inventory with confine_to_root paths; refuse exec-stanza kubeconfigs fail-closed; tier reads T0, mutators T2 (kubectl mutators already T2 in patterns.py), helm uninstall/kubectl delete namespace|pvc|crd T3; SEC-5 host_type gate; broker grant per cluster-host; pre-stage act_kubectl/act_helm UCAs in STPA 05 and map to SEC-5/6/8 in STPA 07. Otherwise Kubernetes/Helm stays a bastion-host skill (cloud/exec auth). No new Python dependency. |
L | open | 0043 |
| BL-112 | Treat non-zero wrapped actuation subprocess exits as audited execution errors without copying stdout/stderr bodies into exception text, so failed tools cannot be recorded as successful actuation and output-body logging remains barred. | S | resolved | 0040 |
| BL-113 | Re-confirm the EU AI Act high-risk application dates and their in-force status against the Official Journal once the Digital Omnibus on AI is formally adopted and published. The 2026-06-23 distillation pass (ADR-0044) recorded the provisionally-agreed deferral (Annex III 2026-08-02 -> 2027-12-02; Annex I 2027-08-02 -> 2028-08-02) in docs/governance/regulatory-deadlines.md, flagged provisional pending the OJ; when the OJ publishes, replace the provisional annotations with the published dates and close this item. Documentation only; no code change. |
XS | open | 0044 |