Skip to content

feat(dev): enforce module auth in --tunnel mode by injecting MS_INTERNAL_SECRET#33

Merged
I-am-nothing merged 1 commit into
mainfrom
feat/tunnel-internal-secret
May 25, 2026
Merged

feat(dev): enforce module auth in --tunnel mode by injecting MS_INTERNAL_SECRET#33
I-am-nothing merged 1 commit into
mainfrom
feat/tunnel-internal-secret

Conversation

@I-am-nothing

Copy link
Copy Markdown
Contributor

Summary

Closes the security gap where `mirrorstack dev --tunnel` exposes the module's `localhost:8080` to remote callers (via dispatch's Leaf-1 307) without ever setting `MS_INTERNAL_SECRET` — so the SDK's InternalAuth middleware takes the local-dev bypass branch and any caller can hit `/__mirrorstack/*` unauthenticated.

This PR is the first slice of the wider tunnel-auth workstream (see memory/feedback_tunnel_auth_no_bypass.md). Architecture rule: tunnel mode never bypasses auth; the CLI auto-injects secrets; dispatch signs forwarded requests.

What changes

  • On `--tunnel`, mint a 32-byte URL-safe-b64 random secret (OsRng).
  • Set `MS_INTERNAL_SECRET=` on the `go run .` child process. The SDK's bypass-vs-enforce matrix flips to enforce as soon as the env is set.
  • Send the same secret to dispatch in the WSS `register` frame as a new optional `internal_secret` field. `skip_serializing_if = Option::is_none` so older dispatch builds keep round-tripping the frame intact.

Diff: +90 / -21 across 3 files in `src/commands/dev/`. No behavior change when `--tunnel` is unset.

Cascade (separate PRs, separate repos)

This PR alone will break the existing dev-mount manifest fetch because dispatch doesn't yet read or forward the new field, so the platform's HTTP call to `/__mirrorstack/platform/manifest` will start 401ing the moment a dev runs the new CLI. Coordinated follow-ups:

  1. api-platform/dispatch — parse `internal_secret` on register, persist in `ws.Session`, attach `X-MS-Internal-Secret` to forwarded requests.
  2. api-platform manifest fetcher — consume the secret from the session record.
  3. app-module-sdk — PlatformAuth identity injection from signed headers so `/platform/*` reaches end-to-end.

Test plan

  • `cargo build` clean
  • `cargo clippy --all-targets -- -D warnings` clean
  • `cargo test` — 61 tests pass
  • New tests cover the serialization shape (`internal_secret` absent when `None`; `internal_secret` emitted when `Some`)
  • Smoke test once dispatch lands the matching parse: `mirrorstack dev --tunnel` from a module, observe `MS_INTERNAL_SECRET` no longer logged as unset, `/__mirrorstack/manifest` over tunnel succeeds with header

🤖 Generated with Claude Code

…NAL_SECRET

`mirrorstack dev --tunnel` exposes the module's localhost:8080 to remote
callers via dispatch's Leaf-1 307 redirect. Today the spawned module
process has no MS_INTERNAL_SECRET, so the SDK's InternalAuth middleware
takes the local-dev bypass branch — and any remote caller can hit
/__mirrorstack/* without auth. The whole point of tunnel mode is to be
production-shaped for dev-test, so the bypass is wrong here.

What this PR does:
- On --tunnel, mint a 32-byte URL-safe-b64 secret (OsRng).
- Set MS_INTERNAL_SECRET=<secret> on the `go run .` child process, which
  flips the bypass-vs-enforce matrix in
  app-module-sdk/auth/middleware.go to "enforce".
- Send the same secret to dispatch in the WSS register frame as a new
  `internal_secret` field (skip_serializing_if = Option::is_none, so
  older dispatch builds keep round-tripping the frame intact).

Follow-ups (separate PRs, separate repos):
- api-platform/dispatch: parse `internal_secret` on register, persist
  in the ws.Session record, and attach `X-MS-Internal-Secret: <secret>`
  to every forwarded request — including the manifest fetcher (which
  will start 401ing the moment this CLI lands without the dispatch fix).
- app-module-sdk: add PlatformAuth identity injection from signed
  headers so /platform/* can be reached end-to-end.

See memory/feedback_tunnel_auth_no_bypass.md for the architecture rule
("tunnel mode never bypasses; CLI auto-injects; dispatch signs").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@I-am-nothing I-am-nothing force-pushed the feat/tunnel-internal-secret branch from a89a37c to 479f32b Compare May 25, 2026 15:37
@I-am-nothing I-am-nothing merged commit 3bcfd66 into main May 25, 2026
5 checks passed
Sign up for free to 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