227 lines
9.8 KiB
YAML
227 lines
9.8 KiB
YAML
name: commit finding intake
|
|
|
|
on:
|
|
repository_dispatch:
|
|
types: [clawsweeper_commit_finding]
|
|
workflow_dispatch:
|
|
inputs:
|
|
enabled:
|
|
description: "Run commit finding intake"
|
|
required: false
|
|
default: "true"
|
|
type: string
|
|
target_repo:
|
|
description: "Target repository"
|
|
required: true
|
|
default: "openclaw/openclaw"
|
|
type: string
|
|
commit_sha:
|
|
description: "Commit SHA with a ClawSweeper finding"
|
|
required: true
|
|
type: string
|
|
report_repo:
|
|
description: "Repository containing the ClawSweeper report"
|
|
required: false
|
|
default: "openclaw/clawsweeper"
|
|
type: string
|
|
report_path:
|
|
description: "Path to the ClawSweeper report"
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
report_url:
|
|
description: "Public report URL"
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
|
|
permissions:
|
|
contents: write
|
|
actions: read
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
CODEX_CLI_VERSION: ${{ vars.CLOWNFISH_CODEX_CLI_VERSION || '0.125.0' }}
|
|
CLOWNFISH_ALLOWED_OWNER: ${{ vars.CLOWNFISH_ALLOWED_OWNER || 'openclaw' }}
|
|
CLOWNFISH_ALLOW_EXECUTE: ${{ vars.CLOWNFISH_ALLOW_EXECUTE == '1' && '1' || '0' }}
|
|
CLOWNFISH_ALLOW_FIX_PR: ${{ vars.CLOWNFISH_ALLOW_FIX_PR == '1' && '1' || '0' }}
|
|
CLOWNFISH_ALLOW_MERGE: "0"
|
|
CLOWNFISH_CODEX_REASONING_EFFORT: ${{ vars.CLOWNFISH_CODEX_REASONING_EFFORT || 'medium' }}
|
|
CLOWNFISH_CODEX_REVIEW_ATTEMPTS: ${{ vars.CLOWNFISH_CODEX_REVIEW_ATTEMPTS || '2' }}
|
|
CLOWNFISH_REBASE_REPAIR_ATTEMPTS: ${{ vars.CLOWNFISH_REBASE_REPAIR_ATTEMPTS || '4' }}
|
|
CLOWNFISH_FIX_CODEX_TIMEOUT_MS: ${{ vars.CLOWNFISH_FIX_CODEX_TIMEOUT_MS || '1200000' }}
|
|
CLOWNFISH_FIX_STEP_TIMEOUT_MS: "1500000"
|
|
CLOWNFISH_FIX_TIMEOUT_RESERVE_MS: ${{ vars.CLOWNFISH_FIX_TIMEOUT_RESERVE_MS || '300000' }}
|
|
CLOWNFISH_FIX_PREFLIGHT_TIMEOUT_MS: ${{ vars.CLOWNFISH_FIX_PREFLIGHT_TIMEOUT_MS || '120000' }}
|
|
CLOWNFISH_MODEL: ${{ vars.CLOWNFISH_MODEL || 'gpt-5.5' }}
|
|
CLOWNFISH_TARGET_VALIDATION_MODE: ${{ vars.CLOWNFISH_TARGET_VALIDATION_MODE || 'changed-only' }}
|
|
CLOWNFISH_RESOLVE_REVIEW_THREADS: ${{ vars.CLOWNFISH_RESOLVE_REVIEW_THREADS || '1' }}
|
|
CLOWNFISH_MAX_ACTIVE_PRS_PER_AREA: ${{ vars.CLOWNFISH_MAX_ACTIVE_PRS_PER_AREA || '50' }}
|
|
CLOWNFISH_GIT_USER_NAME: ${{ vars.CLOWNFISH_GIT_USER_NAME || 'openclaw-clownfish[bot]' }}
|
|
CLOWNFISH_GIT_USER_EMAIL: ${{ vars.CLOWNFISH_GIT_USER_EMAIL || '280122609+openclaw-clownfish[bot]@users.noreply.github.com' }}
|
|
|
|
concurrency:
|
|
group: commit-finding-${{ github.event.inputs.target_repo || github.event.client_payload.target_repo || 'openclaw/openclaw' }}-${{ github.event.inputs.commit_sha || github.event.client_payload.commit_sha || github.run_id }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
intake:
|
|
runs-on: ${{ vars.CLOWNFISH_COMMIT_FINDING_RUNNER || 'blacksmith-16vcpu-ubuntu-2404' }}
|
|
timeout-minutes: 75
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-node@v5
|
|
with:
|
|
node-version: "24"
|
|
|
|
- name: Create GitHub App token
|
|
id: app_token
|
|
continue-on-error: true
|
|
uses: actions/create-github-app-token@v3
|
|
with:
|
|
app-id: ${{ vars.CLOWNFISH_APP_ID }}
|
|
private-key: ${{ secrets.CLOWNFISH_APP_PRIVATE_KEY }}
|
|
owner: ${{ vars.CLOWNFISH_ALLOWED_OWNER || github.repository_owner }}
|
|
permission-contents: write
|
|
permission-issues: write
|
|
permission-pull-requests: write
|
|
permission-workflows: write
|
|
permission-actions: read
|
|
|
|
- name: Prepare commit finding intake
|
|
id: prepare
|
|
env:
|
|
GH_TOKEN: ${{ steps.app_token.outputs.token || secrets.CLOWNFISH_READ_GH_TOKEN || github.token }}
|
|
ENABLED: ${{ github.event.inputs.enabled || github.event.client_payload.enabled || vars.CLOWNFISH_COMMIT_FINDING_INTAKE_ENABLED || 'true' }}
|
|
TARGET_REPO: ${{ github.event.inputs.target_repo || github.event.client_payload.target_repo || 'openclaw/openclaw' }}
|
|
COMMIT_SHA: ${{ github.event.inputs.commit_sha || github.event.client_payload.commit_sha }}
|
|
REPORT_REPO: ${{ github.event.inputs.report_repo || github.event.client_payload.report_repo || 'openclaw/clawsweeper' }}
|
|
REPORT_PATH: ${{ github.event.inputs.report_path || github.event.client_payload.report_path }}
|
|
REPORT_URL: ${{ github.event.inputs.report_url || github.event.client_payload.report_url }}
|
|
run: |
|
|
set -euo pipefail
|
|
args=(
|
|
prepare
|
|
--enabled "$ENABLED"
|
|
--target-repo "$TARGET_REPO"
|
|
--commit-sha "$COMMIT_SHA"
|
|
--report-repo "$REPORT_REPO"
|
|
)
|
|
if [ -n "${REPORT_PATH:-}" ]; then
|
|
args+=(--report-path "$REPORT_PATH")
|
|
fi
|
|
if [ -n "${REPORT_URL:-}" ]; then
|
|
args+=(--report-url "$REPORT_URL")
|
|
fi
|
|
npm run commit-finding-intake -- "${args[@]}"
|
|
|
|
- name: Cache Codex CLI, npm, and target pnpm downloads
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' }}
|
|
uses: actions/cache@v5
|
|
with:
|
|
path: |
|
|
~/.npm
|
|
~/.cache/node/corepack
|
|
~/.local/share/pnpm/store
|
|
~/.projectclownfish/codex
|
|
key: ${{ runner.os }}-node24-codex-${{ env.CODEX_CLI_VERSION }}-target-pnpm-v1
|
|
restore-keys: |
|
|
${{ runner.os }}-node24-codex-${{ env.CODEX_CLI_VERSION }}-target-pnpm-
|
|
${{ runner.os }}-node24-codex-
|
|
|
|
- name: Install Codex CLI
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' }}
|
|
run: |
|
|
set -euo pipefail
|
|
npm config set prefix "$HOME/.projectclownfish/codex"
|
|
npm config set cache "$HOME/.npm"
|
|
echo "$HOME/.projectclownfish/codex/bin" >> "$GITHUB_PATH"
|
|
export PATH="$HOME/.projectclownfish/codex/bin:$PATH"
|
|
|
|
if ! command -v codex >/dev/null 2>&1 || ! codex --version | grep -Fq "$CODEX_CLI_VERSION"; then
|
|
npm install -g "@openai/codex@$CODEX_CLI_VERSION" --prefer-offline --no-audit --no-fund
|
|
fi
|
|
codex --version
|
|
|
|
- name: Authenticate Codex
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' }}
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }}
|
|
run: |
|
|
test -n "${OPENAI_API_KEY:-}"
|
|
test -n "${CODEX_API_KEY:-}"
|
|
printenv OPENAI_API_KEY | codex login --with-api-key >/dev/null
|
|
|
|
- name: Review synthetic result
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' }}
|
|
run: npm run review-results -- "${{ steps.prepare.outputs.result_path }}"
|
|
|
|
- name: Execute credited fix artifact
|
|
id: execute
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' && env.CLOWNFISH_ALLOW_EXECUTE == '1' && env.CLOWNFISH_ALLOW_FIX_PR == '1' }}
|
|
continue-on-error: true
|
|
timeout-minutes: 35
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }}
|
|
GH_TOKEN: ${{ steps.app_token.outputs.token || secrets.CLOWNFISH_GH_TOKEN || github.token }}
|
|
run: npm run execute-fix -- "${{ steps.prepare.outputs.job_path }}" "${{ steps.prepare.outputs.result_path }}"
|
|
|
|
- name: Post-flight finalize fix PRs
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' && steps.execute.outcome == 'success' && env.CLOWNFISH_ALLOW_EXECUTE == '1' && env.CLOWNFISH_ALLOW_FIX_PR == '1' }}
|
|
env:
|
|
GH_TOKEN: ${{ steps.app_token.outputs.token || secrets.CLOWNFISH_GH_TOKEN || github.token }}
|
|
run: npm run post-flight -- "${{ steps.prepare.outputs.job_path }}" "${{ steps.prepare.outputs.result_path }}"
|
|
|
|
- name: Publish local result ledger
|
|
if: ${{ always() && steps.prepare.outputs.should_repair == 'true' }}
|
|
env:
|
|
GH_TOKEN: ${{ steps.app_token.outputs.token || secrets.CLOWNFISH_READ_GH_TOKEN || github.token }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: |
|
|
npm run publish-result -- "${{ steps.prepare.outputs.run_dir }}" \
|
|
--run-id "${{ github.run_id }}" \
|
|
--run-url "$RUN_URL" \
|
|
--head-sha "${{ github.sha }}" \
|
|
--conclusion "${{ steps.execute.outcome == 'success' && 'success' || steps.execute.outcome == 'failure' && 'failure' || 'skipped' }}"
|
|
|
|
- name: Finalize commit finding audit
|
|
if: always()
|
|
run: |
|
|
if [ -n "${{ steps.prepare.outputs.audit_path }}" ]; then
|
|
npm run commit-finding-intake -- finalize \
|
|
--audit-path "${{ steps.prepare.outputs.audit_path }}" \
|
|
--run-dir "${{ steps.prepare.outputs.run_dir }}" \
|
|
--status "${{ steps.prepare.outputs.should_repair == 'true' && (steps.execute.outcome || 'skipped') || steps.prepare.outputs.status }}"
|
|
fi
|
|
|
|
- name: Commit intake ledger
|
|
if: always()
|
|
run: |
|
|
set -euo pipefail
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
git add jobs results README.md apply-report.json
|
|
if git diff --cached --quiet; then
|
|
echo "No intake ledger changes"
|
|
exit 0
|
|
fi
|
|
git commit -m "chore: record commit finding intake"
|
|
for _attempt in 1 2 3; do
|
|
if git pull --rebase && git push; then
|
|
exit 0
|
|
fi
|
|
git rebase --abort || true
|
|
git fetch origin main
|
|
git rebase origin/main
|
|
done
|
|
git push
|
|
|
|
- name: Fail on repair failure
|
|
if: ${{ steps.prepare.outputs.should_repair == 'true' && steps.execute.outcome == 'failure' }}
|
|
run: exit 1
|