fix: refactor: rename vault-runner → runner and vault-run → run (#43) #58

Merged
dev-qwen merged 1 commit from fix/issue-43 into main 2026-03-29 12:49:08 +00:00
10 changed files with 47 additions and 44 deletions

View file

@ -49,7 +49,7 @@ WOODPECKER_DB_NAME=woodpecker # [CONFIG] Postgres database name
# ── Vault-only secrets (DO NOT put these in .env) ──────────────────────── # ── Vault-only secrets (DO NOT put these in .env) ────────────────────────
# These tokens grant access to external systems (GitHub, ClawHub, deploy targets). # These tokens grant access to external systems (GitHub, ClawHub, deploy targets).
# They live ONLY in .env.vault.enc and are injected into the ephemeral vault-runner # They live ONLY in .env.vault.enc and are injected into the ephemeral runner
# container at fire time (#745). lib/env.sh explicitly unsets them so agents # container at fire time (#745). lib/env.sh explicitly unsets them so agents
# can never hold them directly — all external actions go through vault dispatch. # can never hold them directly — all external actions go through vault dispatch.
# #
@ -58,7 +58,7 @@ WOODPECKER_DB_NAME=woodpecker # [CONFIG] Postgres database name
# (deploy keys) — SSH keys for deployment targets # (deploy keys) — SSH keys for deployment targets
# #
# To manage vault secrets: disinto secrets edit-vault # To manage vault secrets: disinto secrets edit-vault
# See also: vault/vault-run-action.sh, vault/vault-fire.sh # See also: vault/run-action.sh, vault/vault-fire.sh
# ── Project-specific secrets ────────────────────────────────────────────── # ── Project-specific secrets ──────────────────────────────────────────────
# Store all project secrets here so formulas reference env vars, never hardcode. # Store all project secrets here so formulas reference env vars, never hardcode.

View file

@ -164,8 +164,8 @@ Humans write these. Agents read and enforce them.
| AD-002 | Single-threaded pipeline per project. | One dev issue at a time. No new work while a PR awaits CI or review. Prevents merge conflicts and keeps context clear. | | AD-002 | Single-threaded pipeline per project. | One dev issue at a time. No new work while a PR awaits CI or review. Prevents merge conflicts and keeps context clear. |
| AD-003 | The runtime creates and destroys, the formula preserves. | Runtime manages worktrees/sessions/temp. Formulas commit knowledge to git before signaling done. | | AD-003 | The runtime creates and destroys, the formula preserves. | Runtime manages worktrees/sessions/temp. Formulas commit knowledge to git before signaling done. |
| AD-004 | Event-driven > polling > fixed delays. | Never `waitForTimeout` or hardcoded sleep. Use phase files, webhooks, or poll loops with backoff. | | AD-004 | Event-driven > polling > fixed delays. | Never `waitForTimeout` or hardcoded sleep. Use phase files, webhooks, or poll loops with backoff. |
| AD-005 | Secrets via env var indirection, never in issue bodies. | Issue bodies become code. Agent secrets go in `.env.enc`, vault secrets in `.env.vault.enc` (both SOPS-encrypted). Referenced as `$VAR_NAME`. Vault-runner gets only vault secrets; agents get only agent secrets. | | AD-005 | Secrets via env var indirection, never in issue bodies. | Issue bodies become code. Agent secrets go in `.env.enc`, vault secrets in `.env.vault.enc` (both SOPS-encrypted). Referenced as `$VAR_NAME`. Runner gets only vault secrets; agents get only agent secrets. |
| AD-006 | External actions go through vault dispatch, never direct. | Agents build addressables; only the vault exercises them (publishes, deploys, posts). Tokens for external systems (`GITHUB_TOKEN`, `CLAWHUB_TOKEN`, deploy keys) live only in `.env.vault.enc` and are injected into the ephemeral vault-runner container. `lib/env.sh` unsets them so agents never hold them. PRs with direct external actions without vault dispatch get REQUEST_CHANGES. | | AD-006 | External actions go through vault dispatch, never direct. | Agents build addressables; only the vault exercises them (publishes, deploys, posts). Tokens for external systems (`GITHUB_TOKEN`, `CLAWHUB_TOKEN`, deploy keys) live only in `.env.vault.enc` and are injected into the ephemeral runner container. `lib/env.sh` unsets them so agents never hold them. PRs with direct external actions without vault dispatch get REQUEST_CHANGES. |
**Who enforces what:** **Who enforces what:**
- **Gardener** checks open backlog issues against ADs during grooming; closes violations with a comment referencing the AD number. - **Gardener** checks open backlog issues against ADs during grooming; closes violations with a comment referencing the AD number.

View file

@ -10,7 +10,7 @@
# disinto shell Shell into the agent container # disinto shell Shell into the agent container
# disinto status Show factory status # disinto status Show factory status
# disinto secrets <subcommand> Manage encrypted secrets # disinto secrets <subcommand> Manage encrypted secrets
# disinto vault-run <action-id> Run action in ephemeral vault container # disinto run <action-id> Run action in ephemeral runner container
# #
# Usage: # Usage:
# disinto init https://github.com/user/repo # disinto init https://github.com/user/repo
@ -39,7 +39,7 @@ Usage:
disinto shell Shell into the agent container disinto shell Shell into the agent container
disinto status Show factory status disinto status Show factory status
disinto secrets <subcommand> Manage encrypted secrets disinto secrets <subcommand> Manage encrypted secrets
disinto vault-run <action-id> Run action in ephemeral vault container disinto run <action-id> Run action in ephemeral runner container
Init options: Init options:
--branch <name> Primary branch (default: auto-detect) --branch <name> Primary branch (default: auto-detect)
@ -242,7 +242,7 @@ services:
- .env - .env
# IMPORTANT: agents get .env only (forge tokens, CI tokens, config). # IMPORTANT: agents get .env only (forge tokens, CI tokens, config).
# Vault-only secrets (GITHUB_TOKEN, CLAWHUB_TOKEN, deploy keys) live in # Vault-only secrets (GITHUB_TOKEN, CLAWHUB_TOKEN, deploy keys) live in
# .env.vault.enc and are NEVER injected here — only the vault-runner # .env.vault.enc and are NEVER injected here — only the runner
# container receives them at fire time (AD-006, #745). # container receives them at fire time (AD-006, #745).
depends_on: depends_on:
- forgejo - forgejo
@ -250,7 +250,7 @@ services:
networks: networks:
- disinto-net - disinto-net
vault-runner: runner:
build: ./docker/agents build: ./docker/agents
profiles: ["vault"] profiles: ["vault"]
security_opt: security_opt:
@ -263,8 +263,8 @@ services:
FORGE_URL: http://forgejo:3000 FORGE_URL: http://forgejo:3000
DISINTO_CONTAINER: "1" DISINTO_CONTAINER: "1"
PROJECT_REPO_ROOT: /home/agent/repos/\${PROJECT_NAME:-project} PROJECT_REPO_ROOT: /home/agent/repos/\${PROJECT_NAME:-project}
# env_file set at runtime by: disinto vault-run --env-file <tmpfile> # env_file set at runtime by: disinto run --env-file <tmpfile>
entrypoint: ["bash", "/home/agent/disinto/vault/vault-run-action.sh"] entrypoint: ["bash", "/home/agent/disinto/vault/run-action.sh"]
networks: networks:
- disinto-net - disinto-net
@ -466,8 +466,8 @@ generate_deploy_pipelines() {
if [ ! -f "${wp_dir}/staging.yml" ]; then if [ ! -f "${wp_dir}/staging.yml" ]; then
cat > "${wp_dir}/staging.yml" <<'STAGINGEOF' cat > "${wp_dir}/staging.yml" <<'STAGINGEOF'
# .woodpecker/staging.yml — Staging deployment pipeline # .woodpecker/staging.yml — Staging deployment pipeline
# Triggered by vault-runner via Woodpecker promote API. # Triggered by runner via Woodpecker promote API.
# Human approves promotion in vault → vault-runner calls promote → this runs. # Human approves promotion in vault → runner calls promote → this runs.
when: when:
event: deployment event: deployment
@ -498,8 +498,8 @@ STAGINGEOF
if [ ! -f "${wp_dir}/production.yml" ]; then if [ ! -f "${wp_dir}/production.yml" ]; then
cat > "${wp_dir}/production.yml" <<'PRODUCTIONEOF' cat > "${wp_dir}/production.yml" <<'PRODUCTIONEOF'
# .woodpecker/production.yml — Production deployment pipeline # .woodpecker/production.yml — Production deployment pipeline
# Triggered by vault-runner via Woodpecker promote API. # Triggered by runner via Woodpecker promote API.
# Human approves promotion in vault → vault-runner calls promote → this runs. # Human approves promotion in vault → runner calls promote → this runs.
when: when:
event: deployment event: deployment
@ -2184,10 +2184,10 @@ EOF
esac esac
} }
# ── vault-run command ───────────────────────────────────────────────────────── # ── run command ───────────────────────────────────────────────────────────────
disinto_vault_run() { disinto_run() {
local action_id="${1:?Usage: disinto vault-run <action-id>}" local action_id="${1:?Usage: disinto run <action-id>}"
local compose_file="${FACTORY_ROOT}/docker-compose.yml" local compose_file="${FACTORY_ROOT}/docker-compose.yml"
local vault_enc="${FACTORY_ROOT}/.env.vault.enc" local vault_enc="${FACTORY_ROOT}/.env.vault.enc"
@ -2221,20 +2221,20 @@ disinto_vault_run() {
echo "Vault secrets decrypted to tmpfile" echo "Vault secrets decrypted to tmpfile"
# Run action in ephemeral vault-runner container # Run action in ephemeral runner container
local rc=0 local rc=0
docker compose -f "$compose_file" \ docker compose -f "$compose_file" \
run --rm --env-file "$tmp_env" \ run --rm --env-file "$tmp_env" \
vault-runner "$action_id" || rc=$? runner "$action_id" || rc=$?
# Clean up — secrets gone # Clean up — secrets gone
rm -f "$tmp_env" rm -f "$tmp_env"
echo "Vault tmpfile removed" echo "Run tmpfile removed"
if [ "$rc" -eq 0 ]; then if [ "$rc" -eq 0 ]; then
echo "Vault action ${action_id} completed successfully" echo "Run action ${action_id} completed successfully"
else else
echo "Vault action ${action_id} failed (exit ${rc})" >&2 echo "Run action ${action_id} failed (exit ${rc})" >&2
fi fi
return "$rc" return "$rc"
} }
@ -2314,7 +2314,7 @@ case "${1:-}" in
shell) shift; disinto_shell ;; shell) shift; disinto_shell ;;
status) shift; disinto_status "$@" ;; status) shift; disinto_status "$@" ;;
secrets) shift; disinto_secrets "$@" ;; secrets) shift; disinto_secrets "$@" ;;
vault-run) shift; disinto_vault_run "$@" ;; run) shift; disinto_run "$@" ;;
-h|--help) usage ;; -h|--help) usage ;;
*) usage ;; *) usage ;;
esac esac

View file

@ -112,7 +112,7 @@ near-duplicate exists, REQUEST_CHANGES and reference the existing item.
Agents must NEVER execute external actions directly. Any action that touches Agents must NEVER execute external actions directly. Any action that touches
an external system (publish, deploy, post, push to external registry, API an external system (publish, deploy, post, push to external registry, API
calls to third-party services) MUST go through vault dispatch i.e., the calls to third-party services) MUST go through vault dispatch i.e., the
agent files a vault item (`$OPS_REPO_ROOT/vault/pending/*.json`) and the vault-runner agent files a vault item (`$OPS_REPO_ROOT/vault/pending/*.json`) and the runner
container executes it with injected secrets. container executes it with injected secrets.
Scan the diff for these patterns: Scan the diff for these patterns:
@ -129,7 +129,7 @@ Scan the diff for these patterns:
If ANY of these patterns appear in agent code (scripts in `dev/`, `action/`, If ANY of these patterns appear in agent code (scripts in `dev/`, `action/`,
`planner/`, `gardener/`, `supervisor/`, `predictor/`, `review/`, `formulas/`, `planner/`, `gardener/`, `supervisor/`, `predictor/`, `review/`, `formulas/`,
`lib/`) WITHOUT routing through vault dispatch (`$OPS_REPO_ROOT/vault/pending/`, `vault-fire.sh`, `lib/`) WITHOUT routing through vault dispatch (`$OPS_REPO_ROOT/vault/pending/`, `vault-fire.sh`,
`vault-run-action.sh`), **REQUEST_CHANGES**. `run-action.sh`), **REQUEST_CHANGES**.
Explain that external actions must use vault dispatch per AD-006. The agent Explain that external actions must use vault dispatch per AD-006. The agent
should file a vault item instead of executing directly. should file a vault item instead of executing directly.
@ -137,7 +137,7 @@ should file a vault item instead of executing directly.
**Exceptions** (do NOT flag these): **Exceptions** (do NOT flag these):
- Code inside `vault/` the vault system itself is allowed to handle secrets - Code inside `vault/` the vault system itself is allowed to handle secrets
- References in comments or documentation explaining the architecture - References in comments or documentation explaining the architecture
- `bin/disinto` setup commands that manage `.env.vault.enc` - `bin/disinto` setup commands that manage `.env.vault.enc` and the `run` subcommand
- Local operations (git push to forge, forge API calls with `FORGE_TOKEN`) - Local operations (git push to forge, forge API calls with `FORGE_TOKEN`)
## 6. Re-review (if previous review is provided) ## 6. Re-review (if previous review is provided)

View file

@ -6,7 +6,7 @@ sourced as needed.
| File | What it provides | Sourced by | | File | What it provides | Sourced by |
|---|---|---| |---|---|---|
| `lib/env.sh` | Loads `.env`, sets `FACTORY_ROOT`, exports project config (`FORGE_REPO`, `PROJECT_NAME`, etc.), defines `log()`, `forge_api()`, `forge_api_all()` (accepts optional second TOKEN parameter, defaults to `$FORGE_TOKEN`), `woodpecker_api()`, `wpdb()`, `memory_guard()` (skips agent if RAM < threshold). Auto-loads project TOML if `PROJECT_TOML` is set. Exports per-agent tokens (`FORGE_PLANNER_TOKEN`, `FORGE_GARDENER_TOKEN`, `FORGE_VAULT_TOKEN`, `FORGE_SUPERVISOR_TOKEN`, `FORGE_PREDICTOR_TOKEN`, `FORGE_ACTION_TOKEN`) each falls back to `$FORGE_TOKEN` if not set. **Vault-only token guard (AD-006)**: `unset GITHUB_TOKEN CLAWHUB_TOKEN` so agents never hold external-action tokens only the vault-runner container receives them. **Container note**: when `DISINTO_CONTAINER=1`, `.env` is NOT re-sourced compose already injects env vars (including `FORGE_URL=http://forgejo:3000`) and re-sourcing would clobber them. | Every agent | | `lib/env.sh` | Loads `.env`, sets `FACTORY_ROOT`, exports project config (`FORGE_REPO`, `PROJECT_NAME`, etc.), defines `log()`, `forge_api()`, `forge_api_all()` (accepts optional second TOKEN parameter, defaults to `$FORGE_TOKEN`), `woodpecker_api()`, `wpdb()`, `memory_guard()` (skips agent if RAM < threshold). Auto-loads project TOML if `PROJECT_TOML` is set. Exports per-agent tokens (`FORGE_PLANNER_TOKEN`, `FORGE_GARDENER_TOKEN`, `FORGE_VAULT_TOKEN`, `FORGE_SUPERVISOR_TOKEN`, `FORGE_PREDICTOR_TOKEN`, `FORGE_ACTION_TOKEN`) each falls back to `$FORGE_TOKEN` if not set. **Vault-only token guard (AD-006)**: `unset GITHUB_TOKEN CLAWHUB_TOKEN` so agents never hold external-action tokens only the runner container receives them. **Container note**: when `DISINTO_CONTAINER=1`, `.env` is NOT re-sourced compose already injects env vars (including `FORGE_URL=http://forgejo:3000`) and re-sourcing would clobber them. | Every agent |
| `lib/ci-helpers.sh` | `ci_passed()` — returns 0 if CI state is "success" (or no CI configured). `ci_required_for_pr()` — returns 0 if PR has code files (CI required), 1 if non-code only (CI not required). `is_infra_step()` — returns 0 if a single CI step failure matches infra heuristics (clone/git exit 128, any exit 137, log timeout patterns). `classify_pipeline_failure()` — returns "infra \<reason>" if any failed Woodpecker step matches infra heuristics via `is_infra_step()`, else "code". `ensure_priority_label()` — looks up (or creates) the `priority` label and returns its ID; caches in `_PRIORITY_LABEL_ID`. `ci_commit_status <sha>` — queries Woodpecker directly for CI state, falls back to forge commit status API. `ci_pipeline_number <sha>` — returns the Woodpecker pipeline number for a commit, falls back to parsing forge status `target_url`. `ci_promote <repo_id> <pipeline_num> <environment>` — promotes a pipeline to a named Woodpecker environment (vault-gated deployment: vault approves, vault-fire calls this). | dev-poll, review-poll, review-pr, supervisor-poll | | `lib/ci-helpers.sh` | `ci_passed()` — returns 0 if CI state is "success" (or no CI configured). `ci_required_for_pr()` — returns 0 if PR has code files (CI required), 1 if non-code only (CI not required). `is_infra_step()` — returns 0 if a single CI step failure matches infra heuristics (clone/git exit 128, any exit 137, log timeout patterns). `classify_pipeline_failure()` — returns "infra \<reason>" if any failed Woodpecker step matches infra heuristics via `is_infra_step()`, else "code". `ensure_priority_label()` — looks up (or creates) the `priority` label and returns its ID; caches in `_PRIORITY_LABEL_ID`. `ci_commit_status <sha>` — queries Woodpecker directly for CI state, falls back to forge commit status API. `ci_pipeline_number <sha>` — returns the Woodpecker pipeline number for a commit, falls back to parsing forge status `target_url`. `ci_promote <repo_id> <pipeline_num> <environment>` — promotes a pipeline to a named Woodpecker environment (vault-gated deployment: vault approves, vault-fire calls this). | dev-poll, review-poll, review-pr, supervisor-poll |
| `lib/ci-debug.sh` | CLI tool for Woodpecker CI: `list`, `status`, `logs`, `failures` subcommands. Not sourced — run directly. | Humans / dev-agent (tool access) | | `lib/ci-debug.sh` | CLI tool for Woodpecker CI: `list`, `status`, `logs`, `failures` subcommands. Not sourced — run directly. | Humans / dev-agent (tool access) |
| `lib/load-project.sh` | Parses a `projects/*.toml` file into env vars (`PROJECT_NAME`, `FORGE_REPO`, `WOODPECKER_REPO_ID`, monitoring toggles, mirror config, etc.). | env.sh (when `PROJECT_TOML` is set), supervisor-poll (per-project iteration) | | `lib/load-project.sh` | Parses a `projects/*.toml` file into env vars (`PROJECT_NAME`, `FORGE_REPO`, `WOODPECKER_REPO_ID`, monitoring toggles, mirror config, etc.). | env.sh (when `PROJECT_TOML` is set), supervisor-poll (per-project iteration) |

View file

@ -112,7 +112,7 @@ export CLAUDE_TIMEOUT="${CLAUDE_TIMEOUT:-7200}"
# Vault-only token guard (#745): external-action tokens (GITHUB_TOKEN, CLAWHUB_TOKEN) # Vault-only token guard (#745): external-action tokens (GITHUB_TOKEN, CLAWHUB_TOKEN)
# must NEVER be available to agents. They live in .env.vault.enc and are injected # must NEVER be available to agents. They live in .env.vault.enc and are injected
# only into the ephemeral vault-runner container at fire time. Unset them here so # only into the ephemeral runner container at fire time. Unset them here so
# even an accidental .env inclusion cannot leak them into agent sessions. # even an accidental .env inclusion cannot leak them into agent sessions.
unset GITHUB_TOKEN 2>/dev/null || true unset GITHUB_TOKEN 2>/dev/null || true
unset CLAWHUB_TOKEN 2>/dev/null || true unset CLAWHUB_TOKEN 2>/dev/null || true

View file

@ -28,7 +28,7 @@ needed — the human reviews and publishes directly.
**Key files**: **Key files**:
- `vault/vault-poll.sh` — Processes pending items: retry approved, auto-reject after 48h timeout, invoke vault-agent for JSON actions, notify human for procurement requests - `vault/vault-poll.sh` — Processes pending items: retry approved, auto-reject after 48h timeout, invoke vault-agent for JSON actions, notify human for procurement requests
- `vault/vault-agent.sh` — Classifies and routes pending JSON actions via `claude -p`: auto-approve, auto-reject, or escalate to human - `vault/vault-agent.sh` — Classifies and routes pending JSON actions via `claude -p`: auto-approve, auto-reject, or escalate to human
- `vault/vault-env.sh` — Shared env setup for vault sub-scripts: sources `lib/env.sh`, overrides `FORGE_TOKEN` with `FORGE_VAULT_TOKEN`, sets `VAULT_TOKEN` for vault-runner container - `vault/vault-env.sh` — Shared env setup for vault sub-scripts: sources `lib/env.sh`, overrides `FORGE_TOKEN` with `FORGE_VAULT_TOKEN`, sets `VAULT_TOKEN` for runner container
- `formulas/run-vault.toml` — Source-of-truth formula for the vault agent's classification and routing logic - `formulas/run-vault.toml` — Source-of-truth formula for the vault agent's classification and routing logic
- `vault/vault-fire.sh` — Executes an approved action (JSON) in an **ephemeral Docker container** with vault-only secrets injected (GITHUB_TOKEN, CLAWHUB_TOKEN — never exposed to agents). For deployment actions, calls `lib/ci-helpers.sh:ci_promote()` to gate production promotes via Woodpecker environments. Writes `$OPS_REPO_ROOT/RESOURCES.md` entry for procurement MD approvals. - `vault/vault-fire.sh` — Executes an approved action (JSON) in an **ephemeral Docker container** with vault-only secrets injected (GITHUB_TOKEN, CLAWHUB_TOKEN — never exposed to agents). For deployment actions, calls `lib/ci-helpers.sh:ci_promote()` to gate production promotes via Woodpecker environments. Writes `$OPS_REPO_ROOT/RESOURCES.md` entry for procurement MD approvals.
- `vault/vault-reject.sh` — Marks a JSON action as rejected - `vault/vault-reject.sh` — Marks a JSON action as rejected

View file

@ -1,25 +1,25 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# vault-run-action.sh — Execute an action inside the ephemeral vault-runner container # run-action.sh — Execute an action inside the ephemeral runner container
# #
# This script is the entrypoint for the vault-runner container. It runs with # This script is the entrypoint for the runner container. It runs with
# vault secrets injected as environment variables (GITHUB_TOKEN, CLAWHUB_TOKEN, # vault secrets injected as environment variables (GITHUB_TOKEN, CLAWHUB_TOKEN,
# deploy keys, etc.) and dispatches to the appropriate action handler. # deploy keys, etc.) and dispatches to the appropriate action handler.
# #
# The vault-runner container is ephemeral: it starts, runs the action, and is # The runner container is ephemeral: it starts, runs the action, and is
# destroyed. Secrets exist only in container memory, never on disk. # destroyed. Secrets exist only in container memory, never on disk.
# #
# Usage: vault-run-action.sh <action-id> # Usage: run-action.sh <action-id>
set -euo pipefail set -euo pipefail
VAULT_SCRIPT_DIR="${DISINTO_VAULT_DIR:-/home/agent/disinto/vault}" VAULT_SCRIPT_DIR="${DISINTO_VAULT_DIR:-/home/agent/disinto/vault}"
OPS_VAULT_DIR="${DISINTO_OPS_VAULT_DIR:-${VAULT_SCRIPT_DIR}}" OPS_VAULT_DIR="${DISINTO_OPS_VAULT_DIR:-${VAULT_SCRIPT_DIR}}"
LOGFILE="${VAULT_SCRIPT_DIR}/vault.log" LOGFILE="${VAULT_SCRIPT_DIR}/vault.log"
ACTION_ID="${1:?Usage: vault-run-action.sh <action-id>}" ACTION_ID="${1:?Usage: run-action.sh <action-id>}"
log() { log() {
printf '[%s] vault-runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE" 2>/dev/null || \ printf '[%s] runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE" 2>/dev/null || \
printf '[%s] vault-runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >&2 printf '[%s] runner: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >&2
} }
# Find action file in approved/ # Find action file in approved/

View file

@ -7,3 +7,6 @@
source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/env.sh" source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/env.sh"
# Use vault-bot's own Forgejo identity # Use vault-bot's own Forgejo identity
FORGE_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}" FORGE_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}"
# Set entrypoint for runner container
export VAULT_RUNNER_ENTRYPOINT="run-action.sh"

View file

@ -3,8 +3,8 @@
# #
# Handles two pipelines: # Handles two pipelines:
# A. Action gating (*.json): pending/ → approved/ → fired/ # A. Action gating (*.json): pending/ → approved/ → fired/
# Execution delegated to ephemeral vault-runner container via disinto vault-run. # Execution delegated to ephemeral runner container via disinto run.
# The vault-runner gets vault secrets (.env.vault.enc); this script does NOT. # The runner gets vault secrets (.env.vault.enc); this script does NOT.
# B. Procurement (*.md): approved/ → fired/ (writes RESOURCES.md entry) # B. Procurement (*.md): approved/ → fired/ (writes RESOURCES.md entry)
# #
# If item is in pending/, moves to approved/ first. # If item is in pending/, moves to approved/ first.
@ -100,7 +100,7 @@ if [ "$IS_PROCUREMENT" = true ]; then
fi fi
# ============================================================================= # =============================================================================
# Pipeline B: Action gating — delegate to ephemeral vault-runner container # Pipeline B: Action gating — delegate to ephemeral runner container
# ============================================================================= # =============================================================================
ACTION_TYPE=$(jq -r '.type // ""' < "$ACTION_FILE") ACTION_TYPE=$(jq -r '.type // ""' < "$ACTION_FILE")
ACTION_SOURCE=$(jq -r '.source // ""' < "$ACTION_FILE") ACTION_SOURCE=$(jq -r '.source // ""' < "$ACTION_FILE")
@ -110,19 +110,19 @@ if [ -z "$ACTION_TYPE" ]; then
exit 1 exit 1
fi fi
log "$ACTION_ID: firing type=$ACTION_TYPE source=$ACTION_SOURCE via vault-runner" log "$ACTION_ID: firing type=$ACTION_TYPE source=$ACTION_SOURCE via runner"
FIRE_EXIT=0 FIRE_EXIT=0
# Delegate execution to the ephemeral vault-runner container. # Delegate execution to the ephemeral runner container.
# The vault-runner gets vault secrets (.env.vault.enc) injected at runtime; # The runner gets vault secrets (.env.vault.enc) injected at runtime;
# this host process never sees those secrets. # this host process never sees those secrets.
if [ -f "${FACTORY_ROOT}/.env.vault.enc" ] && [ -f "${FACTORY_ROOT}/docker-compose.yml" ]; then if [ -f "${FACTORY_ROOT}/.env.vault.enc" ] && [ -f "${FACTORY_ROOT}/docker-compose.yml" ]; then
bash "${FACTORY_ROOT}/bin/disinto" vault-run "$ACTION_ID" >> "$LOGFILE" 2>&1 || FIRE_EXIT=$? bash "${FACTORY_ROOT}/bin/disinto" run "$ACTION_ID" >> "$LOGFILE" 2>&1 || FIRE_EXIT=$?
else else
# Fallback for bare-metal or pre-migration setups: run action handler directly # Fallback for bare-metal or pre-migration setups: run action handler directly
log "$ACTION_ID: no .env.vault.enc or docker-compose.yml — running action directly" log "$ACTION_ID: no .env.vault.enc or docker-compose.yml — running action directly"
bash "${SCRIPT_DIR}/vault-run-action.sh" "$ACTION_ID" >> "$LOGFILE" 2>&1 || FIRE_EXIT=$? bash "${SCRIPT_DIR}/run-action.sh" "$ACTION_ID" >> "$LOGFILE" 2>&1 || FIRE_EXIT=$?
fi fi
# ============================================================================= # =============================================================================