Skip to content

Feature: parameterize safe-output PR policy fields in workflow_call workflows #29173

Description

@bbonafed

Problem

Safe-output pull request workflows often need caller-specific policy choices in reusable workflow_call workflows. Today several PR safe-output policy fields are compile-time-only because they are validated as static enums or static strings.

High-value examples include:

safe-outputs:
  push-to-pull-request-branch:
    protected-files: ${{ inputs.protected-files-policy }}
    patch-format: ${{ inputs.patch-format }}

Without expression support, reusable workflow authors need separate workflow files for otherwise-identical workflows that differ only in protected-file policy or patch transport format.

Related context: #23724 confirmed appetite for runtime parameterization of frontmatter fields where safe. Earlier follow-ups covered timeout/version fields, but not safe-output PR policy fields.

Desired Behavior

Allow expression strings for enum-like PR policy fields while preserving existing literal validation:

on:
  workflow_call:
    inputs:
      protected-files-policy:
        type: string
        default: fallback-to-issue
      patch-format:
        type: string
        default: am
---
safe-outputs:
  push-to-pull-request-branch:
    protected-files: ${{ inputs.protected-files-policy }}
    patch-format: ${{ inputs.patch-format }}

Literal values must still work and should continue to receive compile-time enum validation:

safe-outputs:
  push-to-pull-request-branch:
    protected-files: fallback-to-issue
    patch-format: am

Proposed Scope

Start with enum-like policy fields that do not change the generated job permission model:

  • safe-outputs.push-to-pull-request-branch.protected-files
  • safe-outputs.push-to-pull-request-branch.patch-format
  • safe-outputs.create-pull-request.protected-files
  • safe-outputs.create-pull-request.patch-format
  • Any shared validation helper used by both handlers, such as validateStringEnumField, so the behavior stays consistent.

If object-form protected-files cannot reasonably support expressions for nested policy, it is acceptable to start with expression support for the string policy form only.

Implementation Plan

  1. Schema updates

    • Update the relevant protected-files and patch-format schema definitions to accept either the current enum literals or a GitHub Actions expression string.
    • Keep object-form protected-files behavior unchanged unless nested expression support is straightforward.
  2. Parser and validation updates

    • Update enum validation helpers so literal strings are validated against the existing allowlist, while expression strings are accepted and passed through.
    • Preserve clear errors for invalid literal strings.
    • Ensure both create-PR and push-to-PR-branch paths use the same helper behavior.
  3. Compilation/runtime behavior

    • Ensure the expression string is emitted into the generated handler config in a runtime-evaluable way.
    • Confirm JavaScript safe-output handlers evaluate the resolved runtime value against the same policy enum before applying it.
    • Fail closed at runtime if the resolved value is not one of the allowed policies/formats.
  4. Tests

    • Add schema/parser tests for literal valid values, literal invalid values, and expression values.
    • Add compiler tests showing expressions appear in the safe-output handler config.
    • Add JS runtime tests for invalid resolved values to ensure fail-closed behavior.
  5. Documentation

    • Update PR safe-output docs with reusable-workflow examples.
    • Document the allowed runtime-resolved values for each field.

Acceptance Criteria

  • protected-files and patch-format literal values remain backward compatible.
  • Expression strings are accepted for the scoped PR safe-output policy fields.
  • Invalid literal strings remain compile-time errors.
  • Invalid runtime-resolved expression values fail closed before mutating repository state.
  • Create-PR and push-to-PR-branch behavior is consistent.
  • Tests and docs are updated.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions