Files
browser/openspec/changes/secure-single-file-run-distribution/design.md
T
npc0-hue 292b380f3c feat: ship single-file run distribution and list key reset
Compile-time run auth replaces zip sidecars, lengthens run keys, revokes
active sessions on reset, and exposes run-key reset in the server list.
2026-07-24 14:14:26 +08:00

4.4 KiB

Context

The existing distribution pipeline already queues real distribution.build jobs and keeps raw component keys out of platform APIs. The weak point is the generated package shape: Run artifacts still contain config.json, which makes accidental token disclosure easy when a ZIP is shared or inspected. The operator expectation is also a single run.exe on Windows, not an archive.

Goals / Non-Goals

Goals:

  • Produce Windows Run downloads as run-windows-amd64.exe and Linux Run downloads as raw executable files such as run-linux-amd64.
  • Compile server identity and the current Run key into the Run binary using Go native -ldflags -X.
  • Keep RUN_PLATFORM_URL and other explicit environment overrides working for local development and diagnostics.
  • Support raw-executable Run self-update artifacts with checksum verification and the existing staging/rollback flow.
  • Make run-key reset reachable from the server list while preserving the compact action popover.
  • Immediately revoke an online Run control session after its key is reset.

Non-Goals:

  • Do not add device authorization, enrollment binding, or a token exchange ceremony.
  • Do not claim compile-time embedded tokens are unrecoverable from the executable; possession of the executable remains a trust boundary.
  • Do not change Client Manager packaging or plugin-declared client-manager build semantics.
  • Do not modify billing, cloud host sales, AI provider, plugin marketplace, or unrelated server workflows.

Decisions

Decision 1: Compile-time Run identity is a build-input contract

Platform extends authenticated distribution build input with the public Run platform URL and the existing identity fields. The trusted Run worker passes those values to go build -ldflags -X browser.local/run/config.<Var>=<value>. Run config loading prefers explicit environment variables, then compile-time build values, then developer defaults.

This uses the Go-native mechanism the user requested. It avoids go:embed, generated source files, temporary code rewrites, or sidecar config files for Run. The compile-time value is still recoverable by someone holding the binary, but it removes the casual ZIP/config leak.

Decision 2: Raw executable is a Run-only package format

Run distributions use a new raw-executable package format. The worker uploads the compiled binary bytes directly and does not call the archive writer for Run. Client-manager distributions keep the existing ZIP/tar.gz packaging and config injection because they are plugin-declared companion builds with their own lifecycle.

Decision 3: Self-update treats raw executable as first-class

Run update input may carry raw-executable. The self-update executor still downloads through the artifact channel, verifies the full artifact checksum, writes the staged executable under the transaction workspace, records its binary checksum, and uses the existing activation and rollback logic.

Decision 4: Run keys get a dedicated generator

The existing randomToken() remains 32 random bytes because it is also used for auth sessions, user ID suffixes, and job leases. Run component keys use a new 64-byte URL-safe generator, increasing key length only for Run authorization.

Decision 5: Reset revokes the active Run session

The reset service already revokes old distribution artifacts and increments key generation. This change also removes the active Run control session for that server endpoint when the Run component key is reset, forcing a freshly compiled binary to authenticate before more control/job traffic is accepted.

Risks / Trade-offs

  • Embedded authorization can be extracted from a binary by a determined operator or attacker with file access. This is acceptable for the requested distribution model and is explicitly not a DRM or device-binding system.
  • Compile-time values can be visible to privileged users on the build worker. The build worker remains part of the trusted platform boundary.
  • Raw executables lose the convenience of multi-file package payloads, so any future service installer/systemd wrapper should be a separate explicit distribution profile rather than hidden in this change.

Verification

  • openspec validate secure-single-file-run-distribution --strict
  • cd run && go test ./...
  • cd platform && go test ./...
  • cd platform_web && npm test
  • cd platform_web && npm run typecheck
  • scripts/check-structure.sh