mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-24 00:51:19 +00:00
Invert the docs convention so the Mintlify-published site lives under docs/public/ and internal artifacts (strategy docs, brainstorms, plans, etc.) sit at docs/ root or docs/internal/. Tools that default to writing into docs/ now land in the catch-all instead of leaking into the published tree. - Move Mintlify content (administration/, agents/, api-reference/, changelog/, core-concepts/, examples/, execution/, getting-started/, human-tools/, integrations/, languages/, reference/, tutorials/, workflows/, images/, logo/, docs.json, favicon.svg, dot-highlight.js) into docs/public/. - Collapse docs-internal/ into docs/internal/. - Update Rust path references (fabro-api/build.rs, fabro-server, fabro-dev), TypeScript generator arg, CI path filters, clippy.toml reasons, AGENTS.md/CLAUDE.md, and README.md image refs. Mintlify dashboard project root must be updated to docs/public/ in a follow-up. .mintignore move/trim and .claude/skills/ updates land in a separate commit.
69 lines
3.4 KiB
Markdown
69 lines
3.4 KiB
Markdown
# Server Secrets Strategy
|
|
|
|
This document defines how Fabro handles server-level secrets.
|
|
|
|
## Core Rules
|
|
|
|
- `ServerSecrets` is the canonical server-secret reader.
|
|
- It reads from `process env` and `<storage>/server.env`.
|
|
- Resolution is snapshot-based: env and file are read once at construction, then treated as immutable for the life of the process.
|
|
- `process env` wins over `server.env` on conflicts.
|
|
- `fabro server start` never generates secrets. Missing required secrets are a startup error.
|
|
- `std::env::set_var` and `std::env::remove_var` are banned workspace-wide. Tests are not exempt. Enforced by clippy via `disallowed_methods` in `clippy.toml`; intentional exceptions must be annotated with a scoped `#[expect(clippy::disallowed_methods, reason = "...")]` at the call site.
|
|
|
|
## Active Server Secrets
|
|
|
|
These values belong to the server runtime and are read via `state.server_secret(...)`:
|
|
|
|
| Secret | Used by |
|
|
|---|---|
|
|
| `SESSION_SECRET` | Cookie encryption and JWT signing derivation |
|
|
| `FABRO_DEV_TOKEN` | Dev-token user auth when `server.auth.methods` includes `dev-token` |
|
|
| `GITHUB_APP_PRIVATE_KEY` | GitHub App credentials |
|
|
| `GITHUB_APP_WEBHOOK_SECRET` | GitHub webhook verification |
|
|
| `GITHUB_APP_CLIENT_SECRET` | GitHub OAuth login |
|
|
|
|
`FABRO_JWT_PRIVATE_KEY` and `FABRO_JWT_PUBLIC_KEY` are removed. `SESSION_SECRET` is the single auth root.
|
|
|
|
## Startup
|
|
|
|
- Foreground and daemon startup use the same validation path.
|
|
- Required-at-startup secrets are:
|
|
- `SESSION_SECRET`
|
|
- `FABRO_DEV_TOKEN` when dev-token auth is enabled
|
|
- `GITHUB_APP_CLIENT_SECRET` when GitHub auth is enabled
|
|
- Other server secrets remain lazy/feature-specific rather than universal boot blockers.
|
|
|
|
## Provisioning
|
|
|
|
Server secrets come from one of two sources:
|
|
|
|
- Platform env for 12-factor deployments
|
|
- `server.env` written by install flows
|
|
|
|
There is no compatibility layer for removed secrets and no startup-time secret generation.
|
|
|
|
## Subprocess Boundaries
|
|
|
|
- Worker and render-graph subprocesses start from `env_clear()` and re-add only explicit allowlisted variables.
|
|
- Authority-bearing values are re-injected intentionally. For worker subprocesses this is `FABRO_WORKER_TOKEN`, not user auth state such as `FABRO_DEV_TOKEN` or `auth.json`.
|
|
- The worker reads `FABRO_WORKER_TOKEN` from its env at startup (in `main()` before Tokio initializes) and immediately calls `std::env::remove_var` to scrub it. The token then flows through function arguments to `runner::execute`. Every descendant process (hooks, sandbox commands, devcontainer setup, MCP stdio, etc.) therefore inherits a worker env that no longer contains the bearer, so an unscrubbed spawn site cannot leak it.
|
|
- The daemon child inherits the parent env unchanged except for output-format hygiene (`FABRO_JSON` removal).
|
|
|
|
## Tests
|
|
|
|
- In-process tests must inject server secrets with construction-time stubs (`EnvSource`, `StubEnv`) or by writing `server.env`.
|
|
- Subprocess tests must set child env with `Command::env`.
|
|
- Tests must not mutate the process-wide environment.
|
|
|
|
## Rotation
|
|
|
|
- Secret rotation requires restart.
|
|
- Live rotation is intentionally unsupported.
|
|
|
|
## Adding A New Server Secret
|
|
|
|
1. Provision it through platform env or install-written `server.env`.
|
|
2. Read it through `state.server_secret(...)`.
|
|
3. Decide explicitly whether startup should fail when it is absent.
|
|
4. If a worker or render subprocess needs it, re-inject it explicitly rather than broadening inheritance casually.
|