Files
agent-framework/.github/workflows/issue-triage.yml
T
Evan Mattson fbbc2ebe86 Propagate integration-test model credentials to issue-triage repro (#5443)
Scopes the triage job to the integration GitHub Environment, adds
the azure/login OIDC step, and exposes the same OpenAI / Azure
OpenAI / Foundry / Anthropic env vars the integration test
workflow uses. This lets the triage agent write repro code that
constructs model clients from the environment without any secrets
entering the agent prompt or generated-code literals.

Azure OpenAI and Foundry continue to authenticate via AAD
(DefaultAzureCredential), so there is no API key to leak for
those providers.
2026-04-23 21:01:24 +09:00

200 lines
7.2 KiB
YAML

name: Issue Triage
on:
workflow_dispatch:
inputs:
issue_number:
description: Issue number to triage
required: true
type: string
permissions:
contents: read
issues: write
id-token: write
concurrency:
group: issue-triage-${{ github.repository }}-${{ github.event.issue.number || inputs.issue_number || github.run_id }}
cancel-in-progress: true
env:
DEVFLOW_REPOSITORY: ${{ vars.DF_REPO }}
DEVFLOW_REF: main
TARGET_REPO_PATH: ${{ github.workspace }}/target-repo
DEVFLOW_PATH: ${{ github.workspace }}/devflow
jobs:
team_check:
runs-on: ubuntu-latest
outputs:
is_team_member: ${{ steps.check.outputs.is_team_member }}
issue_number: ${{ steps.issue.outputs.issue_number }}
repo: ${{ steps.issue.outputs.repo }}
steps:
- name: Resolve issue metadata
id: issue
shell: bash
env:
ISSUE_NUMBER_EVENT: ${{ github.event.issue.number }}
ISSUE_NUMBER_INPUT: ${{ inputs.issue_number }}
run: |
set -euo pipefail
if [[ "${GITHUB_EVENT_NAME}" == "issues" ]]; then
issue_number="${ISSUE_NUMBER_EVENT}"
else
issue_number="${ISSUE_NUMBER_INPUT}"
fi
if [[ ! "$issue_number" =~ ^[1-9][0-9]*$ ]]; then
echo "Could not determine issue number; for workflow_dispatch runs, the 'issue_number' input is required." >&2
exit 1
fi
echo "issue_number=${issue_number}" >> "$GITHUB_OUTPUT"
echo "repo=${GITHUB_REPOSITORY}" >> "$GITHUB_OUTPUT"
- name: Checkout scripts
uses: actions/checkout@v6
with:
sparse-checkout: .github/scripts
fetch-depth: 1
persist-credentials: false
- name: Check issue author team membership
id: check
uses: actions/github-script@v8
env:
TEAM_NAME: ${{ secrets.DEVELOPER_TEAM }}
ISSUE_NUMBER: ${{ steps.issue.outputs.issue_number }}
with:
github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
script: |
const checkTeamMembership = require('./.github/scripts/check_team_membership.js');
const { author, isTeamMember } = await checkTeamMembership({
github,
context,
core,
teamSlug: process.env.TEAM_NAME,
issueNumber: process.env.ISSUE_NUMBER,
});
core.setOutput('is_team_member', isTeamMember ? 'true' : 'false');
if (isTeamMember) {
core.info(`Author ${author} is a team member; skipping auto-triage.`);
} else {
core.info(`Author ${author} is not a team member; proceeding with triage.`);
}
triage:
runs-on: ubuntu-latest
needs: team_check
if: ${{ needs.team_check.outputs.is_team_member == 'false' }}
environment: integration
timeout-minutes: 60
steps:
# Safe checkout: base repo only.
- name: Checkout target repo base
uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
path: target-repo
# Private DevFlow (maf-dashboard) checkout.
- name: Checkout DevFlow
uses: actions/checkout@v6
with:
repository: ${{ env.DEVFLOW_REPOSITORY }}
ref: ${{ env.DEVFLOW_REF }}
token: ${{ secrets.DEVFLOW_TOKEN }}
fetch-depth: 1
persist-credentials: false
path: devflow
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
version: "0.11.x"
enable-cache: true
- name: Install DevFlow dependencies
working-directory: ${{ env.DEVFLOW_PATH }}
run: uv sync --frozen
- name: Azure CLI Login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Classify issue relevance
id: spam
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
ISSUE_REPO: ${{ needs.team_check.outputs.repo }}
ISSUE_NUMBER: ${{ needs.team_check.outputs.issue_number }}
run: |
uv run python scripts/classify_issue_spam.py \
--repo "$ISSUE_REPO" \
--issue-number "$ISSUE_NUMBER" \
--repo-path "${TARGET_REPO_PATH}" \
--apply-labels
- name: Stop after spam gate
if: ${{ steps.spam.outputs.decision != 'allow' }}
shell: bash
env:
SPAM_DECISION: ${{ steps.spam.outputs.decision }}
run: |
echo "Stopping: spam gate decided: ${SPAM_DECISION}"
exit 1
- name: Reproduce reported issue
if: ${{ steps.spam.outputs.decision == 'allow' }}
id: repro
working-directory: ${{ env.DEVFLOW_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_COPILOT_TOKEN: ${{ secrets.GH_COPILOT_TOKEN }}
SK_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
AGENT_REPO_PATH: ${{ env.TARGET_REPO_PATH }}
ISSUE_REPO: ${{ needs.team_check.outputs.repo }}
ISSUE_NUMBER: ${{ needs.team_check.outputs.issue_number }}
# Model-provider settings for generated repro code. Never enter the
# agent prompt; consumed by SDK constructors via os.environ. Azure
# OpenAI and Foundry auth via AAD from the azure/login step above.
OPENAI_API_KEY: ${{ secrets.OPENAI__APIKEY }}
OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.OPENAI__CHATMODELID }}
OPENAI_CHAT_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
OPENAI_MODEL: ${{ vars.OPENAI__RESPONSESMODELID }}
OPENAI_EMBEDDING_MODEL: ${{ vars.OPENAI_EMBEDDING_MODEL_ID }}
AZURE_OPENAI_ENDPOINT: ${{ vars.AZUREOPENAI__ENDPOINT }}
AZURE_OPENAI_CHAT_COMPLETION_MODEL: ${{ vars.AZUREOPENAI__CHATDEPLOYMENTNAME }}
AZURE_OPENAI_CHAT_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
AZURE_OPENAI_MODEL: ${{ vars.AZUREOPENAI__RESPONSESDEPLOYMENTNAME }}
AZURE_OPENAI_EMBEDDING_MODEL: ${{ vars.AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME }}
FOUNDRY_PROJECT_ENDPOINT: ${{ vars.FOUNDRY_PROJECT_ENDPOINT }}
FOUNDRY_MODEL: ${{ vars.FOUNDRY_MODEL }}
FOUNDRY_AGENT_NAME: ${{ vars.FOUNDRY_AGENT_NAME }}
FOUNDRY_AGENT_VERSION: ${{ vars.FOUNDRY_AGENT_VERSION }}
FOUNDRY_MODELS_ENDPOINT: ${{ vars.FOUNDRY_MODELS_ENDPOINT || '' }}
FOUNDRY_MODELS_API_KEY: ${{ secrets.FOUNDRY_MODELS_API_KEY || '' }}
FOUNDRY_EMBEDDING_MODEL: ${{ vars.FOUNDRY_EMBEDDING_MODEL || '' }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
ANTHROPIC_CHAT_MODEL: ${{ vars.ANTHROPIC_CHAT_MODEL_ID }}
run: |
uv run python scripts/trigger_issue_repro.py \
--repo "$ISSUE_REPO" \
--issue-number "$ISSUE_NUMBER" \
--github-username "$GITHUB_ACTOR"