feat: add production deployment handoff controls

This commit is contained in:
thanhnv
2026-07-10 16:41:14 +09:00
parent 7cea023dce
commit aa284e9bd4
14 changed files with 408 additions and 109 deletions
+5 -5
View File
@@ -117,7 +117,6 @@ npm run console:build # backend tsc + frontend typecheck/vite build
## Production-Like Smoke
```bash
docker compose -f docker-compose.control-panel.yml config
bash packages/casan-control-panel/scripts/local-prod-smoke.sh
```
@@ -131,12 +130,13 @@ asserts the Command Center returns all nine widgets with provenance envelopes an
therefore emits both `CP_LOCAL_SMOKE_PASS ...` and
`CP_MANAGED_SMOKE_PASS actor=oidc-ops role=org-admin widgets=9`.
Managed production readiness, once the host has real TLS files and an enterprise OIDC
env file:
Managed production readiness is intentionally a stronger, fail-closed contract: it
requires a DNS-matching TLS certificate, enterprise OIDC, non-dev Vault Transit,
an actual S3 Object Lock COMPLIANCE write, and CI-attested digest-pinned images.
Follow [the Linux handoff guide](../../infra/production/README.md), then run:
```bash
CASAN_CP_TLS_DIR=/opt/casan-control-panel/tls \
CASAN_CP_OAUTH_ENV=/opt/casan-control-panel/oauth2-proxy.env \
CASAN_CP_PROD_ENV=infra/production/casan-prod.env \
bash packages/casan-control-panel/scripts/prod-readiness-check.sh
```
@@ -2,91 +2,11 @@
set -euo pipefail
# Validate the managed-production Control Panel handoff without printing secrets.
# This does not contact the enterprise IdP; it proves the host has the required
# TLS/OIDC files and that values are not still local/mock placeholders.
# The harness preflight adds Vault Transit, S3 Object Lock and digest-pinned
# images to the original TLS/OIDC/nginx contract.
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
COMPOSE="${CASAN_CP_COMPOSE:-$ROOT/docker-compose.control-panel.yml}"
TLS_DIR="${CASAN_CP_TLS_DIR:-/opt/casan-control-panel/tls}"
OAUTH_ENV="${CASAN_CP_OAUTH_ENV:-/opt/casan-control-panel/oauth2-proxy.env}"
ENV_FILE="${CASAN_CP_PROD_ENV:-$ROOT/infra/production/casan-prod.env}"
fail() {
echo "CP_PROD_READINESS_FAIL $1"
exit 1
}
pass() {
echo "PASS: $1"
}
value_of() {
local key="$1"
sed -n -E "s/^${key}=//p" "$OAUTH_ENV" | tail -1
}
require_file() {
local path="$1"
[[ -f "$path" ]] || fail "missing_file path=$path"
[[ -s "$path" ]] || fail "empty_file path=$path"
}
require_env() {
local key="$1"
local value
value="$(value_of "$key")"
[[ -n "$value" ]] || fail "missing_env key=$key file=$OAUTH_ENV"
case "$value" in
*replace-with*|*example.com*|*localhost*|*127.0.0.1*|*idp:8080*)
fail "placeholder_env key=$key"
;;
esac
}
docker compose -f "$COMPOSE" config >/tmp/casan-cp-prod-compose-config.txt
pass "docker compose config"
require_file "$TLS_DIR/tls.crt"
require_file "$TLS_DIR/tls.key"
openssl x509 -in "$TLS_DIR/tls.crt" -noout >/dev/null
pass "tls certificate/key present"
require_file "$OAUTH_ENV"
for key in \
OAUTH2_PROXY_PROVIDER \
OAUTH2_PROXY_OIDC_ISSUER_URL \
OAUTH2_PROXY_CLIENT_ID \
OAUTH2_PROXY_CLIENT_SECRET \
OAUTH2_PROXY_COOKIE_SECRET \
OAUTH2_PROXY_REDIRECT_URL \
OAUTH2_PROXY_OIDC_GROUPS_CLAIM
do
require_env "$key"
done
[[ "$(value_of OAUTH2_PROXY_PROVIDER)" == "oidc" ]] || fail "provider_must_be_oidc"
[[ "$(value_of OAUTH2_PROXY_COOKIE_SECURE)" == "true" ]] || fail "cookie_secure_must_be_true"
[[ "$(value_of OAUTH2_PROXY_SET_XAUTHREQUEST)" == "true" ]] || fail "xauthrequest_must_be_true"
[[ "$(value_of OAUTH2_PROXY_PASS_ACCESS_TOKEN)" == "false" ]] || fail "pass_access_token_must_be_false"
[[ "$(value_of OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER)" == "false" ]] || fail "pass_authorization_header_must_be_false"
[[ "$(value_of OAUTH2_PROXY_OIDC_ISSUER_URL)" == https://* ]] || fail "issuer_must_be_https"
[[ "$(value_of OAUTH2_PROXY_REDIRECT_URL)" == https://*"/oauth2/callback" ]] || fail "redirect_url_must_be_https_callback"
[[ "$(value_of OAUTH2_PROXY_OIDC_GROUPS_CLAIM)" == "groups" ]] || fail "groups_claim_must_be_groups"
pass "oauth2-proxy env"
tmp="$(mktemp -d)"
cp "$TLS_DIR/tls.crt" "$tmp/tls.crt"
cp "$TLS_DIR/tls.key" "$tmp/tls.key"
docker run --rm \
--add-host oauth2-proxy:127.0.0.1 \
--add-host control-panel-api:127.0.0.1 \
-v "$ROOT/nginx/control-panel.conf:/etc/nginx/conf.d/default.conf:ro" \
-v "$tmp:/etc/nginx/tls:ro" \
nginx:1.27-alpine nginx -t >/tmp/casan-cp-prod-nginx-test.log 2>&1 || {
cat /tmp/casan-cp-prod-nginx-test.log
rm -rf "$tmp"
fail "nginx_config"
}
rm -rf "$tmp"
pass "nginx config"
echo "CP_PROD_READINESS_PASS compose=true tls=true oidc=true nginx=true"
bash "$ROOT/packages/casan-harness/scripts/bash/production-preflight.sh" "$ENV_FILE"
echo "CP_PROD_READINESS_PASS production_preflight=true"