Skip to content

secrets:read caller scopes + rt-client packaging honesty - #8

Merged
m4ttheweric merged 4 commits into
mainfrom
deck-secrets-whitelist
Aug 21, 2026
Merged

secrets:read caller scopes + rt-client packaging honesty#8
m4ttheweric merged 4 commits into
mainfrom
deck-secrets-whitelist

Conversation

@m4ttheweric

@m4tthewericm4ttheweric commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

The deck lane's rt half: secrets:read gains a caller-scope whitelist (extension default = the two existing keys; deck = the CF pair from the encrypted deck domain; structural per-scope isolation, token gate first on both transports, bad-scope refusal). rt-client: prepack build, an honest full-tree dist-freshness diff test, and the transport default-sock path moves to call-time resolution (the RED test reached the real socket, proving the hazard).

Gates: lib 1388/0, commands 70/0, packages 154/0, tsc 0.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added support for reading approved Cloudflare deck credentials through the secrets command.
    • Added optional secret scopes for extension and deck credentials, with scope-specific access controls and token protection.
    • Default socket resolution now respects the current home directory at command time.
  • Bug Fixes

    • Package builds now run automatically before publishing.
    • Added checks to detect stale or missing compiled package artifacts.

m4tthewericand others added 4 commits August 21, 2026 09:08
…+ rt-client dist guard
secrets:read now takes payload.scope ("extension" default | "deck"), each
reading its own encrypted domain behind the same token gate — lets deck
fetch its CF credentials without widening the extension's existing
whitelist. Also fixes the rt-client packaging stall: prepack builds dist/
for npm pack/publish, and a new test rebuilds dist/ and checks it before
file: consumers (mr-board, gitq) can silently pick up a stale one.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…op task refs
dist-freshness test now builds into a temp dir and diffs against the
on-disk dist/ instead of rebuilding it in place, so a stale dist/ actually
fails the test; also checks a fresh build's commands.d.ts carries
cfApiToken (catalog drift). secrets:read's data type is now a union of
the two exact per-scope shapes instead of a merged bag of all four keys,
so a caller narrowing the wrong scope's fields is a compile error. Drops
lane/task references from source comments (invariant prose kept), fixes
the deck-seams-singleton comment's rationale (module privacy, not domain
binding), and adds coverage for a case-variant scope, a non-string scope,
and a deck-reader throw surfacing as a transport error instead of a
partial ok.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches settings/paths.ts's call-time HOME convention: rtCommand now
derives its default sock path fresh on every call instead of reading a
module-load `homedir()` snapshot, so a test repointing process.env.HOME
after this module has already loaded no longer silently falls through to
the real ~/.mattstack/rt/rt.sock. Confirmed no consumer (checked mr-board
and gitq on disk) imports the exported DEFAULT_SOCK constant directly, so
it stays as a display-only snapshot while rtCommand itself no longer
reads it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… files
Re-docced: dist/ is gitignored (never "committed"), and prepack only
rebuilds it for npm publish -- it does nothing for the file:-consumer
dev-linking path this test actually protects. Widened the comparison to
every emitted file (recursive listing + byte compare), so a stale
dist/index.js -- the original failure class -- now fails the test instead
of shipping silently; a missing dist/ (a fresh clone's starting state)
gets its own message naming `bun run build` as the fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m4ttheweric
m4ttheweric merged commit ba436f0 into mainAug 21, 2026
@coderabbitai

coderabbitaiBot commented Aug 21, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64cebf32-8ef2-45c0-b107-cbbf05c709ed

📥 Commits

Reviewing files that changed from the base of the PR and between 71474d6 and 8ff86c7.

📒 Files selected for processing (8)
  • extensions/vscode/rt-context/src/secretsMapping.ts
  • lib/daemon/__tests__/secrets-handler.test.ts
  • lib/daemon/handlers/secrets.ts
  • packages/rt-client/package.json
  • packages/rt-client/src/commands.ts
  • packages/rt-client/src/transport.ts
  • packages/rt-client/test/dist-freshness.test.ts
  • packages/rt-client/test/transport.test.ts

📝 Walkthrough

Walkthrough

The daemon now supports token-gated extension and deck secret scopes. The client contract exposes both response shapes. The client resolves default sockets at invocation time and validates fresh distribution output.

Changes

Scoped secrets reads

Layer / File(s)Summary
Daemon scoped secret handling
lib/daemon/handlers/secrets.ts, lib/daemon/__tests__/secrets-handler.test.ts, extensions/vscode/rt-context/src/secretsMapping.ts
The daemon adds deck secret loading, scope validation, per-scope whitelists, token checks, and failure coverage.
Client secrets command contract
packages/rt-client/src/commands.ts
secrets:read accepts optional extension or deck scopes and returns the matching secret shape.

rt-client runtime and distribution

Layer / File(s)Summary
Dynamic default socket resolution
packages/rt-client/src/transport.ts, packages/rt-client/test/transport.test.ts
rtCommand resolves the default socket from the current HOME value on each call.
Distribution build and freshness validation
packages/rt-client/package.json, packages/rt-client/test/dist-freshness.test.ts
The package builds before packing, and tests compare committed dist/ files with fresh JavaScript and declaration output.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
participant Client
participant Daemon
participant SecretLoader
Client->>Daemon: secrets:read(scope, token)
Daemon->>Daemon: validate scope and token
Daemon->>SecretLoader: load selected secret domain
SecretLoader-->>Daemon: scoped secret values
Daemon-->>Client: whitelisted response
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deck-secrets-whitelist

Comment @coderabbitai help to get the list of available commands.

m4ttheweric added a commit that referenced this pull request Aug 22, 2026
…DME drift, escaping, log collision)
#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.
#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).
#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.
#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.
#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.
Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 22, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.
R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.
R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.
R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.
#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".
#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).
#7: the five optional rows carry real optionalNotes.
#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.
#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.
#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.
#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".
#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.
#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@m4ttheweric
m4ttheweric deleted the deck-secrets-whitelist branch August 24, 2026 17:49
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
secrets:read caller scopes + rt-client packaging honesty
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
…DME drift, escaping, log collision)
#1: walkthrough.sh's cleanup() defaulted a missing phases.jsonl to success
via ${f:-0}, so dying before the first vm_phase_end (e.g. no tart on a
fresh machine) exited 0 with an empty report. Dropped the default so a
missing ledger fails the `[ -eq 0 ]` test and falls through to exit 1,
matching xcuitest.sh's existing fail-closed form. Pre-existing on main;
reproduced the before/after with the review's no-tart repro.
#2/#9: README described ax.sh/drive-setup.sh/trigger-update.sh as not yet
in the tree and misattributed the screens-phase failure to an unstaged
guest script; all three are staged into $GUEST_BIN by walkthrough.sh today.
Corrected the Status/Layout prose to state what's actually gating
`--scenario create/join` (L3's setup screens) and the update phase (L3's
MATTSTACK_APPCAST_URL hook). Also corrected the disk-footprint line: the
~60 GB figure is cleanroom-only, and an --xcode golden needs substantially
more (full Xcode install on top of the base OS).
#3: check-vm-scripts.sh's ax.sh syntax-error net only matched "script
error"/"Expected " literally, missing other osascript compile-failure
shapes (e.g. "syntax error: A property can't go after..."). Widened to a
bare "syntax error" alternative, which osascript writes for every compile
failure and never for a runtime error.
#4: ax_click_button_named defaulted its process arg to the already-escaped
$AX_APP, then ran ax_esc on it again, double-escaping any AX_APP containing
a quote or backslash. Now only escapes when an explicit (raw) $2 is given.
#6: build-golden.sh's tart boot log was named golden-$VER-tart.log for both
flavours, so an --xcode build silently overwrote the cleanroom golden's
boot log. Named it after $GOLDEN instead, which already carries the -xcode
suffix.
Findings #5 (VM_APPCAST_PORT default duplication), #7 (--ver not
version-validated), #8 (xcuitest.sh's guest-staging convention), and #10
(PAT/password on guest ssh argv) are parked per the reviewer's ruling —
not touched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
m4ttheweric added a commit that referenced this pull request Aug 24, 2026
R-T7-a (#1): tool.daemon's launchd/worktrees sub-facts are real negative
signals now, not folded into a "ready" detail — either failing flips the
row to "invalid" with the specific fact named.
R-T7-b (#4): the legacy split-state branch (required, invalid) carries a
{type:"steps"} merge-by-hand remedy instead of action:null; the detail also
gets verify's plural handling back.
R-T7-c (#6): fixes the bundle-memo hazard at its source. appBundleRoot()
(lib/bundle-layout.ts) now memoizes only the true default
(exists === existsSync); an injected exists (every Probes-driven caller)
never reads or writes it. Validator tests drop the reset ceremony this made
unnecessary.
R-T7-d (#12): tool.rt-link's needs-you branch carries a {type:"run"} action
to fix the link in one step.
#2/#3: tool.fzf and tool.rt now distinguish "genuinely absent" (127) from
"resolved but won't run" (any other exit) — the latter is "error", never
"ready"/"missing".
#5: tool.daemon and tool.app get recheck:"on-activate" (Task 6's convention
for out-of-band, leave-the-app-and-come-back rows).
#7: the five optional rows carry real optionalNotes.
#8: tool.app's legacy note names the exact hit path(s), matching verify's
phrasing.
#9: interceptsRow wraps shimReport()/staleIntercepts() so a throw degrades
to an "error" row instead of rejecting the whole plan.
#10: tool.daemon's Login Items action is imported from permissions.ts
(now exported as LOGIN_ITEMS_SETTINGS_ACTION) instead of a duplicate
literal.
#11: lib/shell-integration.ts gains detectShellFrom()/shellRcPathFor(),
pure functions the real detectShell()/shellRcPath() now delegate to and
tool.shell reuses over Probes; an unrecognized shell gets an honest
"can't write automatically" detail instead of "Install writes it".
#13: the tool.daemon describe saves/restores DAEMON_CONFIG_PATH's
pre-existing content around the whole block instead of only deleting it,
so status-fallback.test.ts's absence assumption can't be poisoned.
#14/#15: header comment no longer cites the brief's table, the rt-link
"no app" test asserts its reason string, and commands/verify.ts's docblock
is trimmed to the one load-bearing line.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@m4ttheweric