Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/aw/workflow-constraints.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ When a requested feature increases risk:
- auto-merge or bypassing review
- overly broad network access
- unbounded bash allowlists for untrusted input
- shell injection: interpolating `${{ github.event.* }}` or other untrusted expressions directly into `run:` scripts; pass untrusted values through environment variables instead
- placing OIDC/secret bootstrap in `pre-steps` instead of earlier `setup-steps`
- using `post-steps:` for agent-driven write actions

Expand Down
48 changes: 48 additions & 0 deletions .github/aw/workflow-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,54 @@ For recurring maintenance in large repos:

See also: [memory.md](memory.md)

## Step Authoring Guidance

When writing `steps:`, `pre-steps:`, and `post-steps:`, choose the implementation type in this order of preference:

### 1. Preferred: `actions/github-script`

Use `actions/github-script` for GitHub API interactions and general scripting. The workflow compiler handles action pinning automatically; specify a recent major version tag (`@v7`) without a SHA.

- Provides typed access to the GitHub REST API via `github.rest.*`
- Exposes `context`, `core`, `github`, `io`, and `exec` helpers
- Eliminates shell injection risks for untrusted input
- Example:

```yaml
steps:
- name: Fetch issue data
uses: actions/github-script@v7
with:
Comment on lines +111 to +113
script: |
const issue = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
core.setOutput('title', issue.data.title);
```

### 2. Shell scripts

Use `run:` steps when `actions/github-script` is not suitable. To prevent shell injection, never interpolate untrusted values directly into the script body. Any value that originates from user input — including `github.event.issue.title`, `github.event.issue.body`, `github.event.comment.body`, `github.event.pull_request.title`, `github.event.pull_request.body`, and `github.head_ref` — must be passed through environment variables:

```yaml
# ❌ Unsafe: direct expression interpolation into the shell script
- name: Unsafe comment
run: gh issue comment ${{ github.event.issue.number }} --body "${{ github.event.issue.title }}"

# ✅ Safe: pass untrusted values through env vars and reference them as $VAR_NAME
- name: Safe comment
env:
ISSUE_NUMBER: ${{ github.event.issue.number }}
TITLE: ${{ github.event.issue.title }}
run: gh issue comment "$ISSUE_NUMBER" --body "$TITLE"
```

### 3. Python (last resort)

Use Python only when the task genuinely requires data science or numeric libraries (for example `pandas`, `numpy`, `matplotlib`). Prefer `actions/github-script` or a shell step for everything else.

## Pre-Step Data Fetching Pattern

Use deterministic `steps:` when the workflow needs large external data before the agent runs.
Expand Down