feat: add isolated release gates and CI checks
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# Release and rollout safety (T01)
|
||||
|
||||
This repository uses Gitea Actions for CI. The workflow in `.gitea/workflows/ci.yml`
|
||||
only installs the frozen lockfile, runs local tests/check/build, compiles the
|
||||
checked-in synthetic reference fixture, and runs an isolated demo web smoke.
|
||||
It does not receive deployment credentials, trigger a remote deployment, or
|
||||
write a persistent Convex backend.
|
||||
|
||||
## Server-side rollout gate
|
||||
|
||||
`APP_CAPABILITY_ALLOWLIST` is a comma-separated deployment setting parsed by
|
||||
`src/lib/server/release-gate.ts`. An omitted setting preserves the existing
|
||||
private asset/sign-in baseline (`asset_search`, `asset_valuation`,
|
||||
`asset_sync`, `assistant_dispatch`, and `session_token`). An explicitly empty
|
||||
setting disables all capabilities. Unknown names fail configuration rather
|
||||
than becoming an accidental opt-in; known capabilities that are not in the
|
||||
baseline (for example `wallet_balance`, `inventory_export`, and
|
||||
`subscriptions`) are default-deny.
|
||||
|
||||
The web server checks the allowlist at the relevant boundary:
|
||||
|
||||
- `/api/chat` checks `assistant_dispatch` before invoking manual or external
|
||||
intent routing.
|
||||
- `/assets` and assistant execution check the selected asset capability.
|
||||
- `/api/sync` and the application synchronizer check `asset_sync`.
|
||||
- `/api/session/token` checks `session_token`.
|
||||
|
||||
This is an admission control mechanism, not a UI feature flag. Disabled
|
||||
operations return an explicit unavailable/503 response and do not invoke a
|
||||
provider. No subscription or durable user-job service exists in this baseline;
|
||||
their capability names remain closed until those services have a reviewed
|
||||
entry point.
|
||||
|
||||
## Immutable release metadata
|
||||
|
||||
`APP_RELEASE_ID` is carried into the runtime image and returned as the
|
||||
non-secret `x-application-release` response header. Local/fixture runs use
|
||||
`local` or `fixture`. Staging and production must provide a non-placeholder
|
||||
identifier (normally the source commit or an operator-approved image digest).
|
||||
`bun run release:check` rejects placeholder staging/production identifiers,
|
||||
unpinned staging/production dashboard images, demo mode in staging/production,
|
||||
invalid capability names, and tracked secret-like files. The Dockerfile accepts
|
||||
`--build-arg APP_RELEASE_ID=...`; Compose passes the runtime value explicitly.
|
||||
|
||||
## Isolated local validation
|
||||
|
||||
Use a separate worktree-local output directory and a unique Compose project
|
||||
name for backend experiments. Never point these commands at a persistent
|
||||
backend or copy a live `.env`/volume:
|
||||
|
||||
```sh
|
||||
APP_MODE=demo APP_RELEASE_ID=fixture bun run build
|
||||
APP_MODE=demo APP_RELEASE_ID=fixture bun run release:check
|
||||
APP_MODE=demo APP_RELEASE_ID=fixture bun run test:fixture
|
||||
```
|
||||
|
||||
`test:fixture` compiles the checked-in reference sources into a temporary
|
||||
folder, starts the built server on loopback with synthetic data, checks the
|
||||
release header and matching `/assets`/chat totals, then kills the server and
|
||||
removes the temporary artifact directory.
|
||||
|
||||
For an isolated Compose rehearsal, set `COMPOSE_PROJECT_NAME` to a unique
|
||||
throwaway value, keep all binds on loopback, use a fixture/demo environment,
|
||||
and remove the project only after recording the result. The release gate does
|
||||
not itself perform migrations, backups, restores, or cleanup of an operator's
|
||||
persistent deployment.
|
||||
|
||||
## Evidence boundaries
|
||||
|
||||
Read-only `tea` inspection on 2026-09-19 reported no Gitea workflows or runs
|
||||
for `jb/eden`; runner labels and action availability are therefore not
|
||||
validated. The workflow is prepared locally but has not run remotely.
|
||||
No browser automation, OAuth callback failure injection, Convex migration
|
||||
rollback, instance-credential backup/restore, key rotation, or live
|
||||
revocation/transfer evidence is claimed by this lane. Those remain explicit
|
||||
operator/integration gates and must use synthetic or separately consented
|
||||
isolated environments.
|
||||
Reference in New Issue
Block a user