@optimuslabs/harness-map-staging 1.5.29 → 1.5.30
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.
|
@@ -62,6 +62,7 @@ export function readClaudeSignedInTenant(env = process.env) {
|
|
|
62
62
|
tenant_name: text('organizationName'),
|
|
63
63
|
email: text('emailAddress'),
|
|
64
64
|
account_uuid: text('accountUuid'),
|
|
65
|
+
plan: text('organizationType').toLowerCase().replace(/^claude_/, ''),
|
|
65
66
|
};
|
|
66
67
|
}
|
|
67
68
|
catch {
|
|
@@ -69,14 +70,74 @@ export function readClaudeSignedInTenant(env = process.env) {
|
|
|
69
70
|
return null;
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Block messages, one shape for every agent (Optimus Labs' prompt-block wording):
|
|
75
|
+
* "This device only allows <agent> <under/on/in> the <approved> <kind>. You're signed in to
|
|
76
|
+
* <what>. <how to switch>." With nothing approved yet: "This device doesn't allow <agent> signed in
|
|
77
|
+
* to <what>." and the same last sentence.
|
|
78
|
+
*/
|
|
79
|
+
const TENANT_WORDS = {
|
|
80
|
+
claude: { name: 'Claude Code', kind: 'organization', prep: 'under' },
|
|
81
|
+
claude_desktop: { name: 'Claude Desktop', kind: 'organization', prep: 'under' },
|
|
82
|
+
cursor: { name: 'Cursor', kind: 'team', prep: 'on' },
|
|
83
|
+
codex: { name: 'Codex', kind: 'workspace', prep: 'in' },
|
|
84
|
+
};
|
|
85
|
+
/** A tenant's name as the admin approved it, or its id when it has none. */
|
|
86
|
+
function nameOf(t) {
|
|
87
|
+
return (t.tenant_name || '').trim() || t.tenant_id.trim();
|
|
88
|
+
}
|
|
89
|
+
function emailDomain(email) {
|
|
90
|
+
const address = (email ?? '').trim().toLowerCase();
|
|
91
|
+
const at = address.lastIndexOf('@');
|
|
92
|
+
return at >= 0 && at < address.length - 1 ? address.slice(at + 1) : '';
|
|
77
93
|
}
|
|
78
|
-
function
|
|
79
|
-
return
|
|
94
|
+
function capitalised(word) {
|
|
95
|
+
return word ? word[0].toUpperCase() + word.slice(1) : word;
|
|
96
|
+
}
|
|
97
|
+
/** What to pick to get back in: the one approved tenant, one of several, or the company's own. */
|
|
98
|
+
function choice(approved, kind) {
|
|
99
|
+
if (approved.length === 1)
|
|
100
|
+
return approved[0];
|
|
101
|
+
return approved.length > 1 ? 'one of them' : `your company's ${kind}`;
|
|
102
|
+
}
|
|
103
|
+
function switchStep(agent, approved) {
|
|
104
|
+
const kind = TENANT_WORDS[agent].kind;
|
|
105
|
+
if (agent === 'claude_desktop')
|
|
106
|
+
return `Switch Claude Desktop to ${choice(approved, kind)}.`;
|
|
107
|
+
if (agent === 'codex')
|
|
108
|
+
return `Run codex logout, then codex login and choose ${choice(approved, kind)}.`;
|
|
109
|
+
if (agent === 'cursor') {
|
|
110
|
+
if (approved.length === 1)
|
|
111
|
+
return `Sign out of Cursor and sign in with your ${approved[0]} team account.`;
|
|
112
|
+
return approved.length > 1
|
|
113
|
+
? 'Sign out of Cursor and sign in with an account on one of those teams.'
|
|
114
|
+
: "Sign out of Cursor and sign in with your company's team account.";
|
|
115
|
+
}
|
|
116
|
+
return `Run /login and choose ${choice(approved, kind)}.`;
|
|
117
|
+
}
|
|
118
|
+
/** The block message for `agent` signed in to `signedIn` (already worded) with these approved. */
|
|
119
|
+
export function tenantBlockMessage(agent, approved, signedIn) {
|
|
120
|
+
const w = TENANT_WORDS[agent];
|
|
121
|
+
const lead = approved.length
|
|
122
|
+
? `This device only allows ${w.name} ${w.prep} the ${approved.join(' or ')} ${w.kind}. ` +
|
|
123
|
+
`You're signed in to ${signedIn}.`
|
|
124
|
+
: `This device doesn't allow ${w.name} signed in to ${signedIn}.`;
|
|
125
|
+
return `${lead} ${switchStep(agent, approved)}`;
|
|
126
|
+
}
|
|
127
|
+
const CLAUDE_PERSONAL_PLANS = new Set(['free', 'pro', 'max']);
|
|
128
|
+
/** "a personal Max account (gmail.com)" or "the Beta Corp organization". */
|
|
129
|
+
function claudeSignedInText(signedIn) {
|
|
130
|
+
const plan = (signedIn.plan ?? '').trim().toLowerCase();
|
|
131
|
+
const domain = emailDomain(signedIn.email);
|
|
132
|
+
const at = domain ? ` (${domain})` : '';
|
|
133
|
+
// A personal claude.ai org is named after its owner: "ada@gmail.com's Organization".
|
|
134
|
+
if (CLAUDE_PERSONAL_PLANS.has(plan) || /'s organization$/i.test(signedIn.tenant_name)) {
|
|
135
|
+
const planWord = CLAUDE_PERSONAL_PLANS.has(plan) ? `${capitalised(plan)} ` : '';
|
|
136
|
+
return `a personal ${planWord}account${at}`;
|
|
137
|
+
}
|
|
138
|
+
if (signedIn.tenant_name)
|
|
139
|
+
return `the ${signedIn.tenant_name} organization`;
|
|
140
|
+
return `an organization your company has not approved${at}`;
|
|
80
141
|
}
|
|
81
142
|
function tenantIds(tenants) {
|
|
82
143
|
return (tenants ?? []).filter((t) => t && typeof t.tenant_id === 'string' && t.tenant_id.trim());
|
|
@@ -96,21 +157,11 @@ export function approvedTenantViolation(agent, approved, signedIn) {
|
|
|
96
157
|
const unapprovedTenants = tenantIds(policy?.unapproved_tenants);
|
|
97
158
|
const signedInId = signedIn.tenant_id.trim();
|
|
98
159
|
const isIn = (list) => list.some((t) => t.tenant_id.trim() === signedInId);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
else if ((policy?.enforced || approvedTenants.length > 0) && !isIn(approvedTenants)) {
|
|
104
|
-
reason = 'which your organization has not approved';
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
160
|
+
const blocked = isIn(unapprovedTenants) ||
|
|
161
|
+
((policy?.enforced || approvedTenants.length > 0) && !isIn(approvedTenants));
|
|
162
|
+
if (!blocked)
|
|
107
163
|
return null;
|
|
108
|
-
|
|
109
|
-
const allowed = approvedTenants.map((t) => label(t.tenant_name, t.tenant_id)).join(', ');
|
|
110
|
-
return (`this session is signed into ${label(signedIn.tenant_name, signedIn.tenant_id)}, ${reason}. ` +
|
|
111
|
-
(allowed
|
|
112
|
-
? `Approved: ${allowed}. ${fix(agent, 'an approved')}`
|
|
113
|
-
: fix(agent, 'a different')));
|
|
164
|
+
return tenantBlockMessage(agent, approvedTenants.map(nameOf), claudeSignedInText(signedIn));
|
|
114
165
|
}
|
|
115
166
|
/**
|
|
116
167
|
* The tenants a Cursor login is in: its teams, or, on no team, `@` and its email domain. Mirrors the
|
|
@@ -142,43 +193,61 @@ export function readCursorSignedInTeams(home = homedir()) {
|
|
|
142
193
|
* the login; failing that, one marked unapproved is always blocked, and any other -- an unknown
|
|
143
194
|
* tenant, or a personal account -- only once at least one tenant is approved for this agent.
|
|
144
195
|
*/
|
|
145
|
-
function listedTenantViolation(policy, tenants
|
|
196
|
+
function listedTenantViolation(policy, tenants) {
|
|
146
197
|
const approvedList = tenantIds(policy?.tenants);
|
|
147
198
|
if (tenants.some((id) => isListed(approvedList, id)))
|
|
148
199
|
return null;
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
200
|
+
const enforced = approvedList.length > 0 || Boolean(policy?.enforced);
|
|
201
|
+
if (!isRefused(tenants, enforced, tenantIds(policy?.unapproved_tenants)))
|
|
151
202
|
return null;
|
|
152
|
-
return {
|
|
203
|
+
return { approved: approvedList.map(nameOf) };
|
|
153
204
|
}
|
|
154
205
|
function isListed(list, id) {
|
|
155
206
|
return list.some((t) => t.tenant_id.trim() === id);
|
|
156
207
|
}
|
|
157
|
-
|
|
158
|
-
|
|
208
|
+
/** Whether a login in these tenants is refused: one marked unapproved always; any other only once
|
|
209
|
+
* the agent is enforced (an older backend that sends no flag, with nothing approved, lets it pass). */
|
|
210
|
+
function isRefused(tenants, enforced, unapprovedList) {
|
|
211
|
+
if (tenants.some((id) => isListed(unapprovedList, id)))
|
|
212
|
+
return true;
|
|
213
|
+
return enforced;
|
|
159
214
|
}
|
|
160
|
-
/**
|
|
161
|
-
function
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
215
|
+
/** A tenant's name from the organization's lists, or '' when it has none there. */
|
|
216
|
+
function knownName(policy, id) {
|
|
217
|
+
const all = [...tenantIds(policy?.tenants), ...tenantIds(policy?.unapproved_tenants)];
|
|
218
|
+
const hit = all.find((t) => t.tenant_id.trim() === id);
|
|
219
|
+
return (hit?.tenant_name || '').trim();
|
|
220
|
+
}
|
|
221
|
+
/** "a personal account on no team (gmail.com)", "the Beta team" or "team 9876". */
|
|
222
|
+
function cursorSignedInText(signedIn, policy) {
|
|
223
|
+
const tenants = cursorTenants(signedIn);
|
|
224
|
+
if (!tenants.length || tenants[0].startsWith('@')) {
|
|
225
|
+
const domain = emailDomain(signedIn.email) || (tenants[0] ?? '').slice(1);
|
|
226
|
+
return `a personal account on no team${domain ? ` (${domain})` : ''}`;
|
|
227
|
+
}
|
|
228
|
+
return tenants
|
|
229
|
+
.map((id) => (knownName(policy, id) ? `the ${knownName(policy, id)} team` : `team ${id}`))
|
|
230
|
+
.join(' and ');
|
|
231
|
+
}
|
|
232
|
+
/** "a personal ChatGPT Plus account (gmail.com)", "the Beta workspace" or "workspace ws-1". */
|
|
233
|
+
function codexSignedInText(signedIn, tenants, policy) {
|
|
234
|
+
const tenant = tenants[0] ?? '';
|
|
235
|
+
if (!tenant || tenant.startsWith('@')) {
|
|
236
|
+
const plan = capitalised((signedIn.plan ?? '').trim().toLowerCase());
|
|
237
|
+
const domain = emailDomain(signedIn.email) || tenant.slice(1);
|
|
238
|
+
return `a personal ChatGPT ${plan ? `${plan} ` : ''}account${domain ? ` (${domain})` : ''}`;
|
|
239
|
+
}
|
|
240
|
+
const name = knownName(policy, tenant);
|
|
241
|
+
return name ? `the ${name} workspace` : `workspace ${tenant}`;
|
|
171
242
|
}
|
|
172
243
|
/** The block message when Cursor's login may not be used, else null. */
|
|
173
244
|
export function cursorTeamViolation(approved, signedIn) {
|
|
174
245
|
if (!signedIn)
|
|
175
246
|
return null;
|
|
176
|
-
const v = listedTenantViolation(approved?.cursor, cursorTenants(signedIn)
|
|
247
|
+
const v = listedTenantViolation(approved?.cursor, cursorTenants(signedIn));
|
|
177
248
|
if (!v)
|
|
178
249
|
return null;
|
|
179
|
-
return (
|
|
180
|
-
(v.allowed ? `Approved: ${v.allowed}. ` : '') +
|
|
181
|
-
'Sign out of Cursor and sign in with an account on an approved team.');
|
|
250
|
+
return tenantBlockMessage('cursor', v.approved, cursorSignedInText(signedIn, approved?.cursor));
|
|
182
251
|
}
|
|
183
252
|
/**
|
|
184
253
|
* Codex plans that are personal, mirroring the backend's `CodexPlans.PERSONAL`. On one of these
|
|
@@ -221,12 +290,10 @@ export function codexTenantViolation(approved, signedIn) {
|
|
|
221
290
|
const tenants = signedIn ? codexTenants(signedIn) : null;
|
|
222
291
|
if (!tenants)
|
|
223
292
|
return null;
|
|
224
|
-
const v = listedTenantViolation(approved?.codex, tenants
|
|
293
|
+
const v = listedTenantViolation(approved?.codex, tenants);
|
|
225
294
|
if (!v)
|
|
226
295
|
return null;
|
|
227
|
-
return (
|
|
228
|
-
(v.allowed ? `Approved: ${v.allowed}. ` : '') +
|
|
229
|
-
'Run `codex logout`, then sign in to an approved workspace.');
|
|
296
|
+
return tenantBlockMessage('codex', v.approved, codexSignedInText(signedIn, tenants, approved?.codex));
|
|
230
297
|
}
|
|
231
298
|
/**
|
|
232
299
|
* Whether a personal account's `@<domain>` tenant is on a team domain: an allowlisted domain that
|
|
@@ -276,6 +343,7 @@ export function readClaudeDesktopSignedInTenant(home = homedir(), env = process.
|
|
|
276
343
|
tenant_name: same ? fromClaudeCode.tenant_name : '',
|
|
277
344
|
email: same ? fromClaudeCode.email : '',
|
|
278
345
|
account_uuid: account || (same ? fromClaudeCode.account_uuid : ''),
|
|
346
|
+
plan: same ? fromClaudeCode.plan : '',
|
|
279
347
|
};
|
|
280
348
|
}
|
|
281
349
|
/**
|
|
@@ -293,8 +361,8 @@ export function unapprovedEmailDomainViolation(email, unapproved) {
|
|
|
293
361
|
const hit = unapproved.find((d) => domain === d || domain.endsWith(`.${d}`));
|
|
294
362
|
if (!hit)
|
|
295
363
|
return null;
|
|
296
|
-
return (`
|
|
297
|
-
'Sign in with
|
|
364
|
+
return (`This device doesn't allow accounts on ${hit}. You're signed in as ${address}. ` +
|
|
365
|
+
'Sign in with your work account.');
|
|
298
366
|
}
|
|
299
367
|
/**
|
|
300
368
|
* The block message when a login's email is not on the organization's email allowlist, else null.
|
|
@@ -313,8 +381,8 @@ export function emailAllowlistViolation(email, allowed) {
|
|
|
313
381
|
const domain = address.slice(at + 1);
|
|
314
382
|
if (allowed.some((d) => domain === d || domain.endsWith(`.${d}`)))
|
|
315
383
|
return null;
|
|
316
|
-
return (`
|
|
317
|
-
'Sign in with
|
|
384
|
+
return (`This device only allows accounts on your organization's email domains. You're signed in as ${address}. ` +
|
|
385
|
+
'Sign in with your work account.');
|
|
318
386
|
}
|
|
319
387
|
/** The id an agent is approved under on the Agents page: Desktop's Code tab runs Claude Code. */
|
|
320
388
|
const APPROVAL_ID = { claude_desktop: 'claude' };
|
|
@@ -87,9 +87,10 @@ function printAllowWithAdvisory(ide, advisoryMessage) {
|
|
|
87
87
|
}));
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
/** Every block reads as an Optimus Labs notice: a title line, then the message. */
|
|
91
|
+
const BLOCK_TITLE = 'Optimus Labs\n\n';
|
|
90
92
|
function blockPayload(ide, violationMessage) {
|
|
91
|
-
const
|
|
92
|
-
const text = prefix + violationMessage;
|
|
93
|
+
const text = BLOCK_TITLE + violationMessage;
|
|
93
94
|
if (ide === 'claude' || ide === 'copilot' || ide === 'opencode') {
|
|
94
95
|
return JSON.stringify({ decision: 'block', reason: text, systemMessage: text });
|
|
95
96
|
}
|
|
@@ -100,7 +101,7 @@ function blockPayload(ide, violationMessage) {
|
|
|
100
101
|
* warning, so the Claude-shaped payload (which carries both) prints the same sentence twice.
|
|
101
102
|
*/
|
|
102
103
|
function codexBlockPayload(violationMessage) {
|
|
103
|
-
return JSON.stringify({ decision: 'block', reason:
|
|
104
|
+
return JSON.stringify({ decision: 'block', reason: BLOCK_TITLE + violationMessage });
|
|
104
105
|
}
|
|
105
106
|
function getManifestStalenessMs() {
|
|
106
107
|
try {
|