Skip to content
Open
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
225 changes: 225 additions & 0 deletions .github/workflows/flamingo-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# 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, which is what makes drift
# detectable by comparison.
name: Flamingo Code Review

on:
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:
inputs:
run_id:
required: false
type: string
run_token:
required: false
type: string
mode:
required: false
type: string
default: sweep

# Superseding a PR cancels the in-flight REVIEW only. The gate job is outside
# this group on purpose: a cancelled required check is a merge deadlock.
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:
# 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 == '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
timeout-minutes: 20
steps:
- 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 }}-

# Same download_and_verify + hash-pinning discipline as the
# doc-orchestrator workflow, fetching the SAME workflow-helpers.sh from
# the SAME scripts endpoint. send_webhook comes from there — the report
# step does not hand-roll its own callback curl.
- name: Fetch shared workflow helpers
env:
HUB_URL: "https://admin-hub.flamingo.so"
WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }}
HASH_WORKFLOW_HELPERS: "11c1019fe69a24325d3849ea27bce73ec81591e3d6f6a72f3b3421cfb72551ea"
run: |
set -euo pipefail
download_and_verify() {
local script_name="$1"
local expected_hash="$2"
local output_path="/tmp/$script_name"
curl -fsSL "$HUB_URL/api/doc-orchestrator/scripts/$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"
exit 1
fi
if [[ "$script_name" == *.sh ]]; then
chmod +x "$output_path"
fi
echo "$script_name verified"
}
download_and_verify "workflow-helpers.sh" "$HASH_WORKFLOW_HELPERS"

- name: Fetch the rule corpus
id: rules
env:
HUB_URL: "https://admin-hub.flamingo.so"
REPO_NAME: "MeshAgent"
WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }}
run: |
set -euo pipefail
# Hash-addressed: the stored corpus hash is sent back, so an unchanged
# corpus answers 304 and a green run costs one conditional request.
# The secret goes in a HEADER, never the query string — a URL with a
# secret in it lands in access logs and proxy history.
prev=$(cat .rules-hash 2>/dev/null || echo '')
code=$(curl -sS -o rules.json -w '%{http_code}' \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
"$HUB_URL/api/code-review/rules?repo=$(printf %s "$REPO_NAME" | jq -sRr @uri)&format=prompt&hash=$prev")
if [ "$code" = "304" ]; then
if [ ! -s rules.json ]; then
echo "::warning::304 with no cached corpus — re-fetching in full."
curl -sS -o rules.json \
-H "Authorization: Bearer $WEBHOOK_SECRET" \
"$HUB_URL/api/code-review/rules?repo=$(printf %s "$REPO_NAME" | jq -sRr @uri)&format=prompt"
else
echo "Corpus unchanged since the last run."
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "http_code=$code" >> "$GITHUB_OUTPUT"
if [ "$code" = "409" ]; then
echo "Review is disabled for this repository — nothing to do."
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "degraded=review_disabled" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "$code" != "200" ]; then
# Fail OPEN but LOUD, and record it: a silent skip on a blocking repo
# is indistinguishable from a clean review.
echo "::warning::Could not fetch the rule corpus (HTTP $code) — review skipped, reported as degraded."
echo "skip=true" >> "$GITHUB_OUTPUT"
echo "degraded=corpus_unavailable_http_$code" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
jq -r '.hash' rules.json > .rules-hash

- name: Review
if: steps.rules.outputs.skip != 'true'
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
MODE: ${{ github.event_name == 'pull_request' && 'pr' || 'sweep' }}
RUN_ID: ${{ github.event.client_payload.run_id || inputs.run_id }}
run: |
set -euo pipefail
# The reviewer itself is delivered by the hub as a hash-pinned script
# (see /api/code-review/scripts). Until that lands this step reports a
# no-op run rather than pretending to have reviewed anything.
echo "::notice::Rule corpus resolved ($(cat .rules-hash)). Reviewer not yet installed."
echo '{"findings":[]}' > findings.json

- name: Report back to the hub
if: always()
env:
HUB_URL: "https://admin-hub.flamingo.so"
WEBHOOK_SECRET: ${{ secrets.DOC_ORCH_WEBHOOK_SECRET }}
RUN_ID: ${{ github.event.client_payload.run_id || inputs.run_id }}
# Minted per run by the hub and shipped in the dispatch. It binds this
# callback to THIS run: the org-wide secret alone would let any repo's
# workflow report against another repo's run. Travels in the payload
# because send_webhook posts JSON and adds no custom headers.
RUN_TOKEN: ${{ github.event.client_payload.run_token || inputs.run_token }}
# ALL GitHub context enters through env, never interpolated into the
# script body — same discipline as the doc-orchestrator workflow.
JOB_STATUS: ${{ job.status }}
DEGRADED: ${{ steps.rules.outputs.degraded }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
WF_RUN_ID: ${{ github.run_id }}
REPO_FULL: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
RUN_MODE: ${{ github.event_name == 'pull_request' && 'pr' || 'sweep' }}
run: |
set -euo pipefail
# send_webhook comes from the doc-orchestrator's verified helpers —
# the same function every documentation run reports through.
source /tmp/workflow-helpers.sh
if [ -n "${DEGRADED:-}" ]; then STATUS=neutral; else STATUS="$JOB_STATUS"; fi
# A sweep carries its run id from the dispatch. A PR run has none, so
# the hub creates the row from this callback.
PAYLOAD=$(jq -n \
--arg run_id "${RUN_ID:-}" \
--arg run_token "${RUN_TOKEN:-}" \
--arg status "$STATUS" \
--arg head_sha "${HEAD_SHA:-}" \
--arg workflow_run_id "$WF_RUN_ID" \
--arg ruleset_hash "$(cat .rules-hash 2>/dev/null || echo '')" \
--arg degraded "${DEGRADED:-}" \
--arg repo_full "$REPO_FULL" \
--arg pr_number "${PR_NUMBER:-}" \
--arg mode "$RUN_MODE" \
--argjson findings "$(jq -c '.findings // []' findings.json 2>/dev/null || echo '[]')" \
'{run_id: $run_id, run_token: $run_token, status: $status,
head_sha: $head_sha, mode: $mode,
repo_full_name: $repo_full,
pr_number: (if $pr_number == "" then null else ($pr_number|tonumber) end),
degraded_reason: (if $degraded == "" then null else $degraded end),
workflow_run_id: $workflow_run_id,
ruleset_hash: (if $ruleset_hash == "" then null else $ruleset_hash end),
findings: $findings}')
# A rejected callback must turn the check red: the job stayed green
# while the hub recorded nothing, which is how PR mode silently
# produced no data at all.
HTTP_CODE=$(send_webhook "$HUB_URL/api/code-review/webhook" "$WEBHOOK_SECRET" "$PAYLOAD" "/tmp/webhook_response.txt") || HTTP_CODE="failed"
echo "Webhook response: $HTTP_CODE"
cat /tmp/webhook_response.txt 2>/dev/null || true
case "$HTTP_CODE" in 2*) ;; *) echo "Hub rejected the callback"; exit 1;; esac
Loading