fix: agents container: dev-poll fails because factory is mounted read-only (#781)
Add DISINTO_LOG_DIR to lib/env.sh: points to $HOME/data/logs inside the container (writable volume) and $FACTORY_ROOT on the host (existing behavior). Update all agent scripts to write logs, CI fix tracker, metrics, and vault locks to DISINTO_LOG_DIR instead of FACTORY_ROOT. This keeps the factory mount read-only while ensuring all writable state lands on the persistent data volume. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ef544f58f9
commit
9f5a6f9942
12 changed files with 22 additions and 18 deletions
|
|
@ -36,7 +36,7 @@ source "$(dirname "$0")/../lib/formula-session.sh"
|
||||||
source "$(dirname "$0")/../dev/phase-handler.sh"
|
source "$(dirname "$0")/../dev/phase-handler.sh"
|
||||||
SESSION_NAME="action-${PROJECT_NAME}-${ISSUE}"
|
SESSION_NAME="action-${PROJECT_NAME}-${ISSUE}"
|
||||||
LOCKFILE="/tmp/action-agent-${ISSUE}.lock"
|
LOCKFILE="/tmp/action-agent-${ISSUE}.lock"
|
||||||
LOGFILE="${FACTORY_ROOT}/action/action-poll-${PROJECT_NAME:-default}.log"
|
LOGFILE="${DISINTO_LOG_DIR}/action/action-poll-${PROJECT_NAME:-default}.log"
|
||||||
IDLE_TIMEOUT="${ACTION_IDLE_TIMEOUT:-14400}" # 4h default
|
IDLE_TIMEOUT="${ACTION_IDLE_TIMEOUT:-14400}" # 4h default
|
||||||
MAX_LIFETIME="${ACTION_MAX_LIFETIME:-28800}" # 8h default wall-clock cap
|
MAX_LIFETIME="${ACTION_MAX_LIFETIME:-28800}" # 8h default wall-clock cap
|
||||||
SESSION_START_EPOCH=$(date +%s)
|
SESSION_START_EPOCH=$(date +%s)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ FORGE_TOKEN="${FORGE_ACTION_TOKEN:-${FORGE_TOKEN}}"
|
||||||
source "$(dirname "$0")/../lib/guard.sh"
|
source "$(dirname "$0")/../lib/guard.sh"
|
||||||
check_active action
|
check_active action
|
||||||
|
|
||||||
LOGFILE="${FACTORY_ROOT}/action/action-poll-${PROJECT_NAME:-default}.log"
|
LOGFILE="${DISINTO_LOG_DIR}/action/action-poll-${PROJECT_NAME:-default}.log"
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ status() {
|
||||||
printf '[%s] dev-agent #%s: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$ISSUE" "$*" > "$STATUSFILE"
|
printf '[%s] dev-agent #%s: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$ISSUE" "$*" > "$STATUSFILE"
|
||||||
log "$*"
|
log "$*"
|
||||||
}
|
}
|
||||||
LOGFILE="${FACTORY_ROOT}/dev/dev-agent.log"
|
LOGFILE="${DISINTO_LOG_DIR}/dev/dev-agent.log"
|
||||||
PREFLIGHT_RESULT="/tmp/dev-agent-preflight.json"
|
PREFLIGHT_RESULT="/tmp/dev-agent-preflight.json"
|
||||||
BRANCH="fix/issue-${ISSUE}"
|
BRANCH="fix/issue-${ISSUE}"
|
||||||
WORKTREE="/tmp/${PROJECT_NAME}-worktree-${ISSUE}"
|
WORKTREE="/tmp/${PROJECT_NAME}-worktree-${ISSUE}"
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ UNDERSPECIFIED_LABEL_ID=$(forge_api GET "/labels" 2>/dev/null \
|
||||||
UNDERSPECIFIED_LABEL_ID="${UNDERSPECIFIED_LABEL_ID:-1300816}"
|
UNDERSPECIFIED_LABEL_ID="${UNDERSPECIFIED_LABEL_ID:-1300816}"
|
||||||
|
|
||||||
# Track CI fix attempts per PR to avoid infinite respawn loops
|
# Track CI fix attempts per PR to avoid infinite respawn loops
|
||||||
CI_FIX_TRACKER="${FACTORY_ROOT}/dev/ci-fixes-${PROJECT_NAME:-default}.json"
|
CI_FIX_TRACKER="${DISINTO_LOG_DIR}/dev/ci-fixes-${PROJECT_NAME:-default}.json"
|
||||||
CI_FIX_LOCK="${CI_FIX_TRACKER}.lock"
|
CI_FIX_LOCK="${CI_FIX_TRACKER}.lock"
|
||||||
ci_fix_count() {
|
ci_fix_count() {
|
||||||
local pr="$1"
|
local pr="$1"
|
||||||
|
|
@ -399,7 +399,7 @@ Instructions:
|
||||||
|
|
||||||
API="${FORGE_API}"
|
API="${FORGE_API}"
|
||||||
LOCKFILE="/tmp/dev-agent-${PROJECT_NAME:-default}.lock"
|
LOCKFILE="/tmp/dev-agent-${PROJECT_NAME:-default}.lock"
|
||||||
LOGFILE="${FACTORY_ROOT}/dev/dev-agent-${PROJECT_NAME:-default}.log"
|
LOGFILE="${DISINTO_LOG_DIR}/dev/dev-agent-${PROJECT_NAME:-default}.log"
|
||||||
PREFLIGHT_RESULT="/tmp/dev-agent-preflight.json"
|
PREFLIGHT_RESULT="/tmp/dev-agent-preflight.json"
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,12 @@ FACTORY_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
# maps land on the persistent volume instead of /tmp (which is ephemeral).
|
# maps land on the persistent volume instead of /tmp (which is ephemeral).
|
||||||
if [ "${DISINTO_CONTAINER:-}" = "1" ]; then
|
if [ "${DISINTO_CONTAINER:-}" = "1" ]; then
|
||||||
DISINTO_DATA_DIR="${HOME}/data"
|
DISINTO_DATA_DIR="${HOME}/data"
|
||||||
mkdir -p "${DISINTO_DATA_DIR}"
|
DISINTO_LOG_DIR="${DISINTO_DATA_DIR}/logs"
|
||||||
|
mkdir -p "${DISINTO_DATA_DIR}" "${DISINTO_LOG_DIR}"/{dev,action,review,supervisor,vault,site,metrics}
|
||||||
|
else
|
||||||
|
DISINTO_LOG_DIR="${FACTORY_ROOT}"
|
||||||
fi
|
fi
|
||||||
|
export DISINTO_LOG_DIR
|
||||||
|
|
||||||
# Load secrets: prefer .env.enc (SOPS-encrypted), fall back to plaintext .env.
|
# Load secrets: prefer .env.enc (SOPS-encrypted), fall back to plaintext .env.
|
||||||
# Inside the container, compose already injects env vars via env_file + environment
|
# Inside the container, compose already injects env vars via env_file + environment
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ git -C "$FACTORY_ROOT" pull --ff-only origin main 2>/dev/null || true
|
||||||
PR_NUMBER="${1:?Usage: review-pr.sh <pr-number> [--force]}"
|
PR_NUMBER="${1:?Usage: review-pr.sh <pr-number> [--force]}"
|
||||||
FORCE="${2:-}"
|
FORCE="${2:-}"
|
||||||
API="${FORGE_API}"
|
API="${FORGE_API}"
|
||||||
LOGFILE="${FACTORY_ROOT}/review/review.log"
|
LOGFILE="${DISINTO_LOG_DIR}/review/review.log"
|
||||||
SESSION="review-${PROJECT_NAME}-${PR_NUMBER}"
|
SESSION="review-${PROJECT_NAME}-${PR_NUMBER}"
|
||||||
PHASE_FILE="/tmp/review-session-${PROJECT_NAME}-${PR_NUMBER}.phase"
|
PHASE_FILE="/tmp/review-session-${PROJECT_NAME}-${PR_NUMBER}.phase"
|
||||||
OUTPUT_FILE="/tmp/${PROJECT_NAME}-review-output-${PR_NUMBER}.json"
|
OUTPUT_FILE="/tmp/${PROJECT_NAME}-review-output-${PR_NUMBER}.json"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ FACTORY_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
# shellcheck source=../lib/env.sh
|
# shellcheck source=../lib/env.sh
|
||||||
source "$FACTORY_ROOT/lib/env.sh"
|
source "$FACTORY_ROOT/lib/env.sh"
|
||||||
|
|
||||||
LOGFILE="${FACTORY_ROOT}/site/collect-engagement.log"
|
LOGFILE="${DISINTO_LOG_DIR}/site/collect-engagement.log"
|
||||||
log() {
|
log() {
|
||||||
printf '[%s] collect-engagement: %s\n' \
|
printf '[%s] collect-engagement: %s\n' \
|
||||||
"$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
"$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ source "$FACTORY_ROOT/lib/env.sh"
|
||||||
# shellcheck source=../lib/ci-helpers.sh
|
# shellcheck source=../lib/ci-helpers.sh
|
||||||
source "$FACTORY_ROOT/lib/ci-helpers.sh" 2>/dev/null || true
|
source "$FACTORY_ROOT/lib/ci-helpers.sh" 2>/dev/null || true
|
||||||
|
|
||||||
LOGFILE="${FACTORY_ROOT}/site/collect-metrics.log"
|
LOGFILE="${DISINTO_LOG_DIR}/site/collect-metrics.log"
|
||||||
log() {
|
log() {
|
||||||
printf '[%s] collect-metrics: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
printf '[%s] collect-metrics: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ set -euo pipefail
|
||||||
source "$(dirname "$0")/../lib/env.sh"
|
source "$(dirname "$0")/../lib/env.sh"
|
||||||
source "$(dirname "$0")/../lib/ci-helpers.sh"
|
source "$(dirname "$0")/../lib/ci-helpers.sh"
|
||||||
|
|
||||||
LOGFILE="${FACTORY_ROOT}/supervisor/supervisor.log"
|
LOGFILE="${DISINTO_LOG_DIR}/supervisor/supervisor.log"
|
||||||
STATUSFILE="/tmp/supervisor-status"
|
STATUSFILE="/tmp/supervisor-status"
|
||||||
LOCKFILE="/tmp/supervisor-poll.lock"
|
LOCKFILE="/tmp/supervisor-poll.lock"
|
||||||
PROMPT_FILE="${FACTORY_ROOT}/supervisor/PROMPT.md"
|
PROMPT_FILE="${FACTORY_ROOT}/supervisor/PROMPT.md"
|
||||||
PROJECTS_DIR="${FACTORY_ROOT}/projects"
|
PROJECTS_DIR="${FACTORY_ROOT}/projects"
|
||||||
|
|
||||||
METRICS_FILE="${FACTORY_ROOT}/metrics/supervisor-metrics.jsonl"
|
METRICS_FILE="${DISINTO_LOG_DIR}/metrics/supervisor-metrics.jsonl"
|
||||||
|
|
||||||
emit_metric() {
|
emit_metric() {
|
||||||
printf '%s\n' "$1" >> "$METRICS_FILE"
|
printf '%s\n' "$1" >> "$METRICS_FILE"
|
||||||
|
|
@ -428,7 +428,7 @@ check_project() {
|
||||||
AGE_MIN=$(( (NOW_EPOCH - UPDATED_EPOCH) / 60 ))
|
AGE_MIN=$(( (NOW_EPOCH - UPDATED_EPOCH) / 60 ))
|
||||||
if [ "$AGE_MIN" -gt 60 ]; then
|
if [ "$AGE_MIN" -gt 60 ]; then
|
||||||
p3 "${proj_name}: PR #${pr}: CI passed, no review for ${AGE_MIN}min"
|
p3 "${proj_name}: PR #${pr}: CI passed, no review for ${AGE_MIN}min"
|
||||||
bash "${FACTORY_ROOT}/review/review-pr.sh" "$pr" >> "${FACTORY_ROOT}/review/review.log" 2>&1 &
|
bash "${FACTORY_ROOT}/review/review-pr.sh" "$pr" >> "${DISINTO_LOG_DIR}/review/review.log" 2>&1 &
|
||||||
fixed "${proj_name}: Auto-triggered review for PR #${pr}"
|
fixed "${proj_name}: Auto-triggered review for PR #${pr}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
source "${SCRIPT_DIR}/vault-env.sh"
|
source "${SCRIPT_DIR}/vault-env.sh"
|
||||||
|
|
||||||
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
||||||
LOCKS_DIR="${FACTORY_ROOT}/vault/.locks"
|
LOCKS_DIR="${DISINTO_LOG_DIR}/vault/.locks"
|
||||||
LOGFILE="${FACTORY_ROOT}/vault/vault.log"
|
LOGFILE="${DISINTO_LOG_DIR}/vault/vault.log"
|
||||||
RESOURCES_FILE="${OPS_REPO_ROOT}/RESOURCES.md"
|
RESOURCES_FILE="${OPS_REPO_ROOT}/RESOURCES.md"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ source "${SCRIPT_DIR}/../lib/env.sh"
|
||||||
# Use vault-bot's own Forgejo identity (#747)
|
# Use vault-bot's own Forgejo identity (#747)
|
||||||
FORGE_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}"
|
FORGE_TOKEN="${FORGE_VAULT_TOKEN:-${FORGE_TOKEN}}"
|
||||||
|
|
||||||
LOGFILE="${FACTORY_ROOT}/vault/vault.log"
|
LOGFILE="${DISINTO_LOG_DIR}/vault/vault.log"
|
||||||
STATUSFILE="/tmp/vault-status"
|
STATUSFILE="/tmp/vault-status"
|
||||||
LOCKFILE="/tmp/vault-poll.lock"
|
LOCKFILE="/tmp/vault-poll.lock"
|
||||||
VAULT_SCRIPT_DIR="${FACTORY_ROOT}/vault"
|
VAULT_SCRIPT_DIR="${FACTORY_ROOT}/vault"
|
||||||
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
||||||
LOCKS_DIR="${VAULT_SCRIPT_DIR}/.locks"
|
LOCKS_DIR="${DISINTO_LOG_DIR}/vault/.locks"
|
||||||
|
|
||||||
TIMEOUT_HOURS=48
|
TIMEOUT_HOURS=48
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
source "${SCRIPT_DIR}/vault-env.sh"
|
source "${SCRIPT_DIR}/vault-env.sh"
|
||||||
|
|
||||||
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
OPS_VAULT_DIR="${OPS_REPO_ROOT}/vault"
|
||||||
LOGFILE="${FACTORY_ROOT}/vault/vault.log"
|
LOGFILE="${DISINTO_LOG_DIR}/vault/vault.log"
|
||||||
LOCKS_DIR="${FACTORY_ROOT}/vault/.locks"
|
LOCKS_DIR="${DISINTO_LOG_DIR}/vault/.locks"
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
printf '[%s] vault-reject: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
printf '[%s] vault-reject: %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*" >> "$LOGFILE"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue