test/claude-expired-auth.test.js
Rama main · réplica de lectura del repositorio original.
var test = require("node:test");
var assert = require("node:assert/strict");
var users = require("../lib/users");
var normalize = require("../lib/yoke/adapters/claude").contractTestKit.normalizeEvent;
var attachMessageProcessor = require("../lib/sdk-message-processor").attachMessageProcessor;
var expired = "Failed to authenticate: OAuth session expired and could not be refreshed";
function fixture(t, linuxUser) {
t.mock.method(users, "isMultiUser", function () { return true; });
t.mock.method(users, "findUserById", function (id) {
return id === "member" ? { id: id, role: "member", linuxUser: linuxUser } : null;
});
var session = {
localId: 22, vendor: "claude", ownerId: "member", cliSessionId: "expired-session",
history: [], messageUUIDs: [], responsePreview: "", pendingPermissions: {},
pendingElicitations: {}, pendingAskUser: {}, sentToolResults: {},
};
var sent = [];
var notifications = [];
var processor = attachMessageProcessor({
sm: {
sendAndRecord: function (target, msg) { target.history.push(msg); },
sendToSession: function (target, msg) { sent.push({ target: target.localId, message: msg }); },
broadcastSessionList: function () {},
},
opts: {}, onProcessingChanged: function () {}, onTurnDone: function () {},
getNotificationsModule: function () {
return { notify: function (type, data) { notifications.push({ type: type, data: data }); } };
},
});
return {
session: session, sent: sent, notifications: notifications,
finish: function (text, cost) {
session.isProcessing = true;
session._awaitingTurnResult = true;
processor.processSDKMessage(session, normalize({ type: "assistant", message: {
role: "assistant", content: [{ type: "text", text: text }],
} }));
processor.processSDKMessage(session, normalize({ type: "result", subtype: "success", total_cost_usd: cost, duration_ms: 100 }));
},
};
}
test("expired OAuth response sends transient recovery for the session's Linux user", function (t) {
var f = fixture(t, "clay_member");
f.finish(expired, 0);
var auth = f.sent.filter(function (entry) { return entry.message.type === "auth_required"; });
assert.equal(auth.length, 1);
assert.equal(auth[0].target, 22);
assert.equal(auth[0].message.vendor, "claude");
assert.equal(auth[0].message.linuxUser, "clay_member");
assert.equal(auth[0].message.canAutoLogin, true);
assert.equal(f.session.cliSessionId, null);
assert.equal(f.session.isProcessing, false);
assert.equal(f.session.history.some(function (msg) { return msg.type === "auth_required"; }), false);
var notice = f.notifications.find(function (entry) { return entry.type === "auth_required"; });
assert.equal(notice.data.ownerId, "member");
f.finish(expired, 0);
assert.equal(f.sent.filter(function (entry) { return entry.message.type === "auth_required"; }).length, 1);
});
test("expired OAuth does not grant host login access to an unmapped member", function (t) {
var f = fixture(t, null);
f.finish(expired, 0);
var auth = f.sent.find(function (entry) { return entry.message.type === "auth_required"; });
assert.equal(auth.message.canAutoLogin, false);
assert.equal(auth.message.linuxUser, null);
});
test("older not-logged-in responses still request recovery", function (t) {
var f = fixture(t, "clay_member");
f.finish("Not logged in · Please run /login", 0);
assert.equal(f.sent.some(function (entry) { return entry.message.type === "auth_required"; }), true);
});
test("paid responses, explanations and other vendors do not trigger expired-Claude recovery", function (t) {
var f = fixture(t, "clay_member");
f.finish(expired, 0.01);
f.finish("The error says: " + expired, 0);
f.finish(expired + " — here is how to fix it.", 0);
f.session.vendor = "codex";
f.finish(expired, 0);
assert.equal(f.sent.some(function (entry) { return entry.message.type === "auth_required"; }), false);
});