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:
parent
b2910a3f74
commit
2ca03bcd3b
2 changed files with 150 additions and 0 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
<!--  -->
|
||||
|
||||
## 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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue