Compare commits
No commits in common. "16fc7979c5f1797f8d66fd691f6feb9b2e2acf9b" and "fb4ffe9fb666308d1ccee256c9cd36225dac12af" have entirely different histories.
16fc7979c5
...
fb4ffe9fb6
1 changed files with 7 additions and 159 deletions
166
docker/edge/dispatcher.sh
Executable file → Normal file
166
docker/edge/dispatcher.sh
Executable file → Normal file
|
|
@ -1,164 +1,12 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# dispatcher.sh — Edge task dispatcher
|
# dispatcher.sh — Edge task dispatcher placeholder
|
||||||
#
|
#
|
||||||
# Polls the ops repo for approved actions and launches task-runner containers.
|
# TODO: Implement task polling and runner launching (#45)
|
||||||
# Part of #24.
|
# Currently a no-op loop for future expansion.
|
||||||
#
|
|
||||||
# Action JSON schema:
|
|
||||||
# {
|
|
||||||
# "id": "publish-skill-20260328",
|
|
||||||
# "formula": "clawhub-publish",
|
|
||||||
# "secrets": ["CLAWHUB_TOKEN"],
|
|
||||||
# "tools": ["clawhub"],
|
|
||||||
# "context": "SKILL.md bumped to 0.3.0",
|
|
||||||
# "model": "sonnet"
|
|
||||||
# }
|
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# Resolve script root (parent of lib/)
|
while true; do
|
||||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
# Placeholder: no-op loop, no logic yet
|
||||||
|
sleep 60
|
||||||
# Source shared environment
|
done
|
||||||
source "${SCRIPT_ROOT}/../lib/env.sh"
|
|
||||||
|
|
||||||
# Load vault secrets after env.sh (env.sh unsets them for agent security)
|
|
||||||
# Vault secrets must be available to the dispatcher
|
|
||||||
if [ -f "$FACTORY_ROOT/.env.vault.enc" ] && command -v sops &>/dev/null; then
|
|
||||||
set -a
|
|
||||||
eval "$(sops -d --output-type dotenv "$FACTORY_ROOT/.env.vault.enc" 2>/dev/null)" \
|
|
||||||
|| echo "Warning: failed to decrypt .env.vault.enc — vault secrets not loaded" >&2
|
|
||||||
set +a
|
|
||||||
elif [ -f "$FACTORY_ROOT/.env.vault" ]; then
|
|
||||||
set -a
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source "$FACTORY_ROOT/.env.vault"
|
|
||||||
set +a
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ops repo location (vault/actions directory)
|
|
||||||
OPS_REPO_ROOT="${OPS_REPO_ROOT:-/home/debian/disinto-ops}"
|
|
||||||
VAULT_ACTIONS_DIR="${OPS_REPO_ROOT}/vault/actions"
|
|
||||||
|
|
||||||
# Log function
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date -u '+%Y-%m-%d %H:%M:%S UTC')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Clone or pull the ops repo
|
|
||||||
ensure_ops_repo() {
|
|
||||||
if [ ! -d "${OPS_REPO_ROOT}/.git" ]; then
|
|
||||||
log "Cloning ops repo from ${FORGE_URL}/${FORGE_OPS_REPO}..."
|
|
||||||
git clone "${FORGE_URL}/${FORGE_OPS_REPO}" "${OPS_REPO_ROOT}"
|
|
||||||
else
|
|
||||||
log "Pulling latest ops repo changes..."
|
|
||||||
(cd "${OPS_REPO_ROOT}" && git pull --rebase)
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if an action has already been completed
|
|
||||||
is_action_completed() {
|
|
||||||
local id="$1"
|
|
||||||
[ -f "${VAULT_ACTIONS_DIR}/${id}.result.json" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Launch a runner for the given action ID
|
|
||||||
launch_runner() {
|
|
||||||
local id="$1"
|
|
||||||
log "Launching runner for action: ${id}"
|
|
||||||
|
|
||||||
# Read action config
|
|
||||||
local action_file="${VAULT_ACTIONS_DIR}/${id}.json"
|
|
||||||
if [ ! -f "$action_file" ]; then
|
|
||||||
log "ERROR: Action file not found: ${action_file}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract formula from action JSON
|
|
||||||
local formula
|
|
||||||
formula=$(jq -r '.formula // empty' "$action_file")
|
|
||||||
if [ -z "$formula" ]; then
|
|
||||||
log "ERROR: Action ${id} missing 'formula' field"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract secrets (array for safe handling)
|
|
||||||
local -a secrets=()
|
|
||||||
while IFS= read -r secret; do
|
|
||||||
[ -n "$secret" ] && secrets+=("$secret")
|
|
||||||
done < <(jq -r '.secrets[]? // empty' "$action_file" 2>/dev/null)
|
|
||||||
|
|
||||||
# Build command array (safe from shell injection)
|
|
||||||
local -a cmd=(docker compose run --rm runner)
|
|
||||||
|
|
||||||
# Add environment variables BEFORE service name
|
|
||||||
for secret in "${secrets[@]+"${secrets[@]}"}"; do
|
|
||||||
cmd+=(-e "${secret}") # Pass actual value to container (from env)
|
|
||||||
done
|
|
||||||
|
|
||||||
# Add formula and id as arguments (after service name)
|
|
||||||
cmd+=("$formula" "$id")
|
|
||||||
|
|
||||||
# Log command skeleton (hide all -e flags for security)
|
|
||||||
local -a log_cmd=()
|
|
||||||
local skip_next=0
|
|
||||||
for arg in "${cmd[@]}"; do
|
|
||||||
if [[ $skip_next -eq 1 ]]; then
|
|
||||||
skip_next=0
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
if [[ "$arg" == "-e" ]]; then
|
|
||||||
log_cmd+=("$arg" "<redacted>")
|
|
||||||
skip_next=1
|
|
||||||
else
|
|
||||||
log_cmd+=("$arg")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
log "Running: ${log_cmd[*]}"
|
|
||||||
|
|
||||||
# Execute with array expansion (safe from shell injection)
|
|
||||||
"${cmd[@]}"
|
|
||||||
|
|
||||||
log "Runner completed for action: ${id}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main dispatcher loop
|
|
||||||
main() {
|
|
||||||
log "Starting dispatcher..."
|
|
||||||
log "Polling ops repo: ${VAULT_ACTIONS_DIR}"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
# Refresh ops repo at the start of each poll cycle
|
|
||||||
ensure_ops_repo
|
|
||||||
|
|
||||||
# Check if actions directory exists
|
|
||||||
if [ ! -d "${VAULT_ACTIONS_DIR}" ]; then
|
|
||||||
log "Actions directory not found: ${VAULT_ACTIONS_DIR}"
|
|
||||||
sleep 60
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Process each action file
|
|
||||||
for action_file in "${VAULT_ACTIONS_DIR}"/*.json; do
|
|
||||||
# Handle case where no .json files exist
|
|
||||||
[ -e "$action_file" ] || continue
|
|
||||||
|
|
||||||
local id
|
|
||||||
id=$(basename "$action_file" .json)
|
|
||||||
|
|
||||||
# Skip if already completed
|
|
||||||
if is_action_completed "$id"; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Launch runner for this action
|
|
||||||
launch_runner "$id"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Wait before next poll
|
|
||||||
sleep 60
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run main
|
|
||||||
main "$@"
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue