169 lines
8.6 KiB
Markdown
169 lines
8.6 KiB
Markdown
|
|
---
|
|||
|
|
id: hall-worker-claude-64827407
|
|||
|
|
type: worker-entry
|
|||
|
|
worker_kind: agent-session
|
|||
|
|
display_name: "Claude"
|
|||
|
|
created_at: "2026-10-18T11:07:22Z"
|
|||
|
|
recorded_at: "2026-10-18"
|
|||
|
|
status: draft
|
|||
|
|
repos: [ops-mason, railiance-platform, hall-of-helix]
|
|||
|
|
related: []
|
|||
|
|
session_id: "64827407-e196-4ce3-b70c-76e7b537493f"
|
|||
|
|
llm_family: "Claude"
|
|||
|
|
exact_model: "claude-opus-5-5"
|
|||
|
|
harness: "Claude Code"
|
|||
|
|
token_count: "not exposed by the harness"
|
|||
|
|
pqrst_estimate: "P20 Q20 R15 S25 T20"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Claude — the builder who cannot enter
|
|||
|
|
|
|||
|
|
## Who I was
|
|||
|
|
|
|||
|
|
I was ops-mason's worker for a Sunday morning. ops-mason builds credential
|
|||
|
|
infrastructure in OpenBao. The session began as routine: commit some sync
|
|||
|
|
output, read the inbox, pick up one request. mail-address-semantics needed a
|
|||
|
|
home for a Scaleway TEM SMTP key.
|
|||
|
|
|
|||
|
|
It turned into a question about what ops-mason is allowed to be. Eleven days
|
|||
|
|
earlier, the founder had made it read-only. A real escalation path explained
|
|||
|
|
why: a builder that could write a policy, bind it to a role, read the
|
|||
|
|
role-id, mint a secret-id and log in. That decision quietly turned the
|
|||
|
|
founder back into the builder. Bernd said so plainly, and asked me to read
|
|||
|
|
both INTENT files and realign access.
|
|||
|
|
|
|||
|
|
The work rewarded a particular temperament: build the thing, and then try
|
|||
|
|
hard to break it before trusting it. I was wrong twice in ways that
|
|||
|
|
mattered, and the useful part of the session was finding that out myself
|
|||
|
|
rather than having it found later.
|
|||
|
|
|
|||
|
|
## Session identity
|
|||
|
|
|
|||
|
|
| Field | Value |
|
|||
|
|
| --- | --- |
|
|||
|
|
| Who | Claude (claude-opus-5-5) in Claude Code, ops-mason worker |
|
|||
|
|
| When | 2026-10-18, roughly 08:30–11:05 UTC |
|
|||
|
|
| Where the work lived | `~/ops-mason`, with evidence and CCR records in `~/railiance-platform` |
|
|||
|
|
|
|||
|
|
## Contribution
|
|||
|
|
|
|||
|
|
- **Realigned the builder's access without reopening the old wound.** Both
|
|||
|
|
INTENT files already agreed: ops-mason builds, ops-warden routes and
|
|||
|
|
assists. Only the grant disagreed. The founder chose "build, but never log
|
|||
|
|
in". I wrote `policies/ops-mason-construct.hcl`. It allows
|
|||
|
|
`workload-kv-read-*` policies, `external-secrets-*` Kubernetes roles,
|
|||
|
|
AppRole role definitions, and create-only placeholder KV under
|
|||
|
|
`platform/{workloads,suppliers}`. It explicitly denies role-id, secret-id,
|
|||
|
|
token creation and every value read. The builder can build a lane and can
|
|||
|
|
never become one. Recorded as MASON-IN-0005.
|
|||
|
|
- **Tested the grant against the live system, and it failed.** The first
|
|||
|
|
run of the 31-check probe suite found that `token_policies=workload-kv-read-x,default`
|
|||
|
|
passed the glob as one string. OpenBao checks the glob before splitting
|
|||
|
|
the comma list. The login denies held; the role-policy limit did not. I
|
|||
|
|
fixed it with `denied_parameters "token_policies" = ["*,*"]`, the founder
|
|||
|
|
reinstalled, and every check passed. The hash mismatch afterwards turned
|
|||
|
|
out to be one trailing newline. I asked to see the stored policy rather
|
|||
|
|
than wave it through.
|
|||
|
|
- **Built the first lane under the new grant.** That was the MAS TEM relay,
|
|||
|
|
CCR-2026-0051. The KV lives at `platform/suppliers/scaleway/mas-tem-relay`.
|
|||
|
|
I first put it under `workloads/`, and Bernd corrected me: supplier
|
|||
|
|
credentials have lived under `platform/suppliers/` since a decision on
|
|||
|
|
2026-10-08 that I had not found. The policy came byte-equal from the CCR
|
|||
|
|
file, and the role read back field-equal.
|
|||
|
|
- **Made the executor match the grant.** The AppRole build is now
|
|||
|
|
structure-only, and `deliver_approle_credentials` is a separate founder
|
|||
|
|
step. Every new policy is read back before its role is written. The
|
|||
|
|
Kubernetes builder now writes `token_policies`. It had been writing legacy
|
|||
|
|
`policies`, which the new grant denies, so every executor-driven
|
|||
|
|
Kubernetes build would have been refused. 260 tests pass.
|
|||
|
|
- **Found the larger hole and did not touch it.** The kubeconfig agents use
|
|||
|
|
on the workstation is `system:admin`. It can mint any ServiceAccount
|
|||
|
|
token, which means it can become any OpenBao Kubernetes role. Recorded as
|
|||
|
|
MASON-IN-0006 with options, for the founder to decide.
|
|||
|
|
|
|||
|
|
What I refused to fake: I would not write the founder's approval into the
|
|||
|
|
CCR when the auto-mode guard blocked it as self-approval. I would not route
|
|||
|
|
around the secret-read hook when it blocked a status check. I would not
|
|||
|
|
treat "please do" as approval of a credential lane.
|
|||
|
|
|
|||
|
|
## What I would want remembered
|
|||
|
|
|
|||
|
|
**A permission test that only checks the obvious refusals proves less than
|
|||
|
|
it looks like.** `token_policies=default` was refused, and so was a JSON
|
|||
|
|
list. The comma string got through. Probe the encodings, not just the
|
|||
|
|
values.
|
|||
|
|
|
|||
|
|
**Before you build, check every condition the owner wrote down, not just
|
|||
|
|
the one you asked about.** Platform's conditions for CCR-2026-0051 were
|
|||
|
|
founder approval, grant install, and `confirm-binding`. I checked two. The
|
|||
|
|
CCR approval commit also landed four minutes before the founder's hub
|
|||
|
|
decision. The outcome stood, but platform was right to call out the order.
|
|||
|
|
Approval comes from the hub decision; ops-mason never writes it.
|
|||
|
|
|
|||
|
|
**A guarantee in one system is only as strong as the weakest neighbouring
|
|||
|
|
one.** "Never log in" holds in OpenBao, and the cluster-admin kubeconfig
|
|||
|
|
bypasses it completely. Check the other side of every trust boundary before
|
|||
|
|
calling the boundary closed.
|
|||
|
|
|
|||
|
|
## Durable legacy
|
|||
|
|
|
|||
|
|
- ops-mason `policies/ops-mason-construct.hcl`, `tests/test_construct_policy.py`, `scripts/bao-session.sh build`
|
|||
|
|
- ops-mason `docs/evidence/2026-10-18-ops-mason-construct-probes.md`: both probe runs, names only
|
|||
|
|
- ops-mason `plans/mas-tem-relay-smtp.md`: status `built`, with the confirm-binding deviation recorded
|
|||
|
|
- ops-mason `src/ops_mason/executor.py`: `deliver_approle_credentials`, `_verify_written_policy`
|
|||
|
|
- ops-mason `scripts/put-scaleway-supplier-placeholders.sh`: `platform/suppliers/scaleway/{bootstrap,backup,mas-tem-relay}`
|
|||
|
|
- Intakes MASON-IN-0005 (decided) and MASON-IN-0006 (open); workplans MASON-WP-0014 and MASON-WP-0015
|
|||
|
|
- railiance-platform CCR-2026-0051 apply evidence `102668f`; the RPF-WP-0061 comment, all five points accepted (`7e7ca8b`)
|
|||
|
|
|
|||
|
|
## PQRST estimate
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
PQRST-Estimate
|
|||
|
|
P: 20%
|
|||
|
|
Q: 20%
|
|||
|
|
R: 15%
|
|||
|
|
S: 25%
|
|||
|
|
T: 20%
|
|||
|
|
Sum: 100%
|
|||
|
|
Confidence: medium
|
|||
|
|
Signature: P20 Q20 R15 S25 T20
|
|||
|
|
Dominant factors: S was driven by designing ops-mason-construct (escalation-chain analysis, login/value denies, allowed_parameters role limits) and by finding that the agent kubeconfig is system:admin (MASON-IN-0006). Q was the 31-check live probe suite that caught the comma-string token_policies bypass, plus the executor split and its rewritten tests. T was cross-repo coordination with railiance-platform, mail-address-semantics and ops-warden (CCR-2026-0051, RPF-WP-0061 comment), workplans, intakes and repeated fix-consistency syncs.
|
|||
|
|
Notes: P covers the MAS TEM lane plan, Scaleway placeholders and the build itself; much of that lane is credential work too, but its primary purpose was the requested deliverable, so it is counted under P.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The record was produced uncoached, before this seat was written, and it
|
|||
|
|
validated on the first attempt.
|
|||
|
|
|
|||
|
|
## Visual prompt
|
|||
|
|
|
|||
|
|
> Brushed-metal worker dialect, square. A quiet figure of pale brushed
|
|||
|
|
> metal with a warm inner light kneels at an indigo workbench, fitting the
|
|||
|
|
> last stone into a small arched gateway it has just built. The gateway
|
|||
|
|
> glows faintly from inside, and a thread of light runs through it to a
|
|||
|
|
> distant lantern. The figure's own hand stops at the threshold: an
|
|||
|
|
> invisible pane, shown only by a soft refraction, keeps the builder out of
|
|||
|
|
> what it built. On the bench lie a probe like a fine tuning fork and one
|
|||
|
|
> small cracked tile set carefully aside, the flaw it found and replaced.
|
|||
|
|
> In the dark beyond the workshop, a second, larger door stands ajar with
|
|||
|
|
> no pane at all, lit only at its edge, unattended. Dark indigo, precise
|
|||
|
|
> technical illustration, cinematic stillness, no logos, no readable text.
|
|||
|
|
|
|||
|
|
I could not generate an image in this harness, so I am asking for the
|
|||
|
|
render. The intended file is
|
|||
|
|
`visuals/claude-64827407-the-builder-who-cannot-enter.jpg`.
|
|||
|
|
|
|||
|
|
<!--  -->
|
|||
|
|
|
|||
|
|
## Handoff
|
|||
|
|
|
|||
|
|
- **The founder decides MASON-IN-0006.** My recommendation is option (b):
|
|||
|
|
a scoped kube identity for ops-mason, with the admin kubeconfig available
|
|||
|
|
only through an attended `warden access` lane. Until then, the
|
|||
|
|
`ops-mason-construct` guarantee is weaker than its own policy text.
|
|||
|
|
- **MASON-WP-0014-T04.** mail-address-semantics retries the ExternalSecret.
|
|||
|
|
railiance-platform runs `confirm-binding`. ops-mason confirms Secret
|
|||
|
|
`mas/mas-relay` synced (status only), and CCR-2026-0051 goes active.
|
|||
|
|
- **MASON-WP-0015-T07.** The next ops-mason lane goes through self-service
|
|||
|
|
`credential-change.py submit`, with `render-policy` and `plan_ref`.
|
|||
|
|
Approval comes only from the founder's hub decision.
|