Add safe deployment revision promotion
Some checks are pending
Quality / full-local-gates (push) Waiting to run
Some checks are pending
Quality / full-local-gates (push) Waiting to run
This commit is contained in:
parent
d432368147
commit
209da8fb61
|
|
@ -83,6 +83,14 @@ TEST_GOOGLE_OAUTH_CLIENT_SECRET=YOUR_TEST_CLIENT_SECRET \
|
||||||
./scripts/deploy-up.sh .env
|
./scripts/deploy-up.sh .env
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For later test updates, check out the desired clean revision and update only
|
||||||
|
the image tags. Existing deployment secrets remain unchanged:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/set-deployment-revision.sh .env
|
||||||
|
./scripts/deploy-up.sh .env
|
||||||
|
```
|
||||||
|
|
||||||
Test always uses its own `who_need_help_test` PostGIS container/volume and
|
Test always uses its own `who_need_help_test` PostGIS container/volume and
|
||||||
Mailpit. Its messages cannot be sent by the production UniSender account.
|
Mailpit. Its messages cannot be sent by the production UniSender account.
|
||||||
|
|
||||||
|
|
@ -103,6 +111,15 @@ PRODUCTION_CODEX_SESSION_ID=YOUR_MAIN_CODEX_SESSION_ID \
|
||||||
./scripts/validate-production-env.sh .env whoneedhelp.com
|
./scripts/validate-production-env.sh .env whoneedhelp.com
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Promote the exact revision already verified in test by checking out that SHA in
|
||||||
|
the independent production clone, then update only the production image tags:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git checkout --detach <verified-test-sha>
|
||||||
|
./scripts/set-deployment-revision.sh .env
|
||||||
|
./scripts/deploy-up.sh .env
|
||||||
|
```
|
||||||
|
|
||||||
Before either public switch, prove cross-environment isolation without printing
|
Before either public switch, prove cross-environment isolation without printing
|
||||||
credentials:
|
credentials:
|
||||||
|
|
||||||
|
|
|
||||||
104
scripts/set-deployment-revision.sh
Executable file
104
scripts/set-deployment-revision.sh
Executable file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||||
|
env_file=${1:-"$ROOT/.env"}
|
||||||
|
|
||||||
|
case "$env_file" in
|
||||||
|
/*) ;;
|
||||||
|
*) env_file="$ROOT/$env_file" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ ! -f "$env_file" ]; then
|
||||||
|
echo "Deployment environment does not exist: $env_file" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(stat -c '%a' "$env_file")" != 600 ]; then
|
||||||
|
echo "Deployment environment must have mode 0600: $env_file" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$(git -C "$ROOT" status --porcelain --untracked-files=no)" ]; then
|
||||||
|
echo "Refusing to select a deployment revision from a dirty tracked checkout." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
read_env_value() {
|
||||||
|
key=$1
|
||||||
|
|
||||||
|
awk -v key="$key" '
|
||||||
|
index($0, key "=") == 1 {
|
||||||
|
print substr($0, length(key) + 2)
|
||||||
|
found = 1
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
END { if (!found) exit 1 }
|
||||||
|
' "$env_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_single_key() {
|
||||||
|
key=$1
|
||||||
|
count=$(awk -v key="$key" 'index($0, key "=") == 1 { count++ } END { print count + 0 }' "$env_file")
|
||||||
|
|
||||||
|
if [ "$count" -ne 1 ]; then
|
||||||
|
echo "$key must occur exactly once in $env_file." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment_env=$(read_env_value DEPLOYMENT_ENV)
|
||||||
|
domain=$(read_env_value PHX_HOST)
|
||||||
|
git_sha=$(git -C "$ROOT" rev-parse --short=12 HEAD)
|
||||||
|
|
||||||
|
case "$deployment_env" in
|
||||||
|
test)
|
||||||
|
required_keys='APP_IMAGE SOCKET_PROXY_IMAGE POSTGIS_IMAGE'
|
||||||
|
;;
|
||||||
|
production)
|
||||||
|
required_keys='APP_IMAGE SOCKET_PROXY_IMAGE POSTGIS_IMAGE CADDY_IMAGE'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "DEPLOYMENT_ENV must be test or production." >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for key in $required_keys; do
|
||||||
|
require_single_key "$key"
|
||||||
|
done
|
||||||
|
|
||||||
|
target_dir=$(dirname -- "$env_file")
|
||||||
|
tmp=$(mktemp "$target_dir/.deployment-revision.XXXXXX")
|
||||||
|
trap 'rm -f "$tmp"' EXIT HUP INT TERM
|
||||||
|
chmod 600 "$tmp"
|
||||||
|
|
||||||
|
DEPLOYMENT_ENV_VALUE=$deployment_env GIT_SHA_VALUE=$git_sha awk '
|
||||||
|
BEGIN {
|
||||||
|
prefix = ENVIRON["DEPLOYMENT_ENV_VALUE"]
|
||||||
|
sha = ENVIRON["GIT_SHA_VALUE"]
|
||||||
|
replacement["APP_IMAGE"] = "who-need-help:" prefix "-" sha
|
||||||
|
replacement["SOCKET_PROXY_IMAGE"] = "who-need-help:socket-proxy-" prefix "-" sha
|
||||||
|
replacement["POSTGIS_IMAGE"] = "who-need-help:postgis-" prefix "-" sha
|
||||||
|
if (prefix == "production") {
|
||||||
|
replacement["CADDY_IMAGE"] = "who-need-help:caddy-production-" sha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
separator = index($0, "=")
|
||||||
|
key = separator > 1 ? substr($0, 1, separator - 1) : ""
|
||||||
|
print (key in replacement) ? key "=" replacement[key] : $0
|
||||||
|
}
|
||||||
|
' "$env_file" >"$tmp"
|
||||||
|
|
||||||
|
mv "$tmp" "$env_file"
|
||||||
|
chmod 600 "$env_file"
|
||||||
|
trap - EXIT HUP INT TERM
|
||||||
|
|
||||||
|
case "$deployment_env" in
|
||||||
|
test) "$ROOT/scripts/validate-test-env.sh" "$env_file" "$domain" ;;
|
||||||
|
production) "$ROOT/scripts/validate-production-env.sh" "$env_file" "$domain" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "Selected $deployment_env deployment revision $git_sha without rotating secrets."
|
||||||
Loading…
Reference in New Issue
Block a user