mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-07 16:11:46 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server signs decision specifications with an HMAC > - PR #10010 made `PAPERCLIP_DECISION_SIGNING_SECRET` a hard startup requirement > - Existing installs do not have this new environment variable > - Those installs now stop during startup > - This pull request uses a secure persisted instance key when the override is absent > - The benefit is that existing installs start without new configuration and decision signing remains fail-closed ## Linked Issues or Issue Description **What happened?** After #10010, `startServer()` throws when `PAPERCLIP_DECISION_SIGNING_SECRET` is unset or shorter than 32 characters. Existing installs without the new environment variable stop at startup. **Expected behavior** The server starts without manual configuration. A new optional feature must not add a required environment variable for existing installs. **Steps to reproduce** 1. Check out `master` at9c1f8e7887. 2. Unset `PAPERCLIP_DECISION_SIGNING_SECRET`. 3. Start the server. 4. Observe that startup stops with a missing-secret error. **Paperclip version or commit** `master` at9c1f8e7887. **Deployment mode** All deployment modes are affected when the environment variable is absent. ## What Changed - Treat `PAPERCLIP_DECISION_SIGNING_SECRET` as an optional override. - Generate a random per-instance key at `<instance>/secrets/decision-signing.key` when the override is absent. - Publish a complete first-time key with an atomic no-overwrite link so concurrent server starts use one key. - Repair permissive modes on process-owned secrets directories and regular key files, reject planted symlinks or foreign-owned paths, and fail startup if `0700`/`0600` cannot be enforced. - Keep an explicitly configured secret shorter than 32 characters as a startup error. - Add startup, permission, planted-symlink, fail-closed verification, and generated-key round-trip tests. ## Verification - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/decisions-service.test.ts src/__tests__/server-startup-feedback-export.test.ts` — 45 tests passed. - `pnpm --filter @paperclipai/server exec tsc --noEmit` — passed. - Eight simultaneous resolver processes returned the same persisted key. The secrets directory/key modes were `0700`/`0600`. - `git diff --check` — passed. ## Risks - Existing configured secrets remain unchanged. - Removing a configured secret after a proposal makes the prior signature fail verification. Restoring the secret restores verification. - A restored secrets directory or key with unsafe permissions now fails startup when the server cannot repair it to `0700`/`0600`; symlinks and paths owned by another local user are rejected rather than trusted. - The generated key uses an atomic hard link in the instance secrets directory. An unsupported file system fails startup instead of replacing an existing key. - Existing installs that failed at startup did not sign decisions with a missing key. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Fable 5, model ID `claude-fable-5`, produced the initial implementation with extended reasoning and tool use. - OpenAI Codex, model ID `gpt-5`, addressed review findings and prepared the PR with reasoning, repository editing, code execution, and GitHub tooling. The runtime did not expose the context-window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>