ci(gitea): shared composite actions + pipeline generator for Gitea Actions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqpXh3hQMMaC74pTjFq4it Gitea 1.25 cannot run reusable workflows (workflow_call), so the logic of deploy-app.yml, smoke.yml and ci.yml moves into composite actions under .gitea/actions/, and each repo gets a thin pipeline rendered by tools/gitea-pipeline/render.py from repos.json. .github/workflows is left untouched (Gitea ignores it once .gitea/workflows exists).
This commit is contained in:
57
.gitea/actions/audit-direct-push/action.yml
Normal file
57
.gitea/actions/audit-direct-push/action.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Audit - direct push to main
|
||||
description: >-
|
||||
Tripwire (Gitea port of main-push-audit.yml): if the pushed commit is not tied
|
||||
to a merged pull request, open an issue labelled policy-violation + audit.
|
||||
Never blocks the push. Uses Gitea's /commits/{sha}/pull API.
|
||||
inputs:
|
||||
token:
|
||||
required: true
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Check commit came from a merged PR
|
||||
shell: bash
|
||||
env:
|
||||
TOKEN: ${{ inputs.token }}
|
||||
PUSHER: ${{ github.event.pusher.username || github.event.pusher.login || github.actor }}
|
||||
HEAD_MSG: ${{ github.event.head_commit.message }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
API="$GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY"
|
||||
H="Authorization: token $TOKEN"
|
||||
SHA="$GITHUB_SHA"; S7="${SHA:0:7}"
|
||||
for attempt in 1 2 3 4 5; do
|
||||
code=$(curl -s -o pr.json -w '%{http_code}' -H "$H" "$API/commits/$SHA/pull" || echo 000)
|
||||
if [ "$code" = 200 ] && python3 -c 'import json,sys; sys.exit(0 if json.load(open("pr.json")).get("merged") else 1)'; then
|
||||
echo "OK: commit $S7 came from PR #$(python3 -c 'import json;print(json.load(open("pr.json"))["number"])')"
|
||||
exit 0
|
||||
fi
|
||||
[ "$attempt" -lt 5 ] && sleep 10
|
||||
done
|
||||
# Ensure both labels exist, collect their ids.
|
||||
ids=()
|
||||
for L in policy-violation audit; do
|
||||
id=$(curl -s -H "$H" "$API/labels?limit=100" | python3 -c "import json,sys; print(next((str(l['id']) for l in json.load(sys.stdin) if l['name']=='$L'),''))")
|
||||
if [ -z "$id" ]; then
|
||||
color=$([ "$L" = audit ] && echo '#1d76db' || echo '#d93f0b')
|
||||
id=$(curl -s -H "$H" -H 'Content-Type: application/json' -X POST "$API/labels" \
|
||||
-d "{\"name\":\"$L\",\"color\":\"$color\"}" | python3 -c 'import json,sys;print(json.load(sys.stdin).get("id",""))')
|
||||
fi
|
||||
[ -n "$id" ] && ids+=("$id")
|
||||
done
|
||||
MSG=$(printf '%s' "$HEAD_MSG" | head -1)
|
||||
python3 - "$S7" "${MSG:-(no message)}" "$PUSHER" "${ids[@]}" > issue.json <<'PY'
|
||||
import json, os, sys
|
||||
s7, msg, pusher, *ids = sys.argv[1:]
|
||||
run = f"{os.environ['GITHUB_SERVER_URL']}/{os.environ['GITHUB_REPOSITORY']}/actions/runs/{os.environ.get('GITHUB_RUN_NUMBER','')}"
|
||||
body = "\n".join([
|
||||
"**Direct push to `main` detected** - commit was not associated with a merged PR.", "",
|
||||
f"- Commit: `{s7}` - {msg}", f"- Pusher: @{pusher}", f"- Workflow run: {run}", "",
|
||||
"The project policy is that all changes to `main` go through a pull request so they can be "
|
||||
"reviewed before deploying to production. If this push was intentional (hotfix, infra change) "
|
||||
"close this issue with a comment explaining why.", "",
|
||||
"_Opened automatically by the audit-direct-push action (peptide-e2e)._"])
|
||||
print(json.dumps({"title": f"Direct push to main: {s7}", "body": body, "labels": [int(i) for i in ids]}))
|
||||
PY
|
||||
code=$(curl -s -o /dev/null -w '%{http_code}' -H "$H" -H 'Content-Type: application/json' -X POST "$API/issues" --data-binary @issue.json)
|
||||
echo "::warning::Opened audit issue for direct push $S7 (HTTP $code)"
|
||||
Reference in New Issue
Block a user