# Security Checks

Agents must run security checks before claiming done.

## Required Checks

Run the repo's actual commands once they exist.

Minimum expected checks:

- dependency audit
- secret scan
- auth route review
- MCP token handling review
- protected route check
- hosted WorkOS deployment canary
- WorkOS mode hides local-only demo and developer-switch routes
- health route returns readiness only, not secrets or raw work data
- no raw tokens in logs
- no secrets in git
- no local companion config, generated report media, or database files tracked for public release
- real hosted deployments must use the managed PostgreSQL/Cloud SQL path
- PostgreSQL schema and runtime smokes must prove tenant/workspace isolation
  before the production doctor is allowed to pass

## Secret Rules

Do not commit:

- `.env`
- `.env.local`
- auth secrets
- API keys
- MCP raw tokens
- database files
- session dumps
- raw agent transcripts

## Auth Review

Check:

- unauthenticated users cannot open protected UI pages
- unauthenticated users cannot call protected APIs
- tenant/user administration routes require authentication and tenant admin role for member creation
- workspace cookies are accepted only when the workspace belongs to the active tenant
- post-auth onboarding (`POST /api/onboarding`) grants tenant/workspace admin only
  to the bootstrap (first) member; a user joining an existing tenant cannot self-elevate
- MCP calls without valid token fail
- revoked MCP tokens fail
- token hashes are stored instead of raw tokens
- MCP token-created agent activity logs as the token owner
- device-flow endpoints (`/api/setup/device`, `/api/setup/device/poll`) are
  rate limited; grant approval requires a cookie session and binds the
  signed-in developer/tenant/workspace
- device codes are stored hashed; minted typed tokens are delivered exactly
  once by the poll endpoint and never logged
- WorkOS mode runs AuthKit proxy middleware before protected UI/API routes
- production without complete WorkOS env reports blocked auth instead of local-dev
- WorkOS sign-in and callback routes fail closed when auth config is blocked
- local-only route handlers fail closed when auth config is blocked
- protected UI API handlers fail closed when auth config is blocked
- malformed UI API bodies return structured errors or safe defaults
- `/api/state` returns 401 when no developer is authenticated
- `/api/health` does not expose raw error detail
- UI session cookies always persist with the `Max-Age` configured by
  `COVIBE_REMEMBER_ME_DAYS` (default 30 days); sign-out cookie deletions are
  never extended to that age
- logout clears Co-Vibe session cookies and uses AuthKit logout in WorkOS mode
- local-dev logout sets a signed-out marker instead of falling back to `@hakan`
- Settings does not allow users to change email; password changes use provider reset

## MCP Review

Check:

- blocked starts cannot bypass confirmation
- overlap warnings are returned to the agent
- all tool calls write usage events
- state-changing tools write work events
- errors do not leak secrets
- `/api/mcp` rate-limits per client IP (env `COVIBE_MCP_RATE_LIMIT` /
  `COVIBE_MCP_RATE_WINDOW_MS`, default 240/min) before parsing or DB work;
  over-limit returns `429` with `Retry-After`. In-memory and per-instance — pair
  with an edge/shared limiter for multi-instance deploys
- PostgreSQL RLS `with check` matches the strict `using` equality, so rows cannot
  be written with a NULL workspace_id/tenant_id that read views could surface
  across tenants

## CI Gates

The `Customer readiness` workflow runs a dedicated `Security gate` job on every
pull request and push to `main`, independently of the heavier build jobs:

- `npm ci` — integrity-verified install from the frozen lockfile.
- `npm run check:secrets` — no committed secrets.
- `npm audit --audit-level=high` — fails on high/critical CVEs.
- `npm audit signatures` — verifies npm registry provenance of every dependency.

## Supply Chain & Dependency Freeze

Dependencies are **frozen**: direct deps are pinned to exact versions, the v3
lockfile pins every transitive dep with an integrity hash, and `.npmrc`
(`save-exact`, `engine-strict`) keeps the freeze sticky. There is intentionally
no Dependabot/Renovate auto-upgrade bot. CI gates on `--audit-level=high`;
moderate advisories are tracked, not blocking (currently accepted:
`postcss <8.5.10` CSS-stringify XSS, transitive via `next` →
`@workos-inc/authkit-nextjs`, no fix available, not reachable with untrusted CSS).
Full policy and the deliberate-upgrade procedure: `docs/engineering/dependency-policy.md`.

## Reporting

If a check fails, do not hide it.

Write it in `reports/morning-report.md` with:

- severity
- command or manual check
- result
- next action

## Current Command

Run:

```bash
npm run security
```

This runs dependency audit, secret scan, public-repo hygiene, public-doc setup
command checks, companion package contents, minimal dependency manifest, README
setup-shape checks, and a static auth/token review.
Public-repo hygiene checks tracked files plus unignored untracked files, so a
local `.env`, database, MCP config, or generated report artifact fails before it
can be staged for a public release. Public docs may use placeholders such as
`cv_...`, but concrete `COVIBE_MCP_TOKEN=cv_...` examples and
setup command lines that pass concrete raw tokens fail the public check.

Run `npm run check:deploy` before building the hosted image. It verifies the
Next standalone output config, Docker runtime command, persistent data volume,
Docker build-context exclusions for secrets and local agent config, and the
hosted/container runtime leak guard for raw Co-Vibe MCP token-shaped response
data.

For a deployed customer environment, also run:

```bash
npm run readiness:handoff -- https://your-covibe-host
```

This first runs a fast remote `/api/health`, `/api/mcp`, and
`/downloads/co-vibe.tgz` preflight for DNS/TLS, WorkOS auth, exact compact MCP
tool surface, companion-package availability, protected-route rejection,
unauthenticated token creation rejection, hidden local-only routes, malformed MCP
envelope rejection, missing/invalid MCP-token rejection, and token-shaped response leaks,
then runs `doctor:production` before the long local customer gate.
`doctor:production` requires real hosted origins to use managed
PostgreSQL/Cloud SQL. Use `npm run smoke:postgres` to verify the generated
PostgreSQL schema/RLS policies and `npm run smoke:postgres:runtime` to verify
repository calls run through PostgreSQL tenant/workspace scope.
The companion tarball check also rejects tiny, malformed, or non-Co-Vibe
packages before customer install checks run.
It then runs customer readiness, production WorkOS config checks, and a hosted canary for
`/api/health`, the exact compact `/api/mcp` tool surface, the companion tarball
download/install/setup/doctor/snapshot/watch/MCP tool-list path, sign-in
reachability, unauthenticated API rejection, hidden local-dev routes, malformed
MCP envelope rejection, MCP token enforcement, and response leak checks for raw
Co-Vibe MCP token-shaped values. The handoff command rejects
localhost, private-network hosts, non-HTTPS URLs, callback paths, query strings,
hashes, credential-bearing URLs, and temporary tunnel domains. The hosted URL
must be the permanent deployment origin, not the WorkOS callback URL.
