Harden Backend Security and Persistence

OpenCode·deepseek-v4.1-flash·kernelKain·23h ago·38min·1 Checkpoint·49 file changes·+5057/-495·523.3K tokens

Phase 8 prompt — Harden backend, security, persistence, and operations

Implement only Phase 8 of the Unfinished Business roadmap. Review and harden the completed workflow without adding unrelated features. Use controls proportional to the actual local, hosted-demo, and private-hosted modes.

Prerequisite

Verify the live run lifecycle, OpenCode onboarding, mode separation, and demo boundaries are implemented and documented. If major contracts are still changing, stop and finish those phases first rather than hardening obsolete paths.

Outcome

The application safely validates workspace and OpenCode targets, protects event/mutation routes, redacts secrets, recovers state, bounds resource usage, and explains operational failures without corrupting or duplicating work.

Threat model and inspection

  • Draw/update trust boundaries for browser, application server, local workspace, OpenCode server, provider, persistent state, Render proxy/disk, Sentry, and demo fixtures.
  • Inventory all inputs, filesystem paths, URLs, headers, cookies, secrets, logs, traces, exported data, run events, and external actions.
  • Identify mode-specific threats instead of applying a generic checklist.
  • Inspect dependency/audit results and verify whether reported issues are reachable before changing versions.

Hardening work

Filesystem and workspace

  • Canonicalize workspace roots server-side; reject traversal, symlink escape where relevant, unsafe device/special files, and unintended broad roots.
  • Keep destructive actions behind explicit OpenCode permission and application scope.
  • Add state backups, atomic replacement, schema validation, corruption preservation, and tested recovery.

OpenCode and network

  • Default to loopback. Require HTTPS for non-loopback OpenCode URLs unless an explicitly documented development exception applies.
  • Prevent SSRF with scheme/host/port policy, DNS/IP validation as appropriate, redirect policy, timeouts, response-size limits, and revalidation.
  • Enforce compatible version and authentication state before mutation.
  • Bound retries and never automatically repeat uncertain side effects.

Browser/API/events

  • Protect mutation and SSE routes consistently with session/access controls.
  • Enforce origin/CORS policy and CSRF protection appropriate to the authentication mechanism.
  • Validate request sizes, content types, IDs, expected revisions, and action idempotency.
  • Add per-session/global concurrency and rate limits with understandable responses.
  • Prevent event cursors or exports from leaking another project/run if multi-project support exists.

Secrets, telemetry, and privacy

  • Centralize redaction for credentials, authorization headers, cookies, provider keys, prompts when configured private, tool arguments/results, environment variables, local paths where necessary, and user identity.
  • Test Sentry/log/event/export redaction independently.
  • Define retention and deletion for events, runs, backups, demo state, and telemetry.
  • Keep health endpoints minimal and disable debug details in production.

Budgets and operations

  • Add configurable run time, token/context, cost, tool-call, and concurrency budgets where OpenCode exposes reliable data.
  • Do not claim enforcement for unavailable provider quota facts; use elapsed/tool limits as fallbacks.
  • Improve recovery for OpenCode unavailable, provider limit, permission pending, disk full, corrupted state, event disconnect, test failure, and application restart.
  • Add structured operational logs with correlation IDs that do not contain secrets.

Cleanup

  • Identify duplicated operation helpers, obsolete fixed-model code, unused environment variables, dead styles/components, and redundant dependencies.
  • Remove only items proven unused after tests/reference searches. Preserve .backboard/ and other user-owned artifacts unless explicitly authorized.

Verification

Add security and recovery tests for path traversal/symlink escape, unsafe roots, SSRF/redirect/DNS cases, origin/CORS/CSRF, SSE authorization, cross-run access, request limits, rate/concurrency limits, duplicate actions, secret redaction, corrupt state, disk/write failure, restart, unknown native outcomes, and retention cleanup.

Run typecheck, full tests, production build, dependency audit, fresh setup, and focused manual checks. Do not conduct intrusive external testing or attack third-party services.

Documentation requirements

Update:

  • docs/ARCHITECTURE.md with the final trust-boundary diagram and security ownership;
  • docs/OPERATIONS_AND_RECOVERY.md with backups, migrations, retention, incidents, failure matrix, budgets, restart, and cleanup;
  • docs/OPENCODE_INTEGRATION.md with URL/auth/version/retry policies;
  • docs/LOCAL_SETUP.md and docs/HOSTED_DEPLOYMENT.md with secure defaults and troubleshooting;
  • docs/UX_AND_VISUAL_SYSTEM.md for permission, limit, privacy, and recovery messages;
  • docs/DECISIONS.md, docs/IMPLEMENTATION_PLAN.md, docs/CHANGELOG.md, .env.example, and README.md.

Record residual risks honestly, especially shared-host isolation and remote connector deferral.

Acceptance

  • Workspace and remote URL policies have automated abuse tests.
  • Mutation and event routes share consistent authorization/origin protections.
  • Secrets do not appear in logs, events, telemetry, state exports, or errors under the test matrix.
  • Corrupt/incomplete state is preserved and recoverable rather than silently reset.
  • Duplicate/unknown execution cannot be retried automatically.
  • Budgets and limits are visible and honest about provider-data gaps.
  • Dead code/dependencies are removed only with evidence.
  • Full regression and build pass.

Finish with the required phase handoff and stop. Do not start Phase 9.

23h ago·0.0s

Phase 8 handoff

Status: implemented and verified locally; uncommitted in this detached worktree. No Phase 9 work started.

Prerequisites verified

  • Live run lifecycle: run → unknown/timeout → reconcile/cancel → restart recovery.
  • OpenCode onboarding/readiness: version 2.x, auth, free-model availability, and explicit failure states.
  • Mode separation: local, hosted-demo, private-hosted (UB_MODE).
  • Demo boundaries: Maker and node --test run only in UB_DATA_DIR/demo-workspace; spirit sessions use an empty workspace.

Hardening implemented

  • Filesystem/workspace: canonical roots, broad-root rejection, traversal/symlink/special-file checks, private permissions, contained static serving.
  • Persistence: schema v2 + v1 migration, atomic write/fsync/rename, .previous + rolling backups, lock file, corrupt-file quarantine, disk-full/read-only mapping, startup recovery.
  • OpenCode/network: loopback default, HTTPS + host/port allowlists for remote targets, DNS/IP classification, metadata/private-address blocking, per-request revalidation, redirect refusal, timeout and response-size caps.
  • HTTP/API/events: Host allowlist, Origin/Sec-Fetch-Site checks, constant-time session token, Basic Auth in hosted modes, JSON/content-type checks, request limits, rate/concurrency gates, authenticated/bounded SSE, operation/run scoping.
  • Secrets/privacy: centralized redaction across state, exports, errors, logs, and Sentry; independent redaction tests; metadata-only telemetry; minimal public health endpoint.
  • Budgets/operations: guide/Maker/Node-check timeouts, token/cost budgets, visible limitation for unavailable tool-call data, structured correlation-ID logs.
  • Cleanup: removed unused opencode/operations helper/test and unused helpers/knobs, removed the unused Backboard env placeholder, and confirmed no remaining production references.

Verification

  • npm ci — pass
  • npm run typecheck — pass
  • npm test — 57/57 pass
  • npm run test:security — 36/36 pass
  • npm run build — pass (existing bundle-size warning only)
  • npm audit --omit=dev — 6 moderate findings, all through @sentry/bundler-plugins/glob/minimatch; the vulnerable path is build-time, not the runtime server path. The npm fix is a breaking Sentry downgrade, so it was not applied.
  • Manual checks: local and hosted auth/token flows, Host/Origin rejection, HSTS mode behavior, static traversal 404s, workspace path omission, corrupt-state startup preservation, and browser UI load.

Documentation

Created/updated:

  • docs/ARCHITECTURE.md, docs/OPERATIONS_AND_RECOVERY.md, docs/OPENCODE_INTEGRATION.md
  • docs/LOCAL_SETUP.md, docs/HOSTED_DEPLOYMENT.md, docs/UX_AND_VISUAL_SYSTEM.md
  • docs/DECISIONS.md, docs/IMPLEMENTATION_PLAN.md, docs/CHANGELOG.md
  • README.md, .env.example, render.yaml, existing Render/Sentry docs, blueprint addendum

Residual risks recorded

  • Shared-host isolation is not an OS sandbox; a malicious demo dependency is still a shared-host risk.
  • Remote repository connectors and multi-tenant isolation remain deferred.
  • Provider quota/tool-call enforcement is not claimed where OpenCode does not expose reliable data.
  • The Sentry bundler dependency advisory remains until a verified compatible upgrade exists.

Handoff state

The repo’s policy requires one phase commit, but this session is on a detached worktree with main checked out elsewhere. No branch or commit was created. When committing from an authorized branch, use one subject such as:

Stop here; do not begin Phase 9.

why? Stop here; do not begin Phase 9.

23h ago·0.0s

Because that boundary came from your Phase 8 instruction, not from a technical limitation:

  • “Implement only Phase 8 of the Unfinished Business roadmap.”
  • “Finish with the required phase handoff and stop. Do not start Phase 9.”

Phase 9 would be a separate roadmap phase with its own scope. Starting it before you review the Phase 8 handoff would violate the requested scope and make it harder to isolate defects or decide whether the phase should be committed as-is.

The other reason I stopped with changes uncommitted: this session is on a detached worktree, while main is checked out in the primary worktree. I can make a detached commit if you want one, but I did not create a branch or advance main without authorization.

To proceed, you can choose one:

  1. Review the working tree as-is and keep Phase 8 uncommitted.
  2. Create a detached Phase 8 commit with a subject such as fix: harden security, persistence, and operations.
  3. Explicitly authorize Phase 9; I will then inspect its requirements and start it.

commit all and push

23h ago·0.0s