#!/usr/bin/env sh set -eu secret_path="kv/atlas/hermes/developer-jenkins" secret_api_path="kv/data/atlas/hermes/developer-jenkins" jwt_file="${VAULT_K8S_JWT_FILE:-/var/run/secrets/kubernetes.io/serviceaccount/token}" vault_role="${VAULT_K8S_ROLE:-hermes-jenkins-token-seed}" payload_file="${TMPDIR:-/tmp}/hermes-jenkins-token.json" log() { printf '[hermes-jenkins-token] %s\n' "$*" >&2; } cleanup() { rm -f "${payload_file}"; } trap cleanup EXIT HUP INT TERM retry_command() { attempt=1 while [ "${attempt}" -le 5 ]; do set +e command_output="$("$@" 2>&1)" command_status=$? set -e if [ "${command_status}" -eq 0 ]; then printf '%s' "${command_output}" return 0 fi if [ "${attempt}" -lt 5 ]; then sleep "${attempt}" fi attempt=$((attempt + 1)) done return "${command_status}" } ensure_token() { if [ -n "${VAULT_TOKEN:-}" ]; then return fi jwt="$(cat "${jwt_file}")" VAULT_TOKEN="$(retry_command vault write -field=token \ auth/kubernetes/login role="${vault_role}" jwt="${jwt}")" || { log "Vault Kubernetes login failed after retries" exit 1 } unset jwt if [ -z "${VAULT_TOKEN}" ]; then log "Vault Kubernetes login returned an empty token" exit 1 fi export VAULT_TOKEN } # Return 0 for the complete field, 10 when absent, 11 when present but # incomplete, and 12 for a persistent authorization/transport failure. read_build_token() { attempt=1 while [ "${attempt}" -le 5 ]; do set +e secret_json="$(vault read -format=json "${secret_api_path}" 2>&1)" secret_status=$? set -e if [ "${secret_status}" -eq 0 ]; then unset secret_json set +e build_token="$(vault kv get -field=build_token "${secret_path}" 2>&1)" field_status=$? set -e if [ "${field_status}" -eq 0 ]; then case "${build_token}" in ''|*[!0-9a-f]*) unset build_token; return 11 ;; esac if [ "${#build_token}" -eq 64 ]; then unset build_token return 0 fi unset build_token return 11 fi if printf '%s' "${build_token}" | grep -q 'No value found'; then unset build_token return 11 fi unset build_token elif printf '%s' "${secret_json}" | grep -Eq 'Code: 404|No value found at'; then unset secret_json return 10 fi if [ "${attempt}" -lt 5 ]; then sleep "${attempt}" fi attempt=$((attempt + 1)) done unset secret_json return 12 } ensure_token if read_build_token; then read_status=0 else read_status=$? fi case "${read_status}" in 0) log "job-scoped token already present; no write performed" exit 0 ;; 11) log "secret exists without a valid build_token; refusing to overwrite existing fields" exit 1 ;; 12) log "secret read failed after retries; refusing to seed" exit 1 ;; 10) ;; *) log "unexpected secret read state ${read_status}" exit 1 ;; esac new_token="$(retry_command vault write -field=random_bytes \ sys/tools/random/32 format=hex)" || { log "Vault random token generation failed after retries" exit 1 } case "${new_token}" in ''|*[!0-9a-f]*) unset new_token log "Vault returned an invalid random token" exit 1 ;; esac if [ "${#new_token}" -ne 64 ]; then unset new_token log "Vault returned an invalid random token" exit 1 fi umask 077 printf '{"options":{"cas":0},"data":{"build_token":"%s"}}\n' \ "${new_token}" > "${payload_file}" unset new_token set +e create_error="$(vault write "${secret_api_path}" @"${payload_file}" 2>&1 >/dev/null)" create_status=$? set -e cleanup if [ "${create_status}" -eq 0 ]; then log "job-scoped token created with KV-v2 CAS create-only semantics" exit 0 fi if printf '%s' "${create_error}" | grep -qi 'check-and-set'; then unset create_error if read_build_token; then log "another seeder won CAS; existing token preserved" exit 0 fi log "CAS race did not produce a readable build_token; refusing to continue" exit 1 fi unset create_error log "KV-v2 CAS create failed; refusing to retry a write" exit 1