Skip to content

security(deploy-pages): replace blanket inherited secrets with an explicit reusable-workflow contract #900

Open

Description

@seonghobae

Buyer/control-plane risk

Protected main currently documents and requires callers of .github/workflows/deploy-pages.yml to use secrets: inherit, while the reusable workflow actually needs only CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID. This creates unnecessary secret exposure at a reusable deployment boundary and contradicts the central explicit-secret contract documented in the active automation architecture line.

RCA

  • Symptom: caller examples and the runtime guard require blanket inherited secrets.
  • Immediate cause: workflow_call declares no explicit secrets interface, so the documentation uses secrets: inherit as the transport.
  • Root cause: the reusable deploy workflow predates the current least-privilege reusable-workflow contract.
  • Current search evidence: organization code search finds no product caller of deploy-pages.yml@... beyond the central workflow and Cloudflare documentation, so an explicit-interface migration is currently bounded to the central repository; this must be rechecked immediately before merge.

Required test-first correction

  1. Add a permanent contract test from protected main that fails while workflow_call.secrets does not explicitly require exactly CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID, or while central examples/guard text require secrets: inherit.
  2. Verify RED on the test-only head before production changes.
  3. Declare the two exact reusable-workflow secrets and reference only those names in the job.
  4. Replace secrets: inherit examples with explicit caller mappings.
  5. Keep workflow-level contents: read, immutable action pins, caller-repository checkout behavior, Cloudflare token purpose, and deployment semantics unchanged.
  6. Re-search the organization for consumers before merge; if any appear, update those thin callers explicitly rather than restoring inheritance.
  7. Run focused test, full central suite, workflow syntax, security/supply-chain gates, git diff --check, and current review.

Acceptance

  • No secrets: inherit remains in the authoritative deploy-pages workflow or its central usage docs.
  • The reusable workflow exposes only the two Cloudflare secret names it consumes.
  • Missing either secret fails closed without printing values.
  • No unrelated secret becomes addressable merely because a caller invokes the deploy workflow.
  • Consumer search/migration evidence and rollback are documented.

Refs the explicit-secret-contract debt in the canonical automation documentation PR.

Activity

  1. seonghobae commented on Aug 9, 2026

    @seonghobae
    ContributorAuthor

    /oc Implement this issue test-first from current protected main; refetch the live main tip immediately before branching and abort if another active branch/PR already owns this exact deploy-pages explicit-secret slice. Do not use COPILOT_GITHUB_TOKEN or create a one-shot/self-modifying writer workflow.

    RED first: add a permanent focused contract that reads .github/workflows/deploy-pages.yml and infra/cloudflare/README.md and fails while (a) on.workflow_call.secrets does not explicitly require exactly CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID, (b) either authoritative usage example tells callers to use secrets: inherit, or (c) the runtime guard tells callers to use inheritance. Verify that RED failure on the test-only head before changing production/docs.

    GREEN: declare the two required reusable-workflow secrets, keep them as the only Cloudflare deployment credentials referenced, replace inheritance examples with explicit secret mappings, and update the fail-closed missing-secret diagnostic accordingly. Preserve contents: read, action SHA pins, caller checkout semantics, project/build/domain behavior, and never print secret values. Re-search ContextualWisdomLab for deploy-pages.yml@ consumers before finalizing; migrate any real thin callers explicitly if discovered, otherwise record that no consumer migration was required. Add a brief doctoring/CHANGELOG note with GitHub reusable-workflow secret-contract references and rollback.

    Run focused RED→GREEN proof, complete central tests, 100% owned production statement/branch coverage and public docstrings where applicable, compile/syntax/actionlint, Secret/SAST/Security/CodeQL/OSV/Scorecard/SBOM checks, and git diff --check. Open one bounded Draft PR linked to #900. Do not merge, self-approve, weaken branch protection, or broaden any other secret contract.

  2. added
    area: apiAPI, protocol, event, or external contract
    area: authAuthentication, authorization, identity, or tenant isolation
    area: ci-cdCI, GitHub Actions, checks, release, or supply chain
    area: securitySecurity boundary, hardening, or vulnerability prevention
    status: triagedOpen issue has an organization taxonomy assignment
    type: securitySecurity vulnerability or security-specific remediation
    on Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionbugSomething isn't workingpriority: highHigh-priority or P1 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: securitySecurity vulnerability or security-specific remediation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions