@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.
- package/LICENSE +22 -0
- package/dist/cli/format-event.d.ts +2 -0
- package/dist/cli/format-event.d.ts.map +1 -0
- package/dist/cli/format-event.js +55 -0
- package/dist/cli/format-event.js.map +1 -0
- package/dist/cli/format-event.test.d.ts +2 -0
- package/dist/cli/format-event.test.d.ts.map +1 -0
- package/dist/cli/format-event.test.js +19 -0
- package/dist/cli/format-event.test.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/server/adapter-auth-promotion.d.ts +87 -0
- package/dist/server/adapter-auth-promotion.d.ts.map +1 -0
- package/dist/server/adapter-auth-promotion.js +294 -0
- package/dist/server/adapter-auth-promotion.js.map +1 -0
- package/dist/server/adapter-auth-promotion.test.d.ts +2 -0
- package/dist/server/adapter-auth-promotion.test.d.ts.map +1 -0
- package/dist/server/adapter-auth-promotion.test.js +563 -0
- package/dist/server/adapter-auth-promotion.test.js.map +1 -0
- package/dist/server/device-login-parse.d.ts +23 -0
- package/dist/server/device-login-parse.d.ts.map +1 -0
- package/dist/server/device-login-parse.js +148 -0
- package/dist/server/device-login-parse.js.map +1 -0
- package/dist/server/device-login-parse.test.d.ts +2 -0
- package/dist/server/device-login-parse.test.d.ts.map +1 -0
- package/dist/server/device-login-parse.test.js +146 -0
- package/dist/server/device-login-parse.test.js.map +1 -0
- package/dist/server/execute.d.ts +3 -0
- package/dist/server/execute.d.ts.map +1 -0
- package/dist/server/execute.js +572 -0
- package/dist/server/execute.js.map +1 -0
- package/dist/server/execute.test.d.ts +2 -0
- package/dist/server/execute.test.d.ts.map +1 -0
- package/dist/server/execute.test.js +731 -0
- package/dist/server/execute.test.js.map +1 -0
- package/dist/server/grok-auth-copyback.d.ts +48 -0
- package/dist/server/grok-auth-copyback.d.ts.map +1 -0
- package/dist/server/grok-auth-copyback.js +92 -0
- package/dist/server/grok-auth-copyback.js.map +1 -0
- package/dist/server/grok-auth-copyback.test.d.ts +2 -0
- package/dist/server/grok-auth-copyback.test.d.ts.map +1 -0
- package/dist/server/grok-auth-copyback.test.js +246 -0
- package/dist/server/grok-auth-copyback.test.js.map +1 -0
- package/dist/server/grok-auth-merge-decision.cjs +157 -0
- package/dist/server/grok-auth-merge-decision.d.ts +21 -0
- package/dist/server/grok-auth-merge-decision.d.ts.map +1 -0
- package/dist/server/grok-auth-merge-decision.js +58 -0
- package/dist/server/grok-auth-merge-decision.js.map +1 -0
- package/dist/server/grok-auth-merge-decision.test.d.ts +2 -0
- package/dist/server/grok-auth-merge-decision.test.d.ts.map +1 -0
- package/dist/server/grok-auth-merge-decision.test.js +189 -0
- package/dist/server/grok-auth-merge-decision.test.js.map +1 -0
- package/dist/server/grok-home.d.ts +57 -0
- package/dist/server/grok-home.d.ts.map +1 -0
- package/dist/server/grok-home.js +145 -0
- package/dist/server/grok-home.js.map +1 -0
- package/dist/server/grok-home.test.d.ts +2 -0
- package/dist/server/grok-home.test.d.ts.map +1 -0
- package/dist/server/grok-home.test.js +109 -0
- package/dist/server/grok-home.test.js.map +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +67 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/parse.d.ts +15 -0
- package/dist/server/parse.d.ts.map +1 -0
- package/dist/server/parse.js +93 -0
- package/dist/server/parse.js.map +1 -0
- package/dist/server/parse.test.d.ts +2 -0
- package/dist/server/parse.test.d.ts.map +1 -0
- package/dist/server/parse.test.js +82 -0
- package/dist/server/parse.test.js.map +1 -0
- package/dist/server/skills.d.ts +4 -0
- package/dist/server/skills.d.ts.map +1 -0
- package/dist/server/skills.js +21 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/test.d.ts +9 -0
- package/dist/server/test.d.ts.map +1 -0
- package/dist/server/test.js +362 -0
- package/dist/server/test.js.map +1 -0
- package/dist/server/test.test.d.ts +2 -0
- package/dist/server/test.test.d.ts.map +1 -0
- package/dist/server/test.test.js +293 -0
- package/dist/server/test.test.js.map +1 -0
- package/dist/shared/turn-boundary.d.ts +7 -0
- package/dist/shared/turn-boundary.d.ts.map +1 -0
- package/dist/shared/turn-boundary.js +44 -0
- package/dist/shared/turn-boundary.js.map +1 -0
- package/dist/shared/turn-boundary.test.d.ts +2 -0
- package/dist/shared/turn-boundary.test.d.ts.map +1 -0
- package/dist/shared/turn-boundary.test.js +43 -0
- package/dist/shared/turn-boundary.test.js.map +1 -0
- package/dist/ui/build-config.d.ts +3 -0
- package/dist/ui/build-config.d.ts.map +1 -0
- package/dist/ui/build-config.js +29 -0
- package/dist/ui/build-config.js.map +1 -0
- package/dist/ui/build-config.test.d.ts +2 -0
- package/dist/ui/build-config.test.d.ts.map +1 -0
- package/dist/ui/build-config.test.js +26 -0
- package/dist/ui/build-config.test.js.map +1 -0
- package/dist/ui/index.d.ts +3 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +3 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/parse-stdout.d.ts +7 -0
- package/dist/ui/parse-stdout.d.ts.map +1 -0
- package/dist/ui/parse-stdout.js +76 -0
- package/dist/ui/parse-stdout.js.map +1 -0
- package/dist/ui/parse-stdout.test.d.ts +2 -0
- package/dist/ui/parse-stdout.test.d.ts.map +1 -0
- package/dist/ui/parse-stdout.test.js +62 -0
- package/dist/ui/parse-stdout.test.js.map +1 -0
- 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"}
|