diff --git a/.gitea/workflows/auto-deploy.yml b/.gitea/workflows/auto-deploy.yml index 4da38cf..1e578af 100644 --- a/.gitea/workflows/auto-deploy.yml +++ b/.gitea/workflows/auto-deploy.yml @@ -14,56 +14,14 @@ jobs: with: fetch-depth: 2 - - name: Detect changed stacks and trigger Komodo webhooks + - name: Detect changed stacks and deploy via Komodo API + env: + KOMODO_URL: ${{ secrets.KOMODO_URL }} + KOMODO_API_KEY: ${{ secrets.KOMODO_API_KEY }} + KOMODO_API_SECRET: ${{ secrets.KOMODO_API_SECRET }} run: | set -euo pipefail - # --------------------------------------------------------------- - # Webhook map: stack-name → Komodo webhook URL - # Komodo webhook URLs are self-authenticating (token is embedded - # in the URL path). Fill in URLs from: - # Komodo UI → Stack → Webhooks tab → copy the full URL - # --------------------------------------------------------------- - declare -A WEBHOOK_MAP - - # heimdall stacks - WEBHOOK_MAP["5etools"]="TODO" - WEBHOOK_MAP["authentik"]="TODO" - WEBHOOK_MAP["bentopdf"]="TODO" - WEBHOOK_MAP["byparr"]="TODO" - WEBHOOK_MAP["convertx"]="TODO" - WEBHOOK_MAP["core"]="TODO" - WEBHOOK_MAP["docker_registry"]="TODO" - WEBHOOK_MAP["gitea"]="TODO" - WEBHOOK_MAP["guardian"]="TODO" - WEBHOOK_MAP["homelab-registry-mcp"]="TODO" - WEBHOOK_MAP["karakeep"]="TODO" - WEBHOOK_MAP["kitchenowl"]="TODO" - WEBHOOK_MAP["ntfy"]="TODO" - WEBHOOK_MAP["overseerr"]="TODO" - WEBHOOK_MAP["profilarr"]="TODO" - WEBHOOK_MAP["prowlarr"]="TODO" - WEBHOOK_MAP["radarr"]="TODO" - WEBHOOK_MAP["sabnzbd"]="TODO" - WEBHOOK_MAP["snapotter"]="TODO" - WEBHOOK_MAP["sonarr"]="TODO" - WEBHOOK_MAP["sparkyfitness"]="TODO" - WEBHOOK_MAP["tautulli"]="TODO" - WEBHOOK_MAP["tracearr"]="TODO" - WEBHOOK_MAP["trek"]="TODO" - WEBHOOK_MAP["vaultwarden"]="TODO" - WEBHOOK_MAP["vscode"]="TODO" - WEBHOOK_MAP["weatherchannel"]="TODO" - WEBHOOK_MAP["wizarr"]="TODO" - WEBHOOK_MAP["zipline"]="TODO" - - # waldorf stacks - WEBHOOK_MAP["immich"]="TODO" - WEBHOOK_MAP["openwebui"]="TODO" - WEBHOOK_MAP["pinchflat"]="TODO" - WEBHOOK_MAP["plex"]="TODO" - WEBHOOK_MAP["tunarr"]="TODO" - # --------------------------------------------------------------- # Detect changed paths vs the previous commit # --------------------------------------------------------------- @@ -83,7 +41,6 @@ jobs: # --------------------------------------------------------------- declare -A SEEN_STACKS declare -a STACKS_TO_DEPLOY - declare -a UNMATCHED_PATHS while IFS= read -r filepath; do [[ -z "$filepath" ]] && continue @@ -104,60 +61,38 @@ jobs: [[ -n "${SEEN_STACKS[$stack]+_}" ]] && continue SEEN_STACKS["$stack"]=1 - if [[ -n "${WEBHOOK_MAP[$stack]+_}" ]]; then - STACKS_TO_DEPLOY+=("$stack") - echo " Queued for deploy: $stack (node: $node)" - else - UNMATCHED_PATHS+=("$filepath (stack: $stack)") - fi + STACKS_TO_DEPLOY+=("$stack") + echo " Queued for deploy: $stack (node: $node)" done <<< "$CHANGED_FILES" echo "" - # --------------------------------------------------------------- - # Warn about paths that have no webhook entry — not silent - # --------------------------------------------------------------- - if [[ "${#UNMATCHED_PATHS[@]}" -gt 0 ]]; then - echo "=== WARNING: paths with no matching webhook entry ===" - for p in "${UNMATCHED_PATHS[@]}"; do - echo " - $p" - done - echo " Add these stack names to WEBHOOK_MAP in this workflow." - echo "" - fi - - # --------------------------------------------------------------- - # Nothing under nodes/ changed - # --------------------------------------------------------------- if [[ "${#STACKS_TO_DEPLOY[@]}" -eq 0 ]]; then echo "No stack changes detected — nothing to deploy." exit 0 fi # --------------------------------------------------------------- - # POST to each Komodo webhook + # Call Komodo DeployStack API for each changed stack # --------------------------------------------------------------- - echo "=== Triggering Komodo webhooks ===" + echo "=== Triggering Komodo deployments ===" FAILED=0 for stack in "${STACKS_TO_DEPLOY[@]}"; do - url="${WEBHOOK_MAP[$stack]}" - - if [[ "$url" == "TODO" ]]; then - echo " SKIP: $stack — webhook URL not configured yet (fill in WEBHOOK_MAP)" - continue - fi - echo -n " → $stack ... " HTTP_STATUS=$(curl --silent --show-error --output /dev/null \ --write-out "%{http_code}" \ --max-time 30 \ - --request POST "$url" \ + --request POST "${KOMODO_URL}/execute/DeployStack" \ --header "Content-Type: application/json" \ - --data '{"trigger":"gitea-push"}') + --header "X-Api-Key: ${KOMODO_API_KEY}" \ + --header "X-Api-Secret: ${KOMODO_API_SECRET}" \ + --data "{\"stack\": \"${stack}\"}") if [[ "$HTTP_STATUS" =~ ^2 ]]; then echo "HTTP $HTTP_STATUS OK" + elif [[ "$HTTP_STATUS" == "404" ]]; then + echo "HTTP 404 WARNING — stack not found in Komodo (not yet registered?)" else echo "HTTP $HTTP_STATUS FAILED" FAILED=1 @@ -166,8 +101,8 @@ jobs: echo "" if [[ "$FAILED" -ne 0 ]]; then - echo "ERROR: One or more Komodo webhook POSTs returned a non-2xx status." + echo "ERROR: One or more Komodo API calls returned a non-2xx status." exit 1 fi - echo "All webhooks triggered successfully." + echo "All deployments triggered successfully." diff --git a/README.md b/README.md index f988ccb..4c5b67a 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,9 @@ Merging a PR to `main` automatically deploys every stack whose folder changed. **Before it goes live you need:** - A Gitea Actions runner installed on Heimdall (see [SOP-003](documentation/SOPs/SOP-003-Gitea-Actions-Runner-Setup.md)) -- All `TODO` webhook URLs in `WEBHOOK_MAP` replaced with the actual Komodo webhook URLs - (Komodo UI → Stack → Webhooks tab → copy the full self-authenticating URL) +- A Komodo service user (`gitea-ci`) with Stack → Execute permissions and an API key generated +- Three Gitea repo secrets configured: `KOMODO_URL`, `KOMODO_API_KEY`, `KOMODO_API_SECRET` +- Stack folder names in this repo must match stack names in Komodo UI --- diff --git a/documentation/SOPs/SOP-003-Gitea-Actions-Runner-Setup.md b/documentation/SOPs/SOP-003-Gitea-Actions-Runner-Setup.md index 1392c33..a38b9bd 100644 --- a/documentation/SOPs/SOP-003-Gitea-Actions-Runner-Setup.md +++ b/documentation/SOPs/SOP-003-Gitea-Actions-Runner-Setup.md @@ -12,8 +12,8 @@ Install and register a Gitea Actions runner on Heimdall so that the `.gitea/workflows/auto-deploy.yml` workflow can execute when PRs are merged -to `main`. The runner triggers Komodo webhooks for any stack whose folder -changed in the push. +to `main`. The runner calls the Komodo REST API to redeploy any stack whose +folder changed in the push — no per-stack webhook URLs required. --- @@ -23,7 +23,8 @@ changed in the push. - [ ] Docker and Docker Compose running on Heimdall - [ ] Gitea instance accessible at `https://git.castaldifamily.com` - [ ] Admin or repo-owner access to the `nathan/homelab` Gitea repository -- [ ] Komodo webhook URLs retrieved from Komodo UI (see [Step 4](#step-4--add-required-secrets-in-gitea)) +- [ ] Komodo service user created with Stack → Execute permissions (see [Step 4](#step-4--create-komodo-service-user-and-api-key)) +- [ ] API key + secret copied and ready to add as Gitea secrets --- @@ -108,38 +109,43 @@ Verify the runner appears in Gitea: --- -## Step 4 — Add Required Secrets in Gitea +## Step 4 — Create Komodo Service User and API Key -The auto-deploy workflow does not use a shared secret (Komodo webhook URLs -are self-authenticating). No repository secrets are required for the -workflow itself. +The workflow authenticates to Komodo using a dedicated service user with +minimal permissions. Do not use your personal admin account. -If you later need to store additional credentials (e.g., a Komodo API key -for a future workflow), add them at: - -> **Repository** → **Settings** → **Secrets and Variables** → **Actions** → **New secret** - ---- - -## Step 5 — Fill In Webhook URLs - -Open `.gitea/workflows/auto-deploy.yml` in the repo and replace each `TODO` -value in `WEBHOOK_MAP` with the actual URL from Komodo: +### 4a — Create the service user 1. Log into Komodo UI (`https://komodo.castaldifamily.com`) -2. Navigate to **Stacks** → select the stack -3. Open the **Webhooks** tab -4. Copy the full webhook URL (token is embedded in the path) -5. Paste it as the map value for that stack name +2. Go to **Settings** → **Users** → **New User** +3. Set type to **Service** +4. Name it something like `gitea-ci` +5. Grant **Execute** permission on **Stacks** only — no write or delete access +6. Save the user -Commit the updated workflow file to `main` (or merge a PR that includes it). +### 4b — Generate an API key -> **Never paste webhook URLs into public forks or issue comments.** They are -> equivalent to credentials. +1. Open the `gitea-ci` user → **Api Keys** → **New Api Key** +2. Copy both the **key** and the **secret** immediately — the secret is not shown again + +### 4c — Add secrets to Gitea + +In Gitea: **Repository** → **Settings** → **Secrets and Variables** → **Actions** → **New secret** + +Add all three: + +| Secret name | Value | +|---|---| +| `KOMODO_URL` | `https://komodo.castaldifamily.com` | +| `KOMODO_API_KEY` | API key from step 4b | +| `KOMODO_API_SECRET` | API secret from step 4b | + +> **Security:** Never commit these values to the repo. The workflow reads them +> from Gitea secrets at runtime. --- -## Step 6 — Verify End-to-End +## Step 5 — Verify End-to-End 1. Make a trivial change to any stack folder (e.g., add a blank line to `nodes/heimdall/sonarr/compose.yaml`) @@ -154,10 +160,10 @@ Commit the updated workflow file to `main` (or merge a PR that includes it). Queued for deploy: sonarr (node: heimdall) - === Triggering Komodo webhooks === + === Triggering Komodo deployments === → sonarr ... HTTP 200 OK - All webhooks triggered successfully. + All deployments triggered successfully. ``` 6. In Komodo UI, verify the `sonarr` stack shows a recent deployment event @@ -170,10 +176,10 @@ Commit the updated workflow file to `main` (or merge a PR that includes it). |---|---| | Runner shows **Offline** in Gitea | `docker compose logs runner` on Heimdall; check `GITEA_INSTANCE_URL` reachability | | Job never picks up | Runner label must match `runs-on` in the workflow (`ubuntu-latest`) | -| `HTTP 404` on webhook POST | URL in `WEBHOOK_MAP` is wrong; re-copy from Komodo UI | -| `HTTP 401` / `403` on webhook POST | URL token is stale; regenerate webhook in Komodo UI | +| `HTTP 401` / `403` on DeployStack call | Check `KOMODO_API_KEY` / `KOMODO_API_SECRET` secrets are set correctly in Gitea | +| `HTTP 404` on DeployStack call | Stack name in repo folder does not match the name registered in Komodo UI | +| `HTTP 404` logged as WARNING, not failure | Expected — stack exists in repo but isn't registered in Komodo yet | | Job shows `HEAD~1` diff error | Ensure `fetch-depth: 2` is set in the checkout step | -| Stack not in `WEBHOOK_MAP` | Logged as a warning in job output; add the stack name to the map | ---