Reconcile development provider secrets
This commit is contained in:
parent
9e0d41eadf
commit
67747813cb
|
|
@ -669,6 +669,14 @@ that dump. After a successful rollout it also removes the obsolete chart Secret
|
|||
and only the local Helm history revisions that stored the former inline
|
||||
credential fields.
|
||||
|
||||
When the ignored mode-`0600` `.env` exists, every `kind-up.sh` run also
|
||||
reconciles a fixed allowlist of development provider settings into that same
|
||||
Secret: Google/GitHub sign-in, browser push, FCM delivery, Android App Links,
|
||||
sender identity, and support routing. It never prints their values and does not
|
||||
replace the independently generated database or application secrets. Empty
|
||||
allowlisted values remove stale provider settings so `.env` remains the single
|
||||
development source of truth.
|
||||
|
||||
Exercise the verified local rolling-update path without recreating PostGIS or
|
||||
the Secret:
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,16 @@ elif [ -z "$(kube --namespace "$NAMESPACE" get secret "$SECRET_NAME" -o jsonpath
|
|||
unset metrics_token
|
||||
fi
|
||||
|
||||
if [ -f "$ROOT/.env" ]; then
|
||||
KUBECTL_BIN="$ROOT/.tools/bin/kubectl" \
|
||||
KUBE_CONTEXT="kind-${CLUSTER}" \
|
||||
KUBE_NAMESPACE="$NAMESPACE" \
|
||||
KUBE_SECRET_NAME="$SECRET_NAME" \
|
||||
"$ROOT/scripts/sync-kind-runtime-secret.sh" "$ROOT/.env"
|
||||
else
|
||||
echo "No .env found; retained the existing optional kind runtime keys."
|
||||
fi
|
||||
|
||||
if [ -n "$legacy_backup" ]; then
|
||||
kube --namespace "$NAMESPACE" delete deployment postgis --wait=true
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -83,6 +83,39 @@ scan_image() {
|
|||
|
||||
scan_image_sequence=0
|
||||
|
||||
echo "Checking the development kind runtime Secret allowlist"
|
||||
kind_runtime_env="$scan_dir/kind-runtime.env"
|
||||
kind_runtime_rendered="$scan_dir/kind-runtime.rendered"
|
||||
cat >"$kind_runtime_env" <<'EOF'
|
||||
DATABASE_URL=must-not-be-copied
|
||||
GOOGLE_OAUTH_CLIENT_ID=quality-google-id
|
||||
GOOGLE_OAUTH_CLIENT_SECRET="quality-google-secret"
|
||||
GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-android-id
|
||||
WEB_PUSH_VAPID_PUBLIC_KEY=quality-vapid-public
|
||||
FCM_PROJECT_ID=
|
||||
EOF
|
||||
chmod 600 "$kind_runtime_env"
|
||||
./scripts/sync-kind-runtime-secret.sh \
|
||||
"$kind_runtime_env" --render-only "$kind_runtime_rendered" >/dev/null
|
||||
grep -Fx 'GOOGLE_OAUTH_CLIENT_ID=quality-google-id' \
|
||||
"$kind_runtime_rendered" >/dev/null
|
||||
grep -Fx 'GOOGLE_OAUTH_CLIENT_SECRET=quality-google-secret' \
|
||||
"$kind_runtime_rendered" >/dev/null
|
||||
grep -Fx 'GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS=quality-android-id' \
|
||||
"$kind_runtime_rendered" >/dev/null
|
||||
grep -Fx 'WEB_PUSH_VAPID_PUBLIC_KEY=quality-vapid-public' \
|
||||
"$kind_runtime_rendered" >/dev/null
|
||||
if grep -Eq '^(DATABASE_URL|FCM_PROJECT_ID)=' "$kind_runtime_rendered"; then
|
||||
echo "Kind runtime Secret renderer copied an unmanaged or empty value." >&2
|
||||
exit 1
|
||||
fi
|
||||
printf '%s\n' 'GOOGLE_OAUTH_CLIENT_ID=duplicate' >>"$kind_runtime_env"
|
||||
if ./scripts/sync-kind-runtime-secret.sh \
|
||||
"$kind_runtime_env" --render-only "$kind_runtime_rendered" >/dev/null 2>&1; then
|
||||
echo "Kind runtime Secret renderer accepted a duplicate managed key." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking shell scripts with ShellCheck 0.11.0"
|
||||
# Word splitting is intentional: find emits repository-controlled paths and
|
||||
# ShellCheck expects each file as a separate argument.
|
||||
|
|
|
|||
160
scripts/sync-kind-runtime-secret.sh
Executable file
160
scripts/sync-kind-runtime-secret.sh
Executable file
|
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
umask 077
|
||||
|
||||
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
env_file=${1:-"$ROOT/.env"}
|
||||
mode=${2:-}
|
||||
render_target=${3:-}
|
||||
|
||||
if [[ "$env_file" != /* ]]; then
|
||||
env_file="$ROOT/$env_file"
|
||||
fi
|
||||
|
||||
if [[ -n "$mode" && "$mode" != "--render-only" ]]; then
|
||||
echo "Usage: $0 [ENV_FILE] [--render-only OUTPUT_FILE]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ "$mode" == "--render-only" && -z "$render_target" ]]; then
|
||||
echo "Usage: $0 [ENV_FILE] [--render-only OUTPUT_FILE]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
[[ -f "$env_file" ]] || {
|
||||
echo "Development environment does not exist: $env_file" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
[[ "$(stat -c '%a' "$env_file")" == 600 ]] || {
|
||||
echo "Development environment must have mode 0600: $env_file" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
[[ "$(stat -c '%u' "$env_file")" == "$(id -u)" ]] || {
|
||||
echo "Development environment must be owned by the current user: $env_file" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
managed_keys=(
|
||||
ANDROID_APP_LINKS_PACKAGE_NAME
|
||||
ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS
|
||||
EMAIL_FROM_ADDRESS
|
||||
EMAIL_FROM_NAME
|
||||
FCM_PROJECT_ID
|
||||
FCM_SERVICE_ACCOUNT_JSON_BASE64
|
||||
GITHUB_OAUTH_CLIENT_ID
|
||||
GITHUB_OAUTH_CLIENT_SECRET
|
||||
GOOGLE_OAUTH_AUTHORIZED_PARTY_IDS
|
||||
GOOGLE_OAUTH_CLIENT_ID
|
||||
GOOGLE_OAUTH_CLIENT_SECRET
|
||||
SUPPORT_INBOX_ADDRESS
|
||||
SUPPORT_OPERATOR_EMAIL_MODE
|
||||
WEB_PUSH_VAPID_PRIVATE_KEY
|
||||
WEB_PUSH_VAPID_PUBLIC_KEY
|
||||
WEB_PUSH_VAPID_SUBJECT
|
||||
)
|
||||
|
||||
runtime_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-kind-runtime-secret.XXXXXX")
|
||||
cleanup() {
|
||||
status=$?
|
||||
trap - EXIT HUP INT TERM
|
||||
find "$runtime_dir" -xdev -depth -delete 2>/dev/null || true
|
||||
exit "$status"
|
||||
}
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
keys_file="$runtime_dir/managed-keys"
|
||||
printf '%s\n' "${managed_keys[@]}" >"$keys_file"
|
||||
filtered_env="$runtime_dir/runtime.env"
|
||||
|
||||
awk -F= '
|
||||
NR == FNR {
|
||||
managed[$1] = 1
|
||||
next
|
||||
}
|
||||
{
|
||||
key = $1
|
||||
if (!(key in managed)) next
|
||||
seen[key]++
|
||||
if (seen[key] > 1) {
|
||||
printf "Managed development key occurs more than once: %s\n", key > "/dev/stderr"
|
||||
invalid = 1
|
||||
next
|
||||
}
|
||||
value = substr($0, length(key) + 2)
|
||||
if ((value ~ /^".*"$/) || (value ~ /^\047.*\047$/)) {
|
||||
value = substr(value, 2, length(value) - 2)
|
||||
}
|
||||
if (length(value) > 0) print key "=" value
|
||||
}
|
||||
END { if (invalid) exit 1 }
|
||||
' "$keys_file" "$env_file" >"$filtered_env"
|
||||
chmod 600 "$filtered_env"
|
||||
|
||||
if [[ "$mode" == "--render-only" ]]; then
|
||||
case "$render_target" in
|
||||
/*) ;;
|
||||
*) render_target="$ROOT/$render_target" ;;
|
||||
esac
|
||||
install -m 600 "$filtered_env" "$render_target"
|
||||
echo "Rendered managed development runtime keys without printing their values."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
KUBECTL_BIN=${KUBECTL_BIN:-kubectl}
|
||||
KUBE_CONTEXT=${KUBE_CONTEXT:-kind-who-need-help}
|
||||
KUBE_NAMESPACE=${KUBE_NAMESPACE:-who-need-help}
|
||||
KUBE_SECRET_NAME=${KUBE_SECRET_NAME:-who-need-help-local}
|
||||
|
||||
existing_json="$runtime_dir/existing.json"
|
||||
extra_json="$runtime_dir/extra.json"
|
||||
desired_json="$runtime_dir/desired.json"
|
||||
observed_json="$runtime_dir/observed.json"
|
||||
|
||||
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||
get secret "$KUBE_SECRET_NAME" --output json >"$existing_json"
|
||||
|
||||
if [[ -s "$filtered_env" ]]; then
|
||||
"$KUBECTL_BIN" create secret generic "$KUBE_SECRET_NAME" \
|
||||
--namespace "$KUBE_NAMESPACE" \
|
||||
--from-env-file="$filtered_env" \
|
||||
--dry-run=client \
|
||||
--output json >"$extra_json"
|
||||
else
|
||||
printf '%s\n' '{"data":{}}' >"$extra_json"
|
||||
fi
|
||||
|
||||
jq --slurpfile extra "$extra_json" --rawfile managed "$keys_file" '
|
||||
($managed | split("\n") | map(select(length > 0))) as $managed_keys
|
||||
| .data = (
|
||||
((.data // {})
|
||||
| with_entries(select(.key as $key | ($managed_keys | index($key) | not))))
|
||||
+ ($extra[0].data // {})
|
||||
)
|
||||
| {
|
||||
apiVersion: "v1",
|
||||
kind: "Secret",
|
||||
metadata: {
|
||||
name: .metadata.name,
|
||||
namespace: .metadata.namespace,
|
||||
resourceVersion: .metadata.resourceVersion
|
||||
},
|
||||
type: (.type // "Opaque"),
|
||||
data: .data
|
||||
}
|
||||
' "$existing_json" >"$desired_json"
|
||||
|
||||
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||
replace --filename "$desired_json" >/dev/null
|
||||
"$KUBECTL_BIN" --context "$KUBE_CONTEXT" --namespace "$KUBE_NAMESPACE" \
|
||||
get secret "$KUBE_SECRET_NAME" --output json >"$observed_json"
|
||||
|
||||
jq --exit-status --slurpfile desired "$desired_json" \
|
||||
'.data == $desired[0].data' "$observed_json" >/dev/null || {
|
||||
echo "Kubernetes Secret verification did not match the desired key set." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
synced_count=$(wc -l <"$filtered_env" | tr -d '[:space:]')
|
||||
echo "Synchronized $synced_count managed development runtime keys without printing their values."
|
||||
Loading…
Reference in New Issue
Block a user