// Two-sided tests for the pure parts of extensions/aws-sso.ts (node >= 23 strips // the types; the only pi import is type-only). Shapes observed 2026-10-10/11 on // mbp-m1-2020. import { test } from "node:test"; import assert from "node:assert/strict"; import { fingerprint, cacheKeyFor, parseIni, resolveSsoSession, parseDeviceOutput, isSsoExpiredError, reanchor, fmtLeft, probeDue, probeWith, REFRESH_WINDOW_MS, normalizeMode, resolveMode, autoLoginGap, ntfyRequest, describeTopic, } from "../extensions/aws-sso.ts"; const START = "https://d-1234567890.awsapps.com/start"; const HOST = "d-1234567890.awsapps.com"; const CONFIG = ` [profile Base] sso_session = MySession sso_account_id = 111111111111 sso_role_name = Dev [sso-session MySession] sso_start_url = ${START} sso_region = eu-west-1 [profile Bedrock] role_arn = arn:aws:iam::111111111111:role/X source_profile = Base [profile LoopA] source_profile = LoopB [profile LoopB] source_profile = LoopA [profile Legacy] sso_start_url = ${START} [profile Dangling] sso_session = Nope `; test("fingerprint: 8 hex chars, stable, never the value", () => { const v = "aoaAAAAAGh0dHBzOi8vZXhhbXBsZS5jb20v"; assert.match(fingerprint(v), /^[0-9a-f]{8}$/); assert.equal(fingerprint(v), fingerprint(v)); assert.notEqual(fingerprint(v), fingerprint(v + "x")); assert.ok(!v.includes(fingerprint(v))); assert.equal(fingerprint(""), "-"); }); test("cache key = sha1(session name) — the measured botocore file name", () => { assert.equal(cacheKeyFor("GFTLIntelligenceOnTap"), "c8ef84539c753bc7f3a20b5dceef5c2f03e744a7"); }); test("resolveSsoSession follows source_profile to the sso-session", () => { const r = resolveSsoSession(CONFIG, "Bedrock"); assert.equal(r.sessionName, "MySession"); assert.equal(r.startUrl, START); assert.deepEqual(r.chain, ["Bedrock", "Base"]); }); test("resolveSsoSession refuses broken configs with a reason", () => { assert.throws(() => resolveSsoSession(CONFIG, "LoopA"), /loop/); assert.throws(() => resolveSsoSession(CONFIG, "Missing"), /not found/); assert.throws(() => resolveSsoSession(CONFIG, "Legacy"), /legacy/); assert.throws(() => resolveSsoSession(CONFIG, "Dangling"), /sso-session Nope/); assert.deepEqual(parseIni("# c\n[profile A]\nk = v = w\n"), { "profile A": { k: "v = w" } }); }); const CLI = (code, host = HOST) => `Browser will not be automatically opened. Please visit the following URL: https://${host}/start/#/device Then enter the code: ${code} Alternatively, you may visit the following URL which will autofill the code upon loading: https://${host}/start/#/device?user_code=${code} `; test("parseDeviceOutput: real shape accepted; foreign host / bad code refused", () => { const r = parseDeviceOutput(CLI("PCDB-WSGH"), START); assert.equal(r.code, "PCDB-WSGH"); assert.equal(new URL(r.url).host, HOST); assert.equal(parseDeviceOutput(CLI("PCDB-WSGH", "evil.example.com"), START), null); assert.equal(parseDeviceOutput(CLI("PCDB-WSGH", `${HOST}.evil.example.com`), START), null); assert.equal(parseDeviceOutput(CLI("pcdb-wsgh"), START), null); assert.equal(parseDeviceOutput("Browser will not be automatically opened.\n", START), null); }); test("isSsoExpiredError: the real pi error matches; unrelated failures do not", () => { assert.ok(isSsoExpiredError("Token is expired. To refresh this SSO session run 'aws sso login' with the corresponding profile.")); // measured 2026-10-11T14:18:08Z assert.ok(isSsoExpiredError("The SSO session associated with this profile has expired or is otherwise invalid")); assert.ok(isSsoExpiredError("ExpiredTokenException: The security token included in the request is expired")); for (const m of ["Provider stopped with: content_filtered", "getaddrinfo ENOTFOUND bedrock-runtime.eu-west-1.amazonaws.com", "AccessDeniedException: not authorized", "ThrottlingException: Too many requests"]) { assert.ok(!isSsoExpiredError(m), m); } }); const H = 3600e3; const T0 = Date.UTC(2026, 9, 11, 14, 19, 0); const tok = (fp, accessExp) => ({ refreshFp: fp, accessExpiresAt: accessExp }); test("probeDue: only inside the SDK's 5-min window; 60 s apart while valid, 10 min apart once expired", () => { const exp = T0 + H; assert.equal(REFRESH_WINDOW_MS, 5 * 60e3); // token-providers 3.1127.0 EXPIRE_WINDOW_MS assert.equal(probeDue(exp, exp - 6 * 60e3, 0), false); // outside: the SDK would not even try assert.equal(probeDue(exp, exp - 5 * 60e3, 0), true); assert.equal(probeDue(exp, exp - 4 * 60e3, exp - 4.5 * 60e3), false); // 30 s after the last attempt assert.equal(probeDue(exp, exp - 3 * 60e3, exp - 4.5 * 60e3), true); assert.equal(probeDue(exp, exp + 5 * 60e3, exp + 1 * 60e3), false); // expired: back off assert.equal(probeDue(exp, exp + 12 * 60e3, exp + 1 * 60e3), true); }); // probeWith: a fake SDK provider and a fake cache, mirroring token-providers' real behaviour. const cacheSim = (exp) => ({ exp, read() { return this.exp; } }); test("probeWith: refreshed when the cache advances; refused when the SDK silently keeps the old token", async () => { const now = () => T0 + H - 3 * 60e3; const ok = cacheSim(T0 + H); let r = await probeWith(() => () => async () => { ok.exp = T0 + 2 * H; return { token: "x" }; }, () => ok.read(), "Base", now); assert.equal(r.result, "refreshed"); const ended = cacheSim(T0 + H); // session over: refresh fails inside the window, SDK returns the old token, no throw r = await probeWith(() => () => async () => ({ token: "old" }), () => ended.read(), "Base", now); assert.equal(r.result, "refused"); r = await probeWith(() => () => async () => { throw new Error("Token is expired. To refresh this SSO session run 'aws sso login'"); }, () => ended.read(), "Base", () => T0 + 2 * H); assert.equal(r.result, "refused"); assert.match(r.error, /expired/); }); test("probeWith: never calls the SDK outside the window; a missing SDK is 'unavailable', not 'session ended'", async () => { let called = 0; const c = cacheSim(T0 + H); let r = await probeWith(() => () => async () => { called++; }, () => c.read(), "Base", () => T0); assert.equal(r.result, "fresh"); assert.equal(called, 0); r = await probeWith(() => { throw new Error("Cannot find module '@aws-sdk/token-providers'"); }, () => c.read(), "Base", () => T0 + H - 60e3); assert.equal(r.result, "unavailable"); let seen; await probeWith(() => (init) => { seen = init; return async () => {}; }, () => c.read(), "GFTLIoT-Base", () => T0 + H - 60e3); assert.deepEqual(seen, { profile: "GFTLIoT-Base", ignoreCache: true }); // the SSO profile at the end of the chain }); test("reanchor: a new token BEFORE the end inherits it (silent renewal); AFTER the end or an expiry starts fresh", () => { const st = { anchor: { refreshFp: "aaaa1111", since: T0 } }; assert.equal(reanchor(st, "aaaa1111", T0 + 3 * H, T0 + 3 * H), null); // hourly access refresh: same refresh token assert.deepEqual(reanchor(st, "bbbb2222", T0 + 1 * H, T0 + 1 * H), { refreshFp: "bbbb2222", since: T0 }); // measured 2026-10-11: green box, same session assert.deepEqual(reanchor(st, "bbbb2222", T0 + 8.05 * H, T0 + 8.05 * H), { refreshFp: "bbbb2222", since: T0 + 8.05 * H }); assert.deepEqual(reanchor({ ...st, sessionEnded: true }, "bbbb2222", T0 + 2 * H, T0 + 2 * H), { refreshFp: "bbbb2222", since: T0 + 2 * H }); assert.deepEqual(reanchor({ ...st, sessionHours: 1 }, "bbbb2222", T0 + 2 * H, T0 + 2 * H), { refreshFp: "bbbb2222", since: T0 + 2 * H }); assert.deepEqual(reanchor({}, "aaaa1111", T0, T0), { refreshFp: "aaaa1111", since: T0 }); }); test("mode: command beats .env beats default local; old names map; junk ignored", () => { assert.deepEqual(resolveMode({}, {}), { mode: "local", source: "default" }); assert.deepEqual(resolveMode({}, { PI_AWS_SSO_MODE: "remote" }), { mode: "remote", source: "env" }); assert.deepEqual(resolveMode({ mode: "local" }, { PI_AWS_SSO_MODE: "remote" }), { mode: "local", source: "command" }); assert.deepEqual(resolveMode({ mode: "device" }, {}), { mode: "remote", source: "command" }); assert.deepEqual(resolveMode({ mode: "mac" }, {}), { mode: "local", source: "command" }); assert.deepEqual(resolveMode({ mode: "bogus" }, { PI_AWS_SSO_MODE: " Remote " }), { mode: "remote", source: "env" }); assert.equal(normalizeMode("headless"), null); }); test("autoLoginGap: retries 30 min, 1 h, 2 h, then every 4 h; never closer than 30 min", () => { assert.deepEqual([0, 1, 2, 3, 4, 9].map((n) => autoLoginGap(n) / 60e3), [30, 30, 60, 120, 240, 240]); }); test("ntfyRequest: title/click/priority headers, bearer only when given, ASCII-safe; bad URLs refused", () => { const r = ntfyRequest("https://ntfy.sh/aws-x7Kq2", undefined, { title: "AWS SSO approval needed (mbp)", message: "Code PCDB-WSGH — tap", click: `https://${HOST}/start/#/device?user_code=PCDB-WSGH`, priority: "high", tags: ["key"] }); assert.equal(r.url, "https://ntfy.sh/aws-x7Kq2"); assert.equal(r.init.method, "POST"); assert.deepEqual(r.init.headers, { Title: "AWS SSO approval needed (mbp)", Priority: "high", Click: `https://${HOST}/start/#/device?user_code=PCDB-WSGH`, Tags: "key" }); assert.equal(r.init.body, "Code PCDB-WSGH — tap"); // the body may be UTF-8, headers may not assert.equal(ntfyRequest("https://n.example/t", "tk_abc", { title: "x", message: "y" }).init.headers.Authorization, "Bearer tk_abc"); assert.equal(ntfyRequest("https://n.example/t", undefined, { title: "Förnyad ✓", message: "y" }).init.headers.Title, "F?rnyad ?"); assert.throws(() => ntfyRequest("https://ntfy.sh/", undefined, { title: "x", message: "y" }), /no topic/); assert.throws(() => ntfyRequest("file:///etc/passwd", undefined, { title: "x", message: "y" }), /http/); assert.throws(() => ntfyRequest("not a url", undefined, { title: "x", message: "y" })); }); test("describeTopic never prints the topic (it is the secret)", () => { const d = describeTopic("https://ntfy.sh/aws-x7Kq2-very-secret"); assert.match(d, /^ntfy\.sh \(topic [0-9a-f]{8}\)$/); assert.ok(!d.includes("secret")); assert.equal(describeTopic(undefined), "not configured"); }); test("fmtLeft", () => { assert.equal(fmtLeft(-5), "0m"); assert.equal(fmtLeft(25 * 60e3), "25m"); assert.equal(fmtLeft(7 * H + 5 * 60e3), "7h05m"); });