Skip to content

feat(shared-workflows): support sandbox field in shared workflow partials with merge semantics #37722

Description

@yskopets

🤖 This issue has been filed by Claude Code.

Problem

The sandbox frontmatter field is currently only accepted in main workflow files (those with an on: trigger). Attempting to use it in a shared workflow partial causes the compiler to reject or silently ignore it:

field 'sandbox' cannot be used in shared workflows (only allowed in main workflows with 'on' trigger)

This means a shared partial that installs a binary into the runner environment cannot co-locate the mount declaration needed to make that binary accessible inside the agent sandbox. The mount must instead be duplicated in every main workflow that imports the shared partial — exactly the kind of repetition that shared partials exist to eliminate.

Motivating example

Suppose a shared partial sets up a CLI tool:

# shared/setup-my-cli.md
---
steps:
  - name: Set up my-cli
    uses: my-org/setup-my-cli@v2  # installs binary into ${MY_CLI_PATH}
---

`my-cli` is available. You can run `my-cli validate`, `my-cli fmt --check`, etc.

setup-my-cli unconditionally installs its binary into ${MY_CLI_PATH}, which by default is not on any path mounted into the agent container. Without a mount, the agent cannot invoke the binary even though it is present on the host.

The only way to expose it today is to add sandbox.agent.mounts to every main workflow that imports this partial:

# every-workflow-that-uses-my-cli.md  (repeated in N files)
sandbox:
  agent:
    mounts:
      - ${MY_CLI_PATH}/my-cli:${MY_CLI_PATH}/my-cli:ro

Proposed solution

Allow sandbox.agent.mounts (and potentially other sandbox.agent.* fields) in shared workflow partials. When compiling, the compiler should merge all mount lists from all imported shared partials with the main workflow's own sandbox.agent.mounts:

# shared/setup-my-cli.md
---
sandbox:
  agent:
    mounts:
      - ${MY_CLI_PATH}/my-cli:${MY_CLI_PATH}/my-cli:ro

steps:
  - name: Set up my-cli
    uses: my-org/setup-my-cli@v2
---

`my-cli` is available. ...

With this, importing the shared partial is sufficient — the mount is declared alongside the step that installs the binary, and all consuming workflows get it automatically.

Merge semantics

When multiple shared partials (or a shared partial and the main workflow) each declare sandbox.agent.mounts, the compiler should union all mount lists into a single deduplicated list. Order within the list is not significant for correctness.

Example: if shared/setup-my-cli.md declares mount A and shared/setup-other-tool.md declares mount B, and a main workflow imports both and also declares mount C, the compiled awf invocation should include --mount A --mount B --mount C (deduplicated).

Alternatives considered

  • Symlink into a well-known path: works for making the binary callable on the host PATH, but does not help the agent sandbox since the sandbox only sees explicitly mounted paths.
  • Document the workaround: requires every workflow author to know they must add sandbox.agent.mounts when importing a setup partial — fragile and easy to forget.

Impact

This would allow shared partials that install external tools to be truly self-contained, keeping the setup step and the corresponding sandbox declaration co-located in one file rather than scattered across every consuming workflow.

Metadata

Metadata

Labels

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