Skip to content

recompile: regenerate lock files after second main merge #161

recompile: regenerate lock files after second main merge

recompile: regenerate lock files after second main merge #161

#

Check failure on line 1 in .github/workflows/daily-performance-summary.lock.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/daily-performance-summary.lock.yml

Invalid workflow file

(Line: 277, Col: 19): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME || '/opt/gh-aw', (Line: 279, Col: 27): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME, (Line: 280, Col: 39): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME, (Line: 281, Col: 38): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME, (Line: 1464, Col: 19): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME || '/opt/gh-aw', (Line: 1579, Col: 19): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME || '/opt/gh-aw', (Line: 1646, Col: 19): Unrecognized named-value: 'env'. Located at position 1 within expression: env.GH_AW_HOME || '/opt/gh-aw'
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
# | _ |/ _` |/ _ \ '_ \| __| |/ __|
# | | | | (_| | __/ | | | |_| | (__
# \_| |_/\__, |\___|_| |_|\__|_|\___|
# __/ |
# _ _ |___/
# | | | | / _| |
# | | | | ___ _ __ _ __| |_| | _____ ____
# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
# This file was automatically generated by gh-aw. DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
# Not all edits will cause changes to this file.
#
# For more information: https://github.github.com/gh-aw/introduction/overview/
#
# Daily project performance summary (90-day window) with trend charts using mcp-scripts
#
# Resolved workflow manifest:
# Imports:
# - shared/github-queries-mcp-script.md
# - shared/reporting.md
# - shared/trending-charts-simple.md
#
# gh-aw-metadata: {"schema_version":"v2","frontmatter_hash":"c93c3cce9fe58a74b02303d790120c6508d3d4d0bf95bb4fc24c36df3847efd0","strict":true}
name: "Daily Project Performance Summary Generator (Using MCP Scripts)"
"on":
schedule:
- cron: "26 19 * * *"
# Friendly format: daily (scattered)
workflow_dispatch:
permissions: {}
concurrency:
group: "gh-aw-${{ github.workflow }}"
run-name: "Daily Project Performance Summary Generator (Using MCP Scripts)"
jobs:
activation:
runs-on: ubuntu-slim
permissions:
contents: read
outputs:
comment_id: ""
comment_repo: ""
model: ${{ steps.generate_aw_info.outputs.model }}
secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
GH_AW_INFO_VERSION: ""
GH_AW_INFO_AGENT_VERSION: "latest"
GH_AW_INFO_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","python"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
GH_AW_INFO_AWF_VERSION: "v0.24.2"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { main } = require(process.env.GH_AW_HOME + '/actions/generate_aw_info.cjs');
await main(core, context);
- name: Validate COPILOT_GITHUB_TOKEN secret
id: validate-secret
run: ${GH_AW_HOME}/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- name: Checkout .github and .agents folders
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
sparse-checkout: |
.github
.agents
sparse-checkout-cone-mode: true
fetch-depth: 1
- name: Check workflow file timestamps
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_WORKFLOW_FILE: "daily-performance-summary.lock.yml"
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/check_workflow_timestamp_api.cjs');
await main();
- name: Create prompt with built-in context
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
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 }}
GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
run: |
bash ${GH_AW_HOME}/actions/create_prompt_first.sh
{
cat << 'GH_AW_PROMPT_EOF'
<system>
GH_AW_PROMPT_EOF
cat "${GH_AW_HOME}/prompts/xpia.md"
cat "${GH_AW_HOME}/prompts/temp_folder_prompt.md"
cat "${GH_AW_HOME}/prompts/markdown.md"
cat "${GH_AW_HOME}/prompts/cache_memory_prompt.md"
cat "${GH_AW_HOME}/prompts/safe_outputs_prompt.md"
cat << 'GH_AW_PROMPT_EOF'
<safe-output-tools>
Tools: create_discussion, close_discussion, upload_asset, missing_tool, missing_data, noop
upload_asset: provide a file path; returns a URL; assets are published after the workflow completes (safeoutputs).
</safe-output-tools>
<github-context>
The following GitHub context information is available for this workflow:
{{#if __GH_AW_GITHUB_ACTOR__ }}
- **actor**: __GH_AW_GITHUB_ACTOR__
{{/if}}
{{#if __GH_AW_GITHUB_REPOSITORY__ }}
- **repository**: __GH_AW_GITHUB_REPOSITORY__
{{/if}}
{{#if __GH_AW_GITHUB_WORKSPACE__ }}
- **workspace**: __GH_AW_GITHUB_WORKSPACE__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }}
- **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }}
- **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }}
- **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__
{{/if}}
{{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }}
- **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__
{{/if}}
{{#if __GH_AW_GITHUB_RUN_ID__ }}
- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
{{/if}}
</github-context>
GH_AW_PROMPT_EOF
cat "${GH_AW_HOME}/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
cat << 'GH_AW_PROMPT_EOF'
</system>
GH_AW_PROMPT_EOF
cat << 'GH_AW_PROMPT_EOF'
{{#runtime-import .github/workflows/shared/github-queries-mcp-script.md}}
GH_AW_PROMPT_EOF
cat << 'GH_AW_PROMPT_EOF'
{{#runtime-import .github/workflows/shared/trending-charts-simple.md}}
GH_AW_PROMPT_EOF
cat << 'GH_AW_PROMPT_EOF'
{{#runtime-import .github/workflows/shared/reporting.md}}
GH_AW_PROMPT_EOF
cat << 'GH_AW_PROMPT_EOF'
{{#runtime-import .github/workflows/daily-performance-summary.md}}
GH_AW_PROMPT_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_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/interpolate_prompt.cjs');
await main();
- name: Substitute placeholders
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_ALLOWED_EXTENSIONS: ''
GH_AW_CACHE_DESCRIPTION: ''
GH_AW_CACHE_DIR: '/tmp/gh-aw/cache-memory/'
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 }}
GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const substitutePlaceholders = require(process.env.GH_AW_HOME + '/actions/substitute_placeholders.cjs');
// Call the substitution function
return await substitutePlaceholders({
file: process.env.GH_AW_PROMPT,
substitutions: {
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_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,
GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER,
GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER,
GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE
}
});
- name: Validate prompt placeholders
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
run: bash ${GH_AW_HOME}/actions/validate_prompt_placeholders.sh
- name: Print prompt
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
run: bash ${GH_AW_HOME}/actions/print_prompt_summary.sh
- name: Upload activation artifact
if: success()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: activation
path: |
/tmp/gh-aw/aw_info.json
/tmp/gh-aw/aw-prompts/prompt.txt
retention-days: 1
agent:
needs: activation
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
discussions: read
issues: read
pull-requests: read
concurrency:
group: "gh-aw-copilot-${{ github.workflow }}"
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg"
GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}"
GH_AW_ASSETS_MAX_SIZE_KB: 10240
GH_AW_HOME: ${{ env.GH_AW_HOME || '/opt/gh-aw' }}
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_HOME }}/safeoutputs/outputs.jsonl
GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ env.GH_AW_HOME }}/safeoutputs/config.json
GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ env.GH_AW_HOME }}/safeoutputs/tools.json
GH_AW_WORKFLOW_ID_SANITIZED: dailyperformancesummary
outputs:
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
detection_success: ${{ steps.detection_conclusion.outputs.success }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
inference_access_error: ${{ steps.detect-inference-error.outputs.inference_access_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Create gh-aw temp directory
run: |
bash ${GH_AW_HOME}/actions/create_gh_aw_tmp_dir.sh
echo "GH_AW_SAFE_OUTPUTS=${GH_AW_HOME}/safeoutputs/outputs.jsonl" >> "$GITHUB_ENV"
echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${GH_AW_HOME}/safeoutputs/config.json" >> "$GITHUB_ENV"
echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${GH_AW_HOME}/safeoutputs/tools.json" >> "$GITHUB_ENV"
- name: Setup Python environment
run: |
mkdir -p /tmp/gh-aw/python/{data,charts,artifacts}
pip install --user --quiet numpy pandas matplotlib seaborn scipy
- if: always()
name: Upload charts
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
if-no-files-found: warn
name: trending-charts
path: /tmp/gh-aw/python/charts/*.png
retention-days: 30
- if: always()
name: Upload source files and data
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
if-no-files-found: warn
name: trending-source-and-data
path: |
/tmp/gh-aw/python/*.py
/tmp/gh-aw/python/data/*
retention-days: 30
# Cache memory file share configuration from frontmatter processed below
- name: Create cache-memory directory
run: bash ${GH_AW_HOME}/actions/create_cache_memory_dir.sh
- name: Restore cache-memory file share data
uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
key: trending-data-${{ github.workflow }}-${{ github.run_id }}
path: /tmp/gh-aw/cache-memory
restore-keys: |
trending-data-${{ github.workflow }}-
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Checkout PR branch
id: checkout-pr
if: |
(github.event.pull_request) || (github.event.issue.pull_request)
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
run: ${GH_AW_HOME}/actions/install_copilot_cli.sh latest
env:
GH_HOST: github.com
- name: Install AWF binary
run: bash ${GH_AW_HOME}/actions/install_awf_binary.sh v0.24.2
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
with:
script: |
const determineAutomaticLockdown = require(process.env.GH_AW_HOME + '/actions/determine_automatic_lockdown.cjs');
await determineAutomaticLockdown(github, context, core);
- name: Download container images
run: bash ${GH_AW_HOME}/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.24.2 ghcr.io/github/gh-aw-firewall/api-proxy:0.24.2 ghcr.io/github/gh-aw-firewall/squid:0.24.2 ghcr.io/github/gh-aw-mcpg:v0.1.15 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine
- name: Write Safe Outputs Config
run: |
mkdir -p ${GH_AW_HOME}/safeoutputs
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > ${GH_AW_HOME}/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_EOF'
{"close_discussion":{"max":10},"create_discussion":{"expires":72,"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"upload_asset":{"max":0}}
GH_AW_SAFE_OUTPUTS_CONFIG_EOF
- name: Write Safe Outputs Tools
run: |
cat > ${GH_AW_HOME}/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF'
{
"description_suffixes": {
"close_discussion": " CONSTRAINTS: Maximum 10 discussion(s) can be closed.",
"create_discussion": " CONSTRAINTS: Maximum 1 discussion(s) can be created. Title will be prefixed with \"[daily performance] \". Discussions will be created in category \"audits\".",
"upload_asset": " CONSTRAINTS: Maximum file size: 10240KB. Allowed file extensions: [.png .jpg .jpeg]."
},
"repo_params": {},
"dynamic_tools": []
}
GH_AW_SAFE_OUTPUTS_TOOLS_META_EOF
cat > ${GH_AW_HOME}/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_EOF'
{
"close_discussion": {
"defaultMax": 1,
"fields": {
"body": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"discussion_number": {
"optionalPositiveInteger": true
},
"reason": {
"type": "string",
"enum": [
"RESOLVED",
"DUPLICATE",
"OUTDATED",
"ANSWERED"
]
},
"repo": {
"type": "string",
"maxLength": 256
}
}
},
"create_discussion": {
"defaultMax": 1,
"fields": {
"body": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
},
"category": {
"type": "string",
"sanitize": true,
"maxLength": 128
},
"repo": {
"type": "string",
"maxLength": 256
},
"title": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 128
}
}
},
"missing_data": {
"defaultMax": 20,
"fields": {
"alternatives": {
"type": "string",
"sanitize": true,
"maxLength": 256
},
"context": {
"type": "string",
"sanitize": true,
"maxLength": 256
},
"data_type": {
"type": "string",
"sanitize": true,
"maxLength": 128
},
"reason": {
"type": "string",
"sanitize": true,
"maxLength": 256
}
}
},
"missing_tool": {
"defaultMax": 20,
"fields": {
"alternatives": {
"type": "string",
"sanitize": true,
"maxLength": 512
},
"reason": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 256
},
"tool": {
"type": "string",
"sanitize": true,
"maxLength": 128
}
}
},
"noop": {
"defaultMax": 1,
"fields": {
"message": {
"required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
}
}
},
"upload_asset": {
"defaultMax": 10,
"fields": {
"path": {
"required": true,
"type": "string"
}
}
}
}
GH_AW_SAFE_OUTPUTS_VALIDATION_EOF
node ${GH_AW_HOME}/actions/generate_safe_outputs_tools.cjs
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
run: |
# Generate a secure random API key (360 bits of entropy, 40+ chars)
# Mask immediately to prevent timing vulnerabilities
API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
echo "::add-mask::${API_KEY}"
PORT=3001
# Set outputs for next steps
{
echo "safe_outputs_api_key=${API_KEY}"
echo "safe_outputs_port=${PORT}"
} >> "$GITHUB_OUTPUT"
echo "Safe Outputs MCP server will run on port ${PORT}"
- name: Start Safe Outputs MCP HTTP Server
id: safe-outputs-start
env:
DEBUG: '*'
GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ env.GH_AW_HOME }}/safeoutputs/tools.json
GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ env.GH_AW_HOME }}/safeoutputs/config.json
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
run: |
# Environment variables are set above to prevent template injection
export DEBUG
export GH_AW_SAFE_OUTPUTS_PORT
export GH_AW_SAFE_OUTPUTS_API_KEY
export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
export GH_AW_MCP_LOG_DIR
bash ${GH_AW_HOME}/actions/start_safe_outputs_server.sh
- name: Setup MCP Scripts Config
run: |
mkdir -p ${GH_AW_HOME}/mcp-scripts/logs
cat > ${GH_AW_HOME}/mcp-scripts/tools.json << 'GH_AW_MCP_SCRIPTS_TOOLS_EOF'
{
"serverName": "mcpscripts",
"version": "1.0.0",
"logDir": "${GH_AW_HOME}/mcp-scripts/logs",
"tools": [
{
"name": "github-discussion-query",
"description": "Query GitHub discussions with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.",
"inputSchema": {
"properties": {
"jq": {
"description": "jq filter expression to apply to output. If not provided, returns schema info instead of full data.",
"type": "string"
},
"limit": {
"description": "Maximum number of discussions to fetch (default: 30)",
"type": "number"
},
"repo": {
"description": "Repository in owner/repo format (defaults to current repository)",
"type": "string"
}
},
"type": "object"
},
"handler": "github-discussion-query.sh",
"env": {
"GH_TOKEN": "GH_TOKEN"
},
"timeout": 60
},
{
"name": "github-issue-query",
"description": "Query GitHub issues with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.",
"inputSchema": {
"properties": {
"jq": {
"description": "jq filter expression to apply to output. If not provided, returns schema info instead of full data.",
"type": "string"
},
"limit": {
"description": "Maximum number of issues to fetch (default: 30)",
"type": "number"
},
"repo": {
"description": "Repository in owner/repo format (defaults to current repository)",
"type": "string"
},
"state": {
"description": "Issue state: open, closed, all (default: open)",
"type": "string"
}
},
"type": "object"
},
"handler": "github-issue-query.sh",
"env": {
"GH_TOKEN": "GH_TOKEN"
},
"timeout": 60
},
{
"name": "github-pr-query",
"description": "Query GitHub pull requests with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.",
"inputSchema": {
"properties": {
"jq": {
"description": "jq filter expression to apply to output. If not provided, returns schema info instead of full data.",
"type": "string"
},
"limit": {
"description": "Maximum number of PRs to fetch (default: 30)",
"type": "number"
},
"repo": {
"description": "Repository in owner/repo format (defaults to current repository)",
"type": "string"
},
"state": {
"description": "PR state: open, closed, merged, all (default: open)",
"type": "string"
}
},
"type": "object"
},
"handler": "github-pr-query.sh",
"env": {
"GH_TOKEN": "GH_TOKEN"
},
"timeout": 60
}
]
}
GH_AW_MCP_SCRIPTS_TOOLS_EOF
cat > ${GH_AW_HOME}/mcp-scripts/mcp-server.cjs << 'GH_AW_MCP_SCRIPTS_SERVER_EOF'
const path = require("path");
const { startHttpServer } = require("./mcp_scripts_mcp_server_http.cjs");
const configPath = path.join(__dirname, "tools.json");
const port = parseInt(process.env.GH_AW_MCP_SCRIPTS_PORT || "3000", 10);
const apiKey = process.env.GH_AW_MCP_SCRIPTS_API_KEY || "";
startHttpServer(configPath, {
port: port,
stateless: true,
logDir: process.env.GH_AW_HOME + "/mcp-scripts/logs"
}).catch(error => {
console.error("Failed to start mcp-scripts HTTP server:", error);
process.exit(1);
});
GH_AW_MCP_SCRIPTS_SERVER_EOF
chmod +x ${GH_AW_HOME}/mcp-scripts/mcp-server.cjs
- name: Setup MCP Scripts Tool Files
run: |
cat > ${GH_AW_HOME}/mcp-scripts/github-discussion-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-discussion-query
# Query GitHub discussions with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
set -euo pipefail
set -e
# Default values
REPO="${INPUT_REPO:-}"
LIMIT="${INPUT_LIMIT:-30}"
JQ_FILTER="${INPUT_JQ:-}"
# Parse repository owner and name
if [[ -n "$REPO" ]]; then
OWNER=$(echo "$REPO" | cut -d'/' -f1)
NAME=$(echo "$REPO" | cut -d'/' -f2)
else
# Get current repository from GitHub context
OWNER="${GITHUB_REPOSITORY_OWNER:-}"
NAME=$(echo "${GITHUB_REPOSITORY:-}" | cut -d'/' -f2)
fi
# Validate owner and name
if [[ -z "$OWNER" || -z "$NAME" ]]; then
echo "Error: Could not determine repository owner and name" >&2
exit 1
fi
# Build GraphQL query for discussions
GRAPHQL_QUERY=$(cat <<QUERY
{
repository(owner: "$OWNER", name: "$NAME") {
discussions(first: $LIMIT, orderBy: {field: CREATED_AT, direction: DESC}) {
nodes {
number
title
author {
login
}
createdAt
updatedAt
body
category {
name
}
labels(first: 10) {
nodes {
name
}
}
comments {
totalCount
}
answer {
id
}
url
}
}
}
}
QUERY
)
# Execute GraphQL query via gh api
GRAPHQL_OUTPUT=$(gh api graphql -f query="$GRAPHQL_QUERY")
# Transform GraphQL output to match gh discussion list format
OUTPUT=$(echo "$GRAPHQL_OUTPUT" | jq '[.data.repository.discussions.nodes[] | {
number: .number,
title: .title,
author: .author,
createdAt: .createdAt,
updatedAt: .updatedAt,
body: .body,
category: .category,
labels: .labels.nodes,
comments: .comments,
answer: .answer,
url: .url
}]')
# Apply jq filter if specified
if [[ -n "$JQ_FILTER" ]]; then
jq "$JQ_FILTER" <<< "$OUTPUT"
else
# Return schema and size instead of full data
ITEM_COUNT=$(jq 'length' <<< "$OUTPUT")
DATA_SIZE=${#OUTPUT}
# Validate values are numeric
if ! [[ "$ITEM_COUNT" =~ ^[0-9]+$ ]]; then
ITEM_COUNT=0
fi
if ! [[ "$DATA_SIZE" =~ ^[0-9]+$ ]]; then
DATA_SIZE=0
fi
cat << EOF
{
"message": "No --jq filter provided. Use --jq to filter and retrieve data.",
"item_count": $ITEM_COUNT,
"data_size_bytes": $DATA_SIZE,
"schema": {
"type": "array",
"description": "Array of discussion objects",
"item_fields": {
"number": "integer - Discussion number",
"title": "string - Discussion title",
"author": "object - Author info with login field",
"createdAt": "string - ISO timestamp of creation",
"updatedAt": "string - ISO timestamp of last update",
"body": "string - Discussion body content",
"category": "object - Category info with name field",
"labels": "array - Array of label objects with name field",
"comments": "object - Comments info with totalCount field",
"answer": "object|null - Accepted answer if exists",
"url": "string - Discussion URL"
}
},
"suggested_queries": [
{"description": "Get all data", "query": "."},
{"description": "Get discussion numbers and titles", "query": ".[] | {number, title}"},
{"description": "Get discussions by author", "query": ".[] | select(.author.login == \"USERNAME\")"},
{"description": "Get discussions in category", "query": ".[] | select(.category.name == \"Ideas\")"},
{"description": "Get answered discussions", "query": ".[] | select(.answer != null)"},
{"description": "Get unanswered discussions", "query": ".[] | select(.answer == null) | {number, title, category: .category.name}"},
{"description": "Count by category", "query": "group_by(.category.name) | map({category: .[0].category.name, count: length})"}
]
}
EOF
fi
GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_EOF
chmod +x ${GH_AW_HOME}/mcp-scripts/github-discussion-query.sh
cat > ${GH_AW_HOME}/mcp-scripts/github-issue-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-issue-query
# Query GitHub issues with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
set -euo pipefail
set -e
# Default values
REPO="${INPUT_REPO:-}"
STATE="${INPUT_STATE:-open}"
LIMIT="${INPUT_LIMIT:-30}"
JQ_FILTER="${INPUT_JQ:-}"
# JSON fields to fetch
JSON_FIELDS="number,title,state,author,createdAt,updatedAt,closedAt,body,labels,assignees,comments,milestone,url"
# Build and execute gh command
if [[ -n "$REPO" ]]; then
OUTPUT=$(gh issue list --state "$STATE" --limit "$LIMIT" --json "$JSON_FIELDS" --repo "$REPO")
else
OUTPUT=$(gh issue list --state "$STATE" --limit "$LIMIT" --json "$JSON_FIELDS")
fi
# Apply jq filter if specified
if [[ -n "$JQ_FILTER" ]]; then
jq "$JQ_FILTER" <<< "$OUTPUT"
else
# Return schema and size instead of full data
ITEM_COUNT=$(jq 'length' <<< "$OUTPUT")
DATA_SIZE=${#OUTPUT}
# Validate values are numeric
if ! [[ "$ITEM_COUNT" =~ ^[0-9]+$ ]]; then
ITEM_COUNT=0
fi
if ! [[ "$DATA_SIZE" =~ ^[0-9]+$ ]]; then
DATA_SIZE=0
fi
cat << EOF
{
"message": "No --jq filter provided. Use --jq to filter and retrieve data.",
"item_count": $ITEM_COUNT,
"data_size_bytes": $DATA_SIZE,
"schema": {
"type": "array",
"description": "Array of issue objects",
"item_fields": {
"number": "integer - Issue number",
"title": "string - Issue title",
"state": "string - Issue state (OPEN, CLOSED)",
"author": "object - Author info with login field",
"createdAt": "string - ISO timestamp of creation",
"updatedAt": "string - ISO timestamp of last update",
"closedAt": "string|null - ISO timestamp of close",
"body": "string - Issue body content",
"labels": "array - Array of label objects with name field",
"assignees": "array - Array of assignee objects with login field",
"comments": "object - Comments info with totalCount field",
"milestone": "object|null - Milestone info with title field",
"url": "string - Issue URL"
}
},
"suggested_queries": [
{"description": "Get all data", "query": "."},
{"description": "Get issue numbers and titles", "query": ".[] | {number, title}"},
{"description": "Get open issues only", "query": ".[] | select(.state == \"OPEN\")"},
{"description": "Get issues by author", "query": ".[] | select(.author.login == \"USERNAME\")"},
{"description": "Get issues with label", "query": ".[] | select(.labels | map(.name) | index(\"bug\"))"},
{"description": "Get issues with many comments", "query": ".[] | select(.comments.totalCount > 5) | {number, title, comments: .comments.totalCount}"},
{"description": "Count by state", "query": "group_by(.state) | map({state: .[0].state, count: length})"}
]
}
EOF
fi
GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_EOF
chmod +x ${GH_AW_HOME}/mcp-scripts/github-issue-query.sh
cat > ${GH_AW_HOME}/mcp-scripts/github-pr-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-pr-query
# Query GitHub pull requests with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
set -euo pipefail
set -e
# Default values
REPO="${INPUT_REPO:-}"
STATE="${INPUT_STATE:-open}"
LIMIT="${INPUT_LIMIT:-30}"
JQ_FILTER="${INPUT_JQ:-}"
# JSON fields to fetch
JSON_FIELDS="number,title,state,author,createdAt,updatedAt,mergedAt,closedAt,headRefName,baseRefName,isDraft,reviewDecision,additions,deletions,changedFiles,labels,assignees,reviewRequests,url"
# Build and execute gh command
if [[ -n "$REPO" ]]; then
OUTPUT=$(gh pr list --state "$STATE" --limit "$LIMIT" --json "$JSON_FIELDS" --repo "$REPO")
else
OUTPUT=$(gh pr list --state "$STATE" --limit "$LIMIT" --json "$JSON_FIELDS")
fi
# Apply jq filter if specified
if [[ -n "$JQ_FILTER" ]]; then
jq "$JQ_FILTER" <<< "$OUTPUT"
else
# Return schema and size instead of full data
ITEM_COUNT=$(jq 'length' <<< "$OUTPUT")
DATA_SIZE=${#OUTPUT}
# Validate values are numeric
if ! [[ "$ITEM_COUNT" =~ ^[0-9]+$ ]]; then
ITEM_COUNT=0
fi
if ! [[ "$DATA_SIZE" =~ ^[0-9]+$ ]]; then
DATA_SIZE=0
fi
cat << EOF
{
"message": "No --jq filter provided. Use --jq to filter and retrieve data.",
"item_count": $ITEM_COUNT,
"data_size_bytes": $DATA_SIZE,
"schema": {
"type": "array",
"description": "Array of pull request objects",
"item_fields": {
"number": "integer - PR number",
"title": "string - PR title",
"state": "string - PR state (OPEN, CLOSED, MERGED)",
"author": "object - Author info with login field",
"createdAt": "string - ISO timestamp of creation",
"updatedAt": "string - ISO timestamp of last update",
"mergedAt": "string|null - ISO timestamp of merge",
"closedAt": "string|null - ISO timestamp of close",
"headRefName": "string - Source branch name",
"baseRefName": "string - Target branch name",
"isDraft": "boolean - Whether PR is a draft",
"reviewDecision": "string|null - Review decision (APPROVED, CHANGES_REQUESTED, REVIEW_REQUIRED)",
"additions": "integer - Lines added",
"deletions": "integer - Lines deleted",
"changedFiles": "integer - Number of files changed",
"labels": "array - Array of label objects with name field",
"assignees": "array - Array of assignee objects with login field",
"reviewRequests": "array - Array of review request objects",
"url": "string - PR URL"
}
},
"suggested_queries": [
{"description": "Get all data", "query": "."},
{"description": "Get PR numbers and titles", "query": ".[] | {number, title}"},
{"description": "Get open PRs only", "query": ".[] | select(.state == \"OPEN\")"},
{"description": "Get merged PRs", "query": ".[] | select(.mergedAt != null)"},
{"description": "Get PRs by author", "query": ".[] | select(.author.login == \"USERNAME\")"},
{"description": "Get large PRs", "query": ".[] | select(.changedFiles > 10) | {number, title, changedFiles}"},
{"description": "Count by state", "query": "group_by(.state) | map({state: .[0].state, count: length})"}
]
}
EOF
fi
GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_EOF
chmod +x ${GH_AW_HOME}/mcp-scripts/github-pr-query.sh
- name: Generate MCP Scripts Server Config
id: mcp-scripts-config
run: |
# Generate a secure random API key (360 bits of entropy, 40+ chars)
# Mask immediately to prevent timing vulnerabilities
API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
echo "::add-mask::${API_KEY}"
PORT=3000
# Set outputs for next steps
{
echo "mcp_scripts_api_key=${API_KEY}"
echo "mcp_scripts_port=${PORT}"
} >> "$GITHUB_OUTPUT"
echo "MCP Scripts server will run on port ${PORT}"
- name: Start MCP Scripts HTTP Server
id: mcp-scripts-start
env:
DEBUG: '*'
GH_AW_MCP_SCRIPTS_PORT: ${{ steps.mcp-scripts-config.outputs.mcp_scripts_port }}
GH_AW_MCP_SCRIPTS_API_KEY: ${{ steps.mcp-scripts-config.outputs.mcp_scripts_api_key }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Environment variables are set above to prevent template injection
export DEBUG
export GH_AW_MCP_SCRIPTS_PORT
export GH_AW_MCP_SCRIPTS_API_KEY
bash ${GH_AW_HOME}/actions/start_mcp_scripts_server.sh
- name: Start MCP Gateway
id: start-mcp-gateway
env:
GH_AW_ASSETS_ALLOWED_EXTS: ${{ env.GH_AW_ASSETS_ALLOWED_EXTS }}
GH_AW_ASSETS_BRANCH: ${{ env.GH_AW_ASSETS_BRANCH }}
GH_AW_ASSETS_MAX_SIZE_KB: ${{ env.GH_AW_ASSETS_MAX_SIZE_KB }}
GH_AW_MCP_SCRIPTS_API_KEY: ${{ steps.mcp-scripts-start.outputs.api_key }}
GH_AW_MCP_SCRIPTS_PORT: ${{ steps.mcp-scripts-start.outputs.port }}
GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -eo pipefail
mkdir -p /tmp/gh-aw/mcp-config
# Export gateway environment variables for MCP config and gateway script
export MCP_GATEWAY_PORT="80"
export MCP_GATEWAY_DOMAIN="host.docker.internal"
MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
echo "::add-mask::${MCP_GATEWAY_API_KEY}"
export MCP_GATEWAY_API_KEY
export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
export DEBUG="*"
export GH_AW_ENGINE="copilot"
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_MCP_SCRIPTS_PORT -e GH_AW_MCP_SCRIPTS_API_KEY -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GH_TOKEN -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.1.15'
mkdir -p /home/runner/.copilot
cat << GH_AW_MCP_CONFIG_EOF | bash ${GH_AW_HOME}/actions/start_mcp_gateway.sh
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:v0.32.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
"GITHUB_READ_ONLY": "1",
"GITHUB_TOOLSETS": "context,repos,issues,pull_requests,discussions"
},
"guard-policies": {
"allow-only": {
"min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
"repos": "$GITHUB_MCP_GUARD_REPOS"
}
}
},
"mcpscripts": {
"type": "http",
"url": "http://host.docker.internal:$GH_AW_MCP_SCRIPTS_PORT",
"headers": {
"Authorization": "\${GH_AW_MCP_SCRIPTS_API_KEY}"
},
"guard-policies": {
"write-sink": {
"accept": [
"*"
]
}
}
},
"safeoutputs": {
"type": "http",
"url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
"headers": {
"Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
},
"guard-policies": {
"write-sink": {
"accept": [
"*"
]
}
}
}
},
"gateway": {
"port": $MCP_GATEWAY_PORT,
"domain": "${MCP_GATEWAY_DOMAIN}",
"apiKey": "${MCP_GATEWAY_API_KEY}",
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
GH_AW_MCP_CONFIG_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: activation
path: /tmp/gh-aw
- name: Clean git credentials
continue-on-error: true
run: bash ${GH_AW_HOME}/actions/clean_git_credentials.sh
- name: Execute GitHub Copilot CLI
id: agentic_execution
# Copilot CLI tool arguments (sorted):
timeout-minutes: 30
run: |
set -o pipefail
touch /tmp/gh-aw/agent-step-summary.md
# shellcheck disable=SC1003
sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.24.2 --skip-pull --enable-api-proxy \
-- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --add-dir /tmp/gh-aw/cache-memory/ --allow-all-paths --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }}
GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg"
GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}"
GH_AW_ASSETS_MAX_SIZE_KB: 10240
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
GH_AW_VERSION: dev
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_HEAD_REF: ${{ github.head_ref }}
GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
GITHUB_WORKSPACE: ${{ github.workspace }}
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
XDG_CONFIG_HOME: /home/runner
- name: Detect inference access error
id: detect-inference-error
if: always()
continue-on-error: true
run: bash ${GH_AW_HOME}/actions/detect_inference_access_error.sh
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Copy Copilot session state files to logs
if: always()
continue-on-error: true
run: |
# Copy Copilot session state files to logs folder for artifact collection
# This ensures they are in /tmp/gh-aw/ where secret redaction can scan them
SESSION_STATE_DIR="$HOME/.copilot/session-state"
LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs"
if [ -d "$SESSION_STATE_DIR" ]; then
echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR"
mkdir -p "$LOGS_DIR"
cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true
echo "Session state files copied successfully"
else
echo "No session-state directory found at $SESSION_STATE_DIR"
fi
- name: Stop MCP Gateway
if: always()
continue-on-error: true
env:
MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
run: |
bash ${GH_AW_HOME}/actions/stop_mcp_gateway.sh "$GATEWAY_PID"
- name: Redact secrets in logs
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/redact_secrets.cjs');
await main();
env:
GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Append agent step summary
if: always()
run: bash ${GH_AW_HOME}/actions/append_agent_step_summary.sh
- name: Copy Safe Outputs
if: always()
run: |
mkdir -p /tmp/gh-aw
cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
- name: Ingest agent output
id: collect_output
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }}
GH_AW_ALLOWED_DOMAINS: "*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/collect_ndjson_output.cjs');
await main();
- name: Parse agent logs for step summary
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/parse_copilot_log.cjs');
await main();
- name: Parse MCP Scripts logs for step summary
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/parse_mcp_scripts_logs.cjs');
await main();
- name: Parse MCP Gateway logs for step summary
if: always()
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/parse_mcp_gateway_log.cjs');
await main();
- name: Print firewall logs
if: always()
continue-on-error: true
env:
AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
run: |
# Fix permissions on firewall logs so they can be uploaded as artifacts
# AWF runs with sudo, creating files owned by root
sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true
# Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
if command -v awf &> /dev/null; then
awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
else
echo 'AWF binary not installed, skipping firewall log summary'
fi
- name: Upload cache-memory data as artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: always()
with:
name: cache-memory
path: /tmp/gh-aw/cache-memory
# Upload safe-outputs assets for upload_assets job
- name: Upload Safe Outputs assets
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: safe-outputs-assets
path: /tmp/gh-aw/safeoutputs/assets/
retention-days: 1
if-no-files-found: ignore
- name: Upload agent artifacts
if: always()
continue-on-error: true
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: agent
path: |
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/sandbox/agent/logs/
/tmp/gh-aw/redacted-urls.log
/tmp/gh-aw/mcp-logs/
/tmp/gh-aw/mcp-scripts/logs/
/tmp/gh-aw/sandbox/firewall/logs/
/tmp/gh-aw/agent-stdio.log
/tmp/gh-aw/agent/
/tmp/gh-aw/safeoutputs.jsonl
/tmp/gh-aw/agent_output.json
if-no-files-found: ignore
# --- Threat Detection (inline) ---
- name: Check if detection needed
id: detection_guard
if: always()
env:
OUTPUT_TYPES: ${{ steps.collect_output.outputs.output_types }}
HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
run: |
if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
echo "run_detection=true" >> "$GITHUB_OUTPUT"
echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
else
echo "run_detection=false" >> "$GITHUB_OUTPUT"
echo "Detection skipped: no agent outputs or patches to analyze"
fi
- name: Clear MCP configuration for detection
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
rm -f /tmp/gh-aw/mcp-config/mcp-servers.json
rm -f /home/runner/.copilot/mcp-config.json
rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
- name: Prepare threat detection files
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
done
echo "Prepared threat detection files:"
ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true
- name: Setup threat detection
if: always() && steps.detection_guard.outputs.run_detection == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
WORKFLOW_DESCRIPTION: "Daily project performance summary (90-day window) with trend charts using mcp-scripts"
HAS_PATCH: ${{ steps.collect_output.outputs.has_patch }}
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/setup_threat_detection.cjs');
await main();
- name: Ensure threat-detection directory and log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
run: |
mkdir -p /tmp/gh-aw/threat-detection
touch /tmp/gh-aw/threat-detection/detection.log
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
id: detection_agentic_execution
# Copilot CLI tool arguments (sorted):
# --allow-tool shell(cat)
# --allow-tool shell(grep)
# --allow-tool shell(head)
# --allow-tool shell(jq)
# --allow-tool shell(ls)
# --allow-tool shell(tail)
# --allow-tool shell(wc)
timeout-minutes: 20
run: |
set -o pipefail
touch /tmp/gh-aw/agent-step-summary.md
# shellcheck disable=SC1003
sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,github.com,host.docker.internal,raw.githubusercontent.com,registry.npmjs.org,telemetry.enterprise.githubcopilot.com" --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.24.2 --skip-pull --enable-api-proxy \
-- /bin/bash -c '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(wc)'\'' --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_VERSION: dev
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_HEAD_REF: ${{ github.head_ref }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
GITHUB_WORKSPACE: ${{ github.workspace }}
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
XDG_CONFIG_HOME: /home/runner
- name: Parse threat detection results
id: parse_detection_results
if: always() && steps.detection_guard.outputs.run_detection == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
with:
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/parse_threat_detection_results.cjs');
await main();
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: detection
path: /tmp/gh-aw/threat-detection/detection.log
if-no-files-found: ignore
- name: Set detection conclusion
id: detection_conclusion
if: always()
env:
RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
DETECTION_SUCCESS: ${{ steps.parse_detection_results.outputs.success }}
run: |
if [[ "$RUN_DETECTION" != "true" ]]; then
echo "conclusion=skipped" >> "$GITHUB_OUTPUT"
echo "success=true" >> "$GITHUB_OUTPUT"
echo "Detection was not needed, marking as skipped"
elif [[ "$DETECTION_SUCCESS" == "true" ]]; then
echo "conclusion=success" >> "$GITHUB_OUTPUT"
echo "success=true" >> "$GITHUB_OUTPUT"
echo "Detection passed successfully"
else
echo "conclusion=failure" >> "$GITHUB_OUTPUT"
echo "success=false" >> "$GITHUB_OUTPUT"
echo "Detection found issues"
fi
conclusion:
needs:
- activation
- agent
- safe_outputs
- update_cache_memory
- upload_assets
if: (always()) && (needs.agent.result != 'skipped')
runs-on: ubuntu-slim
permissions:
contents: write
discussions: write
issues: write
concurrency:
group: "gh-aw-conclusion-daily-performance-summary"
cancel-in-progress: false
env:
GH_AW_HOME: ${{ env.GH_AW_HOME || '/opt/gh-aw' }}
outputs:
noop_message: ${{ steps.noop.outputs.noop_message }}
tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
total_count: ${{ steps.missing_tool.outputs.total_count }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV"
- name: Process No-Op Messages
id: noop
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_TRACKER_ID: "daily-performance-summary"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/noop.cjs');
await main();
- name: Record Missing Tool
id: missing_tool
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_TRACKER_ID: "daily-performance-summary"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/missing_tool.cjs');
await main();
- name: Handle Agent Failure
id: handle_agent_failure
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_TRACKER_ID: "daily-performance-summary"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "daily-performance-summary"
GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
GH_AW_CREATE_DISCUSSION_ERRORS: ${{ needs.safe_outputs.outputs.create_discussion_errors }}
GH_AW_CREATE_DISCUSSION_ERROR_COUNT: ${{ needs.safe_outputs.outputs.create_discussion_error_count }}
GH_AW_GROUP_REPORTS: "false"
GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
GH_AW_TIMEOUT_MINUTES: "30"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/handle_agent_failure.cjs');
await main();
- name: Handle No-Op Message
id: handle_noop_message
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_TRACKER_ID: "daily-performance-summary"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/handle_noop_message.cjs');
await main();
safe_outputs:
needs: agent
if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.agent.outputs.detection_success == 'true')
runs-on: ubuntu-slim
permissions:
contents: write
discussions: write
issues: write
timeout-minutes: 15
env:
GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/daily-performance-summary"
GH_AW_ENGINE_ID: "copilot"
GH_AW_HOME: ${{ env.GH_AW_HOME || '/opt/gh-aw' }}
GH_AW_TRACKER_ID: "daily-performance-summary"
GH_AW_WORKFLOW_ID: "daily-performance-summary"
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV"
- name: Process Safe Outputs
id: process_safe_outputs
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_ALLOWED_DOMAINS: "*.pythonhosted.org,anaconda.org,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,binstar.org,bootstrap.pypa.io,conda.anaconda.org,conda.binstar.org,crates.io,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,files.pythonhosted.org,github.com,host.docker.internal,index.crates.io,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pip.pypa.io,ppa.launchpad.net,pypi.org,pypi.python.org,raw.githubusercontent.com,registry.npmjs.org,repo.anaconda.com,repo.continuum.io,s.symcb.com,s.symcd.com,security.ubuntu.com,static.crates.io,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"close_discussion\":{\"max\":10},\"create_discussion\":{\"category\":\"audits\",\"close_older_discussions\":true,\"expires\":72,\"fallback_to_issue\":true,\"max\":1,\"title_prefix\":\"[daily performance] \"},\"missing_data\":{},\"missing_tool\":{}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/safe_output_handler_manager.cjs');
await main();
- name: Upload Safe Output Items Manifest
if: always()
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: safe-output-items
path: /tmp/safe-output-items.jsonl
if-no-files-found: warn
update_cache_memory:
needs: agent
if: always() && needs.agent.outputs.detection_success == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
env:
GH_AW_HOME: ${{ env.GH_AW_HOME || '/opt/gh-aw' }}
GH_AW_WORKFLOW_ID_SANITIZED: dailyperformancesummary
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Download cache-memory artifact (default)
id: download_cache_default
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
continue-on-error: true
with:
name: cache-memory
path: /tmp/gh-aw/cache-memory
- name: Check if cache-memory folder has content (default)
id: check_cache_default
shell: bash
run: |
if [ -d "/tmp/gh-aw/cache-memory" ] && [ "$(ls -A /tmp/gh-aw/cache-memory 2>/dev/null)" ]; then
echo "has_content=true" >> "$GITHUB_OUTPUT"
else
echo "has_content=false" >> "$GITHUB_OUTPUT"
fi
- name: Save cache-memory to cache (default)
if: steps.check_cache_default.outputs.has_content == 'true'
uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
key: trending-data-${{ github.workflow }}-${{ github.run_id }}
path: /tmp/gh-aw/cache-memory
upload_assets:
needs: agent
if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'upload_asset'))
runs-on: ubuntu-slim
permissions:
contents: write
timeout-minutes: 10
outputs:
branch_name: ${{ steps.upload_assets.outputs.branch_name }}
published_count: ${{ steps.upload_assets.outputs.published_count }}
steps:
- name: Checkout actions folder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: github/gh-aw
sparse-checkout: |
actions
persist-credentials: false
- name: Setup Scripts
uses: ./actions/setup
with:
destination: ${{ env.GH_AW_HOME }}/actions
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
fetch-depth: 0
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
SERVER_URL: ${{ github.server_url }}
run: |
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git config --global am.keepcr true
# Re-authenticate git with GitHub token
SERVER_URL_STRIPPED="${SERVER_URL#https://}"
git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
echo "Git configured with standard GitHub Actions identity"
- name: Download assets
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: safe-outputs-assets
path: /tmp/gh-aw/safeoutputs/assets/
- name: List downloaded asset files
continue-on-error: true
run: |
echo "Downloaded asset files:"
find /tmp/gh-aw/safeoutputs/assets/ -maxdepth 1 -ls
- name: Download agent output artifact
id: download-agent-output
continue-on-error: true
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: agent
path: /tmp/gh-aw/
- name: Setup agent output environment variable
if: steps.download-agent-output.outcome == 'success'
run: |
mkdir -p /tmp/gh-aw/
find "/tmp/gh-aw/" -type f -print
echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_ENV"
- name: Push assets
id: upload_assets
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
env:
GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }}
GH_AW_ASSETS_BRANCH: "assets/${{ github.workflow }}"
GH_AW_ASSETS_MAX_SIZE_KB: 10240
GH_AW_ASSETS_ALLOWED_EXTS: ".png,.jpg,.jpeg"
GH_AW_WORKFLOW_NAME: "Daily Project Performance Summary Generator (Using MCP Scripts)"
GH_AW_TRACKER_ID: "daily-performance-summary"
GH_AW_ENGINE_ID: "copilot"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { setupGlobals } = require(process.env.GH_AW_HOME + '/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require(process.env.GH_AW_HOME + '/actions/upload_assets.cjs');
await main();