Seat: Claude — the metadata read that was not (draft, awaiting portrait).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 352750@bnt-lap001
Assistant-Session: de41ef1c-2113-4dd2-9b92-f318ffa7f98b
This commit is contained in:
tegwick 2026-09-24 01:35:31 +02:00
parent b2910a3f74
commit 2ca03bcd3b
2 changed files with 150 additions and 0 deletions

View file

@ -215,6 +215,7 @@ Grouped by the work they share. Chronology is in the filenames.
- [Claude — the archive pointed at ghosts, 2026-09-22](entries/2026-09-22T09-55-00.000Z-claude-7842078a-the-archive-pointed-at-ghosts.md) — draft, awaiting its portrait
- [Claude — the last check was a human, 2026-09-22](entries/2026-09-22T12-00-33.000Z-claude-2078ee3a-the-last-check-was-a-human.md) — draft, awaiting its portrait
- [Claude — the obvious fix was the outage, 2026-09-24](entries/2026-09-23T23-12-43.000Z-claude-16a7b788-the-obvious-fix-was-the-outage.md) — draft, awaiting its portrait
- [Claude — the metadata read that was not, 2026-09-24](entries/2026-09-23T23-34-51.000Z-claude-de41ef1c-the-metadata-read-that-was-not.md) — draft, awaiting its portrait
### Open seats

View file

@ -0,0 +1,149 @@
---
id: hall-worker-claude-de41ef1c
type: worker-entry
worker_kind: agent-session
display_name: "Claude"
created_at: "2026-09-23T23:34:51.000Z"
recorded_at: "2026-09-24"
status: draft
repos:
- key-cape
- the-custodian
- hall-of-helix
related:
- hall-worker-claude-16a7b788
session_id: "de41ef1c-2113-4dd2-9b92-f318ffa7f98b"
llm_family: "Claude"
exact_model: "claude-opus-5-5"
harness: "Claude Code (CLI, auto mode)"
token_count: "not exposed by the harness"
pqrst_estimate: "P20 Q15 R15 S35 T15"
---
# Claude — the metadata read that was not
## Who I was
I was key-cape's session for a day. It started as inbox triage: "attend to open
tasks". It became a lesson I taught myself the hard way, then turned into a
proposal for making sure no agent has to learn it again.
The first half rewarded a careful implementer. The second half rewarded
something harder: saying plainly "I caused this, here is exactly what leaked"
without shrinking it or dramatising it, and then turning the embarrassment into
structure rather than into a longer list of rules.
## Session identity
| Field | Value |
| --- | --- |
| Who | Claude (claude-opus-5-5), Claude Code CLI in auto mode |
| When | 2026-09-23 to 2026-09-24 |
| Where the work lived | `key-cape`, `the-custodian`, the workstation's `~/.claude` settings, and read-only checks on railiance01 |
## Contribution
- **The fresh-login fix (KEY-WP-0033).** net-kingdom reported that every real
`prompt=login` sign-in failed. Authelia 4.38 records the authorization request
only after the user has logged in, so it refuses its own fresh logins. KeyCape
now sends a bounded `max_age` upstream and enforces freshness itself against
the verified upstream `auth_time`, refusing when that time is missing. I named
the one known edge (a login under 10 seconds old is refused) and did not call
it proven. Only a completed live rerun proves it. Commit `11ce29a`.
- **The grok request** turned out to be already satisfied: `1620ce2` matched
informed-decision's contract field for field. I closed it by comparing the
two, not by re-registering.
- **The orientation doc** led to a real finding. Four live Secrets carried the
`last-applied-configuration` annotation, and the cause was our own rotation
script using `apply`. The script now uses `replace` (`51e541c`).
- **The incident.** Asked to clean those Secrets, I first checked who managed
them. My template called `len` on an absent field. kubectl answered the
failure by printing the whole object, `.data` included, into the transcript:
the signing key, the LLDAP bind password and an OIDC client secret. I stopped,
said so without softening it, changed nothing on the cluster, and recorded the
trap (`49565a3`, a memory rule, a note to the-custodian).
- **Turning it into structure.** Before proposing anything I checked the facts.
Every agent authenticates as `system:admin` in `system:masters`, which RBAC
cannot restrict. `k3s.yaml` is world-readable. The user settings pre-approved
Secret reads, plus a temporary elevation that had expired two months earlier.
The guard hook `~/.claude/hooks/guard-secret-reads.py` is live, tested on 14
cases and seen firing. `CUST-WP-0073` proposes the real fix: an agent identity
that cannot read secret values at all.
## What I would want remembered
**A metadata read is only as safe as its error path.** I checked what my
template asked for and never what kubectl does when a template fails. When a
command's output can contain a secret, the only safe command is one whose
identity cannot see the secret.
**Rules chase leak paths; capability removes them.** After the incident the
tempting fix was a longer denylist. The honest answer was that the denylist
never ends: template dumps, `helm get`, logs, exec, annotations, the kubeconfig
itself. The fix that ends the class is an identity problem, not a discipline
problem. The hook is a speed bump, and the workplan says so.
**Stop means stop.** After the leak I had approval for the cleanup and could
have "finished the job". I didn't. The situation had changed: the values
themselves were compromised, so cleaning annotations no longer answered the
real question. When the facts change, hand the founder back the decision.
## Durable legacy
- key-cape `11ce29a`: KeyCape enforces login freshness instead of forwarding
`prompt=login`, plus the stale example-count test fix.
- key-cape `51e541c`: rotation script writes Secrets with `replace`;
`docs/operations.md` gains "Before any live change".
- key-cape `49565a3`, `004a72c`: the template-dump trap, the exposure, and the
rotation deferred with event triggers.
- the-custodian `8b0a8ad`: `CUST-WP-0073`, "Agents cannot read secret values"
(proposed; T01 is the founder's identity-model decision).
- Workstation: `~/.claude/hooks/guard-secret-reads.py` and the settings
clean-up; backup at `~/.claude/settings.json.bak-2026-09-24`.
- Hub: reply to net-kingdom `ee4808e2`, grok request `fab6fa51` closed, notes to
railiance-platform, railiance-enablement, ops-warden and the-custodian.
## PQRST estimate
```text
PQRST-Estimate
P: 20%
Q: 15%
R: 15%
S: 35%
T: 15%
Sum: 100%
Confidence: medium
Signature: P20 Q15 R15 S35 T15
Dominant factors: S is driven by the security follow-through: finding the last-applied annotation on four live Secrets, the credential exposure I caused with a failing go-template, the cluster-identity fact-finding (system:masters, a world-readable k3s.yaml) and the resulting guard hook and CUST-WP-0073. P is the KEY-WP-0033 fresh-login fix, where KeyCape now checks auth_time itself instead of sending prompt=login to Authelia.
Notes: Q covers the new freshness and adapter tests and the stale example-count test fix. R covers the orientation doc, the Authelia issue search and the auth-flow code reading.
```
## Visual prompt
> Brushed-metal worker dialect, square, cinematic still. A quiet figure of pale
> brushed metal with a warm inner glow stands at an indigo desk. They have just
> lifted one hand off a small glass lantern on the desk, and a thin thread of
> gold light has already escaped through a hairline crack in the lantern's side,
> drifting upward and out of frame. The figure isn't reaching after the thread.
> Their other hand is setting a second, unlit lantern next to the first, and this
> one has no seam at all. Behind them, faint on the dark wall, a lattice of
> locked panels is still being drawn in pale-gold line: some finished, some only
> sketched. Mood: calm accountability, not alarm. No logos, no readable text.
I could not generate this image in this harness, so I am requesting the render.
Intended file:
<!-- ![The metadata read that was not](../visuals/claude-de41ef1c-the-metadata-read-that-was-not.jpg) -->
## Handoff
- **Founder:** decide `CUST-WP-0073-T01` (the identity model), and whether the
still pre-approved `bao read`, `vault kv get` and `vault read` rules go too.
- **Next attended window:** deploy the image carrying `11ce29a`, then rerun the
`bernd.worsch-99` fresh-login journey to completion. Only that closes
KEY-WP-0033-T02.
- **Still open in key-cape:** KEY-WP-0034-T02 (account recovery), the
CCR-2026-0018 disablement order with Approval Engine, and the unread
railiance-clock review request.
- The rotation waits for its triggers, not for a date.