@agentmeshhq/agent 0.4.5 → 0.4.10
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/dist/__tests__/auth-doctor-integration.test.d.ts +14 -0
- package/dist/__tests__/auth-doctor-integration.test.js +130 -0
- package/dist/__tests__/auth-doctor-integration.test.js.map +1 -0
- package/dist/__tests__/auth-guard.integration.test.d.ts +12 -0
- package/dist/__tests__/auth-guard.integration.test.js +132 -0
- package/dist/__tests__/auth-guard.integration.test.js.map +1 -0
- package/dist/__tests__/auth-guard.test.d.ts +17 -0
- package/dist/__tests__/auth-guard.test.js +483 -0
- package/dist/__tests__/auth-guard.test.js.map +1 -0
- package/dist/__tests__/done-state-guard.integration.test.d.ts +1 -0
- package/dist/__tests__/done-state-guard.integration.test.js +281 -0
- package/dist/__tests__/done-state-guard.integration.test.js.map +1 -0
- package/dist/__tests__/done-state-guard.test.d.ts +1 -0
- package/dist/__tests__/done-state-guard.test.js +327 -0
- package/dist/__tests__/done-state-guard.test.js.map +1 -0
- package/dist/__tests__/session-recovery.test.d.ts +1 -0
- package/dist/__tests__/session-recovery.test.js +16 -0
- package/dist/__tests__/session-recovery.test.js.map +1 -0
- package/dist/__tests__/tmux-runtime.test.d.ts +1 -0
- package/dist/__tests__/tmux-runtime.test.js +113 -0
- package/dist/__tests__/tmux-runtime.test.js.map +1 -0
- package/dist/cli/auth.d.ts +11 -0
- package/dist/cli/auth.js +92 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/index.js +45 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/local.d.ts +4 -2
- package/dist/cli/local.js +257 -108
- package/dist/cli/local.js.map +1 -1
- package/dist/cli/migrate.d.ts +1 -0
- package/dist/cli/migrate.js +14 -10
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/start.d.ts +2 -0
- package/dist/cli/start.js +3 -0
- package/dist/cli/start.js.map +1 -1
- package/dist/cli/test.d.ts +1 -0
- package/dist/cli/test.js +15 -9
- package/dist/cli/test.js.map +1 -1
- package/dist/config/schema.d.ts +11 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/core/auth-guard.d.ts +155 -0
- package/dist/core/auth-guard.js +498 -0
- package/dist/core/auth-guard.js.map +1 -0
- package/dist/core/auth-sync.d.ts +105 -0
- package/dist/core/auth-sync.js +263 -0
- package/dist/core/auth-sync.js.map +1 -0
- package/dist/core/daemon/context-template.js +65 -0
- package/dist/core/daemon/context-template.js.map +1 -1
- package/dist/core/daemon/done-state-guard.d.ts +63 -0
- package/dist/core/daemon/done-state-guard.js +102 -0
- package/dist/core/daemon/done-state-guard.js.map +1 -0
- package/dist/core/daemon/session-recovery.d.ts +1 -0
- package/dist/core/daemon/session-recovery.js +7 -0
- package/dist/core/daemon/session-recovery.js.map +1 -0
- package/dist/core/daemon/tmux-session.d.ts +1 -0
- package/dist/core/daemon/tmux-session.js +1 -1
- package/dist/core/daemon/tmux-session.js.map +1 -1
- package/dist/core/daemon.d.ts +18 -1
- package/dist/core/daemon.js +220 -35
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/registry.d.ts +9 -1
- package/dist/core/registry.js +28 -1
- package/dist/core/registry.js.map +1 -1
- package/dist/core/tmux-runtime.d.ts +11 -2
- package/dist/core/tmux-runtime.js +45 -19
- package/dist/core/tmux-runtime.js.map +1 -1
- package/dist/core/tmux.d.ts +1 -1
- package/dist/core/tmux.js +7 -3
- package/dist/core/tmux.js.map +1 -1
- package/package.json +12 -11
- package/LICENSE +0 -21
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test: auth-sync stale profile → repair → success
|
|
3
|
+
*
|
|
4
|
+
* Simulates the full Epic #470 recovery path:
|
|
5
|
+
* 1. Agent has a stale regular-file auth.json (not a symlink).
|
|
6
|
+
* 2. Canonical auth.json exists and is valid.
|
|
7
|
+
* 3. ensureAuthLink detects the stale file, backs it up, and creates a symlink.
|
|
8
|
+
* 4. preflightAuth now passes.
|
|
9
|
+
* 5. A second call to ensureAuthLink is idempotent (symlink-ok).
|
|
10
|
+
*
|
|
11
|
+
* All functions accept an optional `homeDir` parameter so tests can sandbox
|
|
12
|
+
* operations under a tmp directory instead of touching the real home directory.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test: auth-sync stale profile → repair → success
|
|
3
|
+
*
|
|
4
|
+
* Simulates the full Epic #470 recovery path:
|
|
5
|
+
* 1. Agent has a stale regular-file auth.json (not a symlink).
|
|
6
|
+
* 2. Canonical auth.json exists and is valid.
|
|
7
|
+
* 3. ensureAuthLink detects the stale file, backs it up, and creates a symlink.
|
|
8
|
+
* 4. preflightAuth now passes.
|
|
9
|
+
* 5. A second call to ensureAuthLink is idempotent (symlink-ok).
|
|
10
|
+
*
|
|
11
|
+
* All functions accept an optional `homeDir` parameter so tests can sandbox
|
|
12
|
+
* operations under a tmp directory instead of touching the real home directory.
|
|
13
|
+
*/
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
18
|
+
import { ensureAuthLink, getAuthLinkStatus, preflightAuth } from "../core/auth-sync.js";
|
|
19
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
20
|
+
function makeTmpDir() {
|
|
21
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "auth-doctor-integration-"));
|
|
22
|
+
}
|
|
23
|
+
function agentAuthPathFor(base, agentName) {
|
|
24
|
+
return path.join(base, ".agentmesh", "opencode-data", agentName, "opencode", "auth.json");
|
|
25
|
+
}
|
|
26
|
+
function canonicalPathFor(base) {
|
|
27
|
+
return path.join(base, ".local", "share", "opencode", "auth.json");
|
|
28
|
+
}
|
|
29
|
+
// ─── Integration test ────────────────────────────────────────────────────────
|
|
30
|
+
describe("Auth stale-profile → repair → pass (integration)", () => {
|
|
31
|
+
let base;
|
|
32
|
+
let canonical;
|
|
33
|
+
const AGENT = "forge-dev-1";
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
base = makeTmpDir();
|
|
36
|
+
canonical = canonicalPathFor(base);
|
|
37
|
+
// Create canonical auth with valid provider entry
|
|
38
|
+
fs.mkdirSync(path.dirname(canonical), { recursive: true });
|
|
39
|
+
fs.writeFileSync(canonical, JSON.stringify({ anthropic: { token: "tok-abc123" } }), "utf-8");
|
|
40
|
+
fs.chmodSync(canonical, 0o600);
|
|
41
|
+
});
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
fs.rmSync(base, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
it("repairs a stale regular-file and creates a correct symlink", () => {
|
|
46
|
+
const agentAuth = agentAuthPathFor(base, AGENT);
|
|
47
|
+
const agentDir = path.dirname(agentAuth);
|
|
48
|
+
// Plant a stale regular file (simulating drift — old token copy)
|
|
49
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
50
|
+
fs.writeFileSync(agentAuth, JSON.stringify({ anthropic: { token: "STALE" } }), "utf-8");
|
|
51
|
+
// Verify the stale state
|
|
52
|
+
const stale = fs.lstatSync(agentAuth);
|
|
53
|
+
expect(stale.isFile()).toBe(true);
|
|
54
|
+
expect(stale.isSymbolicLink()).toBe(false);
|
|
55
|
+
// Run repair with sandboxed homeDir
|
|
56
|
+
const result = ensureAuthLink(AGENT, canonical, base);
|
|
57
|
+
expect(result.ok).toBe(true);
|
|
58
|
+
expect(result.action).toBe("symlink-replaced-file");
|
|
59
|
+
// Verify symlink now in place
|
|
60
|
+
const repaired = fs.lstatSync(agentAuth);
|
|
61
|
+
expect(repaired.isSymbolicLink()).toBe(true);
|
|
62
|
+
expect(fs.readlinkSync(agentAuth)).toBe(canonical);
|
|
63
|
+
// Verify backup exists
|
|
64
|
+
const backups = fs.readdirSync(agentDir).filter((f) => f.startsWith("auth.json.bak."));
|
|
65
|
+
expect(backups.length).toBe(1);
|
|
66
|
+
// Verify symlink resolves to valid canonical content
|
|
67
|
+
const content = JSON.parse(fs.readFileSync(agentAuth, "utf-8"));
|
|
68
|
+
expect(content.anthropic).toBeDefined();
|
|
69
|
+
// Token should now be from canonical, not stale
|
|
70
|
+
expect(content.anthropic.token).toBe("tok-abc123");
|
|
71
|
+
});
|
|
72
|
+
it("preflightAuth passes after repair", () => {
|
|
73
|
+
const agentAuth = agentAuthPathFor(base, AGENT);
|
|
74
|
+
const agentDir = path.dirname(agentAuth);
|
|
75
|
+
// Plant stale file, then explicitly repair it first (ensureAuthLink converts
|
|
76
|
+
// the stale regular-file to a symlink). preflightAuth auto-repairs only missing
|
|
77
|
+
// or broken symlinks — a readable regular file is considered linkOk by design.
|
|
78
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
79
|
+
fs.writeFileSync(agentAuth, JSON.stringify({ anthropic: { token: "STALE" } }), "utf-8");
|
|
80
|
+
ensureAuthLink(AGENT, canonical, base);
|
|
81
|
+
// Now preflightAuth on the already-repaired state should pass cleanly
|
|
82
|
+
const result = preflightAuth(AGENT, canonical, base);
|
|
83
|
+
expect(result.passed).toBe(true);
|
|
84
|
+
expect(result.linkOk).toBe(true);
|
|
85
|
+
expect(result.canonicalOk).toBe(true);
|
|
86
|
+
expect(result.contentOk).toBe(true);
|
|
87
|
+
// Verify the symlink is in place at the sandboxed path
|
|
88
|
+
const lstat = fs.lstatSync(agentAuth);
|
|
89
|
+
expect(lstat.isSymbolicLink()).toBe(true);
|
|
90
|
+
expect(fs.readlinkSync(agentAuth)).toBe(canonical);
|
|
91
|
+
});
|
|
92
|
+
it("is idempotent — second ensureAuthLink call returns symlink-ok", () => {
|
|
93
|
+
const agentAuth = agentAuthPathFor(base, AGENT);
|
|
94
|
+
const agentDir = path.dirname(agentAuth);
|
|
95
|
+
// First: create symlink (homeDir sandboxed to base)
|
|
96
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
97
|
+
const r1 = ensureAuthLink(AGENT, canonical, base);
|
|
98
|
+
expect(r1.ok).toBe(true);
|
|
99
|
+
expect(r1.action).toBe("symlink-created");
|
|
100
|
+
// Second: already correct symlink
|
|
101
|
+
const r2 = ensureAuthLink(AGENT, canonical, base);
|
|
102
|
+
expect(r2.ok).toBe(true);
|
|
103
|
+
expect(r2.action).toBe("symlink-ok");
|
|
104
|
+
// Exactly one symlink, no extra backups
|
|
105
|
+
const entries = fs.readdirSync(agentDir);
|
|
106
|
+
expect(entries.filter((f) => f.startsWith("auth.json.bak."))).toHaveLength(0);
|
|
107
|
+
});
|
|
108
|
+
it("handles missing canonical gracefully — returns no-op", () => {
|
|
109
|
+
const agentAuth = agentAuthPathFor(base, AGENT);
|
|
110
|
+
const agentDir = path.dirname(agentAuth);
|
|
111
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
112
|
+
const missingCanonical = path.join(base, ".local", "share", "opencode", "DOES_NOT_EXIST.json");
|
|
113
|
+
const result = ensureAuthLink(AGENT, missingCanonical, base);
|
|
114
|
+
expect(result.ok).toBe(false);
|
|
115
|
+
expect(result.action).toBe("no-op");
|
|
116
|
+
});
|
|
117
|
+
it("getAuthLinkStatus reflects post-repair state accurately", () => {
|
|
118
|
+
const agentAuth = agentAuthPathFor(base, AGENT);
|
|
119
|
+
const agentDir = path.dirname(agentAuth);
|
|
120
|
+
// Plant stale file then repair (homeDir sandboxed to base)
|
|
121
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
122
|
+
fs.writeFileSync(agentAuth, '{"old":true}', "utf-8");
|
|
123
|
+
ensureAuthLink(AGENT, canonical, base);
|
|
124
|
+
// Use getAuthLinkStatus with the same sandbox
|
|
125
|
+
const status = getAuthLinkStatus(AGENT, canonical, base);
|
|
126
|
+
expect(status.isSymlink).toBe(true);
|
|
127
|
+
expect(status.pointsToCanonical).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=auth-doctor-integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-doctor-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/auth-doctor-integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAExF,gFAAgF;AAEhF,SAAS,UAAU;IACjB,OAAO,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,SAAiB;IACvD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AACrE,CAAC;AAED,gFAAgF;AAEhF,QAAQ,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAChE,IAAI,IAAY,CAAC;IACjB,IAAI,SAAiB,CAAC;IACtB,MAAM,KAAK,GAAG,aAAa,CAAC;IAE5B,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,GAAG,UAAU,EAAE,CAAC;QACpB,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAEnC,kDAAkD;QAClD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAC7F,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,iEAAiE;QACjE,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QAExF,yBAAyB;QACzB,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE3C,oCAAoC;QACpC,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAEpD,8BAA8B;QAC9B,MAAM,QAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnD,uBAAuB;QACvB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACvF,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE/B,qDAAqD;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAA4B,CAAC;QAC3F,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QACxC,gDAAgD;QAChD,MAAM,CAAE,OAAO,CAAC,SAA+B,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,6EAA6E;QAC7E,gFAAgF;QAChF,+EAA+E;QAC/E,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;QACxF,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAEvC,sEAAsE;QACtE,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpC,uDAAuD;QACvD,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,oDAAoD;QACpD,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAClD,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAE1C,kCAAkC;QAClC,MAAM,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAClD,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAErC,wCAAwC;QACxC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACzC,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5C,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,qBAAqB,CAAC,CAAC;QAC/F,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;QAE7D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,2DAA2D;QAC3D,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QACrD,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAEvC,8CAA8C;QAC9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test: Auth drift -> doctor repair -> success
|
|
3
|
+
* Epic #470
|
|
4
|
+
*
|
|
5
|
+
* Simulates the real incident:
|
|
6
|
+
* 1. Agent starts with stale per-agent auth (regular file, old tokens)
|
|
7
|
+
* 2. Global auth is refreshed (new token written to canonical)
|
|
8
|
+
* 3. Doctor runs with --repair
|
|
9
|
+
* 4. Per-agent auth now points to fresh canonical via symlink
|
|
10
|
+
* 5. Subsequent reads see fresh token — drift eliminated
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test: Auth drift -> doctor repair -> success
|
|
3
|
+
* Epic #470
|
|
4
|
+
*
|
|
5
|
+
* Simulates the real incident:
|
|
6
|
+
* 1. Agent starts with stale per-agent auth (regular file, old tokens)
|
|
7
|
+
* 2. Global auth is refreshed (new token written to canonical)
|
|
8
|
+
* 3. Doctor runs with --repair
|
|
9
|
+
* 4. Per-agent auth now points to fresh canonical via symlink
|
|
10
|
+
* 5. Subsequent reads see fresh token — drift eliminated
|
|
11
|
+
*/
|
|
12
|
+
import fs from "node:fs";
|
|
13
|
+
import os from "node:os";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
16
|
+
import { isValidAuthSymlink, linkAgentAuth, validateCanonicalAuth, } from "../core/auth-guard.js";
|
|
17
|
+
function makeTmpDir() {
|
|
18
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), "am-auth-integ-"));
|
|
19
|
+
}
|
|
20
|
+
function writeJson(filePath, data) {
|
|
21
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
22
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
23
|
+
}
|
|
24
|
+
describe("Auth drift -> repair -> success (integration)", () => {
|
|
25
|
+
let tmp;
|
|
26
|
+
let canonicalPath;
|
|
27
|
+
let agentAuthFile;
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
tmp = makeTmpDir();
|
|
30
|
+
canonicalPath = path.join(tmp, "global", "opencode", "auth.json");
|
|
31
|
+
agentAuthFile = path.join(tmp, "opencode-data", "forge-dev-1", "opencode", "auth.json");
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
it("simulates stale regular file -> symlink repair -> fresh token visible", () => {
|
|
37
|
+
// Step 1: Agent was started before global auth was refreshed
|
|
38
|
+
// Per-agent auth.json exists as a regular file with OLD token material
|
|
39
|
+
const staleToken = { provider: "anthropic", accessToken: "old_token_STALE_400" };
|
|
40
|
+
writeJson(agentAuthFile, staleToken);
|
|
41
|
+
expect(fs.lstatSync(agentAuthFile).isSymbolicLink()).toBe(false);
|
|
42
|
+
// Step 2: Global auth is refreshed (user re-authenticated)
|
|
43
|
+
const freshToken = { provider: "anthropic", accessToken: "new_token_FRESH_OK" };
|
|
44
|
+
writeJson(canonicalPath, freshToken);
|
|
45
|
+
expect(validateCanonicalAuth(canonicalPath)).toBe(true);
|
|
46
|
+
// At this point, agent still sees the stale token (drift!)
|
|
47
|
+
const staleRead = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
48
|
+
expect(staleRead.accessToken).toBe("old_token_STALE_400");
|
|
49
|
+
// Step 3: Doctor/repair runs — replace regular file with symlink
|
|
50
|
+
const repairResult = linkAgentAuth(agentAuthFile, canonicalPath);
|
|
51
|
+
expect(repairResult.linked).toBe(true);
|
|
52
|
+
expect(repairResult.backedUp).toBeDefined();
|
|
53
|
+
expect(fs.lstatSync(agentAuthFile).isSymbolicLink()).toBe(true);
|
|
54
|
+
// Step 4: Post-repair — agent now sees fresh token via symlink
|
|
55
|
+
expect(isValidAuthSymlink(agentAuthFile)).toBe(true);
|
|
56
|
+
const freshRead = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
57
|
+
expect(freshRead.accessToken).toBe("new_token_FRESH_OK");
|
|
58
|
+
// Step 5: Any subsequent global auth refresh is immediately visible
|
|
59
|
+
const newerToken = { provider: "anthropic", accessToken: "newer_token_ALSO_OK" };
|
|
60
|
+
writeJson(canonicalPath, newerToken);
|
|
61
|
+
const newerRead = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
62
|
+
expect(newerRead.accessToken).toBe("newer_token_ALSO_OK");
|
|
63
|
+
// Backup of stale file preserved
|
|
64
|
+
const backedUpContent = JSON.parse(fs.readFileSync(repairResult.backedUp, "utf-8"));
|
|
65
|
+
expect(backedUpContent.accessToken).toBe("old_token_STALE_400");
|
|
66
|
+
});
|
|
67
|
+
it("symlink-first: new agent always gets fresh token immediately", () => {
|
|
68
|
+
// Global auth exists before agent ever starts
|
|
69
|
+
const freshToken = { provider: "anthropic", accessToken: "initial_fresh_token" };
|
|
70
|
+
writeJson(canonicalPath, freshToken);
|
|
71
|
+
// Agent profile dir created (simulates prepareOpenCodeRuntime)
|
|
72
|
+
fs.mkdirSync(path.dirname(agentAuthFile), { recursive: true });
|
|
73
|
+
// ensureAgentAuthLink creates the symlink (no prior file)
|
|
74
|
+
const result = linkAgentAuth(agentAuthFile, canonicalPath);
|
|
75
|
+
expect(result.linked).toBe(true);
|
|
76
|
+
expect(result.backedUp).toBeUndefined(); // nothing to back up
|
|
77
|
+
// Token is immediately visible
|
|
78
|
+
const read = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
79
|
+
expect(read.accessToken).toBe("initial_fresh_token");
|
|
80
|
+
// Update global -> agent sees it with zero extra steps
|
|
81
|
+
writeJson(canonicalPath, { provider: "anthropic", accessToken: "rotated_token" });
|
|
82
|
+
const read2 = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
83
|
+
expect(read2.accessToken).toBe("rotated_token");
|
|
84
|
+
});
|
|
85
|
+
it("multi-agent: all agents see same fresh token via individual symlinks", () => {
|
|
86
|
+
const agents = ["forge-dev-1", "forge-dev-2", "forge-dev-3"];
|
|
87
|
+
const freshToken = { provider: "anthropic", accessToken: "shared_fresh" };
|
|
88
|
+
writeJson(canonicalPath, freshToken);
|
|
89
|
+
// Set up symlinks for all agents
|
|
90
|
+
for (const agentName of agents) {
|
|
91
|
+
const authPath = path.join(tmp, "opencode-data", agentName, "opencode", "auth.json");
|
|
92
|
+
fs.mkdirSync(path.dirname(authPath), { recursive: true });
|
|
93
|
+
const res = linkAgentAuth(authPath, canonicalPath);
|
|
94
|
+
expect(res.linked).toBe(true);
|
|
95
|
+
}
|
|
96
|
+
// All see fresh token
|
|
97
|
+
for (const agentName of agents) {
|
|
98
|
+
const authPath = path.join(tmp, "opencode-data", agentName, "opencode", "auth.json");
|
|
99
|
+
const content = JSON.parse(fs.readFileSync(authPath, "utf-8"));
|
|
100
|
+
expect(content.accessToken).toBe("shared_fresh");
|
|
101
|
+
}
|
|
102
|
+
// Rotate global token — all agents immediately see new value
|
|
103
|
+
writeJson(canonicalPath, { provider: "anthropic", accessToken: "rotated_all" });
|
|
104
|
+
for (const agentName of agents) {
|
|
105
|
+
const authPath = path.join(tmp, "opencode-data", agentName, "opencode", "auth.json");
|
|
106
|
+
const content = JSON.parse(fs.readFileSync(authPath, "utf-8"));
|
|
107
|
+
expect(content.accessToken).toBe("rotated_all");
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
it("healthcheck watcher detects broken symlink and emits degraded event", async () => {
|
|
111
|
+
// Create initial valid symlink for agent
|
|
112
|
+
writeJson(canonicalPath, { provider: "anthropic", accessToken: "ok_token" });
|
|
113
|
+
fs.mkdirSync(path.dirname(agentAuthFile), { recursive: true });
|
|
114
|
+
linkAgentAuth(agentAuthFile, canonicalPath);
|
|
115
|
+
expect(isValidAuthSymlink(agentAuthFile)).toBe(true);
|
|
116
|
+
// Now simulate canonical being deleted (e.g., moved/rotated)
|
|
117
|
+
fs.unlinkSync(canonicalPath);
|
|
118
|
+
expect(isValidAuthSymlink(agentAuthFile)).toBe(false);
|
|
119
|
+
// Collect events from watcher — using a manual check rather than timers
|
|
120
|
+
// since we can't override AGENTMESH_OPENCODE_DATA_ROOT
|
|
121
|
+
// Test directly: broken symlink should be detected as invalid
|
|
122
|
+
const lstat = fs.lstatSync(agentAuthFile);
|
|
123
|
+
expect(lstat.isSymbolicLink()).toBe(true);
|
|
124
|
+
// Restore canonical
|
|
125
|
+
writeJson(canonicalPath, { provider: "anthropic", accessToken: "restored_token" });
|
|
126
|
+
expect(isValidAuthSymlink(agentAuthFile)).toBe(true);
|
|
127
|
+
// Agent now sees restored token
|
|
128
|
+
const content = JSON.parse(fs.readFileSync(agentAuthFile, "utf-8"));
|
|
129
|
+
expect(content.accessToken).toBe("restored_token");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
//# sourceMappingURL=auth-guard.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-guard.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/auth-guard.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for auth-guard.ts — Epics #470 + #490
|
|
3
|
+
*
|
|
4
|
+
* Tests:
|
|
5
|
+
* 1. validateCanonicalAuth — detects valid/invalid/missing canonical auth
|
|
6
|
+
* 2. isValidAuthSymlink — detects valid/broken/missing/regular-file symlinks
|
|
7
|
+
* 3. linkAgentAuth — creates symlink, backs up regular files, removes stale symlinks
|
|
8
|
+
* 4. ensureAgentAuthLink — full link-or-repair flow
|
|
9
|
+
* 5. preflightAgentAuth — preflight with retry semantics
|
|
10
|
+
* 6. startAuthHealthWatcher — periodic check, backoff, event emission
|
|
11
|
+
* 7. runAuthDoctor — discovery + optional repair
|
|
12
|
+
* 8. isTempPath — temp path detection (#490)
|
|
13
|
+
* 9. validateAuthSchema — schema validation incl. auth.type field (#490)
|
|
14
|
+
* 10. writeRealAuthFile — real-file fallback when symlinking fails (#490)
|
|
15
|
+
* 11. getSymlinkTempTarget — detects temp-path symlink targets (#490)
|
|
16
|
+
*/
|
|
17
|
+
export {};
|