tftsr-devops_investigation/docs/wiki/CICD-Pipeline.md
Shaun Arman 52f464d8bd docs: add wiki source files and CI auto-sync pipeline
- Add docs/wiki/ with 11 wiki pages (Home, Architecture, Database,
  AI-Providers, PII-Detection, IPC-Commands, CICD-Pipeline,
  Security-Model, Integrations, Development-Setup, Troubleshooting)
- Add wiki-sync step to .woodpecker/test.yml: syncs docs/wiki/*.md to
  the Gogs wiki git repo on every push to master
- Add Wiki Maintenance section to CLAUDE.md: code→wiki file mapping
  so Claude and contributors know which wiki page to update per change

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 13:45:30 -05:00

4.9 KiB

CI/CD Pipeline

Infrastructure

Component URL Notes
Gogs http://172.0.0.29:3000 / https://gogs.tftsr.com Git server, version 0.14
Woodpecker CI (direct) http://172.0.0.29:8084 v0.15.4
Woodpecker CI (proxy) http://172.0.0.29:8085 nginx with custom login page
PostgreSQL (Gogs DB) Container: gogs_postgres_db DB: gogsdb, User: gogs

Test Pipeline (.woodpecker/test.yml)

Triggers: Every push and pull request to any branch.

Pipeline steps:
  1. rust-fmt-check     → cargo fmt --check
  2. rust-clippy        → cargo clippy -- -D warnings
  3. rust-tests         → cargo test
  4. frontend-typecheck → npx tsc --noEmit
  5. frontend-tests     → npm run test:run (Vitest)

Docker images used:

  • rust:1.88-slim — Rust steps (minimum for cookie_store + time + darling)
  • node:22-alpine — Frontend steps

System dependencies installed in CI (Rust steps):

libwebkit2gtk-4.1-dev, libssl-dev, libgtk-3-dev, libsoup-3.0-dev,
librsvg2-dev, libglib2.0-dev

Pipeline YAML format (Woodpecker 0.15.4 — legacy MAP format):

clone:
  git:
    image: woodpeckerci/plugin-git
    network_mode: gogs_default     # requires repo_trusted=1
    environment:
      - CI_REPO_CLONE_URL=http://gogs_app:3000/sarman/tftsr-devops_investigation.git

pipeline:
  step-name:                        # KEY = step name (MAP, not list!)
    image: rust:1.88-slim
    commands:
      - cargo test

⚠️ Do NOT use the newer steps: list format — Woodpecker 0.15.4 uses the Drone-legacy map format.


Release Pipeline (.woodpecker/release.yml)

Triggers: Git tags matching v*

Pipeline steps:
  1. build-linux-amd64   → cargo tauri build (x86_64-unknown-linux-gnu)
  2. build-linux-arm64   → cargo tauri build (aarch64-unknown-linux-gnu, cross-compile)
  3. upload-release      → Create Gogs release + upload artifacts via API

Artifacts per platform:

  • Linux amd64: .deb, .rpm, .AppImage
  • Linux arm64: .deb, .AppImage

Gogs Release API:

# Create release
POST $API/repos/sarman/tftsr-devops_investigation/releases
Authorization: token $GOGS_TOKEN

# Upload artifact
POST $API/repos/sarman/tftsr-devops_investigation/releases/{id}/assets

The GOGS_TOKEN is stored as a Woodpecker secret.


Webhook Configuration

Hook ID: 6 (in Gogs) Events: create, push, pull_request URL: http://172.0.0.29:8084/hook?access_token=<JWT>

JWT signing:

  • Algorithm: HS256
  • Secret: repo_hash value from Woodpecker DB (dK8zFWtAu67qfKd3Et6N8LptqTmedumJ)
  • Payload: {"text":"sarman/tftsr-devops_investigation","type":"hook"}

⚠️ JWT has an iat claim. If it's stale, regenerate it.


Woodpecker DB State

SQLite at /docker_mounts/woodpecker/data/woodpecker.sqlite (on host 172.0.0.29).

Key values:

-- User
SELECT user_token FROM users WHERE user_login='sarman';
-- Should be: [REDACTED-ROTATED]

-- Repo
SELECT repo_active, repo_trusted, repo_config_path, repo_hash
FROM repos WHERE repo_full_name='sarman/tftsr-devops_investigation';
-- repo_active=1, repo_trusted=1
-- repo_config_path='.woodpecker/test.yml'
-- repo_hash='dK8zFWtAu67qfKd3Et6N8LptqTmedumJ'

Known Issues & Fixes

Webhook JWT Must Use ?access_token=

token.ParseRequest() in Woodpecker 0.15.4 does not read ?token= URL params. Use ?access_token=<JWT> instead.

JWT Signed with repo_hash (Not User Hash)

Hook JWT must be signed with the repo_hash value, not the user's hash.

Directory-Based Config Not Supported

Woodpecker 0.15.4 only supports a single config file. Set repo_config_path = .woodpecker/test.yml in the Woodpecker DB. The .woodpecker/ directory approach requires v2.x+.

Step Containers Network Isolation

Pipeline step containers run on the default Docker bridge and cannot resolve gogs_app hostname. Fix: set network_mode: gogs_default in the clone section (requires repo_trusted=1).

Empty Clone URL Bug

Woodpecker 0.15.4's go-gogs-client PayloadRepo struct lacks CloneURL/SSHURL fields, so build_remote is always empty from Gogs push payloads. Fix: override the clone URL via CI_REPO_CLONE_URL environment variable.

Gogs Token Authentication

The sha1 field in Gogs token create API response is the actual bearer token (not a hash). Use it directly:

Authorization: token <sha1_from_create_response>

Gogs SPA Login Field Mismatch

Gogs 0.14 SPA login form uses login= field; the Gogs backend reads username=. A custom login page is served by nginx at /login.

Gogs OAuth2 Limitation

Gogs 0.14 has no OAuth2 provider support, blocking upgrade to Woodpecker 2.x.


Gogs PostgreSQL Access

docker exec gogs_postgres_db psql -U gogs -d gogsdb -c "SELECT id, lower_name FROM repository;"

Database name is gogsdb, not gogs.