fix(ci): add serialized Gitea merge queue #819

Merged
devops-engineer merged 2 commits from fix/gitea-merge-queue into main 2026-05-13 09:06:02 +00:00
Owner

Summary

  • add a conservative external Gitea merge queue bot for molecule-core
  • add scheduled/manual workflow gitea-merge-queue using the non-bypass devops-engineer token
  • add tests for queue selection, required status evaluation, stale-branch update decisions, and merge readiness
  • document queue operation and update Gitea operational quirks
  • extend Ops Scripts Tests to cover .gitea/scripts/tests

Root Cause

Gitea 1.22.6 has no native merge queue. pull_auto_merge only auto-merges a PR after checks pass; it does not serialize PRs, update each PR against latest main, and require CI on the updated head before merge. That gap lets two previously-green PRs merge back-to-back even if the second was never tested against the first.

Verification

  • python3 -m pytest .gitea/scripts/tests -q => 93 passed
  • python3 .gitea/scripts/lint-workflow-yaml.py --workflow-dir .gitea/workflows
  • python3 -m py_compile .gitea/scripts/gitea-merge-queue.py
  • git diff --check
  • live dry-run with devops-engineer token paused because current main was not green; no merge attempted
  • live repo setup: created merge-queue and merge-queue-hold labels; set molecule-core/main block_on_outdated_branch=true; merge whitelist remains devops-engineer

SOP Checklist

  • Comprehensive testing performed: unit tests, workflow-shape lint, py_compile, diff check, and live dry-run were run.
  • Local-postgres E2E run: N/A for CI bot/script and workflow changes; no database schema or app runtime code changed.
  • Staging-smoke verified or pending: pending post-merge via scheduled/manual queue workflow; dry-run verified the fail-closed main-not-green path.
  • Root-cause not symptom: the gap is lack of serialized retest-on-latest-main semantics in Gitea, not a missing status rerun.
  • Five-Axis review walked: correctness is fail-closed and one-PR-per-run; readability follows existing Gitea helper style; architecture uses labels and Gitea update API; security uses non-bypass merge actor and no token-in-remote; performance is one lightweight cron tick.
  • No backwards-compat shim / dead code added: this adds the active external queue path and docs; no compatibility shim or dead code.
  • Memory/saved-feedback consulted: used existing CI hardening and runner workflow memories plus repo runbooks documenting no native Gitea merge queue.

Rollback

  • Disable .gitea/workflows/gitea-merge-queue.yml schedule or remove merge-queue labels from PRs.
  • Revert this commit if the queue bot misbehaves.
  • Keep branch protection block_on_outdated_branch=true; it is defense-in-depth even without the bot.
## Summary - add a conservative external Gitea merge queue bot for `molecule-core` - add scheduled/manual workflow `gitea-merge-queue` using the non-bypass `devops-engineer` token - add tests for queue selection, required status evaluation, stale-branch update decisions, and merge readiness - document queue operation and update Gitea operational quirks - extend Ops Scripts Tests to cover `.gitea/scripts/tests` ## Root Cause Gitea 1.22.6 has no native merge queue. `pull_auto_merge` only auto-merges a PR after checks pass; it does not serialize PRs, update each PR against latest `main`, and require CI on the updated head before merge. That gap lets two previously-green PRs merge back-to-back even if the second was never tested against the first. ## Verification - [x] `python3 -m pytest .gitea/scripts/tests -q` => 93 passed - [x] `python3 .gitea/scripts/lint-workflow-yaml.py --workflow-dir .gitea/workflows` - [x] `python3 -m py_compile .gitea/scripts/gitea-merge-queue.py` - [x] `git diff --check` - [x] live dry-run with `devops-engineer` token paused because current `main` was not green; no merge attempted - [x] live repo setup: created `merge-queue` and `merge-queue-hold` labels; set `molecule-core/main` `block_on_outdated_branch=true`; merge whitelist remains `devops-engineer` ## SOP Checklist - [x] Comprehensive testing performed: unit tests, workflow-shape lint, py_compile, diff check, and live dry-run were run. - [x] Local-postgres E2E run: N/A for CI bot/script and workflow changes; no database schema or app runtime code changed. - [x] Staging-smoke verified or pending: pending post-merge via scheduled/manual queue workflow; dry-run verified the fail-closed main-not-green path. - [x] Root-cause not symptom: the gap is lack of serialized retest-on-latest-main semantics in Gitea, not a missing status rerun. - [x] Five-Axis review walked: correctness is fail-closed and one-PR-per-run; readability follows existing Gitea helper style; architecture uses labels and Gitea update API; security uses non-bypass merge actor and no token-in-remote; performance is one lightweight cron tick. - [x] No backwards-compat shim / dead code added: this adds the active external queue path and docs; no compatibility shim or dead code. - [x] Memory/saved-feedback consulted: used existing CI hardening and runner workflow memories plus repo runbooks documenting no native Gitea merge queue. ## Rollback - Disable `.gitea/workflows/gitea-merge-queue.yml` schedule or remove `merge-queue` labels from PRs. - Revert this commit if the queue bot misbehaves. - Keep branch protection `block_on_outdated_branch=true`; it is defense-in-depth even without the bot.
hongming added 1 commit 2026-05-13 08:58:34 +00:00
fix(ci): add serialized Gitea merge queue
Some checks failed
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 6s
E2E API Smoke Test / detect-changes (pull_request) Successful in 13s
CI / Detect changes (pull_request) Successful in 14s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 14s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 14s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 11s
qa-review / approved (pull_request) Failing after 11s
gate-check-v3 / gate-check (pull_request) Successful in 16s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 24s
security-review / approved (pull_request) Failing after 17s
sop-checklist-gate / gate (pull_request) Successful in 12s
sop-tier-check / tier-check (pull_request) Successful in 11s
CI / Platform (Go) (pull_request) Successful in 5s
CI / Canvas (Next.js) (pull_request) Successful in 5s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 4s
CI / Python Lint & Test (pull_request) Successful in 4s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 6s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 5s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m19s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m23s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m24s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m29s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m40s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m40s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 2s
9eb8aad5c1
hongming added 1 commit 2026-05-13 08:59:59 +00:00
Merge branch 'main' into fix/gitea-merge-queue
All checks were successful
CI / Detect changes (pull_request) Successful in 23s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 11s
E2E API Smoke Test / detect-changes (pull_request) Successful in 27s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 39s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 17s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 41s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 33s
sop-tier-check / tier-check (pull_request) Successful in 17s
sop-checklist-gate / gate (pull_request) Successful in 21s
gate-check-v3 / gate-check (pull_request) Successful in 26s
CI / Platform (Go) (pull_request) Successful in 8s
CI / Canvas (Next.js) (pull_request) Successful in 8s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 4s
CI / Python Lint & Test (pull_request) Successful in 6s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m16s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 8s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 8s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 5s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m31s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m42s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 12s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m52s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m24s
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m51s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / all-required (pull_request) Successful in 3s
sop-checklist / all-items-acked (pull_request) Manual verified: acked 7/7 by core-qa, infra-sre, core-lead
qa-review / approved (pull_request) Manual verified: qa-review APPROVED by core-qa (team=qa)
security-review / approved (pull_request) Manual verified: security-review APPROVED by core-security (team=security)
audit-force-merge / audit (pull_request) Successful in 8s
c65a43133e
Member

/sop-ack comprehensive-testing reviewed .gitea script tests, workflow lint, py_compile, diff check, and live dry-run evidence
/sop-ack local-postgres-e2e N/A is valid for CI bot/workflow/runbook change
/sop-ack five-axis-review reviewed queue correctness/readability/architecture/security/performance notes
/sop-ack memory-consulted memory and repo runbooks support the Gitea no-native-queue root cause

/sop-ack comprehensive-testing reviewed .gitea script tests, workflow lint, py_compile, diff check, and live dry-run evidence /sop-ack local-postgres-e2e N/A is valid for CI bot/workflow/runbook change /sop-ack five-axis-review reviewed queue correctness/readability/architecture/security/performance notes /sop-ack memory-consulted memory and repo runbooks support the Gitea no-native-queue root cause
Member

/sop-ack staging-smoke queue workflow will verify through scheduled/manual runs post-merge; dry-run confirmed fail-closed when main is not green

/sop-ack staging-smoke queue workflow will verify through scheduled/manual runs post-merge; dry-run confirmed fail-closed when main is not green
Member

/sop-ack root-cause Gitea lacks serialized retest-on-latest-main merge semantics; this is not a missing rerun symptom
/sop-ack no-backwards-compat active queue path only, no compatibility shim or dead code added

/sop-ack root-cause Gitea lacks serialized retest-on-latest-main merge semantics; this is not a missing rerun symptom /sop-ack no-backwards-compat active queue path only, no compatibility shim or dead code added
core-qa approved these changes 2026-05-13 09:02:05 +00:00
core-qa left a comment
Member

QA approval: tests cover queue decisions and local verification passed on refreshed head.

QA approval: tests cover queue decisions and local verification passed on refreshed head.
core-security approved these changes 2026-05-13 09:02:09 +00:00
core-security left a comment
Member

Security approval: uses non-bypass merge actor, does not put tokens into git remotes, and rejects fork PR mutation.

Security approval: uses non-bypass merge actor, does not put tokens into git remotes, and rejects fork PR mutation.
core-lead approved these changes 2026-05-13 09:02:16 +00:00
core-lead left a comment
Member

Lead approval: architecture addresses the merge race by serialization plus current-main checks and branch-protection defense in depth.

Lead approval: architecture addresses the merge race by serialization plus current-main checks and branch-protection defense in depth.
Member

[core-security-agent] APPROVED — PR #819: fix(ci): add serialized Gitea merge queue

Reviewed: .gitea/scripts/gitea-merge-queue.py (new)

Security analysis:

  • urllib.request for HTTP — no subprocess, no shell
  • Token in Authorization header (not URL)
  • Env vars only (GITEA_TOKEN, GITEA_HOST, REPO)
  • No eval/exec of user input
  • Dynamic module loading only in test code (loads from known script path)
  • Merge policy: one PR per run, serialized by cron

OWASP: OWASP X/X clean. No auth/SQL/XSS/SSRF concerns.

[core-security-agent] APPROVED — PR #819: fix(ci): add serialized Gitea merge queue Reviewed: .gitea/scripts/gitea-merge-queue.py (new) Security analysis: - urllib.request for HTTP — no subprocess, no shell ✅ - Token in Authorization header (not URL) ✅ - Env vars only (GITEA_TOKEN, GITEA_HOST, REPO) ✅ - No eval/exec of user input ✅ - Dynamic module loading only in test code (loads from known script path) ✅ - Merge policy: one PR per run, serialized by cron ✅ OWASP: OWASP X/X clean. No auth/SQL/XSS/SSRF concerns.
devops-engineer merged commit 98fe199de4 into main 2026-05-13 09:06:02 +00:00
devops-engineer deleted branch fix/gitea-merge-queue 2026-05-13 09:06:03 +00:00
Sign in to join this conversation.
No description provided.