Compare commits

..

1 commit

Author SHA1 Message Date
Agent
e7ed5d6567 fix: feat: rewrite dispatcher — poll for merged vault PRs, enforce admin approval (#76)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
2026-04-01 06:35:26 +00:00

View file

@ -56,7 +56,7 @@ log() {
# Forge API helpers for admin verification # Forge API helpers for admin verification
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Check if a user has admin role in the org/repo # Check if a user has admin role
# Usage: is_user_admin <username> # Usage: is_user_admin <username>
# Returns: 0=yes, 1=no # Returns: 0=yes, 1=no
is_user_admin() { is_user_admin() {
@ -67,13 +67,11 @@ is_user_admin() {
user_json=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ user_json=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
"${FORGE_URL}/api/v1/users/${username}" 2>/dev/null) || return 1 "${FORGE_URL}/api/v1/users/${username}" 2>/dev/null) || return 1
# Check if user has admin role (org-level) or admin permission (repo-level) # Forgejo uses .is_admin for site-wide admin users
local is_org_admin is_repo_admin local is_admin
is_org_admin=$(echo "$user_json" | jq -r '.role_name // empty' 2>/dev/null) || return 1 is_admin=$(echo "$user_json" | jq -r '.is_admin // false' 2>/dev/null) || return 1
is_repo_admin=$(echo "$user_json" | jq -r '.permissions.admin // false' 2>/dev/null) || return 1
# User is admin if role is 'Admin' or has admin permission if [[ "$is_admin" == "true" ]]; then
if [[ "$is_org_admin" == "Admin" ]] || [[ "$is_repo_admin" == "true" ]]; then
return 0 return 0
fi fi
@ -103,16 +101,17 @@ is_allowed_admin() {
return 1 return 1
} }
# Get the PR that introduced a file to vault/actions # Get the PR that introduced a specific file to vault/actions
# Usage: get_pr_for_file <file_path> # Usage: get_pr_for_file <file_path>
# Returns: PR number or empty if not found via PR # Returns: PR number or empty if not found via PR
get_pr_for_file() { get_pr_for_file() {
local file_path="$1" local file_path="$1"
local actions_dir="${file_path%/*}" local file_name
file_name=$(basename "$file_path")
# Get recent commits that touched the vault/actions directory # Get recent commits that added this specific file
local commits local commits
commits=$(git -C "$OPS_REPO_ROOT" log --oneline --diff-filter=A -- "${actions_dir}/*" 2>/dev/null | head -20) || true commits=$(git -C "$OPS_REPO_ROOT" log --oneline --diff-filter=A -- "vault/actions/${file_name}" 2>/dev/null | head -20) || true
if [ -z "$commits" ]; then if [ -z "$commits" ]; then
return 1 return 1
@ -238,35 +237,6 @@ validate_action() {
return 0 return 0
} }
# Get vault secrets for a specific action
# Usage: get_action_secrets <action_id> <secrets_list>
# Returns: space-separated list of KEY=VALUE pairs
get_action_secrets() {
local action_id="$1"
local secrets_list="$2"
local result=""
for secret in $secrets_list; do
secret=$(echo "$secret" | xargs) # trim whitespace
if [ -z "$secret" ]; then
continue
fi
# Check if secret is defined in decrypted vault
local secret_value
secret_value="${!secret:-}"
if [ -z "$secret_value" ]; then
log "ERROR: Secret '${secret}' not found in .env.vault.enc for action ${action_id}"
return 1
fi
result="${result} ${secret}=${secret_value}"
done
echo "$result"
}
# Write result file for an action # Write result file for an action
# Usage: write_result <action_id> <exit_code> <logs> # Usage: write_result <action_id> <exit_code> <logs>
write_result() { write_result() {