mirror of
https://github.com/peass-ng/PEASS-ng.git
synced 2026-11-07 09:25:57 -10:00
The chack-agent workflows pinned the action to commit 9fd38a06; they now use carlospolop/chack-agent@master. The steps that install the Codex CLI also install [email protected].5 so chack's opencode backend is available. AGENTS.md records both rules. Co-authored-by: Carlos Polop <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
345 lines
15 KiB
YAML
345 lines
15 KiB
YAML
name: PR Failure Chack-Agent Dispatch
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["PR-tests"]
|
|
types: [completed]
|
|
|
|
# Context resolution happens before checkout, including branch-based PR lookup.
|
|
env:
|
|
GH_REPO: ${{ github.repository }}
|
|
|
|
jobs:
|
|
resolve_pr_context:
|
|
if: >-
|
|
${{ github.event.workflow_run.conclusion == 'failure' &&
|
|
!startsWith(github.event.workflow_run.head_commit.message || '', 'Fix CI failures for PR #') }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
pull-requests: read
|
|
issues: read
|
|
outputs:
|
|
number: ${{ steps.pr_context.outputs.number }}
|
|
author: ${{ steps.pr_context.outputs.author }}
|
|
head_repo: ${{ steps.pr_context.outputs.head_repo }}
|
|
head_branch: ${{ steps.pr_context.outputs.head_branch }}
|
|
should_run: ${{ steps.pr_context.outputs.should_run }}
|
|
steps:
|
|
- name: Resolve PR context
|
|
id: pr_context
|
|
env:
|
|
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
SOURCE_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
if [ -z "$PR_NUMBER" ] && [ -n "$HEAD_BRANCH" ]; then
|
|
PR_NUMBER="$(gh pr list --state open --head "$HEAD_BRANCH" --json number --jq '.[0].number')"
|
|
fi
|
|
if [ -z "$PR_NUMBER" ]; then
|
|
echo "No pull request found for workflow_run; skipping."
|
|
{
|
|
echo "number="
|
|
echo "author="
|
|
echo "head_repo="
|
|
echo "head_branch=${HEAD_BRANCH}"
|
|
echo "should_run=false"
|
|
} >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
pr_author=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
|
--jq '.user.login')
|
|
pr_state=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
|
--jq '.state')
|
|
if [ "$pr_state" != "open" ]; then
|
|
echo "PR #${PR_NUMBER} is $pr_state; skipping stale fix."
|
|
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
pr_head_repo=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
|
--jq '.head.repo.full_name')
|
|
pr_head_branch=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
|
--jq '.head.ref')
|
|
pr_head_sha=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/pulls/${PR_NUMBER} \
|
|
--jq '.head.sha')
|
|
if [ "$pr_head_sha" != "$SOURCE_HEAD_SHA" ]; then
|
|
echo "PR #${PR_NUMBER} moved from failed head $SOURCE_HEAD_SHA to $pr_head_sha; skipping stale fix."
|
|
echo "should_run=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
pr_labels=$(gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/issues/${PR_NUMBER} \
|
|
--jq '.labels[].name')
|
|
if echo "$pr_labels" | grep -q "^chack-agent-fix-attempted$"; then
|
|
echo "chack-agent fix already attempted for PR #${PR_NUMBER}; skipping."
|
|
should_run=false
|
|
else
|
|
should_run=true
|
|
fi
|
|
{
|
|
echo "number=${PR_NUMBER}"
|
|
echo "author=${pr_author}"
|
|
echo "head_repo=${pr_head_repo}"
|
|
echo "head_branch=${pr_head_branch}"
|
|
echo "should_run=${should_run}"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
chack_agent_on_failure:
|
|
needs: resolve_pr_context
|
|
if: ${{ needs.resolve_pr_context.outputs.author == 'carlospolop' && needs.resolve_pr_context.outputs.should_run == 'true' }}
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
issues: write
|
|
actions: write
|
|
env:
|
|
# chack-agent OTel traces to Phoenix; off when the header secret is absent (e.g. forks).
|
|
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: ${{ secrets.PHOENIX_OTLP_HEADERS != '' && 'https://chacks.hacktricks.wiki/v1/traces' || '' }}
|
|
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.PHOENIX_OTLP_HEADERS }}
|
|
OTEL_SERVICE_NAME: peass-ng
|
|
OTEL_RESOURCE_ATTRIBUTES: openinference.project.name=peass-ng
|
|
steps:
|
|
- name: Mark fix attempt
|
|
env:
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh api -X POST -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/issues/${PR_NUMBER}/labels \
|
|
-f labels[]=chack-agent-fix-attempted
|
|
|
|
- name: Checkout PR head
|
|
uses: actions/checkout@v5
|
|
with:
|
|
repository: ${{ needs.resolve_pr_context.outputs.head_repo }}
|
|
ref: ${{ github.event.workflow_run.head_sha }}
|
|
fetch-depth: 0
|
|
persist-credentials: true
|
|
token: ${{ secrets.CODEX_FIXER_TOKEN || github.token }}
|
|
|
|
- name: Configure git author
|
|
run: |
|
|
git config user.name "chack-agent"
|
|
git config user.email "[email protected]"
|
|
|
|
- name: Fetch failure summary
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
RUN_ID: ${{ github.event.workflow_run.id }}
|
|
run: |
|
|
gh api -H "Accept: application/vnd.github+json" \
|
|
/repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs \
|
|
--paginate > /tmp/jobs.json
|
|
python3 - <<'PY'
|
|
import json
|
|
|
|
data = json.load(open('/tmp/jobs.json'))
|
|
lines = []
|
|
for job in data.get('jobs', []):
|
|
if job.get('conclusion') == 'failure':
|
|
lines.append(f"Job: {job.get('name')} (id {job.get('id')})")
|
|
lines.append(f"URL: {job.get('html_url')}")
|
|
for step in job.get('steps', []):
|
|
if step.get('conclusion') == 'failure':
|
|
lines.append(f" Step: {step.get('name')}")
|
|
lines.append("")
|
|
|
|
summary = "\n".join(lines).strip() or "No failing job details found."
|
|
with open('chack_failure_summary.txt', 'w') as handle:
|
|
handle.write(summary)
|
|
PY
|
|
|
|
- name: Create Chack Agent prompt
|
|
env:
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
|
HEAD_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }}
|
|
run: |
|
|
{
|
|
echo "You are fixing CI failures for PR #${PR_NUMBER} in ${{ github.repository }}."
|
|
echo "The failing workflow run is: ${RUN_URL}"
|
|
echo "The PR branch is: ${HEAD_BRANCH}"
|
|
echo ""
|
|
echo "Failure summary:"
|
|
cat chack_failure_summary.txt
|
|
echo ""
|
|
echo "Please identify the cause, apply a easy, simple and minimal fix, and update files accordingly."
|
|
echo "Do not edit or create any .md or .txt files and do not modify build_lists/regexes.yaml."
|
|
echo "Run any fast checks you can locally (no network)."
|
|
echo "Leave the repo in a state ready to commit as when you finish, it'll be automatically committed and pushed."
|
|
} > chack_prompt.txt
|
|
|
|
- name: Set up Node.js for Codex
|
|
uses: actions/setup-node@v5
|
|
with:
|
|
node-version: "20"
|
|
|
|
- name: Install Codex and opencode CLIs
|
|
run: |
|
|
npm install --global @openai/codex@latest
|
|
npm i -g [email protected]
|
|
codex --version
|
|
opencode --version
|
|
|
|
- name: Run Chack Agent
|
|
id: run_chack
|
|
# Always run the latest chack-agent; never pin a commit.
|
|
uses: carlospolop/chack-agent@master
|
|
with:
|
|
provider: codex
|
|
model_primary: gpt-5.6-sol
|
|
main_action: peass-ng-pr-failure
|
|
max_turns: 125
|
|
sub_action: PR Failure Chack-Agent Dispatch
|
|
system_prompt: |
|
|
You are Chack Agent, an elite CI-fix engineer.
|
|
Diagnose the failing workflow, propose the minimal safe fix, and implement it.
|
|
Do not merely describe a problem you can fix. Only leave explanatory text when you
|
|
cannot confidently repair and validate the failure or the PR should not be merged.
|
|
Never edit any .md or .txt files. Don't create job or summary files of you actions.
|
|
Never create or modify build_lists/regexes.yaml.
|
|
Run only fast, local checks (no network). Leave the repo ready to commit.
|
|
prompt_file: chack_prompt.txt
|
|
tools_config_json: "{\"exec_enabled\": true}"
|
|
session_config_json: "{\"long_term_memory_enabled\": false}"
|
|
agent_config_json: "{\"self_critique_enabled\": false, \"require_task_steps_manager_init_first\": true}"
|
|
codex_access_token: ${{ secrets.CODEX_ACCESS_TOKEN }}
|
|
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
|
|
|
|
- name: Commit and push if changed
|
|
id: push_fix
|
|
env:
|
|
TARGET_BRANCH: ${{ needs.resolve_pr_context.outputs.head_branch }}
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
ORIGINAL_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
PUSH_TOKEN: ${{ secrets.CODEX_FIXER_TOKEN }}
|
|
WORKFLOW_TOKEN: ${{ github.token }}
|
|
run: |
|
|
rm -f chack_failure_summary.txt chack_prompt.txt
|
|
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
git add -A
|
|
# Keep all fixer changes, including .github/workflows, and rely on permissioned tokens to push safely.
|
|
# Only temporary tool artifacts are filtered out.
|
|
git reset -- chack_failure_summary.txt chack_prompt.txt
|
|
# Never commit generated or regenerated regex list files from this workflow.
|
|
git reset -- build_lists/regexes.yaml || true
|
|
# Never allow the agent to commit generated linpeas artifacts.
|
|
git reset -- linpeas.sh linpeas_fat.sh || true
|
|
while IFS= read -r forbidden_file; do
|
|
git reset -- "$forbidden_file" || true
|
|
done < <(git diff --name-only --cached | grep -E '(^|/)(linpeas\.sh|linpeas_fat\.sh)$' || true)
|
|
while IFS= read -r file; do
|
|
case "$file" in
|
|
*.txt|*.md)
|
|
git reset -- "$file"
|
|
;;
|
|
esac
|
|
done < <(git diff --name-only --cached)
|
|
if git diff --cached --name-only | grep -Eq '(^|/)(linpeas\.sh|linpeas_fat\.sh)$'; then
|
|
echo "Forbidden generated linpeas files are still staged; skipping push."
|
|
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
if ! git diff --cached --quiet; then
|
|
git commit -m "Fix CI failures for PR #${PR_NUMBER}"
|
|
fi
|
|
fi
|
|
|
|
after_head="$(git rev-parse HEAD)"
|
|
if [ "$after_head" = "$ORIGINAL_HEAD_SHA" ]; then
|
|
echo "No commit produced by Chack Agent for PR #${PR_NUMBER}."
|
|
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
if [ -z "$PUSH_TOKEN" ]; then
|
|
echo "CODEX_FIXER_TOKEN is required to push and retest Chack Agent fixes."
|
|
exit 1
|
|
fi
|
|
|
|
pr_state="$(GH_TOKEN="$WORKFLOW_TOKEN" gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json state --jq .state)"
|
|
current_head_sha="$(GH_TOKEN="$WORKFLOW_TOKEN" gh pr view "$PR_NUMBER" --repo "${{ github.repository }}" --json headRefOid --jq .headRefOid)"
|
|
if [ "$pr_state" != "OPEN" ] || [ "$current_head_sha" != "$ORIGINAL_HEAD_SHA" ]; then
|
|
echo "PR #${PR_NUMBER} is $pr_state at $current_head_sha; skipping stale fix push."
|
|
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
if ! git push origin HEAD:${TARGET_BRANCH}; then
|
|
echo "Push failed (likely token workflow permission limits); leaving run successful without push."
|
|
echo "pushed=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
retest_url="$(GH_TOKEN="$WORKFLOW_TOKEN" gh workflow run PR-tests.yml --ref "$TARGET_BRANCH")"
|
|
retest_id="${retest_url##*/}"
|
|
echo "retest_url=$retest_url" >> "$GITHUB_OUTPUT"
|
|
|
|
retest_conclusion="timed_out"
|
|
for attempt in $(seq 1 180); do
|
|
run_state="$(GH_TOKEN="$WORKFLOW_TOKEN" gh run view "$retest_id" --json status,conclusion --jq '[.status, (.conclusion // "")] | @tsv' 2>/dev/null || true)"
|
|
status="${run_state%%$'\t'*}"
|
|
conclusion="${run_state#*$'\t'}"
|
|
if [ "$status" = "completed" ]; then
|
|
retest_conclusion="$conclusion"
|
|
break
|
|
fi
|
|
sleep 15
|
|
done
|
|
|
|
echo "pushed=true" >> "$GITHUB_OUTPUT"
|
|
echo "retest_conclusion=$retest_conclusion" >> "$GITHUB_OUTPUT"
|
|
if [ "$retest_conclusion" = "success" ]; then
|
|
echo "retest_passed=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "retest_passed=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Dispatch Chack review after a successful retest
|
|
if: ${{ steps.push_fix.outputs.retest_passed == 'true' }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
run: gh workflow run chack-agent-pr-triage.yml -f pr_number="$PR_NUMBER"
|
|
|
|
- name: Comment only when Chack Agent could not produce a fix
|
|
if: ${{ steps.push_fix.outputs.pushed != 'true' && steps.run_chack.outputs.final-message != '' }}
|
|
uses: actions/github-script@v7
|
|
env:
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
CHACK_MESSAGE: ${{ steps.run_chack.outputs.final-message }}
|
|
with:
|
|
github-token: ${{ github.token }}
|
|
script: |
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: Number(process.env.PR_NUMBER),
|
|
body: process.env.CHACK_MESSAGE,
|
|
});
|
|
|
|
- name: Comment when the Chack CI fix does not pass its retest
|
|
if: ${{ steps.push_fix.outputs.pushed == 'true' && steps.push_fix.outputs.retest_passed != 'true' }}
|
|
uses: actions/github-script@v7
|
|
env:
|
|
PR_NUMBER: ${{ needs.resolve_pr_context.outputs.number }}
|
|
RETEST_URL: ${{ steps.push_fix.outputs.retest_url }}
|
|
RETEST_CONCLUSION: ${{ steps.push_fix.outputs.retest_conclusion }}
|
|
with:
|
|
github-token: ${{ github.token }}
|
|
script: |
|
|
const body = `Chack Agent applied a CI fix, but its full retest finished with \`${process.env.RETEST_CONCLUSION}\`. I could not validate this fix for review or merge.\n\nRetest: ${process.env.RETEST_URL}`;
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: Number(process.env.PR_NUMBER),
|
|
body,
|
|
});
|