Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
357 changes: 357 additions & 0 deletions .github/workflows/flamingo-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
# 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'

pull_request:
types: [opened, synchronize, 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
# Sweep mode scans the WHOLE repo, not a diff — budgeted accordingly
# (the doc sibling budgets 720 for its whole-repo stages).
timeout-minutes: 60
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: "11c1019fe69a24325d3849ea27bce73ec81591e3d6f6a72f3b3421cfb72551ea"
HASH_REPORT: "fcf168962ebc58a4690d57ad275eb96925d0fd7c3ed89ce19fcf45dca86928ba"
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

- name: Check out the code under review
uses: actions/checkout@v4
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.
- name: Restore the last corpus hash
uses: actions/cache@v4
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: "5426fb033aba570a40f343542c123a7630638b26b5508914300ad791771adade"
HASH_RUN: "e4ebfe017a09ed3f783c8aea995a079be46b4add3b3f92db1918291d1b3e7412"
HASH_MINE: "fdc21c2e221c5667f0c7f66191ab31562a11aa55384a639fccb1f64b7e296ae4"
HASH_REVIEW: "b2d6a5ae15ca671a8e897ca868aa948ff2c6944a8616dff2806b5c00ebab5772"
HASH_LIB: "acaab8052d01ef0055693999ac28bada91da18235da8be98536f59e11412110f"
HASH_POST: "9d182d17a36c80f2a4a37b768406b12b93bd29be220cf3290f45aa208a8d6942"
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 }}
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

# 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"
jq -n --arg run_id "${RUN_ID:-}" --arg run_token "${RUN_TOKEN:-}" \
--arg wf "$WF_RUN_ID" --arg repo "$REPO_FULL" --arg mode "$MODE" \
'{run_id: $run_id, run_token: $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 -X POST "$HUB_BASE_URL/api/code-review/webhook" \
-H "Content-Type: application/json" -H "Authorization: Bearer $WEBHOOK_SECRET" -d @- || true
exit 1
fi
/tmp/code-review-report.sh
Loading