ship: phase-01 repo-scaffolding #1
@@ -67,4 +67,37 @@ The demo is a three-repo, stub-driven system that simulates an autonomous cloud
|
||||
5. Reusable pipeline workflow (Dev → QA → Prod → Finalize) + environment gates.
|
||||
6. Issue-triggered L3B workflow in `acdl-contracts`.
|
||||
7. Evidence UI (`index.html` + Pages config).
|
||||
8. Demo dry-run + the four scripted acts.
|
||||
8. Demo dry-run + the four scripted acts.
|
||||
|
||||
## Gitea API Surface (Phase 01 research)
|
||||
|
||||
Authoritative findings from the Gitea docs (added in RESEARCH; supersedes any
|
||||
GitHub-Pages / GitHub-Environments assumptions carried over from the spec):
|
||||
|
||||
| Capability | Gitea support | ACDL approach |
|
||||
|------------|---------------|---------------|
|
||||
| Org-scoped repo create | `POST /api/v1/orgs/{org}/repos` (`CreateRepoOption`) | Used to create `acdl-contracts` + `acdl-evidence` |
|
||||
| Native Pages | **None** (no `[pages]` config section) | Serve `acdl-evidence` via raw file URLs: `https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html`; `index.html` fetches `audit.json` from the same raw path. Requires `[cors] ENABLED=true` on the server if the UI is loaded cross-origin. |
|
||||
| Environments API | **None**; `jobs.<id>.environment` is ignored by act_runner | Model QA/Prod gates as `workflow_dispatch` approval inputs (D-004 / D-013); optionally create `qa` and `prod` branches as a visible stand-in |
|
||||
| `repository_dispatch` trigger | **Not supported** | Cross-repo trigger via `workflow_dispatch` API: `POST /api/v1/repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches` called from a step using `$GITEA_TOKEN` |
|
||||
| Reusable workflows (`workflow_call`) | Supported | `acdl/.gitea/workflows/pipeline.yml` called via `uses: continuous-intelligence/acdl/.gitea/workflows/pipeline.yml@milestone/v1.0-initial` |
|
||||
| `workflow_dispatch` | Supported (trigger + API) | Used for the manual-approval fallback and the issue workflow's cross-repo trigger |
|
||||
| `issues.opened` trigger | Supported | Drives the L3B issue-trigger workflow in `acdl-contracts` |
|
||||
| `act_runner` labels | Single label only (`runs-on: ubuntu-latest`) | All workflows use `runs-on: ubuntu-latest` |
|
||||
| Context | `${{ gitea.* }}` and `${{ github.* }}` both work | Workflows use `gitea.*` for clarity |
|
||||
|
||||
### Branch pinning rule
|
||||
|
||||
The reusable workflow in the `acdl` repo lives on `milestone/v1.0-initial`
|
||||
(that is the repo's default branch). `uses:` references from `acdl-contracts`
|
||||
must pin to `@milestone/v1.0-initial`, not `@main` (the `acdl` repo has no
|
||||
`main` branch). The new repos `acdl-contracts` and `acdl-evidence` use
|
||||
`default_branch: "main"` (D-015) so their default branch exists immediately
|
||||
for pushes.
|
||||
|
||||
### Default verification toolchain
|
||||
|
||||
There is no `package.json`; ACDL is bash + python stubs. The verification gate
|
||||
substitutes `bash -n` and `python -m py_compile` for `npm run typecheck`, and
|
||||
per-phase `scripts/verify_phaseNN.sh` for `npm test`. `npm run build` is a
|
||||
no-op (no build step). See PERSONAS.md / VERIFICATION note.
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
project: acdl
|
||||
milestone: v1.0
|
||||
generated_at: 2026-07-21
|
||||
generator: lead-developer
|
||||
verification_toolchain:
|
||||
typecheck: "bash -n scripts/**/*.sh modules/**/*.sh && python3 -m py_compile scripts/**/*.py"
|
||||
test: "scripts/verify_phaseNN.sh"
|
||||
build: "no-op (no build step; bash + python stubs)"
|
||||
note: |
|
||||
ACDL has no package.json. The execute/verify/ship workflows substitute
|
||||
bash -n and python -m py_compile for npm run typecheck, a per-phase
|
||||
verify script for npm test, and treat npm run build as a no-op. This
|
||||
override is documented here as the single source of truth; the ci-*
|
||||
agents read PERSONAS.md before running verification commands.
|
||||
---
|
||||
|
||||
# ACDL — Persona Roster (project-level)
|
||||
|
||||
## Active personas
|
||||
|
||||
### lead-developer
|
||||
- **Domain:** coordination
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** (none)
|
||||
- **Constraints:** pragmatic, battle-tested defaults, no-cross-territory-edits
|
||||
- **Territory:** `.ciagent/**`, `scripts/verify_phase*.sh`, `README.md`, `.gitignore`
|
||||
- **Reason:** Owns CIAgent metadata and cross-phase verification scripts.
|
||||
|
||||
### backend-engineer
|
||||
- **Domain:** backend
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** gitea-actions, act_runner, bash, python, yaml
|
||||
- **Constraints:** no-cloud, no-ai, stub-only, hash-chain-must-be-deterministic, max-depth-5
|
||||
- **Territory:** `.gitea/workflows/**`, `scripts/**` (except `scripts/verify_phase*.sh`), `modules/l2/**/manifest.yaml`
|
||||
- **Reason:** Owns workflow YAML, core scripts (mock_executor, policy_checker, confidence_signal, evidence_writer, l3b_agent_stub), and L2 composition manifests.
|
||||
|
||||
### infra-stub-engineer (custom)
|
||||
- **Domain:** backend
|
||||
- **Active:** true
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** bash, yaml
|
||||
- **Constraints:** mock-only, echo-contract-from-D-007, sleep-1s-exit-0, substrate-agnostic, single-purpose
|
||||
- **Territory:** `modules/l1/**`
|
||||
- **Reason:** Created to own L1 stub modules (Phase 02) and their uniform mock_apply.sh behavior per D-007. Domain is backend (bash stubs) but territory is strictly L1 modules to keep L1/L2 concerns separated from workflow YAML.
|
||||
|
||||
## Deactivated personas
|
||||
|
||||
### data-engineer
|
||||
- **Domain:** data
|
||||
- **Active:** false
|
||||
- **Reason:** No persistence layer. ACDL state is flat JSON files (`audit.json`, `state.json`) written by bash/python scripts; no ORM, no migrations, no DB. Schema contracts live in `manifest.yaml` (owned by backend-engineer / infra-stub-engineer).
|
||||
- **Phase-specific:** false
|
||||
- **Frameworks:** (would have been: drizzle, prisma)
|
||||
- **Constraints:** (would have been: schema-first, type-safe-orm)
|
||||
- **Territory:** (would have been: `**/db/**`, `**/migrations/**`)
|
||||
|
||||
### frontend-engineer
|
||||
- **Domain:** frontend
|
||||
- **Active:** false
|
||||
- **Reason:** No UI in Phases 01-04. The single UI artifact (`index.html`, vanilla JS) is built in Phase 05. frontend-engineer is reactivated for Phase 05 only (see Phase-specific overrides below).
|
||||
- **Phase-specific:** true (reactivates in Phase 05)
|
||||
- **Frameworks:** vanilla-js, dom-api, fetch-api
|
||||
- **Constraints:** no-frameworks, single-file, fetch-from-same-origin-raw-url
|
||||
- **Territory:** `acdl-evidence/index.html` (Phase 05)
|
||||
|
||||
## Phase-specific overrides
|
||||
|
||||
| Phase | Personas active | Reactivations / notes |
|
||||
|-------|-----------------|----------------------|
|
||||
| 01 repo-scaffolding | lead-developer, backend-engineer | infra-stub-engineer idle (no L1 work this phase) |
|
||||
| 02 l1-modules | lead-developer, backend-engineer, infra-stub-engineer | infra-stub-engineer owns L1 stubs |
|
||||
| 03 l2-modules-and-core-scripts | lead-developer, backend-engineer, infra-stub-engineer | backend-engineer owns core scripts + L2 manifests; infra-stub-engineer only updates L1 manifests if referenced |
|
||||
| 04 pipeline-and-approval-gates | lead-developer, backend-engineer | infra-stub-engineer idle; frontend-engineer still off |
|
||||
| 05 evidence-ui-and-demo-dry-run | lead-developer, backend-engineer, frontend-engineer | frontend-engineer REACTIVATED for `index.html` only; backend-engineer owns the dry-run script and audit.json wiring |
|
||||
|
||||
## Domain priority (used by TaskDecomposer)
|
||||
|
||||
`coordination -> backend -> infra-stub-engineer -> frontend-engineer (Phase 05 only)`
|
||||
|
||||
## Conflict resolutions (lead-developer arbitration)
|
||||
|
||||
- `backend-engineer` vs `infra-stub-engineer` over `modules/l2/**/manifest.yaml`: backend-engineer owns L2 manifests; infra-stub-engineer owns L1 manifests. No overlap.
|
||||
- `backend-engineer` vs `frontend-engineer` over `acdl-evidence/index.html`: frontend-engineer owns the file in Phase 05; backend-engineer provides the `audit.json` schema contract (event shape) via `evidence_writer.py` and a `SCHEMA.md` note in ARCHITECTURE.md.
|
||||
- `lead-developer` vs any: lead-developer owns `.ciagent/**` and verification scripts; persona engineers do not edit CIAgent metadata.
|
||||
|
||||
## Territory enforcement mode
|
||||
|
||||
`warn` — config.json has no `personas.territory_enforcement` field, so the default per execute.md is `warn`. Cross-territory edits are logged in the commit message but do not fail the task.
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
phase: 01
|
||||
name: repo-scaffolding
|
||||
milestone: v1.0
|
||||
milestone_type: feature
|
||||
status: planned
|
||||
requirements: [REQ-01, REQ-09, REQ-10]
|
||||
must_haves:
|
||||
- "Repo acdl-contracts exists under continuous-intelligence and is pushable (HTTP 200 on GET /repos/continuous-intelligence/acdl-contracts)"
|
||||
- "Repo acdl-evidence exists under continuous-intelligence and is pushable (HTTP 200 on GET /repos/continuous-intelligence/acdl-evidence)"
|
||||
- "Raw URL https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html returns HTTP 200 with placeholder HTML (D-012/D-016 substitute for Pages check)"
|
||||
- "Branches qa and prod exist on acdl-contracts (visible stand-in for unsupported Gitea environments; D-013)"
|
||||
- "scripts/gitea_setup.sh is idempotent and exits 0 (re-running against existing repos is a no-op)"
|
||||
- "scripts/verify_phase01.sh passes: enumerates repos, fetches the raw index.html, lists qa/prod branches, exits 0"
|
||||
verification:
|
||||
typecheck: "bash -n scripts/*.sh"
|
||||
test: "scripts/verify_phase01.sh"
|
||||
build: no-op
|
||||
---
|
||||
|
||||
# Phase 01 — repo-scaffolding PLAN
|
||||
|
||||
## Goal
|
||||
|
||||
Stand up the three-repo scaffold under the `continuous-intelligence` Gitea org
|
||||
and the Phase 01 visible artifacts in the local `acdl` checkout: the
|
||||
Gitea-setup script, the workflow skeletons, and the Phase 01 verification
|
||||
script. After this phase, Phases 02-05 can push stub modules, core scripts,
|
||||
and workflows into the right repos.
|
||||
|
||||
## Requirements covered
|
||||
|
||||
- REQ-01: All demo code lives under `continuous-intelligence` Gitea org
|
||||
- REQ-09: Three repos exist (`acdl`, `acdl-contracts`, `acdl-evidence`)
|
||||
- REQ-10: reusable pipeline runs Dev → QA (approval) → Prod (approval) → Finalize; Phase 01 builds the skeleton (gates wired in Phase 04)
|
||||
|
||||
## Waves (vertical slices, executed in domain priority order)
|
||||
|
||||
### Wave 1 — coordination (lead-developer)
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- **T-1.1** Add `.gitignore` (ignore `audit.json` artifacts, `__pycache__/`, `*.pyc`, `state.json`, `.env`). Create repo directory layout markers: `scripts/.gitkeep`, `modules/l1/.gitkeep`, `modules/l2/.gitkeep`, `.gitea/workflows/.gitkeep`. Add a top-level `README.md` with the project name, the 4-act demo summary, and a pointer to `.ciagent/PROJECT.md`.
|
||||
- **T-1.2** Add `scripts/verify_phase01.sh` — the Phase 01 verification script. It reads `$ACDL_GITEA_TOKEN` from the env, calls the Gitea API to confirm both new repos exist, curls the raw `index.html` URL, lists branches on `acdl-contracts` looking for `qa` and `prod`, and prints a PASS/FAIL summary. Exits 0 on success, non-zero on any failure. Idempotent.
|
||||
|
||||
**Files owned (territory):**
|
||||
- `.gitignore`, `README.md`
|
||||
- `scripts/.gitkeep`, `modules/l1/.gitkeep`, `modules/l2/.gitkeep`, `.gitea/workflows/.gitkeep`
|
||||
- `scripts/verify_phase01.sh`
|
||||
|
||||
**Commits:** one per task, `---ci---` block has `phase: 1, status: plan-as-execute, persona: lead-developer, task: T-1.x, requirements.covered: [REQ-01]`.
|
||||
|
||||
### Wave 2 — backend (backend-engineer)
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- **T-2.1** Add `scripts/gitea_setup.sh`. Idempotent. Reads `$ACDL_GITEA_TOKEN` and `$GITEA_HOST` (default `https://git.cloudinit.dev`). Creates `acdl-contracts` and `acdl-evidence` under `continuous-intelligence` if missing (POST `/orgs/continuous-intelligence/repos` with `auto_init: true`, `default_branch: "main"`, `private: true`). Pushes a placeholder `index.html` to `acdl-evidence` main via the Gitea file-contents API (POST `/repos/{owner}/{repo}/contents/{path}` with base64 content + "Initial placeholder" commit message). Creates `qa` and `prod` branches on `acdl-contracts` from `main` via the Gitea branch API (POST `/repos/{owner}/{repo}/branches`). All HTTP errors are logged with status + body; the script is idempotent (409 / "already exists" treated as success). Uses `curl` + `python3 -c` for base64 encoding; no jq dependency.
|
||||
- **T-2.2** Add `acdl/.gitea/workflows/pipeline.yml` skeleton. `on: workflow_call`. Four jobs: `dev` (runs-on ubuntu-latest, placeholder "Dev stage" step), `qa-gate` (needs dev, runs-on ubuntu-latest, placeholder "Awaiting QA approval" step; in Phase 04 this becomes a `workflow_dispatch` approval input per D-013), `prod-gate` (needs qa-gate, placeholder "Awaiting Prod approval"), `finalize` (needs prod-gate, placeholder "Commit audit.json to acdl-evidence"). All steps are explicit placeholders marked `# Phase 04 will implement`. Comment at top documents the branch-pin rule (`@milestone/v1.0-initial`).
|
||||
- **T-2.3** Add `acdl-contracts/.gitea/workflows/issue-to-contract.yml` skeleton (committed to the `acdl` repo under `contracts-repo/.gitea/workflows/` as a reference copy; pushed to the actual `acdl-contracts` repo in Phase 04). `on: issues` with `types: [opened]`. One job `parse-and-trigger` with placeholder steps for: checkout, run `l3b_agent_stub.py`, commit `contract.yaml`, push, trigger the `acdl` pipeline via `workflow_dispatch` API (D-014). Marked `# Phase 04 will implement`.
|
||||
|
||||
**Files owned (territory):**
|
||||
- `scripts/gitea_setup.sh`
|
||||
- `.gitea/workflows/pipeline.yml`
|
||||
- `contracts-repo/.gitea/workflows/issue-to-contract.yml` (reference copy in the `acdl` repo; source of truth for Phase 04)
|
||||
|
||||
**Commits:** one per task, `---ci---` block has `persona: backend-engineer, task: T-2.x, requirements.covered: [REQ-01 or REQ-09 or REQ-10]`.
|
||||
|
||||
### Wave 3 — coordination (lead-developer, verification wiring)
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- **T-3.1** Run `scripts/gitea_setup.sh` against the live Gitea (executed as part of EXECUTE; recorded as a commit only if it modifies repo state — it does not, so no commit. Instead, the verify run in Wave 3 confirms the artifacts exist via the API.) Add `scripts/verify_phase01.sh` invocation note to README.md ("Run `scripts/verify_phase01.sh` after `scripts/gitea_setup.sh` to confirm Phase 01 success criteria"). Update `.ciagent/REQUIREMENTS.md` Traceability table to mark REQ-01/09/10 as `covered` (pending VERIFY confirmation). Update `.ciagent/ROADMAP.md` Phase 01 status to `executing` (will flip to `complete` on SHIP).
|
||||
|
||||
**Files owned (territory):**
|
||||
- `README.md` (update)
|
||||
- `.ciagent/REQUIREMENTS.md` (traceability update only)
|
||||
- `.ciagent/ROADMAP.md` (phase status update only)
|
||||
|
||||
**Commits:** one for T-3.1 (a `chore(P01)` update with `phase: 1, status: execute, persona: lead-developer, task: T-3.1`).
|
||||
|
||||
## Wave ordering rationale
|
||||
|
||||
- Wave 1 (coordination) creates the directory skeleton + verification script so Wave 2's scripts have a place to live and a check to satisfy.
|
||||
- Wave 2 (backend) builds the Gitea setup script and workflow skeletons.
|
||||
- Wave 3 (coordination) wires the verification script into README and updates traceability after Wave 2's scripts exist.
|
||||
- infra-stub-engineer and frontend-engineer have 0 tasks this phase (per PERSONAS.md), so their persona groups are skipped.
|
||||
|
||||
## Dependencies on other phases
|
||||
|
||||
None. Phase 01 is self-contained. Phases 02-05 depend on Phase 01 having created the two new repos and the workflow skeletons.
|
||||
|
||||
## Risk notes
|
||||
|
||||
- If `gitea_setup.sh` hits a 401/403, treat as an escalation (token scope insufficient). Per run.md Step 4: retry once, then escalate. Do NOT proceed to SHIP with uncreated repos.
|
||||
- The Gitea file-contents API requires the file to NOT already exist on first POST. The script must check existence first (GET) and skip POST if 200. Otherwise 422.
|
||||
- Creating branches requires the default branch to exist first (`auto_init: true` handles this).
|
||||
+7
-1
@@ -69,4 +69,10 @@ Build a runnable demo (Linux + GitHub/Gitea Actions) that walks executives throu
|
||||
| D-007 | Each `mock_apply.sh` echoes `[L1: <name>] applying...` + `OK`, sleeps 1s, exits 0 | Spec literal; uniformity aids timeline parsing | Predictable evidence events |
|
||||
| D-008 | Keyword→stack mapping for L3B: gas/price/ingest/data-lake → commodity-price-feed; invoice/billing → invoice-service; analytics/historical/query → energy-analytics-api; regulatory/compliance/reporting/trading → regulatory-reporting; fallback → invoice-service | Mirrors the 4 L2 modules + Act 3 example issue | Act 3 reproduces deterministic behavior |
|
||||
| D-009 | Init milestone = `v1.0`, branch `milestone/v1.0-initial` | init.md Step 5 mandate | Branching strategy follows convention |
|
||||
| D-010 | Single-project mode for the `acdl` checkout | User chose standalone single-project | `---ci---` blocks omit `project:` field |
|
||||
| D-010 | Single-project mode for the `acdl` checkout | User chose standalone single-project | `---ci---` blocks omit `project:` field |
|
||||
| D-011 | Single-project mode explicitly enforced via `config.json mode: "single"` overriding `projects[]` length signal | run.md Step 0 reads `projects[]` length as multi-project trigger; explicit flag disambiguates | No `project:` prefix in commits or branches |
|
||||
| D-012 | Gitea has no native Pages — serve `acdl-evidence` via raw file URLs (`/raw/branch/main/...`) and a CORS note in ARCHITECTURE.md | Research confirms Gitea has no `[pages]` section | Demo can render `index.html` via raw URL without server-side Pages config |
|
||||
| D-013 | Gitea has no environments API and ignores `jobs.<id>.environment` — model QA/Prod gates as `workflow_dispatch` approval inputs (D-004 fallback) | Research confirms `environment:` blocks are ignored by act_runner | Approval gates become dispatch inputs; "environments" become workflow job names + optional branch protection on `qa`/`prod` branches |
|
||||
| D-014 | Cross-repo triggering uses the `workflow_dispatch` Gitea API (POST `/actions/workflows/{id}/dispatches`) from inside a step instead of `repository_dispatch` | Gitea Actions does not support `repository_dispatch` | Issue-trigger workflow calls the main pipeline via authenticated dispatch from a step |
|
||||
| D-015 | New repos `acdl-contracts` and `acdl-evidence` use `default_branch: "main"` with `auto_init: true` | Matches Gitea `DEFAULT_BRANCH=main`; required for the default branch to exist before any push | Reusable-workflow `uses:` references still pin `acdl` workflows to `@milestone/v1.0-initial` |
|
||||
| D-016 | Pages placeholder for Phase 01 is a minimal HTML stub (`<title>ACDL Evidence</title>` + "evidence stream coming soon"); full UI deferred to Phase 05 | Phase 01 success criterion is "Pages returns 200 with placeholder index.html" but Gitea has no Pages | Raw-URL HTTP 200 against `index.html` substitutes for the Pages check; full timeline UI built in Phase 05 |
|
||||
@@ -35,6 +35,14 @@
|
||||
|
||||
(None — v1 covers the complete demo.)
|
||||
|
||||
## Clarifications (Phase 01)
|
||||
|
||||
| REQ | Original criterion | Clarified criterion (effective) | Decision |
|
||||
|-----|--------------------|----------------------------------|----------|
|
||||
| REQ-09 | Three repos exist | Three repos exist (`acdl`, `acdl-contracts`, `acdl-evidence`) under `continuous-intelligence`; new repos use `default_branch: "main"`, `auto_init: true` | D-015 |
|
||||
| REQ-10 | "Pages returns 200 with placeholder `index.html`" on `acdl-evidence` | Gitea has no Pages; substitute: an HTTP GET against the raw file URL `https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html` returns 200 with the placeholder HTML body | D-012, D-016 |
|
||||
| REQ-10 | "`qa` and `prod` environments exist on `acdl-contracts`" | Gitea has no environments API and ignores `environment:` blocks; substitute: the reusable workflow defines `qa-gate` and `prod-gate` jobs gated by `workflow_dispatch` approval inputs (D-004 fallback); a `qa` and `prod` branch may be created on `acdl-contracts` as a visible stand-in for environments | D-013 |
|
||||
|
||||
## Out of Scope
|
||||
|
||||
| Feature | Reason |
|
||||
@@ -49,7 +57,7 @@
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| REQ-01 | 1 | pending |
|
||||
| REQ-01 | 1 | covered (pending VERIFY) |
|
||||
| REQ-02 | 2 | pending |
|
||||
| REQ-03 | 2 | pending |
|
||||
| REQ-04 | 3 | pending |
|
||||
@@ -57,10 +65,10 @@
|
||||
| REQ-06 | 3 | pending |
|
||||
| REQ-07 | 3 | pending |
|
||||
| REQ-08 | 3 | pending |
|
||||
| REQ-09 | 1 | pending |
|
||||
| REQ-10 | 4 | pending |
|
||||
| REQ-09 | 1 | covered (pending VERIFY) |
|
||||
| REQ-10 | 4 | partial (skeleton in Phase 01; full impl in Phase 04) |
|
||||
| REQ-11 | 3 | pending |
|
||||
| REQ-12 | 4 | pending |
|
||||
| REQ-12 | 4 | partial (skeleton in Phase 01; full impl in Phase 04) |
|
||||
| REQ-13 | 5 | pending |
|
||||
| REQ-14 | 5 | pending |
|
||||
| REQ-15 | 5 | pending |
|
||||
+1
-1
@@ -8,7 +8,7 @@ Five-phase breakdown to take ACDL from empty repo to a reproducible 4-act execut
|
||||
|
||||
### Phase 01 — repo-scaffolding
|
||||
- **Description:** Create the three repos under `continuous-intelligence` (`acdl-contracts`, `acdl-evidence`; `acdl` already exists), seed directory layouts, configure Pages on `acdl-evidence`, add environment protection for `qa` and `prod` on `acdl-contracts`.
|
||||
- **Status:** not_started
|
||||
- **Status:** executing
|
||||
- **Depends on:** —
|
||||
- **Requirements:** REQ-01, REQ-09, REQ-10
|
||||
- **Success Criteria:**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"mode": "single",
|
||||
"projects": [
|
||||
{
|
||||
"slug": "acdl",
|
||||
@@ -47,7 +48,7 @@
|
||||
},
|
||||
"gitea": {
|
||||
"base_url": "https://git.cloudinit.dev",
|
||||
"api_token_env": "b8fa72220e350314704a8a28a0e570b418bb4655",
|
||||
"api_token_env": "ACDL_GITEA_TOKEN",
|
||||
"owner": "continuous-intelligence",
|
||||
"repo": "acdl"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# ACDL reusable pipeline workflow (Phase 01 skeleton).
|
||||
#
|
||||
# This workflow is called from acdl-contracts via:
|
||||
# uses: continuous-intelligence/acdl/.gitea/workflows/pipeline.yml@milestone/v1.0-initial
|
||||
#
|
||||
# Branch pinning rule (see .ciagent/ARCHITECTURE.md): the `acdl` repo's default
|
||||
# branch is `milestone/v1.0-initial`, so `uses:` references must pin to
|
||||
# `@milestone/v1.0-initial`, NOT `@main`.
|
||||
#
|
||||
# Phase 04 will implement the actual stage logic + approval gates (D-013:
|
||||
# Gitea has no environments API; gates become workflow_dispatch approval
|
||||
# inputs).
|
||||
name: acdl-pipeline
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
contract-ref:
|
||||
description: "Ref on acdl-contracts that triggered the pipeline"
|
||||
required: false
|
||||
type: string
|
||||
default: main
|
||||
|
||||
jobs:
|
||||
dev:
|
||||
name: "Dev (autonomous)"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Phase 04 will implement: checkout acdl + acdl-contracts, run
|
||||
# policy_checker.py, mock_executor.sh, confidence_signal.py, write
|
||||
# evidence via evidence_writer.py.
|
||||
- name: "Dev stage placeholder"
|
||||
run: |
|
||||
echo "Dev stage placeholder (Phase 01 skeleton)"
|
||||
echo "Phase 04 will run policy_checker, mock_executor, confidence_signal, evidence_writer"
|
||||
exit 0
|
||||
|
||||
qa-gate:
|
||||
name: "QA (manual approval)"
|
||||
needs: dev
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Phase 04 will implement: gate via workflow_dispatch approval input
|
||||
# (D-013 fallback; Gitea ignores jobs.<id>.environment).
|
||||
- name: "QA gate placeholder"
|
||||
run: |
|
||||
echo "QA gate placeholder (Phase 01 skeleton)"
|
||||
echo "Phase 04 will pause here for human approval via workflow_dispatch"
|
||||
exit 0
|
||||
|
||||
prod-gate:
|
||||
name: "Prod (manual approval)"
|
||||
needs: qa-gate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Phase 04 will implement: same approval-input gate as qa-gate.
|
||||
- name: "Prod gate placeholder"
|
||||
run: |
|
||||
echo "Prod gate placeholder (Phase 01 skeleton)"
|
||||
echo "Phase 04 will pause here for human approval via workflow_dispatch"
|
||||
exit 0
|
||||
|
||||
finalize:
|
||||
name: "Finalize (publish evidence)"
|
||||
needs: prod-gate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Phase 04/05 will implement: commit audit.json to acdl-evidence main
|
||||
# via the Gitea file-contents API; raw URL republishes index.html +
|
||||
# audit.json for the timeline UI (D-012).
|
||||
- name: "Finalize placeholder"
|
||||
run: |
|
||||
echo "Finalize placeholder (Phase 01 skeleton)"
|
||||
echo "Phase 04/05 will commit audit.json to acdl-evidence main"
|
||||
exit 0
|
||||
@@ -0,0 +1,9 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
.env.*
|
||||
state.json
|
||||
audit.json
|
||||
*.tmp
|
||||
.DS_Store
|
||||
@@ -0,0 +1,55 @@
|
||||
# ACDL — Agentic Cloud Delivery Platform
|
||||
|
||||
A 30-minute executive demo proving that infrastructure can be delivered
|
||||
**automatically, safely, and with a complete audit trail** — without the
|
||||
usual weeks of manual tickets, reviews, and copy-pasted configuration.
|
||||
|
||||
The demo runs entirely on **local stubs** (no AWS/GCP/Azure, no external LLM
|
||||
APIs). It shows intent and safety behavior rather than provisioning real
|
||||
cloud resources.
|
||||
|
||||
## Four acts
|
||||
|
||||
1. **Act 1 — The Friction:** the old manual 2-week deployment process.
|
||||
2. **Act 2 — Developer Self-Service:** commit a valid `contract.yaml` for
|
||||
`l2-commodity-price-feed`, watch Dev auto-run, QA + Prod approval gates,
|
||||
then the evidence timeline.
|
||||
3. **Act 3 — Citizen Developer:** open a GitHub/Gitea Issue with natural-
|
||||
language intent; the Python keyword parser generates the same
|
||||
`contract.yaml` and triggers the identical pipeline.
|
||||
4. **Act 4 — The Safety Net:** commit a malicious `contract.yaml`
|
||||
(`public-ingress: true`) for `l2-regulatory-reporting`; the pipeline
|
||||
halts in Dev because the confidence signal drops below 0.50, and the
|
||||
rejection is visible on the evidence stream.
|
||||
|
||||
## Repositories
|
||||
|
||||
All under the `continuous-intelligence` Gitea org at
|
||||
`https://git.cloudinit.dev`:
|
||||
|
||||
- `acdl` (this repo) — platform + stubs + reusable workflows
|
||||
- `acdl-contracts` — developer surface (`contract.yaml` + issue trigger)
|
||||
- `acdl-evidence` — audit timeline (served via raw file URLs; Gitea has no
|
||||
native Pages — see `.ciagent/ARCHITECTURE.md` Gitea API Surface table)
|
||||
|
||||
## Project metadata
|
||||
|
||||
See `.ciagent/PROJECT.md` for the full spec, `.ciagent/ROADMAP.md` for the
|
||||
5-phase breakdown, `.ciagent/REQUIREMENTS.md` for traceable requirements,
|
||||
and `.ciagent/PERSONAS.md` for the active persona roster.
|
||||
|
||||
## Phase 01 verification
|
||||
|
||||
After running `scripts/gitea_setup.sh` (which creates `acdl-contracts` and
|
||||
`acdl-evidence` in the org and pushes the placeholder `index.html`), run:
|
||||
|
||||
```bash
|
||||
ACDL_GITEA_TOKEN=<token> scripts/verify_phase01.sh
|
||||
```
|
||||
|
||||
The script confirms:
|
||||
- both new repos exist via the Gitea API
|
||||
- the raw `index.html` URL on `acdl-evidence` returns HTTP 200
|
||||
- the `qa` and `prod` branches exist on `acdl-contracts`
|
||||
|
||||
Exit 0 = Phase 01 success criteria met.
|
||||
@@ -0,0 +1,40 @@
|
||||
# ACDL issue-to-contract workflow (Phase 01 skeleton, reference copy).
|
||||
#
|
||||
# This file is the source-of-truth copy kept in the `acdl` repo under
|
||||
# contracts-repo/.gitea/workflows/. Phase 04 will push it to the actual
|
||||
# `acdl-contracts` repo under .gitea/workflows/ and implement the real
|
||||
# step bodies.
|
||||
#
|
||||
# Trigger: a new Issue is opened in acdl-contracts. The workflow runs
|
||||
# l3b_agent_stub.py to map the Issue body to a contract.yaml, commits the
|
||||
# contract to a new branch, closes the Issue, and triggers the main
|
||||
# pipeline in the `acdl` repo via the workflow_dispatch API (D-014; Gitea
|
||||
# Actions does not support repository_dispatch).
|
||||
name: issue-to-contract
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
parse-and-trigger:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Phase 04 will implement:
|
||||
# 1. checkout acdl-contracts (so l3b_agent_stub.py is available).
|
||||
# 2. run: python3 scripts/l3b_agent_stub.py "${{ gitea.event.issue.body }}" > contract.yaml
|
||||
# 3. parse the generated contract; commit it to a new branch
|
||||
# (e.g. contract/<issue-number>).
|
||||
# 4. push the branch.
|
||||
# 5. close the Issue with a comment linking to the pipeline run.
|
||||
# 6. trigger the main pipeline:
|
||||
# curl -X POST \
|
||||
# -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
# https://git.cloudinit.dev/api/v1/repos/continuous-intelligence/acdl/actions/workflows/<id>/dispatches \
|
||||
# -d '{"ref":"milestone/v1.0-initial","inputs":{"contract-ref":"<branch>"}}'
|
||||
- name: "Issue-trigger placeholder"
|
||||
run: |
|
||||
echo "issue-to-contract placeholder (Phase 01 skeleton)"
|
||||
echo "Issue body: ${{ gitea.event.issue.body }}"
|
||||
echo "Phase 04 will run l3b_agent_stub.py, commit contract.yaml, close issue, dispatch pipeline"
|
||||
exit 0
|
||||
Executable
+228
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 01 Gitea scaffolding. Idempotent.
|
||||
#
|
||||
# Creates the two new repos under the continuous-intelligence org, pushes a
|
||||
# placeholder index.html to acdl-evidence, and creates qa + prod branches on
|
||||
# acdl-contracts. Running against existing repos / branches / files is a
|
||||
# no-op (409 or 422 is treated as success).
|
||||
#
|
||||
# Usage: ACDL_GITEA_TOKEN=<token> scripts/gitea_setup.sh
|
||||
# Exit codes: 0 = success (created or already existed); 1 = unrecoverable error.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_HOST="${GITEA_HOST:-https://git.cloudinit.dev}"
|
||||
ORG="continuous-intelligence"
|
||||
TOKEN="${ACDL_GITEA_TOKEN:?ACDL_GITEA_TOKEN is required}"
|
||||
API="${GITEA_HOST}/api/v1"
|
||||
|
||||
AUTH=(-H "Authorization: token ${TOKEN}" -H "Content-Type: application/json")
|
||||
|
||||
log() { printf '[setup] %s\n' "$*"; }
|
||||
warn() { printf '[setup][WARN] %s\n' "$*" >&2; }
|
||||
err() { printf '[setup][ERROR] %s\n' "$*" >&2; }
|
||||
|
||||
# --- helpers ----------------------------------------------------------------
|
||||
|
||||
# http_status_code URL
|
||||
http_get_status() {
|
||||
local url="$1"
|
||||
curl -sS -o /dev/null -w "%{http_code}" "${AUTH[@]}" "$url"
|
||||
}
|
||||
|
||||
# repo_exists NAME -> 0 if exists, 1 otherwise
|
||||
repo_exists() {
|
||||
local name="$1"
|
||||
local status
|
||||
status=$(http_get_status "${API}/repos/${ORG}/${name}")
|
||||
[ "$status" = "200" ]
|
||||
}
|
||||
|
||||
# create_repo NAME DESCRIPTION
|
||||
create_repo() {
|
||||
local name="$1"
|
||||
local description="$2"
|
||||
local body
|
||||
body=$(python3 -c "
|
||||
import json, sys
|
||||
print(json.dumps({
|
||||
'name': '${name}',
|
||||
'description': ${description@Q},
|
||||
'private': True,
|
||||
'default_branch': 'main',
|
||||
'auto_init': True,
|
||||
'gitignores': 'Python',
|
||||
'license': '',
|
||||
'readme': 'Default'
|
||||
}))
|
||||
")
|
||||
log "Creating repo ${ORG}/${name} (default_branch=main, auto_init=true)"
|
||||
local status body_out
|
||||
status=$(curl -sS -o /tmp/setup_repo_create.json -w "%{http_code}" \
|
||||
"${AUTH[@]}" -X POST -d "$body" \
|
||||
"${API}/orgs/${ORG}/repos")
|
||||
case "$status" in
|
||||
201) log " created (HTTP 201)" ;;
|
||||
409) log " already exists (HTTP 409); skipping" ;;
|
||||
*)
|
||||
err "create_repo ${name} failed: HTTP ${status}"
|
||||
cat /tmp/setup_repo_create.json >&2 || true
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# set_repo_visibility REPO VISIBILITY (public|private)
|
||||
set_repo_visibility() {
|
||||
local repo="$1"
|
||||
local visibility="$2"
|
||||
local body
|
||||
body=$(python3 -c "
|
||||
import json
|
||||
is_private = ('${visibility}' == 'private')
|
||||
print(json.dumps({'private': is_private, 'visibility': '${visibility}'}))
|
||||
")
|
||||
log "Setting ${repo} visibility to ${visibility}"
|
||||
local status
|
||||
status=$(curl -sS -o /tmp/setup_vis.json -w "%{http_code}" \
|
||||
"${AUTH[@]}" -X PATCH -d "$body" \
|
||||
"${API}/repos/${ORG}/${repo}")
|
||||
case "$status" in
|
||||
200) log " ok (HTTP 200)" ;;
|
||||
*) warn "set_repo_visibility ${repo} -> ${visibility} returned HTTP ${status} (continuing)"; cat /tmp/setup_vis.json >&2 || true ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# file_exists REPO PATH -> 0 if the file already exists on the default branch
|
||||
file_exists_on_default() {
|
||||
local repo="$1"
|
||||
local path="$2"
|
||||
local status
|
||||
status=$(http_get_status "${API}/repos/${ORG}/${repo}/contents/${path}?ref=main")
|
||||
[ "$status" = "200" ]
|
||||
}
|
||||
|
||||
# create_placeholder_index REPO
|
||||
create_placeholder_index() {
|
||||
local repo="$1"
|
||||
local path="index.html"
|
||||
local placeholder
|
||||
placeholder='<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>ACDL Evidence</title>
|
||||
<style>body{font-family:system-ui,sans-serif;margin:2rem;color:#333}</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>ACDL Evidence Stream</h1>
|
||||
<p>Evidence timeline will appear here in Phase 05.</p>
|
||||
<p>Placeholder served via Gitea raw file URL (D-012; Gitea has no native Pages).</p>
|
||||
</body>
|
||||
</html>'
|
||||
|
||||
if file_exists_on_default "$repo" "$path"; then
|
||||
log "index.html already exists on ${repo} main; skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local body
|
||||
body=$(python3 -c "
|
||||
import json, base64
|
||||
content = '''${placeholder}'''
|
||||
print(json.dumps({
|
||||
'content': base64.b64encode(content.encode('utf-8')).decode('ascii'),
|
||||
'message': 'Initial placeholder index.html (Phase 01, D-016)',
|
||||
'branch': 'main'
|
||||
}))
|
||||
")
|
||||
log "Pushing placeholder index.html to ${repo} main"
|
||||
local status
|
||||
status=$(curl -sS -o /tmp/setup_index_push.json -w "%{http_code}" \
|
||||
"${AUTH[@]}" -X POST -d "$body" \
|
||||
"${API}/repos/${ORG}/${repo}/contents/${path}")
|
||||
case "$status" in
|
||||
201) log " pushed (HTTP 201)" ;;
|
||||
409|422) log " already exists or conflict (HTTP ${status}); skipping" ;;
|
||||
*)
|
||||
err "create_placeholder_index on ${repo} failed: HTTP ${status}"
|
||||
cat /tmp/setup_index_push.json >&2 || true
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# branch_exists REPO BRANCH -> 0 if exists
|
||||
branch_exists() {
|
||||
local repo="$1"
|
||||
local branch="$2"
|
||||
local status
|
||||
status=$(http_get_status "${API}/repos/${ORG}/${repo}/branches/${branch}")
|
||||
[ "$status" = "200" ]
|
||||
}
|
||||
|
||||
# create_branch REPO BRANCH FROM_REF
|
||||
create_branch() {
|
||||
local repo="$1"
|
||||
local branch="$2"
|
||||
local from_ref="$3"
|
||||
if branch_exists "$repo" "$branch"; then
|
||||
log "Branch ${branch} already exists on ${repo}; skipping"
|
||||
return 0
|
||||
fi
|
||||
local body
|
||||
body=$(python3 -c "
|
||||
import json
|
||||
print(json.dumps({'new_branch_name': '${branch}', 'old_branch_name': '${from_ref}'}))
|
||||
")
|
||||
log "Creating branch ${branch} on ${repo} from ${from_ref}"
|
||||
local status
|
||||
status=$(curl -sS -o /tmp/setup_branch.json -w "%{http_code}" \
|
||||
"${AUTH[@]}" -X POST -d "$body" \
|
||||
"${API}/repos/${ORG}/${repo}/branches")
|
||||
case "$status" in
|
||||
201) log " created (HTTP 201)" ;;
|
||||
409) log " already exists (HTTP 409); skipping" ;;
|
||||
*)
|
||||
err "create_branch ${branch} on ${repo} failed: HTTP ${status}"
|
||||
cat /tmp/setup_branch.json >&2 || true
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- main -------------------------------------------------------------------
|
||||
|
||||
log "Host: ${GITEA_HOST}"
|
||||
log "Org: ${ORG}"
|
||||
log "Token: <set, ${#TOKEN} chars>"
|
||||
|
||||
# Step 1: create acdl-contracts
|
||||
if ! repo_exists acdl-contracts; then
|
||||
create_repo acdl-contracts "ACDL developer + agentic entry surface (contract.yaml + issue trigger)" || exit 1
|
||||
else
|
||||
log "acdl-contracts already exists; skipping create"
|
||||
fi
|
||||
|
||||
# Step 2: create acdl-evidence
|
||||
if ! repo_exists acdl-evidence; then
|
||||
create_repo acdl-evidence "ACDL hash-chained audit timeline served as a static site via raw file URLs" || exit 1
|
||||
else
|
||||
log "acdl-evidence already exists; skipping create"
|
||||
fi
|
||||
|
||||
# Step 2b: make acdl-evidence public so the Phase 05 UI (index.html) can
|
||||
# fetch audit.json from a browser without exposing the API token (D-012
|
||||
# raw-URL approach). acdl-contracts stays private.
|
||||
set_repo_visibility acdl-evidence public
|
||||
|
||||
# Step 3: push placeholder index.html to acdl-evidence
|
||||
create_placeholder_index acdl-evidence || exit 1
|
||||
|
||||
# Step 4: create qa + prod branches on acdl-contracts (visible stand-in for
|
||||
# the unsupported Gitea environments API; per D-013).
|
||||
create_branch acdl-contracts qa main || exit 1
|
||||
create_branch acdl-contracts prod main || exit 1
|
||||
|
||||
log "Done. Run scripts/verify_phase01.sh to confirm success criteria."
|
||||
exit 0
|
||||
Executable
+109
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
# Phase 01 verification script.
|
||||
# Confirms the three-repo scaffold exists under the continuous-intelligence
|
||||
# Gitea org and that the Phase 01 visible artifacts (placeholder index.html on
|
||||
# acdl-evidence; qa + prod branches on acdl-contracts) are present.
|
||||
#
|
||||
# Usage: ACDL_GITEA_TOKEN=<token> scripts/verify_phase01.sh
|
||||
# Exit codes: 0 = all checks passed; 1 = one or more checks failed.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
GITEA_HOST="${GITEA_HOST:-https://git.cloudinit.dev}"
|
||||
ORG="continuous-intelligence"
|
||||
TOKEN="${ACDL_GITEA_TOKEN:-}"
|
||||
|
||||
fail_count=0
|
||||
note() { printf ' [%s] %s\n' "$1" "$2"; }
|
||||
pass() { note "PASS" "$1"; }
|
||||
fail() { note "FAIL" "$1"; fail_count=$((fail_count + 1)); }
|
||||
warn() { printf ' [WARN] %s\n' "$1" >&2; }
|
||||
|
||||
echo "== Phase 01 verification =="
|
||||
echo "Host: $GITEA_HOST"
|
||||
echo "Org: $ORG"
|
||||
if [ -n "$TOKEN" ]; then
|
||||
echo "Token: <set, ${#TOKEN} chars>"
|
||||
else
|
||||
echo "Token: <unset>"
|
||||
fi
|
||||
echo
|
||||
|
||||
# --- Check 1: acdl-contracts repo exists ---
|
||||
echo "-- Check 1: acdl-contracts repo exists --"
|
||||
status=$(curl -sS -o /tmp/p01_contracts.json -w "%{http_code}" \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
"${GITEA_HOST}/api/v1/repos/${ORG}/acdl-contracts")
|
||||
if [ "$status" = "200" ]; then
|
||||
default_branch=$(python3 -c "import json; print(json.load(open('/tmp/p01_contracts.json')).get('default_branch','?'))")
|
||||
pass "acdl-contracts exists (default_branch=${default_branch})"
|
||||
else
|
||||
fail "acdl-contracts GET returned HTTP ${status}"
|
||||
fi
|
||||
|
||||
# --- Check 2: acdl-evidence repo exists ---
|
||||
echo "-- Check 2: acdl-evidence repo exists --"
|
||||
status=$(curl -sS -o /tmp/p01_evidence.json -w "%{http_code}" \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
"${GITEA_HOST}/api/v1/repos/${ORG}/acdl-evidence")
|
||||
if [ "$status" = "200" ]; then
|
||||
default_branch=$(python3 -c "import json; print(json.load(open('/tmp/p01_evidence.json')).get('default_branch','?'))")
|
||||
pass "acdl-evidence exists (default_branch=${default_branch})"
|
||||
else
|
||||
fail "acdl-evidence GET returned HTTP ${status}"
|
||||
fi
|
||||
|
||||
# --- Check 3: acdl-evidence raw index.html returns 200 (Pages substitute per D-012/D-016) ---
|
||||
# acdl-evidence is public per gitea_setup.sh step 2b, so the raw URL should
|
||||
# work without auth. We also try with the auth header as a fallback so the
|
||||
# check does not spuriously fail if the repo visibility was reset.
|
||||
echo "-- Check 3: acdl-evidence raw index.html returns 200 --"
|
||||
index_url="${GITEA_HOST}/${ORG}/acdl-evidence/raw/branch/main/index.html"
|
||||
status=$(curl -sS -o /tmp/p01_index.html -w "%{http_code}" "${index_url}")
|
||||
if [ "$status" != "200" ] && [ -n "$TOKEN" ]; then
|
||||
warn "raw URL returned ${status} unauth; retrying with Authorization header"
|
||||
status=$(curl -sS -o /tmp/p01_index.html -w "%{http_code}" \
|
||||
-H "Authorization: token ${TOKEN}" "${index_url}")
|
||||
fi
|
||||
if [ "$status" = "200" ]; then
|
||||
body_size=$(wc -c < /tmp/p01_index.html)
|
||||
if grep -q "ACDL Evidence" /tmp/p01_index.html; then
|
||||
pass "raw index.html returns 200 with placeholder body (${body_size} bytes)"
|
||||
else
|
||||
fail "raw index.html returns 200 but body does not contain 'ACDL Evidence' marker"
|
||||
fi
|
||||
else
|
||||
fail "GET ${index_url} returned HTTP ${status}"
|
||||
fi
|
||||
|
||||
# --- Check 4: qa + prod branches exist on acdl-contracts ---
|
||||
echo "-- Check 4: qa + prod branches exist on acdl-contracts --"
|
||||
status=$(curl -sS -o /tmp/p01_branches.json -w "%{http_code}" \
|
||||
-H "Authorization: token ${TOKEN}" \
|
||||
"${GITEA_HOST}/api/v1/repos/${ORG}/acdl-contracts/branches?limit=50")
|
||||
if [ "$status" != "200" ]; then
|
||||
fail "list branches on acdl-contracts returned HTTP ${status}"
|
||||
else
|
||||
for want in qa prod; do
|
||||
if python3 -c "
|
||||
import json, sys
|
||||
branches = json.load(open('/tmp/p01_branches.json'))
|
||||
names = [b.get('name', '') for b in branches]
|
||||
sys.exit(0 if '${want}' in names else 1)
|
||||
"; then
|
||||
pass "branch '${want}' exists on acdl-contracts"
|
||||
else
|
||||
fail "branch '${want}' missing on acdl-contracts"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== Summary =="
|
||||
if [ "$fail_count" -eq 0 ]; then
|
||||
echo "Phase 01 verification PASSED (all checks ok)"
|
||||
exit 0
|
||||
else
|
||||
echo "Phase 01 verification FAILED (${fail_count} check(s) failed)"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user