#!/usr/bin/env sh set -eu # Tier-1 seed (§22-current). Stands up Gitea content + registry so the current # three-tier app boots, plus a faceted **named collection** (a `.collection.yaml` # with a `fields:` schema + entries carrying metadata) so the §22.4a metadata # UI — faceted filter (SLICE-3), edit panel (SLICE-4), bulk bar (SLICE-5) — can # be exercised end-to-end in a real browser. GITEA="${GITEA_URL:-http://gitea:3000}" ADMIN_USER="${GITEA_ADMIN_USER:-giteaadmin}" ADMIN_PASS="${GITEA_ADMIN_PASSWORD:-giteaadmin-pass}" ORG="${GITEA_ORG:-wiggleverse}" BOT_USER="${GITEA_BOT_USER:-rfc-bot}" BOT_PASS="${GITEA_BOT_PASSWORD:-rfc-bot-pass}" CONTENT_REPO="${META_REPO:-ohm-content}" REGISTRY_REPO="${REGISTRY_REPO:-rfc-registry}" DEFAULT_PROJECT_ID="${DEFAULT_PROJECT_ID:-ohm}" APP_URL="${APP_URL:-http://localhost:8080}" WEBHOOK_SECRET="${GITEA_WEBHOOK_SECRET:-tier1-webhook-secret}" OUT="${SEED_OUT:-/seed/.env.tier1.generated}" echo "seed: waiting for gitea at $GITEA" i=0 while ! curl -sf "$GITEA/api/healthz" >/dev/null 2>&1; do i=$((i+1)); [ "$i" -gt 60 ] && echo "gitea never came up" && exit 1 sleep 2 done auth_admin() { curl -sf -u "$ADMIN_USER:$ADMIN_PASS" "$@"; } # Idempotency guard: if a prior run already wrote a bot token that still works # against THIS gitea (the registry is readable), the stack is already seeded — # skip entirely. This makes a second invocation a true no-op, so a later # dependency-triggered re-run can't delete/remint the token the backend is # already using (that mismatch 401s the registry mirror). A fresh `down -v` # brings up a new gitea where the stale token fails, so the seed re-runs. if [ -f "$OUT" ]; then EXIST_TOK=$(sed -n 's/^GITEA_BOT_TOKEN=//p' "$OUT") if [ -n "$EXIST_TOK" ] && curl -sf -H "Authorization: token $EXIST_TOK" \ "$GITEA/api/v1/repos/$ORG/$REGISTRY_REPO/contents/projects.yaml?ref=main" >/dev/null 2>&1; then echo "seed: existing token valid and registry present — already seeded, skipping" exit 0 fi fi echo "seed: ensuring bot user" auth_admin -X POST "$GITEA/api/v1/admin/users" \ -H 'Content-Type: application/json' \ -d "{\"username\":\"$BOT_USER\",\"email\":\"$BOT_USER@example.test\",\"password\":\"$BOT_PASS\",\"must_change_password\":false}" \ || echo "seed: bot user exists, continuing" echo "seed: ensuring owner user (for OWNER_GITEA_LOGIN)" auth_admin -X POST "$GITEA/api/v1/admin/users" \ -H 'Content-Type: application/json' \ -d "{\"username\":\"owner\",\"email\":\"owner@example.test\",\"password\":\"owner-pass\",\"must_change_password\":false}" \ || echo "seed: owner exists, continuing" echo "seed: minting bot access token (drop any prior 'tier1-bot' first — idempotent)" curl -s -u "$BOT_USER:$BOT_PASS" -X DELETE "$GITEA/api/v1/users/$BOT_USER/tokens/tier1-bot" >/dev/null 2>&1 || true TOKEN=$(curl -sf -u "$BOT_USER:$BOT_PASS" -X POST "$GITEA/api/v1/users/$BOT_USER/tokens" \ -H 'Content-Type: application/json' \ -d '{"name":"tier1-bot","scopes":["write:repository","write:organization","write:user","write:admin"]}' \ | sed -n 's/.*"sha1":"\([^"]*\)".*/\1/p') [ -n "$TOKEN" ] || { echo "seed: failed to mint bot token" ; exit 1; } api() { curl -s -H "Authorization: token $TOKEN" "$@"; } echo "seed: ensuring org $ORG (owned by bot)" api -X POST "$GITEA/api/v1/orgs" -H 'Content-Type: application/json' \ -d "{\"username\":\"$ORG\"}" >/dev/null || echo "seed: org exists, continuing" ensure_repo() { api -X POST "$GITEA/api/v1/orgs/$ORG/repos" -H 'Content-Type: application/json' \ -d "{\"name\":\"$1\",\"auto_init\":true,\"default_branch\":\"main\"}" >/dev/null \ || echo "seed: repo $1 exists, continuing" } # put_file put_file() { _b64=$(printf '%s' "$3" | base64 | tr -d '\n') api -X POST "$GITEA/api/v1/repos/$ORG/$1/contents/$2" \ -H 'Content-Type: application/json' \ -d "{\"message\":\"seed $2\",\"content\":\"$_b64\",\"branch\":\"main\"}" >/dev/null \ || echo "seed: $1/$2 exists, continuing" } register_webhook() { api -X POST "$GITEA/api/v1/repos/$ORG/$1/hooks" \ -H 'Content-Type: application/json' \ -d "{\"type\":\"gitea\",\"active\":true,\"events\":[\"push\",\"pull_request\"],\"config\":{\"url\":\"http://backend:8000/api/webhooks/gitea\",\"content_type\":\"json\",\"secret\":\"$WEBHOOK_SECRET\"}}" >/dev/null \ || echo "seed: webhook on $1 exists, continuing" } echo "seed: ensuring content repo $ORG/$CONTENT_REPO and registry $ORG/$REGISTRY_REPO" ensure_repo "$CONTENT_REPO" ensure_repo "$REGISTRY_REPO" echo "seed: registry projects.yaml (default project '$DEFAULT_PROJECT_ID')" put_file "$REGISTRY_REPO" "projects.yaml" "deployment: name: Tier1 RFC tagline: Tier-1 end-to-end deployment projects: - id: $DEFAULT_PROJECT_ID name: OHM type: document content_repo: $CONTENT_REPO visibility: public " echo "seed: default-collection entry under rfcs/ (no fields — legacy/document path)" put_file "$CONTENT_REPO" "rfcs/intro.md" "--- slug: intro title: Intro state: active id: RFC-0001 owners: [owner] --- # Intro Seed entry for the default (document) collection. " echo "seed: faceted named collection 'bdd' with a fields: schema (§22.4a)" put_file "$CONTENT_REPO" "bdd/.collection.yaml" "type: bdd visibility: public name: BDD Scenarios fields: priority: type: enum values: [P0, P1, P2] label: Priority tags: type: tags label: Tags " # Three entries with varied priority/tags so facets have counts and the bulk # bar has multiple selectable rows. put_file "$CONTENT_REPO" "bdd/rfcs/checkout-guest.md" "--- slug: checkout-guest title: Guest checkout state: active priority: P0 tags: [checkout, payments] --- Guest checkout scenario. " put_file "$CONTENT_REPO" "bdd/rfcs/checkout-returning.md" "--- slug: checkout-returning title: Returning-customer checkout state: active priority: P1 tags: [checkout] --- Returning-customer checkout scenario. " put_file "$CONTENT_REPO" "bdd/rfcs/search-facets.md" "--- slug: search-facets title: Faceted search state: active priority: P0 tags: [search] --- Faceted search scenario. " echo "seed: registering OAuth application" OAUTH_JSON=$(auth_admin -X POST "$GITEA/api/v1/user/applications/oauth2" \ -H 'Content-Type: application/json' \ -d "{\"name\":\"rfc-app-tier1\",\"redirect_uris\":[\"$APP_URL/auth/callback\"],\"confidential_client\":true}") CLIENT_ID=$(printf '%s' "$OAUTH_JSON" | sed -n 's/.*"client_id":"\([^"]*\)".*/\1/p') CLIENT_SECRET=$(printf '%s' "$OAUTH_JSON" | sed -n 's/.*"client_secret":"\([^"]*\)".*/\1/p') echo "seed: registering webhooks (content + registry) -> backend" register_webhook "$CONTENT_REPO" register_webhook "$REGISTRY_REPO" echo "seed: writing generated env to $OUT" cat > "$OUT" <<EOF GITEA_BOT_TOKEN=$TOKEN OAUTH_CLIENT_ID=$CLIENT_ID OAUTH_CLIENT_SECRET=$CLIENT_SECRET EOF echo "seed: done"