Skip to content

auth setup

Step-by-step provisioning of credentials for petrova --apply. The user-facing summary is at /cli/auth/ — this page is the operator runbook with troubleshooting.

Decide: PAT or GitHub App?

  • PAT if: solo dev, single user, short rotation cadence is fine.
  • GitHub App if: multiple fleets, multiple users, want per-fleet audit log, want install/uninstall as the access toggle.

When in doubt, start with PAT. Migration to App later is straightforward (the CLI auto-detects which is set).

GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokensGenerate new token.

Settings:

  • Token name: PETROVA-<env> (e.g. PETROVA-prod, PETROVA-test).
  • Expiration: maximum 90 days. Calendar a rotation reminder for 7 days prior.
  • Resource owner: the org that owns governed repos (e.g. petrova-hq, kahn-hq).
  • Repository access: Only select repositories → list every slug in registry.yaml for that owner. Avoid “All repositories”.
  • Permissions:
    • Contents: Read and write
    • Metadata: Read-only (auto-set)
    • Pull requests: Read and write
    • Administration: Read-only (only if using request_merge_when_green — needed for branch-protection check)
Terminal window
op item create --category=password \
--title="PETROVA_GITHUB_TOKEN" \
--vault=PETROVA \
password="<paste-token>"

(Or your password manager of choice.)

In your shell rc / .envrc:

Terminal window
export PETROVA_GITHUB_TOKEN="$(op read 'op://PETROVA/PETROVA_GITHUB_TOKEN/credential')"
Terminal window
echo "${PETROVA_GITHUB_TOKEN:0:4}…" # should print 'gith…' or similar
petrova open_decision petrova-hq --input /tmp/test-decision.json --apply --json | jq '.envelope.status'
# Expected: "applied" or "skipped_idempotent"
  • AUTH_MISSING → token not in environment. Re-export.
  • 403 → permissions too narrow. Check token scopes match the table above.
  • 404 Not Found on a real repo → token’s repository access list doesn’t include this repo.
  • 401 → token expired or revoked. Generate a fresh one.

Org settings → Developer settings → GitHub Apps → New GitHub App.

Settings:

  • Name: PETROVA Control Plane.
  • Homepage URL: https://petrova.devarno.cloud (or https://github.com/petrova-hq/petrova).
  • Webhook: disabled for now (re-enable when the deferred webhook receiver lands).
  • Repository permissions:
    • Contents: Read and write
    • Metadata: Read-only
    • Pull requests: Read and write
    • Administration: Read-only
  • Subscribe to events: push, pull_request (future use).
  • Where can this GitHub App be installed? Only on this account.

Click Create.

App’s settings → Private keysGenerate a private key. Downloads as .pem.

Terminal window
mkdir -p ~/.petrova
mv ~/Downloads/*.private-key.pem ~/.petrova/petrova-app.private-key.pem
chmod 600 ~/.petrova/petrova-app.private-key.pem

Or store the contents in 1Password:

Terminal window
op item create --category=secure-note \
--title="PETROVA App Private Key" \
--vault=PETROVA \
notes-plain="$(cat ~/.petrova/petrova-app.private-key.pem)"

App’s public page → Install → choose org → choose Only select repositories → pick every slug in registry.yaml.

Note the Installation ID from the post-install URL: https://github.com/settings/installations/<INSTALLATION_ID>.

Terminal window
export PETROVA_APP_ID=12345 # from app's settings page
export PETROVA_APP_PRIVATE_KEY_PATH=~/.petrova/petrova-app.private-key.pem
export PETROVA_APP_INSTALLATION_ID=67890 # from install URL
Terminal window
unset PETROVA_GITHUB_TOKEN # ensure App path is exercised, not PAT fallthrough
petrova open_decision petrova-hq --input /tmp/test-decision.json --apply --json | jq '.envelope.status'
  • AUTH_MISSING → one of the three env vars unset. Check all three.
  • Bad credentials → private key path wrong, or key file permissions unreadable. cat $PETROVA_APP_PRIVATE_KEY_PATH | head -1 should show -----BEGIN RSA PRIVATE KEY-----.
  • 403 Resource not accessible by integration → app not installed on the target repo, or installation lacks the required permissions. Re-install or update install settings.
  • 401 Bad credentials → installation ID wrong. Recheck.

Calendar reminder 7 days before expiry. On rotation:

  1. Generate new token with same scopes.
  2. Update 1Password.
  3. Re-export in active shells.
  4. Revoke old token.

Apps don’t expire, but rotate the private key annually:

  1. App settings → Private keys → Generate a new private key.
  2. Replace the .pem on disk.
  3. Re-export PETROVA_APP_PRIVATE_KEY_PATH if path changed.
  4. Revoke the old key.

Revoke the token in GitHub. All --apply invocations using that token immediately fail with 401.

Either:

  • Uninstall the app from the target repos (per-repo revocation), or
  • Suspend the app entirely (org-wide revocation).