Development and Security

Access ladder

Role Repository Development data Production credentials Production deploy
Reader/reviewer Read None None No
Contributor Pull-request/write as approved Synthetic local workspaces None No
Maintainer Write/admin as assigned Synthetic plus bounded diagnostics None by default No by default
Operator Admin only where required Bounded diagnostics Individually granted, scoped, encrypted Explicit upload and promote

Repository access never implies secret or production authority. Do not share one person's token with another developer. Add an operator by minting an individual least-privilege credential and adding its encrypted recipient through the operator-controlled secret store.

Reproducible checkout

git clone --recurse-submodules git@github.com:corbet-labs/careervector-corbet-ch.git
cd careervector-corbet-ch
git lfs pull
nix develop .#ci --command bun install --frozen-lockfile
nix develop .#ci --command bun run check

The private Sporewright submodule is required by the full TypeScript and orchestrator graph. Missing access must fail visibly; do not replace it with a copied package or personal token in external CI.

Local data and secrets

  • *.example files define names and safe defaults only.
  • Real .env and .dev.vars files are ignored, remain local, and use mode 600 on Unix.
  • Transcrypt is retired. Do not add its filters, keys, or metadata; shared operator secrets are stored outside the repository with SOPS and age.
  • Use deliberately invalid provider credentials in fixtures.
  • Use local Miniflare state and synthetic workspace links. Never paste a live workspace capability into a test, issue, or support transcript.
  • bun run check:secrets rejects tracked credential files, common token/key shapes, unpinned GitHub actions, GitHub Actions secret use, stale transcrypt configuration, and permissive local credential-file modes.

PUBLIC_GOOGLE_MAPS_KEY is intentionally browser-visible, restricted at Google to approved HTTP referrers and APIs, and is not a server credential. It must not be reused for a backend or a different domain.

Production secrets

Deployed Worker secrets are vendor bindings and cannot be read back through the repository. Operator source material is encrypted outside this repository.

The Cloudflare wrapper resolves credentials in this order:

  1. CLOUDFLARE_API_TOKEN plus CLOUDFLARE_ACCOUNT_ID already present in the process environment;
  2. a strict, non-executable, mode-600 file selected by CAREERVECTOR_CLOUDFLARE_ENV;
  3. the encrypted file selected by CAREERVECTOR_CLOUDFLARE_SOPS_FILE, reading only careervector_workers_deploy_token and account_id.

Contributors do not need any of these. The current deploy token grants only account-level Workers Scripts Write; it does not grant DNS, billing, D1 data, R2 data, or account-settings mutation.

CI trust boundary

  • Crow runs the full gate on controlled infrastructure and can consume the private submodule through its repository checkout.
  • GitHub Actions jobs are source-read only, use no repository/production secrets, disable persisted checkout credentials, and pin third-party actions by full commit SHA.
  • CircleCI jobs are local/synthetic test dispatch only. Do not add vendor, database, signing, release, or production tokens to CircleCI.
  • Production deployment is not push-triggered.

Before handoff

bun run check:secrets
bun audit
git diff --check

Run bun run check and bun run test in nix develop .#ci, then the relevant browser, TUI, Tauri, or deployment-specific evidence gate.

Suspected exposure

Stop copying or displaying the material, preserve the smallest useful evidence, and report privately according to the root SECURITY.md. Do not rotate or delete credentials independently: operators first identify every consumer and then change the source, bindings, and dependent services as one coordinated action.

Source: wiki/content/onboarding/05-development-and-security.md