#!/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= 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=' ACDL Evidence

ACDL Evidence Stream

Evidence timeline will appear here in Phase 05.

Placeholder served via Gitea raw file URL (D-012; Gitea has no native Pages).

' 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: " # 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