Skip to content

No agent seat can read the deployed auth secret, so an auth-gated render proof always costs a founder #9339

Description

@usirin

The decision

An agent seat carries no ALCHEMY_PASSWORD, and that password guards the only readable copy of the
repo-wide BETTER_AUTH_SECRET. So a seat can seed session rows but cannot sign them with the key
the deployed preview worker verifies against. Every review-ui shot of an :auth or
:auth-caylak surface therefore ends on a person.

Two named routes, and someone has to pick one:

  1. Sanction a supply route — a seat is handed the exported secret for the life of one render
    (a scoped export, a short-lived file, a wrapper that reads ci-credentials state and never writes
    it to disk).
  2. Rule the proof founder-only — a live auth-gated render is declared human work, and the
    criterion class is named as such where such criteria are written, so a lane stops minting a row
    no agent can ever close.

Either answer is a founder ruling, not a build. This is ready-for:human for that reason.

What is true at origin/main

Read at main, not in a lane's snapshot:

  • infra/ci-credentials/github.ts mints one repo-wide BETTER_AUTH_SECRET into the ci-credentials
    stack's alchemy state and pushes it to GitHub as a write-only Actions secret.
  • apps/web/worker/config.ts binds it as secret_text, which does not read back.
  • packages/fabrika-cli/src/capture/auth.ts (classifyAuthSecret, signSessionToken) signs the
    better-auth session cookie with whatever the caller names, and refuses an empty or insecure_
    placeholder value. Its docblock states plainly that the one readable copy sits behind
    $ALCHEMY_PASSWORD.
  • packages/fabrika-cli/src/review-ui/render-verb.ts takes --auth-secret-from <file> and, on a
    visitor answer, tells the caller to re-export from that same state behind $ALCHEMY_PASSWORD.

So the guard from the earlier lane landed and works. It makes a wrong key loud instead of silent.
It does not make the right key reachable, which is what this issue is about. Nothing on main opens
a route from a seat to that value.

Frequency

Four lanes so far: #9276, #9279, the fourth criterion of #9288, and #9423 / #8776. In the #9423
case the operator had already hand-seeded both tiers against that PR's own preview D1 and all six
shots still refused on 11 as a visitor — the seat's secret simply was not the deployed one.

Triage note — why this is standalone

#9288 owns the seeded-session bug and is a buildable type:bug. The question here is a credential
policy call with two named alternatives, and folding it into a buildable ticket is what left it
unreachable through four review rounds. #9337 (the five-surface duplication of this fact) and #9338
(the untested refusal route-out) are adjacent, but neither absorbs the ruling.

Acceptance criteria

  • One of the two routes above is recorded as a founder ruling on this issue
  • If route 1: the sanctioned supply route is written down where a lane can follow it, and a seat can produce a non-placeholder BETTER_AUTH_SECRET that the deployed preview worker verifies [evidence: a live review-ui render of an :auth surface returning a signed-in capture rather than exit 11]
  • If route 2: the founder-only criterion class is named in the review-ui skill and in the intake guidance that mints such criteria, so triage stops writing a row no agent can close
  • The ruling is cited from the artifact it lands in, an ADR or a skill amendment

Triage note: the criteria cover both shapes the ruling can take. Only the branch the founder picks
is graded.


Original report (verbatim)

Summary

An agent seat in this repo carries no ALCHEMY_PASSWORD, and that password is the only key to the
one readable copy of the deployed BETTER_AUTH_SECRET. So any acceptance criterion that asks for a
live signed-in render against a preview cannot be discharged by an agent, however the pipeline is
driven. It always stops on a person holding that credential.

What I was doing

Driving lane 9288 (PR #9328), which adds review-ui render --auth-secret-from <file> and a refusal
for an insecure_ placeholder or empty signing secret. The issue's fourth acceptance criterion asks
for a live proof: after preview-seed test-account, a :auth surface on PR #9276 or #9279 captures
the signed-in page instead of exit 11.

What I observed

The driver seat and every builder and reviewer seat spawned for the lane reported no
ALCHEMY_PASSWORD in the environment. The value the criterion needs is minted by
infra/ci-credentials/github.ts into the ci-credentials stack's alchemy state and pushed to GitHub
as a write-only Actions secret; the deployed Cloudflare secret_text binding does not read back.
Both readable routes are therefore closed to an agent. The PR landed the guard and stated the
criterion open, shipping as Part of #9288 rather than Fixes, because no seat in the lane could
take the proof. Four review rounds ran with that row unreachable on every one of them.

Why it matters

Every auth-gated review-ui review parks the same way, and the new guard does not change that — it
makes a wrong secret loud instead of silent, which is progress, but a correct secret still cannot
reach a seat. Lanes whose rendered change sits behind sign-in will keep ending on a founder read,
and a criterion no agent can meet leaves its issue open after the work that could be done is done.
There may be a good reason to keep this credential off agent seats; if so the criterion class wants
naming as founder-only so a lane stops carrying an unreachable row to its terminal.

Pointers

Suggested next step (non-binding)

Either sanction a supply route that hands a seat the exported secret for the duration of a render,
or rule that a live auth-gated render proof is founder-only work and say so where such criteria are
written, so a lane does not carry a row it can never close.


Filed by an agent · session 94113692-2733-4534-9963-c7ae534247d0 · 2026-09-16T21:13:34Z

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    p1Medium priorityready-for:agentAn execution engine may pick this up.status:triagedTriage signed off; ready for write-code to picktype:decisionOne question; output is a recorded choice

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions