teleo-infrastructure/deploy/sync-gcp-leoclean-runtime.sh
2026-07-15 04:40:26 +02:00

863 lines
35 KiB
Bash
Executable file

#!/usr/bin/env bash
# Deploy the source-controlled Cloud SQL bridge and non-secret service settings
# to the GCP parallel leoclean runtime. This does not create database users,
# read secret values, send Telegram messages, or promote Cloud SQL.
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
PROJECT="${PROJECT:-teleo-501523}"
ZONE="${ZONE:-europe-west6-a}"
INSTANCE="${INSTANCE:-teleo-prod-1}"
SERVICE="${SERVICE:-leoclean-gcp-prod-parallel.service}"
MERGED_REF="${MERGED_REF:-origin/main}"
REMOTE_RUNTIME_BIN="${REMOTE_RUNTIME_BIN:-/usr/local/libexec/livingip/leoclean-kb}"
SERVICE_PROFILE_BIN="${SERVICE_PROFILE_BIN:-/home/teleo/.hermes/profiles/leoclean/bin}"
SERVICE_PROFILE_ROOT="${SERVICE_PROFILE_ROOT:-/home/teleo/.hermes/profiles/leoclean}"
SERVICE_HERMES_ROOT="${SERVICE_HERMES_ROOT:-/home/teleo/.hermes}"
REMOTE_DROPIN_DIR="${REMOTE_DROPIN_DIR:-/etc/systemd/system/$SERVICE.d}"
EXPECTED_VM_SERVICE_ACCOUNT="${EXPECTED_VM_SERVICE_ACCOUNT:-sa-teleo-prod-vm@teleo-501523.iam.gserviceaccount.com}"
WRAPPER_REL="hermes-agent/leoclean-bin/teleo-kb"
TOOL_REL="hermes-agent/leoclean-bin/cloudsql_memory_tool.py"
PERMISSION_VERIFIER_REL="ops/verify_gcp_leoclean_runtime_permissions.py"
SERVICE_ENV_VERIFIER_REL="ops/verify_gcp_leoclean_service_environment.py"
DROPIN_REL="systemd/leoclean-gcp-prod-parallel-cloudsql.conf"
DROPIN_NAME="10-cloudsql-memory.conf"
DRY_RUN=false
RESTART=false
VERIFY_ONLY=false
PREFLIGHT_ONLY=false
usage() {
cat <<'USAGE'
Usage: deploy/sync-gcp-leoclean-runtime.sh [--dry-run] [--preflight-only] [--restart] [--verify-only]
The database role and scoped Secret Manager secret must exist before --restart.
This script deploys only the bridge files and non-secret systemd drop-in.
USAGE
}
for arg in "$@"; do
case "$arg" in
--dry-run) DRY_RUN=true ;;
--preflight-only) PREFLIGHT_ONLY=true ;;
--restart) RESTART=true ;;
--verify-only) VERIFY_ONLY=true ;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown arg: $arg" >&2
usage >&2
exit 64
;;
esac
done
if $PREFLIGHT_ONLY && $RESTART; then
echo "--preflight-only and --restart are mutually exclusive." >&2
exit 64
fi
if $VERIFY_ONLY && { $PREFLIGHT_ONLY || $RESTART; }; then
echo "--verify-only cannot be combined with --preflight-only or --restart." >&2
exit 64
fi
for path in \
"$WRAPPER_REL" \
"$TOOL_REL" \
"$PERMISSION_VERIFIER_REL" \
"$SERVICE_ENV_VERIFIER_REL" \
"$DROPIN_REL"; do
if [ ! -f "$REPO_ROOT/$path" ]; then
echo "Required source file is missing: $path" >&2
exit 66
fi
if [ -L "$REPO_ROOT/$path" ]; then
echo "Refusing symlinked runtime source file: $path" >&2
exit 65
fi
done
if ! grep -Fxq 'UnsetEnvironment=PGPASSWORD' "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in must explicitly unset inherited PGPASSWORD." >&2
exit 65
fi
if ! grep -Fxq 'Environment=TELEO_GCP_METADATA_ONLY=1' "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in must enforce metadata-only GCP credentials." >&2
exit 65
fi
if ! grep -Fxq "BindReadOnlyPaths=$REMOTE_RUNTIME_BIN:$SERVICE_PROFILE_BIN" "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in does not bind the root-controlled runtime into the service profile." >&2
exit 65
fi
if ! grep -Fxq "ReadOnlyPaths=$SERVICE_HERMES_ROOT" "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in does not protect the service-profile ancestor from replacement." >&2
exit 65
fi
if ! grep -Fxq "ReadWritePaths=$SERVICE_PROFILE_ROOT/state $SERVICE_PROFILE_ROOT/workspace" "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in does not limit service-profile writes to state and workspace." >&2
exit 65
fi
if ! grep -Fxq 'CapabilityBoundingSet=~CAP_SYS_ADMIN' "$REPO_ROOT/$DROPIN_REL"; then
echo "Runtime drop-in must remove CAP_SYS_ADMIN from the service." >&2
exit 65
fi
SOURCE_REVISION="$(git -C "$REPO_ROOT" rev-parse HEAD)"
if ! git -C "$REPO_ROOT" diff --quiet HEAD -- \
"$WRAPPER_REL" \
"$TOOL_REL" \
"$PERMISSION_VERIFIER_REL" \
"$SERVICE_ENV_VERIFIER_REL" \
"$DROPIN_REL"; then
echo "Refusing to deploy runtime files that do not match HEAD." >&2
exit 65
fi
if [ -n "$(git -C "$REPO_ROOT" ls-files --others --exclude-standard -- \
"$WRAPPER_REL" \
"$TOOL_REL" \
"$PERMISSION_VERIFIER_REL" \
"$SERVICE_ENV_VERIFIER_REL" \
"$DROPIN_REL")" ]; then
echo "Refusing to deploy untracked runtime files." >&2
exit 65
fi
if ! git -C "$REPO_ROOT" rev-parse --verify "$MERGED_REF^{commit}" >/dev/null 2>&1; then
echo "Merged reference is unavailable: $MERGED_REF" >&2
exit 69
fi
if ! git -C "$REPO_ROOT" merge-base --is-ancestor "$SOURCE_REVISION" "$MERGED_REF"; then
echo "Refusing to deploy unmerged revision $SOURCE_REVISION (not contained in $MERGED_REF)." >&2
exit 65
fi
WRAPPER_SHA="$(shasum -a 256 "$REPO_ROOT/$WRAPPER_REL" | awk '{print $1}')"
TOOL_SHA="$(shasum -a 256 "$REPO_ROOT/$TOOL_REL" | awk '{print $1}')"
PERMISSION_VERIFIER_SHA="$(shasum -a 256 "$REPO_ROOT/$PERMISSION_VERIFIER_REL" | awk '{print $1}')"
SERVICE_ENV_VERIFIER_SHA="$(shasum -a 256 "$REPO_ROOT/$SERVICE_ENV_VERIFIER_REL" | awk '{print $1}')"
DROPIN_SHA="$(shasum -a 256 "$REPO_ROOT/$DROPIN_REL" | awk '{print $1}')"
GCP_SSH=(
gcloud compute ssh "$INSTANCE"
--project="$PROJECT"
--zone="$ZONE"
--tunnel-through-iap
)
remote_helpers=$(cat <<'REMOTE'
assert_service_running() {
local active_state sub_state main_pid unit_user process_user
active_state="$(systemctl show "$SERVICE" --property=ActiveState --value)"
sub_state="$(systemctl show "$SERVICE" --property=SubState --value)"
if [ "$active_state" != "active" ] || [ "$sub_state" != "running" ]; then
echo "Service is not active/running: ActiveState=$active_state SubState=$sub_state" >&2
return 1
fi
main_pid="$(systemctl show "$SERVICE" --property=MainPID --value)"
unit_user="$(systemctl show "$SERVICE" --property=User --value)"
case "$main_pid" in
''|0|*[!0-9]*)
echo "Service has no live MainPID: $main_pid" >&2
return 1
;;
esac
if [ "$unit_user" != "teleo" ]; then
echo "Service unit user is not teleo: $unit_user" >&2
return 1
fi
process_user="$(ps -o user= -p "$main_pid" | awk '{print $1}')"
if [ "$process_user" != "teleo" ]; then
echo "Service process user is not teleo: $process_user" >&2
return 1
fi
}
assert_unit_configuration() {
local require_reviewed="${1:-true}"
local dropin_path dropin_name dropin_paths environment_files reviewed_dropin_seen=false
dropin_paths="$(systemctl show "$SERVICE" --property=DropInPaths --value)"
environment_files="$(systemctl show "$SERVICE" --property=EnvironmentFiles --value)"
if [ -n "$environment_files" ]; then
echo "Service has an effective EnvironmentFile, which is not allowed for the scoped runtime." >&2
return 1
fi
for dropin_path in $dropin_paths; do
if [ "$dropin_path" = "$REMOTE_DROPIN_DIR/$DROPIN_NAME" ]; then
reviewed_dropin_seen=true
continue
fi
dropin_name="${dropin_path##*/}"
if [[ "$dropin_name" > "$DROPIN_NAME" ]]; then
echo "Service has a later drop-in than the reviewed Cloud SQL configuration: $dropin_name" >&2
return 1
fi
done
if [ "$require_reviewed" = true ] && [ "$reviewed_dropin_seen" != true ]; then
echo "Service does not load the reviewed Cloud SQL drop-in." >&2
return 1
fi
}
assert_runtime_environment() {
local verifier_path="$1" require_reviewed="${2:-true}" main_pid
main_pid="$(systemctl show "$SERVICE" --property=MainPID --value)"
sudo /usr/bin/python3 "$verifier_path" --pid "$main_pid"
assert_unit_configuration "$require_reviewed"
}
assert_attached_service_account() {
local metadata_email
metadata_email="$(
sudo -n -u teleo env -i \
HOME=/home/teleo \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
/usr/bin/curl -q --noproxy '*' --proto '=http' --max-time 10 --fail --silent --show-error \
--header 'Metadata-Flavor: Google' \
'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email'
)"
if [ "$metadata_email" != "$EXPECTED_VM_SERVICE_ACCOUNT" ]; then
echo "Attached VM service account mismatch: $metadata_email" >&2
return 1
fi
echo "ATTACHED_VM_SERVICE_ACCOUNT=$metadata_email"
}
assert_administrator_secret_denied() {
local main_pid
main_pid="$(systemctl show "$SERVICE" --property=MainPID --value)"
sudo nsenter -t "$main_pid" -m --env -- \
/usr/bin/setpriv \
--reuid=teleo \
--regid=teleo \
--init-groups \
--no-new-privs \
/usr/bin/python3 - "$PROJECT" "$EXPECTED_VM_SERVICE_ACCOUNT" <<'PY'
import json
import sys
import urllib.error
import urllib.parse
import urllib.request
project, expected_email = sys.argv[1:]
metadata_headers = {"Metadata-Flavor": "Google"}
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
def metadata(path: str) -> bytes:
request = urllib.request.Request(
"http://169.254.169.254/computeMetadata/v1/" + path,
headers=metadata_headers,
)
with opener.open(request, timeout=10) as response:
return response.read(65536)
try:
email = metadata("instance/service-accounts/default/email").decode("utf-8").strip()
if email != expected_email:
raise RuntimeError
token_payload = json.loads(metadata("instance/service-accounts/default/token"))
token = token_payload.get("access_token")
if token_payload.get("token_type") != "Bearer" or not isinstance(token, str) or not token:
raise RuntimeError
secret = urllib.parse.quote("gcp-teleo-pgvector-standby-postgres-password", safe="")
url = f"https://secretmanager.googleapis.com/v1/projects/{project}/secrets/{secret}/versions/latest:access"
request = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
try:
response = opener.open(request, timeout=10)
except urllib.error.HTTPError as error:
body = error.read(65536)
parsed = json.loads(body)
detail = parsed.get("error", {})
message = str(detail.get("message", "")).lower()
if error.code != 403 or detail.get("status") != "PERMISSION_DENIED":
raise RuntimeError from None
if "secretmanager.versions.access" not in message:
raise RuntimeError
else:
response.close()
raise RuntimeError
except Exception:
raise SystemExit("administrator secret was not the exact expected metadata-identity IAM denial") from None
print(json.dumps({
"administrator_secret_access": "iam_permission_denied",
"credential_context": "systemd_main_pid_environment",
"identity_source": "gce_metadata",
"stdout_discarded": True,
}, sort_keys=True))
PY
}
run_scoped_status() {
local phase="$1" tool_path="$2"
assert_attached_service_account
echo "SCOPED_STATUS phase=$phase user=teleo database=teleo_canonical"
sudo -n -u teleo env -i \
HOME=/home/teleo \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
TELEO_GCP_PROJECT=teleo-501523 \
TELEO_GCP_METADATA_ONLY=1 \
TELEO_CLOUDSQL_HOST=10.61.0.3 \
TELEO_CLOUDSQL_PORT=5432 \
TELEO_CLOUDSQL_DB=teleo_canonical \
TELEO_CANONICAL_CLOUDSQL_DB=teleo_canonical \
TELEO_CLOUDSQL_USER=leoclean_kb_runtime \
TELEO_CLOUDSQL_PASSWORD_SECRET=gcp-teleo-pgvector-standby-leoclean-kb-runtime-password \
TELEO_CLOUDSQL_ENABLE_AUDIT_FALLBACK=0 \
/usr/bin/python3 "$tool_path" status --format json --redacted
}
run_service_wrapper_status() {
local phase="$1" main_pid
assert_attached_service_account
main_pid="$(systemctl show "$SERVICE" --property=MainPID --value)"
echo "SCOPED_WRAPPER_STATUS phase=$phase user=teleo database=teleo_canonical"
# --env imports the target MainPID's effective /proc environment. setpriv
# drops back to the service's Unix identity without sudo resetting that env.
sudo nsenter -t "$main_pid" -m --env -- \
/usr/bin/setpriv \
--reuid=teleo \
--regid=teleo \
--init-groups \
--no-new-privs \
"$SERVICE_PROFILE_BIN/teleo-kb" status --format json --redacted
}
service_fingerprint() {
printf '%s|%s|%s|%s' \
"$(systemctl show "$SERVICE" --property=ActiveState --value)" \
"$(systemctl show "$SERVICE" --property=SubState --value)" \
"$(systemctl show "$SERVICE" --property=MainPID --value)" \
"$(systemctl show "$SERVICE" --property=NRestarts --value)"
}
assert_service_fingerprint() {
local expected="$1" actual
actual="$(service_fingerprint)"
if [ "$actual" != "$expected" ]; then
echo "Service state changed during the read-only preflight." >&2
return 1
fi
echo "PREFLIGHT_SERVICE_UNCHANGED fingerprint=$actual"
}
run_permission_verifier() {
local phase="$1" verifier_path="$2" receipt_path="$3" receipt_dir run_id receipt_state
run_id="$(date -u +%Y%m%d%H%M%S)-$phase"
receipt_dir="$(dirname "$receipt_path")"
sudo -n -u teleo mkdir -p -- "$receipt_dir"
sudo -n -u teleo chmod 0700 "$receipt_dir"
echo "NEGATIVE_PERMISSION_RECEIPT phase=$phase run_id=$run_id"
sudo -n -u teleo env -i \
HOME=/home/teleo \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
/usr/bin/python3 "$verifier_path" --run-id "$run_id" --output "$receipt_path"
receipt_state="$(sudo stat -c '%U:%G:%a' "$receipt_path")"
if [ "$receipt_state" != "teleo:teleo:600" ]; then
echo "Permission receipt has unexpected ownership or mode: $receipt_state" >&2
return 1
fi
sudo /usr/bin/python3 - "$receipt_path" <<'PY'
import json
import sys
from pathlib import Path
receipt = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
expected = {
"artifact": "gcp_leoclean_runtime_permissions",
"current_tier": "T3_live_readonly",
"mode": "live_private_gcp_staging",
"required_tier": "T3_live_readonly",
"status": "pass",
}
mismatched = sorted(key for key, value in expected.items() if receipt.get(key) != value)
if mismatched:
raise SystemExit("permission receipt contract mismatch: " + ",".join(mismatched))
print(json.dumps({"permission_receipt": "validated", "validated_fields": sorted(expected)}, sort_keys=True))
PY
}
assert_installed_files() {
local wrapper tool permission_verifier service_env_verifier dropin revision executable_dir protected_dir protected_file
wrapper="$REMOTE_RUNTIME_BIN/teleo-kb"
tool="$REMOTE_RUNTIME_BIN/cloudsql_memory_tool.py"
permission_verifier="$REMOTE_RUNTIME_BIN/verify_gcp_leoclean_runtime_permissions.py"
service_env_verifier="$REMOTE_RUNTIME_BIN/verify_gcp_leoclean_service_environment.py"
dropin="$REMOTE_DROPIN_DIR/$DROPIN_NAME"
revision="$REMOTE_RUNTIME_BIN/.livingip-runtime-revision"
test "$(sudo sha256sum "$wrapper" | awk '{print $1}')" = "$WRAPPER_SHA"
test "$(sudo sha256sum "$tool" | awk '{print $1}')" = "$TOOL_SHA"
test "$(sudo sha256sum "$permission_verifier" | awk '{print $1}')" = "$PERMISSION_VERIFIER_SHA"
test "$(sudo sha256sum "$service_env_verifier" | awk '{print $1}')" = "$SERVICE_ENV_VERIFIER_SHA"
test "$(sudo sha256sum "$dropin" | awk '{print $1}')" = "$DROPIN_SHA"
test "$(sudo stat -c '%U:%G:%a' "$REMOTE_RUNTIME_BIN")" = "root:root:755"
test "$(sudo stat -c '%U:%G:%a' "$wrapper")" = "root:root:755"
test "$(sudo stat -c '%U:%G:%a' "$tool")" = "root:root:755"
test "$(sudo stat -c '%U:%G:%a' "$permission_verifier")" = "root:root:755"
test "$(sudo stat -c '%U:%G:%a' "$service_env_verifier")" = "root:root:755"
test "$(sudo stat -c '%U:%G:%a' "$revision")" = "root:root:644"
test "$(sudo stat -c '%U:%G:%a' "$dropin")" = "root:root:644"
test "$(sudo cat "$revision")" = "$SOURCE_REVISION"
for protected_dir in \
/usr \
/usr/local \
/usr/local/libexec \
/usr/local/libexec/livingip \
"$REMOTE_RUNTIME_BIN" \
"$REMOTE_DROPIN_DIR"; do
sudo test -d "$protected_dir"
sudo test ! -L "$protected_dir"
test "$(sudo stat -c '%U:%G' "$protected_dir")" = "root:root"
sudo -n -u teleo test ! -w "$protected_dir"
done
for protected_file in \
"$wrapper" \
"$tool" \
"$permission_verifier" \
"$service_env_verifier" \
"$revision" \
"$dropin"; do
sudo test -f "$protected_file"
sudo test ! -L "$protected_file"
sudo -n -u teleo test ! -w "$protected_file"
done
for executable_dir in \
/usr/local/sbin \
/usr/local/bin \
/usr/sbin \
/usr/bin \
/sbin \
/bin; do
sudo test -d "$executable_dir"
test "$(sudo stat -Lc '%U:%G' "$executable_dir")" = "root:root"
sudo -n -u teleo test ! -w "$executable_dir"
done
for protected_file in /bin/bash /usr/bin/curl /usr/bin/python3; do
sudo test -x "$protected_file"
test "$(sudo stat -Lc '%U:%G' "$protected_file")" = "root:root"
sudo -n -u teleo test ! -w "$protected_file"
done
sudo grep -Fx 'UnsetEnvironment=PGPASSWORD' "$dropin"
sudo grep -E '^Environment=TELEO_(KB_MODE|GCP_PROJECT|GCP_METADATA_ONLY|CLOUDSQL_|CANONICAL_CLOUDSQL_DB)' "$dropin"
sudo grep -Fx "ReadOnlyPaths=$SERVICE_HERMES_ROOT" "$dropin"
sudo grep -Fx "ReadWritePaths=$SERVICE_PROFILE_ROOT/state $SERVICE_PROFILE_ROOT/workspace" "$dropin"
sudo grep -Fx "BindReadOnlyPaths=$REMOTE_RUNTIME_BIN:$SERVICE_PROFILE_BIN" "$dropin"
sudo grep -Fx 'CapabilityBoundingSet=~CAP_SYS_ADMIN' "$dropin"
}
assert_deployed_files() {
local main_pid namespace_state source_state mount_state
local hermes_mount_state state_mount_state workspace_mount_state capability_set
assert_installed_files
main_pid="$(systemctl show "$SERVICE" --property=MainPID --value)"
source_state="$(stat -Lc '%d:%i' "$REMOTE_RUNTIME_BIN")"
namespace_state="$(sudo nsenter -t "$main_pid" -m -- stat -Lc '%d:%i' "$SERVICE_PROFILE_BIN")"
if [ "$namespace_state" != "$source_state" ]; then
echo "Service namespace does not bind the reviewed runtime directory." >&2
return 1
fi
mount_state="$(sudo nsenter -t "$main_pid" -m -- findmnt -T "$SERVICE_PROFILE_BIN" -n -o OPTIONS)"
case ",$mount_state," in
*,ro,*) ;;
*)
echo "Service runtime bind is not read-only." >&2
return 1
;;
esac
hermes_mount_state="$(sudo nsenter -t "$main_pid" -m -- findmnt -M "$SERVICE_HERMES_ROOT" -n -o OPTIONS)"
state_mount_state="$(sudo nsenter -t "$main_pid" -m -- findmnt -M "$SERVICE_PROFILE_ROOT/state" -n -o OPTIONS)"
workspace_mount_state="$(sudo nsenter -t "$main_pid" -m -- findmnt -M "$SERVICE_PROFILE_ROOT/workspace" -n -o OPTIONS)"
case ",$hermes_mount_state," in
*,ro,*) ;;
*)
echo "Service .hermes ancestor mount is not read-only." >&2
return 1
;;
esac
case ",$state_mount_state," in
*,rw,*) ;;
*)
echo "Service state mount is not writable." >&2
return 1
;;
esac
case ",$workspace_mount_state," in
*,rw,*) ;;
*)
echo "Service workspace mount is not writable." >&2
return 1
;;
esac
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test ! -w /home
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test ! -w "$SERVICE_HERMES_ROOT"
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test ! -w "$SERVICE_HERMES_ROOT/profiles"
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test ! -w "$SERVICE_PROFILE_ROOT"
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test ! -w "$SERVICE_PROFILE_BIN"
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test -w "$SERVICE_PROFILE_ROOT/state"
sudo nsenter -t "$main_pid" -m -- /usr/bin/sudo -n -u teleo test -w "$SERVICE_PROFILE_ROOT/workspace"
capability_set="$(systemctl show "$SERVICE" --property=CapabilityBoundingSet --value)"
if printf '%s\n' "$capability_set" | grep -Eqi '(^|[[:space:]])cap_sys_admin([[:space:]]|$)'; then
echo "Service capability bounding set still contains CAP_SYS_ADMIN." >&2
return 1
fi
test "$(sudo nsenter -t "$main_pid" -m -- sha256sum "$SERVICE_PROFILE_BIN/teleo-kb" | awk '{print $1}')" = "$WRAPPER_SHA"
test "$(sudo nsenter -t "$main_pid" -m -- sha256sum "$SERVICE_PROFILE_BIN/cloudsql_memory_tool.py" | awk '{print $1}')" = "$TOOL_SHA"
test "$(sudo nsenter -t "$main_pid" -m -- sha256sum "$SERVICE_PROFILE_BIN/verify_gcp_leoclean_runtime_permissions.py" | awk '{print $1}')" = "$PERMISSION_VERIFIER_SHA"
test "$(sudo nsenter -t "$main_pid" -m -- sha256sum "$SERVICE_PROFILE_BIN/verify_gcp_leoclean_service_environment.py" | awk '{print $1}')" = "$SERVICE_ENV_VERIFIER_SHA"
}
REMOTE
)
printf -v verify_context \
'PROJECT=%q\nSERVICE=%q\nEXPECTED_VM_SERVICE_ACCOUNT=%q\nREMOTE_RUNTIME_BIN=%q\nSERVICE_PROFILE_BIN=%q\nSERVICE_PROFILE_ROOT=%q\nSERVICE_HERMES_ROOT=%q\nREMOTE_DROPIN_DIR=%q\nDROPIN_NAME=%q\nWRAPPER_SHA=%q\nTOOL_SHA=%q\nPERMISSION_VERIFIER_SHA=%q\nSERVICE_ENV_VERIFIER_SHA=%q\nDROPIN_SHA=%q\nSOURCE_REVISION=%q\n' \
"$PROJECT" "$SERVICE" "$EXPECTED_VM_SERVICE_ACCOUNT" "$REMOTE_RUNTIME_BIN" "$SERVICE_PROFILE_BIN" "$SERVICE_PROFILE_ROOT" "$SERVICE_HERMES_ROOT" \
"$REMOTE_DROPIN_DIR" "$DROPIN_NAME" \
"$WRAPPER_SHA" "$TOOL_SHA" "$PERMISSION_VERIFIER_SHA" "$SERVICE_ENV_VERIFIER_SHA" "$DROPIN_SHA" "$SOURCE_REVISION"
verify_body=$(cat <<'REMOTE'
set -euo pipefail
verification_tmp="$(mktemp -d /tmp/teleo-gcp-runtime-verify.XXXXXX)"
sudo chown teleo:teleo "$verification_tmp"
sudo chmod 0700 "$verification_tmp"
cleanup_verification() { sudo rm -rf -- "$verification_tmp"; }
trap cleanup_verification EXIT
assert_deployed_files
assert_service_running
assert_runtime_environment "$REMOTE_RUNTIME_BIN/verify_gcp_leoclean_service_environment.py"
run_service_wrapper_status verify
assert_administrator_secret_denied
run_permission_verifier verify "$REMOTE_RUNTIME_BIN/verify_gcp_leoclean_runtime_permissions.py" "$verification_tmp/permission-receipt.json"
systemctl show "$SERVICE" -p ActiveState -p SubState -p NRestarts -p MainPID -p User --no-pager
REMOTE
)
verify_command="${verify_context}${remote_helpers}"$'\n'"${verify_body}"
if $DRY_RUN; then
echo "DRY RUN: project=$PROJECT zone=$ZONE instance=$INSTANCE service=$SERVICE preflight_only=$PREFLIGHT_ONLY restart=$RESTART"
echo "DRY RUN: revision=$SOURCE_REVISION wrapper_sha256=$WRAPPER_SHA tool_sha256=$TOOL_SHA permission_verifier_sha256=$PERMISSION_VERIFIER_SHA service_env_verifier_sha256=$SERVICE_ENV_VERIFIER_SHA dropin_sha256=$DROPIN_SHA"
exit 0
fi
if $VERIFY_ONLY; then
"${GCP_SSH[@]}" --command="$verify_command"
exit 0
fi
if ! $RESTART && ! $PREFLIGHT_ONLY; then
echo "Refusing to install runtime files without --restart; use --dry-run, --preflight-only, or --verify-only for read-only work." >&2
exit 64
fi
printf -v sync_context \
'PROJECT=%q\nSERVICE=%q\nEXPECTED_VM_SERVICE_ACCOUNT=%q\nREMOTE_RUNTIME_BIN=%q\nSERVICE_PROFILE_BIN=%q\nSERVICE_PROFILE_ROOT=%q\nSERVICE_HERMES_ROOT=%q\nREMOTE_DROPIN_DIR=%q\nDROPIN_NAME=%q\nWRAPPER_SHA=%q\nTOOL_SHA=%q\nPERMISSION_VERIFIER_SHA=%q\nSERVICE_ENV_VERIFIER_SHA=%q\nDROPIN_SHA=%q\nWRAPPER_REL=%q\nTOOL_REL=%q\nPERMISSION_VERIFIER_REL=%q\nSERVICE_ENV_VERIFIER_REL=%q\nDROPIN_REL=%q\nSOURCE_REVISION=%q\nPREFLIGHT_ONLY=%q\n' \
"$PROJECT" "$SERVICE" "$EXPECTED_VM_SERVICE_ACCOUNT" "$REMOTE_RUNTIME_BIN" "$SERVICE_PROFILE_BIN" "$SERVICE_PROFILE_ROOT" "$SERVICE_HERMES_ROOT" \
"$REMOTE_DROPIN_DIR" "$DROPIN_NAME" \
"$WRAPPER_SHA" "$TOOL_SHA" "$PERMISSION_VERIFIER_SHA" "$SERVICE_ENV_VERIFIER_SHA" "$DROPIN_SHA" \
"$WRAPPER_REL" "$TOOL_REL" "$PERMISSION_VERIFIER_REL" "$SERVICE_ENV_VERIFIER_REL" "$DROPIN_REL" "$SOURCE_REVISION" "$PREFLIGHT_ONLY"
sync_body=$(cat <<'REMOTE'
set -euo pipefail
remote_tmp="$(sudo mktemp -d /var/tmp/teleo-gcp-leoclean-runtime.XXXXXX)"
runtime_bin="$REMOTE_RUNTIME_BIN"
runtime_parent="$(dirname "$runtime_bin")"
runtime_grandparent="$(dirname "$runtime_parent")"
runtime_anchor="$(dirname "$runtime_grandparent")"
dropin_dir="$REMOTE_DROPIN_DIR"
dropin_parent="$(dirname "$dropin_dir")"
payload_dir="$remote_tmp/payload"
backup_dir="$remote_tmp/backup"
work_dir="$remote_tmp/work"
wrapper_stage="$runtime_bin/.teleo-kb.livingip-new.$$"
tool_stage="$runtime_bin/.cloudsql-memory-tool.livingip-new.$$"
permission_verifier_stage="$runtime_bin/.runtime-permission-verifier.livingip-new.$$"
service_env_verifier_stage="$runtime_bin/.service-environment-verifier.livingip-new.$$"
revision_stage="$runtime_bin/.livingip-runtime-revision.livingip-new.$$"
dropin_stage="$dropin_dir/.${DROPIN_NAME}.livingip-new.$$"
mutation_started=false
assert_existing_root_directory() {
local target="$1"
if sudo test -e "$target" || sudo test -L "$target"; then
sudo test -d "$target"
sudo test ! -L "$target"
test "$(sudo stat -c '%U:%G' "$target")" = "root:root"
sudo -n -u teleo test ! -w "$target"
fi
}
assert_existing_root_file() {
local target="$1"
if sudo test -e "$target" || sudo test -L "$target"; then
sudo test -f "$target"
sudo test ! -L "$target"
test "$(sudo stat -c '%U:%G' "$target")" = "root:root"
sudo -n -u teleo test ! -w "$target"
fi
}
backup_path() {
local target="$1" name="$2"
if sudo test -e "$target"; then
sudo cp -a -- "$target" "$backup_dir/$name"
sudo touch "$backup_dir/$name.present"
fi
}
backup_directory_state() {
local target="$1" name="$2"
if sudo test -d "$target"; then
sudo stat -c '%u %g %a' "$target" | sudo tee "$backup_dir/$name.metadata" >/dev/null
sudo touch "$backup_dir/$name.present"
fi
}
restore_directory_state() {
local target="$1" name="$2" uid gid mode
if sudo test -f "$backup_dir/$name.present"; then
read -r uid gid mode <<<"$(sudo cat "$backup_dir/$name.metadata")"
sudo chown "$uid:$gid" "$target"
sudo chmod "$mode" "$target"
elif sudo test -d "$target"; then
sudo rmdir -- "$target"
fi
}
restore_path() {
local target="$1" name="$2" restore_rc=0 restore_tmp
if sudo test -f "$backup_dir/$name.present"; then
restore_tmp="${target}.livingip-rollback.$$"
sudo rm -f -- "$restore_tmp" || restore_rc=1
if sudo cp -a -- "$backup_dir/$name" "$restore_tmp"; then
sudo mv -f -- "$restore_tmp" "$target" || restore_rc=1
else
restore_rc=1
fi
sudo rm -f -- "$restore_tmp" || restore_rc=1
else
sudo rm -f -- "$target" || restore_rc=1
fi
return "$restore_rc"
}
validate_restored_path() {
local target="$1" name="$2"
if sudo test -f "$backup_dir/$name.present"; then
sudo test -f "$target"
sudo test ! -L "$target"
sudo cmp -s -- "$backup_dir/$name" "$target"
test "$(sudo stat -c '%u:%g:%a' "$target")" = \
"$(sudo stat -c '%u:%g:%a' "$backup_dir/$name")"
else
sudo test ! -e "$target"
sudo test ! -L "$target"
fi
}
validate_restored_directory() {
local target="$1" name="$2" expected_state
if sudo test -f "$backup_dir/$name.present"; then
expected_state="$(sudo cat "$backup_dir/$name.metadata" | tr ' ' ':')"
sudo test -d "$target"
sudo test ! -L "$target"
test "$(sudo stat -c '%u:%g:%a' "$target")" = "$expected_state"
else
sudo test ! -e "$target"
sudo test ! -L "$target"
fi
}
rollback_runtime() {
local rollback_rc=0
echo "Deployment failed; restoring the complete previous runtime set." >&2
sudo systemctl stop "$SERVICE" || rollback_rc=1
restore_path "$runtime_bin/teleo-kb" wrapper || rollback_rc=1
restore_path "$runtime_bin/cloudsql_memory_tool.py" tool || rollback_rc=1
restore_path "$runtime_bin/verify_gcp_leoclean_runtime_permissions.py" verifier || rollback_rc=1
restore_path "$runtime_bin/verify_gcp_leoclean_service_environment.py" service_env_verifier || rollback_rc=1
restore_path "$dropin_dir/$DROPIN_NAME" dropin || rollback_rc=1
restore_path "$runtime_bin/.livingip-runtime-revision" revision || rollback_rc=1
restore_directory_state "$runtime_bin" runtime_bin || rollback_rc=1
restore_directory_state "$runtime_parent" runtime_parent || rollback_rc=1
restore_directory_state "$runtime_grandparent" runtime_grandparent || rollback_rc=1
restore_directory_state "$dropin_dir" dropin_dir || rollback_rc=1
if [ "$rollback_rc" -eq 0 ]; then
validate_restored_path "$runtime_bin/teleo-kb" wrapper || rollback_rc=1
validate_restored_path "$runtime_bin/cloudsql_memory_tool.py" tool || rollback_rc=1
validate_restored_path "$runtime_bin/verify_gcp_leoclean_runtime_permissions.py" verifier || rollback_rc=1
validate_restored_path "$runtime_bin/verify_gcp_leoclean_service_environment.py" service_env_verifier || rollback_rc=1
validate_restored_path "$dropin_dir/$DROPIN_NAME" dropin || rollback_rc=1
validate_restored_path "$runtime_bin/.livingip-runtime-revision" revision || rollback_rc=1
validate_restored_directory "$runtime_grandparent" runtime_grandparent || rollback_rc=1
validate_restored_directory "$runtime_parent" runtime_parent || rollback_rc=1
validate_restored_directory "$runtime_bin" runtime_bin || rollback_rc=1
validate_restored_directory "$dropin_dir" dropin_dir || rollback_rc=1
fi
if [ "$rollback_rc" -eq 0 ]; then
sudo systemctl daemon-reload || rollback_rc=1
fi
if [ "$rollback_rc" -eq 0 ]; then
assert_unit_configuration false || rollback_rc=1
fi
if [ "$rollback_rc" -eq 0 ]; then
sudo systemctl start "$SERVICE" || rollback_rc=1
assert_service_running || rollback_rc=1
fi
return "$rollback_rc"
}
on_exit() {
local rc="$1" rollback_rc=0
trap - EXIT INT TERM
if [ "$rc" -ne 0 ] && [ "$mutation_started" = true ]; then
set +e
rollback_runtime
rollback_rc=$?
set -e
if [ "$rollback_rc" -ne 0 ]; then
echo "CRITICAL: previous runtime restoration did not return the service to active/running." >&2
rc=1
fi
fi
sudo rm -f -- \
"$wrapper_stage" \
"$tool_stage" \
"$permission_verifier_stage" \
"$service_env_verifier_stage" \
"$revision_stage" \
"$dropin_stage" || true
sudo rm -rf -- "$remote_tmp" || true
exit "$rc"
}
trap 'on_exit $?' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
sudo chmod 0711 "$remote_tmp"
sudo install -d -o root -g root -m 0755 "$payload_dir"
sudo install -d -o root -g root -m 0700 "$backup_dir"
sudo install -d -o teleo -g teleo -m 0700 "$work_dir"
sudo tar --no-same-owner --no-same-permissions --no-xattrs --no-acls --no-selinux -C "$payload_dir" -xf -
if sudo find "$payload_dir" -type l -print -quit | grep -q .; then
echo "Staged runtime payload contains a symlink." >&2
exit 65
fi
if sudo find "$payload_dir" ! -type d ! -type f -print -quit | grep -q .; then
echo "Staged runtime payload contains a non-regular entry." >&2
exit 65
fi
sudo chown -R root:root "$payload_dir"
sudo find "$payload_dir" -type d -exec chmod 0555 {} +
sudo find "$payload_dir" -type f -exec chmod 0444 {} +
sudo chmod 0555 \
"$payload_dir/$WRAPPER_REL" \
"$payload_dir/$TOOL_REL" \
"$payload_dir/$PERMISSION_VERIFIER_REL" \
"$payload_dir/$SERVICE_ENV_VERIFIER_REL"
test "$(sudo sha256sum "$payload_dir/$WRAPPER_REL" | awk '{print $1}')" = "$WRAPPER_SHA"
test "$(sudo sha256sum "$payload_dir/$TOOL_REL" | awk '{print $1}')" = "$TOOL_SHA"
test "$(sudo sha256sum "$payload_dir/$PERMISSION_VERIFIER_REL" | awk '{print $1}')" = "$PERMISSION_VERIFIER_SHA"
test "$(sudo sha256sum "$payload_dir/$SERVICE_ENV_VERIFIER_REL" | awk '{print $1}')" = "$SERVICE_ENV_VERIFIER_SHA"
test "$(sudo sha256sum "$payload_dir/$DROPIN_REL" | awk '{print $1}')" = "$DROPIN_SHA"
test "$(sudo stat -c '%U:%G:%a' "$remote_tmp")" = "root:root:711"
test "$(sudo stat -c '%U:%G:%a' "$payload_dir")" = "root:root:555"
test "$(sudo stat -c '%U:%G:%a' "$backup_dir")" = "root:root:700"
test "$(sudo stat -c '%U:%G:%a' "$work_dir")" = "teleo:teleo:700"
sudo -n -u teleo test ! -w "$remote_tmp"
sudo -n -u teleo test ! -w "$payload_dir"
sudo -n -u teleo test ! -w "$backup_dir"
sudo test -d "$runtime_anchor"
sudo test -d "$dropin_parent"
sudo test ! -L "$runtime_anchor"
sudo test ! -L "$dropin_parent"
test "$(sudo stat -c '%U:%G' "$runtime_anchor")" = "root:root"
test "$(sudo stat -c '%U:%G' "$dropin_parent")" = "root:root"
sudo -n -u teleo test ! -w "$runtime_anchor"
sudo -n -u teleo test ! -w "$dropin_parent"
for existing_directory in \
"$runtime_grandparent" \
"$runtime_parent" \
"$runtime_bin" \
"$dropin_dir"; do
assert_existing_root_directory "$existing_directory"
done
for existing_file in \
"$runtime_bin/teleo-kb" \
"$runtime_bin/cloudsql_memory_tool.py" \
"$runtime_bin/verify_gcp_leoclean_runtime_permissions.py" \
"$runtime_bin/verify_gcp_leoclean_service_environment.py" \
"$runtime_bin/.livingip-runtime-revision" \
"$dropin_dir/$DROPIN_NAME"; do
assert_existing_root_file "$existing_file"
done
assert_service_running
preflight_service_before="$(service_fingerprint)"
assert_runtime_environment "$payload_dir/$SERVICE_ENV_VERIFIER_REL" false
run_scoped_status pre "$payload_dir/$TOOL_REL"
assert_administrator_secret_denied
run_permission_verifier pre "$payload_dir/$PERMISSION_VERIFIER_REL" "$work_dir/permission-pre/receipt.json"
assert_service_fingerprint "$preflight_service_before"
if [ "$PREFLIGHT_ONLY" = true ]; then
systemctl show "$SERVICE" -p ActiveState -p SubState -p NRestarts -p MainPID -p User --no-pager
exit 0
fi
backup_path "$runtime_bin/teleo-kb" wrapper
backup_path "$runtime_bin/cloudsql_memory_tool.py" tool
backup_path "$runtime_bin/verify_gcp_leoclean_runtime_permissions.py" verifier
backup_path "$runtime_bin/verify_gcp_leoclean_service_environment.py" service_env_verifier
backup_path "$dropin_dir/$DROPIN_NAME" dropin
backup_path "$runtime_bin/.livingip-runtime-revision" revision
backup_directory_state "$runtime_parent" runtime_parent
backup_directory_state "$runtime_grandparent" runtime_grandparent
backup_directory_state "$runtime_bin" runtime_bin
backup_directory_state "$dropin_dir" dropin_dir
mutation_started=true
sudo systemctl stop "$SERVICE"
sudo install -d -o root -g root -m 0755 "$runtime_parent"
sudo install -d -o root -g root -m 0755 "$runtime_bin"
sudo install -o root -g root -m 0755 "$payload_dir/$WRAPPER_REL" "$wrapper_stage"
sudo install -o root -g root -m 0755 "$payload_dir/$TOOL_REL" "$tool_stage"
sudo install -o root -g root -m 0755 "$payload_dir/$PERMISSION_VERIFIER_REL" "$permission_verifier_stage"
sudo install -o root -g root -m 0755 "$payload_dir/$SERVICE_ENV_VERIFIER_REL" "$service_env_verifier_stage"
sudo mv -f -- "$wrapper_stage" "$runtime_bin/teleo-kb"
sudo mv -f -- "$tool_stage" "$runtime_bin/cloudsql_memory_tool.py"
sudo mv -f -- "$permission_verifier_stage" "$runtime_bin/verify_gcp_leoclean_runtime_permissions.py"
sudo mv -f -- "$service_env_verifier_stage" "$runtime_bin/verify_gcp_leoclean_service_environment.py"
sudo install -d -o root -g root -m 0755 "$dropin_dir"
sudo install -o root -g root -m 0644 "$payload_dir/$DROPIN_REL" "$dropin_stage"
sudo mv -f -- "$dropin_stage" "$dropin_dir/$DROPIN_NAME"
printf '%s\n' "$SOURCE_REVISION" | sudo tee "$revision_stage" >/dev/null
sudo chown root:root "$revision_stage"
sudo chmod 0644 "$revision_stage"
sudo mv -f -- "$revision_stage" "$runtime_bin/.livingip-runtime-revision"
assert_installed_files
sudo systemctl daemon-reload
assert_unit_configuration
sudo systemctl start "$SERVICE"
assert_deployed_files
assert_service_running
assert_runtime_environment "$runtime_bin/verify_gcp_leoclean_service_environment.py"
run_service_wrapper_status post
assert_administrator_secret_denied
run_permission_verifier post "$runtime_bin/verify_gcp_leoclean_runtime_permissions.py" "$work_dir/permission-post/receipt.json"
systemctl show "$SERVICE" -p ActiveState -p SubState -p NRestarts -p MainPID -p User --no-pager
mutation_started=false
REMOTE
)
sync_command="${sync_context}${remote_helpers}"$'\n'"${sync_body}"
COPYFILE_DISABLE=1 tar --format=ustar -C "$REPO_ROOT" -cf - \
"$WRAPPER_REL" \
"$TOOL_REL" \
"$PERMISSION_VERIFIER_REL" \
"$SERVICE_ENV_VERIFIER_REL" \
"$DROPIN_REL" | "${GCP_SSH[@]}" --command="$sync_command"