test/issues-launch-hardening.test.js
Rama main · réplica de lectura del repositorio original.
var test = require("node:test");
var assert = require("node:assert/strict");
var fs = require("node:fs");
var os = require("node:os");
var path = require("node:path");
var attachLaunch = require("../lib/project-issue-launch").attachIssueLaunch;
var attachService = require("../lib/issues-service").attachIssuesService;
var resolveIssueWorkSession = require("../lib/issue-work-session").resolveIssueWorkSession;
var issueStore = require("../lib/issues-store");
function fixture(options) {
var opts = options || {};
var actor = { id: "u1", displayName: "Owner" };
var ws = { readyState: 1, _clayUser: actor };
var entry = { ref: "issue:" + "a".repeat(24), revision: 1, title: "Launch work", summary: "Do it", body: "Details",
status: "open", linkedWorkSessions: [] };
var sessions = new Map();
var created = 0; var runtimeCalls = 0; var sdkCalls = [];
var sm = { sessions: sessions, installedVendors: ["codex"],
createSessionRaw: function (settings) { var session = Object.assign({ localId: ++created, history: [], isProcessing: false }, settings); sessions.set(session.localId, session); return session; },
deleteSession: function (id) { sessions.delete(id); }, saveSessionFile: function () {}, broadcastSessionList: function () {},
switchSession: function (id, socket) { socket._clayActiveSession = id; },
sendAndRecord: function (session, event) { session.history.push(event); }, sendToSession: function () {} };
var bound = { scopeId: "project/pk/issues", readIssue: function () { return Object.assign({}, entry, { linkedWorkSessions: entry.linkedWorkSessions.slice() }); },
linkWorkSession: function (args, session) {
if (args.expectedRevision !== entry.revision) throw new Error("Issue revision conflict.");
entry = Object.assign({}, entry, { revision: entry.revision + 1, status: "in_progress",
linkedWorkSessions: [{ sessionId: session.sessionOriginId, role: "driver", issueRevision: args.expectedRevision, requestId: args.requestId }] });
return entry;
} };
var linuxUser = opts.linuxUser || null;
var context = { sm: sm, osUsers: opts.osUsers === true,
getProjectAccess: function () { return opts.projectAccess || { sessionVisibilityDefault: "private" }; },
resolveDefaultAi: function () { runtimeCalls++; return opts.runtime || Promise.resolve({ ready: true, vendor: "codex", model: "test-model" }); },
canStartWork: function (socket, user) { return opts.canStart ? opts.canStart(socket, user) : true; },
getLinuxUserForSession: function () { return linuxUser; },
ensureProjectAccessForSession: function () { return linuxUser; },
getSdk: function () { return { startQuery: function (session, prompt, images, linuxUser) {
sdkCalls.push({ session: session, prompt: prompt, images: images, linuxUser: linuxUser });
if (opts.sdk) return opts.sdk(session, prompt, images, linuxUser);
session.queryInstance = { active: true };
return Promise.resolve();
} }; }, onProcessingChanged: function () {} };
return { start: attachLaunch(context), ws: ws, actor: actor, bound: bound, entry: function () { return entry; }, setLinuxUser: function (value) { linuxUser = value; },
sessions: sessions, sdkCalls: sdkCalls, runtimeCalls: function () { return runtimeCalls; } };
}
test("two request IDs deduplicate one in-flight issue launch and completed IDs replay exactly", async function () {
var release;
var runtime = new Promise(function (resolve) { release = resolve; });
var f = fixture({ runtime: runtime });
var args = { ref: f.entry().ref, expectedRevision: 1 };
var first = f.start(f.ws, { requestId: "first", args: args }, f.bound);
var second = f.start(f.ws, { requestId: "second", args: args }, f.bound);
assert.equal(f.runtimeCalls(), 1);
release({ ready: true, vendor: "codex", model: "test-model" });
var results = await Promise.all([first, second]);
assert.equal(results[0].sessionId, results[1].sessionId);
assert.equal(f.sessions.size, 1);
assert.equal(f.sdkCalls.length, 1);
assert.equal((await f.start(f.ws, { requestId: "first", args: args }, f.bound)).sessionId, results[0].sessionId);
await assert.rejects(f.start(f.ws, { requestId: "first", args: { ref: args.ref, expectedRevision: 2 } }, f.bound), /different arguments/);
assert.equal(f.entry().status, "in_progress");
assert.equal(f.entry().linkedWorkSessions[0].issueRevision, 1);
assert.equal(f.entry().linkedWorkSessions[0].requestId, "first");
assert.equal(f.sdkCalls[0].session.issueOrigin.requestId, "first");
f.sdkCalls[0].session.isProcessing = false;
assert.equal(f.entry().status, "in_progress", "session completion never resolves an Issue");
});
test("visible Issue Start work sessions inherit the project visibility default", async function () {
var f = fixture({ projectAccess: { sessionVisibilityDefault: "shared" } });
await f.start(f.ws, { requestId: "shared-issue", args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound);
assert.equal(f.sessions.get(1).sessionVisibility, "shared");
});
test('Start work carries the direct GitHub issue association into session metadata', async function () {
var f = fixture();
f.entry().github = { kind: 'issue', url: 'https://github.com/owner/repo/issues/12', repository: 'owner/repo', number: 12, title: 'Bug', state: 'open' };
await f.start(f.ws, { requestId: 'github-linked', args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound);
assert.deepEqual(f.sessions.get(1).githubLinks, [f.entry().github]);
assert.notEqual(f.sessions.get(1).githubLinks[0], f.entry().github);
});
test("launch revalidates the exact actor and creation authority after runtime resolution", async function () {
var release;
var runtime = new Promise(function (resolve) { release = resolve; });
var allowed = true;
var f = fixture({ runtime: runtime, canStart: function () { return allowed; } });
var pending = f.start(f.ws, { requestId: "revoked", args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound);
allowed = false;
release({ ready: true, vendor: "codex", model: "test-model" });
await assert.rejects(pending, /no longer allowed/);
assert.equal(f.sessions.size, 0);
});
test("launch rejects an OS identity change during Default AI resolution", async function () {
var release;
var runtime = new Promise(function (resolve) { release = resolve; });
var f = fixture({ runtime: runtime, osUsers: true, linuxUser: "linux-owner" });
var pending = f.start(f.ws, { requestId: "identity-change", args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound);
f.setLinuxUser("other-owner");
release({ ready: true, vendor: "codex", model: "test-model" });
await assert.rejects(pending, /OS identity changed/);
assert.equal(f.sessions.size, 0);
});
test("OS identity reaches the real SDK argument and a launch failure stays visible in the session", async function () {
var f = fixture({ osUsers: true, linuxUser: "linux-owner", sdk: function (session) {
session.isProcessing = false;
session.history.push({ type: "error", text: "Adapter login failed." });
return Promise.resolve();
} });
var error;
try { await f.start(f.ws, { requestId: "failure", args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound); }
catch (caught) { error = caught; }
assert.ok(error);
assert.match(error.message, /Adapter login failed/);
assert.equal(error.sessionId, 1);
assert.equal(f.sdkCalls[0].images, undefined);
assert.equal(f.sdkCalls[0].linuxUser, "linux-owner");
assert.match(f.sdkCalls[0].prompt, /Session completion never resolves/);
assert.ok(f.sdkCalls[0].session.history.some(function (event) { return event.type === "user_message" && event.issueRef === f.entry().ref; }));
assert.ok(f.sdkCalls[0].session.history.some(function (event) { return event.type === "error"; }));
});
test("linked work session APIs enforce exact revision and visible Driver identity while preserving closed history", async function (t) {
var directory = fs.mkdtempSync(path.join(os.tmpdir(), "clay-issue-links-"));
t.after(function () { fs.rmSync(directory, { recursive: true, force: true }); });
var sessions = new Map();
var status = { slug: "app", path: directory, projectKnowledgeId: "pk_links", projectOwnerId: "u1", isMate: false };
var manager = { sessions: sessions };
var project = { getStatus: function () { return status; }, getSessionManager: function () { return manager; } };
var service = attachService({ getProjects: function () { return new Map([["app", project]]); }, isMultiUser: function () { return true; },
findUserById: function (id) { return id === "u1" ? { id: "u1" } : null; }, baseDir: directory });
var bound = service.bindUser({ projectSlug: "app", userId: "u1" });
var issue = issueStore.createIssuesStore({ projectKnowledgeId: "pk_links", baseDir: directory }).create({ title: "Lifecycle" }, { type: "user", userId: "u1" });
var hidden = { localId: 1, ownerId: "u1", hidden: true }; sessions.set(1, hidden);
assert.throws(function () { bound.linkWorkSession({ ref: issue.ref, expectedRevision: 1 }, hidden); }, /Invalid work session/);
var driver = { localId: 2, ownerId: "u1" }; sessions.set(2, driver);
var linked = bound.linkWorkSession({ ref: issue.ref, expectedRevision: 1 }, driver);
assert.equal(linked.status, "in_progress");
assert.throws(function () { resolveIssueWorkSession(bound, { ref: issue.ref, expectedRevision: 1, sessionOriginId: driver.sessionOriginId }); }, /conflict/);
assert.equal(resolveIssueWorkSession(bound, { ref: issue.ref, expectedRevision: 2, sessionOriginId: driver.sessionOriginId }), driver);
driver.delegated = true;
assert.throws(function () { bound.resolveWorkSession({ ref: issue.ref, expectedRevision: 2, sessionOriginId: driver.sessionOriginId }); }, /unavailable/);
driver.delegated = false;
var closed = await bound.updateIssue({ ref: issue.ref, expectedRevision: 2, status: "closed", closeReason: "declined" });
assert.equal(resolveIssueWorkSession(bound, { ref: issue.ref, expectedRevision: closed.revision, sessionOriginId: driver.sessionOriginId }), driver,
"closed issues retain navigable work history");
});
test('Issue launch refuses an invalid declared transport before creating or linking work', async function () {
var info = require('../lib/yoke/vendor-registry').getVendorInfo('codex');
var previous = info.queryContract;
info.queryContract = Object.assign({}, previous, { toolTransport: 'invalid-declared-kind' });
try {
var f = fixture();
await assert.rejects(f.start(f.ws, { requestId: 'invalid-transport', args: { ref: f.entry().ref, expectedRevision: 1 } }, f.bound), /does not support Issues tools/);
assert.equal(f.sessions.size, 0);
assert.equal(f.sdkCalls.length, 0);
assert.equal(f.entry().status, 'open');
assert.equal(f.entry().revision, 1);
assert.deepEqual(f.entry().linkedWorkSessions, []);
} finally { info.queryContract = previous; }
});