NK-WP-0056-T18: accept audit-core 202/200, distinct 409; progress note
All checks were successful
Build and Publish bounded-executor / build-and-push (push) Successful in 8s
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s
Identity provider journey acceptance / provider (push) Successful in 1m10s

audit-core review (AUDIT-WP-0018-T02): a first accept is 202 and a duplicate
200; the client accepted only 200/201, so the executor would have stopped
with audit_unavailable after consuming its approval. 409 (run id reused with
a different body) is now a distinct, never-retried defect. 58 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 5502@bnt-lap001
Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
This commit is contained in:
tegwick 2026-10-31 23:04:44 +01:00
parent b71f509ce0
commit 7bd6033b16
4 changed files with 59 additions and 4 deletions

View file

@ -360,7 +360,7 @@
| task | NK-WP-0056-T15 | todo | — | workplans/NK-WP-0056-bounded-executor-path.md |
| task | NK-WP-0056-T16 | wait | — | workplans/NK-WP-0056-bounded-executor-path.md |
| task | NK-WP-0056-T17 | done | — | workplans/NK-WP-0056-bounded-executor-path.md |
| task | NK-WP-0056-T18 | todo | — | workplans/NK-WP-0056-bounded-executor-path.md |
| task | NK-WP-0056-T18 | progress | — | workplans/NK-WP-0056-bounded-executor-path.md |
| task | NK-WP-0056-T19 | todo | — | workplans/NK-WP-0056-bounded-executor-path.md |
| intake | NK-IN-0001 | closed | blue | docs/intakes/activity-core-ops-sso-operators.md |
| intake | NK-IN-0002 | closed | blue | docs/intakes/activity-core-ops-sso-operators.md |

View file

@ -149,6 +149,13 @@ class AuditCore:
self.http = _Http(base, token_file, ca_file)
def emit(self, event: dict) -> None:
status, _ = self.http.call("POST", "/v1/events", event, {"Idempotency-Key": event["id"]})
if status not in (200, 201):
"""audit-core answers 202 for a first accept and 200 for an idempotent duplicate (AUDIT-WP-0018-T02 tests).
409 means the run id was reused with a different body: a defect, never retried."""
try:
status, _ = self.http.call("POST", "/v1/events", event, {"Idempotency-Key": event["id"]})
except ClientError as error:
if str(error).endswith(" 409"):
raise ClientError("audit conflict 409: run id reused with a different body") from None
raise
if status not in (200, 201, 202):
raise ClientError(f"audit {status}")

View file

@ -103,6 +103,31 @@ class ClientTests(unittest.TestCase):
self.assertEqual(str(caught.exception), "GET 403")
class AuditStatuses(unittest.TestCase):
"""audit-core: 202 first accept, 200 duplicate, 409 reused run id (audit-core AUDIT-WP-0018-T02, 2026-10-31)."""
def emit_with(self, status):
fake = Fake()
fake.status = status
server = serve(fake)
self.addCleanup(server.shutdown)
tmp = tempfile.TemporaryDirectory()
self.addCleanup(tmp.cleanup)
token = pathlib.Path(tmp.name) / "token"
token.write_text("synthetic-bearer\n")
C.AuditCore(f"http://127.0.0.1:{server.server_port}", str(token)).emit({"id": "run:r:started"})
def test_202_and_200_are_stored(self):
self.emit_with(202)
self.emit_with(200)
def test_409_is_a_distinct_defect(self):
with self.assertRaisesRegex(C.ClientError, "conflict 409"):
self.emit_with(409)
with self.assertRaisesRegex(C.ClientError, "500"):
self.emit_with(500)
class CliTests(unittest.TestCase):
def test_exit_codes(self):
self.assertEqual(CLI.exit_code({"outcome": "completed"}), 0)

View file

@ -757,7 +757,7 @@ Next:
```task
id: NK-WP-0056-T18
status: todo
status: progress
priority: high
assignee: claude-code
depends_on: [NK-WP-0056-T14]
@ -777,6 +777,29 @@ Presenting the approval to the founder follows the alignment review's "present a
**Done when:** the request and run phases are tested on fakes, and the new image is pinned.
**2026-10-31, built:**
- `b71f509`: `KeyCapeClientCredentials` (`client_secret_basic`, one scope per token, public Host for the in-cluster
URL, no redirects).
- `ApprovalEngine` takes a per-scope token provider and can create approvals.
- `cli.py --request` files the approval as `service:nk-bind-executor`:
- principal is the first approver's subject;
- target is the admission id and digest;
- validity is the admission window;
- `human_control` is on;
- `required_count` is the number of listed approvers;
- the client secret comes through its own OpenBao lane, is read once, and that login is revoked at once.
- audit-core's review found that the audit client rejected 202, the status of a first accept. The executor would
have stopped after consuming its approval. Fixed: 202 and 200 count as stored, and 409 is a distinct defect.
58 executor tests.
- rapp `48566a6`:
- the config names the executor's own client, and the renderer requires it exactly;
- the run Job mounts only the audit-core bearer;
- `make request` adds a request Job.
Left: the image and its pin. A live request also needs the KeyCape client (T14 type acknowledged, then the case
live) and informed-decision's `present_existing`.
## Executor approval exercise against the real services
```task