Skip to content

GitHub Environments

GitHub Environments in unipuka/soa used by do-deploy.yml for deployment tracking and protection gates.

Environments

Environment Tenant Protection Branch policy
oep-stg oep-stg None (auto-deploys from CI) None
mansety-prd mansety-prd Required reviewers: Backend team (when billing supports it) Protected branches only
us-prd us-prd Required reviewers: Backend team (when billing supports it) Protected branches only

do-deploy.yml declares environment: ${{ inputs.tenant }}, which maps directly to these environments for deployment audit logs and (when protection rules are active) reviewer gates.

Creating environments (idempotent script)

All 3 environments were created via API. Run this to recreate if deleted:

# oep-stg - no protection rules (auto-deploys from release job in do-build.yml)
gh api -X PUT repos/unipuka/soa/environments/oep-stg --input - <<'EOF'
{}
EOF

# mansety-prd - no reviewer gate yet (see billing note below)
gh api -X PUT repos/unipuka/soa/environments/mansety-prd --input - <<'EOF'
{}
EOF

# us-prd - no reviewer gate yet (see billing note below)
gh api -X PUT repos/unipuka/soa/environments/us-prd --input - <<'EOF'
{}
EOF

Adding required reviewers (once billing supports it)

GitHub requires Team plan or higher for environment protection rules on private repositories. At time of BD-5.4 implementation, the API returned a 422 for all protection rule types (reviewers and wait_timer) despite the org reporting "team" plan. Verify via GitHub billing UI before proceeding.

  1. Go to https://github.com/unipuka/soa/settings/environments
  2. Click mansety-prd -> Edit
  3. Under Required reviewers, add team @unipuka/backend
  4. Check Prevent self-review if desired
  5. Under Deployment branches and tags, select Protected branches
  6. Save protection rules
  7. Repeat for us-prd

Via API (once billing issue confirmed resolved)

# Discover the Backend team ID dynamically (errors if team not found)
BACKEND_TEAM_ID=$(gh api orgs/unipuka/teams/backend --jq '.id')
if [ -z "$BACKEND_TEAM_ID" ]; then
  echo "Error: could not resolve @unipuka/backend team ID" >&2
  exit 1
fi
echo "Backend team ID: ${BACKEND_TEAM_ID}"

for ENV in mansety-prd us-prd; do
  gh api -X PUT "repos/unipuka/soa/environments/${ENV}" --input - <<EOF
{
  "reviewers": [
    {
      "type": "Team",
      "id": ${BACKEND_TEAM_ID}
    }
  ],
  "deployment_branch_policy": {
    "protected_branches": true,
    "custom_branch_policies": false
  }
}
EOF
  echo "Updated ${ENV}"
done

Verify reviewers are set

gh api repos/unipuka/soa/environments \
  --jq '.environments[] | {name: .name, rules: [.protection_rules[]? | {type: .type, reviewers: [.reviewers[]?.reviewer.name // .reviewer.login // empty]}]}'

V&V (once reviewers active)

  1. Dispatch do-deploy.yml with tenant=mansety-prd + any valid tag
  2. Workflow run should pause with status "Waiting for review"
  3. Backend team member approves -> workflow proceeds
  4. Backend team member declines -> workflow aborts with "Deployment was rejected"
  5. Dispatch with tenant=oep-stg -> proceeds immediately, no gate

Notes

  • oep-stg is auto-deployed by the release job in do-build.yml after every master push. No gate by design.
  • Prod tenant deployments (mansety-prd, us-prd) are always manual workflow_dispatch only. No CI job triggers them.
  • The do-deploy.yml workflow needs no code changes - it already declares environment: ${{ inputs.tenant }}.