@tickernelz/paperclip-pro-adapter-grok-local 2026.925.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +22 -0
  2. package/dist/cli/format-event.d.ts +2 -0
  3. package/dist/cli/format-event.d.ts.map +1 -0
  4. package/dist/cli/format-event.js +55 -0
  5. package/dist/cli/format-event.js.map +1 -0
  6. package/dist/cli/format-event.test.d.ts +2 -0
  7. package/dist/cli/format-event.test.d.ts.map +1 -0
  8. package/dist/cli/format-event.test.js +19 -0
  9. package/dist/cli/format-event.test.js.map +1 -0
  10. package/dist/cli/index.d.ts +2 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/cli/index.js +2 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/index.d.ts +10 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +53 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/server/adapter-auth-promotion.d.ts +87 -0
  19. package/dist/server/adapter-auth-promotion.d.ts.map +1 -0
  20. package/dist/server/adapter-auth-promotion.js +294 -0
  21. package/dist/server/adapter-auth-promotion.js.map +1 -0
  22. package/dist/server/adapter-auth-promotion.test.d.ts +2 -0
  23. package/dist/server/adapter-auth-promotion.test.d.ts.map +1 -0
  24. package/dist/server/adapter-auth-promotion.test.js +563 -0
  25. package/dist/server/adapter-auth-promotion.test.js.map +1 -0
  26. package/dist/server/device-login-parse.d.ts +23 -0
  27. package/dist/server/device-login-parse.d.ts.map +1 -0
  28. package/dist/server/device-login-parse.js +148 -0
  29. package/dist/server/device-login-parse.js.map +1 -0
  30. package/dist/server/device-login-parse.test.d.ts +2 -0
  31. package/dist/server/device-login-parse.test.d.ts.map +1 -0
  32. package/dist/server/device-login-parse.test.js +146 -0
  33. package/dist/server/device-login-parse.test.js.map +1 -0
  34. package/dist/server/execute.d.ts +3 -0
  35. package/dist/server/execute.d.ts.map +1 -0
  36. package/dist/server/execute.js +572 -0
  37. package/dist/server/execute.js.map +1 -0
  38. package/dist/server/execute.test.d.ts +2 -0
  39. package/dist/server/execute.test.d.ts.map +1 -0
  40. package/dist/server/execute.test.js +731 -0
  41. package/dist/server/execute.test.js.map +1 -0
  42. package/dist/server/grok-auth-copyback.d.ts +48 -0
  43. package/dist/server/grok-auth-copyback.d.ts.map +1 -0
  44. package/dist/server/grok-auth-copyback.js +92 -0
  45. package/dist/server/grok-auth-copyback.js.map +1 -0
  46. package/dist/server/grok-auth-copyback.test.d.ts +2 -0
  47. package/dist/server/grok-auth-copyback.test.d.ts.map +1 -0
  48. package/dist/server/grok-auth-copyback.test.js +246 -0
  49. package/dist/server/grok-auth-copyback.test.js.map +1 -0
  50. package/dist/server/grok-auth-merge-decision.cjs +157 -0
  51. package/dist/server/grok-auth-merge-decision.d.ts +21 -0
  52. package/dist/server/grok-auth-merge-decision.d.ts.map +1 -0
  53. package/dist/server/grok-auth-merge-decision.js +58 -0
  54. package/dist/server/grok-auth-merge-decision.js.map +1 -0
  55. package/dist/server/grok-auth-merge-decision.test.d.ts +2 -0
  56. package/dist/server/grok-auth-merge-decision.test.d.ts.map +1 -0
  57. package/dist/server/grok-auth-merge-decision.test.js +189 -0
  58. package/dist/server/grok-auth-merge-decision.test.js.map +1 -0
  59. package/dist/server/grok-home.d.ts +57 -0
  60. package/dist/server/grok-home.d.ts.map +1 -0
  61. package/dist/server/grok-home.js +145 -0
  62. package/dist/server/grok-home.js.map +1 -0
  63. package/dist/server/grok-home.test.d.ts +2 -0
  64. package/dist/server/grok-home.test.d.ts.map +1 -0
  65. package/dist/server/grok-home.test.js +109 -0
  66. package/dist/server/grok-home.test.js.map +1 -0
  67. package/dist/server/index.d.ts +12 -0
  68. package/dist/server/index.d.ts.map +1 -0
  69. package/dist/server/index.js +67 -0
  70. package/dist/server/index.js.map +1 -0
  71. package/dist/server/parse.d.ts +15 -0
  72. package/dist/server/parse.d.ts.map +1 -0
  73. package/dist/server/parse.js +93 -0
  74. package/dist/server/parse.js.map +1 -0
  75. package/dist/server/parse.test.d.ts +2 -0
  76. package/dist/server/parse.test.d.ts.map +1 -0
  77. package/dist/server/parse.test.js +82 -0
  78. package/dist/server/parse.test.js.map +1 -0
  79. package/dist/server/skills.d.ts +4 -0
  80. package/dist/server/skills.d.ts.map +1 -0
  81. package/dist/server/skills.js +21 -0
  82. package/dist/server/skills.js.map +1 -0
  83. package/dist/server/test.d.ts +9 -0
  84. package/dist/server/test.d.ts.map +1 -0
  85. package/dist/server/test.js +362 -0
  86. package/dist/server/test.js.map +1 -0
  87. package/dist/server/test.test.d.ts +2 -0
  88. package/dist/server/test.test.d.ts.map +1 -0
  89. package/dist/server/test.test.js +293 -0
  90. package/dist/server/test.test.js.map +1 -0
  91. package/dist/shared/turn-boundary.d.ts +7 -0
  92. package/dist/shared/turn-boundary.d.ts.map +1 -0
  93. package/dist/shared/turn-boundary.js +44 -0
  94. package/dist/shared/turn-boundary.js.map +1 -0
  95. package/dist/shared/turn-boundary.test.d.ts +2 -0
  96. package/dist/shared/turn-boundary.test.d.ts.map +1 -0
  97. package/dist/shared/turn-boundary.test.js +43 -0
  98. package/dist/shared/turn-boundary.test.js.map +1 -0
  99. package/dist/ui/build-config.d.ts +3 -0
  100. package/dist/ui/build-config.d.ts.map +1 -0
  101. package/dist/ui/build-config.js +29 -0
  102. package/dist/ui/build-config.js.map +1 -0
  103. package/dist/ui/build-config.test.d.ts +2 -0
  104. package/dist/ui/build-config.test.d.ts.map +1 -0
  105. package/dist/ui/build-config.test.js +26 -0
  106. package/dist/ui/build-config.test.js.map +1 -0
  107. package/dist/ui/index.d.ts +3 -0
  108. package/dist/ui/index.d.ts.map +1 -0
  109. package/dist/ui/index.js +3 -0
  110. package/dist/ui/index.js.map +1 -0
  111. package/dist/ui/parse-stdout.d.ts +7 -0
  112. package/dist/ui/parse-stdout.d.ts.map +1 -0
  113. package/dist/ui/parse-stdout.js +76 -0
  114. package/dist/ui/parse-stdout.js.map +1 -0
  115. package/dist/ui/parse-stdout.test.d.ts +2 -0
  116. package/dist/ui/parse-stdout.test.d.ts.map +1 -0
  117. package/dist/ui/parse-stdout.test.js +62 -0
  118. package/dist/ui/parse-stdout.test.js.map +1 -0
  119. package/package.json +58 -0
@@ -0,0 +1,563 @@
1
+ import { chmod, lstat, mkdir, mkdtemp, readdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+ import { assertUsableGrokAuthShape, checkStagedGrokCredentialReadiness, DeviceLoginReadinessError, promoteGrokDeviceLoginCredential, } from "./adapter-auth-promotion.js";
6
+ import { resolveManagedGrokHomeDir } from "./grok-home.js";
7
+ const COMPANY_A = "company-a";
8
+ const COMPANY_B = "company-b";
9
+ const ISSUER = "https://issuer.x.ai";
10
+ const UUID_A = "3fa85f64-5717-4562-b3fc-2c963f66afa6";
11
+ const UUID_B = "8f14e45f-ceea-467e-a4b6-8b0e12345678";
12
+ const TOKEN_SENTINEL = "SENTINEL_REFRESH_TOKEN_XYZ";
13
+ // This suite proves the Grok device-login credential promotion helper. It runs
14
+ // an independent readiness check on the exact staged credential first, then
15
+ // validates its shape, then writes only the company-scoped credential home. It
16
+ // writes only while the session holds the sole active claim on the slot, and
17
+ // only for a user-initiated login. For a home that already holds the SAME
18
+ // account, it installs the login only when the login is strictly newer than
19
+ // the existing credential (the same freshness predicate the teardown
20
+ // copy-back path uses), so it never replaces a fresher remote copy-back
21
+ // credential. It never writes the instance-global host, never crosses a
22
+ // company boundary, and never logs a secret.
23
+ describe("grok device-login credential promotion", () => {
24
+ const cleanupDirs = [];
25
+ afterEach(async () => {
26
+ while (cleanupDirs.length > 0) {
27
+ const dir = cleanupDirs.pop();
28
+ if (!dir)
29
+ continue;
30
+ await chmod(dir, 0o700).catch(() => undefined);
31
+ await rm(dir, { recursive: true, force: true }).catch(() => undefined);
32
+ }
33
+ });
34
+ async function makeInstanceRoot() {
35
+ const dir = await mkdtemp(path.join(os.tmpdir(), "paperclip-grok-promotion-"));
36
+ cleanupDirs.push(dir);
37
+ return dir;
38
+ }
39
+ function envFor(instanceHome) {
40
+ return {
41
+ PAPERCLIP_HOME: instanceHome,
42
+ PAPERCLIP_INSTANCE_ID: "default",
43
+ };
44
+ }
45
+ function grokAuth(input) {
46
+ const suffix = input.marker ?? input.uuid;
47
+ return Buffer.from(JSON.stringify({
48
+ [`${input.issuer ?? ISSUER}::${input.uuid}`]: {
49
+ key: `api-key-${suffix}`,
50
+ refresh_token: `${TOKEN_SENTINEL}-${suffix}`,
51
+ expires_at: input.expiresAt ?? "2026-01-01T00:00:00Z",
52
+ oidc_issuer: input.issuer ?? ISSUER,
53
+ oidc_client_id: "client-1",
54
+ email: `user-${suffix}@example.com`,
55
+ first_name: "Test",
56
+ last_name: "User",
57
+ user_id: `user-${suffix}`,
58
+ principal_id: `principal-${suffix}`,
59
+ team_id: `team-${suffix}`,
60
+ },
61
+ }));
62
+ }
63
+ const ready = () => ({ ready: true });
64
+ const notReady = () => ({ ready: false, reason: "auth_unusable" });
65
+ const soleOwner = () => true;
66
+ const notSoleOwner = () => false;
67
+ const noopLog = (_line) => { };
68
+ function companyHomeAuthPath(env, companyId) {
69
+ return path.join(resolveManagedGrokHomeDir(env, companyId), "auth.json");
70
+ }
71
+ // ---------------------------------------------------------------------
72
+ // Shape validation.
73
+ // ---------------------------------------------------------------------
74
+ describe("assertUsableGrokAuthShape", () => {
75
+ it("rejects empty bytes", () => {
76
+ expect(() => assertUsableGrokAuthShape(Buffer.alloc(0))).toThrow(/empty/);
77
+ });
78
+ it("rejects oversized bytes", () => {
79
+ const big = Buffer.alloc(64 * 1024 + 1, "a");
80
+ expect(() => assertUsableGrokAuthShape(big)).toThrow(/oversized/);
81
+ });
82
+ it("rejects invalid JSON", () => {
83
+ expect(() => assertUsableGrokAuthShape(Buffer.from("{not json"))).toThrow(/invalid JSON/);
84
+ });
85
+ it("rejects an object with no top-level key", () => {
86
+ expect(() => assertUsableGrokAuthShape(Buffer.from("{}"))).toThrow(/single/);
87
+ });
88
+ it("rejects an object with more than one top-level key", () => {
89
+ const bytes = Buffer.from(JSON.stringify({
90
+ [`${ISSUER}::${UUID_A}`]: { key: "k", refresh_token: "r" },
91
+ [`${ISSUER}::${UUID_B}`]: { key: "k2", refresh_token: "r2" },
92
+ }));
93
+ expect(() => assertUsableGrokAuthShape(bytes)).toThrow(/single/);
94
+ });
95
+ it("rejects a key that does not match the <issuer>::<uuid> shape", () => {
96
+ const bytes = Buffer.from(JSON.stringify({ some_fixed_key: { key: "k", refresh_token: "r" } }));
97
+ expect(() => assertUsableGrokAuthShape(bytes)).toThrow(/single/);
98
+ });
99
+ it("rejects a value with no usable key or refresh_token", () => {
100
+ const bytes = Buffer.from(JSON.stringify({ [`${ISSUER}::${UUID_A}`]: { key: "k" } }));
101
+ expect(() => assertUsableGrokAuthShape(bytes)).toThrow(/usable/);
102
+ });
103
+ it("accepts an object whose single key matches <issuer>::<uuid> and holds key + refresh_token", () => {
104
+ const payload = assertUsableGrokAuthShape(grokAuth({ uuid: UUID_A }));
105
+ expect(payload.identityKey).toBe(`${ISSUER}::${UUID_A}`);
106
+ expect(payload.value.key).toBe(`api-key-${UUID_A}`);
107
+ });
108
+ });
109
+ // ---------------------------------------------------------------------
110
+ // Readiness.
111
+ // ---------------------------------------------------------------------
112
+ describe("checkStagedGrokCredentialReadiness", () => {
113
+ it("reports not ready for empty bytes", async () => {
114
+ const result = await checkStagedGrokCredentialReadiness(Buffer.alloc(0));
115
+ expect(result.ready).toBe(false);
116
+ });
117
+ it("reports not ready for a Codex-shaped payload", async () => {
118
+ const codexShaped = Buffer.from(JSON.stringify({ OPENAI_API_KEY: "sk-test" }));
119
+ const result = await checkStagedGrokCredentialReadiness(codexShaped);
120
+ expect(result.ready).toBe(false);
121
+ expect(result.reason).toBe("no_usable_auth");
122
+ });
123
+ it("reports ready for a usable Grok payload", async () => {
124
+ const result = await checkStagedGrokCredentialReadiness(grokAuth({ uuid: UUID_A }));
125
+ expect(result.ready).toBe(true);
126
+ });
127
+ });
128
+ // ---------------------------------------------------------------------
129
+ // The promotion order and gates.
130
+ // ---------------------------------------------------------------------
131
+ it("a failed readiness check rejects and writes nothing", async () => {
132
+ const home = await makeInstanceRoot();
133
+ const env = envFor(home);
134
+ const logs = [];
135
+ await expect(promoteGrokDeviceLoginCredential({
136
+ authBytes: grokAuth({ uuid: UUID_A }),
137
+ companyId: COMPANY_A,
138
+ userInitiated: true,
139
+ checkReadiness: notReady,
140
+ isSoleActiveOwner: soleOwner,
141
+ env,
142
+ log: (line) => {
143
+ logs.push(line);
144
+ },
145
+ })).rejects.toBeInstanceOf(DeviceLoginReadinessError);
146
+ await expect(lstat(companyHomeAuthPath(env, COMPANY_A))).rejects.toThrow();
147
+ expect(logs.join("\n")).not.toContain(TOKEN_SENTINEL);
148
+ expect(logs.join("\n")).not.toContain("example.com");
149
+ });
150
+ it("an invalid shape rejects after a passed readiness check and writes nothing", async () => {
151
+ const home = await makeInstanceRoot();
152
+ const env = envFor(home);
153
+ await expect(promoteGrokDeviceLoginCredential({
154
+ authBytes: Buffer.from("{}"),
155
+ companyId: COMPANY_A,
156
+ userInitiated: true,
157
+ checkReadiness: ready,
158
+ isSoleActiveOwner: soleOwner,
159
+ env,
160
+ log: noopLog,
161
+ })).rejects.toThrow(/single/);
162
+ await expect(lstat(companyHomeAuthPath(env, COMPANY_A))).rejects.toThrow();
163
+ });
164
+ it("skips a background (non-user-initiated) login and writes nothing", async () => {
165
+ const home = await makeInstanceRoot();
166
+ const env = envFor(home);
167
+ const outcome = await promoteGrokDeviceLoginCredential({
168
+ authBytes: grokAuth({ uuid: UUID_A }),
169
+ companyId: COMPANY_A,
170
+ userInitiated: false,
171
+ checkReadiness: ready,
172
+ isSoleActiveOwner: soleOwner,
173
+ env,
174
+ log: noopLog,
175
+ });
176
+ expect(outcome).toBe("background_skipped");
177
+ await expect(lstat(companyHomeAuthPath(env, COMPANY_A))).rejects.toThrow();
178
+ });
179
+ it("skips a session that lost the sole active claim and writes nothing", async () => {
180
+ const home = await makeInstanceRoot();
181
+ const env = envFor(home);
182
+ const outcome = await promoteGrokDeviceLoginCredential({
183
+ authBytes: grokAuth({ uuid: UUID_A }),
184
+ companyId: COMPANY_A,
185
+ userInitiated: true,
186
+ checkReadiness: ready,
187
+ isSoleActiveOwner: notSoleOwner,
188
+ env,
189
+ log: noopLog,
190
+ });
191
+ expect(outcome).toBe("not_sole_owner");
192
+ await expect(lstat(companyHomeAuthPath(env, COMPANY_A))).rejects.toThrow();
193
+ });
194
+ it("creates the company Grok home at mode 0700 and writes auth.json at exact mode 0600", async () => {
195
+ const home = await makeInstanceRoot();
196
+ const env = envFor(home);
197
+ const outcome = await promoteGrokDeviceLoginCredential({
198
+ authBytes: grokAuth({ uuid: UUID_A }),
199
+ companyId: COMPANY_A,
200
+ userInitiated: true,
201
+ checkReadiness: ready,
202
+ isSoleActiveOwner: soleOwner,
203
+ env,
204
+ log: noopLog,
205
+ });
206
+ expect(outcome).toBe("promoted");
207
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
208
+ const dirStat = await lstat(companyHome);
209
+ expect(dirStat.mode & 0o777).toBe(0o700);
210
+ const authPath = path.join(companyHome, "auth.json");
211
+ const fileStat = await lstat(authPath);
212
+ expect(fileStat.mode & 0o777).toBe(0o600);
213
+ const written = JSON.parse(await readFile(authPath, "utf8"));
214
+ expect(Object.keys(written)).toEqual([`${ISSUER}::${UUID_A}`]);
215
+ });
216
+ it("normalizes the company Grok home to mode 0700 when the home already exists at a broader mode", async () => {
217
+ const home = await makeInstanceRoot();
218
+ const env = envFor(home);
219
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
220
+ await mkdir(companyHome, { recursive: true, mode: 0o755 });
221
+ const outcome = await promoteGrokDeviceLoginCredential({
222
+ authBytes: grokAuth({ uuid: UUID_A }),
223
+ companyId: COMPANY_A,
224
+ userInitiated: true,
225
+ checkReadiness: ready,
226
+ isSoleActiveOwner: soleOwner,
227
+ env,
228
+ log: noopLog,
229
+ });
230
+ expect(outcome).toBe("promoted");
231
+ const dirStat = await lstat(companyHome);
232
+ expect(dirStat.mode & 0o777).toBe(0o700);
233
+ const authPath = path.join(companyHome, "auth.json");
234
+ const fileStat = await lstat(authPath);
235
+ expect(fileStat.mode & 0o777).toBe(0o600);
236
+ });
237
+ it("keeps an occupied home that holds a different identity", async () => {
238
+ const home = await makeInstanceRoot();
239
+ const env = envFor(home);
240
+ const first = await promoteGrokDeviceLoginCredential({
241
+ authBytes: grokAuth({ uuid: UUID_A }),
242
+ companyId: COMPANY_A,
243
+ userInitiated: true,
244
+ checkReadiness: ready,
245
+ isSoleActiveOwner: soleOwner,
246
+ env,
247
+ log: noopLog,
248
+ });
249
+ expect(first).toBe("promoted");
250
+ const second = await promoteGrokDeviceLoginCredential({
251
+ authBytes: grokAuth({ uuid: UUID_B }),
252
+ companyId: COMPANY_A,
253
+ userInitiated: true,
254
+ checkReadiness: ready,
255
+ isSoleActiveOwner: soleOwner,
256
+ env,
257
+ log: noopLog,
258
+ });
259
+ expect(second).toBe("kept_foreign_identity");
260
+ const authPath = companyHomeAuthPath(env, COMPANY_A);
261
+ const written = JSON.parse(await readFile(authPath, "utf8"));
262
+ expect(Object.keys(written)).toEqual([`${ISSUER}::${UUID_A}`]);
263
+ });
264
+ it("redacts the credential bytes and the account email the same way on a promoted and on a kept_foreign_identity outcome", async () => {
265
+ const home = await makeInstanceRoot();
266
+ const env = envFor(home);
267
+ const logs = [];
268
+ const captureLog = (line) => {
269
+ logs.push(line);
270
+ };
271
+ const promoted = await promoteGrokDeviceLoginCredential({
272
+ authBytes: grokAuth({ uuid: UUID_A }),
273
+ companyId: COMPANY_A,
274
+ userInitiated: true,
275
+ checkReadiness: ready,
276
+ isSoleActiveOwner: soleOwner,
277
+ env,
278
+ log: captureLog,
279
+ });
280
+ expect(promoted).toBe("promoted");
281
+ const keptForeign = await promoteGrokDeviceLoginCredential({
282
+ authBytes: grokAuth({ uuid: UUID_B }),
283
+ companyId: COMPANY_A,
284
+ userInitiated: true,
285
+ checkReadiness: ready,
286
+ isSoleActiveOwner: soleOwner,
287
+ env,
288
+ log: captureLog,
289
+ });
290
+ expect(keptForeign).toBe("kept_foreign_identity");
291
+ const allLogs = logs.join("\n");
292
+ expect(allLogs).not.toContain(TOKEN_SENTINEL);
293
+ expect(allLogs).not.toContain(`user-${UUID_A}@example.com`);
294
+ expect(allLogs).not.toContain(`user-${UUID_B}@example.com`);
295
+ expect(allLogs).not.toContain(UUID_A);
296
+ expect(allLogs).not.toContain(UUID_B);
297
+ });
298
+ it("overwrites the home with a strictly newer credential for the same identity", async () => {
299
+ const home = await makeInstanceRoot();
300
+ const env = envFor(home);
301
+ await promoteGrokDeviceLoginCredential({
302
+ authBytes: grokAuth({ uuid: UUID_A, marker: "first", expiresAt: "2026-01-01T00:00:00Z" }),
303
+ companyId: COMPANY_A,
304
+ userInitiated: true,
305
+ checkReadiness: ready,
306
+ isSoleActiveOwner: soleOwner,
307
+ env,
308
+ log: noopLog,
309
+ });
310
+ const outcome = await promoteGrokDeviceLoginCredential({
311
+ authBytes: grokAuth({ uuid: UUID_A, marker: "second", expiresAt: "2026-06-01T00:00:00Z" }),
312
+ companyId: COMPANY_A,
313
+ userInitiated: true,
314
+ checkReadiness: ready,
315
+ isSoleActiveOwner: soleOwner,
316
+ env,
317
+ log: noopLog,
318
+ });
319
+ expect(outcome).toBe("promoted");
320
+ const authPath = companyHomeAuthPath(env, COMPANY_A);
321
+ const written = JSON.parse(await readFile(authPath, "utf8"));
322
+ expect(written[`${ISSUER}::${UUID_A}`].refresh_token).toBe(`${TOKEN_SENTINEL}-second`);
323
+ });
324
+ // ---------------------------------------------------------------------
325
+ // The freshness gate: a same-identity login never replaces a home
326
+ // credential that is at least as new, so a remote copy-back cannot lose
327
+ // its fresher credential to an older device login.
328
+ // ---------------------------------------------------------------------
329
+ it("keeps the home when the login is older than the existing same-identity credential", async () => {
330
+ const home = await makeInstanceRoot();
331
+ const env = envFor(home);
332
+ await promoteGrokDeviceLoginCredential({
333
+ authBytes: grokAuth({ uuid: UUID_A, marker: "fresher", expiresAt: "2026-06-01T00:00:00Z" }),
334
+ companyId: COMPANY_A,
335
+ userInitiated: true,
336
+ checkReadiness: ready,
337
+ isSoleActiveOwner: soleOwner,
338
+ env,
339
+ log: noopLog,
340
+ });
341
+ const outcome = await promoteGrokDeviceLoginCredential({
342
+ authBytes: grokAuth({ uuid: UUID_A, marker: "staler", expiresAt: "2026-01-01T00:00:00Z" }),
343
+ companyId: COMPANY_A,
344
+ userInitiated: true,
345
+ checkReadiness: ready,
346
+ isSoleActiveOwner: soleOwner,
347
+ env,
348
+ log: noopLog,
349
+ });
350
+ expect(outcome).toBe("kept");
351
+ const authPath = companyHomeAuthPath(env, COMPANY_A);
352
+ const written = JSON.parse(await readFile(authPath, "utf8"));
353
+ expect(written[`${ISSUER}::${UUID_A}`].refresh_token).toBe(`${TOKEN_SENTINEL}-fresher`);
354
+ });
355
+ it("keeps the home when the login expiry ties the existing same-identity credential", async () => {
356
+ const home = await makeInstanceRoot();
357
+ const env = envFor(home);
358
+ await promoteGrokDeviceLoginCredential({
359
+ authBytes: grokAuth({ uuid: UUID_A, marker: "first", expiresAt: "2026-01-01T00:00:00Z" }),
360
+ companyId: COMPANY_A,
361
+ userInitiated: true,
362
+ checkReadiness: ready,
363
+ isSoleActiveOwner: soleOwner,
364
+ env,
365
+ log: noopLog,
366
+ });
367
+ const outcome = await promoteGrokDeviceLoginCredential({
368
+ authBytes: grokAuth({ uuid: UUID_A, marker: "second", expiresAt: "2026-01-01T00:00:00Z" }),
369
+ companyId: COMPANY_A,
370
+ userInitiated: true,
371
+ checkReadiness: ready,
372
+ isSoleActiveOwner: soleOwner,
373
+ env,
374
+ log: noopLog,
375
+ });
376
+ expect(outcome).toBe("kept");
377
+ const authPath = companyHomeAuthPath(env, COMPANY_A);
378
+ const written = JSON.parse(await readFile(authPath, "utf8"));
379
+ expect(written[`${ISSUER}::${UUID_A}`].refresh_token).toBe(`${TOKEN_SENTINEL}-first`);
380
+ });
381
+ it("leaves no staged temporary file in the company home after a kept (not-fresher) outcome", async () => {
382
+ const home = await makeInstanceRoot();
383
+ const env = envFor(home);
384
+ await promoteGrokDeviceLoginCredential({
385
+ authBytes: grokAuth({ uuid: UUID_A, marker: "fresher", expiresAt: "2026-06-01T00:00:00Z" }),
386
+ companyId: COMPANY_A,
387
+ userInitiated: true,
388
+ checkReadiness: ready,
389
+ isSoleActiveOwner: soleOwner,
390
+ env,
391
+ log: noopLog,
392
+ });
393
+ const outcome = await promoteGrokDeviceLoginCredential({
394
+ authBytes: grokAuth({ uuid: UUID_A, marker: "staler", expiresAt: "2026-01-01T00:00:00Z" }),
395
+ companyId: COMPANY_A,
396
+ userInitiated: true,
397
+ checkReadiness: ready,
398
+ isSoleActiveOwner: soleOwner,
399
+ env,
400
+ log: noopLog,
401
+ });
402
+ expect(outcome).toBe("kept");
403
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
404
+ const entries = await readdir(companyHome);
405
+ expect(entries).toEqual(["auth.json"]);
406
+ });
407
+ it("redacts the credential bytes on a kept (not-fresher) outcome the same way as a promoted outcome", async () => {
408
+ const home = await makeInstanceRoot();
409
+ const env = envFor(home);
410
+ const logs = [];
411
+ const captureLog = (line) => {
412
+ logs.push(line);
413
+ };
414
+ await promoteGrokDeviceLoginCredential({
415
+ authBytes: grokAuth({ uuid: UUID_A, marker: "fresher", expiresAt: "2026-06-01T00:00:00Z" }),
416
+ companyId: COMPANY_A,
417
+ userInitiated: true,
418
+ checkReadiness: ready,
419
+ isSoleActiveOwner: soleOwner,
420
+ env,
421
+ log: captureLog,
422
+ });
423
+ const outcome = await promoteGrokDeviceLoginCredential({
424
+ authBytes: grokAuth({ uuid: UUID_A, marker: "staler", expiresAt: "2026-01-01T00:00:00Z" }),
425
+ companyId: COMPANY_A,
426
+ userInitiated: true,
427
+ checkReadiness: ready,
428
+ isSoleActiveOwner: soleOwner,
429
+ env,
430
+ log: captureLog,
431
+ });
432
+ expect(outcome).toBe("kept");
433
+ const allLogs = logs.join("\n");
434
+ expect(allLogs).not.toContain(TOKEN_SENTINEL);
435
+ expect(allLogs).not.toContain(`user-fresher@example.com`);
436
+ expect(allLogs).not.toContain(`user-staler@example.com`);
437
+ expect(allLogs).not.toContain(UUID_A);
438
+ });
439
+ // ---------------------------------------------------------------------
440
+ // Fail closed on an unreadable or unparseable existing home.
441
+ // ---------------------------------------------------------------------
442
+ it("keeps a home whose auth.json holds corrupt JSON, and writes nothing", async () => {
443
+ const home = await makeInstanceRoot();
444
+ const env = envFor(home);
445
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
446
+ await mkdir(companyHome, { recursive: true, mode: 0o700 });
447
+ const authPath = path.join(companyHome, "auth.json");
448
+ const corruptBytes = Buffer.from("{not valid json");
449
+ await writeFile(authPath, corruptBytes, { mode: 0o600 });
450
+ const outcome = await promoteGrokDeviceLoginCredential({
451
+ authBytes: grokAuth({ uuid: UUID_A }),
452
+ companyId: COMPANY_A,
453
+ userInitiated: true,
454
+ checkReadiness: ready,
455
+ isSoleActiveOwner: soleOwner,
456
+ env,
457
+ log: noopLog,
458
+ });
459
+ expect(outcome).toBe("kept_foreign_identity");
460
+ const afterBytes = await readFile(authPath);
461
+ expect(afterBytes.equals(corruptBytes)).toBe(true);
462
+ });
463
+ it("keeps a home whose auth.json holds a well-formed but unusable payload, and writes nothing", async () => {
464
+ const home = await makeInstanceRoot();
465
+ const env = envFor(home);
466
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
467
+ await mkdir(companyHome, { recursive: true, mode: 0o700 });
468
+ const authPath = path.join(companyHome, "auth.json");
469
+ const unusableBytes = Buffer.from(JSON.stringify({ some_fixed_key: { key: "k" } }));
470
+ await writeFile(authPath, unusableBytes, { mode: 0o600 });
471
+ const outcome = await promoteGrokDeviceLoginCredential({
472
+ authBytes: grokAuth({ uuid: UUID_A }),
473
+ companyId: COMPANY_A,
474
+ userInitiated: true,
475
+ checkReadiness: ready,
476
+ isSoleActiveOwner: soleOwner,
477
+ env,
478
+ log: noopLog,
479
+ });
480
+ expect(outcome).toBe("kept_foreign_identity");
481
+ const afterBytes = await readFile(authPath);
482
+ expect(afterBytes.equals(unusableBytes)).toBe(true);
483
+ });
484
+ // ---------------------------------------------------------------------
485
+ // Atomic write.
486
+ // ---------------------------------------------------------------------
487
+ it("leaves no staged temporary file in the company home after a successful promotion", async () => {
488
+ const home = await makeInstanceRoot();
489
+ const env = envFor(home);
490
+ const outcome = await promoteGrokDeviceLoginCredential({
491
+ authBytes: grokAuth({ uuid: UUID_A }),
492
+ companyId: COMPANY_A,
493
+ userInitiated: true,
494
+ checkReadiness: ready,
495
+ isSoleActiveOwner: soleOwner,
496
+ env,
497
+ log: noopLog,
498
+ });
499
+ expect(outcome).toBe("promoted");
500
+ const companyHome = resolveManagedGrokHomeDir(env, COMPANY_A);
501
+ const entries = await readdir(companyHome);
502
+ expect(entries).toEqual(["auth.json"]);
503
+ });
504
+ // ---------------------------------------------------------------------
505
+ // Company isolation.
506
+ // ---------------------------------------------------------------------
507
+ it("a promotion for company A creates no file, replaces no file, and reads no file under company B's home", async () => {
508
+ const home = await makeInstanceRoot();
509
+ const env = envFor(home);
510
+ // Seed company B's home first, so a read-through would be observable.
511
+ const companyBHome = resolveManagedGrokHomeDir(env, COMPANY_B);
512
+ await mkdir(companyBHome, { recursive: true, mode: 0o700 });
513
+ const companyBAuthPath = path.join(companyBHome, "auth.json");
514
+ const companyBBytes = grokAuth({ uuid: UUID_B });
515
+ await writeFile(companyBAuthPath, companyBBytes, { mode: 0o600 });
516
+ const beforeBBytes = await readFile(companyBAuthPath);
517
+ const outcome = await promoteGrokDeviceLoginCredential({
518
+ authBytes: grokAuth({ uuid: UUID_A }),
519
+ companyId: COMPANY_A,
520
+ userInitiated: true,
521
+ checkReadiness: ready,
522
+ isSoleActiveOwner: soleOwner,
523
+ env,
524
+ log: noopLog,
525
+ });
526
+ expect(outcome).toBe("promoted");
527
+ // Company A's write landed only under company A's home.
528
+ const companyAAuthPath = companyHomeAuthPath(env, COMPANY_A);
529
+ expect(resolveManagedGrokHomeDir(env, COMPANY_A)).not.toBe(companyBHome);
530
+ await expect(lstat(companyAAuthPath)).resolves.toBeDefined();
531
+ // Company B's home is byte-identical to before the company A promotion.
532
+ const afterBBytes = await readFile(companyBAuthPath);
533
+ expect(afterBBytes.equals(beforeBBytes)).toBe(true);
534
+ });
535
+ it("rejects a companyId that holds a path separator", async () => {
536
+ const home = await makeInstanceRoot();
537
+ const env = envFor(home);
538
+ await expect(promoteGrokDeviceLoginCredential({
539
+ authBytes: grokAuth({ uuid: UUID_A }),
540
+ companyId: `${COMPANY_A}/../${COMPANY_B}`,
541
+ userInitiated: true,
542
+ checkReadiness: ready,
543
+ isSoleActiveOwner: soleOwner,
544
+ env,
545
+ log: noopLog,
546
+ })).rejects.toThrow(/path separator/);
547
+ await expect(lstat(resolveManagedGrokHomeDir(env, COMPANY_B))).rejects.toThrow();
548
+ });
549
+ it("rejects a companyId that is a parent-directory segment", async () => {
550
+ const home = await makeInstanceRoot();
551
+ const env = envFor(home);
552
+ await expect(promoteGrokDeviceLoginCredential({
553
+ authBytes: grokAuth({ uuid: UUID_A }),
554
+ companyId: "..",
555
+ userInitiated: true,
556
+ checkReadiness: ready,
557
+ isSoleActiveOwner: soleOwner,
558
+ env,
559
+ log: noopLog,
560
+ })).rejects.toThrow(/relative path segment/);
561
+ });
562
+ });
563
+ //# sourceMappingURL=adapter-auth-promotion.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-auth-promotion.test.js","sourceRoot":"","sources":["../../src/server/adapter-auth-promotion.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface DeviceLoginPrompt {
2
+ url: string;
3
+ code: string;
4
+ }
5
+ /** The one and only accepted device-login command. */
6
+ export declare const GROK_DEVICE_LOGIN_COMMAND = "grok login --device-auth";
7
+ /** The one and only accepted device-login URL origin. */
8
+ export declare const GROK_DEVICE_LOGIN_URL_ORIGIN = "https://accounts.x.ai";
9
+ /** The one and only accepted device-login URL path. */
10
+ export declare const GROK_DEVICE_LOGIN_URL_PATH = "/oauth2/device";
11
+ /**
12
+ * Parses Grok device-login output. Removes ANSI color sequences first. The
13
+ * parser reads the URL first, validates its query and its embedded code, then
14
+ * finds the code preamble after the URL and reads the code from the dedicated
15
+ * code line right after the preamble line. It returns the prompt only when the
16
+ * code on that dedicated line equals the code the URL query carries. Returns
17
+ * null for any other input, including a non-string input, an absent prompt, a
18
+ * wrong origin or path, a URL with a fragment, a malformed or mismatched query,
19
+ * and a malformed short code. Never throws on input, and never puts the URL or
20
+ * the code into a log or an error.
21
+ */
22
+ export declare function parseGrokDeviceLoginPrompt(text: string): DeviceLoginPrompt | null;
23
+ //# sourceMappingURL=device-login-parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login-parse.d.ts","sourceRoot":"","sources":["../../src/server/device-login-parse.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,sDAAsD;AACtD,eAAO,MAAM,yBAAyB,6BAA6B,CAAC;AAEpE,yDAAyD;AACzD,eAAO,MAAM,4BAA4B,0BAA0B,CAAC;AAEpE,uDAAuD;AACvD,eAAO,MAAM,0BAA0B,mBAAmB,CAAC;AAsH3D;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CASjF"}