Skip to content

Feature: parameterize tools availability and allowlists for reusable workflows #29189

@bbonafed

Description

@bbonafed

Problem

Reusable workflow_call agentic workflows can parameterize some tool-related values today, such as tools.timeout and tools.startup-timeout, but the actual tools and tool allowlists remain compile-time-only.

This makes reusable workflows hard to compose when callers need to choose between otherwise-similar tool policies. For example, callers may want to select a Bash command allowlist, GitHub MCP toolsets, or whether an editing tool is enabled without maintaining separate workflow files for each tool configuration.

Representative examples that are not currently supported:

on:
  workflow_call:
    inputs:
      bash-tools:
        type: string
      github-toolsets:
        type: string
---
tools:
  bash: ${{ inputs.bash-tools }}
  github:
    toolsets: ${{ inputs.github-toolsets }}

Related context: #23724 confirmed appetite for parameterizing frontmatter fields other than engine.id. Follow-up work covered timeout-minutes, engine.version, and tool timeout fields, but not tool availability or tool allowlists.

Desired Behavior

Reusable workflows should be able to expose selected tool policy inputs while preserving least privilege and fail-closed behavior.

Possible authoring pattern:

on:
  workflow_call:
    inputs:
      bash-allowlist:
        type: string
        description: JSON array or newline/comma-separated command allowlist
      github-toolsets:
        type: string
        description: JSON array or newline/comma-separated GitHub MCP toolsets
---
tools:
  bash: ${{ inputs.bash-allowlist }}
  github:
    toolsets: ${{ inputs.github-toolsets }}

Literal static config must remain valid:

tools:
  bash: ["bash", "git", "gh"]
  edit:
  github:
    toolsets: [repos, issues]

Security Model

Because tools directly affect what an agent can do, expression support should not silently widen privileges.

A conservative implementation would be acceptable, for example:

  • Require workflow authors to declare a compile-time maximum/superset of allowed tools.
  • Let runtime inputs select a subset of that declared superset.
  • Validate runtime-resolved values before enabling tools.
  • Fail closed when an expression resolves to an invalid command/tool/toolset.
  • Avoid expression support for fields that would require adding broader GitHub permissions at runtime unless the compiled workflow already includes the needed least-privilege permissions safely.

Proposed Scope

Start with fields that are high-value for reusable workflows and can be validated against known allowlists:

  • tools.bash command allowlist
  • tools.edit enable/disable if this can be expressed without changing job permissions unsafely
  • tools.github.toolsets
  • tools.github.allowed / tools.github.blocked if those are the current precise allowlist controls
  • Any shared parsing helpers for string-list tool config

This issue intentionally excludes engine.id, which is a separate architectural question already called out in #23724.

Implementation Plan

Please implement this as an agentic-plan contribution rather than a direct community PR.

  1. Audit tool config shape

    • Inspect pkg/parser/schemas/main_workflow_schema.json tool definitions and Go parsing under pkg/workflow.
    • Identify which tool fields influence generated jobs, generated permissions, MCP server config, or runtime handler config.
    • Classify fields as safe for expression support, safe only with compile-time superset validation, or not appropriate for runtime parameterization.
  2. Choose runtime list format

    • Reuse an existing convention where possible, such as JSON array, comma-separated string, newline-separated string, or the flexible list parser used by GitHub guard-policy fields.
    • Document the chosen format for workflow_call inputs.
  3. Schema updates

    • Allow selected fields to accept either their current literal types or a GitHub Actions expression string.
    • Keep item-level validation for literal arrays.
    • Keep non-expression strings invalid unless a field already intentionally accepts scalar strings.
  4. Parser/config updates

    • Preserve expression strings distinctly from literal arrays or booleans.
    • Add or reuse templatable string-list helpers for tool allowlists.
    • For fields with a compile-time superset model, validate that literal supersets are present and that runtime selections cannot exceed them.
  5. Compilation/runtime validation

    • Ensure expression values are emitted so GitHub Actions can evaluate them at runtime.
    • Validate runtime-resolved values before starting tool servers or handing capabilities to the agent.
    • Fail closed on malformed values or values outside the allowed superset.
    • Avoid direct shell interpolation of expression-resolved values.
  6. Tests

    • Add schema/parser tests for literal values, expression values, invalid literal values, and invalid expression-resolved values.
    • Add compiler tests proving expressions are preserved in generated lock YAML in runtime-evaluable locations.
    • Add runtime tests for fail-closed validation of command/toolset selections.
  7. Documentation

    • Update the tools reference with reusable workflow_call examples.
    • Clearly document any compile-time superset requirement and runtime input format.
    • Explain which tool fields support expressions and which remain compile-time by design.

Acceptance Criteria

  • Selected tools fields accept GitHub Actions expression strings in reusable workflows.
  • Literal tool configs remain backward compatible.
  • Runtime-resolved tool selections are validated before use.
  • Runtime inputs cannot silently expand beyond the workflow author's declared security boundary.
  • Invalid or malformed resolved values fail closed with clear errors.
  • Tests and documentation are updated.

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