diff --git a/scripts/enroll.sh b/scripts/enroll.sh index b665642..7a93563 100755 --- a/scripts/enroll.sh +++ b/scripts/enroll.sh @@ -78,7 +78,9 @@ gen_password() { head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 24; } write_enroll_nix() { local signing_pub="$1" harmonia_pub_key="$2" - cat > "${ENROLL_NIX}" < "${ENROLL_NIX}.tmp" < "${AGE_PUB}" info "Public key: ${AGE_PUBKEY}" @@ -247,9 +253,20 @@ else fi KATELLO_PASSWORD=$(cat "${KATELLO_ADMIN_PW_FILE}") +[[ -n "${KATELLO_PASSWORD}" ]] || \ + die "Katello password file is empty: ${KATELLO_ADMIN_PW_FILE} + Regenerate: rm -f ${KATELLO_ADMIN_PW_FILE} ${COMPOSE_ENV} && sudo bash scripts/enroll.sh" docker-compose -f "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up -d -info "Containers started. Waiting for foreman-installer (10-15 min)..." + +# Verify that compose actually started containers — `up -d` exits 0 even if +# containers crash-loop immediately. Count running containers for this project. +_KATELLO_RUNNING=$(docker ps --filter "name=katello" --format "{{.Names}}" 2>/dev/null | wc -l | tr -d ' ') +[[ "${_KATELLO_RUNNING}" -ge 1 ]] || \ + die "docker compose up -d returned 0 but no katello containers are running. + Diagnose: docker compose -f ${COMPOSE_FILE} logs + Then retry: sudo bash scripts/enroll.sh" +info "Containers started (${_KATELLO_RUNNING} katello container(s) running). Waiting for foreman-installer (10-15 min)..." info "Follow: docker compose -f ${COMPOSE_FILE} logs -f foreman-katello" MAX_WAIT="${FOREMAN_WAIT_TIMEOUT:-1800}"; ELAPSED=0; INTERVAL=15 @@ -306,7 +323,14 @@ if [[ "${_needs_encrypt}" -eq 1 ]]; then PLAINTEXT=$(mktemp /tmp/sourceos-secrets-XXXXXX.yaml) trap "rm -f ${PLAINTEXT}" EXIT printf 'katello-password: "%s"\n' "${KATELLO_PASSWORD}" > "${PLAINTEXT}" - SOPS_AGE_RECIPIENTS="${AGE_PUBKEY}" sops --encrypt "${PLAINTEXT}" > "${SECRETS_YAML}" + # Write to a temp file on the same filesystem so the final mv is atomic. + # A plain `> ${SECRETS_YAML}` would truncate the file before sops runs; + # if sops then fails the file is empty and subsequent re-runs skip encryption. + _SECRETS_TMP=$(mktemp "${SOURCEOS_DIR}/secrets-XXXXXX.yaml.tmp") + chmod 600 "${_SECRETS_TMP}" + trap "rm -f ${PLAINTEXT} ${_SECRETS_TMP}" EXIT + SOPS_AGE_RECIPIENTS="${AGE_PUBKEY}" sops --encrypt "${PLAINTEXT}" > "${_SECRETS_TMP}" + mv "${_SECRETS_TMP}" "${SECRETS_YAML}" chmod 600 "${SECRETS_YAML}" rm -f "${PLAINTEXT}"; trap - EXIT ok "Encrypted secrets written to ${SECRETS_YAML} ($(elapsed))" @@ -333,6 +357,9 @@ else fi HARMONIA_PUBKEY=$(cat "${HARMONIA_PUB}") +[[ -n "${HARMONIA_PUBKEY}" ]] || \ + die "harmonia public key file is empty or malformed: ${HARMONIA_PUB} + Delete both and re-run: rm -f ${HARMONIA_KEY} ${HARMONIA_PUB} && sudo bash scripts/enroll.sh" info "harmonia public key: ${HARMONIA_PUBKEY}" # ── Step 8: minisign key pair + nix-cache-info signature ────────────────────── @@ -361,13 +388,14 @@ SIGNING_PUBKEY=$(grep -v '^untrusted comment' "${MINISIGN_PUB}" | head -1) Delete and re-run: rm -f ${MINISIGN_PUB} ${MINISIGN_SEC} && sudo bash scripts/enroll.sh" info "Signing public key: ${SIGNING_PUBKEY}" -# Write nix-cache-info and sign it. nginx serves the .minisig file alongside -# harmonia so sourceos-syncd can verify the cache before pulling packages. -cat > "${MINISIGN_CACHE_INFO}" < "${MINISIGN_CACHE_INFO}.tmp" <