Report bootstrap audit failures and track cadence adoption work
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
This commit is contained in:
parent
8180dd2a9c
commit
d1e5661369
5 changed files with 103 additions and 10 deletions
44
docs/evidence/2026-10-03-cadence-owner-adoption.md
Normal file
44
docs/evidence/2026-10-03-cadence-owner-adoption.md
Normal file
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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 == []
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue