72b359c9a9
Squash merge of phase/04-pipeline-and-approval-gates; pipeline.yml + issue-to-contract.yml + finalize_evidence.py; verify_phase04.sh green; 1 P0 fixed (shell injection).
153 lines
6.0 KiB
YAML
153 lines
6.0 KiB
YAML
# ACDL pipeline workflow (Phase 04 implementation).
|
|
#
|
|
# 3-dispatch approval-gate topology (D-027 / D-028; ARCHITECTURE.md
|
|
# "Phase 04 pipeline topology"):
|
|
#
|
|
# Dispatch 1 (initial): approve_qa=false, approve_prod=false
|
|
# -> runs the `dev` job (policy check, confidence
|
|
# gate, mock_executor, evidence + finalize).
|
|
# Dispatch 2 (QA approve): approve_qa=true, approve_prod=false
|
|
# -> runs the `qa-gate` job (records QA approval
|
|
# in the audit chain via evidence_writer +
|
|
# finalize_evidence).
|
|
# Dispatch 3 (Prod approve): approve_prod=true
|
|
# -> runs the `prod-gate` job, then the `finalize`
|
|
# job (needs: prod-gate) which writes the final
|
|
# evidence event and commits audit.json to
|
|
# acdl-evidence.
|
|
#
|
|
# Gitea Actions limitations driving this design:
|
|
# - No `repository_dispatch` trigger (D-014).
|
|
# - No environments API / `environment:` blocks are ignored (D-013).
|
|
# - Re-dispatch starts a NEW run; artifacts do NOT survive between runs,
|
|
# so state is persisted to acdl-evidence via the file-contents API
|
|
# (D-028 / finalize_evidence.py) instead of via artifacts.
|
|
#
|
|
# Branch-pin rule (ARCHITECTURE.md "Branch pinning rule"):
|
|
# This workflow lives on `acdl`'s default branch `milestone/v1.0-initial`.
|
|
# Cross-repo `uses:` references (e.g. the issue-trigger's checkout of
|
|
# l3b_agent_stub.py) MUST pin to `@milestone/v1.0-initial`, NOT `@main`
|
|
# (the `acdl` repo has no `main` branch). This workflow is invoked via
|
|
# the workflow_dispatch API (D-014), NOT via `workflow_call`, so the
|
|
# `uses:` rule applies to the issue-trigger's checkout of the acdl repo,
|
|
# not to this file itself.
|
|
name: acdl-pipeline
|
|
|
|
"on":
|
|
workflow_dispatch:
|
|
inputs:
|
|
contract-ref:
|
|
description: "Ref on acdl-contracts that carries the contract"
|
|
required: false
|
|
type: string
|
|
default: main
|
|
approve_qa:
|
|
description: "Human approval to advance past QA"
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
approve_prod:
|
|
description: "Human approval to advance past Prod"
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
jobs:
|
|
dev:
|
|
name: "Dev (autonomous)"
|
|
if: inputs.approve_qa != true && inputs.approve_prod != true
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: "Checkout acdl (this repo, pinned to milestone/v1.0-initial)"
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: milestone/v1.0-initial
|
|
|
|
- name: "Checkout acdl-contracts at contract-ref"
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: continuous-intelligence/acdl-contracts
|
|
ref: ${{ inputs.contract-ref }}
|
|
token: ${{ secrets.GITEA_TOKEN }}
|
|
path: acdl-contracts
|
|
|
|
- name: "Policy check"
|
|
run: |
|
|
python3 scripts/policy_checker.py acdl-contracts/contract.yaml
|
|
|
|
- name: "Confidence signal"
|
|
id: confidence
|
|
run: |
|
|
set +e
|
|
SCORE_JSON=$(python3 scripts/confidence_signal.py acdl-contracts/contract.yaml)
|
|
echo "$SCORE_JSON"
|
|
echo "score_json=$SCORE_JSON" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: "Apply or reject based on confidence (gate < 0.50)"
|
|
run: |
|
|
set +e
|
|
SCORE=$(python3 -c "import json,sys; print(json.load(sys.stdin)['score'])" <<< '${{ steps.confidence.outputs.score_json }}')
|
|
python3 -c "import sys; sys.exit(0 if float('${SCORE}') >= 0.50 else 1)"
|
|
THRESHOLD_RC=$?
|
|
if [ "$THRESHOLD_RC" -ne 0 ]; then
|
|
python3 scripts/evidence_writer.py --stage dev --event "dev rejected: confidence < 0.50" --audit audit.json
|
|
python3 scripts/finalize_evidence.py --audit audit.json
|
|
exit 1
|
|
fi
|
|
STACK=$(python3 -c 'import yaml; print(yaml.safe_load(open("acdl-contracts/contract.yaml"))["stack"])')
|
|
bash scripts/mock_executor.sh acdl-contracts/contract.yaml
|
|
python3 scripts/evidence_writer.py --stage dev --event "dev applied: ${STACK}" --audit audit.json
|
|
python3 scripts/finalize_evidence.py --audit audit.json
|
|
|
|
- name: "Upload dev state artifacts (best-effort)"
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: dev-state
|
|
path: |
|
|
audit.json
|
|
state.json
|
|
|
|
qa-gate:
|
|
name: "QA (manual approval)"
|
|
if: inputs.approve_qa == true && inputs.approve_prod != true
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: "Checkout acdl (this repo, pinned to milestone/v1.0-initial)"
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: milestone/v1.0-initial
|
|
|
|
- name: "Record QA approval in evidence"
|
|
run: |
|
|
python3 scripts/evidence_writer.py --stage qa --event "qa approved" --audit audit.json
|
|
python3 scripts/finalize_evidence.py --audit audit.json
|
|
|
|
prod-gate:
|
|
name: "Prod (manual approval)"
|
|
if: inputs.approve_prod == true
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: "Checkout acdl (this repo, pinned to milestone/v1.0-initial)"
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: milestone/v1.0-initial
|
|
|
|
- name: "Record Prod approval in evidence"
|
|
run: |
|
|
python3 scripts/evidence_writer.py --stage prod --event "prod approved" --audit audit.json
|
|
python3 scripts/finalize_evidence.py --audit audit.json
|
|
|
|
finalize:
|
|
name: "Finalize (publish evidence)"
|
|
needs: [prod-gate]
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: "Checkout acdl (this repo, pinned to milestone/v1.0-initial)"
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: milestone/v1.0-initial
|
|
|
|
- name: "Write finalize event + commit audit.json to acdl-evidence"
|
|
run: |
|
|
python3 scripts/evidence_writer.py --stage finalize --event "pipeline complete: audit.json committed to acdl-evidence" --audit audit.json
|
|
python3 scripts/finalize_evidence.py --audit audit.json |