From e4826dc9544d1590b5efbcd77e0f4775c8f55bbf Mon Sep 17 00:00:00 2001 From: "flamingo[bot]" <277372822+flamingo[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2026 14:10:21 +0000 Subject: [PATCH] =?UTF-8?q?chore:=20add=20=F0=9F=A6=A9=20Flamingo=20Code?= =?UTF-8?q?=20Review=20workflow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This workflow enables automated code review using the 🦩 Flamingo Code Review pipeline. It runs on pull_request and repository_dispatch events triggered by the multi-platform-hub. Rules are fetched at run time and are hash-addressed, so a rule change needs no update to this file. --- .github/workflows/flamingo-code-review.yml | 401 +++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 .github/workflows/flamingo-code-review.yml diff --git a/.github/workflows/flamingo-code-review.yml b/.github/workflows/flamingo-code-review.yml new file mode 100644 index 0000000..d81c554 --- /dev/null +++ b/.github/workflows/flamingo-code-review.yml @@ -0,0 +1,401 @@ +# Generated by the Flamingo hub β€” do not edit by hand. +# Per-repo settings live in the hub admin (/admin/code-review); this file is +# byte-identical across every reviewed repository AND every deployment, which +# is what makes drift detectable by comparison. The hub's address arrives in +# the dispatch payload (doc-orchestrator style) or, for pull_request runs, the +# org Actions variable FLAMINGO_HUB_BASE_URL. +# Named like its sibling pipeline ('🦩 Flamingo Code Documentation') so both +# read as one product family in the Actions sidebar. +name: 🦩 Flamingo Code Review + +on: + # Push trigger - registers workflow with GitHub Actions (required for + # workflow_dispatch API). Only fires when this file itself changes; the job + # skips it β€” same pattern as the doc-orchestrator workflow. + push: + paths: + - '.github/workflows/flamingo-code-review.yml' + + # READY-FOR-REVIEW ONLY (owner decision 2026-08-12): per-push re-reviews + # ('synchronize') are deliberately OFF β€” reviewing every push of an active + # branch is excessive spend. A PR is reviewed when it ENTERS review: + # opened non-draft (born ready β€” ready_for_review never fires for these), + # marked ready from draft, or reopened. Re-reviews (a draftβ†’ready re-cycle, + # a reopen) diff only the delta since the last reviewed head β€” see the + # incremental anchor in code-review-review.mjs. + pull_request: + types: [opened, ready_for_review, reopened] + repository_dispatch: + types: [flamingo-code-review] + # Lets the hub target a SETUP BRANCH before the install PR merges β€” the same + # test-before-merge flow the doc pipeline uses. repository_dispatch only ever + # fires on the default branch. + workflow_dispatch: + # ═══════════════════════════════════════════════════════════════════════════ + # GENERATED FROM SINGLE SOURCE OF TRUTH: CODE_REVIEW_PARAMS (this module) + # This section is auto-generated when creating workflow PRs + # ═══════════════════════════════════════════════════════════════════════════ + inputs: + run_id: + description: 'Hub run-record id binding this execution to a code_review_runs row. Empty for pull_request runs β€” the hub creates the row from the callback.' + required: false + default: '' + run_token: + description: 'Per-run token minted by the hub at dispatch. Binds the callback to THIS run β€” the org-wide secret alone would let any repo report against another repo’s run.' + required: false + default: '' + mode: + description: 'Review mode: pr (diff-scoped), sweep (whole-repo scanner) or mine (rule mining over the full checkout).' + required: false + default: 'sweep' + hub_base_url: + description: 'Absolute hub origin. Dispatches carry it doc-orchestrator style; pull_request runs fall back to the org/repo Actions variable FLAMINGO_HUB_BASE_URL (shipped by Sync Secrets).' + required: false + default: '' + review_budget_chars: + description: 'Sweep corpus budget in characters for this run (review_config.sweep_budget_chars). Empty = UNCAPPED β€” the whole eligible corpus is reviewed in ~80K batches. The local twin defaults to 80000 instead; set the per-repo value to cap CI spend.' + required: false + default: '' + # ═══════════════════════════════════════════════════════════════════════════ + # END GENERATED SECTION + # ═══════════════════════════════════════════════════════════════════════════ + +# GENERATED FROM SINGLE SOURCE OF TRUTH: CODE_REVIEW_PARAMS (this module) +# The doc-orchestrator's parameter chain for EVERY dispatch param: payload +# first, workflow_dispatch input second, then the param's runtime fallback. +# Workflow-level, so every dispatch var reaches every step and every +# downloaded script. SECURITY: only NON-SENSITIVE values live here β€” secrets +# are passed per-step, same as the doc workflow. +env: + RUN_ID: ${{ github.event.client_payload.run_id || github.event.inputs.run_id || '' }} + MODE: ${{ github.event.client_payload.mode || github.event.inputs.mode || (github.event_name == 'pull_request' && 'pr' || 'sweep') }} + HUB_BASE_URL: ${{ github.event.client_payload.hub_base_url || github.event.inputs.hub_base_url || vars.FLAMINGO_HUB_BASE_URL }} + REVIEW_BUDGET_CHARS: ${{ github.event.client_payload.review_budget_chars || github.event.inputs.review_budget_chars || '' }} + +# Superseding a PR cancels the in-flight review of the stale head SHA; the +# fresh run reviews (and reports on) the new one. The always() report step +# still fires on the cancelled run, so its row records 'cancelled' rather +# than dangling. +concurrency: + group: flamingo-code-review-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + checks: write + +jobs: + review: + # Skip actual work when triggered by push (push only registers the + # workflow with GitHub, which is what lets workflow_dispatch target a + # setup branch before the install PR merges). + # Drafts, bots and forks never dispatch. A fork's token is read-only + # regardless of what is declared here, so running would only waste minutes. + # NOTE: there is deliberately no vars. kill switch here. The hub's + # per-repo enabled dial already covers it and answers 409 REVIEW_DISABLED, + # which produces a recorded run. A second switch living in GitHub would be + # invisible to the admin screen and would produce no callback at all. + if: >- + github.event_name != 'push' && + (github.event_name == 'repository_dispatch' || + github.event_name == 'workflow_dispatch' || + (github.event.pull_request.draft == false && + github.event.pull_request.user.type != 'Bot' && + github.event.pull_request.head.repo.full_name == github.repository)) + runs-on: ubuntu-latest + # NO custom timeout-minutes β€” deliberately. GitHub's 6h hosted-runner + # ceiling is the only clock: on hitting it the always() report step still + # runs, so a sweep ships its per-batch checkpoint home and the NEXT sweep + # resumes from the covered files (nothing is lost, nothing re-paid). Hung + # runs are the hub reaper's job (run-safety-net-utils.ts, no-report cutoff + # sized past the platform ceiling) β€” a second hand-tuned ceiling here was + # one more number to keep in sync for no added safety. + steps: + # Fail LOUD, not silent: a pull_request run on a repo whose org never set + # FLAMINGO_HUB_BASE_URL would otherwise curl an empty origin and die with + # an unrelated error. Also normalizes a trailing slash ONCE for every + # downstream consumer (a value of https://hub.example/ would otherwise + # yield //api double-slash paths in four places). + - name: Validate configuration + run: | + if [ -z "$HUB_BASE_URL" ]; then + echo "::error::HUB_BASE_URL is empty β€” set the org Actions variable FLAMINGO_HUB_BASE_URL (or pass hub_base_url in the dispatch payload)." + exit 1 + fi + echo "HUB_BASE_URL=${HUB_BASE_URL%/}" >> "$GITHUB_ENV" + + # REPORT CAPABILITY FIRST. Only workflow-helpers.sh + code-review-report.sh + # download here β€” before checkout, cache, or any other script β€” so every + # later failure (including the download step for the REST of the scripts + # 404ing or hash-mismatching, the class that produced phantom 'running' + # rows) still has a verified report script to call home with. + - name: Download the report script + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + HASH_WORKFLOW_HELPERS: "3df9f07c408d987a44e9df7ba1584f01ff57502a596f013dd3218d3b4c30fd4c" + HASH_REPORT: "b23b97673d98cdd095d10579524d9b8b7e6859f68f5491206531d86704574df3" + run: | + set -euo pipefail + SCRIPTS_BASE_URL="${HUB_BASE_URL}/api/doc-orchestrator/scripts" + + download_and_verify() { + local script_name="$1" + local expected_hash="$2" + local output_path="/tmp/$script_name" + + curl -fsSL "$SCRIPTS_BASE_URL/$script_name" \ + -H "Authorization: Bearer $WEBHOOK_SECRET" \ + -o "$output_path" + + local actual_hash=$(shasum -a 256 "$output_path" | cut -d' ' -f1) + + if [ "$actual_hash" != "$expected_hash" ]; then + echo "❌ HASH MISMATCH for $script_name!" + echo " Expected: $expected_hash" + echo " Actual: $actual_hash" + echo " This could indicate tampering or an outdated hash." + exit 1 + fi + + # Make shell scripts executable + if [[ "$script_name" == *.sh ]]; then + chmod +x "$output_path" + fi + + echo "βœ… $script_name verified (hash: ${actual_hash:0:16}...)" + } + + download_and_verify "workflow-helpers.sh" "$HASH_WORKFLOW_HELPERS" + download_and_verify "code-review-report.sh" "$HASH_REPORT" + + # Early liveness ping β€” the FIRST real step after report capability is + # secured. Stamps workflow_run_id + status 'running' on the hub's run row, + # so "dispatch accepted but nothing ever ran" (no ping β€” reaped fast) is + # distinguishable from "started, then crashed" (pinged β€” longer deadline). + # Best-effort by design: the script exits 0 regardless; the always() + # report below is the authoritative callback. + - name: Tell the hub the run started + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + RUN_TOKEN: ${{ github.event.client_payload.run_token || github.event.inputs.run_token || '' }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + WF_RUN_ID: ${{ github.run_id }} + REPO_FULL: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: /tmp/code-review-report.sh --started + + # v5 = the Node 24 drop-in (v4 targets EOL Node 20 and warns on every run). + - name: Check out the code under review + uses: actions/checkout@v5 + with: + fetch-depth: 0 + # The review job must never hold a push credential. + persist-credentials: false + + # The corpus hash has to SURVIVE between runs, or the hash param is empty + # and the 304 path the hub implements is unreachable β€” the corpus would be + # transferred in full on every run in both modes. + # v5 = the Node 24 drop-in (v4 targets EOL Node 20 and warns on every run). + - name: Restore the last corpus hash + uses: actions/cache@v5 + with: + # BOTH files. Caching only the hash meant a 304 left rules.json + # truncated to zero bytes while the run continued as if it had a + # corpus. + path: | + .rules-hash + rules.json + key: flamingo-rules-hash-${{ github.repository }}-${{ github.run_id }} + restore-keys: | + flamingo-rules-hash-${{ github.repository }}- + + # The SAME download_and_verify function as the doc-orchestrator workflow + # (single source: lib/config/workflow-scripts-bootstrap.ts, parity with + # the doc template asserted at build time), fetching from the SAME + # scripts endpoint. This bootstrap (and the report-capability step above, + # which shares it) is the ONLY inline bash in the file β€” every other step + # runs a verified unified script, so a script change ships from the hub + # without touching this caller. Helpers + report already downloaded above; + # this step fetches the rest, and its failure is REPORTABLE. + - name: Download and verify scripts + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + HASH_FETCH_RULES: "a3adb1976b782a6bfe405b68c7adc52f6650535e0d9fbc2ea427c3567f2c9943" + HASH_RUN: "e4ebfe017a09ed3f783c8aea995a079be46b4add3b3f92db1918291d1b3e7412" + HASH_MINE: "196ca7afd0a05395fbded4a05fa18cbe0f5d8c6cf28bf49b025f3daed43e233f" + HASH_REVIEW: "a365f8f04b9bb007666a1ebaaa24501b5b3eed0b64fc5e369260747a7520c4b0" + HASH_LIB: "6d4c4b9a6b596581af6028da1de4f62dd629ebf5bd0d7d69d90467aafe8d52a0" + HASH_POST: "75404d6cf735f9a9f1332e65efb6e055ccaf18fe678b1fb3d74d0b0b996c6f2d" + run: | + set -euo pipefail + SCRIPTS_BASE_URL="${HUB_BASE_URL}/api/doc-orchestrator/scripts" + + download_and_verify() { + local script_name="$1" + local expected_hash="$2" + local output_path="/tmp/$script_name" + + curl -fsSL "$SCRIPTS_BASE_URL/$script_name" \ + -H "Authorization: Bearer $WEBHOOK_SECRET" \ + -o "$output_path" + + local actual_hash=$(shasum -a 256 "$output_path" | cut -d' ' -f1) + + if [ "$actual_hash" != "$expected_hash" ]; then + echo "❌ HASH MISMATCH for $script_name!" + echo " Expected: $expected_hash" + echo " Actual: $actual_hash" + echo " This could indicate tampering or an outdated hash." + exit 1 + fi + + # Make shell scripts executable + if [[ "$script_name" == *.sh ]]; then + chmod +x "$output_path" + fi + + echo "βœ… $script_name verified (hash: ${actual_hash:0:16}...)" + } + + download_and_verify "code-review-fetch-rules.sh" "$HASH_FETCH_RULES" + download_and_verify "code-review-run.sh" "$HASH_RUN" + download_and_verify "code-review-mine.mjs" "$HASH_MINE" + download_and_verify "code-review-review.mjs" "$HASH_REVIEW" + download_and_verify "code-review-lib.mjs" "$HASH_LIB" + download_and_verify "code-review-post.mjs" "$HASH_POST" + + - name: Fetch the rule corpus + id: rules + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + # PR runs identify the pull request so the hub can answer with the + # last successfully reviewed head SHA (X-Last-Reviewed-Sha) β€” the + # incremental-review anchor persisted as .last-reviewed-sha. + PR_NUMBER: ${{ github.event.pull_request.number }} + run: /tmp/code-review-fetch-rules.sh + + # Stage checkpoints are their OWN credentialed steps β€” the review step + # deliberately never holds the webhook secret or run token (it processes + # untrusted PR content), so pings happen at step boundaries, not inside. + - name: Report progress β€” reviewing + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + RUN_TOKEN: ${{ github.event.client_payload.run_token || github.event.inputs.run_token || '' }} + WF_RUN_ID: ${{ github.run_id }} + REPO_FULL: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: /tmp/code-review-report.sh --progress review + + - name: Review + # The id lets the report step read the reviewer's own degraded output + # (e.g. skipped_trivial_diff) alongside the rules step's. + id: review + if: steps.rules.outputs.skip != 'true' + # MODE / RUN_ID arrive via the generated workflow-level env; only the + # secret is scoped to the step (doc-workflow security discipline). + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + run: /tmp/code-review-run.sh + + # Post the findings to the PULL REQUEST itself and publish the + # 'Flamingo Code Review' check run. pull_request events only β€” a sweep + # has no PR to post to (its findings live in the hub dashboard). Uses the + # runner's own GITHUB_TOKEN under the workflow's minimal grant + # (pull-requests: write for the comments, checks: write for the check + # run). One UPSERTED summary comment + inline comments where the diff + # supports them; already-posted fingerprints are never re-commented, so + # a new push adds only NEW findings. The check run is 'neutral' unless + # the repo's served mode is 'blocking' AND action_required findings + # exist. Writes posted.json (fingerprint -> comment id) for the report + # step's callback β€” the reaction-learning loop reads it. + - name: Report progress β€” finalizing + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + RUN_TOKEN: ${{ github.event.client_payload.run_token || github.event.inputs.run_token || '' }} + WF_RUN_ID: ${{ github.run_id }} + REPO_FULL: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: /tmp/code-review-report.sh --progress post + + - name: Post to the pull request + id: post + if: github.event_name == 'pull_request' && steps.rules.outputs.skip != 'true' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEGRADED: ${{ steps.review.outputs.degraded }} + PR_NUMBER: ${{ github.event.pull_request.number }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: node /tmp/code-review-post.mjs + + # A crashed Review step must still leave a trace ON THE PR: default + # step-skip semantics silently skip the post step on failure, so the + # developer saw no signal at all that a review was attempted β€” the + # failure lived only on the hub's internal dashboard. Best-effort (|| + # true): a failed courtesy comment must not mask the real failure state. + - name: Post crash notice to the pull request + if: failure() && github.event_name == 'pull_request' && steps.review.outcome == 'failure' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO_FULL: ${{ github.repository }} + WF_RUN_ID: ${{ github.run_id }} + run: | + BODY="🦩 **Flamingo Code Review crashed on this push.** No findings were posted β€” this is an infrastructure failure, not a clean review. See the [workflow run](https://github.com/$REPO_FULL/actions/runs/$WF_RUN_ID)." + CURL_CFG=$(mktemp) && chmod 600 "$CURL_CFG" + printf 'header = "Authorization: Bearer %s"\n' "$GITHUB_TOKEN" > "$CURL_CFG" + curl -s -K "$CURL_CFG" -X POST "https://api.github.com/repos/$REPO_FULL/issues/$PR_NUMBER/comments" \ + -H "Content-Type: application/json" \ + --data "$(printf '%s' "$BODY" | jq -Rs '{body: .}')" > /dev/null || true + rm -f "$CURL_CFG" + + # The report script downloads FIRST (dedicated step above), so a missing + # /tmp/code-review-report.sh here means the report-capability bootstrap + # itself failed (endpoint down, hash mismatch before anything else ran). + # The guarded inline curl below still posts a minimal failure callback for + # exactly that case; the hub's tiered reaper remains the last resort. + - name: Report back to the hub + if: always() && env.HUB_BASE_URL != '' + # RUN_ID / MODE / HUB_BASE_URL arrive via the generated workflow-level + # env. RUN_TOKEN is SENSITIVE (per-run bearer) so it is step-scoped + # HERE β€” the only consumer β€” and masked by the script; the review step + # that processes untrusted PR content never sees it. Remaining step env + # is the secret plus values that exist nowhere but the GitHub context β€” + # which enters through env, never interpolated into a script body. + env: + WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }} + RUN_TOKEN: ${{ github.event.client_payload.run_token || github.event.inputs.run_token || '' }} + JOB_STATUS: ${{ job.status }} + # Either step can degrade a run: the rules step (corpus unavailable) + # or the reviewer itself (trivial-diff skip, unresolvable PR base). + DEGRADED: ${{ steps.rules.outputs.degraded || steps.review.outputs.degraded }} + # Dispatch events carry no pull_request context β€” github.sha is the + # tip of the checked-out ref, so sweep runs record the commit too. + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + WF_RUN_ID: ${{ github.run_id }} + REPO_FULL: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + # The ONE justified inline-bash exception beyond the bootstrap: when the + # report script itself never downloaded, no unified script exists to + # report the failure β€” so a minimal guarded curl posts it. Kept tiny on + # purpose; all real reporting logic stays in code-review-report.sh. + run: | + if [ ! -x /tmp/code-review-report.sh ]; then + echo "::error::code-review-report.sh missing β€” sending bootstrap-failure callback" + # Secrets NEVER ride argv (ps-visible): the bearer goes through a + # 0600 curl config file and RUN_TOKEN through jq's env β€” the same + # transport rule the report script itself follows. + CURL_CFG=$(mktemp) && chmod 600 "$CURL_CFG" + printf 'header = "Authorization: Bearer %s"\n' "$WEBHOOK_SECRET" > "$CURL_CFG" + jq -n --arg run_id "${RUN_ID:-}" \ + --arg wf "$WF_RUN_ID" --arg repo "$REPO_FULL" --arg mode "$MODE" \ + '{run_id: $run_id, run_token: ($ENV.RUN_TOKEN // ""), status: "failure", + degraded_reason: "bootstrap_failed", workflow_run_id: $wf, + repo_full_name: $repo, mode: $mode, + error_message: "Script bootstrap failed: the report script never downloaded from the hub."}' | + curl -sS --max-time 30 -K "$CURL_CFG" -X POST "$HUB_BASE_URL/api/code-review/webhook" \ + -H "Content-Type: application/json" -d @- || true + rm -f "$CURL_CFG" + exit 1 + fi + /tmp/code-review-report.sh