Skip to content

Feature: allow expression inputs for safe-output list constraints #29174

@bbonafed

Description

@bbonafed

Problem

Reusable workflow_call workflows often need callers to supply list-valued safe-output constraints at runtime. Today many of these fields require literal YAML arrays, which forces authors to duplicate workflows when only labels, allowed repositories, allowed branches, reviewers, or similar constraints vary per caller.

Representative examples:

safe-outputs:
  push-to-pull-request-branch:
    labels: ${{ inputs.required-labels }}
  add-comment:
    allowed-repos: ${{ inputs.allowed-repos }}

Existing support is inconsistent: some fields document examples containing expressions inside arrays, but array-valued fields generally cannot be replaced wholesale by a workflow_call input expression.

Related context: #23724 confirmed appetite for frontmatter expression support for reusable workflows. This issue focuses on list-valued safe-output constraints, which are distinct from integer/boolean templating.

Desired Behavior

Support both literal arrays and runtime expressions for list-valued constraints:

on:
  workflow_call:
    inputs:
      required-labels:
        type: string
        description: JSON array or newline/comma-separated labels
      allowed-repos:
        type: string
        description: JSON array or newline/comma-separated owner/repo values
---
safe-outputs:
  push-to-pull-request-branch:
    labels: ${{ inputs.required-labels }}
  add-comment:
    allowed-repos: ${{ inputs.allowed-repos }}

Literal arrays must remain valid:

safe-outputs:
  push-to-pull-request-branch:
    labels: [automation]
  add-comment:
    allowed-repos: [owner/repo]

Proposed Scope

Start with list-valued safe-output constraints used for target validation and filtering:

  • safe-outputs.push-to-pull-request-branch.labels
  • safe-outputs.create-pull-request.labels
  • safe-outputs.add-comment.allowed-repos
  • safe-outputs.push-to-pull-request-branch.allowed-repos
  • safe-outputs.create-pull-request.allowed-base-branches
  • Shared helpers such as ParseStringArrayFromConfig, parseLabelsFromConfig, and related schema definitions.

This can be extended later to other list-valued safe-output fields once the pattern is established.

Implementation Plan

  1. Decide accepted runtime format

    • Pick one documented representation for expression-resolved lists, such as JSON arrays, comma-separated strings, newline-separated strings, or the same flexible parsing used by existing guard-policy fields.
    • Prefer reusing an existing parser convention already present in tools.github guard-policy fields if possible.
  2. Schema updates

    • Update selected list fields to accept either an array of strings or a GitHub Actions expression string.
    • Keep array item validation for literal arrays.
  3. Parser/config updates

    • Update shared string-list parsing helpers to preserve expression strings rather than dropping or rejecting them.
    • Add a templatable string-list representation if needed so generated handler config can distinguish literal arrays from runtime expressions.
  4. Runtime validation

    • Ensure handlers parse runtime-resolved list values deterministically.
    • Validate each resolved entry according to the field's existing semantics.
    • Fail closed on malformed input rather than silently widening constraints.
  5. Tests

    • Add schema/parser tests for literal arrays, expression strings, malformed literal values, and malformed runtime-resolved values.
    • Add compiler tests proving expressions are preserved in the generated safe-output handler config.
    • Add handler/runtime tests for the chosen string-list format.
  6. Documentation

    • Document the accepted runtime list format.
    • Add examples for reusable workflows using workflow_call inputs.

Acceptance Criteria

  • Selected list-valued safe-output constraints accept literal arrays and expression strings.
  • Runtime-resolved lists are parsed and validated consistently.
  • Malformed or invalid resolved values fail closed.
  • Literal array behavior remains backward compatible.
  • Shared helper behavior is covered by tests.
  • Documentation includes reusable-workflow examples and the accepted list format.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions