C8 G1+G1c: sendrast-release robot into sbx-sendrast (head-pinned merge helper) #940

Open
pi-landing wants to merge 3 commits from plane/IR-20261111-c8grants into live
Collaborator

C8 G1 + G1c — REBUILD: the Sendrast-only robot in Jesús's sandbox, and the hardened merge helper

This head replaces the first attempt after homelab-93's BLOCKING review
(working-files/security-hypervisor/pr-ic940/review-93.md). Nothing is applied, restarted or created by this PR.

Why the rebuild (93 F1)

The first version mounted the existing release robot. That robot also has write on Homelab/prod, and every
Homelab/prod workflow runs on the infra:host runner, which carries the SOPS age key, the AWS credentials for
the terraform state and the OPENBAO_APPLY_* / OPENBAO_CI_* AppRoles. A writer there can run arbitrary code on
the infrastructure, so "landing is still gated" did not cover it. The sandbox now gets a Sendrast-only robot:

  • sendrast-robot — created by Aaron (click list, section E). Write on Sendrast/api-sendrast and
    Sendrast/sendrast-web only. Neither the account nor its token exists yet, and this PR creates neither.
  • Its token lives at kv/sendrast/sbx/release-robot (field token) — also not created yet, and this PR
    creates no OpenBao object
    .
  • The previous robot keeps doing exactly what it did: api-sendrast's own Actions secret for bump branches. It is
    not mounted anywhere new.

G1 — the credential (externalsecrets.yaml, statefulset.yaml)

  • ExternalSecret sbx-sendrast-release-robot (ns sbx-sendrast) reads kv/sendrast/sbx/release-robot
    field token → Secret sbx-sendrast-release-robot (creationPolicy: Owner, deletionPolicy: Retain, like its
    siblings). Every reference to the old shared-robot object is gone from the PR's files and from this body.
  • Store: openbao-sendrast (role eso-sendrast), the namespace's own store — never the broad openbao store,
    which would hand the sandbox all of kv/data/*.
  • Mounted read-only, outside /home/jesus: volume release-robot → /run/secrets/sendrast/release-robot/token
    in the sandbox container only (not in dind, health or the init containers).

F2 — the store is now scoped to its namespace

openbao-sendrast is a ClusterSecretStore, and an unscoped one can be selected from any namespace by anyone
allowed to create an ExternalSecret there. The fix is spec.conditions[].namespaces: [sbx-sendrast].

The store has exactly one copy, in Homelab/prod
(manifests/lab-director/ld-fleet-cluster-secret-stores.yaml), so this change cannot live in this repo. It is
committed and pushed on a prod branch — plane/IR-20261111-c8grants-store, head
f51f9b1d2dd9eff2d5e281b4a16415f8f55cefb4 — and no PR has been opened for it by this seat; it needs a
landing worker. Verified against the live CRD: external-secrets v2.2.0, spec.conditions is schema-supported
(kubectl explain clustersecretstore.spec.conditions).

Census before the change (live cluster, read-only, all 103 ExternalSecrets in every namespace matched on
secretStoreRef.name == openbao-sendrast):

consumer store key state
sbx-sendrast/sbx-sendrast-forgejo-token openbao-sendrast (ClusterSecretStore) sendrast/sbx/forgejo-bot Ready=True SecretSynced

One consumer, inside sbx-sendrast. No namespace-scoped SecretStore exists anywhere (kubectl get secretstores -A → none), no ClusterExternalSecret exists, so nothing outside the sandbox loses anything. The new
ExternalSecret in this PR is in the same namespace.

Policy — no terraform change is needed (plan v2)

eso-sendrast already reads kv/data/sendrast/sbx/* and kv/metadata/sendrast/sbx/*, read-only
(prod terraform/openbao.tf, sendrast_eso_consumers). The new object is under that same prefix, so:

Plan: 0 to add, 0 to change, 0 to destroy — no edit authored, nothing staged, nothing applied. The live proof
is the census row above: the sibling ExternalSecret reads another object under the same prefix and is synced
today. Recorded in working-files/infra-stability/c8-jesus-grants-20261111/tf-plan-eso-sendrast-v2.txt.

The old tf-plan-eso-sendrast.txt (v1) is dead: it planned an in-place widening to reach the shared robot's
path, which belonged to the rejected design. It must not be applied, and its uncommitted change in
prod/.worktrees/IR-20261111-c8grants-tf is discarded.

G1c — the helper (sendrast-tools.yaml, statefulset.yaml)

ConfigMap sbx-sendrast-tools, mounted read-only at /opt/sendrast-tools/ (outside his home), two files.
Provenance: working-files/infra-stability/sendrast-release-unblock-20261110/sendrast-merge.py, source sha256
re-verified db8108eb40e7… before adapting; the {"Do": …, "head_commit_id": <expected>} merge call — the one
property Forgejo enforces server-side — is untouched.

  1. Hard repo allowlist. Sendrast/api-sendrast and Sendrast/sendrast-web, nothing else, refused before the
    first API call
    (step=allowlist, exit 1). A --repo Homelab/prod run was checked by hand and dies at that
    step without touching the network. The server-reported base is then checked too: base.repo.full_name from
    the PR payload must be on the same allowlist (step=repo-server, fails closed when missing or non-string), so a
    hand-typed --repo cannot misdescribe the PR's real base.
  2. Review gate stricter than the server. ANY dismissed approval, or ANY approval recorded on a non-head commit,
    is refused; then one ld-reviewer APPROVED review at the current head is required. This matters because
    main asks for zero required approvals, so the server-side approval whitelist is inert.
  3. --self-check on both scripts — offline fixtures, no network, no token. The merge helper's set covers
    allowlist accept/refuse (incl. a case variant), the server-reported base.repo.full_name accept/refuse, clean
    approval / dismissed / stale-flag / non-head / wrong-user / no-approval / no-reviews / non-list, CI success +
    pending, "no token-bearing URL", "no command-line token", and the token-file mode rule (0666 refused, 0440
    accepted) — 22/22 PASS: python3 /opt/sendrast-tools/sendrast-merge.py --self-check. The credential
    helper's own self-check covers exactly the push route and nothing else — request with no path → refuse,
    Homelab/prod → refuse, and both Sendrast repos → answer — 14/14 PASS:
    sh /opt/sendrast-tools/sendrast-credential-helper.sh --self-check.
  4. Token from the file only — never argv, never env, never a URL; a group/world-writable file is refused.
  5. Sanctioned push/tag route (93 F4/F5): sendrast-credential-helper.sh, a git credential helper that reads the
    same file and answers only get, only https, only forgejo.aaron.reynoza.org and only the two allowlisted
    repos; store/erase are no-ops, so nothing is cached in .git/config on his persistent home. It replaces the
    improvisation git push https://x:$(cat token)@…, which puts the token in argv and history:
    git -c credential.helper= \
        -c credential.useHttpPath=true \
        -c credential.helper='!sh /opt/sendrast-tools/sendrast-credential-helper.sh' \
        push origin <ref>
    
    All three parts are load-bearing. credential.helper= comes first: the pod's own environment already
    registers a helper, and a bare !/opt/sendrast-tools/… (or a helper appended without clearing the inherited
    one) has the pod's helper answering instead — and the script is mounted 0440, so invoking it directly gets
    Permission denied; it is run through sh for the same reason. useHttpPath=true is required: without it
    git sends no path on the credential request, and the helper deliberately refuses a path-less request rather
    than answering for any repo on the host.
  6. Hardening the review also asked for: redirects are refused, so the Authorization header cannot be replayed
    at another host; the docstring now matches reality (exit 1/2, file mode 0440).

His home's pi-extensions copy (1112bfb) calls /merge without the head pin. That copy is not edited and
nothing is written under /home/jesus: this helper is the sanctioned route.

Deviations that still apply

  • defaultMode: 288 (0440), not 0400. The container runs as uid 1006 with pod fsGroup 1006, so a
    root-owned 0400 file is unreadable for Jesús's uid and the mount would be dead weight. 0440 is the pattern
    already proven in this pod (the git token), still non-writable for everyone, never in env, never in argv.
  • optional: true on the Secret volume, and now doubly gated: the robot account does not exist AND the kv
    object does not exist. An unplanned pod recreate must not leave Jesús's sandbox Pending over a secret that
    cannot exist yet. Drop optional: true once the ES is SecretSynced, so the mount is enforced.

Go-live

At the next sbx-sendrast restart that homelab-a9 coordinates with Jesús, and ONLY once Aaron has created
sendrast-robot (click list, section E) and kv/sendrast/sbx/release-robot exists.
updateStrategy is
OnDelete: merging this changes nothing in the running pod, and this PR touches no restart path. The restart
window checks SecretSynced=True on sbx-sendrast-release-robot before any pod delete, exactly as for
ci-reader.

Revocation, written down (93 F6): deletionPolicy: Retain means removing the ExternalSecret later leaves the last
token in the namespace and in the pod. Revoking means rotating or deleting the robot's token in Forgejo, not
deleting the Secret.

Verify

  • kubectl kustomize core/manifests/apps/sbx-sendrast renders: the new ConfigMap, the new ExternalSecret
    (key sendrast/sbx/release-robot), and both mounts readOnly: true on the sandbox container
  • embedded helpers round-trip byte-identically out of the ConfigMap, compile, and --self-check → merge
    helper 22/22 PASS, credential helper 14/14 PASS
  • sh -n on the credential helper; it refuses a foreign host, a foreign repo path and a path-less
    request
    (no useHttpPath), accepts both Sendrast repos, and is exercised through the documented
    credential.helper= + useHttpPath=true + !sh … invocation
  • yaml-lint + shellcheck + terraform-validate green on this head (CI run #3581)
  • store census: 1 consumer, inside sbx-sendrast (table above)
  • spec.conditions exists in the live CRD (external-secrets v2.2.0)
  • no secret value, prefix or fingerprint printed anywhere; no OpenBao write; no kubectl write; no restart
  • live: SecretSynced=True on sbx-sendrast-release-robot — blocked on Aaron creating the robot and the kv
    object (reported, not done here)

Lab-Run: IR-20261111-c8grants

## C8 G1 + G1c — REBUILD: the Sendrast-only robot in Jesús's sandbox, and the hardened merge helper This head replaces the first attempt after homelab-93's **BLOCKING** review (`working-files/security-hypervisor/pr-ic940/review-93.md`). Nothing is applied, restarted or created by this PR. ### Why the rebuild (93 F1) The first version mounted the **existing** release robot. That robot also has write on `Homelab/prod`, and every `Homelab/prod` workflow runs on the `infra:host` runner, which carries the SOPS age key, the AWS credentials for the terraform state and the `OPENBAO_APPLY_*` / `OPENBAO_CI_*` AppRoles. A writer there can run arbitrary code on the infrastructure, so "landing is still gated" did not cover it. The sandbox now gets a **Sendrast-only robot**: * **`sendrast-robot`** — created by **Aaron** (click list, section E). Write on **`Sendrast/api-sendrast`** and **`Sendrast/sendrast-web` only**. Neither the account nor its token exists yet, and **this PR creates neither**. * Its token lives at **`kv/sendrast/sbx/release-robot`** (field `token`) — also not created yet, and **this PR creates no OpenBao object**. * The previous robot keeps doing exactly what it did: api-sendrast's own Actions secret for bump branches. It is **not** mounted anywhere new. ### G1 — the credential (`externalsecrets.yaml`, `statefulset.yaml`) * `ExternalSecret sbx-sendrast-release-robot` (ns `sbx-sendrast`) reads **`kv/sendrast/sbx/release-robot`** field `token` → Secret `sbx-sendrast-release-robot` (`creationPolicy: Owner`, `deletionPolicy: Retain`, like its siblings). Every reference to the old shared-robot object is gone from the PR's files and from this body. * Store: **`openbao-sendrast`** (role `eso-sendrast`), the namespace's own store — never the broad `openbao` store, which would hand the sandbox all of `kv/data/*`. * Mounted **read-only, outside `/home/jesus`**: volume `release-robot` → `/run/secrets/sendrast/release-robot/token` in the `sandbox` container only (not in `dind`, `health` or the init containers). ### F2 — the store is now scoped to its namespace `openbao-sendrast` is a **ClusterSecretStore**, and an unscoped one can be selected from any namespace by anyone allowed to create an ExternalSecret there. The fix is `spec.conditions[].namespaces: [sbx-sendrast]`. The store has exactly **one** copy, in Homelab/prod (`manifests/lab-director/ld-fleet-cluster-secret-stores.yaml`), so this change cannot live in this repo. It is committed and pushed on a prod branch — **`plane/IR-20261111-c8grants-store`**, head **`f51f9b1d2dd9eff2d5e281b4a16415f8f55cefb4`** — and **no PR has been opened for it by this seat**; it needs a landing worker. Verified against the live CRD: `external-secrets v2.2.0`, `spec.conditions` is schema-supported (`kubectl explain clustersecretstore.spec.conditions`). **Census before the change** (live cluster, read-only, all 103 ExternalSecrets in every namespace matched on `secretStoreRef.name == openbao-sendrast`): | consumer | store | key | state | |---|---|---|---| | `sbx-sendrast/sbx-sendrast-forgejo-token` | `openbao-sendrast` (ClusterSecretStore) | `sendrast/sbx/forgejo-bot` | `Ready=True SecretSynced` | **One consumer, inside `sbx-sendrast`.** No namespace-scoped `SecretStore` exists anywhere (`kubectl get secretstores -A` → none), no ClusterExternalSecret exists, so nothing outside the sandbox loses anything. The new ExternalSecret in this PR is in the same namespace. ### Policy — no terraform change is needed (plan v2) `eso-sendrast` already reads `kv/data/sendrast/sbx/*` and `kv/metadata/sendrast/sbx/*`, read-only (prod `terraform/openbao.tf`, `sendrast_eso_consumers`). The new object is under that same prefix, so: **`Plan: 0 to add, 0 to change, 0 to destroy`** — no edit authored, nothing staged, nothing applied. The live proof is the census row above: the sibling ExternalSecret reads another object under the same prefix and is synced today. Recorded in `working-files/infra-stability/c8-jesus-grants-20261111/tf-plan-eso-sendrast-v2.txt`. The old `tf-plan-eso-sendrast.txt` (v1) is **dead**: it planned an in-place widening to reach the shared robot's path, which belonged to the rejected design. It must not be applied, and its uncommitted change in `prod/.worktrees/IR-20261111-c8grants-tf` is discarded. ### G1c — the helper (`sendrast-tools.yaml`, `statefulset.yaml`) `ConfigMap sbx-sendrast-tools`, mounted **read-only at `/opt/sendrast-tools/`** (outside his home), two files. Provenance: `working-files/infra-stability/sendrast-release-unblock-20261110/sendrast-merge.py`, source sha256 re-verified `db8108eb40e7…` before adapting; the `{"Do": …, "head_commit_id": <expected>}` merge call — the one property Forgejo enforces server-side — is untouched. 1. **Hard repo allowlist.** `Sendrast/api-sendrast` and `Sendrast/sendrast-web`, nothing else, refused **before the first API call** (`step=allowlist`, exit 1). A `--repo Homelab/prod` run was checked by hand and dies at that step without touching the network. The **server-reported** base is then checked too: `base.repo.full_name` from the PR payload must be on the same allowlist (`step=repo-server`, fails closed when missing or non-string), so a hand-typed `--repo` cannot misdescribe the PR's real base. 2. **Review gate stricter than the server.** ANY dismissed approval, or ANY approval recorded on a non-head commit, is refused; then one `ld-reviewer` APPROVED review **at the current head** is required. This matters because `main` asks for **zero** required approvals, so the server-side approval whitelist is inert. 3. **`--self-check` on both scripts** — offline fixtures, no network, no token. The merge helper's set covers allowlist accept/refuse (incl. a case variant), the server-reported `base.repo.full_name` accept/refuse, clean approval / dismissed / stale-flag / non-head / wrong-user / no-approval / no-reviews / non-list, CI success + pending, "no token-bearing URL", "no command-line token", and the token-file mode rule (0666 refused, 0440 accepted) — **22/22 PASS**: `python3 /opt/sendrast-tools/sendrast-merge.py --self-check`. The credential helper's own self-check covers exactly the push route and nothing else — request with **no path → refuse**, **`Homelab/prod` → refuse**, and **both Sendrast repos → answer** — **14/14 PASS**: `sh /opt/sendrast-tools/sendrast-credential-helper.sh --self-check`. 4. **Token from the file only** — never argv, never env, never a URL; a group/world-writable file is refused. 5. **Sanctioned push/tag route (93 F4/F5):** `sendrast-credential-helper.sh`, a git credential helper that reads the same file and answers only `get`, only `https`, only `forgejo.aaron.reynoza.org` and only the two allowlisted repos; `store`/`erase` are no-ops, so nothing is cached in `.git/config` on his persistent home. It replaces the improvisation `git push https://x:$(cat token)@…`, which puts the token in argv and history: ``` git -c credential.helper= \ -c credential.useHttpPath=true \ -c credential.helper='!sh /opt/sendrast-tools/sendrast-credential-helper.sh' \ push origin <ref> ``` All three parts are load-bearing. `credential.helper=` comes **first**: the pod's own environment already registers a helper, and a bare `!/opt/sendrast-tools/…` (or a helper appended without clearing the inherited one) has the pod's helper answering instead — and the script is mounted **0440**, so invoking it directly gets `Permission denied`; it is run through `sh` for the same reason. `useHttpPath=true` is **required**: without it git sends no `path` on the credential request, and the helper deliberately refuses a path-less request rather than answering for any repo on the host. 6. **Hardening the review also asked for:** redirects are refused, so the `Authorization` header cannot be replayed at another host; the docstring now matches reality (exit 1/2, file mode 0440). His home's pi-extensions copy (**1112bfb**) calls `/merge` **without** the head pin. That copy is not edited and nothing is written under `/home/jesus`: **this helper is the sanctioned route**. ### Deviations that still apply * **`defaultMode: 288` (0440), not `0400`.** The container runs as **uid 1006** with pod `fsGroup` 1006, so a root-owned 0400 file is unreadable for Jesús's uid and the mount would be dead weight. 0440 is the pattern already proven in this pod (the git token), still non-writable for everyone, never in env, never in argv. * **`optional: true` on the Secret volume**, and now **doubly gated**: the robot account does not exist AND the kv object does not exist. An unplanned pod recreate must not leave Jesús's sandbox `Pending` over a secret that cannot exist yet. Drop `optional: true` once the ES is `SecretSynced`, so the mount is enforced. ### Go-live **At the next `sbx-sendrast` restart that homelab-a9 coordinates with Jesús, and ONLY once Aaron has created `sendrast-robot` (click list, section E) and `kv/sendrast/sbx/release-robot` exists.** `updateStrategy` is `OnDelete`: merging this changes nothing in the running pod, and this PR touches no restart path. The restart window checks `SecretSynced=True` on `sbx-sendrast-release-robot` **before** any pod delete, exactly as for `ci-reader`. Revocation, written down (93 F6): `deletionPolicy: Retain` means removing the ExternalSecret later leaves the last token in the namespace and in the pod. Revoking means **rotating or deleting the robot's token in Forgejo**, not deleting the Secret. ### Verify * [x] `kubectl kustomize core/manifests/apps/sbx-sendrast` renders: the new ConfigMap, the new ExternalSecret (key `sendrast/sbx/release-robot`), and both mounts `readOnly: true` on the `sandbox` container * [x] embedded helpers round-trip byte-identically out of the ConfigMap, compile, and `--self-check` → merge helper **22/22 PASS**, credential helper **14/14 PASS** * [x] `sh -n` on the credential helper; it refuses a foreign host, a foreign repo path **and a path-less request** (no `useHttpPath`), accepts both Sendrast repos, and is exercised through the documented `credential.helper=` + `useHttpPath=true` + `!sh …` invocation * [x] `yaml-lint` + `shellcheck` + `terraform-validate` green on this head (CI run #3581) * [x] store census: 1 consumer, inside `sbx-sendrast` (table above) * [x] `spec.conditions` exists in the live CRD (`external-secrets v2.2.0`) * [x] no secret value, prefix or fingerprint printed anywhere; no OpenBao write; no kubectl write; no restart * [ ] live: `SecretSynced=True` on `sbx-sendrast-release-robot` — blocked on Aaron creating the robot and the kv object (reported, not done here) `Lab-Run: IR-20261111-c8grants`
C8 G1+G1c: sendrast-release robot into sbx-sendrast (head-pinned merge helper)
All checks were successful
CI Review / helm-validate (pull_request) Successful in 12s
CI Review / runner-manifest-test (pull_request) Successful in 9s
CI Review / receiver-test (pull_request) Successful in 6s
CI Review / alert-receiver-test (pull_request) Successful in 21s
Lint & Validate / yaml-lint (pull_request) Successful in 23s
Lint & Validate / shellcheck (pull_request) Successful in 9s
CI Review / record-sql-test (pull_request) Successful in 58s
Lint & Validate / terraform-validate (pull_request) Successful in 2m0s
CI Review / dispatcher-test (pull_request) Successful in 3m8s
CI Review / cockpit-test (pull_request) Successful in 3m35s
CI Review / cockpit-e2e (pull_request) Successful in 3m35s
6ef31481dc
G1 (El Director lifted the hold 16:14:25Z): the release robot now also lives in
Jesús's sandbox, by Aaron's equal-authority word (11-11).

- ExternalSecret sbx-sendrast-release-robot in ns sbx-sendrast pulls the
  EXISTING object kv/ci/forgejo-sendrast-release (field `token`) through the
  namespace's own store `openbao-sendrast` (role eso-sendrast) — NOT the broad
  `openbao` store, which would let the sandbox sync any kv object (the G6
  lesson in prod's ld-fleet-cluster-secret-stores.yaml).
- Secret mounted READ-ONLY, outside /home/jesus, at
  /run/secrets/sendrast/release-robot/token on the StatefulSet. The pod is
  OnDelete: this changes nothing until the next planned sbx restart that
  homelab-a9 coordinates with Jesús. Nothing is restarted here.
- defaultMode 0440 (288), not the brief's 0400: the container runs as uid 1006
  with pod fsGroup 1006, and a root-owned 0400 file is unreadable for uid 1006.
  0440 is the pattern already proven in this pod (the git token) and is still
  non-writable.
- Volume is `optional: true` on purpose while the ESO policy gap below stands,
  so an unplanned pod recreate cannot leave the sandbox Pending.

G1c: ConfigMap sbx-sendrast-tools mounted READ-ONLY at /opt/sendrast-tools/
(next to G1's volume) with sendrast-merge.py, the head-pinned helper
(sha256 db8108eb source). Only change: --token-file defaults to the G1 mount.
The pi-extensions copy in his home (1112bfb) merges WITHOUT the head pin; this
helper is the sanctioned route. No writes in /home/jesus.

ESO policy check (sa-operator route, metadata only, revoke-self verified):
kv/ci/forgejo-sendrast-release exists (current_version 2). The role
`eso-sendrast` reads ONLY kv/data/sendrast/sbx/* + metadata (prod
terraform/openbao.tf), so it CANNOT read this path: GAP. A prod terraform change
was PLANNED only — 0 to add, 1 to change, 0 to destroy — and NOT applied (the
C8 brief forbids an apply). The ES therefore sits in SecretSyncedError until
that policy lands, then syncs by itself.

Sendrast/deploy write is added by Jesús himself; we don't touch it.

Lab-Run: IR-20261111-c8grants
Collaborator

Exact head: 6ef31481dc
Base: 35a336157d
VERDICT: APPROVED (census format, seat A)

SESSION: IR-20261111-c8grants-seatA-20261111T1652Z
MODEL: deepseek-flash

Read route: ambient pi-landing API read only (PR body + diff + file blobs at the head sha + prod@live store/terraform). No comment/review read on this PR at any point before this comment (NO-READ respected).

Diff surface, verified against the tree, not the prose: exactly 4 files, all under core/manifests/apps/sbx-sendrast/ (externalsecrets.yaml, kustomization.yaml, new sendrast-tools.yaml, statefulset.yaml). Two hunks in the StatefulSet (volumeMounts, volumes), nothing else. kubectl kustomize core/manifests/apps/sbx-sendrast on a clean clone of the head renders (exit 0): ConfigMap sbx-sendrast-tools, ExternalSecret sbx-sendrast-release-robot, StatefulSet with both new mounts readOnly: true and updateStrategy: OnDelete. CI combined status at the head = success (11 contexts, re-read myself, not taken from the body).

LEGS

(a) G1 credential — PASS. ES sbx-sendrast-release-robot in ns sbx-sendrast, secretStoreRef ClusterSecretStore openbao-sendrast, remoteRef.key: ci/forgejo-sendrast-release + property: token → resolves to kv/data/ci/forgejo-sendrast-release (store path kv, v2). Secret sbx-sendrast-release-robot, creationPolicy: Owner, deletionPolicy: Retain — matches the other 4 ESes in the file. Store identity verified independently: openbao-sendrast exists in Homelab/prod@live (manifests/lab-director/ld-fleet-cluster-secret-stores.yaml, wave 8) with role: eso-sendrast bound to external-secrets/eso-openbao-reader, and the SAME store already serves the working sbx-sendrast-forgejo-token ES in this namespace — so the new ES is not blocked by store readiness, only by the role's path scope. Mount release-robot → /run/secrets/sendrast/release-robot + item token ⇒ exact file /run/secrets/sendrast/release-robot/token; readOnly: true; outside /home/jesus. Names, paths and readonly are all correct.

(b) defaultMode 288 (0440) deviation — PASS, and the deviation is the correct call. Verified in the manifest: pod securityContext.fsGroup: 1006; the sandbox container (the one that owns mounts 586–640) is runAsUser: 1006 / runAsGroup: 1006 / runAsNonRoot: true / readOnlyRootFilesystem: true. A secret volume is delivered root:<fsGroup> at defaultMode, so 0400 would be unreadable for uid 1006 and the mount would be dead weight; 0440 grants group-read only and is non-writable by anyone — and since every process in that container is uid/gid 1006, group-read adds no privilege beyond what 0400-for-1006 would have. Documented in both the manifest comment and the PR body, i.e. flagged rather than silently done. No env var, no argv: the diff adds no environment entries and the helper reads the token from the file. PASS.

(c) optional: true — PASS with a note. Correct fail-closed shape: while the ESO gap stands an unplanned pod recreate mounts an empty directory instead of leaving Jesús's sandbox Pending, and once the Secret syncs the projected volume updates in place with no recreate (accurate as documented). Two precision notes, neither blocking: (1) with optional: true, a Secret that existed and is then deleted leaves the last file content mounted, so "never starts with a stale token" is true at pod start but not for a long-lived pod; (2) if the token file is absent the helper dies on a bare FileNotFoundError traceback from open(args.token_file) rather than the step=… code=… fail path — fail-closed (no merge, exit 1) but the body's "the helper's error says so" overstates the diagnostics. Dropping optional: true once SecretSynced=True, as the body says, closes both.

(d) G1c ConfigMap helper — PASS. Embedded copy extracted from the rendered ConfigMap: ast.parse OK, --help shows --token-file optional with default exactly /run/secrets/sendrast/release-robot/token (byte-matches the G1 mount path), head pin intact ({"Do": …, "head_commit_id": args.expect_sha}), the four checks present and ordered, token only via file, exits 2 on head move / 3 on unexpected code, mode 0440 and non-executable (invoked python3 …), mounted read-only at /opt/sendrast-tools — same pattern as the already-working /opt/sbx-skills and /opt/sbx-models mounts in this pod, so no read-only-rootfs conflict. sendrast-tools.yaml is in resources (7 entries = the 7 non-kustomization manifests in the directory; verified), and it renders, so ArgoCD will not prune it. Caveat on the one claim I cannot verify: the "byte-identical to sha256 db8108eb except the --token-file default" comparison is attested, not checkable — the pristine source lives in a working-files/… path that is not in Git (I searched infra-core@head, prod, and the repo root; no such tree). The embedded blob hashes 30e98f9c…. Recommend committing the pristine source (or its diff) into that record so the next reader can audit it instead of trusting the note.

(e) No writes under /home/jesus — PASS. The whole diff is 4 files under core/manifests/apps/sbx-sendrast/; no hostPath, no init container, no script touching the home tree. The amendment is purely additive manifests + controller-side mounts.

(f) Trailer — PASS. Last line of the head commit message is exactly Lab-Run: IR-20261111-c8grants (checked on the commit object at the exact head). Cosmetic only: the PR description wraps the same line in backticks.

(g) No restart semantics — PASS. spec.updateStrategy.type: OnDelete is unchanged by the diff, present in the render, and no rollingUpdate/partition is introduced. No image, command, argument, annotation or env change in the StatefulSet hunks; only volumeMounts + volumes. The merge therefore changes nothing in the running pod, as claimed; it takes effect only at a restart coordinated with Jesús.

(h) ESO gap honesty — PASS, and the disclosure is accurate. prod@live terraform/openbao.tf sendrast_eso_consumers = { sendrast = "sendrast/sbx" } grants eso-eso-sendrast read on kv/data/sendrast/sbx/* and kv/metadata/sendrast/sbx/* and nothing else, so this ES genuinely cannot read kv/ci/… and will sit in SecretSyncedError until the policy widens. Plan-only (no apply) is consistent with the brief; nothing in this diff depends on the apply having happened. Fail-closed, unchanged running pod, self-healing on apply.

STATED CONSEQUENCE, recorded: with this mount the sendrast-release robot can push branches and open PRs on Homelab/prod (El Director, 16:14:25Z); landing stays gated; Sendrast/deploy write is Jesús's own addition and is not touched here.

FOLLOW-UPS I am not blocking on, but which should not be lost:

  1. "Landing stays gated" is not evidenced anywhere in this change. The mounted helper takes --repo, and its merge gate is step 2 = one Forgejo formal APPROVED review by ld-reviewer at the head — which our own landing policy explicitly treats as never-evidence. So the gate is the robot token's Forgejo permissions, not the helper file (the same token can call /merge with plain curl). This PR does not state the robot's permission set on Homelab/prod, and no Git record of it exists (kv/ci/forgejo-sendrast-release is out-of-band; prod terraform documents only sendrast-bot). Ask: record the robot's permissions — branch/PR write, explicitly no merge on Homelab/prod — in the same place the grant is documented, so "gated" is a documented fact rather than an intention.

  2. When the prod policy change is applied, ClusterSecretStore openbao-sendrast currently has NO spec.conditions.namespaceSelector, so after the role is widened to kv/data/ci/forgejo-sendrast-release any namespace's ExternalSecret could pull that token cluster-wide. The prod PR that applies the one-line policy widen should add the namespace condition (and ideally tighten it to sbx-sendrast) — otherwise the "narrow store" framing in this PR's comments stops being true at exactly the moment the gap closes.

VERDICT: APPROVED — legs (a)–(h) pass on substance at head 6ef31481dc; the two items above are required follow-ups in the prod apply, not defects in this diff.

Exact head: 6ef31481dcd32e9ab55f91121a8feba3d4b85022 Base: 35a336157df27578698b50e0f21f69b1aa71c564 VERDICT: APPROVED (census format, seat A) SESSION: IR-20261111-c8grants-seatA-20261111T1652Z MODEL: deepseek-flash Read route: ambient pi-landing API read only (PR body + diff + file blobs at the head sha + prod@live store/terraform). No comment/review read on this PR at any point before this comment (NO-READ respected). Diff surface, verified against the tree, not the prose: exactly 4 files, all under `core/manifests/apps/sbx-sendrast/` (`externalsecrets.yaml`, `kustomization.yaml`, new `sendrast-tools.yaml`, `statefulset.yaml`). Two hunks in the StatefulSet (volumeMounts, volumes), nothing else. `kubectl kustomize core/manifests/apps/sbx-sendrast` on a clean clone of the head renders (exit 0): ConfigMap `sbx-sendrast-tools`, ExternalSecret `sbx-sendrast-release-robot`, StatefulSet with both new mounts `readOnly: true` and `updateStrategy: OnDelete`. CI combined status at the head = `success` (11 contexts, re-read myself, not taken from the body). LEGS (a) G1 credential — PASS. ES `sbx-sendrast-release-robot` in ns `sbx-sendrast`, `secretStoreRef` ClusterSecretStore `openbao-sendrast`, `remoteRef.key: ci/forgejo-sendrast-release` + `property: token` → resolves to `kv/data/ci/forgejo-sendrast-release` (store path `kv`, v2). Secret `sbx-sendrast-release-robot`, `creationPolicy: Owner`, `deletionPolicy: Retain` — matches the other 4 ESes in the file. Store identity verified independently: `openbao-sendrast` exists in `Homelab/prod@live` (`manifests/lab-director/ld-fleet-cluster-secret-stores.yaml`, wave 8) with `role: eso-sendrast` bound to `external-secrets/eso-openbao-reader`, and the SAME store already serves the working `sbx-sendrast-forgejo-token` ES in this namespace — so the new ES is not blocked by store readiness, only by the role's path scope. Mount `release-robot` → `/run/secrets/sendrast/release-robot` + item `token` ⇒ exact file `/run/secrets/sendrast/release-robot/token`; `readOnly: true`; outside `/home/jesus`. Names, paths and readonly are all correct. (b) defaultMode 288 (0440) deviation — PASS, and the deviation is the correct call. Verified in the manifest: pod `securityContext.fsGroup: 1006`; the `sandbox` container (the one that owns mounts 586–640) is `runAsUser: 1006 / runAsGroup: 1006 / runAsNonRoot: true / readOnlyRootFilesystem: true`. A secret volume is delivered `root:<fsGroup>` at `defaultMode`, so 0400 would be unreadable for uid 1006 and the mount would be dead weight; 0440 grants group-read only and is non-writable by anyone — and since every process in that container is uid/gid 1006, group-read adds no privilege beyond what 0400-for-1006 would have. Documented in both the manifest comment and the PR body, i.e. flagged rather than silently done. No env var, no argv: the diff adds no environment entries and the helper reads the token from the file. PASS. (c) `optional: true` — PASS with a note. Correct fail-closed shape: while the ESO gap stands an unplanned pod recreate mounts an empty directory instead of leaving Jesús's sandbox `Pending`, and once the Secret syncs the projected volume updates in place with no recreate (accurate as documented). Two precision notes, neither blocking: (1) with `optional: true`, a Secret that existed and is then deleted leaves the last file content mounted, so "never starts with a stale token" is true at pod start but not for a long-lived pod; (2) if the token file is absent the helper dies on a bare `FileNotFoundError` traceback from `open(args.token_file)` rather than the `step=… code=…` fail path — fail-closed (no merge, exit 1) but the body's "the helper's error says so" overstates the diagnostics. Dropping `optional: true` once `SecretSynced=True`, as the body says, closes both. (d) G1c ConfigMap helper — PASS. Embedded copy extracted from the rendered ConfigMap: `ast.parse` OK, `--help` shows `--token-file` optional with default exactly `/run/secrets/sendrast/release-robot/token` (byte-matches the G1 mount path), head pin intact (`{"Do": …, "head_commit_id": args.expect_sha}`), the four checks present and ordered, token only via file, exits 2 on head move / 3 on unexpected code, mode 0440 and non-executable (invoked `python3 …`), mounted read-only at `/opt/sendrast-tools` — same pattern as the already-working `/opt/sbx-skills` and `/opt/sbx-models` mounts in this pod, so no read-only-rootfs conflict. `sendrast-tools.yaml` is in `resources` (7 entries = the 7 non-kustomization manifests in the directory; verified), and it renders, so ArgoCD will not prune it. Caveat on the one claim I cannot verify: the "byte-identical to sha256 db8108eb except the `--token-file` default" comparison is attested, not checkable — the pristine source lives in a `working-files/…` path that is not in Git (I searched infra-core@head, prod, and the repo root; no such tree). The embedded blob hashes `30e98f9c…`. Recommend committing the pristine source (or its diff) into that record so the next reader can audit it instead of trusting the note. (e) No writes under /home/jesus — PASS. The whole diff is 4 files under `core/manifests/apps/sbx-sendrast/`; no hostPath, no init container, no script touching the home tree. The amendment is purely additive manifests + controller-side mounts. (f) Trailer — PASS. Last line of the head commit message is exactly `Lab-Run: IR-20261111-c8grants` (checked on the commit object at the exact head). Cosmetic only: the PR description wraps the same line in backticks. (g) No restart semantics — PASS. `spec.updateStrategy.type: OnDelete` is unchanged by the diff, present in the render, and no `rollingUpdate`/`partition` is introduced. No image, command, argument, annotation or env change in the StatefulSet hunks; only `volumeMounts` + `volumes`. The merge therefore changes nothing in the running pod, as claimed; it takes effect only at a restart coordinated with Jesús. (h) ESO gap honesty — PASS, and the disclosure is accurate. `prod@live terraform/openbao.tf` `sendrast_eso_consumers = { sendrast = "sendrast/sbx" }` grants `eso-eso-sendrast` read on `kv/data/sendrast/sbx/*` and `kv/metadata/sendrast/sbx/*` and nothing else, so this ES genuinely cannot read `kv/ci/…` and will sit in `SecretSyncedError` until the policy widens. Plan-only (no apply) is consistent with the brief; nothing in this diff depends on the apply having happened. Fail-closed, unchanged running pod, self-healing on apply. STATED CONSEQUENCE, recorded: with this mount the `sendrast-release` robot can push branches and open PRs on `Homelab/prod` (El Director, 16:14:25Z); landing stays gated; `Sendrast/deploy` write is Jesús's own addition and is not touched here. FOLLOW-UPS I am not blocking on, but which should not be lost: 1. "Landing stays gated" is not evidenced anywhere in this change. The mounted helper takes `--repo`, and its merge gate is step 2 = one Forgejo formal `APPROVED` review by `ld-reviewer` at the head — which our own landing policy explicitly treats as never-evidence. So the gate is the robot token's Forgejo permissions, not the helper file (the same token can call `/merge` with plain curl). This PR does not state the robot's permission set on `Homelab/prod`, and no Git record of it exists (`kv/ci/forgejo-sendrast-release` is out-of-band; prod terraform documents only `sendrast-bot`). Ask: record the robot's permissions — branch/PR write, explicitly no merge on `Homelab/prod` — in the same place the grant is documented, so "gated" is a documented fact rather than an intention. 2. When the prod policy change is applied, `ClusterSecretStore openbao-sendrast` currently has NO `spec.conditions.namespaceSelector`, so after the role is widened to `kv/data/ci/forgejo-sendrast-release` any namespace's ExternalSecret could pull that token cluster-wide. The prod PR that applies the one-line policy widen should add the namespace condition (and ideally tighten it to `sbx-sendrast`) — otherwise the "narrow store" framing in this PR's comments stops being true at exactly the moment the gap closes. VERDICT: APPROVED — legs (a)–(h) pass on substance at head 6ef31481dcd32e9ab55f91121a8feba3d4b85022; the two items above are required follow-ups in the prod apply, not defects in this diff.
Collaborator

Seat B — census-format review, head 6ef31481dc

SESSION: IR-20261111-c8grants-seatB-20261111T1652Z
MODEL: deepseek-flash

VERDICT: CHANGES — 1 blocking leg; the five substance legs (a)–(e) PASS as built.

What I re-derived myself instead of trusting the body: base 35a3361 → head 6ef31481 is ONE commit, 4 files, 274 insertions, 0 deletions; kubectl kustomize core/manifests/apps/sbx-sendrast renders clean; resources (7) == ls *.yaml minus the kustomization; the ClusterSecretStore and the ESO policy read out of Homelab/prod live (not copied from this description).

(a) ExternalSecret + mount — PASS (both deviations safe and documented)

externalsecrets.yaml:180-200: ns sbx-sendrast, ClusterSecretStore openbao-sendrast, remoteRef ci/forgejo-sendrast-release property token, target Secret sbx-sendrast-release-robot, creationPolicy: Owner / deletionPolicy: Retain — the same shape as the five ES already in that file.

  • Store verified at prod manifests/lab-director/ld-fleet-cluster-secret-stores.yaml:326-350: path: kv, version: v2, role: eso-sendrast. So key: ci/forgejo-sendrast-release resolves to kv/data/ci/forgejo-sendrast-release, matching this file's own convention (ld/omniroute, ld/forgejo-ci-reader, sendrast/sbx/forgejo-bot). Path leg correct, and correctly NOT the broad openbao store.
  • Mount statefulset.yaml:626-628, readOnly: true, on the sandbox container. Volume :763-770: secretName: sbx-sendrast-release-robot, items: token→token, defaultMode: 288. The chain lines up end to end: property token → secretKey token → items.path token → /run/secrets/sendrast/release-robot/token = the helper's default.
  • 0440 instead of 0400: safe, and required. sandbox runs runAsUser: 1006 (:442) with pod fsGroup: 1006 (:107-108); a Secret volume is root-owned, so 0400 is unreadable for uid 1006 and the mount would be dead weight. 288 is the pattern already proven in this pod (ci-reader :746, omniroute key, sbx-skills). readOnly: true on the mount is the write barrier — nothing in argv, nothing in env. Accepted trade, worth stating once: 0440 exposes the token to anything in the pod's group 1006, i.e. the same exposure the git bot token already has — consistent, not new.
  • optional: true: safe for availability, honest, acceptable. It converts a misconfiguration into a silent absence instead of a Pending pod, which is the right trade for a sandbox that must not wedge on a policy that is not applied yet. Two nits, non-blocking: with no token file the helper dies at open(args.token_file) with a bare FileNotFoundError traceback (line 97 of the extracted helper) — the PR says "the error says it"; it does, but not readably; and it sits next to ci-reader, whose comment at :738 says it deliberately has NO optional escape hatch, so a reader who does not have this PR body in front of them will read the two polarities as a mistake.
  • Policy gap confirmed, not overstated: prod terraform/openbao.tf:1039-1057 grants eso-sendrast read on kv/data|metadata/sendrast/sbx/* only. This ES will sit in SecretSyncedError until the planned one-object policy change lands — exactly as documented, and the plan-only discipline (no apply) is right for C8.
  • Not verifiable from this seat: that kv/ci/forgejo-sendrast-release exists at v2 with a token field (no OpenBao credential here; the builder read metadata only). If the field name is wrong this fails closed and, thanks to optional: true, the pod still starts — bounded, so not a blocker.

(b) ConfigMap / head-pinned helper — PASS on substance, provenance NOT verifiable

sendrast-tools.yaml:27-180; CM sbx-sendrast-tools mounted read-only at /opt/sendrast-tools (statefulset.yaml:632-634, volume :774-779, defaultMode: 288), listed at kustomization.yaml:39, invoked as python3 /opt/sendrast-tools/sendrast-merge.py so 0440 and non-executable is correct.

I extracted the block scalar and checked it: ast.parse OK; the merge call is {"Do": …, "head_commit_id": args.expect_sha} (line 135) after the head check (line 104) and the read-back; the token comes only from a file (open(args.token_file), line 97), never argv, never env, never printed; --help confirms --token-file is optional with /run/secrets/sendrast/release-robot/token as default (line 90). The four checks are intact.

But the sha256 claim cannot be reviewed. working-files/infra-stability/sendrast-release-unblock-20261110/sendrast-merge.py exists in no reachable tree — not in infra-core, prod, lab-director or pi-extensions, and it is not gitignored, it is simply not committed. So db8108eb… cannot be re-derived by a reviewer or by CI, and nothing pins the bytes that are actually mounted (embedded copy: 6500 B, sha256 30e98f9c4ea52739b8616a1330d16fa837ceec21646ece6a4944c8dab4c8d651). Also "byte-identical except one change" is imprecise: the docstring gains a C8 G1c paragraph as well as --token-file changing.

(c) No writes under /home/jesus — PASS

Zero deletion lines in the whole diff; no hostPath, seed, image or /home/jesus path is touched; both new mounts are read-only and outside the home; the helper's default token path is under /run/secrets/, never the home.

(d) Trailer — PASS

Single commit; %(trailers) is exactly one trailer; the last non-empty line of the message, and nothing after it, is Lab-Run: IR-20261111-c8grants.

(e) No restart semantics — PASS

updateStrategy: OnDelete (statefulset.yaml:75-76), untouched; the additions are two volumeMounts (both readOnly: true) and two volumes on an unchanged image; no rollingUpdate/partition, no image bump, no delete/restart instruction anywhere in the diff. Nothing rolls on merge; it lands on the next sbx recreate that homelab-a9 coordinates with Jesús.

BLOCKING

1. The repo's own invariant harness goes red on this head. scripts/gits-sbx-epic-test.sh:2536-2556 (H2v3[3]) requires the render's new (kind,name) objects for sbx-sendrast to equal EXACTLY six known ones (models-json, ci-reader, plane, viewer Role/RoleBinding/ServiceAccount), minus whatever the base ref already carries. Base 35a3361 already carries all six ⇒ expected-new is EMPTY. I ran the harness's own objs() derivation over base vs head: added = ConfigMap/sbx-sendrast-tools, ExternalSecret/sbx-sendrast-release-robot; removed = none ⇒ sradded != srexpected ⇒ FAIL. Sections [6]/[7] are also where this file pins the plane/ci-reader volumes and ci-reader's "no optional escape hatch", so the shape the sibling waves used is: extend srexpected with the two new objects and add a small subsection pinning this volume's polarity (secretName, key: token, defaultMode: 288, optional: true and why, mount readOnly: true) so the two deviations are guarded the way the others are, instead of relying on this PR body. Two lines plus a short block. If this epic instead updates the harness in a later wave, say so in a reply and this leg is satisfied.

SHOULD FIX in this PR

  1. Pin the helper's bytes. Put the embedded sha256 (30e98f9c…, 6500 B) next to the G1c comment — or commit the source under a tracked path — so the "sanctioned route" has provenance in Git and future drift of this ConfigMap is visible. Drop the "only one change" wording to "docstring paragraph + --token-file default".
  2. Write down why landing stays gated. The mounted helper gates a merge on ONE ld-reviewer APPROVED formal review at the pinned head plus green CI, and --repo is a free argument — so a pod holding this token also holds a merge tool whose gate is materially weaker than this fleet's landing lock (where verdicts are comments and formal review state is explicitly not evidence). Landing is safe only because Forgejo refuses the robot on Homelab/prod: that is implied by El Director's 16:14:25Z words, not stated in the diff. One line asserting the robot has no merge permission on Homelab/prod (or an allowlist on --repo) makes the boundary checkable instead of assumed. Sendrast/deploy write being Jesús's own addition is noted and correctly left untouched.

NITS

  1. The new ConfigMap carries no labels; sibling models-json.yaml:57-58 has app.kubernetes.io/part-of: sendrast-sandbox.
  2. Only token is mounted. A human pushing with the robot needs the login name in the credential helper too — one line of usage (/opt/sendrast-tools/..., login sendrast-release, token by file) somewhere in Git would make the sanctioned route discoverable without this PR body.

Nothing above asks to change (a)'s two deviations: as built, 0440 and optional: true are correct, and the second is already promised as a follow-up.

## Seat B — census-format review, head 6ef31481dcd32e9ab55f91121a8feba3d4b85022 SESSION: IR-20261111-c8grants-seatB-20261111T1652Z MODEL: deepseek-flash VERDICT: **CHANGES** — 1 blocking leg; the five substance legs (a)–(e) PASS as built. What I re-derived myself instead of trusting the body: base 35a3361 → head 6ef31481 is ONE commit, 4 files, **274 insertions, 0 deletions**; `kubectl kustomize core/manifests/apps/sbx-sendrast` renders clean; `resources` (7) == `ls *.yaml` minus the kustomization; the ClusterSecretStore and the ESO policy read out of Homelab/prod `live` (not copied from this description). ### (a) ExternalSecret + mount — PASS (both deviations safe and documented) `externalsecrets.yaml:180-200`: ns `sbx-sendrast`, ClusterSecretStore `openbao-sendrast`, remoteRef `ci/forgejo-sendrast-release` property `token`, target Secret `sbx-sendrast-release-robot`, `creationPolicy: Owner` / `deletionPolicy: Retain` — the same shape as the five ES already in that file. * Store verified at prod `manifests/lab-director/ld-fleet-cluster-secret-stores.yaml:326-350`: `path: kv`, `version: v2`, `role: eso-sendrast`. So `key: ci/forgejo-sendrast-release` resolves to `kv/data/ci/forgejo-sendrast-release`, matching this file's own convention (`ld/omniroute`, `ld/forgejo-ci-reader`, `sendrast/sbx/forgejo-bot`). Path leg correct, and correctly NOT the broad `openbao` store. * Mount `statefulset.yaml:626-628`, `readOnly: true`, on the `sandbox` container. Volume `:763-770`: `secretName: sbx-sendrast-release-robot`, `items: token→token`, `defaultMode: 288`. The chain lines up end to end: property `token` → secretKey `token` → items.path `token` → `/run/secrets/sendrast/release-robot/token` = the helper's default. * **0440 instead of 0400: safe, and required.** `sandbox` runs `runAsUser: 1006` (`:442`) with pod `fsGroup: 1006` (`:107-108`); a Secret volume is root-owned, so 0400 is unreadable for uid 1006 and the mount would be dead weight. 288 is the pattern already proven in this pod (ci-reader `:746`, omniroute key, sbx-skills). `readOnly: true` on the mount is the write barrier — nothing in argv, nothing in env. Accepted trade, worth stating once: 0440 exposes the token to anything in the pod's group 1006, i.e. the same exposure the git bot token already has — consistent, not new. * **`optional: true`: safe for availability, honest, acceptable.** It converts a misconfiguration into a *silent absence* instead of a Pending pod, which is the right trade for a sandbox that must not wedge on a policy that is not applied yet. Two nits, non-blocking: with no token file the helper dies at `open(args.token_file)` with a bare FileNotFoundError traceback (line 97 of the extracted helper) — the PR says "the error says it"; it does, but not readably; and it sits next to `ci-reader`, whose comment at `:738` says it deliberately has NO optional escape hatch, so a reader who does not have this PR body in front of them will read the two polarities as a mistake. * **Policy gap confirmed, not overstated:** prod `terraform/openbao.tf:1039-1057` grants `eso-sendrast` read on `kv/data|metadata/sendrast/sbx/*` only. This ES *will* sit in SecretSyncedError until the planned one-object policy change lands — exactly as documented, and the plan-only discipline (no apply) is right for C8. * **Not verifiable from this seat:** that `kv/ci/forgejo-sendrast-release` exists at v2 with a `token` field (no OpenBao credential here; the builder read metadata only). If the field name is wrong this fails closed and, thanks to `optional: true`, the pod still starts — bounded, so not a blocker. ### (b) ConfigMap / head-pinned helper — PASS on substance, provenance NOT verifiable `sendrast-tools.yaml:27-180`; CM `sbx-sendrast-tools` mounted read-only at `/opt/sendrast-tools` (`statefulset.yaml:632-634`, volume `:774-779`, `defaultMode: 288`), listed at `kustomization.yaml:39`, invoked as `python3 /opt/sendrast-tools/sendrast-merge.py` so 0440 and non-executable is correct. I extracted the block scalar and checked it: `ast.parse` OK; the merge call is `{"Do": …, "head_commit_id": args.expect_sha}` (line 135) after the head check (line 104) and the read-back; the token comes only from a file (`open(args.token_file)`, line 97), never argv, never env, never printed; `--help` confirms `--token-file` is optional with `/run/secrets/sendrast/release-robot/token` as default (line 90). The four checks are intact. **But the sha256 claim cannot be reviewed.** `working-files/infra-stability/sendrast-release-unblock-20261110/sendrast-merge.py` exists in no reachable tree — not in infra-core, prod, lab-director or pi-extensions, and it is not gitignored, it is simply not committed. So `db8108eb…` cannot be re-derived by a reviewer or by CI, and nothing pins the bytes that are actually mounted (embedded copy: 6500 B, `sha256 30e98f9c4ea52739b8616a1330d16fa837ceec21646ece6a4944c8dab4c8d651`). Also "byte-identical except one change" is imprecise: the docstring gains a C8 G1c paragraph *as well as* `--token-file` changing. ### (c) No writes under /home/jesus — PASS Zero deletion lines in the whole diff; no hostPath, seed, image or `/home/jesus` path is touched; both new mounts are read-only and outside the home; the helper's default token path is under `/run/secrets/`, never the home. ### (d) Trailer — PASS Single commit; `%(trailers)` is exactly one trailer; the last non-empty line of the message, and nothing after it, is `Lab-Run: IR-20261111-c8grants`. ### (e) No restart semantics — PASS `updateStrategy: OnDelete` (`statefulset.yaml:75-76`), untouched; the additions are two `volumeMounts` (both `readOnly: true`) and two volumes on an unchanged image; no `rollingUpdate`/`partition`, no image bump, no delete/restart instruction anywhere in the diff. Nothing rolls on merge; it lands on the next sbx recreate that homelab-a9 coordinates with Jesús. ### BLOCKING **1. The repo's own invariant harness goes red on this head.** `scripts/gits-sbx-epic-test.sh:2536-2556` (H2v3[3]) requires the render's new `(kind,name)` objects for sbx-sendrast to equal EXACTLY six known ones (models-json, ci-reader, plane, viewer Role/RoleBinding/ServiceAccount), minus whatever the base ref already carries. Base 35a3361 already carries all six ⇒ expected-new is EMPTY. I ran the harness's own `objs()` derivation over base vs head: added = `ConfigMap/sbx-sendrast-tools`, `ExternalSecret/sbx-sendrast-release-robot`; removed = none ⇒ `sradded != srexpected` ⇒ FAIL. Sections [6]/[7] are also where this file pins the plane/ci-reader volumes and ci-reader's "no optional escape hatch", so the shape the sibling waves used is: extend `srexpected` with the two new objects **and** add a small subsection pinning this volume's polarity (secretName, `key: token`, `defaultMode: 288`, `optional: true` and why, mount `readOnly: true`) so the two deviations are guarded the way the others are, instead of relying on this PR body. Two lines plus a short block. If this epic instead updates the harness in a later wave, say so in a reply and this leg is satisfied. ### SHOULD FIX in this PR 2. **Pin the helper's bytes.** Put the embedded sha256 (`30e98f9c…`, 6500 B) next to the G1c comment — or commit the source under a tracked path — so the "sanctioned route" has provenance in Git and future drift of this ConfigMap is visible. Drop the "only one change" wording to "docstring paragraph + `--token-file` default". 3. **Write down why landing stays gated.** The mounted helper gates a merge on ONE ld-reviewer APPROVED *formal* review at the pinned head plus green CI, and `--repo` is a free argument — so a pod holding this token also holds a merge tool whose gate is materially weaker than this fleet's landing lock (where verdicts are comments and formal review state is explicitly not evidence). Landing is safe only because Forgejo refuses the robot on Homelab/prod: that is implied by El Director's 16:14:25Z words, not stated in the diff. One line asserting the robot has no merge permission on Homelab/prod (or an allowlist on `--repo`) makes the boundary checkable instead of assumed. Sendrast/deploy write being Jesús's own addition is noted and correctly left untouched. ### NITS 4. The new ConfigMap carries no labels; sibling `models-json.yaml:57-58` has `app.kubernetes.io/part-of: sendrast-sandbox`. 5. Only `token` is mounted. A human pushing with the robot needs the login name in the credential helper too — one line of usage (`/opt/sendrast-tools/...`, login `sendrast-release`, token by file) somewhere in Git would make the sanctioned route discoverable without this PR body. Nothing above asks to change (a)'s two deviations: as built, 0440 and `optional: true` are correct, and the second is already promised as a follow-up.
C8 G1/G1c REBUILD (homelab-93 blocking review): Sendrast-only robot, hardened helper
Some checks failed
CI Review / helm-validate (pull_request) Successful in 18s
CI Review / runner-manifest-test (pull_request) Successful in 10s
CI Review / receiver-test (pull_request) Successful in 10s
CI Review / alert-receiver-test (pull_request) Successful in 28s
Lint & Validate / shellcheck (pull_request) Successful in 12s
Lint & Validate / yaml-lint (pull_request) Successful in 27s
Lint & Validate / terraform-validate (pull_request) Successful in 2m22s
CI Review / cockpit-test (pull_request) Successful in 2m53s
CI Review / cockpit-e2e (pull_request) Successful in 4m35s
CI Review / dispatcher-test (pull_request) Successful in 5m19s
CI Review / record-sql-test (pull_request) Failing after 5m21s
07e41d743b
F1: the credential is NO LONGER `sendrast-release`, which also has write on
Homelab/prod — and Homelab/prod workflows run on the `infra:host` runner that
carries the SOPS age key, the AWS state credentials and the OPENBAO_APPLY_*/CI_*
AppRoles, so any writer there can execute code on the infrastructure. The sandbox
now gets its own robot, `sendrast-robot`: write ONLY on Sendrast/api-sendrast and
Sendrast/sendrast-web, token at kv/sendrast/sbx/release-robot. Aaron creates the
account and the object (click list E); neither exists yet and this PR creates
neither. The ExternalSecret reads that path through the namespace's own store
`openbao-sendrast`; every reference to the old kv path is gone.

F2: `openbao-sendrast` gets `spec.conditions[].namespaces: [sbx-sendrast]`. The
store has exactly one copy, in Homelab/prod
(manifests/lab-director/ld-fleet-cluster-secret-stores.yaml), so the condition
goes there, not in this repo. Census before the change: the only ExternalSecret
using that store today is sbx-sendrast/sbx-sendrast-forgejo-token
(kv/sendrast/sbx/forgejo-bot); nothing outside sbx-sendrast consumes it, so the
condition removes no working consumer.

No prod terraform change is needed: `eso-sendrast` already reads
kv/data/sendrast/sbx/* plus its metadata, read-only (prod terraform/openbao.tf),
and the live proof is that same sibling ExternalSecret being Ready=True
SecretSynced. Plan only: 0 to add / 0 to change / 0 to destroy (any apply is
homelab-93's, not this PR's).

G1c (F4/F5): sendrast-merge.py now has (a) a hard repo allowlist — anything but
the two Sendrast repos is refused BEFORE any API call; (b) a review gate stricter
than the server: ANY dismissed approval, or ANY approval recorded on a non-head
commit, is refused, and then one ld-reviewer approval at the head is required
(main asks for zero required approvals, so the server whitelist is inert); (c)
`--self-check`, 19 offline fixtures: allowlist, dismissed/stale/non-head/
wrong-user/no-approval cases, the CI gate, no token-bearing URL, no command-line
token, and the token-file mode rule; (d) the token comes from the file only —
never argv, never a URL, never env — and a group/world-writable file is refused;
(e) the sanctioned push/tag route, sendrast-credential-helper.sh, a git
credential helper that answers only get, only https, only the Forgejo host and
only the two allowlisted repos, and leaves nothing behind in .git/config.
Redirects are refused, so the Authorization header cannot be replayed at another
host, and the docstring now matches the real exit codes (1/2) and file mode (0440).

Unchanged deviations, restated: 0440 (288) rather than the brief's 0400, because
the container runs as uid 1006 with fsGroup 1006; and `optional: true` until the
robot and the kv object exist — now doubly gated, since two things are missing.

Go-live: at the next sbx restart that homelab-a9 coordinates with Jesús, and ONLY
once Aaron has created sendrast-robot and kv/sendrast/sbx/release-robot exists.
Nothing is restarted, applied or created here.

Lab-Run: IR-20261111-c8grants
Collaborator

VERDICT: CHANGES — 1 blocking leg (L4, the sanctioned push/tag route as documented), 3 advisories. Everything else in the brief checks out at this exact head.

Reviewed head 07e41d743b (base 35a336157d), 4 files. I read the diff and the files at that head via the Forgejo API and re-derived the checks locally (kubectl kustomize render of core/manifests/apps/sbx-sendrast, extracted ConfigMap payloads, real git credential fill). I did not use the author's verify list as evidence.

LEGS

  • L1 G1 ExternalSecret — PASS. sbx-sendrast-release-robot (ns sbx-sendrast) → ClusterSecretStore openbao-sendrast, key: sendrast/sbx/release-robot, property: token, creationPolicy Owner / deletionPolicy Retain. Rendered output confirms exactly that. grep -rIl forgejo-sendrast-release over the whole tree at this head → NONE; the string ci/forgejo-sendrast-release appears nowhere, and the only sendrast-release hits are prose about not mounting the old robot.
  • L2 mount + gating — PASS. Volume release-robot → secretName: sbx-sendrast-release-robot, optional: true, defaultMode: 288, items: [{key: token, path: token}]; mount readOnly: true at /run/secrets/sendrast/release-robot in the sandbox container ONLY (rendered container map: dind 2142, sandbox 2215, health 2269 — the mount block sits inside sandbox; no init container mounts it). 0440 rationale is factually correct here: pod fsGroup: 1006 and sandbox runAsUser 1006 / runAsGroup 1006, so a root-owned 0400 would be unreadable and 288 is the right call. sendrast-tools mount is likewise readOnly and outside the home.
  • L3 G1c merge helper — PASS. Ordering in main() is allowlist → token → PR head → reviews → CI → merge; the allowlist refusal happens before read_token() and before any http() call, so --repo Homelab/prod dies offline. Head pin head_commit_id is in the merge body; --expect-sha drift exits 2. Review gate rejects dismissed, stale, and any approval whose commit_id != head, then requires an ld-reviewer APPROVED at head; CI combined status must be success (missing status is fail-closed). Token: no --token, file only, group/world-writable refused; redirects refused via _NoRedirect; no token in URL construction. I extracted the payload from the ConfigMap and ran it: python3 … --self-check → 19/19 PASS, failures=0, exit 0; py_compile OK; sh -n on the sibling OK.
  • L4 G1c push/tag credential helper — FAIL (blocking). The helper itself is correct (sh <path> accepts both Sendrast repos and refuses a foreign host and Sendrast/api-sendrast-evil), but it cannot be invoked the way the PR documents it. The file is mounted at defaultMode: 288 (0440) on a read-only volume, and git runs !-prefixed helpers through the shell, which must execve the path. Reproduced with real git against the rendered mode, with ambient config cleared:
    printf 'protocol=https\nhost=forgejo.aaron.reynoza.org\npath=Sendrast/sendrast-web.git\n\n' | git -c credential.helper= -c credential.helper='!/tmp/tools/helper.sh' credential fill
    → /tmp/tools/helper.sh get: 1: …: Permission denied / fatal: could not read Username for 'https://forgejo.aaron.reynoza.org' (exit 128).
    The same file at 0440 via !sh /tmp/tools/helper.sh returns username=sendrast-robot + the token; at 0550 the direct form works. So the documented command in the ConfigMap header and in the PR body does not work. This is fail-closed (no leak), but it defeats the point of F4/F5: the "sanctioned route" a future agent would copy is dead, and the fallback stays the https://x:$(cat token)@… improvisation the review asked to eliminate. Fix is one line: document !sh /opt/sendrast-tools/sendrast-credential-helper.sh (keeps 288/0440, cleanest), or raise that volume to 0550 (360) and keep the direct form — then verify through real git credential fill, not only sh -n.
  • L5 no home writes / rollout / trailer / body — PASS. No hunk writes under /home/jesus (the only new references are prose and the two /run + /opt mounts). updateStrategy: OnDelete at this head; nothing restarts a pod. Head commit message's LAST trailer is exactly Lab-Run: IR-20261111-c8grants. The body states go-live only at the next a9-coordinated sbx restart and only after Aaron creates sendrast-robot and kv/sendrast/sbx/release-robot exists, and states that this PR creates neither.

Findings (non-blocking)

  • F1 [L4, advisory] Helper composition: appended helpers do not replace existing ones. In this review box an ambient helper answered first when the sanctioned helper was appended without clearing (username=ld-builder), i.e. -c credential.helper='!…' without a preceding -c credential.helper= can silently fall through to another helper — and this pod already carries a git credential mount (/run/secrets/sendrast/git). The documented command should start with -c credential.helper= to reset the list, so the sanctioned helper is the only one asked.
  • F2 [L4, advisory] The repo allowlist is skipped when git sends no path (if [ -n "$path" ]); a host-only remote URL gets credentials for any path on the host. Bounded by the robot's own Sendrast-only write, but the allowlist should refuse an empty path explicitly rather than bypass.
  • F3 [L3, advisory, wording] "ANY dismissed approval → refuse" holds only if the API returns state: APPROVED with dismissed: true. approval_verdict() filters state == "APPROVED" first, so a review returned with state DISMISSED is dropped rather than triggering an explicit refusal. Net outcome stays fail-closed (a fresh ld-reviewer APPROVED at head is still required), but the docstring/PR wording is stronger than the code; treat DISMISSED as a refusal so the claim is literally true. Related: the two token-mode fixtures re-implement the mode predicate inline instead of calling read_token(), so a regression in read_token() would not be caught — call the function on a temp file.
  • F4 [dependency, not a defect of this diff] The F2 store scoping (spec.conditions[].namespaces: [sbx-sendrast]) is honestly declared as out-of-repo (Homelab/prod, branch head f51f9b1d2dd9eff2d5e281b4a16415f8f55cefb4, no PR from this seat). G1 does not depend on it for the mount to work, but the rebuild's narrower-blast-radius claim is only complete once that lands; it should stay visible as a tracked follow-up rather than being counted as delivered here.

Verified positives worth recording: kustomize renders clean (exit 0) with the new ConfigMap, ES and both readOnly mounts; ES/Secret key (token) matches the helper's default path /run/secrets/sendrast/release-robot/token; 288 = 0440 is consistent across both new volumes; self-check is genuinely offline (no network, no token, temp dir only) and its 19 fixtures are real assertions, not prints.

SESSION: IR-20261111-c8grants-seatA-20261111T1720Z
MODEL: deepseek-flash

VERDICT: CHANGES — 1 blocking leg (L4, the sanctioned push/tag route as documented), 3 advisories. Everything else in the brief checks out at this exact head. Reviewed head 07e41d743bc8c7af56876fd719f644aa8cc7ad85 (base 35a336157df27578698b50e0f21f69b1aa71c564), 4 files. I read the diff and the files at that head via the Forgejo API and re-derived the checks locally (kubectl kustomize render of core/manifests/apps/sbx-sendrast, extracted ConfigMap payloads, real `git credential fill`). I did not use the author's verify list as evidence. LEGS - L1 G1 ExternalSecret — PASS. `sbx-sendrast-release-robot` (ns sbx-sendrast) → ClusterSecretStore `openbao-sendrast`, `key: sendrast/sbx/release-robot`, `property: token`, creationPolicy Owner / deletionPolicy Retain. Rendered output confirms exactly that. `grep -rIl forgejo-sendrast-release` over the whole tree at this head → NONE; the string `ci/forgejo-sendrast-release` appears nowhere, and the only `sendrast-release` hits are prose about *not* mounting the old robot. - L2 mount + gating — PASS. Volume `release-robot` → `secretName: sbx-sendrast-release-robot`, `optional: true`, `defaultMode: 288`, `items: [{key: token, path: token}]`; mount `readOnly: true` at `/run/secrets/sendrast/release-robot` in the `sandbox` container ONLY (rendered container map: dind 2142, sandbox 2215, health 2269 — the mount block sits inside sandbox; no init container mounts it). 0440 rationale is factually correct here: pod `fsGroup: 1006` and sandbox `runAsUser 1006 / runAsGroup 1006`, so a root-owned 0400 would be unreadable and 288 is the right call. `sendrast-tools` mount is likewise readOnly and outside the home. - L3 G1c merge helper — PASS. Ordering in `main()` is allowlist → token → PR head → reviews → CI → merge; the allowlist refusal happens before `read_token()` and before any `http()` call, so `--repo Homelab/prod` dies offline. Head pin `head_commit_id` is in the merge body; `--expect-sha` drift exits 2. Review gate rejects `dismissed`, `stale`, and any approval whose `commit_id != head`, then requires an `ld-reviewer` APPROVED at head; CI combined status must be `success` (missing status is fail-closed). Token: no `--token`, file only, group/world-writable refused; redirects refused via `_NoRedirect`; no token in URL construction. I extracted the payload from the ConfigMap and ran it: `python3 … --self-check` → 19/19 PASS, `failures=0`, exit 0; `py_compile` OK; `sh -n` on the sibling OK. - L4 G1c push/tag credential helper — FAIL (blocking). The helper itself is correct (`sh <path>` accepts both Sendrast repos and refuses a foreign host and `Sendrast/api-sendrast-evil`), but it cannot be invoked the way the PR documents it. The file is mounted at `defaultMode: 288` (0440) on a read-only volume, and git runs `!`-prefixed helpers through the shell, which must execve the path. Reproduced with real git against the rendered mode, with ambient config cleared: printf 'protocol=https\nhost=forgejo.aaron.reynoza.org\npath=Sendrast/sendrast-web.git\n\n' | git -c credential.helper= -c credential.helper='!/tmp/tools/helper.sh' credential fill → `/tmp/tools/helper.sh get: 1: …: Permission denied` / `fatal: could not read Username for 'https://forgejo.aaron.reynoza.org'` (exit 128). The same file at 0440 via `!sh /tmp/tools/helper.sh` returns `username=sendrast-robot` + the token; at 0550 the direct form works. So the documented command in the ConfigMap header and in the PR body does not work. This is fail-closed (no leak), but it defeats the point of F4/F5: the "sanctioned route" a future agent would copy is dead, and the fallback stays the `https://x:$(cat token)@…` improvisation the review asked to eliminate. Fix is one line: document `!sh /opt/sendrast-tools/sendrast-credential-helper.sh` (keeps 288/0440, cleanest), or raise that volume to 0550 (360) and keep the direct form — then verify through real `git credential fill`, not only `sh -n`. - L5 no home writes / rollout / trailer / body — PASS. No hunk writes under /home/jesus (the only new references are prose and the two /run + /opt mounts). `updateStrategy: OnDelete` at this head; nothing restarts a pod. Head commit message's LAST trailer is exactly `Lab-Run: IR-20261111-c8grants`. The body states go-live only at the next a9-coordinated sbx restart and only after Aaron creates `sendrast-robot` and `kv/sendrast/sbx/release-robot` exists, and states that this PR creates neither. Findings (non-blocking) - F1 [L4, advisory] Helper composition: appended helpers do not replace existing ones. In this review box an ambient helper answered first when the sanctioned helper was appended without clearing (`username=ld-builder`), i.e. `-c credential.helper='!…'` without a preceding `-c credential.helper=` can silently fall through to another helper — and this pod already carries a git credential mount (`/run/secrets/sendrast/git`). The documented command should start with `-c credential.helper=` to reset the list, so the sanctioned helper is the only one asked. - F2 [L4, advisory] The repo allowlist is skipped when git sends no `path` (`if [ -n "$path" ]`); a host-only remote URL gets credentials for any path on the host. Bounded by the robot's own Sendrast-only write, but the allowlist should refuse an empty `path` explicitly rather than bypass. - F3 [L3, advisory, wording] "ANY dismissed approval → refuse" holds only if the API returns `state: APPROVED` with `dismissed: true`. `approval_verdict()` filters `state == "APPROVED"` first, so a review returned with state `DISMISSED` is dropped rather than triggering an explicit refusal. Net outcome stays fail-closed (a fresh `ld-reviewer` APPROVED at head is still required), but the docstring/PR wording is stronger than the code; treat `DISMISSED` as a refusal so the claim is literally true. Related: the two token-mode fixtures re-implement the mode predicate inline instead of calling `read_token()`, so a regression in `read_token()` would not be caught — call the function on a temp file. - F4 [dependency, not a defect of this diff] The F2 store scoping (`spec.conditions[].namespaces: [sbx-sendrast]`) is honestly declared as out-of-repo (Homelab/prod, branch head f51f9b1d2dd9eff2d5e281b4a16415f8f55cefb4, no PR from this seat). G1 does not depend on it for the mount to work, but the rebuild's narrower-blast-radius claim is only complete once that lands; it should stay visible as a tracked follow-up rather than being counted as delivered here. Verified positives worth recording: kustomize renders clean (exit 0) with the new ConfigMap, ES and both readOnly mounts; ES/Secret key (`token`) matches the helper's default path `/run/secrets/sendrast/release-robot/token`; 288 = 0440 is consistent across both new volumes; self-check is genuinely offline (no network, no token, temp dir only) and its 19 fixtures are real assertions, not prints. SESSION: IR-20261111-c8grants-seatA-20261111T1720Z MODEL: deepseek-flash
Collaborator

CENSUS VERDICT — seat B (rebuilt head)
PR: Homelab/infra-core #940 · head 07e41d743b · base 35a336157d
Scope: read-only review of the diff at this head (API diff + archive of the head tree + kubectl kustomize core/manifests/apps/sbx-sendrast). NO-READ honoured: I did not list or read this PR's comments, reviews or inline comments at any point.

SESSION: IR-20261111-c8grants-seatB-20261111T1720Z
MODEL: deepseek-flash

VERDICT: APPROVED (substance of the diff)
LEGS: (a) PASS · (b) PASS · (c) PASS · (d) PASS · (e) PASS · (f) PASS · CI at head FAIL — see F1; this verdict authorises no merge until the exact head is green.

Findings and evidence

(a) PASS — new credential, old path gone. externalsecrets.yaml:191-209: ExternalSecret sbx-sendrast-release-robot in ns sbx-sendrast, secretStoreRef kind ClusterSecretStore / name openbao-sendrast, data[0].remoteRef.key: sendrast/sbx/release-robot, property: token, creationPolicy: Owner, deletionPolicy: Retain, refreshInterval: 1h. Mounted at /run/secrets/sendrast/release-robot (statefulset.yaml:626-628, readOnly: true, sandbox container only — the mounts at 594/597 are omniroute/git, no path collision). grep -rn 'ci/forgejo-sendrast-release' over the whole head tree → 0 hits; no old shared-robot reference anywhere.

(b) PASS — doubly gated, mode justified. Volume release-robot (statefulset.yaml:766-775): secret: sbx-sendrast-release-robot, optional: true, defaultMode: 288, single item token→token. The 0440 rationale is real and consistent: sandbox container runAsUser/runAsGroup: 1006 (442-443) and pod securityContext.fsGroup: 1006 (108), so a root-owned 0400 would be unreadable; the comment says so. optional: true is deliberate until the robot + kv object exist, and the body states both preconditions. Fail-closed when absent: the helper's read_token refuses a missing/unreadable file.

(c) PASS — I extracted both embedded scripts out of the RENDERED ConfigMap (byte-identical to the source block, cmp clean), compiled them, ran them:
• --self-check → 19/19 PASS, exit 0 (allowlist accept/refuse incl. case variant, clean approval, dismissed, stale-flag, non-head commit_id, wrong user, no approvals, no reviews, non-list, CI success/pending, no token-bearing URL, no command-line token, 0666 refused / 0440 accepted).
• Allowlist is enforced before anything else: --repo Homelab/prod --token-file /nonexistent prints FAIL step=allowlist code=refused … refusing before any API call, exit 1 — the token file is not even stat'ed, so no network and no credential read.
• Review gate: any dismissed approval, any stale approval, and any approval whose commit_id != head are refused before the ld-reviewer at-head approval is required (approval_verdict).
• Token: no --token option exists in the parser; token read from file only, group/world-writable file refused; a single POST /merge with {"Do":…, "head_commit_id": <expected>} and a read-back of merged.
• Redirects refused (_NoRedirect → 3xx becomes a hard non-200 failure, so the Authorization header cannot be replayed cross-host).
• sendrast-credential-helper.sh: get-only (store/erase are no-ops, verified exit 0/no output), https-only, host-pinned, two-segment repo allowlist; I ran the accepts and the refusals (foreign host, Sendrast/api-sendrast-evil, non-https all exit 1). Reads the same file, never argv/env/URL.

(d) PASS — exactly 4 files changed (externalsecrets.yaml, kustomization.yaml, new sendrast-tools.yaml, statefulset.yaml), all under core/manifests/apps/sbx-sendrast; no path under /home/jesus is written or added; both new mounts (/run/secrets/sendrast/release-robot, /opt/sendrast-tools) are outside the home and read-only, ConfigMap+Secret volume defaultMode: 288.

(e) PASS — commit 07e41d7 message: last non-empty line is exactly Lab-Run: IR-20261111-c8grants. The PR body's Go-live section states the two preconditions verbatim: goes live at the next sbx-sendrast restart that homelab-a9 coordinates with Jesús, and ONLY once Aaron has created sendrast-robot and kv/sendrast/sbx/release-robot exists; nothing is restarted/applied/created by this PR.

(f) PASS — updateStrategy: type: OnDelete (statefulset.yaml:75-76, unchanged by this diff, present in the render); the diff adds only template fields, so merging cannot restart the running pod.

F1 — CI IS RED AT THIS EXACT HEAD (leg fails; blocking for landing, not for the substance above).
GET /commits/07e41d7…/status → combined: failure, 11 statuses, one non-green:
CI Review / record-sql-test (pull_request) — Failing after 5m21s, run 3580 job 7, created 2026-11-11T17:03:24Z (head authored 16:56:33Z, so it is this head).
The three Lint & Validate jobs the body cites (run 3581: yaml-lint, shellcheck, terraform-validate) are indeed green, and the body does not claim more than that — but it also does not mention this failure. A diff touching only four sbx-sendrast manifests makes a regression of a record/SQL test implausible; treat it as flake/environmental and prove it: re-run and either get the head green or attach the evidence that it fails identically on live (the base sha currently carries no statuses at all, so base-green is not established either). The landing lock needs green at this exact head; I cannot sign the CI leg.

F2 — non-blocking, design (record it): the review gate is a client-side control in a file the token holder can bypass. The token is mounted readable to uid 1006 by design, so Jesús can call POST /repos/…/pulls/{n}/merge directly with the same token; since Sendrast main asks for 0 required approvals (the body says so), the server enforces nothing. G1c therefore protects against accidental use, not against a determined user. If the intent is enforceable review, the control belongs server-side (required approvals / merge whitelist on the Sendrast repos), not in the helper. As specified for this PR it is accepted, but it should not be described as a guarantee.

F3 — non-blocking, operational: the gate refuses ANY approval whose commit_id != head, and Forgejo keeps reviews per commit. After the first re-push of an already-approved PR, the helper refuses that PR forever (no supersession notion, and a dismissed/stale flag is equally permanent). Intended strictness per the brief, but the operator note should say the escape hatch is a fresh PR, otherwise the sanctioned route dead-ends on round 2.

F4 — minor: sendrast-credential-helper.sh only applies the repo allowlist when git sends a path=; a host-only request returns the credential (verified). Bounded by the robot's two-repo scope, so not exploitable here, but it is weaker than "only the two allowlisted repos" as written.

F5 — dependency, outside this diff: the openbao-sendrast namespace scoping (spec.conditions[].namespaces) lives in Homelab/prod manifests/lab-director/ld-fleet-cluster-secret-stores.yaml (body says branch plane/IR-20261111-c8grants-store, head f51f9b1…, no PR opened). Until that lands in prod, the store stays cluster-wide-selectable and the "doubly gated / namespace-scoped" story is incomplete. Also track the follow-up removal of optional: true once SecretSynced=True — with it in place the mount is not enforced.

No token, secret value, prefix or fingerprint appears in this comment. Nothing was written under /home/jesus; no kubectl write, no restart, no OpenBao write performed by this seat.

CENSUS VERDICT — seat B (rebuilt head) PR: Homelab/infra-core #940 · head 07e41d743bc8c7af56876fd719f644aa8cc7ad85 · base 35a336157df27578698b50e0f21f69b1aa71c564 Scope: read-only review of the diff at this head (API diff + archive of the head tree + `kubectl kustomize core/manifests/apps/sbx-sendrast`). NO-READ honoured: I did not list or read this PR's comments, reviews or inline comments at any point. SESSION: IR-20261111-c8grants-seatB-20261111T1720Z MODEL: deepseek-flash VERDICT: APPROVED (substance of the diff) LEGS: (a) PASS · (b) PASS · (c) PASS · (d) PASS · (e) PASS · (f) PASS · CI at head FAIL — see F1; this verdict authorises no merge until the exact head is green. Findings and evidence ---------------------- (a) PASS — new credential, old path gone. `externalsecrets.yaml:191-209`: ExternalSecret `sbx-sendrast-release-robot` in ns `sbx-sendrast`, `secretStoreRef` kind ClusterSecretStore / name `openbao-sendrast`, `data[0].remoteRef.key: sendrast/sbx/release-robot`, `property: token`, `creationPolicy: Owner`, `deletionPolicy: Retain`, `refreshInterval: 1h`. Mounted at `/run/secrets/sendrast/release-robot` (statefulset.yaml:626-628, `readOnly: true`, sandbox container only — the mounts at 594/597 are omniroute/git, no path collision). `grep -rn 'ci/forgejo-sendrast-release'` over the whole head tree → 0 hits; no old shared-robot reference anywhere. (b) PASS — doubly gated, mode justified. Volume `release-robot` (statefulset.yaml:766-775): `secret: sbx-sendrast-release-robot`, `optional: true`, `defaultMode: 288`, single item `token→token`. The 0440 rationale is real and consistent: sandbox container `runAsUser/runAsGroup: 1006` (442-443) and pod `securityContext.fsGroup: 1006` (108), so a root-owned 0400 would be unreadable; the comment says so. `optional: true` is deliberate until the robot + kv object exist, and the body states both preconditions. Fail-closed when absent: the helper's `read_token` refuses a missing/unreadable file. (c) PASS — I extracted both embedded scripts out of the RENDERED ConfigMap (byte-identical to the source block, `cmp` clean), compiled them, ran them: • `--self-check` → 19/19 PASS, exit 0 (allowlist accept/refuse incl. case variant, clean approval, dismissed, stale-flag, non-head `commit_id`, wrong user, no approvals, no reviews, non-list, CI success/pending, no token-bearing URL, no command-line token, 0666 refused / 0440 accepted). • Allowlist is enforced before anything else: `--repo Homelab/prod --token-file /nonexistent` prints `FAIL step=allowlist code=refused … refusing before any API call`, exit 1 — the token file is not even stat'ed, so no network and no credential read. • Review gate: any `dismissed` approval, any `stale` approval, and any approval whose `commit_id != head` are refused before the `ld-reviewer` at-head approval is required (`approval_verdict`). • Token: no `--token` option exists in the parser; token read from file only, group/world-writable file refused; a single `POST /merge` with `{"Do":…, "head_commit_id": <expected>}` and a read-back of `merged`. • Redirects refused (`_NoRedirect` → 3xx becomes a hard non-200 failure, so the Authorization header cannot be replayed cross-host). • `sendrast-credential-helper.sh`: get-only (`store`/`erase` are no-ops, verified exit 0/no output), https-only, host-pinned, two-segment repo allowlist; I ran the accepts and the refusals (foreign host, `Sendrast/api-sendrast-evil`, non-https all exit 1). Reads the same file, never argv/env/URL. (d) PASS — exactly 4 files changed (externalsecrets.yaml, kustomization.yaml, new sendrast-tools.yaml, statefulset.yaml), all under `core/manifests/apps/sbx-sendrast`; no path under `/home/jesus` is written or added; both new mounts (`/run/secrets/sendrast/release-robot`, `/opt/sendrast-tools`) are outside the home and read-only, ConfigMap+Secret volume `defaultMode: 288`. (e) PASS — commit 07e41d7 message: last non-empty line is exactly `Lab-Run: IR-20261111-c8grants`. The PR body's Go-live section states the two preconditions verbatim: goes live at the next `sbx-sendrast` restart that homelab-a9 coordinates with Jesús, and ONLY once Aaron has created `sendrast-robot` and `kv/sendrast/sbx/release-robot` exists; nothing is restarted/applied/created by this PR. (f) PASS — `updateStrategy: type: OnDelete` (statefulset.yaml:75-76, unchanged by this diff, present in the render); the diff adds only template fields, so merging cannot restart the running pod. F1 — CI IS RED AT THIS EXACT HEAD (leg fails; blocking for landing, not for the substance above). `GET /commits/07e41d7…/status` → `combined: failure`, 11 statuses, one non-green: `CI Review / record-sql-test (pull_request)` — `Failing after 5m21s`, run 3580 job 7, created 2026-11-11T17:03:24Z (head authored 16:56:33Z, so it is this head). The three Lint & Validate jobs the body cites (run 3581: yaml-lint, shellcheck, terraform-validate) are indeed green, and the body does not claim more than that — but it also does not mention this failure. A diff touching only four sbx-sendrast manifests makes a regression of a record/SQL test implausible; treat it as flake/environmental and prove it: re-run and either get the head green or attach the evidence that it fails identically on `live` (the base sha currently carries no statuses at all, so base-green is not established either). The landing lock needs green at this exact head; I cannot sign the CI leg. F2 — non-blocking, design (record it): the review gate is a client-side control in a file the token holder can bypass. The token is mounted readable to uid 1006 by design, so Jesús can call `POST /repos/…/pulls/{n}/merge` directly with the same token; since Sendrast `main` asks for 0 required approvals (the body says so), the server enforces nothing. G1c therefore protects against accidental use, not against a determined user. If the intent is enforceable review, the control belongs server-side (required approvals / merge whitelist on the Sendrast repos), not in the helper. As specified for this PR it is accepted, but it should not be described as a guarantee. F3 — non-blocking, operational: the gate refuses ANY approval whose `commit_id != head`, and Forgejo keeps reviews per commit. After the first re-push of an already-approved PR, the helper refuses that PR forever (no supersession notion, and a dismissed/stale flag is equally permanent). Intended strictness per the brief, but the operator note should say the escape hatch is a fresh PR, otherwise the sanctioned route dead-ends on round 2. F4 — minor: `sendrast-credential-helper.sh` only applies the repo allowlist when git sends a `path=`; a host-only request returns the credential (verified). Bounded by the robot's two-repo scope, so not exploitable here, but it is weaker than "only the two allowlisted repos" as written. F5 — dependency, outside this diff: the `openbao-sendrast` namespace scoping (`spec.conditions[].namespaces`) lives in Homelab/prod `manifests/lab-director/ld-fleet-cluster-secret-stores.yaml` (body says branch `plane/IR-20261111-c8grants-store`, head f51f9b1…, no PR opened). Until that lands in prod, the store stays cluster-wide-selectable and the "doubly gated / namespace-scoped" story is incomplete. Also track the follow-up removal of `optional: true` once `SecretSynced=True` — with it in place the mount is not enforced. No token, secret value, prefix or fingerprint appears in this comment. Nothing was written under `/home/jesus`; no kubectl write, no restart, no OpenBao write performed by this seat.
C8 G1 r3 (homelab-93 r2 N1/N2): the credential-helper route now works as documented
All checks were successful
CI Review / runner-manifest-test (pull_request) Successful in 5s
CI Review / receiver-test (pull_request) Successful in 6s
CI Review / helm-validate (pull_request) Successful in 15s
Lint & Validate / shellcheck (pull_request) Successful in 7s
CI Review / alert-receiver-test (pull_request) Successful in 21s
Lint & Validate / yaml-lint (pull_request) Successful in 22s
CI Review / record-sql-test (pull_request) Successful in 1m1s
Lint & Validate / terraform-validate (pull_request) Successful in 2m0s
CI Review / cockpit-e2e (pull_request) Successful in 2m43s
CI Review / dispatcher-test (pull_request) Successful in 2m56s
CI Review / cockpit-test (pull_request) Successful in 2m59s
ddb9694eef
The r2 review reproduced, on git 2.39.5, that the push/tag route this PR
ships could not work: the helper is mounted 0440 so `!<file>` gives Permission
denied; once runnable, the pod's own sendrast-bot helper answers first and
ours is never asked; and with credential.useHttpPath unset git sends no `path`,
so the two-repo allowlist never ran and the helper answered for ANY repo on the
host. Each fix, and where it lives:

(a) Doc + invocation use `!sh <file>`, not `!<file>`. The volume keeps
    defaultMode 0440 and nothing in the mount becomes executable; `sh` reads
    the file. Documented in the ConfigMap header (item 5) and in the helper's
    USAGE block.

(b) The documented command resets the helper list FIRST, because `-c` APPENDS
    after the env entries (statefulset.yaml GIT_CONFIG_*) that already answer
    as sendrast-bot:
      git -c credential.helper= \
          -c credential.useHttpPath=true \
          -c credential.helper='!sh /opt/sendrast-tools/sendrast-credential-helper.sh' \
          push origin <ref>

(c) The helper now REFUSES a request that carries no `path` (exit 1, reason on
    stderr) instead of answering it. That is the hard fail the review asked
    for: no path means the repo check cannot run, so there is nothing safe to
    answer. The refusal message names `-c credential.useHttpPath=true`.
    The decision logic moved into a `decide()` function so it can be driven by
    fixtures; `get`/`store`/`erase` behave as before (store/erase are no-ops).

(d) `--self-check` on the credential helper, 14 fixtures, no network and a
    dummy token file in a temp dir. Ten drive decide() directly: the two
    Sendrast repos answer as sendrast-robot; NO path and empty path refuse;
    Homelab/prod, `api-sendrast-evil` and the case variant refuse; http and a
    foreign host refuse; an unreadable token file refuses. Four run the
    DOCUMENTED command line through real `git credential fill` (with
    `env -i`, so the pod's bot helper cannot answer and turn a refusal into a
    pass): both Sendrast repos yield username=sendrast-robot; Homelab/prod
    yields no credential; and WITHOUT useHttpPath it yields no credential,
    which is the case that used to authenticate silently.

(e) The merge helper now also checks the repo the SERVER reports, not just the
    `--repo` string the caller passed: after the PR read, `base.repo.full_name`
    must be in the allowlist (step 1b, new pure `base_repo_verdict()`; a
    missing or non-string full_name fails closed). Three new fixtures cover it
    (allowlisted base, Homelab/prod base, payload without base.repo), so
    --self-check is now 22 checks.

Both self-checks run green against the extracted ConfigMap items: merge 22/22,
credential helper 14/14. No behaviour outside sbx-sendrast changes, nothing is
applied or restarted here, and go-live is still gated on Aaron creating
sendrast-robot plus kv/sendrast/sbx/release-robot (review 93 C1/C3).

Lab-Run: IR-20261111-c8grants
All checks were successful
CI Review / runner-manifest-test (pull_request) Successful in 5s
CI Review / receiver-test (pull_request) Successful in 6s
CI Review / helm-validate (pull_request) Successful in 15s
Required
Details
Lint & Validate / shellcheck (pull_request) Successful in 7s
Required
Details
CI Review / alert-receiver-test (pull_request) Successful in 21s
Lint & Validate / yaml-lint (pull_request) Successful in 22s
Required
Details
CI Review / record-sql-test (pull_request) Successful in 1m1s
Lint & Validate / terraform-validate (pull_request) Successful in 2m0s
Required
Details
CI Review / cockpit-e2e (pull_request) Successful in 2m43s
CI Review / dispatcher-test (pull_request) Successful in 2m56s
CI Review / cockpit-test (pull_request) Successful in 2m59s
This pull request can be merged automatically.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin plane/IR-20261111-c8grants:plane/IR-20261111-c8grants
git switch plane/IR-20261111-c8grants
Sign in to join this conversation.
No reviewers
No labels
operator-review
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Homelab/infra-core!940
No description provided.