Merge pull request 'fix: [nomad-step-2] S2-fix-F — wire tools/vault-seed-<svc>.sh into bin/disinto --with <svc> (#928)' (#929) from fix/issue-928 into main
This commit is contained in:
commit
8ad5aca6bb
2 changed files with 103 additions and 1 deletions
66
bin/disinto
66
bin/disinto
|
|
@ -783,9 +783,29 @@ _disinto_init_nomad() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$with_services" ]; then
|
if [ -n "$with_services" ]; then
|
||||||
|
# Vault seed plan (S2.6, #928): one line per service whose
|
||||||
|
# tools/vault-seed-<svc>.sh ships. Services without a seeder are
|
||||||
|
# silently skipped — the real-run loop below mirrors this,
|
||||||
|
# making `--with woodpecker` in Step 3 auto-invoke
|
||||||
|
# tools/vault-seed-woodpecker.sh once that file lands without
|
||||||
|
# any further change to bin/disinto.
|
||||||
|
local seed_hdr_printed=false
|
||||||
|
local IFS=','
|
||||||
|
for svc in $with_services; do
|
||||||
|
svc=$(echo "$svc" | xargs) # trim whitespace
|
||||||
|
local seed_script="${FACTORY_ROOT}/tools/vault-seed-${svc}.sh"
|
||||||
|
if [ -x "$seed_script" ]; then
|
||||||
|
if [ "$seed_hdr_printed" = false ]; then
|
||||||
|
echo "── Vault seed dry-run ─────────────────────────────────"
|
||||||
|
seed_hdr_printed=true
|
||||||
|
fi
|
||||||
|
echo "[seed] [dry-run] ${seed_script} --dry-run"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ "$seed_hdr_printed" = true ] && echo ""
|
||||||
|
|
||||||
echo "── Deploy services dry-run ────────────────────────────"
|
echo "── Deploy services dry-run ────────────────────────────"
|
||||||
echo "[deploy] services to deploy: ${with_services}"
|
echo "[deploy] services to deploy: ${with_services}"
|
||||||
local IFS=','
|
|
||||||
for svc in $with_services; do
|
for svc in $with_services; do
|
||||||
svc=$(echo "$svc" | xargs) # trim whitespace
|
svc=$(echo "$svc" | xargs) # trim whitespace
|
||||||
# Validate known services first
|
# Validate known services first
|
||||||
|
|
@ -893,6 +913,50 @@ _disinto_init_nomad() {
|
||||||
echo "[import] no --import-env/--import-sops — skipping; set them or seed kv/disinto/* manually before deploying secret-dependent services"
|
echo "[import] no --import-env/--import-sops — skipping; set them or seed kv/disinto/* manually before deploying secret-dependent services"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Seed Vault for services that ship their own seeder (S2.6, #928).
|
||||||
|
# Convention: tools/vault-seed-<svc>.sh — auto-invoked when --with <svc>
|
||||||
|
# is requested. Runs AFTER vault-import so that real imported values
|
||||||
|
# win over generated seeds when both are present; each seeder is
|
||||||
|
# idempotent on a per-key basis (see vault-seed-forgejo.sh's
|
||||||
|
# "missing → generate, present → unchanged" contract), so re-running
|
||||||
|
# init does not rotate existing keys. Services without a seeder are
|
||||||
|
# silently skipped — keeps this loop forward-compatible with Step 3+
|
||||||
|
# services that may ship their own seeder without touching bin/disinto.
|
||||||
|
#
|
||||||
|
# VAULT_ADDR is passed explicitly because cluster-up.sh writes the
|
||||||
|
# profile.d export *during* this same init run, so the current shell
|
||||||
|
# hasn't sourced it yet; sibling vault-* scripts (engines/policies/
|
||||||
|
# auth/import) default VAULT_ADDR internally via _hvault_default_env,
|
||||||
|
# but vault-seed-forgejo.sh requires the caller to set it.
|
||||||
|
#
|
||||||
|
# The non-root branch invokes the seeder as `sudo -n -- env VAR=val
|
||||||
|
# script` rather than `sudo -n VAR=val -- script`: sudo treats bare
|
||||||
|
# `VAR=val` args as sudoers env-assignments, which the default
|
||||||
|
# `env_reset=on` policy silently discards unless the variable is in
|
||||||
|
# `env_keep` (VAULT_ADDR is not). Using `env` as the actual command
|
||||||
|
# sets VAULT_ADDR in the child process regardless of sudoers policy.
|
||||||
|
if [ -n "$with_services" ]; then
|
||||||
|
local vault_addr="${VAULT_ADDR:-http://127.0.0.1:8200}"
|
||||||
|
local IFS=','
|
||||||
|
for svc in $with_services; do
|
||||||
|
svc=$(echo "$svc" | xargs) # trim whitespace
|
||||||
|
local seed_script="${FACTORY_ROOT}/tools/vault-seed-${svc}.sh"
|
||||||
|
if [ -x "$seed_script" ]; then
|
||||||
|
echo ""
|
||||||
|
echo "── Seeding Vault for ${svc} ───────────────────────────"
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
VAULT_ADDR="$vault_addr" "$seed_script" || exit $?
|
||||||
|
else
|
||||||
|
if ! command -v sudo >/dev/null 2>&1; then
|
||||||
|
echo "Error: vault-seed-${svc}.sh must run as root and sudo is not installed" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sudo -n -- env "VAULT_ADDR=$vault_addr" "$seed_script" || exit $?
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# Deploy services if requested
|
# Deploy services if requested
|
||||||
if [ -n "$with_services" ]; then
|
if [ -n "$with_services" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,44 @@ setup_file() {
|
||||||
[[ "$output" == *"[deploy] dry-run complete"* ]]
|
[[ "$output" == *"[deploy] dry-run complete"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# S2.6 / #928 — every --with <svc> that ships tools/vault-seed-<svc>.sh
|
||||||
|
# must auto-invoke the seeder before deploy.sh runs. forgejo is the
|
||||||
|
# only service with a seeder today, so the dry-run plan must include
|
||||||
|
# its seed line when --with forgejo is set. The seed block must also
|
||||||
|
# appear BEFORE the deploy block (seeded secrets must exist before
|
||||||
|
# nomad reads the template stanza) — pinned here by scanning output
|
||||||
|
# order. Services without a seeder (e.g. unknown hypothetical future
|
||||||
|
# ones) are silently skipped by the loop convention.
|
||||||
|
@test "disinto init --backend=nomad --with forgejo --dry-run prints seed plan before deploy plan" {
|
||||||
|
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --with forgejo --dry-run
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "$output" == *"Vault seed dry-run"* ]]
|
||||||
|
[[ "$output" == *"tools/vault-seed-forgejo.sh --dry-run"* ]]
|
||||||
|
# Order: seed header must appear before deploy header.
|
||||||
|
local seed_line deploy_line
|
||||||
|
seed_line=$(echo "$output" | grep -n "Vault seed dry-run" | head -1 | cut -d: -f1)
|
||||||
|
deploy_line=$(echo "$output" | grep -n "Deploy services dry-run" | head -1 | cut -d: -f1)
|
||||||
|
[ -n "$seed_line" ]
|
||||||
|
[ -n "$deploy_line" ]
|
||||||
|
[ "$seed_line" -lt "$deploy_line" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Regression guard (PR #929 review): `sudo -n VAR=val -- cmd` is subject
|
||||||
|
# to sudoers env_reset policy and silently drops VAULT_ADDR unless it's
|
||||||
|
# in env_keep (it isn't in default configs). vault-seed-forgejo.sh
|
||||||
|
# requires VAULT_ADDR and dies at its own precondition check if unset,
|
||||||
|
# so the non-root branch MUST invoke `sudo -n -- env VAR=val cmd` so
|
||||||
|
# that `env` sets the variable in the child process regardless of
|
||||||
|
# sudoers policy. This grep-level guard catches a revert to the unsafe
|
||||||
|
# form that silently broke non-root seed runs on a fresh LXC.
|
||||||
|
@test "seed loop invokes sudo via 'env VAR=val' (bypasses sudoers env_reset)" {
|
||||||
|
run grep -F 'sudo -n -- env "VAULT_ADDR=' "$DISINTO_BIN"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# Negative: no bare `sudo -n "VAR=val" --` form anywhere in the file.
|
||||||
|
run grep -F 'sudo -n "VAULT_ADDR=' "$DISINTO_BIN"
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
@test "disinto init --backend=nomad --with forgejo,forgejo --dry-run handles comma-separated services" {
|
@test "disinto init --backend=nomad --with forgejo,forgejo --dry-run handles comma-separated services" {
|
||||||
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --with forgejo,forgejo --dry-run
|
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --with forgejo,forgejo --dry-run
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue