@ory/argus 0.14.0 → 1.0.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/README.md +31 -46
- package/assets/commands/temporal-up.md +1 -1
- package/assets/skills/auth-setup/SKILL.md +1 -1
- package/assets/skills/local-dev/SKILL.md +17 -7
- package/assets/skills/ory-build-agent/SKILL.md +39 -91
- package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
- package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
- package/assets/skills/permissions-onboarding/SKILL.md +131 -104
- package/dist/adapters.d.ts +88 -32
- package/dist/adapters.js +443 -164
- package/dist/agent-auth.d.ts +226 -67
- package/dist/agent-auth.js +951 -205
- package/dist/auth-store.d.ts +37 -2
- package/dist/auth-store.js +37 -3
- package/dist/auth.d.ts +33 -4
- package/dist/auth.js +163 -20
- package/dist/bash-parser.d.ts +98 -0
- package/dist/bash-parser.js +396 -0
- package/dist/branding.d.ts +77 -16
- package/dist/branding.js +93 -23
- package/dist/build-info.json +4 -4
- package/dist/cli-invocation.d.ts +1 -1
- package/dist/cli-invocation.js +2 -1
- package/dist/cli.d.ts +20 -29
- package/dist/cli.js +271 -239
- package/dist/client.d.ts +175 -138
- package/dist/client.js +672 -391
- package/dist/config.d.ts +217 -54
- package/dist/config.js +461 -42
- package/dist/context.d.ts +10 -0
- package/dist/context.js +21 -0
- package/dist/contract-suite.d.ts +3 -5
- package/dist/contract-suite.js +75 -47
- package/dist/denial.d.ts +36 -3
- package/dist/denial.js +79 -10
- package/dist/event-reporter.d.ts +77 -0
- package/dist/event-reporter.js +776 -0
- package/dist/external-registrations-main.d.ts +10 -0
- package/dist/external-registrations-main.js +38 -0
- package/dist/external-registrations.d.ts +79 -0
- package/dist/external-registrations.js +188 -0
- package/dist/help-cli.d.ts +39 -0
- package/dist/help-cli.js +55 -0
- package/dist/hook-timeout.d.ts +64 -0
- package/dist/hook-timeout.js +88 -0
- package/dist/index.d.ts +28 -23
- package/dist/index.js +173 -58
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +38 -6
- package/dist/local/cli.js +11 -6
- package/dist/local/configs.d.ts +74 -18
- package/dist/local/configs.js +291 -84
- package/dist/local/health.js +7 -7
- package/dist/local/index.d.ts +2 -2
- package/dist/local/index.js +24 -10
- package/dist/local/manager.d.ts +20 -1
- package/dist/local/manager.js +159 -36
- package/dist/local/ports.d.ts +158 -0
- package/dist/local/ports.js +443 -0
- package/dist/local/seed.d.ts +13 -5
- package/dist/local/seed.js +62 -38
- package/dist/logger.d.ts +54 -25
- package/dist/logger.js +329 -63
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +10 -5
- package/dist/mirror-bootstrap.d.ts +48 -0
- package/dist/mirror-bootstrap.js +254 -0
- package/dist/opl.d.ts +289 -0
- package/dist/opl.js +446 -0
- package/dist/permission-mode.d.ts +87 -0
- package/dist/permission-mode.js +307 -0
- package/dist/permissions-cli.d.ts +13 -49
- package/dist/permissions-cli.js +154 -348
- package/dist/permissions.d.ts +148 -38
- package/dist/permissions.js +591 -45
- package/dist/post-install.d.ts +33 -0
- package/dist/post-install.js +127 -0
- package/dist/read-credential.d.ts +65 -0
- package/dist/read-credential.js +86 -0
- package/dist/registry/cli.js +5 -2
- package/dist/registry/config.d.ts +0 -17
- package/dist/registry/config.js +0 -23
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +2 -2
- package/dist/registry/manager.d.ts +4 -21
- package/dist/registry/manager.js +21 -37
- package/dist/runtime-credential.d.ts +140 -0
- package/dist/runtime-credential.js +572 -0
- package/dist/runtime.d.ts +408 -0
- package/dist/runtime.js +748 -0
- package/dist/setup.d.ts +23 -47
- package/dist/setup.js +59 -116
- package/dist/skills.js +0 -7
- package/dist/status-cli.d.ts +27 -11
- package/dist/status-cli.js +121 -115
- package/dist/status-data.d.ts +116 -17
- package/dist/status-data.js +121 -38
- package/dist/subject.d.ts +126 -20
- package/dist/subject.js +215 -30
- package/dist/testing.d.ts +74 -38
- package/dist/testing.js +185 -68
- package/dist/tool-catalog.d.ts +53 -11
- package/dist/tool-catalog.js +164 -13
- package/dist/tool-metadata.d.ts +7 -6
- package/dist/tool-metadata.js +6 -5
- package/dist/types.d.ts +11 -1
- package/dist/uninstall.d.ts +71 -34
- package/dist/uninstall.js +217 -85
- package/dist/user-login.d.ts +9 -10
- package/dist/user-login.js +56 -75
- package/dist/watch-cli.d.ts +6 -0
- package/dist/watch-cli.js +217 -0
- package/package.json +4 -27
- package/assets/commands/dashboard.md +0 -34
- package/dist/dashboard-cli.d.ts +0 -8
- package/dist/dashboard-cli.js +0 -70
- package/dist/dev.d.ts +0 -103
- package/dist/dev.js +0 -583
- package/dist/interactive-setup.d.ts +0 -286
- package/dist/interactive-setup.js +0 -1734
- package/dist/local/jaeger-main.d.ts +0 -13
- package/dist/local/jaeger-main.js +0 -85
- package/dist/local/jaeger.d.ts +0 -50
- package/dist/local/jaeger.js +0 -162
- package/dist/otel/exporter.d.ts +0 -17
- package/dist/otel/exporter.js +0 -12
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js +0 -8
- package/dist/otel/otlp.d.ts +0 -103
- package/dist/otel/otlp.js +0 -385
- package/dist/project-api-key.d.ts +0 -69
- package/dist/project-api-key.js +0 -147
- package/dist/setup-actions.d.ts +0 -232
- package/dist/setup-actions.js +0 -507
- package/dist/tracer.d.ts +0 -190
- package/dist/tracer.js +0 -481
- package/dist/watch-sandbox.d.ts +0 -9
- package/dist/watch-sandbox.js +0 -81
- package/dist/web/api.d.ts +0 -33
- package/dist/web/api.js +0 -294
- package/dist/web/launch.d.ts +0 -11
- package/dist/web/launch.js +0 -96
- package/dist/web/server.d.ts +0 -20
- package/dist/web/server.js +0 -233
- package/dist/web/types.d.ts +0 -65
- package/dist/web/types.js +0 -2
- package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
- package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
- package/dist/webapp/favicon.ico +0 -0
- package/dist/webapp/index.html +0 -15
package/dist/testing.js
CHANGED
|
@@ -40,19 +40,21 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
40
|
};
|
|
41
41
|
})();
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.BATCH_SERVER_DENIED = exports.BATCH_SERVER_ALLOWED_TOOL_DENIED = exports.BATCH_BOTH_ALLOWED = exports.PERMISSION_DENIED = exports.PERMISSION_ALLOWED = exports.MOCK_INACTIVE_OAUTH2_RESPONSE = exports.MOCK_OAUTH2_RESPONSE = exports.MOCK_INACTIVE_SESSION_RESPONSE = exports.MOCK_SESSION_RESPONSE = exports.runHarnessContractSuite = void 0;
|
|
43
|
+
exports.TEST_OAUTH2_CLIENT_ID = exports.TEST_AGENT_SECURITY_URL = exports.TEST_PROJECT_URL = exports.BATCH_SERVER_DENIED = exports.BATCH_SERVER_ALLOWED_TOOL_DENIED = exports.BATCH_BOTH_ALLOWED = exports.PERMISSION_DENIED = exports.PERMISSION_ALLOWED = exports.MOCK_INACTIVE_OAUTH2_RESPONSE = exports.MOCK_OAUTH2_RESPONSE = exports.MOCK_INACTIVE_SESSION_RESPONSE = exports.MOCK_SESSION_RESPONSE = exports.runHarnessContractSuite = void 0;
|
|
44
44
|
exports.createMockClient = createMockClient;
|
|
45
|
-
exports.
|
|
45
|
+
exports.spyRecordDelegation = spyRecordDelegation;
|
|
46
46
|
exports.stubApi = stubApi;
|
|
47
47
|
exports.makeAxiosError = makeAxiosError;
|
|
48
48
|
exports.makeNetworkError = makeNetworkError;
|
|
49
49
|
exports.makeRateLimitError = makeRateLimitError;
|
|
50
50
|
exports.makeMfaRequiredError = makeMfaRequiredError;
|
|
51
51
|
exports.makeSessionInactiveError = makeSessionInactiveError;
|
|
52
|
-
exports.
|
|
53
|
-
exports.
|
|
52
|
+
exports.getActivityEvents = getActivityEvents;
|
|
53
|
+
exports.expectActivityTools = expectActivityTools;
|
|
54
54
|
exports.setOryEnv = setOryEnv;
|
|
55
55
|
exports.useTempConfigDir = useTempConfigDir;
|
|
56
|
+
exports.connectSecurity = connectSecurity;
|
|
57
|
+
exports.disconnectSecurity = disconnectSecurity;
|
|
56
58
|
exports.clearOryEnv = clearOryEnv;
|
|
57
59
|
exports.stubSessionSuccess = stubSessionSuccess;
|
|
58
60
|
exports.stubSessionInactive = stubSessionInactive;
|
|
@@ -61,12 +63,11 @@ exports.stubSessionMfaRequired = stubSessionMfaRequired;
|
|
|
61
63
|
exports.stubSessionExpired = stubSessionExpired;
|
|
62
64
|
exports.stubOAuth2Success = stubOAuth2Success;
|
|
63
65
|
exports.stubOAuth2Inactive = stubOAuth2Inactive;
|
|
66
|
+
exports.setTestPermissionMode = setTestPermissionMode;
|
|
64
67
|
exports.stubPermissionAllowed = stubPermissionAllowed;
|
|
65
68
|
exports.stubPermissionDenied = stubPermissionDenied;
|
|
66
69
|
exports.stubPermissionNetworkError = stubPermissionNetworkError;
|
|
67
70
|
exports.stubPermissionRateLimited = stubPermissionRateLimited;
|
|
68
|
-
exports.spyRelationshipCreated = spyRelationshipCreated;
|
|
69
|
-
exports.spyRelationshipCreateError = spyRelationshipCreateError;
|
|
70
71
|
exports.stubMcpAllowed = stubMcpAllowed;
|
|
71
72
|
exports.stubMcpServerDenied = stubMcpServerDenied;
|
|
72
73
|
exports.stubMcpToolDenied = stubMcpToolDenied;
|
|
@@ -76,8 +77,12 @@ const os = __importStar(require("node:os"));
|
|
|
76
77
|
const path = __importStar(require("node:path"));
|
|
77
78
|
const vitest_1 = require("vitest");
|
|
78
79
|
const client_js_1 = require("./client.js");
|
|
80
|
+
const config_js_1 = require("./config.js");
|
|
81
|
+
const opl_js_1 = require("./opl.js");
|
|
82
|
+
const permission_mode_js_1 = require("./permission-mode.js");
|
|
79
83
|
// Shared per-harness contract scenarios (session fail-open, gate
|
|
80
|
-
// translation,
|
|
84
|
+
// translation, Agent Security not connected). See contract-suite.ts for the
|
|
85
|
+
// adapter shape.
|
|
81
86
|
var contract_suite_js_1 = require("./contract-suite.js");
|
|
82
87
|
Object.defineProperty(exports, "runHarnessContractSuite", { enumerable: true, get: function () { return contract_suite_js_1.runHarnessContractSuite; } });
|
|
83
88
|
// ─── Client Helpers ────────────────────────────────────────────────
|
|
@@ -88,29 +93,31 @@ Object.defineProperty(exports, "runHarnessContractSuite", { enumerable: true, ge
|
|
|
88
93
|
function createMockClient(overrides) {
|
|
89
94
|
const client = new client_js_1.OryAgentClient({
|
|
90
95
|
projectUrl: "https://test.projects.oryapis.com",
|
|
91
|
-
apiKey: "test-api-key",
|
|
92
96
|
harness: "test",
|
|
93
97
|
sessionCacheTtlMs: 0,
|
|
94
98
|
...overrides,
|
|
95
99
|
});
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
// Delegation edges are recorded through the agent-security broker (a real
|
|
101
|
+
// `fetch` in production). Default it to a resolved no-op so session-start /
|
|
102
|
+
// sub-agent paths under test never make a network call; tests that assert the
|
|
103
|
+
// broker call override this via `spyRecordDelegation`.
|
|
104
|
+
vitest_1.vi.spyOn(client, "recordDelegation").mockResolvedValue({
|
|
105
|
+
nodeId: "agent:mock-node",
|
|
106
|
+
delegationChain: [],
|
|
107
|
+
});
|
|
103
108
|
return client;
|
|
104
109
|
}
|
|
105
110
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* model a failed probe.
|
|
111
|
+
* Spy on {@link OryAgentClient.recordDelegation} (the agent-security broker
|
|
112
|
+
* call the delegation writers use). Resolves to `result` (a stub node by
|
|
113
|
+
* default). Returns the spy so callers assert the broker inputs or
|
|
114
|
+
* `.mockRejectedValue(...)` a broker failure.
|
|
111
115
|
*/
|
|
112
|
-
function
|
|
113
|
-
|
|
116
|
+
function spyRecordDelegation(client, result = {
|
|
117
|
+
nodeId: "agent:mock-node",
|
|
118
|
+
delegationChain: [],
|
|
119
|
+
}) {
|
|
120
|
+
return vitest_1.vi.spyOn(client, "recordDelegation").mockResolvedValue(result);
|
|
114
121
|
}
|
|
115
122
|
/**
|
|
116
123
|
* Stub an internal API instance method on the client.
|
|
@@ -209,28 +216,27 @@ function makeSessionInactiveError() {
|
|
|
209
216
|
error: { id: "session_inactive", message: "No active session" },
|
|
210
217
|
});
|
|
211
218
|
}
|
|
212
|
-
// ───
|
|
219
|
+
// ─── Activity Assertions ──────────────────────────────────────────
|
|
213
220
|
/**
|
|
214
|
-
* Get all recorded
|
|
221
|
+
* Get all recorded activity events from a client, optionally filtered by event.
|
|
215
222
|
*/
|
|
216
|
-
function
|
|
217
|
-
const all = client.
|
|
218
|
-
return event ? all.filter((
|
|
223
|
+
function getActivityEvents(client, event) {
|
|
224
|
+
const all = client.logger.activities();
|
|
225
|
+
return event ? all.filter((entry) => entry.event === event) : all;
|
|
219
226
|
}
|
|
220
227
|
/**
|
|
221
|
-
* Assert the
|
|
222
|
-
* Checks the `toolName` attribute on each span.
|
|
228
|
+
* Assert the activity log recorded the expected tool names for an event type.
|
|
223
229
|
*/
|
|
224
|
-
function
|
|
225
|
-
const
|
|
226
|
-
const tools =
|
|
230
|
+
function expectActivityTools(client, event, expectedTools) {
|
|
231
|
+
const events = getActivityEvents(client, event);
|
|
232
|
+
const tools = events.map((entry) => entry.attributes?.toolName);
|
|
227
233
|
for (const tool of expectedTools) {
|
|
228
234
|
if (!tools.includes(tool)) {
|
|
229
|
-
throw new Error(`Expected
|
|
235
|
+
throw new Error(`Expected activity event "${event}" for tool "${tool}" but got: [${tools.join(", ")}]`);
|
|
230
236
|
}
|
|
231
237
|
}
|
|
232
|
-
if (
|
|
233
|
-
throw new Error(`Expected ${expectedTools.length} "${event}"
|
|
238
|
+
if (events.length !== expectedTools.length) {
|
|
239
|
+
throw new Error(`Expected ${expectedTools.length} "${event}" events but got ${events.length}: [${tools.join(", ")}]`);
|
|
234
240
|
}
|
|
235
241
|
}
|
|
236
242
|
// ─── Environment Helpers ───────────────────────────────────────────
|
|
@@ -244,12 +250,28 @@ function setOryEnv(overrides = {}) {
|
|
|
244
250
|
ORY_PROJECT_URL: "projectUrl" in overrides
|
|
245
251
|
? overrides.projectUrl
|
|
246
252
|
: "https://test.projects.oryapis.com",
|
|
247
|
-
|
|
248
|
-
|
|
253
|
+
ORY_AGENT_SECURITY_URL: "agentSecurityUrl" in overrides
|
|
254
|
+
? overrides.agentSecurityUrl
|
|
255
|
+
: "https://agents.console.ory.com",
|
|
256
|
+
// Both connection values default to present: tests exercise the
|
|
257
|
+
// *connected* posture unless they explicitly clear one.
|
|
258
|
+
ORY_OAUTH2_CLIENT_ID: "oauth2ClientId" in overrides ? overrides.oauth2ClientId : "test-login-client",
|
|
259
|
+
ORY_USER_OAUTH2_TOKEN: "userToken" in overrides ? overrides.userToken : "valid-token",
|
|
249
260
|
ORY_AGENT_SUBJECT_ID: overrides.subjectId,
|
|
250
261
|
ORY_PERMISSION_NAMESPACE: overrides.namespace,
|
|
251
|
-
|
|
262
|
+
// Disable the mode cache's TTL so each gate re-reads the stub — no stale
|
|
263
|
+
// memo bleeds across tests.
|
|
264
|
+
ORY_PERMISSION_MODE_TTL_MS: "0",
|
|
252
265
|
};
|
|
266
|
+
const prevMode = currentTestMode;
|
|
267
|
+
setTestPermissionMode("permissionMode" in overrides ? overrides.permissionMode : "enforce");
|
|
268
|
+
// Isolate the config dir too. The mode is now server-read and the session-start
|
|
269
|
+
// warm persists it to config.json; without isolation that warm would write the
|
|
270
|
+
// developer's real ~/.config and bleed between tests. A test that also calls
|
|
271
|
+
// useTempConfigDir just nests another temp dir on top (both restore cleanly).
|
|
272
|
+
const prevXdg = process.env.XDG_CONFIG_HOME;
|
|
273
|
+
const tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), "ory-env-config-"));
|
|
274
|
+
process.env.XDG_CONFIG_HOME = tmpHome;
|
|
253
275
|
for (const [key, value] of Object.entries(vars)) {
|
|
254
276
|
saved[key] = process.env[key];
|
|
255
277
|
if (value !== undefined) {
|
|
@@ -260,6 +282,7 @@ function setOryEnv(overrides = {}) {
|
|
|
260
282
|
}
|
|
261
283
|
}
|
|
262
284
|
return () => {
|
|
285
|
+
setTestPermissionMode(prevMode);
|
|
263
286
|
for (const [key, value] of Object.entries(saved)) {
|
|
264
287
|
if (value !== undefined) {
|
|
265
288
|
process.env[key] = value;
|
|
@@ -268,6 +291,11 @@ function setOryEnv(overrides = {}) {
|
|
|
268
291
|
delete process.env[key];
|
|
269
292
|
}
|
|
270
293
|
}
|
|
294
|
+
if (prevXdg !== undefined)
|
|
295
|
+
process.env.XDG_CONFIG_HOME = prevXdg;
|
|
296
|
+
else
|
|
297
|
+
delete process.env.XDG_CONFIG_HOME;
|
|
298
|
+
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
271
299
|
};
|
|
272
300
|
}
|
|
273
301
|
/**
|
|
@@ -277,7 +305,7 @@ function setOryEnv(overrides = {}) {
|
|
|
277
305
|
* that restores the env var and removes the temp directory.
|
|
278
306
|
*
|
|
279
307
|
* Use `saveConfig(...)` from `./config.js` inside the test to shape the
|
|
280
|
-
* isolated config (e.g. `saveConfig({
|
|
308
|
+
* isolated config (e.g. `saveConfig({ projectUrl, oauth2ClientId })`).
|
|
281
309
|
*/
|
|
282
310
|
function useTempConfigDir() {
|
|
283
311
|
const saved = process.env.XDG_CONFIG_HOME;
|
|
@@ -291,21 +319,65 @@ function useTempConfigDir() {
|
|
|
291
319
|
fs.rmSync(tmpHome, { recursive: true, force: true });
|
|
292
320
|
};
|
|
293
321
|
}
|
|
322
|
+
/** Placeholder values `connectSecurity` / `disconnectSecurity` write. */
|
|
323
|
+
exports.TEST_PROJECT_URL = "https://test.projects.oryapis.com";
|
|
324
|
+
exports.TEST_AGENT_SECURITY_URL = "https://agents.console.ory.com";
|
|
325
|
+
exports.TEST_OAUTH2_CLIENT_ID = "test-login-client";
|
|
326
|
+
/**
|
|
327
|
+
* Put the isolated config into the **connected** state so the auth gates and
|
|
328
|
+
* permission checks actually run.
|
|
329
|
+
*
|
|
330
|
+
* Agent Security is connected exactly when a project URL and an OAuth2 client
|
|
331
|
+
* id both resolve — there is no flag to set. Tests that exercise checks need
|
|
332
|
+
* both, and writing them through one named call keeps that requirement in one
|
|
333
|
+
* place instead of two literals in every `beforeEach`.
|
|
334
|
+
*
|
|
335
|
+
* Call after `useTempConfigDir()` so it writes to the temp config.
|
|
336
|
+
*/
|
|
337
|
+
function connectSecurity(overrides = {}) {
|
|
338
|
+
(0, config_js_1.saveConfig)({
|
|
339
|
+
projectUrl: overrides.projectUrl ?? exports.TEST_PROJECT_URL,
|
|
340
|
+
agentSecurityUrl: overrides.agentSecurityUrl ?? exports.TEST_AGENT_SECURITY_URL,
|
|
341
|
+
oauth2ClientId: overrides.oauth2ClientId ?? exports.TEST_OAUTH2_CLIENT_ID,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Put the isolated config into a partial connection state for contract tests.
|
|
346
|
+
*
|
|
347
|
+
* `which` selects which connection values are absent. The `no-client-id` case
|
|
348
|
+
* now exercises the reserved client default rather than a disconnected state.
|
|
349
|
+
* The `neither` and `no-project-url` forms remain disconnected.
|
|
350
|
+
*/
|
|
351
|
+
function disconnectSecurity(which = "neither") {
|
|
352
|
+
(0, config_js_1.saveConfig)({
|
|
353
|
+
projectUrl: which === "no-client-id" ? exports.TEST_PROJECT_URL : null,
|
|
354
|
+
agentSecurityUrl: which === "no-client-id" ? exports.TEST_AGENT_SECURITY_URL : null,
|
|
355
|
+
oauth2ClientId: which === "no-project-url" ? exports.TEST_OAUTH2_CLIENT_ID : null,
|
|
356
|
+
});
|
|
357
|
+
// Env wins over the file, so a leaked env var would silently reconnect.
|
|
358
|
+
delete process.env.ORY_PROJECT_URL;
|
|
359
|
+
delete process.env.ORY_SDK_URL;
|
|
360
|
+
delete process.env.ORY_AGENT_SECURITY_URL;
|
|
361
|
+
delete process.env.ORY_OAUTH2_CLIENT_ID;
|
|
362
|
+
if (which === "no-client-id")
|
|
363
|
+
process.env.ORY_PROJECT_URL = exports.TEST_PROJECT_URL;
|
|
364
|
+
if (which === "no-project-url")
|
|
365
|
+
process.env.ORY_OAUTH2_CLIENT_ID = exports.TEST_OAUTH2_CLIENT_ID;
|
|
366
|
+
}
|
|
294
367
|
/**
|
|
295
368
|
* Clear all Ory env vars (simulate unconfigured state).
|
|
296
369
|
*/
|
|
297
370
|
function clearOryEnv() {
|
|
298
371
|
delete process.env.ORY_PROJECT_URL;
|
|
299
|
-
delete process.env.
|
|
300
|
-
delete process.env.
|
|
301
|
-
delete process.env.
|
|
372
|
+
delete process.env.ORY_AGENT_SECURITY_URL;
|
|
373
|
+
delete process.env.ORY_OAUTH2_CLIENT_ID;
|
|
374
|
+
delete process.env.ORY_USER_OAUTH2_TOKEN;
|
|
302
375
|
delete process.env.ORY_AGENT_SUBJECT_ID;
|
|
303
376
|
delete process.env.ORY_USER_SUBJECT_ID;
|
|
304
377
|
delete process.env.ORY_USER_SUBJECT_NAMESPACE;
|
|
305
378
|
delete process.env.ORY_PERMISSION_NAMESPACE;
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
// behavior, and unconfigured-Ory tests don't exercise permission
|
|
379
|
+
// The mode is a server-read permission now (no env var). Leave the stub's
|
|
380
|
+
// `currentTestMode` alone — unconfigured-Ory tests don't exercise permission
|
|
309
381
|
// checks anyway.
|
|
310
382
|
}
|
|
311
383
|
// ─── Stub Presets ──────────────────────────────────────────────────
|
|
@@ -337,55 +409,100 @@ function stubOAuth2Success(client) {
|
|
|
337
409
|
function stubOAuth2Inactive(client) {
|
|
338
410
|
return stubApi(client, "oauth2", "introspectOAuth2Token", () => Promise.resolve(exports.MOCK_INACTIVE_OAUTH2_RESPONSE));
|
|
339
411
|
}
|
|
412
|
+
// ─── Permission mode (server-read) test control ────────────────────
|
|
413
|
+
//
|
|
414
|
+
// The gate now resolves observe/enforce by issuing a `checkPermission` against
|
|
415
|
+
// the reserved `__ory_permission_mode__#enforce` object (see permission-mode.ts).
|
|
416
|
+
// So the generic checkPermission stubs must answer THAT check with the desired
|
|
417
|
+
// mode and every OTHER check with the tool decision. `currentTestMode` holds the
|
|
418
|
+
// mode a test wants (default `enforce`, preserving the historical default where
|
|
419
|
+
// `setOryEnv` pinned enforce so deny-path assertions blocked).
|
|
420
|
+
let currentTestMode = "enforce";
|
|
421
|
+
/**
|
|
422
|
+
* Set the mode the server-read stub reports. Also clears the in-memory
|
|
423
|
+
* permission-mode cache so the new value takes effect immediately (tests run
|
|
424
|
+
* with `ORY_PERMISSION_MODE_TTL_MS=0`, but resetting is belt-and-suspenders).
|
|
425
|
+
*/
|
|
426
|
+
function setTestPermissionMode(mode) {
|
|
427
|
+
currentTestMode = mode;
|
|
428
|
+
(0, permission_mode_js_1.resetPermissionModeCache)();
|
|
429
|
+
}
|
|
430
|
+
/** True when a checkPermission's params target the permission-mode object. */
|
|
431
|
+
function isModeCheck(args) {
|
|
432
|
+
const p = args[0];
|
|
433
|
+
return p?.object === opl_js_1.PERMISSION_MODE_OBJECT && p?.relation === opl_js_1.RELATION_ENFORCED_SUBJECTS;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Build a `checkPermission` impl that answers the mode check with
|
|
437
|
+
* `currentTestMode` and every other check with `toolResponse`. Every stub below
|
|
438
|
+
* routes through this so a single test setting controls the mode independently
|
|
439
|
+
* of the tool decision.
|
|
440
|
+
*/
|
|
441
|
+
function checkPermissionResponder(toolResponse) {
|
|
442
|
+
return (...args) => {
|
|
443
|
+
if (isModeCheck(args)) {
|
|
444
|
+
return Promise.resolve(currentTestMode === "enforce" ? exports.PERMISSION_ALLOWED : exports.PERMISSION_DENIED);
|
|
445
|
+
}
|
|
446
|
+
return Promise.resolve(toolResponse);
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
function ensurePermissionCredential(client) {
|
|
450
|
+
if (client.agentPrincipal.token)
|
|
451
|
+
return;
|
|
452
|
+
client.setAgentPrincipal({ ...client.agentPrincipal, token: "test-agent-token" });
|
|
453
|
+
}
|
|
340
454
|
/** Stub checkPermission to allow. */
|
|
341
455
|
function stubPermissionAllowed(client) {
|
|
342
|
-
|
|
456
|
+
ensurePermissionCredential(client);
|
|
457
|
+
stubApi(client, "permission", "batchCheckPermission", (request) => {
|
|
458
|
+
const tuples = request.batchCheckPermissionBody?.tuples ?? [];
|
|
459
|
+
return Promise.resolve({
|
|
460
|
+
data: {
|
|
461
|
+
results: tuples.map((tuple) => ({
|
|
462
|
+
// "Allowed" means the requested action is granted; an explicit
|
|
463
|
+
// block probe must remain absent or it would reverse that decision.
|
|
464
|
+
allowed: tuple.relation !== "blockedSubjects",
|
|
465
|
+
})),
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
return stubApi(client, "permission", "checkPermission", checkPermissionResponder(exports.PERMISSION_ALLOWED));
|
|
343
470
|
}
|
|
344
|
-
/** Stub checkPermission to deny. */
|
|
471
|
+
/** Stub checkPermission to deny (the tool check; the mode check still answers `currentTestMode`). */
|
|
345
472
|
function stubPermissionDenied(client) {
|
|
346
|
-
|
|
473
|
+
ensurePermissionCredential(client);
|
|
474
|
+
return stubApi(client, "permission", "checkPermission", checkPermissionResponder(exports.PERMISSION_DENIED));
|
|
347
475
|
}
|
|
348
476
|
/** Stub checkPermission to throw a network error. */
|
|
349
477
|
function stubPermissionNetworkError(client) {
|
|
478
|
+
ensurePermissionCredential(client);
|
|
350
479
|
return stubApi(client, "permission", "checkPermission", () => Promise.reject(makeNetworkError()));
|
|
351
480
|
}
|
|
352
481
|
/** Stub checkPermission to throw a rate-limit error. */
|
|
353
482
|
function stubPermissionRateLimited(client) {
|
|
483
|
+
ensurePermissionCredential(client);
|
|
354
484
|
return stubApi(client, "permission", "checkPermission", () => Promise.reject(makeRateLimitError()));
|
|
355
485
|
}
|
|
356
|
-
/**
|
|
357
|
-
* Spy on the public `createRelationship` method and resolve successfully.
|
|
358
|
-
* Prefer this over stubbing the internal relationship API: `setAgentPrincipal`
|
|
359
|
-
* rebuilds the API instances when the agent token changes (e.g. inside
|
|
360
|
-
* `sessionStart`), which silently discards API-level stubs.
|
|
361
|
-
*/
|
|
362
|
-
function spyRelationshipCreated(client) {
|
|
363
|
-
return vitest_1.vi
|
|
364
|
-
.spyOn(client, "createRelationship")
|
|
365
|
-
.mockResolvedValue({ created: true, alreadyExisted: false });
|
|
366
|
-
}
|
|
367
|
-
/** Spy on the public `createRelationship` method and reject. */
|
|
368
|
-
function spyRelationshipCreateError(client) {
|
|
369
|
-
return vitest_1.vi
|
|
370
|
-
.spyOn(client, "createRelationship")
|
|
371
|
-
.mockRejectedValue(new Error("relationship write failed"));
|
|
372
|
-
}
|
|
373
486
|
// ─── MCP Stub Presets ─────────────────────────────────────────────
|
|
374
487
|
/** Stub both checkPermission (server allow) and batchCheckPermission (both allow). */
|
|
375
488
|
function stubMcpAllowed(client) {
|
|
376
|
-
|
|
489
|
+
ensurePermissionCredential(client);
|
|
490
|
+
stubApi(client, "permission", "checkPermission", checkPermissionResponder(exports.PERMISSION_ALLOWED));
|
|
377
491
|
return stubApi(client, "permission", "batchCheckPermission", () => Promise.resolve(exports.BATCH_BOTH_ALLOWED));
|
|
378
492
|
}
|
|
379
493
|
/** Stub checkPermission to deny (server-only MCP check). */
|
|
380
494
|
function stubMcpServerDenied(client) {
|
|
381
|
-
|
|
495
|
+
ensurePermissionCredential(client);
|
|
496
|
+
return stubApi(client, "permission", "checkPermission", checkPermissionResponder(exports.PERMISSION_DENIED));
|
|
382
497
|
}
|
|
383
498
|
/** Stub batchCheckPermission: server allowed, tool denied. */
|
|
384
499
|
function stubMcpToolDenied(client) {
|
|
385
|
-
|
|
500
|
+
ensurePermissionCredential(client);
|
|
501
|
+
stubApi(client, "permission", "checkPermission", checkPermissionResponder(exports.PERMISSION_ALLOWED));
|
|
386
502
|
return stubApi(client, "permission", "batchCheckPermission", () => Promise.resolve(exports.BATCH_SERVER_ALLOWED_TOOL_DENIED));
|
|
387
503
|
}
|
|
388
504
|
/** Stub checkPermission to throw network error (MCP fail-open). */
|
|
389
505
|
function stubMcpNetworkError(client) {
|
|
506
|
+
ensurePermissionCredential(client);
|
|
390
507
|
return stubApi(client, "permission", "checkPermission", () => Promise.reject(makeNetworkError()));
|
|
391
508
|
}
|
package/dist/tool-catalog.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Canonical per-harness tool catalog
|
|
3
|
-
*
|
|
2
|
+
* Canonical per-harness tool catalog: the objects an Ory project grants `use`
|
|
3
|
+
* on, and the set `permissions status` probes coverage across.
|
|
4
4
|
*
|
|
5
5
|
* These lists cover each harness's built-in tools — the names the harness
|
|
6
6
|
* passes to the pre-tool-use hook. MCP server tools are intentionally
|
|
7
7
|
* omitted because they're discovered dynamically per session and can't be
|
|
8
|
-
* enumerated
|
|
8
|
+
* enumerated ahead of time.
|
|
9
9
|
*
|
|
10
|
-
* The lists are best-effort: harness vendors add and rename tools over
|
|
11
|
-
*
|
|
12
|
-
* catalog update is safe.
|
|
10
|
+
* The lists are best-effort: harness vendors add and rename tools over time,
|
|
11
|
+
* so a project's grants may cover more or fewer names than the catalog knows.
|
|
13
12
|
*/
|
|
14
13
|
/**
|
|
15
14
|
* Built-in tool names known to ship with each supported harness.
|
|
@@ -27,6 +26,7 @@ export declare const HARNESS_TOOL_CATALOG: {
|
|
|
27
26
|
readonly amp: readonly ["Bash", "Read", "create_file", "edit_file", "undo_edit", "glob", "Grep", "finder", "read_web_page", "web_search", "todo_read", "todo_write", "oracle", "Task"];
|
|
28
27
|
readonly pi: readonly ["read", "write", "edit", "bash", "grep", "find", "ls"];
|
|
29
28
|
readonly antigravity: readonly ["run_command", "view_file", "write_to_file", "replace_file_content", "multi_replace_file_content", "list_directory", "grep_search", "find", "read_url_content", "search_web", "call_mcp_tool"];
|
|
29
|
+
readonly cursor: readonly ["Read", "Write", "Edit", "Delete", "Shell", "List", "Search", "MCP", "Task"];
|
|
30
30
|
};
|
|
31
31
|
/** Names of the harnesses with a known tool catalog. */
|
|
32
32
|
export type KnownHarness = keyof typeof HARNESS_TOOL_CATALOG;
|
|
@@ -34,13 +34,12 @@ export declare const KNOWN_HARNESSES: readonly KnownHarness[];
|
|
|
34
34
|
/**
|
|
35
35
|
* Tools for a specific harness. Returns the canonical list when known;
|
|
36
36
|
* empty array for unknown harnesses (callers can fall back to {@link
|
|
37
|
-
* ALL_TOOLS} or skip
|
|
37
|
+
* ALL_TOOLS} or skip the catalog-scoped step with a warning).
|
|
38
38
|
*/
|
|
39
39
|
export declare function getToolCatalog(harness: string): readonly string[];
|
|
40
40
|
/**
|
|
41
|
-
* Union of every known tool across all harnesses, deduplicated. Used by
|
|
42
|
-
*
|
|
43
|
-
* broad access so the same launcher can run every harness end-to-end.
|
|
41
|
+
* Union of every known tool across all harnesses, deduplicated. Used by local
|
|
42
|
+
* environment seeding to grant broad access across every built-in tool set.
|
|
44
43
|
*/
|
|
45
44
|
export declare const ALL_TOOLS: readonly string[];
|
|
46
45
|
/**
|
|
@@ -53,7 +52,7 @@ export declare const ALL_TOOLS: readonly string[];
|
|
|
53
52
|
* the user is about to handle directly.
|
|
54
53
|
*
|
|
55
54
|
* Plugins consult this list in their pre-tool gate and short-circuit to
|
|
56
|
-
* a single `user.interaction` audit
|
|
55
|
+
* a single `user.interaction` audit event when a match is found. See
|
|
57
56
|
* `gateToolCall` in `permissions.ts`.
|
|
58
57
|
*
|
|
59
58
|
* The list is best-effort and additive: operators can extend it at
|
|
@@ -74,3 +73,46 @@ export declare function getInteractiveToolCatalog(harness: string): readonly str
|
|
|
74
73
|
* env-var extension still applies.
|
|
75
74
|
*/
|
|
76
75
|
export declare function isInteractiveTool(harness: string, toolName: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Per-harness name(s) of the shell/exec tool whose input is decomposed into
|
|
78
|
+
* `ShellTool:<word>#use` sub-checks. Validated against each harness's
|
|
79
|
+
* types/handlers. Names vary (`Bash`, `shell`, `exec`, `run_command`, …) so a
|
|
80
|
+
* precise map is used rather than the {@link isBashLikeTool} heuristic.
|
|
81
|
+
*/
|
|
82
|
+
export declare const SHELL_TOOL_CATALOG: Record<string, readonly string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Shell-tool names for a harness, merged with the operator env extension
|
|
85
|
+
* `ORY_SHELL_TOOLS` (same pattern as `ORY_INTERACTIVE_TOOLS`) so a vendor tool
|
|
86
|
+
* rename can be handled without a plugin release.
|
|
87
|
+
*/
|
|
88
|
+
export declare function getShellToolCatalog(harness: string): readonly string[];
|
|
89
|
+
/** Is the named tool, for this harness, the shell/exec tool to decompose? */
|
|
90
|
+
export declare function isShellTool(harness: string, toolName: string): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Broad list of shell command *words* — common dev binaries, sensitive
|
|
93
|
+
* binaries, and builtins — that an Ory project is expected to grant `use` on
|
|
94
|
+
* so enforce mode is practical out of the box; revoke a specific word in the
|
|
95
|
+
* Ory Console to close it. Builtins are included because they are a real
|
|
96
|
+
* bypass surface (`echo "$SECRET" >/dev/tcp/…`, `read`, redirection tricks).
|
|
97
|
+
* `permissions status` reports coverage against this list.
|
|
98
|
+
*/
|
|
99
|
+
export declare const SHELL_COMMAND_CATALOG: readonly string[];
|
|
100
|
+
/**
|
|
101
|
+
* The shell command word list, merged with the operator env extension
|
|
102
|
+
* `ORY_SHELL_COMMANDS`.
|
|
103
|
+
*/
|
|
104
|
+
export declare function getShellCommandCatalog(): readonly string[];
|
|
105
|
+
/**
|
|
106
|
+
* Keto namespace for shell-command sub-tools. Defaults to `ShellTool`,
|
|
107
|
+
* parallel to `mcp_servers` / `mcp_tools`. The object is the bare word (`curl`),
|
|
108
|
+
* relation `use`. Override with `ORY_SHELL_COMMAND_NAMESPACE`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resolveShellCommandNamespace(): string;
|
|
111
|
+
/**
|
|
112
|
+
* Extract the shell command string from a harness's tool-args object — the same
|
|
113
|
+
* object the handler already passes to `summarizeToolInput`. Returns `undefined`
|
|
114
|
+
* when the tool isn't a shell tool for this harness or no command field is
|
|
115
|
+
* present (the gate then skips decomposition and degrades to the top-level
|
|
116
|
+
* `Bash` check — it never breaks).
|
|
117
|
+
*/
|
|
118
|
+
export declare function extractShellCommand(harness: string, toolName: string, args: unknown): string | undefined;
|