@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/status-data.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.probePermissionsCoverage = probePermissionsCoverage;
|
|
37
|
+
exports.resolveDynamicName = resolveDynamicName;
|
|
37
38
|
exports.collectStatusReport = collectStatusReport;
|
|
38
39
|
/**
|
|
39
40
|
* Structured status data — the data-gathering half of the `status` command,
|
|
@@ -48,23 +49,34 @@ exports.collectStatusReport = collectStatusReport;
|
|
|
48
49
|
* implementation.
|
|
49
50
|
*/
|
|
50
51
|
const config_js_1 = require("./config.js");
|
|
52
|
+
const permission_mode_js_1 = require("./permission-mode.js");
|
|
53
|
+
const permissions_js_1 = require("./permissions.js");
|
|
51
54
|
const auth_store_js_1 = require("./auth-store.js");
|
|
52
55
|
const agent_auth_js_1 = require("./agent-auth.js");
|
|
53
|
-
const client_js_1 = require("./client.js");
|
|
54
56
|
const subject_js_1 = require("./subject.js");
|
|
57
|
+
const client_js_1 = require("./client.js");
|
|
58
|
+
const subject_js_2 = require("./subject.js");
|
|
55
59
|
const branding_js_1 = require("./branding.js");
|
|
60
|
+
const auth_js_1 = require("./auth.js");
|
|
61
|
+
const node_os_1 = require("node:os");
|
|
56
62
|
const tool_catalog_js_1 = require("./tool-catalog.js");
|
|
63
|
+
const opl_js_1 = require("./opl.js");
|
|
57
64
|
const fs = __importStar(require("node:fs"));
|
|
58
65
|
// Additive dashboard section: core Ory service health (see status-system.ts).
|
|
59
66
|
const status_system_js_1 = require("./status-system.js");
|
|
60
67
|
function resolveNamespace() {
|
|
61
|
-
return process.env.ORY_PERMISSION_NAMESPACE ?? "
|
|
68
|
+
return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTool";
|
|
62
69
|
}
|
|
63
70
|
/**
|
|
64
71
|
* Probe the harness's built-in tool catalog against Ory, returning how many
|
|
65
|
-
* tools the resolved user subject is allowed / denied / errored on
|
|
66
|
-
*
|
|
67
|
-
* identity). Never
|
|
72
|
+
* tools the resolved user subject is allowed / denied / errored on, plus the
|
|
73
|
+
* live permission mode and the subject that was checked. Returns undefined when
|
|
74
|
+
* a probe can't run (no project URL, empty catalog, no user identity). Never
|
|
75
|
+
* throws.
|
|
76
|
+
*
|
|
77
|
+
* Checks route through {@link resolveCheckRelation}, i.e. the `access` permit —
|
|
78
|
+
* the same relation the runtime gate evaluates — so a tool carrying an explicit
|
|
79
|
+
* block is reported as denied here too, exactly as a tool call would be.
|
|
68
80
|
*/
|
|
69
81
|
async function probePermissionsCoverage(harness) {
|
|
70
82
|
const resolved = (0, config_js_1.resolveConfig)();
|
|
@@ -85,16 +97,30 @@ async function probePermissionsCoverage(harness) {
|
|
|
85
97
|
await (0, agent_auth_js_1.ensureAgentIdentity)(client, { projectUrl: resolved.projectUrl }).catch(() => {
|
|
86
98
|
/* best-effort; the probe still runs with whatever credentials we have */
|
|
87
99
|
});
|
|
88
|
-
const subject = (0,
|
|
89
|
-
|
|
100
|
+
const subject = (0, subject_js_2.resolveUserSubject)(client);
|
|
101
|
+
const subjectId = (0, subject_js_2.subjectLabel)(subject);
|
|
102
|
+
if (subjectId === "agent:unknown")
|
|
90
103
|
return undefined;
|
|
104
|
+
const agentSubject = (0, subject_js_2.resolveAgentSubject)(client);
|
|
105
|
+
const live = await (0, permission_mode_js_1.resolvePermissionMode)(client, subject, {
|
|
106
|
+
additionalSubjects: agentSubject ? [{ scope: "agent", subject: agentSubject }] : [],
|
|
107
|
+
});
|
|
91
108
|
const namespace = resolveNamespace();
|
|
92
|
-
const
|
|
109
|
+
const relation = (0, permissions_js_1.resolveCheckRelation)("users");
|
|
110
|
+
const result = {
|
|
111
|
+
total: catalog.length,
|
|
112
|
+
allowed: 0,
|
|
113
|
+
denied: 0,
|
|
114
|
+
errored: 0,
|
|
115
|
+
mode: live.mode,
|
|
116
|
+
modeSource: live.source,
|
|
117
|
+
subject: subjectId,
|
|
118
|
+
};
|
|
93
119
|
for (const tool of catalog) {
|
|
94
|
-
const check = { namespace, object: tool, relation
|
|
120
|
+
const check = { namespace, object: tool, relation, ...subject };
|
|
95
121
|
try {
|
|
96
122
|
const probe = await client.checkPermission(check, {
|
|
97
|
-
|
|
123
|
+
activityAttributes: { toolName: tool, source: "status_coverage" },
|
|
98
124
|
});
|
|
99
125
|
if (probe.allowed)
|
|
100
126
|
result.allowed++;
|
|
@@ -121,17 +147,18 @@ function collectConfig(harness) {
|
|
|
121
147
|
projectIdSource: r.projectIdSource,
|
|
122
148
|
projectName: r.projectName,
|
|
123
149
|
workspaceName: r.workspaceName,
|
|
124
|
-
apiKeyConfigured: !!r.apiKey,
|
|
125
|
-
apiKeySource: r.apiKeySource,
|
|
126
150
|
oauth2ClientId: r.oauth2ClientId,
|
|
127
151
|
oauth2ClientIdSource: r.oauth2ClientIdSource,
|
|
128
|
-
oauth2ClientName:
|
|
129
|
-
|
|
152
|
+
oauth2ClientName: (0, branding_js_1.isUserLoginClient)({ clientId: r.oauth2ClientId })
|
|
153
|
+
? branding_js_1.USER_LOGIN_CLIENT_NAME
|
|
154
|
+
: undefined,
|
|
155
|
+
security: r.security,
|
|
130
156
|
permissionMode: r.permissionMode,
|
|
131
157
|
permissionModeSource: r.permissionModeSource,
|
|
132
158
|
userSubjectNamespace: r.userSubjectNamespace,
|
|
133
159
|
userSubjectNamespaceSource: r.userSubjectNamespaceSource,
|
|
134
160
|
namespace: resolveNamespace(),
|
|
161
|
+
principalNamespaces: [...opl_js_1.PRINCIPAL_NAMESPACES],
|
|
135
162
|
debugEnabled: process.env.ORY_AGENT_DEBUG === "true",
|
|
136
163
|
};
|
|
137
164
|
}
|
|
@@ -144,45 +171,98 @@ function collectUser() {
|
|
|
144
171
|
return {
|
|
145
172
|
tokenCache: (0, auth_store_js_1.isExpired)(tokens) ? "stale" : "present",
|
|
146
173
|
subject: tokens.subject,
|
|
174
|
+
displayName: tokens.displayName ?? (0, auth_js_1.displayNameFromIdToken)(tokens.idToken),
|
|
147
175
|
expiresInSeconds: tokens.expiresAt - nowSec,
|
|
148
176
|
clientId: tokens.clientId,
|
|
149
177
|
};
|
|
150
178
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Human-readable name for a DCR agent / sub-agent credential: the persisted
|
|
181
|
+
* `client_name` when present, else a best-effort reconstruction from the
|
|
182
|
+
* harness and (for sub-agents) type. Reconstruction uses the current hostname,
|
|
183
|
+
* which may differ from the registration host for credentials saved before the
|
|
184
|
+
* name was persisted — acceptable for a display-only label.
|
|
185
|
+
*/
|
|
186
|
+
function resolveDynamicName(creds, subAgentType, harness) {
|
|
187
|
+
return (creds.clientName ??
|
|
188
|
+
(0, branding_js_1.agentClientName)({
|
|
189
|
+
harness: creds.harness ?? harness,
|
|
190
|
+
host: (0, node_os_1.hostname)() || "unknown-host",
|
|
191
|
+
subAgentType,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
function collectAgent(harness, sessionKey) {
|
|
155
195
|
if (process.env.ORY_AGENT_CLIENT_ID && process.env.ORY_AGENT_CLIENT_SECRET) {
|
|
156
196
|
return {
|
|
157
197
|
source: "static_client_credentials",
|
|
158
198
|
clientId: process.env.ORY_AGENT_CLIENT_ID,
|
|
159
|
-
subject:
|
|
199
|
+
subject: (0, subject_js_2.readAgentSubjectOverride)() ?? process.env.ORY_AGENT_CLIENT_ID,
|
|
160
200
|
};
|
|
161
201
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
202
|
+
const selected = sessionKey
|
|
203
|
+
? (() => {
|
|
204
|
+
const credentials = (0, agent_auth_js_1.loadAgentDynamicCredentials)(harness, sessionKey);
|
|
205
|
+
return credentials ? { sessionKey, credentials } : undefined;
|
|
206
|
+
})()
|
|
207
|
+
: (0, agent_auth_js_1.latestAgentRegistration)(harness);
|
|
208
|
+
if (!selected)
|
|
164
209
|
return { source: "unregistered" };
|
|
210
|
+
const { sessionKey: credentialSession, credentials: persisted } = selected;
|
|
165
211
|
const resolved = (0, config_js_1.resolveConfig)();
|
|
166
212
|
const mismatch = resolved.projectUrl && persisted.projectUrl !== resolved.projectUrl
|
|
167
213
|
? { registeredAgainst: persisted.projectUrl, current: resolved.projectUrl }
|
|
168
214
|
: undefined;
|
|
215
|
+
const subject = (0, subject_js_2.readAgentSubjectOverride)() ?? persisted.clientId;
|
|
169
216
|
return {
|
|
170
217
|
source: "dcr",
|
|
218
|
+
name: resolveDynamicName(persisted, undefined, harness),
|
|
219
|
+
sessionKey: credentialSession,
|
|
220
|
+
...(credentialSession === config_js_1.SESSIONLESS_KEY
|
|
221
|
+
? {}
|
|
222
|
+
: { sessionSubject: `${subject_js_1.AGENT_NAMESPACE}:${subject}|${credentialSession}` }),
|
|
171
223
|
clientId: persisted.clientId,
|
|
172
|
-
subject
|
|
224
|
+
subject,
|
|
173
225
|
registeredAt: new Date(persisted.registeredAt * 1000).toISOString(),
|
|
174
226
|
projectUrlMismatch: mismatch,
|
|
175
227
|
};
|
|
176
228
|
}
|
|
229
|
+
function collectSubAgents(harness, requestedSession) {
|
|
230
|
+
const sessionKey = requestedSession
|
|
231
|
+
?? (0, agent_auth_js_1.latestAgentRegistration)(harness)?.sessionKey
|
|
232
|
+
?? (0, agent_auth_js_1.latestSubAgentSession)(harness);
|
|
233
|
+
const persisted = sessionKey ? (0, agent_auth_js_1.loadAllSubAgentDynamicCredentials)(harness, sessionKey) : {};
|
|
234
|
+
const resolved = (0, config_js_1.resolveConfig)();
|
|
235
|
+
return Object.entries(persisted)
|
|
236
|
+
.map(([subAgentType, creds]) => {
|
|
237
|
+
const mismatch = resolved.projectUrl && creds.projectUrl !== resolved.projectUrl
|
|
238
|
+
? { registeredAgainst: creds.projectUrl, current: resolved.projectUrl }
|
|
239
|
+
: undefined;
|
|
240
|
+
return {
|
|
241
|
+
subAgentType,
|
|
242
|
+
name: resolveDynamicName(creds, subAgentType, harness),
|
|
243
|
+
clientId: creds.clientId,
|
|
244
|
+
subject: creds.clientId,
|
|
245
|
+
registeredAt: new Date(creds.registeredAt * 1000).toISOString(),
|
|
246
|
+
delegatedBy: creds.delegation?.delegatedBy,
|
|
247
|
+
projectUrlMismatch: mismatch,
|
|
248
|
+
};
|
|
249
|
+
})
|
|
250
|
+
.sort((a, b) => a.subAgentType.localeCompare(b.subAgentType));
|
|
251
|
+
}
|
|
177
252
|
async function collectPermissions(harness) {
|
|
178
253
|
const resolved = (0, config_js_1.resolveConfig)();
|
|
179
254
|
const namespace = resolveNamespace();
|
|
180
255
|
const catalog = (0, tool_catalog_js_1.getToolCatalog)(harness);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
256
|
+
// Falls back to the last-known cached mode on every path that can't reach the
|
|
257
|
+
// project to read it live.
|
|
258
|
+
const base = {
|
|
259
|
+
mode: resolved.permissionMode,
|
|
260
|
+
modeSource: resolved.permissionModeSource,
|
|
261
|
+
namespace,
|
|
262
|
+
};
|
|
263
|
+
// One reason covers both missing values: with either absent no check can run.
|
|
264
|
+
if (!resolved.security.connected)
|
|
265
|
+
return { ...base, coverageStatus: "not_connected" };
|
|
186
266
|
if (catalog.length === 0) {
|
|
187
267
|
return { ...base, coverageStatus: "no_catalog", knownHarnesses: [...tool_catalog_js_1.KNOWN_HARNESSES] };
|
|
188
268
|
}
|
|
@@ -192,15 +272,17 @@ async function collectPermissions(harness) {
|
|
|
192
272
|
const coverage = await probePermissionsCoverage(harness);
|
|
193
273
|
if (!coverage)
|
|
194
274
|
return { ...base, coverageStatus: "no_user" };
|
|
275
|
+
// The probe read the mode live; prefer it over the cached config value.
|
|
276
|
+
const withMode = { ...base, mode: coverage.mode, modeSource: coverage.modeSource };
|
|
195
277
|
if (coverage.errored > 0 && coverage.allowed === 0 && coverage.denied === 0) {
|
|
196
|
-
return { ...
|
|
278
|
+
return { ...withMode, coverageStatus: "probe_failed", coverage };
|
|
197
279
|
}
|
|
198
280
|
const status = coverage.allowed === coverage.total
|
|
199
|
-
? "
|
|
281
|
+
? "fully_granted"
|
|
200
282
|
: coverage.allowed === 0
|
|
201
|
-
? "
|
|
283
|
+
? "no_grants"
|
|
202
284
|
: "partial";
|
|
203
|
-
return { ...
|
|
285
|
+
return { ...withMode, coverageStatus: status, coverage };
|
|
204
286
|
}
|
|
205
287
|
function isUserTokenUsable() {
|
|
206
288
|
const tokens = (0, auth_store_js_1.loadTokens)();
|
|
@@ -221,28 +303,29 @@ function readTail(file, limit) {
|
|
|
221
303
|
return { file, count: lines.length, recent };
|
|
222
304
|
}
|
|
223
305
|
function collectActivity(harness) {
|
|
224
|
-
const trace = readTail((0, client_js_1.resolveTraceFilePath)(harness), 10);
|
|
225
306
|
const log = readTail((0, client_js_1.resolveDebugLogPath)(harness), 10);
|
|
226
307
|
return {
|
|
227
|
-
traceFile: trace.file,
|
|
228
|
-
traceCount: trace.count,
|
|
229
|
-
recentSpans: trace.recent,
|
|
230
308
|
logFile: log.file,
|
|
231
309
|
logCount: log.count,
|
|
232
|
-
|
|
310
|
+
recentEvents: log.recent,
|
|
233
311
|
};
|
|
234
312
|
}
|
|
235
313
|
/**
|
|
236
314
|
* Gather the full structured status report for a harness. The permissions
|
|
237
315
|
* section runs a live network probe when a project URL and user identity are
|
|
238
316
|
* available (same conditions as the text `status` command).
|
|
317
|
+
*
|
|
318
|
+
* `sessionKey` is the run being reported on, when the caller is inside one. The
|
|
319
|
+
* standalone CLI passes none, so the report selects the harness's newest stored
|
|
320
|
+
* session rather than inventing an ambient session.
|
|
239
321
|
*/
|
|
240
|
-
async function collectStatusReport(harness) {
|
|
322
|
+
async function collectStatusReport(harness, sessionKey) {
|
|
241
323
|
return {
|
|
242
324
|
harness,
|
|
243
325
|
config: collectConfig(harness),
|
|
244
326
|
user: collectUser(),
|
|
245
|
-
agent: collectAgent(),
|
|
327
|
+
agent: collectAgent(harness, sessionKey),
|
|
328
|
+
subAgents: collectSubAgents(harness, sessionKey),
|
|
246
329
|
permissions: await collectPermissions(harness),
|
|
247
330
|
activity: collectActivity(harness),
|
|
248
331
|
system: await (0, status_system_js_1.collectSystemServices)(),
|
package/dist/subject.d.ts
CHANGED
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* User-subject resolution for permission checks.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Every principal — user, agent, sub-agent — is addressed as a **SubjectSet**
|
|
5
|
+
* `<namespace>:<object>` (e.g. `User:<UUID>`). This is the form the Ory Console's
|
|
6
|
+
* *Add relationship* dialog writes, the form the local-stack seed writes, and the
|
|
7
|
+
* Zanzibar-idiomatic composition point (grant `Role:developer` `use` on a tool and
|
|
8
|
+
* add principals to the role, rather than fanning out a tuple per subject). It is
|
|
9
|
+
* the only first-class subject form: Keto does no cross-form expansion, so a check
|
|
10
|
+
* must match the write shape exactly, and standardizing on one shape removes that
|
|
11
|
+
* silent-misfire footgun.
|
|
6
12
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `session:<id>`). Backward-compatible default when no subject
|
|
13
|
-
* namespace is configured.
|
|
14
|
-
*
|
|
15
|
-
* The selection is driven by the user-subject namespace: `ORY_USER_SUBJECT_NAMESPACE`
|
|
16
|
-
* takes precedence, then the client's configured `userSubjectNamespace` (persisted
|
|
17
|
-
* in the shared config, e.g. by the local-stack install path). When a namespace is
|
|
18
|
-
* present the resolver builds a SubjectSet using it; otherwise it falls back to the
|
|
19
|
-
* direct SubjectID chain.
|
|
13
|
+
* The namespace is resolved by precedence: `ORY_USER_SUBJECT_NAMESPACE` (env) →
|
|
14
|
+
* the client's configured `userSubjectNamespace` (persisted in the shared config)
|
|
15
|
+
* → the {@link DEFAULT_USER_SUBJECT_NAMESPACE} (`User`). The env/config values now
|
|
16
|
+
* *override* the default namespace; they are no longer an opt-in switch that
|
|
17
|
+
* toggles between SubjectSet and a legacy direct SubjectID.
|
|
20
18
|
*/
|
|
21
19
|
import type { OryAgentClient } from "./client.js";
|
|
20
|
+
/**
|
|
21
|
+
* Default namespace a resolved user principal is addressed under. The
|
|
22
|
+
* local-stack seed, the Console *Add relationship* dialog, and the Network OPL
|
|
23
|
+
* provisioning all use `User`, so it is the out-of-the-box default.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DEFAULT_USER_SUBJECT_NAMESPACE = "User";
|
|
26
|
+
/** Namespace the agent principal is addressed under (delegation subjects). */
|
|
27
|
+
export declare const AGENT_NAMESPACE = "Agent";
|
|
28
|
+
/** Namespace a sub-agent principal is addressed under. */
|
|
29
|
+
export declare const SUBAGENT_NAMESPACE = "SubAgent";
|
|
30
|
+
/** Namespace the no-user-identity `session:<id>` fallback is addressed under. */
|
|
31
|
+
export declare const SESSION_NAMESPACE = "Session";
|
|
22
32
|
export type UserSubjectRef = {
|
|
23
33
|
subjectId: string;
|
|
24
34
|
} | {
|
|
@@ -33,7 +43,7 @@ export type UserSubjectRef = {
|
|
|
33
43
|
* client's user principal and the env overrides in
|
|
34
44
|
* {@link resolveUserSubject}. The override only applies within `fn`'s
|
|
35
45
|
* async context, so concurrent calls cannot observe each other's subject.
|
|
36
|
-
*
|
|
46
|
+
* SubjectSet shaping still applies.
|
|
37
47
|
*
|
|
38
48
|
* A missing/empty `subject` is a no-op: `fn` runs with the normal
|
|
39
49
|
* resolution chain.
|
|
@@ -46,13 +56,109 @@ export declare function runWithUserSubject<T>(subject: string | undefined, fn: (
|
|
|
46
56
|
* legacy `ORY_AGENT_SUBJECT_ID`, then the caller-supplied `fallback`
|
|
47
57
|
* (typically `session:<id>`).
|
|
48
58
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
59
|
+
* Always returns a SubjectSet. A resolved principal is addressed under the
|
|
60
|
+
* configured user namespace (`ORY_USER_SUBJECT_NAMESPACE` → client config →
|
|
61
|
+
* {@link DEFAULT_USER_SUBJECT_NAMESPACE}). A `session:`-prefixed fallback is
|
|
62
|
+
* addressed under {@link SESSION_NAMESPACE} (`Session:<id>`). Only when nothing
|
|
63
|
+
* resolves at all do we emit the direct `agent:unknown` sentinel — an error
|
|
64
|
+
* marker that must never match a stored tuple.
|
|
52
65
|
*/
|
|
53
66
|
export declare function resolveUserSubject(client: OryAgentClient, fallback?: string): UserSubjectRef;
|
|
54
67
|
/**
|
|
55
68
|
* Printable label for a `UserSubjectRef`. Used in denial messages and
|
|
56
|
-
*
|
|
69
|
+
* activity attributes. SubjectSets render as `<namespace>:<object>`.
|
|
57
70
|
*/
|
|
58
71
|
export declare function subjectLabel(ref: UserSubjectRef): string;
|
|
72
|
+
/** Separator between the credential client id and narrower scoping axes. */
|
|
73
|
+
export declare const SUBJECT_AXIS_SEPARATOR = "|";
|
|
74
|
+
/** The env var that overrides the agent's subject. */
|
|
75
|
+
export declare const AGENT_SUBJECT_ID_ENV_VAR = "ORY_AGENT_SUBJECT_ID";
|
|
76
|
+
/**
|
|
77
|
+
* Validate a subject override (issue #241).
|
|
78
|
+
*
|
|
79
|
+
* `deriveSubject` above already refuses to produce a trailing separator,
|
|
80
|
+
* because a subject ending in `|` silently never matches a stored relation.
|
|
81
|
+
* The same care is owed to the *base* it joins onto, which arrives from an
|
|
82
|
+
* operator-settable env var and was previously used verbatim.
|
|
83
|
+
*
|
|
84
|
+
* A value containing the axis separator is rejected for two independent
|
|
85
|
+
* reasons:
|
|
86
|
+
*
|
|
87
|
+
* 1. **It collapses the identity grains.** The credential, session, and spawn
|
|
88
|
+
* subjects are told apart only by separator position, so an override
|
|
89
|
+
* containing one makes them ambiguous: `override="a|b"` in session `c` and
|
|
90
|
+
* `override="a"` in session `b|c` produce the same string. A session-scoped
|
|
91
|
+
* block written to stop one runaway run could then match the base credential, or a
|
|
92
|
+
* different run — and all three grains are read together in one batched
|
|
93
|
+
* check, so this is a live semantics break rather than a theoretical one.
|
|
94
|
+
* 2. **It forges a delegation-node reference** (#225). A join key is exactly
|
|
95
|
+
* `<identity>|<harness>|<host>|<session>`, and the two string spaces stay
|
|
96
|
+
* disjoint today only because a Hydra client id is a UUID and contains no
|
|
97
|
+
* separator. This env var is the one supported knob that breaks that.
|
|
98
|
+
*
|
|
99
|
+
* Rejected rather than sanitized: silently stripping the separator would
|
|
100
|
+
* produce a *different* subject than the operator asked for, which fails just
|
|
101
|
+
* as confusingly and is harder to notice. Ignoring the value falls back to the
|
|
102
|
+
* client id — a real, working identity — and says so.
|
|
103
|
+
*/
|
|
104
|
+
export declare function validateSubjectOverride(raw: string | undefined, envVar?: string): {
|
|
105
|
+
value?: string;
|
|
106
|
+
warning?: string;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Read and validate `ORY_AGENT_SUBJECT_ID`. Returns `undefined` when unset or
|
|
110
|
+
* rejected, pushing an explanation onto `warnings` in the latter case.
|
|
111
|
+
*
|
|
112
|
+
* One reader for every site that consumes the override, so the rule cannot hold
|
|
113
|
+
* in the resolver and not in what `status` reports.
|
|
114
|
+
*/
|
|
115
|
+
export declare function readAgentSubjectOverride(env?: NodeJS.ProcessEnv, warnings?: string[]): string | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* The registered agent credential subject: `Agent:<clientId>`. For DCR this
|
|
118
|
+
* client belongs to one session; static credentials may be shared explicitly.
|
|
119
|
+
*
|
|
120
|
+
* `undefined` when no agent principal is populated — the agent gate never
|
|
121
|
+
* blocks, so a session with no resolved machine identity is normal and callers
|
|
122
|
+
* must treat a missing agent subject as "nothing to check", not as a deny.
|
|
123
|
+
*/
|
|
124
|
+
export declare function resolveAgentSubject(client: OryAgentClient): UserSubjectRef | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* The **session-level** agent subject: `Agent:<clientId>|<session>`, unique to
|
|
127
|
+
* one run. Used for a block that stops the session's narrower subject without
|
|
128
|
+
* blocking its base credential subject.
|
|
129
|
+
*
|
|
130
|
+
* `undefined` when there is no agent principal, and — deliberately — also when
|
|
131
|
+
* there is no session. A caller with no session concept (an SDK integration in
|
|
132
|
+
* a long-running service) has exactly one sessionless credential subject;
|
|
133
|
+
* inventing a placeholder session would either collapse every run onto
|
|
134
|
+
* one string or produce a subject no admin could have written.
|
|
135
|
+
*/
|
|
136
|
+
export declare function resolveAgentSessionSubject(client: OryAgentClient, sessionId?: string): UserSubjectRef | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* The registered sub-agent credential subject: `SubAgent:<clientId>` for one
|
|
139
|
+
* typed sub-agent in one session.
|
|
140
|
+
*
|
|
141
|
+
* `subAgentClientId` is the client id from {@link ensureSubAgentIdentity};
|
|
142
|
+
* `undefined` in, and `undefined` out, since a sub-agent whose identity did not
|
|
143
|
+
* resolve has nothing to check.
|
|
144
|
+
*/
|
|
145
|
+
export declare function resolveSubAgentSubject(subAgentClientId: string | undefined): UserSubjectRef | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* The **spawn-level** sub-agent subject:
|
|
148
|
+
* `SubAgent:<clientId>|<session>|<type>[|<spawn>]`, the finest grain available.
|
|
149
|
+
*
|
|
150
|
+
* `perSpawnId` distinguishes two *concurrent* same-type sub-agents and is only
|
|
151
|
+
* present on harnesses that expose one (Cursor's `subagent_id`, Claude Code's
|
|
152
|
+
* `agent_id`, OpenClaw's `childRunId`, …). Where the harness exposes none the
|
|
153
|
+
* subject stops at the type and concurrent spawns share it — a limit of the
|
|
154
|
+
* harness, not of this model.
|
|
155
|
+
*
|
|
156
|
+
* As with the agent session subject, a missing session yields `undefined`
|
|
157
|
+
* rather than a placeholder.
|
|
158
|
+
*/
|
|
159
|
+
export declare function resolveSubAgentSpawnSubject(client: OryAgentClient, args: {
|
|
160
|
+
subAgentClientId?: string;
|
|
161
|
+
subAgentType: string;
|
|
162
|
+
perSpawnId?: string;
|
|
163
|
+
sessionId?: string;
|
|
164
|
+
}): UserSubjectRef | undefined;
|