mirror of
https://github.com/Dvorinka/Productier.git
synced 2026-06-04 04:23:00 +00:00
first commit
This commit is contained in:
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
ENV_FILE="${1:-$ROOT_DIR/.env.production}"
|
||||
TIMEOUT_SECONDS="${OPS_SMOKE_TIMEOUT_SECONDS:-15}"
|
||||
INSECURE_TLS="${OPS_SMOKE_INSECURE_TLS:-0}"
|
||||
VERIFY_HTTP_REDIRECT="${VERIFY_HTTP_REDIRECT:-1}"
|
||||
|
||||
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
scripts/ops/smoke-prod.sh [env-file]
|
||||
|
||||
Examples:
|
||||
scripts/ops/smoke-prod.sh
|
||||
OPS_SMOKE_INSECURE_TLS=1 scripts/ops/smoke-prod.sh .env.production
|
||||
|
||||
Checks:
|
||||
- Public homepage responds with 2xx/3xx
|
||||
- /v1/health returns {"ok":true}
|
||||
- Security headers exist on public response
|
||||
- Optional HTTP->HTTPS redirect validation for PUBLIC_DOMAIN
|
||||
USAGE
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ENV_FILE" ]]; then
|
||||
echo "[error] env file not found: $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
node "$ROOT_DIR/scripts/check-production-env.mjs" "$ENV_FILE"
|
||||
|
||||
read_env_value() {
|
||||
local key="$1"
|
||||
local file="$2"
|
||||
local value
|
||||
value="$(
|
||||
awk -F '=' -v k="$key" '
|
||||
/^[[:space:]]*#/ { next }
|
||||
/^[[:space:]]*$/ { next }
|
||||
{
|
||||
line=$0
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
|
||||
if (index(line, "export ") == 1) {
|
||||
sub(/^export[[:space:]]+/, "", line)
|
||||
}
|
||||
split(line, parts, "=")
|
||||
if (parts[1] == k) {
|
||||
val=substr(line, index(line, "=") + 1)
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", val)
|
||||
if ((substr(val,1,1) == "\"" && substr(val,length(val),1) == "\"") || (substr(val,1,1) == "'"'"'" && substr(val,length(val),1) == "'"'"'")) {
|
||||
val=substr(val, 2, length(val)-2)
|
||||
}
|
||||
print val
|
||||
exit
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
)"
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
PUBLIC_URL="$(read_env_value PUBLIC_URL "$ENV_FILE")"
|
||||
PUBLIC_DOMAIN="$(read_env_value PUBLIC_DOMAIN "$ENV_FILE")"
|
||||
|
||||
if [[ -z "$PUBLIC_URL" || -z "$PUBLIC_DOMAIN" ]]; then
|
||||
echo "[error] missing PUBLIC_URL or PUBLIC_DOMAIN in $ENV_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl_args=(-fsS --max-time "$TIMEOUT_SECONDS")
|
||||
if [[ "$INSECURE_TLS" == "1" || "$INSECURE_TLS" == "true" ]]; then
|
||||
curl_args+=(-k)
|
||||
fi
|
||||
|
||||
echo "[step] checking homepage status..."
|
||||
home_status="$(curl "${curl_args[@]}" -o /dev/null -w '%{http_code}' "$PUBLIC_URL/")"
|
||||
if [[ ! "$home_status" =~ ^(2|3)[0-9]{2}$ ]]; then
|
||||
echo "[error] homepage status is $home_status (expected 2xx/3xx)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[step] checking API health payload..."
|
||||
health_payload="$(curl "${curl_args[@]}" "$PUBLIC_URL/v1/health")"
|
||||
node -e '
|
||||
const payload = JSON.parse(process.argv[1]);
|
||||
if (!payload || payload.ok !== true) {
|
||||
console.error("[error] /v1/health did not return ok=true");
|
||||
process.exit(1);
|
||||
}
|
||||
' "$health_payload"
|
||||
|
||||
echo "[step] checking security headers..."
|
||||
headers="$(curl "${curl_args[@]}" -D - -o /dev/null "$PUBLIC_URL/")"
|
||||
for expected_header in "strict-transport-security" "x-content-type-options" "x-frame-options" "referrer-policy"; do
|
||||
if ! printf '%s\n' "$headers" | tr '[:upper:]' '[:lower:]' | grep -q "^${expected_header}:"; then
|
||||
echo "[error] missing security header: $expected_header" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$VERIFY_HTTP_REDIRECT" == "1" || "$VERIFY_HTTP_REDIRECT" == "true" ]]; then
|
||||
echo "[step] checking HTTP->HTTPS redirect..."
|
||||
redirect_headers="$(curl -sS --max-time "$TIMEOUT_SECONDS" -D - -o /dev/null "http://$PUBLIC_DOMAIN/" || true)"
|
||||
redirect_status="$(printf '%s\n' "$redirect_headers" | awk 'NR==1 {print $2}')"
|
||||
redirect_location="$(printf '%s\n' "$redirect_headers" | awk 'BEGIN{IGNORECASE=1} /^Location:/ {sub(/\r$/, "", $2); print $2; exit}')"
|
||||
if [[ "$redirect_status" != "301" && "$redirect_status" != "302" && "$redirect_status" != "307" && "$redirect_status" != "308" ]]; then
|
||||
echo "[error] expected redirect status from http://$PUBLIC_DOMAIN but got '$redirect_status'" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$redirect_location" != https://"$PUBLIC_DOMAIN"* ]]; then
|
||||
echo "[error] expected redirect location to https://$PUBLIC_DOMAIN but got '$redirect_location'" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[ok] production smoke checks passed for $PUBLIC_URL"
|
||||
Reference in New Issue
Block a user