Commit graph

59 commits

Author SHA1 Message Date
johba
8c368c632e feat: set 5-minute pipeline timeout after WP repo activation
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/smoke-init Pipeline failed
Prevents smoke-init and other heavy CI steps from hanging for 40+ min.
Applied automatically during disinto init.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:41:17 +00:00
johba
481f9fc53a fix: set Docker network for WP CI step containers
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/smoke-init Pipeline failed
CI step containers spawned by the WP agent (running on host network)
cannot resolve Docker service names like forgejo. Setting
WOODPECKER_BACKEND_DOCKER_NETWORK puts CI containers on the compose
network so they can reach Forgejo for git clone.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:14:01 +00:00
johba
83bd909378 fix: allow webhooks to private hosts in Forgejo compose template
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/smoke-init Pipeline failed
Forgejo blocks outgoing webhooks to non-allowlisted hosts by default.
Woodpecker CI requires webhook delivery for pipeline triggering.
Setting ALLOWED_HOST_LIST=private allows webhooks to any RFC1918 address.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 10:09:59 +00:00
johba
38a7253c11 fix: WP CI agent gRPC: use host networking to bypass Docker bridge (#813)
Docker bridge networking inside LXD (and potentially other nested container
environments) breaks gRPC/HTTP2 between containers. The gRPC handshake
times out because HTTP/2 frames are not properly forwarded.

Fix: run the WP agent with network_mode: host + privileged, connecting
to the server via localhost:9000 (port mapped from the server container).

- Add port 9000 mapping to woodpecker server
- Switch agent to network_mode: host with privileged: true
- Connect agent to localhost:9000 instead of woodpecker:9000
- Add WOODPECKER_GRPC_SECURE=false
- Move healthcheck to port 3333 (avoid clash with Forgejo on 3000)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 09:40:44 +00:00
johba
883cdc812c fix: compose template: SSH mount, PROJECT_REPO_ROOT, revert WOODPECKER_HOST
- Add ~/.ssh mount to agents container (needed for mirror pushes)
- Add PROJECT_REPO_ROOT env to agents and vault-runner containers
- Revert WOODPECKER_HOST to http://woodpecker:8000 (localhost breaks gRPC)
- Remove WOODPECKER_GRPC_ADDR (did not fix gRPC issue)
- Keep WOODPECKER_OPEN for OAuth2 first-user registration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 09:24:19 +00:00
johba
12d4e6925b fix: disinto init OAuth2 + WP v3 compatibility (#812, #814)
- Rewrite URL-encoded Docker-internal hostnames in OAuth2 redirect
- Submit all Forgejo grant form fields (client_id, state, redirect_uri, granted)
- Add WOODPECKER_OPEN to compose template for first user OAuth registration
- Add WOODPECKER_GRPC_ADDR to compose template
- Fix WP repo activation: use query param with numeric Forgejo repo ID
- WP v3 PAT creation via session cookie + CSRF header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 08:37:14 +00:00
johba
1912a24c46 feat: edge proxy + staging container to docker stack (#807)
This PR implements issue #764 by adding two Caddy-based containers to the disinto docker stack:

## Changes

### Edge Proxy Service
- Caddy reverse proxy serving on ports 80/443
- Routes /forgejo/* -> Forgejo:3000
- Routes /ci/* -> Woodpecker:8000
- Default route -> staging container

### Staging Service
- Caddy static file server for staging artifacts
- Serves a default "Nothing shipped yet" page
- CI pipelines can write to the staging-site volume to update content

### Files Modified
- bin/disinto: Updated generate_compose() to add edge + staging services
- bin/disinto: Added generate_caddyfile() function
- bin/disinto: Added generate_staging_index() function
- docker/staging-index.html: New default staging page

## Acceptance Criteria
- [x] disinto init generates docker-compose.yml with edge + staging services
- [x] Edge proxy routes /forgejo/*, /ci/*, and default routes correctly
- [x] Staging container serves default "Nothing shipped yet" page
- [x] docker/ directory contains Caddyfile template generated by disinto init
- [x] disinto up starts all containers including edge and staging

Co-authored-by: johba <johba@users.noreply.codeberg.org>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/807
2026-03-28 07:58:17 +01:00
johba
ef544f58f9 fix: disinto init: auto-generate WOODPECKER_TOKEN for repo activation (#779) (#790)
Fixes #779

## Changes
Auto-generate WOODPECKER_TOKEN during disinto init by automating the Forgejo OAuth2 login flow after the compose stack starts. Adds generate_woodpecker_token() function that: logs into Forgejo web UI, drives the OAuth2 authorize/consent flow, completes the Woodpecker callback to get a session token, then creates a persistent personal access token via Woodpecker API. Saves to .env so activate_woodpecker_repo() can use it immediately. Failures are non-fatal (guarded with || true).

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/790
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-27 14:01:28 +01:00
johba
4251f9fb0e fix: disinto init: fails late if git user.name/user.email not configured (#778) (#780)
Fixes #778

## Changes
Add git identity warning to preflight_check() (warns if user.name/user.email missing) and auto-configure repo-local identity in setup_ops_repo() before the seed commit. This prevents init from failing late when git identity is not configured globally.

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/780
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-27 06:59:06 +01:00
openhands
c3719618a4 fix: preserve skip-verification on API-unreachable path (#773)
Set is_empty="skipped" before breaking out of the retry loop when
the API is unreachable, so the post-loop guard does not misfire
with a false "still reports empty" failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:21:16 +00:00
openhands
220b5c4004 fix: disinto init: race condition in post-push empty check (#773)
Replace the single-shot Forgejo API emptiness check in push_to_forge()
with a retry loop (up to 5 attempts, 2s apart). Forgejo needs a brief
delay to index pushed refs, so the immediate check could see stale
metadata reporting empty=true even though the push succeeded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 20:09:24 +00:00
openhands
f087771bb1 fix: disinto init: setup_forge fails because .env does not exist yet (#769)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 19:10:05 +00:00
johba
71fe89cdd0 fix: {project}-ops repo — separate operations from code (#757) (#767)
Fixes #757

## Changes
Separate operations from code into {project}-ops repo pattern. Added OPS_REPO_ROOT infrastructure (env.sh, load-project.sh, formula-session.sh with ensure_ops_repo helper). Updated all 8 agent scripts and 7 formulas to read/write vault items, journals, evidence, prerequisites, RESOURCES.md, and knowledge from the ops repo. Added setup_ops_repo() to disinto init for automatic ops repo creation and seeding. Removed migrated data from code repo (vault data dirs, planner journal/memory/prerequisites, supervisor journal/best-practices, evidence, RESOURCES.md). Updated all documentation. 55 files changed, ShellCheck clean, all 38 phase tests pass.

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/767
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
2026-03-26 19:55:12 +01:00
openhands
3372da594b fix: Vault-gated deployment promotion via Woodpecker environments (#755)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:16:39 +00:00
openhands
569313ac93 fix: External actions (publish, deploy, post) must go through vault — agents cannot hold tokens directly (#745)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:59:57 +00:00
openhands
cb5252588c fix: Secure action runtime — ephemeral container with vault-injected secrets (#748)
Split secrets into two SOPS-encrypted files:
- .env.enc for agent secrets (FORGE_TOKEN, CLAUDE_API_KEY, etc.)
- .env.vault.enc for vault secrets (GITHUB_TOKEN, deploy keys, etc.)

Add ephemeral vault-runner container (profiles: ["vault"]) that receives
only vault secrets at runtime. Agents never see vault secrets; vault-runner
never sees agent secrets.

Key changes:
- bin/disinto: vault-run subcommand, dual-file secrets management,
  vault-runner service in compose template
- vault/vault-fire.sh: delegates action execution to vault-runner
  container via disinto vault-run (bare-metal fallback preserved)
- vault/vault-poll.sh: new phase 5 detects vault-bot authorized
  comments on issues with action label
- vault/vault-run-action.sh: entrypoint for ephemeral container,
  dispatches to action handlers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:41:27 +00:00
openhands
89628e50e2 fix: Per-agent Forgejo accounts — identity and permissions via authorship (#747)
Each agent now gets its own Forgejo account (dev-bot, review-bot,
planner-bot, gardener-bot, vault-bot, supervisor-bot, predictor-bot,
action-bot) with a dedicated API token. This enables:

- Audit trail: every forge action attributable to a specific agent
- Permission boundaries: agents act under their own identity
- Vault authorization model: vault-bot comments = proof of approval

Changes:
- bin/disinto: setup_forge() creates all 8 bot accounts during init,
  stores per-agent tokens (FORGE_*_TOKEN) in .env, adds all bots as
  repo collaborators
- lib/env.sh: exports per-agent token vars with fallback to FORGE_TOKEN
  for backwards compat; sets FORGE_BOT_USERNAMES default to all 8 bots
- Agent scripts: each agent overrides FORGE_TOKEN with its per-agent
  token after sourcing env.sh (gardener, planner, supervisor, predictor,
  vault, action)
- .env.example: documents all per-agent token fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:16:13 +00:00
openhands
daa8350085 fix: Address review — remove stale Matrix references from runtime prompts
Critical fixes:
- vault/vault-agent.sh: Update comment and prompt to use PHASE:escalate
  instead of "send a Matrix message"
- dev/dev-agent.sh: Update escalation instruction from "reply via Matrix"
  to "respond via the forge"
- dev/phase-handler.sh: Update build_phase_protocol_prompt() escalation
  text from "reply via Matrix" to "respond via the forge"

Minor fixes:
- bin/disinto: Remove duplicate comment line in docker-compose header
- README.md: Update vault table row from "via Matrix" to "via vault/forge"
- BOOTSTRAP.md: Remove "Matrix credentials" from TOML description
- lib/AGENTS.md: Remove "callers may follow up via Matrix" from
  formula_phase_callback description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:11:44 +00:00
openhands
23949083c0 fix: Remove Matrix integration — notifications move to forge + OpenClaw (#732)
Remove all Matrix/Dendrite infrastructure:
- Delete lib/matrix_listener.sh (long-poll daemon), lib/matrix_listener.service
  (systemd unit), lib/hooks/on-stop-matrix.sh (response streaming hook)
- Remove matrix_send() and matrix_send_ctx() from lib/env.sh
- Remove MATRIX_HOMESERVER auto-detection, MATRIX_THREAD_MAP from lib/env.sh
- Remove [matrix] section parsing from lib/load-project.sh
- Remove Matrix hook installation from lib/agent-session.sh
- Remove notify/notify_ctx helpers and Matrix thread tracking from
  dev/dev-agent.sh and action/action-agent.sh
- Remove all matrix_send calls from dev-poll.sh, phase-handler.sh,
  action-poll.sh, vault-poll.sh, vault-fire.sh, vault-reject.sh,
  review-poll.sh, review-pr.sh, supervisor-poll.sh, formula-session.sh
- Remove Matrix listener startup from docker/agents/entrypoint.sh
- Remove append_dendrite_compose() and setup_matrix() from bin/disinto
- Remove --matrix flag from disinto init
- Clean Matrix references from .env.example, projects/*.toml.example,
  formulas/*.toml, AGENTS.md, BOOTSTRAP.md, README.md, RESOURCES.md,
  PHASE-PROTOCOL.md, and all agent AGENTS.md/PROMPT.md files

Status visibility now via Codeberg PR/issue activity. Human interaction
via vault items through forge. Proactive alerts via OpenClaw heartbeats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:53:56 +00:00
openhands
b8c9334880 fix: Set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC in factory sessions and disinto init (#725)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:21:22 +00:00
johba
cc4c6d7efa Remove exec agent — replaced by OpenClaw skill + vault API (#722)
## What

Removes the exec agent (PR #697). Its functionality is replaced by:

1. **OpenClaw skill** — teaches any OpenClaw instance to be the factory's face
2. **Vault API** — structured interface for proposals, approvals, rejections

The exec agent was rebuilding OpenClaw in bash. Every piece has a native OpenClaw equivalent:
- CHARACTER.md → SOUL.md
- exec/MEMORY.md → MEMORY.md
- exec-session.sh → session management
- exec-briefing.sh → heartbeats/cron
- Matrix dispatch → channel plugins

## Why

Prudence isn't a separate agent. She's what OpenClaw becomes when it has the disinto skill. One LLM, one vault API, no LLM-to-LLM.

## Related

- #721 — remove escalation, route through vault
- #709 — skill registry research
- #466 — example project (vault should have handled this, not escalation)

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/disinto/pulls/722
2026-03-26 10:36:27 +01:00
openhands
cf6400e8f3 fix: shared Claude OAuth credentials in containers — mount + flock to prevent token rotation race (#693)
- Make ~/.claude volume mount read-write (was :ro) so containers can
  write back refreshed OAuth tokens
- Wrap Claude CLI in flock(1) inside tmux sessions using
  ~/.claude/session.lock — prevents concurrent token refresh races
  across agents sharing the same credentials
- Add ANTHROPIC_API_KEY detection in entrypoint.sh: when set, skips
  OAuth entirely (no rotation issues, metered billing)
- Log active auth method (API key vs OAuth vs missing) at container
  startup for easier 401 debugging
- Document 'claude auth login' requirement in disinto init output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 17:48:21 +00:00
disinto-exec
18cea8cad5 merge: integrate origin/main to resolve CI (matrix_send_ctx)
Merge main into feat/exec-agent to pick up ba1ab6e which added
matrix_send_ctx to lib/env.sh and action/action-agent.sh. Without
this merge, CI smoke test fails on the PR merge commit.

Re-applied exec changes on top of main:
- .env.example, AGENTS.md, bin/disinto, lib/matrix_listener.sh
- .woodpecker/agent-smoke.sh: exec scripts added to checks
2026-03-25 16:37:49 +00:00
disinto-exec
b125277db2 feat: auto-provision compass via disinto init from disinto.ai
disinto init now silently downloads the compass from
https://disinto.ai/compass.md to ~/.disinto/compass.md, sets
EXEC_COMPASS in .env, and activates the exec agent. No prompts,
no friction — the compass is public philosophy, not a secret.

Once on disk, the factory cannot modify it. Only the executive
can edit ~/.disinto/compass.md directly.

- site/compass.md: compass hosted on disinto.ai (Codeberg Pages)
- bin/disinto: init downloads compass, sets env var, activates exec
- exec-session.sh, exec-briefing.sh: fallback to ~/.disinto/compass.md
- .env.example: updated comment to reflect auto-provisioning
2026-03-25 15:45:15 +00:00
openhands
54ce91e09e fix: fix: create_labels creates duplicate labels on re-run — no idempotency check (#683)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:35:31 +00:00
openhands
26df57da18 fix: skip push when local repo has no commits (empty clone)
The smoke test clones from an empty Forgejo repo, so there are no
refs to push. Skip the push and verification gracefully when HEAD
does not resolve.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:23:02 +00:00
openhands
f8c8769af3 fix: fix: disinto init does not push repo to local Forgejo — repo stays empty (#682)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:20:53 +00:00
openhands
07616df8a5 fix: fix: Dendrite crash-loops — missing dendrite.yaml config file (#681)
Remove Dendrite from the default docker-compose.yml generated by
`disinto init`. Most deployments don't need Matrix, so Dendrite is now
opt-in via the `--matrix` flag.

When `--matrix` is passed:
- A minimal dendrite.yaml is generated at docker/dendrite/dendrite.yaml
- The Dendrite service is appended to docker-compose.yml with the
  config file bind-mounted
- setup_matrix() provisions the bot user and coordination room

Without `--matrix`, no Dendrite container is started and fresh inits
no longer crash-loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:08:55 +00:00
openhands
0908ddb521 fix: fix: Woodpecker image uses :latest tag which no longer exists — container crash-loops (#680)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:55:00 +00:00
openhands
a414bc8b24 fix: disinto init should activate dev, reviewer, and gardener agents by default (#671)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:20:09 +00:00
openhands
8b8e29e071 fix: feat: add Woodpecker agent to docker-compose stack — enable CI pipeline execution (#670)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:07:27 +00:00
openhands
e411eb224c fix: Forgejo 11.x ignores --must-change-password=false — token creation fails with password change required (#665)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:50:08 +00:00
openhands
c643cf16dc fix: use basic auth for bot token creation — Forgejo rejects token auth (#668)
POST /api/v1/users/{username}/tokens requires basic auth (reqBasicOrRevProxyAuth)
in Forgejo 11.x. The previous code used admin token auth which returns 401.

Fix: authenticate as the bot user with -u "${bot_user}:${bot_pass}" instead of
-H "Authorization: token ${admin_token}". The bot_pass is available in scope
from the user creation step.

Bug caught by the new smoke-init end-to-end test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:06:01 +00:00
openhands
c02a0b29d2 fix: fix: Woodpecker CI not wired during disinto init — OAuth2 app never created, no CI runs (#661)
Split setup_woodpecker() into create_woodpecker_oauth() (pre-compose) and
activate_woodpecker_repo() (post-compose) so OAuth2 creds are in .env before
Woodpecker starts, and repo activation happens after the stack is up.

- Add ports: ["8000:8000"] to Woodpecker service in generate_compose()
- Fix .env var names: WP_FORGEJO_CLIENT/SECRET to match compose references
- Reorder disinto_init(): OAuth2 creation before compose up, repo activation after
- activate_woodpecker_repo() polls Woodpecker readiness with retry loop

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 07:43:59 +00:00
openhands
b361eba2bb fix: setup_forge silently fails to create users and tokens — .env has no FORGE_TOKEN after init (#658)
Add database readiness check (retry loop on `forgejo admin user list`) after
API becomes reachable to avoid the race where HTTP is up but SQLite isn't
accepting writes yet.

Remove `2>/dev/null || true` from user creation commands so failures are
logged with the actual error message. Verify each user exists via API after
creation. Fail init with a clear error if admin token, bot user creation,
or bot token creation fails — instead of silently writing an incomplete .env.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 06:51:47 +00:00
johba
632508e18e fix: bind-mount host Claude credentials instead of empty Docker volume
Replace the claude-auth named Docker volume with bind mounts to the host
user's ~/.claude/ and ~/.claude.json. The named volume creates an empty
directory, so the agents container cannot authenticate with Claude CLI.

Bind-mounting from ${HOME} ensures the container picks up existing
credentials without manual intervention.

Closes codeberg.org/johba/disinto/issues/633

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 05:42:50 +00:00
openhands
a0cdf87a21 fix: move setup_matrix after compose up, use Python for .env writes
- Critical: setup_matrix now runs after docker compose up -d so Dendrite
  is actually running when provisioning is attempted
- Minor: replace sed with Python for .env credential writes to avoid
  delimiter collisions with opaque Matrix access tokens
- Info: update matrix_listener.sh header to mention container mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:35:20 +00:00
openhands
b86edd7e5d fix: Add Dendrite to docker-compose stack (#619)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:28:04 +00:00
openhands
bc2df1a2c7 fix: disinto init fails on minimal Debian — crontab command not found (#638)
In compose mode, skip host cron installation entirely since the agents
container runs cron internally via entrypoint.sh. In bare mode, check
for crontab before attempting to install entries and produce a clear
error with install instructions if missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:40:35 +00:00
openhands
7844b29a37 fix: agents Dockerfile fails to build — cli.anthropic.com DNS does not resolve (#637)
- Remove curl|sh Claude CLI download from Dockerfile (no internet needed)
- Mount host Claude CLI binary into container via docker-compose volume
- generate_compose() resolves host claude path at init time
- entrypoint.sh fails fast with clear error if claude CLI is missing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:26:26 +00:00
openhands
f30c56769a fix: setup_forge runs forgejo admin commands as root — Forgejo refuses to execute (#636)
Add -u git to docker exec and docker compose exec calls in _forgejo_exec()
so Forgejo admin commands run as the git user instead of root.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:15:00 +00:00
openhands
0b54f5e9e9 fix: Docker-in-LXD — su-exec spins at 100% CPU due to AppArmor blocking setuid (#635)
Add security_opt: [apparmor=unconfined] to all three compose services
(forgejo, woodpecker, agents) in generate_compose(). This prevents
su-exec from entering an infinite CPU loop when Docker runs inside an
LXD container whose default AppArmor profile blocks setuid/execve.
Harmless on bare-metal Docker hosts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 22:05:14 +00:00
openhands
5a9ceee1ad fix: Forgejo compose template missing INSTALL_LOCK — API returns 404 until manual install (#634)
Add FORGEJO__security__INSTALL_LOCK: "true" to the forgejo service
environment in generate_compose(). Without this, Forgejo starts in
install-wizard mode and the API returns 404 for all endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:55:02 +00:00
openhands
d3896043d6 fix: docker-compose uses forgejo/forgejo:latest which does not exist on any registry (#633)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:45:17 +00:00
openhands
4f99a7a26a fix: Clean up decrypted secrets on failure, verify Claude CLI install (#618)
Add EXIT trap in disinto_up() so the plaintext .env is removed even if
docker compose up fails.  Previously set -euo pipefail would abort
before the cleanup block, leaving secrets on disk.

Replace the silent || true in the Dockerfile with an explicit
claude --version check so the build fails visibly if the CLI cannot
be installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:36:55 +00:00
openhands
0aa3890fb8 fix: Start cron daemon in agent container entrypoint (#618)
The entrypoint installed a crontab but never started a cron daemon,
leaving the container idle.  Fix by running as root in the entrypoint
(cron requires it), installing the crontab for the agent user via
`crontab -u agent`, and starting cron in the foreground with `cron -f`.
Remove `USER agent` from the Dockerfile and `user: "1000:1000"` from
the compose template accordingly — cron jobs still execute as UID 1000.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:30:44 +00:00
openhands
e38866ab61 fix: Containerize full stack with docker-compose (#618)
Add docker-compose.yml generation, agent Dockerfile, and new CLI
commands (up/down/logs/shell) so the full stack runs containerized.
The --bare flag preserves the current bare-metal setup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:53:55 +00:00
openhands
7bc74caa63 fix: Push to public mirrors after merge (#614)
Add fire-and-forget mirror push support so merges to the primary branch
are automatically pushed to configured public mirrors (GitHub, Codeberg,
etc.). Mirror failures are logged but never block the pipeline.

- lib/mirrors.sh: new shared mirror_push() helper
- lib/load-project.sh: parse [mirrors] TOML section into MIRROR_* env vars
- dev/phase-handler.sh: call mirror_push after do_merge() success
- dev/dev-poll.sh: call mirror_push after try_direct_merge() success
- gardener/gardener-run.sh: call mirror_push after _gardener_merge() success
- bin/disinto: set up mirror remotes during init, add commented mirrors to
  generated TOML
- projects/*.toml.example: show [mirrors] section (commented out)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:19:16 +00:00
openhands
3e2f8f9623 fix: Address review feedback on SOPS integration (#613)
- Warn on stderr when .env.enc decryption fails instead of silent || true
- Guard ensure_age_key() against empty age-keygen -y output
- Fix stale comment on write_secrets_encrypted()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:04:58 +00:00
openhands
5ccf09b28d fix: Encrypt secrets at rest with SOPS + age (#613)
- lib/env.sh: Two-tier secret loader (SOPS .env.enc > plaintext .env),
  remove ~/.netrc fallback
- bin/disinto: Add age key generation and SOPS encryption during init,
  remove write_netrc(), add `disinto secrets` subcommand (edit/show/migrate),
  add sops+age to preflight warnings
- .env.example: Annotate vars as [SECRET] or [CONFIG]
- .gitignore: Allow .env.enc and .sops.yaml to be committed
- BOOTSTRAP.md: Document SOPS + age setup, key backup, secret management
- AGENTS.md: Update AD-005 and coding conventions for .env.enc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:58:33 +00:00