GitHub Actions / Reusable automation and scoped authority / Lesson 10
Environment protection and approval boundaries
Connect an environment job to actual repository protections and a specific candidate decision.
On this page
Lesson goals
- Explain when environment protections and secrets apply.
- Review candidate binding, branch restrictions, and bypass authority.
Referencing an environment is not creating a safety policy
A job can name an environment such as parcel-staging, but the name alone does not establish required reviewers, allowed deployment branches, or a trusted target. The actual environment configuration and repository plan determine available protections. A misspelled name can refer to a different or newly created environment rather than the protected one the author intended. Review the configured object as well as YAML. This course never creates environments or changes repository settings; it teaches how to identify the evidence needed for that review.
Protection happens before privileged execution
For a job referencing an environment, configured protection rules must pass before the job proceeds to a runner and accesses that environment’s secrets under the documented lifecycle. This gives a useful decision boundary, but only if the job’s candidate and target are already clear. An approval to run a job that later selects whichever package is newest does not bind the decision to known bytes. Resolve the candidate through the trusted path first, then present its immutable identity and relevant evidence to the release decision.
Make the environment reference explicit
The fragment below references a synthetic environment and prints an already selected candidate label. It is not a deployment and does not request approval here. The environment must be configured independently with the intended protections. A dynamic environment name from untrusted input can select an unintended policy boundary, so validate any permitted selection and keep target authorization separate. Environment URL metadata is useful for navigation but does not prove that a successful job changed the linked service.
jobs:
review-candidate:
runs-on: ubuntu-latest
environment:
name: parcel-staging
permissions:
contents: read
steps:
- env:
PARCEL_CANDIDATE: parcel-lab-r3
run: printf "%s\n" "$PARCEL_CANDIDATE"
No real environment exists for this lesson. The step only prints a synthetic label and has no package, endpoint, secret, or deployment command. Its presence does not configure reviewers or branch restrictions.
Review the people and refs that can proceed
Deployment branch and tag restrictions, required reviewers, self-review settings, and bypass permissions affect who can authorize a job. Their availability depends on repository visibility, plan, and current product behavior. Do not copy a rule from a public repository and assume it is enforced in a private one. Also review who can edit the workflow and environment settings. A narrow approver list provides little value if an unrelated actor can replace the privileged script or bypass the protection without an accountable exception process.
Validate the intended decision inputs
The complete local model requires exact candidate and target agreement between a request and an approval record. It deliberately rejects an approval for another environment. Actual GitHub environment review is a platform mechanism, and this program does not emulate its internal authorization or create an approval. It illustrates a design invariant that surrounding release logic must preserve. Material changes to candidate, target, configuration, or required evidence need the policy’s defined re-evaluation behavior, especially when a job has waited a long time.
request = {"candidate": "parcel-lab-r3", "target": "parcel-staging"}
approval = {"candidate": "parcel-lab-r3", "target": "parcel-production"}
print(request == approval)
approval["target"] = "parcel-staging"
print(request == approval)
False
True
The approval dictionary is synthetic data, not authenticated authority. No reviewer, environment, or repository is contacted or modified.
Common errors and fixes
A typo silently selects an unprotected environment name.
- Why it happens
- The YAML name was not compared with the intended configured object.
- How to fix it
- Review and correct the exact environment reference under the repository’s process.
- Prevent it next time
- Keep approved environment names and ownership explicit.
An approval authorizes whatever artifact is latest later.
- Why it happens
- The decision precedes or ignores immutable candidate selection.
- How to fix it
- Resolve and bind the intended candidate before the protected decision.
- Prevent it next time
- Reevaluate material changes and stale evidence.
A protection copied from a public repository is assumed enforced privately.
- Why it happens
- Plan and visibility constraints were not checked.
- How to fix it
- Inspect actual feature availability and effective configuration.
- Prevent it next time
- Review settings, bypass authority, and repository context together.
Check your understanding
1. Does environment: production grant the job production credentials automatically?
Show worked solution
It references an environment; credential availability depends on its configured secrets, protections, repository context, and job lifecycle. The declaration does not create a real target identity or authorization policy by itself. Review what exists rather than inferring it from the name.
2. The candidate changes while a job waits for review. What should the process establish?
Show worked solution
Establish which immutable candidate the reviewer is deciding about and whether the change invalidates prior evidence or approval under policy. Avoid applying a decision for one candidate to different bytes. Record configuration and target changes as well.
Key takeaways
- Review the configured environment, not only its YAML name.
- Approval must preserve candidate, target, and evidence relationships.