Skip to content

Commit 2136a03

Browse files
fix(setup): verify kube-context is really local; lengthen CLI handoff wait
- k8s: a context named like a local cluster (kind-*, docker-desktop) can actually point at a remote API server. Verify the server host is loopback/docker-internal before defaulting the 'use this context?' confirm to yes; otherwise warn and default to no, so generated secrets can't ship to a remote cluster on a blind Enter. - cli-auth: bump the device-flow wait from 3 to 15 minutes so first-time users have time to sign up, wait for the email OTP, and approve before the terminal stops polling. The server-side approval record keeps its own short TTL, so a longer client wait only costs cheap rate-limited polls.
1 parent 3bea50f commit 2136a03

2 files changed

Lines changed: 59 additions & 8 deletions

File tree

scripts/setup/cli-auth.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { generateShortId } from '@sim/utils/id'
66
import * as p from './prompter.ts'
77
import { link, theme } from './theme.ts'
88

9-
const WAIT_MS = 180_000
9+
// Generous enough for a first-time user to create an account, wait for the email
10+
// OTP, land back on /cli/auth, and approve — a few minutes is routine. The
11+
// server-side approval record has its own short TTL, so a long client wait only
12+
// costs cheap, rate-limited polls.
13+
const WAIT_MS = 900_000
1014
const POLL_INTERVAL_MS = 2000
1115

1216
function openBrowser(url: string): void {

scripts/setup/modes/k8s.ts

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,38 @@ function isLocalContext(context: string): boolean {
2929
return LOCAL_CONTEXT_PREFIXES.some((prefix) => context === prefix || context.startsWith(prefix))
3030
}
3131

32+
const LOCAL_SERVER_HOSTS = new Set([
33+
'127.0.0.1',
34+
'localhost',
35+
'0.0.0.0',
36+
'::1',
37+
'kubernetes.docker.internal',
38+
'host.docker.internal',
39+
])
40+
41+
/** The API server host a context points at, or null if kubectl can't resolve it. */
42+
function contextServerHost(context: string): string | null {
43+
const result = spawnSync(
44+
'kubectl',
45+
[
46+
'config',
47+
'view',
48+
'--minify',
49+
'--context',
50+
context,
51+
'-o',
52+
'jsonpath={.clusters[0].cluster.server}',
53+
],
54+
{ encoding: 'utf8' }
55+
)
56+
if (result.status !== 0) return null
57+
try {
58+
return new URL(result.stdout.trim()).hostname
59+
} catch {
60+
return null
61+
}
62+
}
63+
3264
/**
3365
* POSIX-quote a value for a copyable shell hint. A kube-context passes only a
3466
* prefix check, so it can still contain whitespace or shell metacharacters that
@@ -48,13 +80,28 @@ async function ensureLocalContext(detection: Detection): Promise<string> {
4880
}
4981
const context = detection.kubeContext
5082
if (context && isLocalContext(context)) {
51-
const useIt = await p.confirm({
52-
message: `Use current kube context "${context}"?`,
53-
initialValue: true,
54-
})
55-
if (useIt) return context
56-
}
57-
if (context && !isLocalContext(context)) {
83+
// The name is only a hint — a remote cluster can be named like a local one
84+
// (e.g. "kind-prod"). Verify the API server is a loopback/host address before
85+
// defaulting to "yes", so generated secrets can't silently ship to a remote
86+
// cluster on a blind Enter.
87+
const server = contextServerHost(context)
88+
if (server && LOCAL_SERVER_HOSTS.has(server)) {
89+
const useIt = await p.confirm({
90+
message: `Use current kube context "${context}"?`,
91+
initialValue: true,
92+
})
93+
if (useIt) return context
94+
} else {
95+
p.log.warn(
96+
`Context "${context}" is named like a local cluster, but its API server${server ? ` (${server})` : ''} does not look local. Continuing would deploy the generated secrets there.`
97+
)
98+
const useIt = await p.confirm({
99+
message: `Deploy to "${context}" anyway?`,
100+
initialValue: false,
101+
})
102+
if (useIt) return context
103+
}
104+
} else if (context) {
58105
p.log.warn(
59106
`Current context "${context}" does not look like a local cluster. Deploying to remote clusters is not supported by the wizard yet — switch to a kind/docker-desktop context, or drive helm directly (see helm/sim/examples/values-production.yaml).`
60107
)

0 commit comments

Comments
 (0)