Repository navigation
Description
Analysis
GitHub Actions can now reference an environment without creating a deployment: environment: { name: <env>, deployment: false } (changelog, March 2026; docs: "Using environments without deployments"). The job keeps the environment's secrets and protection rules (branch policy, required reviewers, wait timers), but no deployment object is created. deployment also accepts an expression, e.g. deployment: ${{ github.ref_name == 'main' }}.
gh-aw can't express it. In v0.93.5 and v1.0.1, pkg/parser/schemas/main_workflow_schema.json allows environment (top-level), safe-outputs.environment and jobs.<id>.environment to be either a string or an object with only name and url. Adding deployment: false is rejected and compilation fails:
safe-outputs:
environment:
name: my-protected-env
deployment: false✗ compilation failed
The compiler itself already passes the object through as raw YAML:
safe_outputs_config_global.go(around line 290):config.Environment = c.extractTopLevelYAMLSection(outputMap, "environment");workflow_builder_frontmatter_extract.go(around line 181):workflowData.Environment = c.extractTopLevelYAMLSection(frontmatter, "environment").
The only blocker therefore appears to be the schema.
Use case. A common pattern uses an environment only to gate a write credential, not to deploy. For example, an agentic workflow keeps a token for an external write API as environment secrets, on an environment whose branch policy allows only the default branch. The safe-output job that performs the write declares safe-outputs.environment, so a run started from an unreviewed branch can't reach the credential. Today every run creates a GitHub deployment:
- a scheduled agentic workflow produces a steady stream of deployment records in the repository's Deployments list;
- pull requests show "failed (outdated) deployment" whenever the workflow is started from a branch and the branch policy correctly refuses it.
Nothing is being deployed, so this is pure noise.
Implementation Plan
Please implement the following changes:
- Update the schema (
pkg/parser/schemas/main_workflow_schema.json): in the object form ofenvironment(top-level),safe-outputs.environmentandjobs.<id>.environment, adddeployment:oneOfboolean, or a string matching a GitHub Actions expression (^\$\{\{.*\}\}$);- a description: "Set to false to use the environment's secrets and protection rules without creating a GitHub deployment."
- Verify the compiler pass-through (
extractTopLevelYAMLSectionfor both call sites above). The emitted job keepsdeploymentexactly as written, on every job that receives the environment: the safe-output jobs, and any other job gh-aw appliessafe-outputs.environmentor the top-levelenvironmentto. If any code path rebuilds the environment fromnameonly, carrydeploymentthrough as well. - Leave the CLI
--environmentoverride (compiler_environment_override.go) unchanged: it sets a literal name. Optionally document that it replaces the wholeenvironmentblock, includingdeployment. - Add tests:
- Schema validation: object with
deployment: false,deployment: true, anddeployment: ${{ github.ref_name == 'main' }}accepted;deployment: "no"(non-expression string) rejected. - Compiler: a workflow with
safe-outputs.environment: { name: x, deployment: false }compiles, and every job that carries the environment hasenvironment.deployment: falsein the lock file. The same for top-levelenvironment.
- Schema validation: object with
- Update the docs (frontmatter reference for
environmentandsafe-outputs.environment) with an example and a note on when to use it: environments that only gate secrets. - Follow guidelines: run
make agent-finish.
Acceptance Criteria
safe-outputs.environmentand top-levelenvironmentacceptdeployment: false(andtrueor an expression) in the object form, and the compiled jobs carry it unchanged.- A workflow using
deployment: falsekeeps the environment's secrets and branch policy, and its runs create no GitHub deployment. - Workflows without
deploymentcompile exactly as before.
Activity