Locks in static validation for every Nomad+Vault artifact before it can
merge. Four fail-closed steps in .woodpecker/nomad-validate.yml, gated
to PRs touching nomad/, lib/init/nomad/, or bin/disinto:
1. nomad config validate nomad/server.hcl nomad/client.hcl
2. vault operator diagnose -config=nomad/vault.hcl -skip=storage -skip=listener
3. shellcheck --severity=warning lib/init/nomad/*.sh bin/disinto
4. bats tests/disinto-init-nomad.bats — dispatcher smoke tests
bin/disinto picks up pre-existing SC2120 warnings on three passthrough
wrappers (generate_agent_docker, generate_caddyfile, generate_staging_index);
annotated with shellcheck disable=SC2120 so the new pipeline is clean
without narrowing the warning for future code.
Pinned image versions (hashicorp/nomad:1.9.5, hashicorp/vault:1.18.5)
match lib/init/nomad/install.sh — bump both or neither.
nomad/AGENTS.md documents the stack layout, how to add a jobspec in
Step 1, how CI validates it, and the two-place version pinning rule.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make `disinto init` safe to re-run on the same box:
- Store admin token as FORGE_ADMIN_TOKEN in .env; preserve on re-run
(previously deleted and recreated every run, churning DB state)
- Fix human token creation: use admin_pass for basic-auth since
human_user == admin_user (previously used a random password that
never matched the actual user password, so HUMAN_TOKEN was never
created successfully)
- Preserve HUMAN_TOKEN in .env on re-run (same pattern as bot tokens)
- Bot tokens were already idempotent (preserved unless --rotate-tokens)
Add --dry-run flag that reports every intended action (file writes,
API calls, docker commands) based on current state, then exits 0
without touching state. Useful for CI gating and cutover confidence.
Update smoke test:
- Add dry-run test (verifies exit 0 and no .env modification)
- Add idempotency state diff (verifies .env is unchanged on re-run)
- Verify FORGE_ADMIN_TOKEN and HUMAN_TOKEN are stored in .env
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix off-by-one in mock admin/users/{username}/repos path extraction
(parts[4] was 'users', not the username — should be parts[5])
- Change _install_cron_impl to return 1 instead of exit 1 when crontab
is missing, so cron failure doesn't abort entire init
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add cleanup trap to smoke-init.sh that kills all mock-forgejo.py processes
on exit (success or failure). Also ensure cleanup at test start removes
any leftover processes from prior runs.
In .woodpecker/smoke-init.yml:
- Store the PID of the mock-forgejo.py background process
- Kill the process after smoke test completes
This prevents accumulation of orphaned Python processes that caused
OOM issues (2881 processes consuming 7.45GB RAM).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix collaborator PUT: use parts[7] instead of parts[6]
- Fix user/repos: store username in token object and use it for lookup
- Fix /mock/shutdown: strip leading slash unconditionally
- Fix SIGTERM: call server.shutdown() in a thread
- Use socket module constants for setsockopt
- Remove duplicate pattern
The mock docker in smoke-init.sh only handled 'admin user create' and
'admin user list'. Add a 'change-password' handler that PATCHes the
user via the Forgejo admin API to clear must_change_password.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The mock crontab file was not being created despite PATH precedence
working correctly. Replace the mock with the real BusyBox crontab
already available in the Forgejo Alpine image. Verify cron entries
via 'crontab -l' output instead of checking a mock state file.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Forgejo's admin API POST /admin/users may not honor
must_change_password:false in the request body. Previously only admin
users got a PATCH (to set admin:true), which incidentally cleared
must_change_password. Bot users had no PATCH, so basic auth for token
creation returned 401.
Now every mock-created user gets a PATCH to explicitly set
must_change_password:false, fixing bot token creation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The install endpoint POST returned 404 because FORGEJO__database__DB_TYPE
env var auto-configured Forgejo, bypassing install mode.
Fix: run the Forgejo image as the step container instead of a service.
This gives CLI access to `forgejo admin user create` for bootstrap
admin setup — no install endpoint needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add tests/smoke-init.sh — an end-to-end smoke test that runs
disinto init --bare --yes against a real Forgejo instance
(started as a Woodpecker service container).
The test validates:
- Forgejo API responds after init
- Admin and bot users created with tokens
- Repo created with labels on Forgejo
- Project TOML generated correctly
- .env written with FORGE_TOKEN and FORGE_REVIEW_TOKEN
- Cron entries installed (dev-poll, review-poll, gardener)
Uses mock binaries for docker (routes user creation to Forgejo
admin API), claude, tmux, and crontab to run in CI without
Docker-in-Docker.
Wired into CI via .woodpecker/smoke-init.yml (separate pipeline
with Forgejo service, runs on push and pull_request).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>