From 61ac06e4f058b300f3d7d1c9e7a06e76177d7280 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 1 Apr 2026 16:31:03 +0000
Subject: [PATCH 1/2] Initial plan
From f24f88061d07cb06e5011cc19e88652c35ac4d27 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 1 Apr 2026 17:21:03 +0000
Subject: [PATCH 2/2] fix: reject env.* expressions in markdown expression
safety validator
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/0ddb843d-8013-4637-820f-6a8c0a613b9f
Co-authored-by: szabta89 <1330202+szabta89@users.noreply.github.com>
---
.github/workflows/contribution-check.lock.yml | 44 ++++++++++---------
.github/workflows/contribution-check.md | 17 ++++---
.../workflows/stale-repo-identifier.lock.yml | 38 ++++++++--------
.github/workflows/stale-repo-identifier.md | 2 +-
pkg/workflow/compile_outputs_label_test.go | 4 +-
pkg/workflow/expression_patterns.go | 5 ---
pkg/workflow/expression_safety_test.go | 25 ++++++++---
pkg/workflow/expression_safety_validation.go | 9 ----
pkg/workflow/expressions_benchmark_test.go | 8 ----
9 files changed, 76 insertions(+), 76 deletions(-)
diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml
index 24aa7f2ced..e496c238c7 100644
--- a/.github/workflows/contribution-check.lock.yml
+++ b/.github/workflows/contribution-check.lock.yml
@@ -21,7 +21,7 @@
# For more information: https://github.github.com/gh-aw/introduction/overview/
#
#
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"c6a3f4c1233714c024d91fc9b1c524d86770132bae2044a11ce34b31aeaaa870","strict":true,"agent_id":"copilot"}
+# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"4b68545cfafcc1dcec82b1a16b740e999c87dc384cd5652a8366c7766b2b8af8","strict":true,"agent_id":"copilot"}
name: "Contribution Check"
"on":
@@ -35,6 +35,10 @@ name: "Contribution Check"
description: Agent caller context (used internally by Agentic Workflows).
required: false
type: string
+ target_repository:
+ description: Target repository to check (owner/repo format, defaults to vars.TARGET_REPOSITORY or current repository)
+ required: false
+ type: string
permissions: {}
@@ -44,7 +48,7 @@ concurrency:
run-name: "Contribution Check"
env:
- TARGET_REPOSITORY: ${{ vars.TARGET_REPOSITORY || github.repository }}
+ TARGET_REPOSITORY: ${{ github.event.inputs.target_repository || vars.TARGET_REPOSITORY || github.repository }}
jobs:
activation:
@@ -123,7 +127,7 @@ jobs:
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_ENV_TARGET_REPOSITORY: ${{ env.TARGET_REPOSITORY }}
+ GH_AW_EXPR_328DA439: ${{ github.event.inputs.target_repository || github.repository }}
GH_AW_GITHUB_ACTOR: ${{ github.actor }}
GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
@@ -136,14 +140,14 @@ jobs:
run: |
bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh
{
- cat << 'GH_AW_PROMPT_c5fafbe77bac02c3_EOF'
+ cat << 'GH_AW_PROMPT_4392e8a2bceea61f_EOF'
- GH_AW_PROMPT_c5fafbe77bac02c3_EOF
+ GH_AW_PROMPT_4392e8a2bceea61f_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_c5fafbe77bac02c3_EOF'
+ cat << 'GH_AW_PROMPT_4392e8a2bceea61f_EOF'
Tools: add_comment(max:10), create_issue, add_labels(max:4), missing_tool, missing_data, noop
@@ -175,18 +179,18 @@ jobs:
{{/if}}
- GH_AW_PROMPT_c5fafbe77bac02c3_EOF
+ GH_AW_PROMPT_4392e8a2bceea61f_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_c5fafbe77bac02c3_EOF'
+ cat << 'GH_AW_PROMPT_4392e8a2bceea61f_EOF'
{{#runtime-import .github/workflows/contribution-check.md}}
- GH_AW_PROMPT_c5fafbe77bac02c3_EOF
+ GH_AW_PROMPT_4392e8a2bceea61f_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_ENV_TARGET_REPOSITORY: ${{ env.TARGET_REPOSITORY }}
+ GH_AW_EXPR_328DA439: ${{ github.event.inputs.target_repository || github.repository }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
with:
script: |
@@ -198,7 +202,7 @@ jobs:
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_ENV_TARGET_REPOSITORY: ${{ env.TARGET_REPOSITORY }}
+ GH_AW_EXPR_328DA439: ${{ github.event.inputs.target_repository || github.repository }}
GH_AW_GITHUB_ACTOR: ${{ github.actor }}
GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
@@ -218,7 +222,7 @@ jobs:
return await substitutePlaceholders({
file: process.env.GH_AW_PROMPT,
substitutions: {
- GH_AW_ENV_TARGET_REPOSITORY: process.env.GH_AW_ENV_TARGET_REPOSITORY,
+ GH_AW_EXPR_328DA439: process.env.GH_AW_EXPR_328DA439,
GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
@@ -344,12 +348,12 @@ jobs:
mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_6bec1d2b7f53adff_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_47c180542f667831_EOF'
{"add_comment":{"hide_older_comments":true,"max":10,"target":"*","target-repo":"${{ vars.TARGET_REPOSITORY }}"},"add_labels":{"allowed":["spam","needs-work","outdated","lgtm"],"max":4,"target":"*","target-repo":"${{ vars.TARGET_REPOSITORY }}"},"create_issue":{"close_older_issues":true,"expires":24,"group_by_day":true,"labels":["contribution-report"],"max":1,"title_prefix":"[Contribution Check Report]"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"}}
- GH_AW_SAFE_OUTPUTS_CONFIG_6bec1d2b7f53adff_EOF
+ GH_AW_SAFE_OUTPUTS_CONFIG_47c180542f667831_EOF
- name: Write Safe Outputs Tools
run: |
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_d7a7258648455683_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_4649ff9110f7be7a_EOF'
{
"description_suffixes": {
"add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *. Comments will be added in repository \"${{ vars.TARGET_REPOSITORY }}\".",
@@ -359,8 +363,8 @@ jobs:
"repo_params": {},
"dynamic_tools": []
}
- GH_AW_SAFE_OUTPUTS_TOOLS_META_d7a7258648455683_EOF
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_13a38a731c2dd3c1_EOF'
+ GH_AW_SAFE_OUTPUTS_TOOLS_META_4649ff9110f7be7a_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_6d4b65be77253df0_EOF'
{
"add_comment": {
"defaultMax": 1,
@@ -490,7 +494,7 @@ jobs:
}
}
}
- GH_AW_SAFE_OUTPUTS_VALIDATION_13a38a731c2dd3c1_EOF
+ GH_AW_SAFE_OUTPUTS_VALIDATION_6d4b65be77253df0_EOF
node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
@@ -556,7 +560,7 @@ jobs:
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.11'
mkdir -p /home/runner/.copilot
- cat << GH_AW_MCP_CONFIG_2eaf8996402089a2_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
+ cat << GH_AW_MCP_CONFIG_806698049c5bb346_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
{
"mcpServers": {
"github": {
@@ -600,7 +604,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_2eaf8996402089a2_EOF
+ GH_AW_MCP_CONFIG_806698049c5bb346_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
diff --git a/.github/workflows/contribution-check.md b/.github/workflows/contribution-check.md
index 708bee21c6..10a544647e 100644
--- a/.github/workflows/contribution-check.md
+++ b/.github/workflows/contribution-check.md
@@ -3,6 +3,11 @@ name: "Contribution Check"
on:
schedule: "every 4 hours"
workflow_dispatch:
+ inputs:
+ target_repository:
+ description: "Target repository to check (owner/repo format, defaults to vars.TARGET_REPOSITORY or current repository)"
+ required: false
+ type: string
permissions:
contents: read
@@ -10,7 +15,7 @@ permissions:
pull-requests: read
env:
- TARGET_REPOSITORY: ${{ vars.TARGET_REPOSITORY || github.repository }}
+ TARGET_REPOSITORY: ${{ github.event.inputs.target_repository || vars.TARGET_REPOSITORY || github.repository }}
tools:
github:
@@ -39,7 +44,7 @@ safe-outputs:
## Target Repository
-The target repository is `${{ env.TARGET_REPOSITORY }}`. All PR fetching and subagent dispatch use this value.
+The target repository is `${{ github.event.inputs.target_repository || github.repository }}`. All PR fetching and subagent dispatch use this value.
## Overview
@@ -49,7 +54,7 @@ You do NOT evaluate PRs yourself. You delegate each evaluation to `.github/agent
## Pre-filtered PR List
-A `pre-agent` step has already queried and filtered PRs from `${{ env.TARGET_REPOSITORY }}`. The results are in `pr-filter-results.json` at the workspace root. Read this file first. It contains:
+A `pre-agent` step has already queried and filtered PRs from `${{ github.event.inputs.target_repository || github.repository }}`. The results are in `pr-filter-results.json` at the workspace root. Read this file first. It contains:
```json
{
@@ -70,7 +75,7 @@ For each PR number in the comma-separated list, delegate evaluation to the **con
Call the contribution-checker subagent for each PR with this prompt:
```
-Evaluate PR ${{ env.TARGET_REPOSITORY }}# against the contribution guidelines.
+Evaluate PR ${{ github.event.inputs.target_repository || github.repository }}# against the contribution guidelines.
```
The subagent accepts any `owner/repo#number` reference — the target repo is not hardcoded.
@@ -176,9 +181,9 @@ If any subagent call failed (❓), also apply `outdated`.
- **You are the orchestrator** — you dispatch and compile. You do NOT run the checklist yourself.
- **PR fetching and filtering is pre-computed** — a `pre-agent` step writes `pr-filter-results.json`. Read it at the start.
- **Subagent does the analysis** — `.github/agents/contribution-checker.agent.md` handles all per-PR evaluation logic.
-- **Read from `${{ env.TARGET_REPOSITORY }}`** — read-only access via GitHub MCP tools.
+- **Read from `${{ github.event.inputs.target_repository || github.repository }}`** — read-only access via GitHub MCP tools.
- **Write to `${{ github.repository }}`** — reports go here as issues.
-- **Use safe output tools for target repository interactions** — use `add-comment` and `add-labels` safe output tools to post comments and labels to PRs in the target repository `${{ env.TARGET_REPOSITORY }}`. Never use `gh` CLI or direct API calls for writes.
+- **Use safe output tools for target repository interactions** — use `add-comment` and `add-labels` safe output tools to post comments and labels to PRs in the target repository `${{ github.event.inputs.target_repository || github.repository }}`. Never use `gh` CLI or direct API calls for writes.
- Close the previous report issue when creating a new one (`close-older-issues: true`).
- Be constructive in assessments — these reports help maintainers prioritize, not gatekeep.
diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml
index 63a5d85422..a21bb4efbe 100644
--- a/.github/workflows/stale-repo-identifier.lock.yml
+++ b/.github/workflows/stale-repo-identifier.lock.yml
@@ -29,7 +29,7 @@
# - shared/reporting.md
# - shared/trending-charts-simple.md
#
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"32da181169b45c3331196c90b357916a58548257641ff3b48b5bd98db44144fc","strict":true,"agent_id":"copilot"}
+# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"8657105a364ca871e2a61c98b3366f368db26b09738a35bea2d0e3c8179d5bac","strict":true,"agent_id":"copilot"}
name: "Stale Repository Identifier"
"on":
@@ -135,7 +135,7 @@ jobs:
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
- GH_AW_ENV_ORGANIZATION: ${{ env.ORGANIZATION }}
+ GH_AW_EXPR_BD84B27F: ${{ github.event.inputs.organization || 'github' }}
GH_AW_GITHUB_ACTOR: ${{ github.actor }}
GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
@@ -148,15 +148,15 @@ jobs:
run: |
bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh
{
- cat << 'GH_AW_PROMPT_04cc7f07fb47b59f_EOF'
+ cat << 'GH_AW_PROMPT_71feae30af7b6081_EOF'
- GH_AW_PROMPT_04cc7f07fb47b59f_EOF
+ GH_AW_PROMPT_71feae30af7b6081_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_04cc7f07fb47b59f_EOF'
+ cat << 'GH_AW_PROMPT_71feae30af7b6081_EOF'
Tools: create_issue(max:10), upload_asset, missing_tool, missing_data, noop
@@ -190,22 +190,22 @@ jobs:
{{/if}}
- GH_AW_PROMPT_04cc7f07fb47b59f_EOF
+ GH_AW_PROMPT_71feae30af7b6081_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_04cc7f07fb47b59f_EOF'
+ cat << 'GH_AW_PROMPT_71feae30af7b6081_EOF'
{{#runtime-import .github/workflows/shared/python-dataviz.md}}
{{#runtime-import .github/workflows/shared/jqschema.md}}
{{#runtime-import .github/workflows/shared/trending-charts-simple.md}}
{{#runtime-import .github/workflows/shared/reporting.md}}
{{#runtime-import .github/workflows/stale-repo-identifier.md}}
- GH_AW_PROMPT_04cc7f07fb47b59f_EOF
+ GH_AW_PROMPT_71feae30af7b6081_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_ENV_ORGANIZATION: ${{ env.ORGANIZATION }}
+ GH_AW_EXPR_BD84B27F: ${{ github.event.inputs.organization || 'github' }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
with:
@@ -221,7 +221,7 @@ jobs:
GH_AW_ALLOWED_EXTENSIONS: ''
GH_AW_CACHE_DESCRIPTION: ''
GH_AW_CACHE_DIR: '/tmp/gh-aw/cache-memory/'
- GH_AW_ENV_ORGANIZATION: ${{ env.ORGANIZATION }}
+ GH_AW_EXPR_BD84B27F: ${{ github.event.inputs.organization || 'github' }}
GH_AW_GITHUB_ACTOR: ${{ github.actor }}
GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }}
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }}
@@ -244,7 +244,7 @@ jobs:
GH_AW_ALLOWED_EXTENSIONS: process.env.GH_AW_ALLOWED_EXTENSIONS,
GH_AW_CACHE_DESCRIPTION: process.env.GH_AW_CACHE_DESCRIPTION,
GH_AW_CACHE_DIR: process.env.GH_AW_CACHE_DIR,
- GH_AW_ENV_ORGANIZATION: process.env.GH_AW_ENV_ORGANIZATION,
+ GH_AW_EXPR_BD84B27F: process.env.GH_AW_EXPR_BD84B27F,
GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID,
GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER,
@@ -447,12 +447,12 @@ jobs:
mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_31a537358bb21b4d_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_e9b68add426057cf_EOF'
{"create_issue":{"expires":48,"group":true,"labels":["stale-repository","automated-analysis","cookie"],"max":10,"title_prefix":"[Stale Repository] "},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"upload_asset":{"allowed-exts":[".png",".jpg",".jpeg"],"branch":"assets/${{ github.workflow }}","max-size":10240}}
- GH_AW_SAFE_OUTPUTS_CONFIG_31a537358bb21b4d_EOF
+ GH_AW_SAFE_OUTPUTS_CONFIG_e9b68add426057cf_EOF
- name: Write Safe Outputs Tools
run: |
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_0c8110d127c8bd31_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_ebcd95f9c9be27ef_EOF'
{
"description_suffixes": {
"create_issue": " CONSTRAINTS: Maximum 10 issue(s) can be created. Title will be prefixed with \"[Stale Repository] \". Labels [\"stale-repository\" \"automated-analysis\" \"cookie\"] will be automatically added.",
@@ -461,8 +461,8 @@ jobs:
"repo_params": {},
"dynamic_tools": []
}
- GH_AW_SAFE_OUTPUTS_TOOLS_META_0c8110d127c8bd31_EOF
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_b481a899eceb925d_EOF'
+ GH_AW_SAFE_OUTPUTS_TOOLS_META_ebcd95f9c9be27ef_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_04772e10e86be072_EOF'
{
"create_issue": {
"defaultMax": 1,
@@ -564,7 +564,7 @@ jobs:
}
}
}
- GH_AW_SAFE_OUTPUTS_VALIDATION_b481a899eceb925d_EOF
+ GH_AW_SAFE_OUTPUTS_VALIDATION_04772e10e86be072_EOF
node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
@@ -633,7 +633,7 @@ jobs:
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.11'
mkdir -p /home/runner/.copilot
- cat << GH_AW_MCP_CONFIG_8bf3865cd00153cd_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
+ cat << GH_AW_MCP_CONFIG_2d6f126c636c1d87_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
{
"mcpServers": {
"github": {
@@ -677,7 +677,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_8bf3865cd00153cd_EOF
+ GH_AW_MCP_CONFIG_2d6f126c636c1d87_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
diff --git a/.github/workflows/stale-repo-identifier.md b/.github/workflows/stale-repo-identifier.md
index 634373c479..fb60ee5e51 100644
--- a/.github/workflows/stale-repo-identifier.md
+++ b/.github/workflows/stale-repo-identifier.md
@@ -104,7 +104,7 @@ Analyze repositories identified as potentially stale by the stale-repos tool and
## Context
-- **Organization**: ${{ env.ORGANIZATION }}
+- **Organization**: ${{ github.event.inputs.organization || 'github' }}
- **Inactive Threshold**: 365 days
- **Exempt Topics**: keep, template
- **Repository**: ${{ github.repository }}
diff --git a/pkg/workflow/compile_outputs_label_test.go b/pkg/workflow/compile_outputs_label_test.go
index 608778231c..8489642fb2 100644
--- a/pkg/workflow/compile_outputs_label_test.go
+++ b/pkg/workflow/compile_outputs_label_test.go
@@ -204,7 +204,7 @@ safe-outputs:
# Test Output Label No Allowed Labels
This workflow tests label addition with no allowed labels restriction.
-Write your labels to ${{ env.GH_AW_SAFE_OUTPUTS }}, one per line.
+Write your labels using the safe output mechanism, one per line.
`
testFile := filepath.Join(tmpDir, "test-label-no-allowed.md")
@@ -281,7 +281,7 @@ safe-outputs:
# Test Output Label Null Config
This workflow tests label addition with null configuration (any labels allowed).
-Write your labels to ${{ env.GH_AW_SAFE_OUTPUTS }}, one per line.
+Write your labels using the safe output mechanism, one per line.
`
testFile := filepath.Join(tmpDir, "test-label-null-config.md")
diff --git a/pkg/workflow/expression_patterns.go b/pkg/workflow/expression_patterns.go
index 20385fe3fe..e6e5dc2c07 100644
--- a/pkg/workflow/expression_patterns.go
+++ b/pkg/workflow/expression_patterns.go
@@ -16,7 +16,6 @@
// - InputsPattern - Matches github.event.inputs.* patterns
// - WorkflowCallInputsPattern - Matches inputs.* patterns (workflow_call)
// - AWInputsPattern - Matches github.aw.inputs.* patterns
-// - EnvPattern - Matches env.* patterns
//
// ## Secret Patterns
// - SecretExpressionPattern - Matches ${{ secrets.SECRET_NAME }} expressions
@@ -111,10 +110,6 @@ var (
// Captures the full dotted path after "import-inputs." (e.g. "count" or "config.apiKey").
// Used for substitution of values provided via the 'with' key in import specifications.
AWImportInputsExpressionPattern = regexp.MustCompile(`\$\{\{\s*github\.aw\.import-inputs\.([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)?)\s*\}\}`)
-
- // EnvPattern matches env.* patterns
- // Example: env.NODE_VERSION
- EnvPattern = regexp.MustCompile(`^env\.[a-zA-Z0-9_-]+$`)
)
// Secret Patterns
diff --git a/pkg/workflow/expression_safety_test.go b/pkg/workflow/expression_safety_test.go
index cc4410ce32..88dcf041cf 100644
--- a/pkg/workflow/expression_safety_test.go
+++ b/pkg/workflow/expression_safety_test.go
@@ -122,9 +122,22 @@ func TestValidateExpressionSafety(t *testing.T) {
expectError: false,
},
{
- name: "authorized_env_variable",
- content: "Environment: ${{ env.MY_VAR }}",
- expectError: false,
+ name: "blocked_env_variable",
+ content: "Environment: ${{ env.MY_VAR }}",
+ expectError: true,
+ expectedErrors: []string{"env.MY_VAR"},
+ },
+ {
+ name: "blocked_env_github_token",
+ content: "Token: ${{ env.GITHUB_TOKEN }}",
+ expectError: true,
+ expectedErrors: []string{"env.GITHUB_TOKEN"},
+ },
+ {
+ name: "blocked_env_underscore",
+ content: "Config: ${{ env.NODE_VERSION }}",
+ expectError: true,
+ expectedErrors: []string{"env.NODE_VERSION"},
},
{
name: "unauthorized_steps_output",
@@ -143,7 +156,7 @@ func TestValidateExpressionSafety(t *testing.T) {
name: "multiple_unauthorized_expressions",
content: "Token: ${{ secrets.GITHUB_TOKEN }}, Valid: ${{ github.actor }}, Env: ${{ env.TEST }}",
expectError: true,
- expectedErrors: []string{"secrets.GITHUB_TOKEN"},
+ expectedErrors: []string{"secrets.GITHUB_TOKEN", "env.TEST"},
},
{
name: "expressions_with_whitespace",
@@ -408,11 +421,11 @@ func TestValidateExpressionSafetyWithParser(t *testing.T) {
- **Working directory**: ${{ github.workspace }}`,
wantErr: false,
},
- // env.* with defaults
+ // env.* with defaults -- env.* is blocked, so this should error even with a fallback
{
name: "env variable with string default",
content: `${{ env.LOG_LEVEL || 'info' }}`,
- wantErr: false,
+ wantErr: true,
},
}
diff --git a/pkg/workflow/expression_safety_validation.go b/pkg/workflow/expression_safety_validation.go
index ba6771196f..c807ecbcf3 100644
--- a/pkg/workflow/expression_safety_validation.go
+++ b/pkg/workflow/expression_safety_validation.go
@@ -29,7 +29,6 @@ var (
workflowCallInputsRegex = regexp.MustCompile(`^inputs\.[a-zA-Z0-9_-]+$`)
awInputsRegex = regexp.MustCompile(`^github\.aw\.inputs\.[a-zA-Z0-9_-]+$`)
awImportInputsRegex = regexp.MustCompile(`^github\.aw\.import-inputs\.[a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)?$`)
- envRegex = regexp.MustCompile(`^env\.[a-zA-Z0-9_-]+$`)
// comparisonExtractionRegex extracts property accesses from comparison expressions
// Matches patterns like "github.workflow == 'value'" and extracts "github.workflow"
comparisonExtractionRegex = regexp.MustCompile(`([a-zA-Z_][a-zA-Z0-9_.]*)\s*(?:==|!=|<|>|<=|>=)\s*`)
@@ -72,7 +71,6 @@ func validateExpressionSafety(markdownContent string) error {
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
AwImportInputsRe: awImportInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExpressions,
})
})
@@ -87,7 +85,6 @@ func validateExpressionSafety(markdownContent string) error {
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
AwImportInputsRe: awImportInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExpressions,
})
if err != nil {
@@ -128,7 +125,6 @@ func validateExpressionSafety(markdownContent string) error {
allowedList.WriteString(" - github.aw.inputs.* (shared workflow inputs)\n")
allowedList.WriteString(" - github.aw.import-inputs.* (import-schema inputs)\n")
allowedList.WriteString(" - inputs.* (workflow_call)\n")
- allowedList.WriteString(" - env.*\n")
return NewValidationError(
"expressions",
@@ -149,7 +145,6 @@ type ExpressionValidationOptions struct {
WorkflowCallInputsRe *regexp.Regexp
AwInputsRe *regexp.Regexp
AwImportInputsRe *regexp.Regexp
- EnvRe *regexp.Regexp
UnauthorizedExpressions *[]string
}
@@ -214,8 +209,6 @@ func validateSingleExpression(expression string, opts ExpressionValidationOption
allowed = true
} else if opts.AwImportInputsRe != nil && opts.AwImportInputsRe.MatchString(expression) {
allowed = true
- } else if opts.EnvRe.MatchString(expression) {
- allowed = true
} else if slices.Contains(constants.AllowedExpressions, expression) {
allowed = true
}
@@ -272,8 +265,6 @@ func validateSingleExpression(expression string, opts ExpressionValidationOption
propertyAllowed = true
} else if opts.AwImportInputsRe != nil && opts.AwImportInputsRe.MatchString(property) {
propertyAllowed = true
- } else if opts.EnvRe.MatchString(property) {
- propertyAllowed = true
} else if slices.Contains(constants.AllowedExpressions, property) {
propertyAllowed = true
}
diff --git a/pkg/workflow/expressions_benchmark_test.go b/pkg/workflow/expressions_benchmark_test.go
index a1ec1d6582..fa99f736f9 100644
--- a/pkg/workflow/expressions_benchmark_test.go
+++ b/pkg/workflow/expressions_benchmark_test.go
@@ -17,7 +17,6 @@ func BenchmarkValidateExpression(b *testing.B) {
InputsRe: inputsRegex,
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExprs,
})
}
@@ -34,7 +33,6 @@ func BenchmarkValidateExpression_Complex(b *testing.B) {
InputsRe: inputsRegex,
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExprs,
})
}
@@ -51,7 +49,6 @@ func BenchmarkValidateExpression_NeedsOutputs(b *testing.B) {
InputsRe: inputsRegex,
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExprs,
})
}
@@ -68,7 +65,6 @@ func BenchmarkValidateExpression_StepsOutputs(b *testing.B) {
InputsRe: inputsRegex,
WorkflowCallInputsRe: workflowCallInputsRegex,
AwInputsRe: awInputsRegex,
- EnvRe: envRegex,
UnauthorizedExpressions: &unauthorizedExprs,
})
}
@@ -123,10 +119,6 @@ func BenchmarkValidateExpressionSafety_Complex(b *testing.B) {
- Environment: ${{ github.event.inputs.environment }}
- Debug Mode: ${{ github.event.inputs.debug }}
- Target: ${{ github.event.inputs.target }}
-
-## Env Variables
-- Config: ${{ env.CONFIG_PATH }}
-- Mode: ${{ env.DEPLOYMENT_MODE }}
`
for b.Loop() {