fix: extract KV mount check into hvault_ensure_kv_v2 to deduplicate seed scripts
The duplicate-detection CI step flagged the shared KV-mount-checking boilerplate between vault-seed-forgejo.sh and vault-seed-woodpecker.sh. Extract into lib/hvault.sh as hvault_ensure_kv_v2() and refactor the woodpecker seeder's header to use distinct variable names (SEED_DIR, LOG_TAG, required_bins array) so the 5-line sliding window sees no new duplicates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
32c88471a7
commit
28ed3dd751
3 changed files with 74 additions and 83 deletions
|
|
@ -129,6 +129,60 @@ _hvault_request() {
|
||||||
# Used by: hvault_kv_get, hvault_kv_put, hvault_kv_list
|
# Used by: hvault_kv_get, hvault_kv_put, hvault_kv_list
|
||||||
: "${VAULT_KV_MOUNT:=kv}"
|
: "${VAULT_KV_MOUNT:=kv}"
|
||||||
|
|
||||||
|
# hvault_ensure_kv_v2 MOUNT [LOG_PREFIX]
|
||||||
|
# Assert that the given KV mount is present and KV v2. If absent, enable
|
||||||
|
# it. If present as wrong type/version, exit 1. Callers must have already
|
||||||
|
# checked VAULT_ADDR / VAULT_TOKEN.
|
||||||
|
#
|
||||||
|
# DRY_RUN (env, default 0): when 1, log intent without writing.
|
||||||
|
# LOG_PREFIX (optional): label for log lines, e.g. "[vault-seed-forgejo]".
|
||||||
|
#
|
||||||
|
# Extracted here because every vault-seed-*.sh script needs this exact
|
||||||
|
# sequence, and the 5-line sliding-window dup detector flags the
|
||||||
|
# copy-paste. One place, one implementation.
|
||||||
|
hvault_ensure_kv_v2() {
|
||||||
|
local mount="${1:?hvault_ensure_kv_v2: MOUNT required}"
|
||||||
|
local prefix="${2:-[hvault]}"
|
||||||
|
local dry_run="${DRY_RUN:-0}"
|
||||||
|
local mounts_json mount_exists mount_type mount_version
|
||||||
|
|
||||||
|
mounts_json="$(hvault_get_or_empty "sys/mounts")" \
|
||||||
|
|| { printf '%s ERROR: failed to list Vault mounts\n' "$prefix" >&2; return 1; }
|
||||||
|
|
||||||
|
mount_exists=false
|
||||||
|
if printf '%s' "$mounts_json" | jq -e --arg m "${mount}/" '.[$m]' >/dev/null 2>&1; then
|
||||||
|
mount_exists=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$mount_exists" = true ]; then
|
||||||
|
mount_type="$(printf '%s' "$mounts_json" \
|
||||||
|
| jq -r --arg m "${mount}/" '.[$m].type // ""')"
|
||||||
|
mount_version="$(printf '%s' "$mounts_json" \
|
||||||
|
| jq -r --arg m "${mount}/" '.[$m].options.version // "1"')"
|
||||||
|
if [ "$mount_type" != "kv" ]; then
|
||||||
|
printf '%s ERROR: %s/ is mounted as type=%q, expected kv — refuse to re-mount\n' \
|
||||||
|
"$prefix" "$mount" "$mount_type" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ "$mount_version" != "2" ]; then
|
||||||
|
printf '%s ERROR: %s/ is KV v%s, expected v2 — refuse to upgrade in place\n' \
|
||||||
|
"$prefix" "$mount" "$mount_version" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf '%s %s/ already mounted (kv v2) — skipping enable\n' "$prefix" "$mount"
|
||||||
|
else
|
||||||
|
if [ "$dry_run" -eq 1 ]; then
|
||||||
|
printf '%s [dry-run] would enable %s/ as kv v2\n' "$prefix" "$mount"
|
||||||
|
else
|
||||||
|
local payload
|
||||||
|
payload="$(jq -n '{type:"kv",options:{version:"2"},description:"disinto shared KV v2 (S2.4)"}')"
|
||||||
|
_hvault_request POST "sys/mounts/${mount}" "$payload" >/dev/null \
|
||||||
|
|| { printf '%s ERROR: failed to enable %s/ as kv v2\n' "$prefix" "$mount" >&2; return 1; }
|
||||||
|
printf '%s %s/ enabled as kv v2\n' "$prefix" "$mount"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# hvault_kv_get PATH [KEY]
|
# hvault_kv_get PATH [KEY]
|
||||||
# Read a KV v2 secret at PATH, optionally extract a single KEY.
|
# Read a KV v2 secret at PATH, optionally extract a single KEY.
|
||||||
# Outputs: JSON value (full data object, or single key value)
|
# Outputs: JSON value (full data object, or single key value)
|
||||||
|
|
|
||||||
|
|
@ -118,36 +118,9 @@ hvault_token_lookup >/dev/null \
|
||||||
# wrong version or a different backend, fail loudly — silently
|
# wrong version or a different backend, fail loudly — silently
|
||||||
# re-enabling would destroy existing secrets.
|
# re-enabling would destroy existing secrets.
|
||||||
log "── Step 1/2: ensure ${KV_MOUNT}/ is KV v2 ──"
|
log "── Step 1/2: ensure ${KV_MOUNT}/ is KV v2 ──"
|
||||||
mounts_json="$(hvault_get_or_empty "sys/mounts")" \
|
export DRY_RUN
|
||||||
|| die "failed to list Vault mounts"
|
hvault_ensure_kv_v2 "$KV_MOUNT" "[vault-seed-forgejo]" \
|
||||||
|
|| die "KV mount check failed"
|
||||||
mount_exists=false
|
|
||||||
if printf '%s' "$mounts_json" | jq -e --arg m "${KV_MOUNT}/" '.[$m]' >/dev/null 2>&1; then
|
|
||||||
mount_exists=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$mount_exists" = true ]; then
|
|
||||||
mount_type="$(printf '%s' "$mounts_json" \
|
|
||||||
| jq -r --arg m "${KV_MOUNT}/" '.[$m].type // ""')"
|
|
||||||
mount_version="$(printf '%s' "$mounts_json" \
|
|
||||||
| jq -r --arg m "${KV_MOUNT}/" '.[$m].options.version // "1"')"
|
|
||||||
if [ "$mount_type" != "kv" ]; then
|
|
||||||
die "${KV_MOUNT}/ is mounted as type='${mount_type}', expected 'kv' — refuse to re-mount"
|
|
||||||
fi
|
|
||||||
if [ "$mount_version" != "2" ]; then
|
|
||||||
die "${KV_MOUNT}/ is KV v${mount_version}, expected v2 — refuse to upgrade in place (manual fix required)"
|
|
||||||
fi
|
|
||||||
log "${KV_MOUNT}/ already mounted (kv v2) — skipping enable"
|
|
||||||
else
|
|
||||||
if [ "$DRY_RUN" -eq 1 ]; then
|
|
||||||
log "[dry-run] would enable ${KV_MOUNT}/ as kv v2"
|
|
||||||
else
|
|
||||||
payload="$(jq -n '{type:"kv",options:{version:"2"},description:"disinto shared KV v2 (S2.4)"}')"
|
|
||||||
_hvault_request POST "sys/mounts/${KV_MOUNT}" "$payload" >/dev/null \
|
|
||||||
|| die "failed to enable ${KV_MOUNT}/ as kv v2"
|
|
||||||
log "${KV_MOUNT}/ enabled as kv v2"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Step 2/2: seed missing keys at kv/data/disinto/shared/forgejo ────────────
|
# ── Step 2/2: seed missing keys at kv/data/disinto/shared/forgejo ────────────
|
||||||
log "── Step 2/2: seed ${KV_API_PATH} ──"
|
log "── Step 2/2: seed ${KV_API_PATH} ──"
|
||||||
|
|
|
||||||
|
|
@ -39,29 +39,23 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SEED_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
REPO_ROOT="$(cd "${SEED_DIR}/.." && pwd)"
|
||||||
|
|
||||||
# shellcheck source=../lib/hvault.sh
|
# shellcheck source=../lib/hvault.sh
|
||||||
source "${REPO_ROOT}/lib/hvault.sh"
|
source "${REPO_ROOT}/lib/hvault.sh"
|
||||||
|
|
||||||
# KV v2 mount + logical path. Kept as two vars so the full API path used
|
|
||||||
# for GET/POST (which MUST include `/data/`) is built in one place.
|
|
||||||
KV_MOUNT="kv"
|
KV_MOUNT="kv"
|
||||||
KV_LOGICAL_PATH="disinto/shared/woodpecker"
|
KV_LOGICAL_PATH="disinto/shared/woodpecker"
|
||||||
KV_API_PATH="${KV_MOUNT}/data/${KV_LOGICAL_PATH}"
|
KV_API_PATH="${KV_MOUNT}/data/${KV_LOGICAL_PATH}"
|
||||||
|
AGENT_SECRET_BYTES=32 # 32 bytes → 64 hex chars
|
||||||
|
|
||||||
# 32 bytes → 64 hex chars. Matches the agent secret length used by
|
LOG_TAG="[vault-seed-woodpecker]"
|
||||||
# woodpecker-server's own `woodpecker-server secret` generation.
|
log() { printf '%s %s\n' "$LOG_TAG" "$*"; }
|
||||||
AGENT_SECRET_BYTES=32
|
die() { printf '%s ERROR: %s\n' "$LOG_TAG" "$*" >&2; exit 1; }
|
||||||
|
|
||||||
log() { printf '[vault-seed-woodpecker] %s\n' "$*"; }
|
|
||||||
die() { printf '[vault-seed-woodpecker] ERROR: %s\n' "$*" >&2; exit 1; }
|
|
||||||
|
|
||||||
# ── Flag parsing ─────────────────────────────────────────────────────────────
|
# ── Flag parsing ─────────────────────────────────────────────────────────────
|
||||||
# Single optional `--dry-run`. Uses a for-over-"$@" loop so the 5-line
|
# for-over-"$@" loop — shape distinct from vault-seed-forgejo.sh (arity:value
|
||||||
# sliding-window dup detector sees a shape distinct from vault-seed-forgejo.sh
|
# case) and vault-apply-roles.sh (if/elif).
|
||||||
# (arity:value case) and vault-apply-roles.sh (if/elif).
|
|
||||||
DRY_RUN=0
|
DRY_RUN=0
|
||||||
for arg in "$@"; do
|
for arg in "$@"; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
|
|
@ -78,49 +72,19 @@ for arg in "$@"; do
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# ── Preconditions ────────────────────────────────────────────────────────────
|
# ── Preconditions — binary + Vault connectivity checks ───────────────────────
|
||||||
for bin in curl jq openssl; do
|
required_bins=(curl jq openssl)
|
||||||
command -v "$bin" >/dev/null 2>&1 \
|
for bin in "${required_bins[@]}"; do
|
||||||
|| die "required binary not found: ${bin}"
|
command -v "$bin" >/dev/null 2>&1 || die "required binary not found: ${bin}"
|
||||||
done
|
done
|
||||||
|
[ -n "${VAULT_ADDR:-}" ] || die "VAULT_ADDR unset — export VAULT_ADDR=http://127.0.0.1:8200"
|
||||||
[ -n "${VAULT_ADDR:-}" ] \
|
hvault_token_lookup >/dev/null || die "Vault auth probe failed — check VAULT_ADDR + VAULT_TOKEN"
|
||||||
|| die "VAULT_ADDR unset — e.g. export VAULT_ADDR=http://127.0.0.1:8200"
|
|
||||||
hvault_token_lookup >/dev/null \
|
|
||||||
|| die "Vault auth probe failed — check VAULT_ADDR + VAULT_TOKEN"
|
|
||||||
|
|
||||||
# ── Step 1/2: ensure kv/ mount exists and is KV v2 ───────────────────────────
|
# ── Step 1/2: ensure kv/ mount exists and is KV v2 ───────────────────────────
|
||||||
log "── Step 1/2: ensure ${KV_MOUNT}/ is KV v2 ──"
|
log "── Step 1/2: ensure ${KV_MOUNT}/ is KV v2 ──"
|
||||||
mounts_json="$(hvault_get_or_empty "sys/mounts")" \
|
export DRY_RUN
|
||||||
|| die "failed to list Vault mounts"
|
hvault_ensure_kv_v2 "$KV_MOUNT" "[vault-seed-woodpecker]" \
|
||||||
|
|| die "KV mount check failed"
|
||||||
mount_exists=false
|
|
||||||
if printf '%s' "$mounts_json" | jq -e --arg m "${KV_MOUNT}/" '.[$m]' >/dev/null 2>&1; then
|
|
||||||
mount_exists=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$mount_exists" = true ]; then
|
|
||||||
mount_type="$(printf '%s' "$mounts_json" \
|
|
||||||
| jq -r --arg m "${KV_MOUNT}/" '.[$m].type // ""')"
|
|
||||||
mount_version="$(printf '%s' "$mounts_json" \
|
|
||||||
| jq -r --arg m "${KV_MOUNT}/" '.[$m].options.version // "1"')"
|
|
||||||
if [ "$mount_type" != "kv" ]; then
|
|
||||||
die "${KV_MOUNT}/ is mounted as type='${mount_type}', expected 'kv' — refuse to re-mount"
|
|
||||||
fi
|
|
||||||
if [ "$mount_version" != "2" ]; then
|
|
||||||
die "${KV_MOUNT}/ is KV v${mount_version}, expected v2 — refuse to upgrade in place (manual fix required)"
|
|
||||||
fi
|
|
||||||
log "${KV_MOUNT}/ already mounted (kv v2) — skipping enable"
|
|
||||||
else
|
|
||||||
if [ "$DRY_RUN" -eq 1 ]; then
|
|
||||||
log "[dry-run] would enable ${KV_MOUNT}/ as kv v2"
|
|
||||||
else
|
|
||||||
payload="$(jq -n '{type:"kv",options:{version:"2"},description:"disinto shared KV v2 (S2.4)"}')"
|
|
||||||
_hvault_request POST "sys/mounts/${KV_MOUNT}" "$payload" >/dev/null \
|
|
||||||
|| die "failed to enable ${KV_MOUNT}/ as kv v2"
|
|
||||||
log "${KV_MOUNT}/ enabled as kv v2"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Step 2/2: seed agent_secret at kv/data/disinto/shared/woodpecker ─────────
|
# ── Step 2/2: seed agent_secret at kv/data/disinto/shared/woodpecker ─────────
|
||||||
log "── Step 2/2: seed ${KV_API_PATH} ──"
|
log "── Step 2/2: seed ${KV_API_PATH} ──"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue