fix: roll sub2api on config changes

This commit is contained in:
Codex
2026-06-09 09:50:02 +00:00
parent 24efae9f52
commit 5e34f2c2f6
2 changed files with 57 additions and 6 deletions
+55 -6
View File
@@ -1,3 +1,4 @@
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
import type { UniDeskConfig } from "./config";
import { rootPath } from "./config";
@@ -193,9 +194,17 @@ function manifest(): string {
const sub2api = readSub2ApiConfig();
const template = readFileSync(manifestPath, "utf8");
const urlAllowlist = sub2api.security.urlAllowlist;
const configHash = createHash("sha256")
.update(JSON.stringify({
image: sub2api.image,
security: sub2api.security,
}))
.digest("hex")
.slice(0, 16);
return template
.replaceAll("__SUB2API_IMAGE__", imageRef(sub2api))
.replaceAll("__SUB2API_IMAGE_PULL_POLICY__", sub2api.image.pullPolicy)
.replaceAll("__SUB2API_CONFIG_HASH__", configHash)
.replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ENABLED__", String(urlAllowlist.enabled))
.replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP__", String(urlAllowlist.allowInsecureHttp))
.replaceAll("__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS__", String(urlAllowlist.allowPrivateHosts))
@@ -550,6 +559,16 @@ capture_json configmap kubectl -n ${namespace} get configmap sub2api-config
capture_json ingresses kubectl -n ${namespace} get ingress
capture_json quotas kubectl -n ${namespace} get resourcequota
capture_json limitranges kubectl -n ${namespace} get limitrange
pod_name="$(kubectl -n ${namespace} get pod -l app.kubernetes.io/name=${serviceName},app.kubernetes.io/component=app -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod-name.err" || true)"
printf '%s' "$pod_name" >"$tmp/pod-name.txt"
if [ -n "$pod_name" ]; then
kubectl -n ${namespace} exec "$pod_name" -- sh -c 'printf "SECURITY_URL_ALLOWLIST_ENABLED=%s\\n" "$SECURITY_URL_ALLOWLIST_ENABLED"; printf "SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP=%s\\n" "$SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP"; printf "SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS=%s\\n" "$SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"; printf "SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=%s\\n" "$SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"' >"$tmp/pod-env.out" 2>"$tmp/pod-env.err"
printf '%s' "$?" >"$tmp/pod-env.rc"
else
: >"$tmp/pod-env.out"
printf '%s\\n' 'sub2api app pod not found' >"$tmp/pod-env.err"
printf '%s' "1" >"$tmp/pod-env.rc"
fi
python3 - "$tmp" <<'PY'
import json
import os
@@ -578,6 +597,13 @@ def items(name):
return []
return data.get("items") or []
def text(name):
path = os.path.join(tmp, name)
try:
return open(path, encoding="utf-8", errors="replace").read()
except FileNotFoundError:
return ""
def deployment_summary(item):
spec = item.get("spec") or {}
status = item.get("status") or {}
@@ -729,12 +755,27 @@ url_allowlist_runtime = {
"allowPrivateHosts": configmap_data.get("SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"),
"upstreamHosts": configmap_data.get("SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"),
}
url_allowlist_aligned = (
url_allowlist_runtime["enabled"] == str(expected_url_allowlist.get("enabled")).lower()
and url_allowlist_runtime["allowInsecureHttp"] == str(expected_url_allowlist.get("allowInsecureHttp")).lower()
and url_allowlist_runtime["allowPrivateHosts"] == str(expected_url_allowlist.get("allowPrivateHosts")).lower()
and url_allowlist_runtime["upstreamHosts"] == ",".join(expected_url_allowlist.get("upstreamHosts") or [])
)
pod_env = {}
for line in text("pod-env.out").splitlines():
if "=" not in line:
continue
key, value = line.split("=", 1)
pod_env[key] = value
url_allowlist_pod_env = {
"enabled": pod_env.get("SECURITY_URL_ALLOWLIST_ENABLED"),
"allowInsecureHttp": pod_env.get("SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP"),
"allowPrivateHosts": pod_env.get("SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS"),
"upstreamHosts": pod_env.get("SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS"),
}
expected_url_allowlist_strings = {
"enabled": str(expected_url_allowlist.get("enabled")).lower(),
"allowInsecureHttp": str(expected_url_allowlist.get("allowInsecureHttp")).lower(),
"allowPrivateHosts": str(expected_url_allowlist.get("allowPrivateHosts")).lower(),
"upstreamHosts": ",".join(expected_url_allowlist.get("upstreamHosts") or []),
}
url_allowlist_configmap_aligned = url_allowlist_runtime == expected_url_allowlist_strings
url_allowlist_pod_env_aligned = rc("pod-env") == 0 and url_allowlist_pod_env == expected_url_allowlist_strings
url_allowlist_aligned = url_allowlist_configmap_aligned and url_allowlist_pod_env_aligned
boundary = {
"internalOnly": len(service_violations) == 0 and len(items("ingresses")) == 0,
"serviceViolations": service_violations,
@@ -771,8 +812,16 @@ payload = {
"configPath": "config/platform-infra/sub2api.yaml",
"expected": expected_url_allowlist,
"runtime": url_allowlist_runtime,
"podEnv": url_allowlist_pod_env,
"aligned": url_allowlist_aligned,
"configMapAligned": url_allowlist_configmap_aligned,
"podEnvAligned": url_allowlist_pod_env_aligned,
"configMapExists": rc("configmap") == 0,
"podEnvProbe": {
"podName": text("pod-name.txt"),
"exitCode": rc("pod-env"),
"stderr": text("pod-env.err")[-1000:],
},
}
},
"boundary": boundary,
@@ -327,6 +327,8 @@ spec:
app.kubernetes.io/component: app
template:
metadata:
annotations:
unidesk.ai/sub2api-config-hash: "__SUB2API_CONFIG_HASH__"
labels:
app.kubernetes.io/name: sub2api
app.kubernetes.io/component: app