* feat: Add GitHub Actions workflows for security audits, CodeQL analysis, contributor updates, performance benchmarks, integration tests, fuzz testing, and reusable Rust build jobs - Implemented `sec-audit.yml` for Rust package security audits using `rustsec/audit-check` and `cargo-deny-action`. - Created `sec-codeql.yml` for CodeQL analysis scheduled twice daily. - Added `sync-contributors.yml` to update the NOTICE file with new contributors automatically. - Introduced `test-benchmarks.yml` for performance benchmarks using Criterion. - Established `test-e2e.yml` for running integration and end-to-end tests. - Developed `test-fuzz.yml` for fuzz testing with configurable runtime. - Created `test-rust-build.yml` as a reusable job for executing Rust commands with customizable parameters. - Documented main branch delivery flows in `main-branch-flow.md` for clarity on CI/CD processes. * ci(workflows): update workflow scripts and rename for clarity; remove obsolete lint feedback script * chore(ci): externalize workflow scripts and relocate main flow doc
9.4 KiB
9.4 KiB
Main Branch Delivery Flows
This document explains what runs when code is proposed to main, merged into main, and released via tags.
Use this with:
Event Summary
| Event | Main workflows |
|---|---|
PR activity (pull_request_target) |
pr-intake-checks.yml, pr-labeler.yml, pr-auto-response.yml |
PR activity (pull_request) |
ci-run.yml, sec-audit.yml, plus path-scoped pub-docker-img.yml, workflow-sanity.yml, pr-label-policy-check.yml |
Push to main |
ci-run.yml, sec-audit.yml, plus path-scoped workflows |
Tag push (v*) |
pub-release.yml, pub-docker-img.yml publish job |
| Scheduled/manual | sec-codeql.yml, feature-matrix.yml, test-fuzz.yml, pr-check-stale.yml, pr-check-status.yml, sync-contributors.yml, test-benchmarks.yml, test-e2e.yml |
Runtime and Docker Matrix
Observed averages below are from recent completed runs (sampled from GitHub Actions on February 17, 2026). Values are directional, not SLA.
| Workflow | Typical trigger in main flow | Avg runtime | Docker build? | Docker run? | Docker push? |
|---|---|---|---|---|---|
pr-intake-checks.yml |
PR open/update (pull_request_target) |
14.5s | No | No | No |
pr-labeler.yml |
PR open/update (pull_request_target) |
53.7s | No | No | No |
pr-auto-response.yml |
PR/issue automation | 24.3s | No | No | No |
ci-run.yml |
PR + push to main |
74.7s | No | No | No |
sec-audit.yml |
PR + push to main |
127.2s | No | No | No |
workflow-sanity.yml |
Workflow-file changes | 34.2s | No | No | No |
pr-label-policy-check.yml |
Label policy/automation changes | 14.7s | No | No | No |
pub-docker-img.yml (pull_request) |
Docker-related PR changes | 240.4s | Yes | Yes | No |
pub-docker-img.yml (push tag) |
Tag push v* |
139.9s | Yes | No | Yes |
pub-release.yml |
Tag push v* |
N/A in recent sample | No | No | No |
Notes:
pub-docker-img.ymlis the only workflow in the main PR/push path that builds Docker images.- Container runtime verification (
docker run) occurs in PR smoke only. - Container registry push occurs on tag pushes only.
ci-run.yml"Build (Smoke)" builds Rust binaries, not Docker images.
Step-By-Step
1) PR from branch in this repository -> main
- Contributor opens or updates PR against
main. pull_request_targetautomation runs (typical runtime):pr-intake-checks.ymlposts intake warnings/errors.pr-labeler.ymlsets size/risk/scope labels.pr-auto-response.ymlruns first-interaction and label routes.
pull_requestCI workflows start:ci-run.ymlsec-audit.yml- path-scoped workflows if matching files changed:
pub-docker-img.yml(Docker-related paths only)workflow-sanity.yml(workflow files only)pr-label-policy-check.yml(label-policy files only)
- In
ci-run.yml,changescomputes:docs_onlydocs_changedrust_changedworkflow_changed
buildruns for Rust-impacting changes.- On PRs, full lint/test/docs checks run when PR has label
ci:full:lintlint-strict-deltatestdocs-quality
- If
.github/workflows/**changed,workflow-owner-approvalmust pass. lint-feedbackposts actionable comment if lint/docs gates fail.CI Required Gateaggregates results to final pass/fail.- Maintainer merges PR once checks and review policy are satisfied.
- Merge emits a
pushevent onmain(see scenario 3).
2) PR from fork -> main
- External contributor opens PR from
fork/<branch>intozeroclaw:main. - Immediately on
opened:pull_request_targetworkflows start with base-repo context and base-repo token:pr-intake-checks.ymlpr-labeler.ymlpr-auto-response.yml
pull_requestworkflows are queued for the fork head commit:ci-run.ymlsec-audit.yml- path-scoped workflows (
pub-docker-img.yml,workflow-sanity.yml,pr-label-policy-check.yml) if changed files match.
- Fork-specific permission behavior in
pull_requestworkflows:- token is restricted (read-focused), so jobs that try to write PR comments/status extras can be limited.
- secrets from the base repo are not exposed to fork PR
pull_requestjobs.
- Approval gate possibility:
- if Actions settings require maintainer approval for fork workflows, the
pull_requestrun stays inaction_required/waiting state until approved.
- if Actions settings require maintainer approval for fork workflows, the
- Event fan-out after labeling:
pr-labeler.ymland manual label changes emitlabeled/unlabeledevents.- those events retrigger
pull_request_targetautomation (pr-labeler.ymlandpr-auto-response.yml), creating extra run volume/noise.
- When contributor pushes new commits to fork branch (
synchronize):- reruns:
pr-intake-checks.yml,pr-labeler.yml,ci-run.yml,sec-audit.yml, and matching path-scoped PR workflows. - does not rerun
pr-auto-response.ymlunless label/open events occur.
- reruns:
ci-run.ymlexecution details for fork PR:changescomputesdocs_only,docs_changed,rust_changed,workflow_changed.buildruns for Rust-impacting changes.lint/lint-strict-delta/test/docs-qualityrun on PR whenci:fulllabel exists.workflow-owner-approvalruns when.github/workflows/**changed.CI Required Gateemits final pass/fail for the PR head.
- Fork PR merge blockers to check first when diagnosing stalls:
- run approval pending for fork workflows.
workflow-owner-approvalfailing on workflow-file changes.CI Required Gatefailure caused by upstream jobs.- repeated
pull_request_targetreruns from label churn causing noisy signals.
- After merge, normal
pushworkflows onmainexecute (scenario 3).
3) Push to main (including after merge)
- Commit reaches
main(usually from a merged PR). ci-run.ymlruns onpush.sec-audit.ymlruns onpush.- Path-filtered workflows run only if touched files match their filters.
- In
ci-run.yml, push behavior differs from PR behavior:- Rust path:
lint,lint-strict-delta,test,buildare expected. - Docs/non-rust paths: fast-path behavior applies.
- Rust path:
CI Required Gatecomputes overall push result.
Docker Publish Logic
Workflow: .github/workflows/pub-docker-img.yml
PR behavior
- Triggered on
pull_requesttomainwhen Docker-related paths change. - Runs
PR Docker Smokejob:- Builds local smoke image with Blacksmith builder.
- Verifies container with
docker run ... --version.
- Typical runtime in recent sample: ~240.4s.
- No registry push happens on PR events.
Push behavior
publishjob runs only whengithub.event_name == 'push'and ref starts withrefs/tags/.- Tag format expected by workflow trigger is
v*. - Login to
ghcr.iouses${{ github.actor }}and${{ secrets.GITHUB_TOKEN }}. - Tag computation includes:
- semantic tag from pushed git tag (
vX.Y.Z) - SHA tag (
sha-<12 chars>)
- semantic tag from pushed git tag (
- Multi-platform publish is used for tag pushes (
linux/amd64,linux/arm64). - Typical runtime in recent sample: ~139.9s.
- Result: pushed image tags under
ghcr.io/<owner>/<repo>.
Important: Docker publish does not run on plain main pushes anymore.
Release Logic
Workflow: .github/workflows/pub-release.yml
- Triggered only on tag push
v*. - Builds release artifacts across matrix targets.
- Generates SBOM (
CycloneDX+SPDX). - Generates
SHA256SUMS. - Signs artifacts with keyless cosign.
- Publishes GitHub Release with artifacts.
Merge/Policy Notes
- Workflow-file changes (
.github/workflows/**) activate owner-approval gate inci-run.yml. - PR lint/test strictness is intentionally controlled by
ci:fulllabel. sec-audit.ymlruns on both PR and push, plus scheduled weekly.- Some workflows are operational and non-merge-path (
pr-check-stale,pr-check-status,sync-contributors, etc.). - Workflow-specific JavaScript helpers are organized under
.github/workflows/scripts/.
Mermaid Diagrams
PR to Main (Internal/Fork)
flowchart TD
A["PR opened or updated -> main"] --> B["pull_request_target lane"]
B --> B1["pr-intake-checks.yml"]
B --> B2["pr-labeler.yml"]
B --> B3["pr-auto-response.yml"]
A --> C["pull_request CI lane"]
C --> C1["ci-run.yml"]
C --> C2["sec-audit.yml"]
C --> C3["pub-docker-img.yml (if Docker paths changed)"]
C --> C4["workflow-sanity.yml (if workflow files changed)"]
C --> C5["pr-label-policy-check.yml (if policy files changed)"]
C1 --> D["CI Required Gate"]
D --> E{"Checks + review policy pass?"}
E -->|No| F["PR stays open"]
E -->|Yes| G["Merge PR"]
G --> H["push event on main"]
Push/Tag Delivery
flowchart TD
A["Commit reaches main"] --> B["ci-run.yml"]
A --> C["sec-audit.yml"]
A --> D["path-scoped workflows (if matched)"]
T["Tag push v*"] --> R["pub-release.yml"]
T --> P["pub-docker-img.yml publish job"]
R --> R1["Artifacts + SBOM + checksums + signatures + GitHub Release"]
P --> P1["Push ghcr image tags (version + sha)"]
Quick Troubleshooting
- Unexpected skipped jobs: inspect
scripts/ci/detect_change_scope.shoutputs. - Workflow-change PR blocked: verify
WORKFLOW_OWNER_LOGINSand approvals. - Fork PR appears stalled: check whether Actions run approval is pending.
- Docker not published: confirm a
v*tag push happened (plainmainpush will not publish).