Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ CMUX_VM_ALLOW_UNMANIFESTED_IMAGES=
CMUX_VM_ALLOWED_ORIGINS=
CMUX_VM_FREESTYLE_ENABLED=1
FREESTYLE_API_KEY=
FREESTYLE_SANDBOX_SNAPSHOT=sh-940ec3bc46224c019e5e8d9a97053293
# The Cloud VM image comes from web/services/vms/images/manifest.json (defaultForKind); no env var selects it.

# Cloud VM database. Local dev derives DATABASE_URL from CMUX_PORT. Staging/production use the
# Vercel Marketplace AWS Aurora PostgreSQL OIDC/RDS IAM env set below.
Expand Down
3 changes: 3 additions & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"cloud-vm:preflight": "bash scripts/cloud-vm/verify-migration-preflight.sh",
"cloud-vm:smoke": "bun scripts/cloud-vm/smoke-vm-api.mjs",
"cloud-vm:stress": "bun scripts/cloud-vm/stress-vm-api.mjs",
"devbox:bake:freestyle": "bun scripts/build-devbox-freestyle.ts",
"devbox:verify": "bun scripts/verify-devbox-image.ts",
"devbox:promote": "bun scripts/promote-devbox-image.ts",
"db:check": "bunx drizzle-kit check --config drizzle.config.ts",
"db:down": "bash scripts/db-local.sh down",
"db:generate": "bunx drizzle-kit generate --config drizzle.config.ts",
Expand Down
494 changes: 332 additions & 162 deletions web/scripts/build-devbox-freestyle.ts

Large diffs are not rendered by default.

46 changes: 25 additions & 21 deletions web/scripts/cloud-vm/defaultProviderAudit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,35 @@ export function auditProviderReadiness(provider, env, manifest) {
return { provider, envVar: null, image: null, problems };
}

// The checked-in manifest is the only source of truth for images: deployed
// runtimes serve the entry flagged defaultForKind (services/vms/images/
// resolver.ts). No env var selects an image any more; a lingering selector
// is stale configuration that would mislead whoever reads the deployment.
const envVar = entries[0].envVar;
const image = env[envVar]?.trim() || null;
if (!image) {
const kindDefaults = entries.filter((entry) => entry.defaultForKind === true);
for (const entry of kindDefaults.filter((entry) => entry.validationStatus !== "passed")) {
problems.push(
`${envVar} is not set; deployed runtimes fail closed on imageless ` +
`creates for provider ${provider}`,
`manifest default ${entry.version} (${entry.kind ?? "base"}) for ${provider} has ` +
`validationStatus ${entry.validationStatus}, not passed`,
);
} else if (image === SENSITIVE_PLACEHOLDER) {
}
// Only a validated default counts as the served image: an unvalidated one
// is already reported above and must not be echoed back as the selection.
const baseDefault = kindDefaults.find(
(entry) => (entry.kind ?? "base") === "base" && entry.validationStatus === "passed",
);
const image = baseDefault?.imageId ?? null;
if (!baseDefault) {
problems.push(
`${envVar} is stored as a Sensitive env var, so its value cannot be audited; ` +
"store it as a plain env var (image ids are configuration, not secrets)",
`the manifest has no validated base default for ${provider} (no entry flagged ` +
"defaultForKind); deployed runtimes fail closed on imageless creates",
);
}
if (envVar && env[envVar] !== undefined) {
problems.push(
`${envVar} is set but ignored: the manifest is the source of truth for images; ` +
"remove it from the deployment",
);
} else {
const entry = entries.find((candidate) => candidate.imageId === image || candidate.version === image);
if (!entry) {
problems.push(
`${envVar}=${image} is not listed in the image manifest for ${provider}; ` +
"deployed runtimes will reject it with vm_image_config_error",
);
} else if (entry.validationStatus !== "passed") {
problems.push(
`${envVar} selects manifest entry ${entry.version} whose validationStatus is ` +
`${entry.validationStatus}, not passed`,
);
}
}

const credentialKeys = PROVIDER_CREDENTIAL_KEYS[provider];
Expand Down Expand Up @@ -106,7 +110,7 @@ export function auditProviderReadiness(provider, env, manifest) {
problems.push(`${enabledKey} disables provider ${provider}, so the selected default cannot create VMs`);
}

return { provider, envVar, image, problems };
return { provider, envVar, image, imageSource: "manifest", problems };
}

function isFalseFlag(value) {
Expand Down
1 change: 0 additions & 1 deletion web/scripts/cloud-vm/projects.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export const requiredRuntimeEnvKeys = [
// Every Vercel cron (VM alerts included) refuses to run without it.
"CRON_SECRET",
"FREESTYLE_API_KEY",
"FREESTYLE_SANDBOX_SNAPSHOT",
"NEXT_PUBLIC_STACK_PROJECT_ID",
"NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY",
"PGDATABASE",
Expand Down
Loading
Loading