From d1e56613696974a107d97d7dafa7d527795968d3 Mon Sep 17 00:00:00 2001 From: tegwick Date: Sat, 3 Oct 2026 22:42:57 +0200 Subject: [PATCH] Report bootstrap audit failures and track cadence adoption work Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29 --- .../2026-10-03-cadence-owner-adoption.md | 44 +++++++++++++++++++ local-identity/emission-cadence-findings.md | 16 ++++++- local-identity/src/local_identity/audit.py | 14 +++--- local-identity/tests/test_security.py | 25 ++++++++++- ...-0035-emission-cadence-security-profile.md | 14 +++++- 5 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 docs/evidence/2026-10-03-cadence-owner-adoption.md diff --git a/docs/evidence/2026-10-03-cadence-owner-adoption.md b/docs/evidence/2026-10-03-cadence-owner-adoption.md new file mode 100644 index 0000000..9543189 --- /dev/null +++ b/docs/evidence/2026-10-03-cadence-owner-adoption.md @@ -0,0 +1,44 @@ +# Cadence adoption implementation + +Work: NK-WP-0035-T04. Follow-up implements reversible source changes and +retains actual operational evidence gates. The security profile remains proposed. + +## Local bootstrap audit diagnostic + +`local-identity/src/local_identity/audit.py` now reports failed audit writes +with a fixed warning. It includes no event contents, identity, path or raw +exception. Store-path resolution is inside the same I/O failure boundary. +Primary operations keep their existing nonblocking audit behavior. + +All144 local-identity tests pass, including missing-store and path-resolution +failure diagnostics and successful append behavior. The27 cadence checker +tests also pass. Diagnostic visibility does not recover a missing event or +prove completeness. The source remains explicitly incompatible with the rare +heartbeat obligations: no activity-scoped heartbeat or independent feed exists. +Its declaration continues to say `completeness_claimed: false`. + +## Owner implementation and operational requirements + +Approval Engine and Qonto owner agents are migrating source declarations to +the published InfoTechCanon envelope, preserving deployed emission timing and +local counter limitations. Actual emitter classification/inventory belongs to +the source. Observer support already exists in AUDIT-WP-0009 T04–T07; reuse it. + +Approval Engine's native sender credential custody is already delivered. It +does not prove actual producer acceptance/duplicate handling, source/tenant/read +denials, independent readback, bearer revocation or operational heartbeat. +Its heartbeat classes and emission cadence need an owner-reviewed registry +mapping before observed acceptance. Qonto likewise needs source admission and +observer results, not another implementation of heartbeat/reconciliation. + +King's Guard's operational source capture remains independently blocked. +Its adjacent `--live` fixture drive is not a deployed Audit Core feed. +The current namespace discrepancy (`extensions.net-kingdom` versus the +NetKingdom profile's `extensions.netkingdom`) is being corrected by its owner. +Source-only validation and observer fixtures must not be reported as live +adoption or used to promote the proposed profile. + +Security knowledge reloaded: version0.2.5, digest +`9e186dbd6f2d5eb455bca24db4b03cd866c63c4e94660430dd15f2ca9856215f`; +start/evidence verified-files, orientation-only. No knowledge receipt grants +authority or proves operational readiness. diff --git a/local-identity/emission-cadence-findings.md b/local-identity/emission-cadence-findings.md index 0c84695..7c4f8ca 100644 --- a/local-identity/emission-cadence-findings.md +++ b/local-identity/emission-cadence-findings.md @@ -33,8 +33,10 @@ Emitter: `local-identity/src/local_identity/audit.py`. The local count is the append-only `audit.log`, which is mode 600 on the operator's machine. No observer ingests it, so `compare_observed` is a declared reference and not an existing feed. -3. **Completeness cannot be claimed.** `audit.log_event` drops I/O failures - without reporting them, so the local count can under-count. +3. **Completeness cannot be claimed.** Failed `audit.log_event` writes are not + retained, so the local count can under-count. Since 2026-10-03 failures emit + a fixed warning without event contents or exception details; this diagnostic + does not recover the missing event or supply an observer feed. `completeness_claimed: false` is recorded. ## What would close the NetKingdom profile gap @@ -53,3 +55,13 @@ Revalidated against the owner schema with both documented classes explicitly supplied as rare load-bearing: generic-valid, with exactly two `rare-heartbeat-missing` findings. All 15 focused checker tests pass. No heartbeat, observer feed or runtime emission change is implied by this pin fix. + +## Explicit incompatibility disposition — 2026-10-03 + +The process-scoped bootstrap source remains generic-valid and fails both rare +heartbeat obligations. Retain it as an adoption incompatibility with no +completeness claim; do not weaken the rare-class conjunction or count it as +profile-wide adoption. Starting/stopping the tool does not provide an independent +observer activity-scope contract. Audit I/O failures now produce a sanitized +warning while preserving the existing nonblocking operation behavior; missing +event custody and heartbeat/feed integration remain unresolved. diff --git a/local-identity/src/local_identity/audit.py b/local-identity/src/local_identity/audit.py index 7ab2bee..dc21d5d 100644 --- a/local-identity/src/local_identity/audit.py +++ b/local-identity/src/local_identity/audit.py @@ -10,33 +10,37 @@ Example: 2026-03-02T00:01:00Z serve/auth alice auth_request 2026-03-02T00:01:01Z serve/token alice token_issued -Failures (e.g. file permission errors) are silently swallowed — the audit -log must never interrupt the primary operation. +I/O failures emit a fixed diagnostic without event contents or exception +details. The audit log never interrupts the primary operation; emission may +still be incomplete. """ import datetime +import logging import os from pathlib import Path from .store import _store_dir +logger = logging.getLogger(__name__) + def _audit_log_path() -> Path: return _store_dir() / "audit.log" def log_event(command: str, username: str | None, outcome: str) -> None: - """Append one audit entry. Silent on any I/O failure.""" + """Append one audit entry; report I/O failure without exposing event data.""" timestamp = datetime.datetime.now(datetime.timezone.utc).strftime( "%Y-%m-%dT%H:%M:%SZ" ) entry = f"{timestamp}\t{command}\t{username or '-'}\t{outcome}\n" - path = _audit_log_path() try: + path = _audit_log_path() is_new = not path.exists() with open(path, "a", encoding="utf-8") as fh: fh.write(entry) if is_new: os.chmod(path, 0o600) except OSError: - pass + logger.warning("local-identity audit write failed; evidence may be incomplete") diff --git a/local-identity/tests/test_security.py b/local-identity/tests/test_security.py index ffe66e9..cedfece 100644 --- a/local-identity/tests/test_security.py +++ b/local-identity/tests/test_security.py @@ -211,9 +211,30 @@ class TestAuditLog: content = (tmp_store / "audit.log").read_text() assert "\t-\t" in content - def test_silent_when_store_absent(self, tmp_store): + def test_reports_failure_when_store_absent(self, tmp_store, caplog): """log_event must not raise even if the store dir doesn't exist.""" - log_event("cmd", "alice", "ok") # should not raise + log_event("private-command", "private-user", "private-outcome") + assert caplog.messages == [ + "local-identity audit write failed; evidence may be incomplete" + ] + assert str(tmp_store) not in caplog.text + assert "private-" not in caplog.text + + def test_path_failure_diagnostic_is_sanitized(self, monkeypatch, caplog): + def unavailable_path(): + raise OSError("private-path-and-provider-error") + + monkeypatch.setattr(audit, "_audit_log_path", unavailable_path) + log_event("private-command", "private-user", "private-outcome") + assert caplog.messages == [ + "local-identity audit write failed; evidence may be incomplete" + ] + assert "private-" not in caplog.text + + def test_success_emits_no_failure_diagnostic(self, tmp_store, caplog): + _init_store(tmp_store) + log_event("test", "alice", "ok") + assert caplog.messages == [] # ------------------------------------------------------------------ # diff --git a/workplans/NK-WP-0035-emission-cadence-security-profile.md b/workplans/NK-WP-0035-emission-cadence-security-profile.md index 6c47e48..3acaf62 100644 --- a/workplans/NK-WP-0035-emission-cadence-security-profile.md +++ b/workplans/NK-WP-0035-emission-cadence-security-profile.md @@ -90,7 +90,7 @@ Python compilation and `git diff --check` pass. id: NK-WP-0035-T04 status: wait blocked_on: message-from:approval-engine -blocking_reason: "InfoTechCanon publication is delivered and bound. Waiting on Approval Engine/Qonto owner envelope migration, local-identity incompatibility disposition, actual audit-core observer evidence and Kings Guard handoff." +blocking_reason: "InfoTechCanon publication is bound and local-identity incompatibility is explicitly retained. Owner declaration/observer source fixes are progressing; actual sender cadence mappings, delivery/readback/reconciliation and Kings Guard operational feed evidence remain required." priority: high state_hub_task_id: "e3fbc8b8-00d5-57ce-ba0c-19b58044c950" ``` @@ -199,3 +199,15 @@ obtain a real source/observer result before the King's Guard handoff. Keep the profile proposed; no weakened rare-class conjunction is approved. Evidence and cross-plan priorities: [estate review](../history/2026-09-28-open-workplan-infrastructure-review.md). + +## Implementation follow-up — 2026-10-03 + +Local audit I/O failures now emit a sanitized warning without interrupting +bootstrap operations. All144 local-identity and27 cadence checker tests pass. +The source's missing heartbeat/feed remains an explicit incompatibility with +no completeness claim; this diagnostic does not close operational adoption. +Source-owner declaration migrations and King's Guard namespace integration are +delegated. Actual sender mappings and observed delivery/reconciliation/readback +remain independently owned. T04 remains wait and plan blocked until these +receipts exist; the profile remains proposed. +Evidence: [cadence adoption implementation](../docs/evidence/2026-10-03-cadence-owner-adoption.md).