fix: scope codex-pool sentinel image to enabled targets

This commit is contained in:
Codex
2026-06-26 04:04:42 +00:00
parent d60813381d
commit 203b3e208a
5 changed files with 48 additions and 14 deletions
@@ -95,9 +95,9 @@ export async function codexPoolSync(config: UniDeskConfig, options: SyncOptions)
};
}
const sentinelImage = pool.sentinel.monitor.enabled
const sentinelImage = pool.sentinel.monitor.enabled && runtimeTarget.sentinelEnabled
? await runCodexPoolSentinelImage(config, pool, { action: "build", confirm: true, dryRun: false, full: options.full, raw: false, targetId: options.targetId })
: { ok: true, mode: "skipped-monitor-disabled" };
: { ok: true, mode: runtimeTarget.sentinelEnabled ? "skipped-monitor-disabled" : "skipped-target-disabled" };
if (sentinelImage.ok !== true) {
return {
ok: false,
@@ -113,17 +113,20 @@ export async function codexPoolSync(config: UniDeskConfig, options: SyncOptions)
const payload = {
pruneRemoved: options.pruneRemoved,
sentinel: {
manifest: renderCodexPoolSentinelManifest(pool.sentinel, sentinelProfileSecrets(profiles), {
namespace: runtimeTarget.namespace,
serviceName: runtimeTarget.serviceName,
serviceDns: runtimeTarget.serviceDns,
appSecretName: runtimeTarget.appSecretName,
adminEmailDefault: pool.adminEmailDefault,
proxy: runtimeTarget.egressProxy?.applyToSentinel ? {
httpProxy: runtimeTarget.egressProxy.httpProxy,
noProxy: runtimeTarget.egressProxy.noProxy,
} : null,
}),
enabledForTarget: runtimeTarget.sentinelEnabled,
manifest: runtimeTarget.sentinelEnabled
? renderCodexPoolSentinelManifest(pool.sentinel, sentinelProfileSecrets(profiles), {
namespace: runtimeTarget.namespace,
serviceName: runtimeTarget.serviceName,
serviceDns: runtimeTarget.serviceDns,
appSecretName: runtimeTarget.appSecretName,
adminEmailDefault: pool.adminEmailDefault,
proxy: runtimeTarget.egressProxy?.applyToSentinel ? {
httpProxy: runtimeTarget.egressProxy.httpProxy,
noProxy: runtimeTarget.egressProxy.noProxy,
} : null,
})
: null,
summary: codexPoolSentinelSummary(pool.sentinel),
},
pool: {
@@ -215,6 +218,20 @@ export async function codexPoolSentinelImage(config: UniDeskConfig, options: Sen
export async function runCodexPoolSentinelImage(config: UniDeskConfig, pool: CodexPoolConfig, options: SentinelImageOptions): Promise<Record<string, unknown>> {
const runtimeTarget = codexPoolRuntimeTarget(options.targetId);
const target = codexPoolSentinelRuntimeImage(pool.sentinel);
if (!runtimeTarget.sentinelEnabled) {
return {
ok: true,
action: "platform-infra-sub2api-codex-pool-sentinel-image",
mode: "skipped-target-disabled",
target: {
id: runtimeTarget.id,
namespace: runtimeTarget.namespace,
},
image: target,
mutation: false,
valuesPrinted: false,
};
}
if (options.action === "build" && options.dryRun) {
return {
ok: true,
@@ -324,5 +324,6 @@ export interface Sub2ApiRuntimeConfig {
defaultTargetId: string;
appSecretName: string;
secretsRoot: string;
sentinelEnabledOnTargets: string[];
targets: Record<string, unknown>[];
}
@@ -67,6 +67,7 @@ EXPECTED_ACCOUNT_TEMP_UNSCHEDULABLE = json.loads(${JSON.stringify(JSON.stringify
MANUAL_ACCOUNT_PROTECTIONS = json.loads(${JSON.stringify(JSON.stringify(resolvedManualAccountProtections(pool, target)))})
SENTINEL_CONFIG = json.loads(${JSON.stringify(JSON.stringify(pool.sentinel))})
TARGET_EGRESS_PROXY = json.loads(${JSON.stringify(JSON.stringify(target.egressProxy))})
TARGET_SENTINEL_ENABLED = ${JSON.stringify(target.sentinelEnabled)}
MODE = "${mode}"
PAYLOAD_B64 = "${encodedPayload}"
@@ -166,7 +167,7 @@ def empty_to_none(value):
return value if isinstance(value, str) and value else None
def sentinel_quality_gate_enabled():
return (SENTINEL_CONFIG.get("monitor") or {}).get("enabled") is True and (SENTINEL_CONFIG.get("actions") or {}).get("enabled") is True
return TARGET_SENTINEL_ENABLED and (SENTINEL_CONFIG.get("monitor") or {}).get("enabled") is True and (SENTINEL_CONFIG.get("actions") or {}).get("enabled") is True
def account_notes_fingerprint(account):
notes = account.get("notes") if isinstance(account, dict) else None
@@ -981,6 +982,12 @@ def ensure_api_key_secret(group_id):
return api_key, secret_action, text(proc.stdout, 1000)
def apply_sentinel_manifest(manifest):
if not TARGET_SENTINEL_ENABLED:
return {
"ok": True,
"action": "skipped-target-disabled",
"valuesPrinted": False,
}
if not isinstance(manifest, str) or not manifest.strip():
return {
"ok": False,
@@ -1433,6 +1440,8 @@ def sentinel_state_summary():
}
def reassert_sentinel_freezes_after_sync(token):
if not TARGET_SENTINEL_ENABLED:
return {"ok": True, "skipped": True, "reason": "target-disabled", "items": [], "valuesPrinted": False}
if (SENTINEL_CONFIG.get("actions") or {}).get("enabled") is not True:
return {"ok": True, "skipped": True, "reason": "actions-disabled", "items": [], "valuesPrinted": False}
_, state = sentinel_state_object()
@@ -41,11 +41,16 @@ export function readSub2ApiRuntimeConfig(): Sub2ApiRuntimeConfig {
const secrets = runtime !== null && isRecord(runtime.secrets) ? runtime.secrets : null;
const secretsRoot = secrets === null ? null : stringValue(secrets.root);
if (secretsRoot === null || !secretsRoot.startsWith("/")) throw new Error(`${sub2apiConfigPath}.runtime.secrets.root must be an absolute path`);
const sentinel = runtime !== null && isRecord(runtime.sentinel) ? runtime.sentinel : null;
const enabledOnTargets = Array.isArray(sentinel?.enabledOnTargets)
? sentinel.enabledOnTargets.map((entry) => stringValue(entry)).filter((entry): entry is string => entry !== null && entry.length > 0)
: [];
if (!Array.isArray(parsed.targets) || !parsed.targets.every(isRecord)) throw new Error(`${sub2apiConfigPath}.targets must be a list`);
return {
defaultTargetId,
appSecretName,
secretsRoot,
sentinelEnabledOnTargets: enabledOnTargets,
targets: parsed.targets,
};
}
@@ -100,6 +105,7 @@ export function codexPoolRuntimeTarget(targetId?: string): CodexPoolRuntimeTarge
publicExposure,
appSecretName: runtimeConfig.appSecretName,
secretsRoot: runtimeConfig.secretsRoot,
sentinelEnabled: runtimeConfig.sentinelEnabledOnTargets.some((entry) => entry.toLowerCase() === id.toLowerCase()),
sentinelImageBuild,
egressProxy,
};
@@ -87,6 +87,7 @@ export interface CodexPoolRuntimeTarget {
publicExposure: PublicServiceExposure | null;
appSecretName: string;
secretsRoot: string;
sentinelEnabled: boolean;
sentinelImageBuild: {
baseImageCachePolicy: "pull" | "local-if-present";
noProxy: string;