Skip to content

[P2.37] The production environment has no secrets, so deploy-production cannot work #1143

Description

@frankbria

Found by a scanner added alongside the release-guard environment fix. Priority P2.37 — severity medium, category ci.

Problem

The production GitHub environment contains zero secrets, but deploy.yml's deploy-production job declares environment: production and references at least ten of them:

REMOTE_HOST:       ${{ secrets.HOST }}
REMOTE_USER:       ${{ secrets.USER }}
REMOTE_PATH:       ${{ secrets.PROJECT_PATH }}
ENV_ANTHROPIC_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ENV_OPENAI_KEY:    ${{ secrets.OPENAI_API_KEY }}
ENV_AUTH_SECRET:   ${{ secrets.AUTH_SECRET }}
...

GitHub exposes environment secrets only to jobs declaring that environment, and production supplies none — so every one of these resolves to an empty string. For comparison, staging holds 20 secrets and the staging deploy works.

Verified against the live repo:

$ gh api repos/frankbria/codeframe/environments/production/secrets --jq .total_count
0
$ gh api repos/frankbria/codeframe/environments/staging/secrets --jq .total_count
20

What actually happens

The job fails early rather than silently deploying something broken — SSH_KEY is empty, so the SSH step cannot authenticate. That is the mitigating factor and why this is P2 rather than P1.

But if the SSH secrets were ever populated without the rest, the job would write a remote .env containing:

ANTHROPIC_API_KEY=
OPENAI_API_KEY=
AUTH_SECRET=

An empty AUTH_SECRET is the dangerous one — that is the JWT signing key.

Decisions this needs

Not a code fix. One of:

  1. Populate production with the same secret set as staging (different values), if production deploys are intended
  2. Delete the deploy-production job and the production environment, if staging is the only deploy target — the repo currently ships a deploy path that has never worked
  3. Guard the job so it fails with an explicit "production is not configured" message rather than an SSH auth error

Acceptance criteria

  • A decision recorded on whether production deploys are a supported path
  • If kept: production holds every secret deploy-production references, and one successful deploy is verified
  • If kept: AUTH_SECRET is confirmed non-empty before any deploy writes the remote .env
  • If dropped: the job and environment are removed, so nothing suggests a path that does not exist
  • The exemption in tests/test_workflow_lint_wiring_1122.py::TestEnvironmentSecretsAreReachable is removed

Note

The scanner that found this asserts that any job using an environment secret declares an environment that actually provides it. deploy-production is currently exempted with a pointer to this issue rather than the check being weakened.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:bugSomething is broken and needs fixing

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions