@ory/argus 0.13.9 → 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 -45
- 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 +43 -97
- package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -18
- package/assets/skills/ory-temporal-worker/SKILL.md +38 -42
- package/assets/skills/permissions-onboarding/SKILL.md +131 -104
- package/dist/adapters.d.ts +93 -30
- package/dist/adapters.js +464 -136
- package/dist/agent-auth.d.ts +258 -68
- package/dist/agent-auth.js +998 -202
- package/dist/auth-store.d.ts +37 -2
- package/dist/auth-store.js +37 -3
- package/dist/auth.d.ts +40 -4
- package/dist/auth.js +247 -19
- package/dist/bash-parser.d.ts +98 -0
- package/dist/bash-parser.js +396 -0
- package/dist/branding.d.ts +128 -0
- package/dist/branding.js +151 -0
- 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 -278
- package/dist/client.d.ts +175 -138
- package/dist/client.js +672 -391
- package/dist/config.d.ts +249 -57
- package/dist/config.js +486 -62
- package/dist/context.d.ts +10 -0
- package/dist/context.js +21 -0
- package/dist/contract-suite.d.ts +8 -8
- package/dist/contract-suite.js +88 -69
- 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 +31 -19
- package/dist/index.js +182 -31
- 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.d.ts +14 -0
- package/dist/local/health.js +50 -4
- 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 +160 -39
- package/dist/local/ports.d.ts +158 -0
- package/dist/local/ports.js +443 -0
- package/dist/local/seed.d.ts +22 -25
- package/dist/local/seed.js +88 -56
- 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 +83 -55
- 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 -28
- package/dist/setup.js +57 -84
- package/dist/status-cli.d.ts +29 -13
- package/dist/status-cli.js +124 -144
- package/dist/status-data.d.ts +195 -0
- package/dist/status-data.js +333 -0
- package/dist/status-system.d.ts +24 -0
- package/dist/status-system.js +56 -0
- 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 +74 -19
- package/dist/uninstall.js +224 -49
- package/dist/user-login.d.ts +22 -16
- package/dist/user-login.js +67 -96
- package/dist/watch-cli.d.ts +6 -0
- package/dist/watch-cli.js +217 -0
- package/package.json +3 -11
- package/dist/dev.d.ts +0 -103
- package/dist/dev.js +0 -584
- package/dist/interactive-setup.d.ts +0 -165
- package/dist/interactive-setup.js +0 -1546
- 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/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/status-cli.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.printUserIdentitySection = printUserIdentitySection;
|
|
4
4
|
exports.printAgentIdentitySection = printAgentIdentitySection;
|
|
5
|
+
exports.printSubAgentIdentitiesSection = printSubAgentIdentitiesSection;
|
|
5
6
|
exports.printPermissionsSection = printPermissionsSection;
|
|
6
7
|
exports.runStatusCommand = runStatusCommand;
|
|
7
8
|
/**
|
|
8
9
|
* Unified `status` CLI implementation. Each harness's `cli/main.ts` `status`
|
|
9
10
|
* subcommand delegates here so onboarding readers see configuration, user
|
|
10
|
-
* identity, agent identity, permissions, and the
|
|
11
|
-
* registration block in a single pass.
|
|
11
|
+
* identity, agent identity, sub-agent identities, permissions, and the
|
|
12
|
+
* harness-specific plugin registration block in a single pass.
|
|
12
13
|
*
|
|
13
14
|
* The drill-down commands (`agent status`, `permissions status`) remain
|
|
14
15
|
* unchanged — this composes their inputs without altering their output.
|
|
@@ -16,30 +17,16 @@ exports.runStatusCommand = runStatusCommand;
|
|
|
16
17
|
const config_js_1 = require("./config.js");
|
|
17
18
|
const auth_store_js_1 = require("./auth-store.js");
|
|
18
19
|
const agent_auth_js_1 = require("./agent-auth.js");
|
|
19
|
-
const
|
|
20
|
-
const logger_js_1 = require("./logger.js");
|
|
21
|
-
const agent_auth_js_2 = require("./agent-auth.js");
|
|
20
|
+
const branding_js_1 = require("./branding.js");
|
|
22
21
|
const subject_js_1 = require("./subject.js");
|
|
22
|
+
const logger_js_1 = require("./logger.js");
|
|
23
|
+
const auth_js_1 = require("./auth.js");
|
|
24
|
+
const status_data_js_1 = require("./status-data.js");
|
|
23
25
|
const tool_catalog_js_1 = require("./tool-catalog.js");
|
|
24
26
|
const cli_js_1 = require("./cli.js");
|
|
25
27
|
const cli_invocation_js_1 = require("./cli-invocation.js");
|
|
26
28
|
function resolveNamespace() {
|
|
27
|
-
return process.env.ORY_PERMISSION_NAMESPACE ?? "
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Human-readable annotation for where the resolved user-login flag came
|
|
31
|
-
* from, so `status` readers know whether to look at the env var or the
|
|
32
|
-
* config file to change it.
|
|
33
|
-
*/
|
|
34
|
-
function formatUserLoginSource(source) {
|
|
35
|
-
switch (source) {
|
|
36
|
-
case "env":
|
|
37
|
-
return " (ORY_USER_LOGIN env var)";
|
|
38
|
-
case "config":
|
|
39
|
-
return " (saved in config; change with: configure --user-login|--no-user-login)";
|
|
40
|
-
case "default":
|
|
41
|
-
return "";
|
|
42
|
-
}
|
|
29
|
+
return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTool";
|
|
43
30
|
}
|
|
44
31
|
/**
|
|
45
32
|
* Format a relative duration like "4h 32m" or "12s" for a future deadline.
|
|
@@ -61,27 +48,16 @@ function formatExpiresIn(expiresAtSec, nowMs = Date.now()) {
|
|
|
61
48
|
return `${remaining}s`;
|
|
62
49
|
}
|
|
63
50
|
/**
|
|
64
|
-
* Render the "User identity" block.
|
|
65
|
-
*
|
|
51
|
+
* Render the "User identity" block. The interactive PKCE login runs every
|
|
52
|
+
* session; this shows the cached token's subject and expiry, if any.
|
|
66
53
|
*/
|
|
67
54
|
function printUserIdentitySection() {
|
|
68
|
-
const resolved = (0, config_js_1.resolveConfig)();
|
|
69
|
-
const loginOn = resolved.userLogin;
|
|
70
55
|
const tokens = (0, auth_store_js_1.loadTokens)();
|
|
71
56
|
console.log("");
|
|
72
57
|
console.log("User identity (interactive PKCE login):");
|
|
73
|
-
const loginState = loginOn
|
|
74
|
-
? `on${formatUserLoginSource(resolved.userLoginSource)}`
|
|
75
|
-
: "off (enable with: configure --user-login, or ORY_USER_LOGIN=true)";
|
|
76
|
-
console.log(` Login: ${loginState}`);
|
|
77
58
|
if (!tokens) {
|
|
78
59
|
console.log(" Token cache: empty");
|
|
79
|
-
|
|
80
|
-
console.log(" Subject: (will resolve at next session start)");
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
console.log(" Subject: (login disabled — no PKCE flow will run)");
|
|
84
|
-
}
|
|
60
|
+
console.log(" Subject: (will resolve at next session start)");
|
|
85
61
|
return;
|
|
86
62
|
}
|
|
87
63
|
const expired = (0, auth_store_js_1.isExpired)(tokens);
|
|
@@ -91,6 +67,10 @@ function printUserIdentitySection() {
|
|
|
91
67
|
else {
|
|
92
68
|
console.log(` Token cache: present (expires in ${formatExpiresIn(tokens.expiresAt)})`);
|
|
93
69
|
}
|
|
70
|
+
const displayName = tokens.displayName ?? (0, auth_js_1.displayNameFromIdToken)(tokens.idToken);
|
|
71
|
+
if (displayName) {
|
|
72
|
+
console.log(` Name: ${displayName}`);
|
|
73
|
+
}
|
|
94
74
|
const subject = tokens.subject ? `user:${tokens.subject}` : "(no subject claim on cached token)";
|
|
95
75
|
console.log(` Subject: ${subject}`);
|
|
96
76
|
if (tokens.clientId) {
|
|
@@ -99,183 +79,182 @@ function printUserIdentitySection() {
|
|
|
99
79
|
}
|
|
100
80
|
/**
|
|
101
81
|
* Render the "Agent identity" block. Summarizes the resolved machine
|
|
102
|
-
* credential — static env override, persisted DCR, or unconfigured.
|
|
82
|
+
* credential — static env override, persisted DCR, or unconfigured. Each
|
|
83
|
+
* installed harness has its own agent registration, so the report is for
|
|
84
|
+
* `harness`'s identity only.
|
|
103
85
|
*/
|
|
104
|
-
function printAgentIdentitySection() {
|
|
86
|
+
function printAgentIdentitySection(harness) {
|
|
105
87
|
console.log("");
|
|
106
88
|
console.log("Agent identity (non-interactive):");
|
|
107
|
-
//
|
|
89
|
+
// The one static override takes precedence — surface it so the reader knows
|
|
108
90
|
// why DCR isn't running.
|
|
109
|
-
if (process.env.ORY_AGENT_API_KEY) {
|
|
110
|
-
console.log(" Source: static API key (ORY_AGENT_API_KEY)");
|
|
111
|
-
if (process.env.ORY_AGENT_SUBJECT_ID) {
|
|
112
|
-
console.log(` Subject: ${process.env.ORY_AGENT_SUBJECT_ID}`);
|
|
113
|
-
}
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
91
|
if (process.env.ORY_AGENT_CLIENT_ID && process.env.ORY_AGENT_CLIENT_SECRET) {
|
|
117
92
|
console.log(" Source: static client_credentials (ORY_AGENT_CLIENT_ID/SECRET)");
|
|
118
93
|
console.log(` Client ID: ${process.env.ORY_AGENT_CLIENT_ID}`);
|
|
119
|
-
const subject =
|
|
94
|
+
const subject = (0, subject_js_1.readAgentSubjectOverride)() ?? process.env.ORY_AGENT_CLIENT_ID;
|
|
120
95
|
console.log(` Subject: ${subject}`);
|
|
121
96
|
return;
|
|
122
97
|
}
|
|
123
|
-
const
|
|
124
|
-
if (!
|
|
98
|
+
const latest = (0, agent_auth_js_1.latestAgentRegistration)(harness);
|
|
99
|
+
if (!latest) {
|
|
125
100
|
console.log(" Source: not registered yet");
|
|
126
101
|
console.log(" Status: first session start will register an OAuth2 client (RFC 7591)");
|
|
127
102
|
return;
|
|
128
103
|
}
|
|
104
|
+
const { sessionKey, credentials: persisted } = latest;
|
|
129
105
|
const resolved = (0, config_js_1.resolveConfig)();
|
|
130
106
|
const mismatched = resolved.projectUrl && persisted.projectUrl !== resolved.projectUrl;
|
|
131
107
|
console.log(" Source: OAuth2 Dynamic Client Registration (RFC 7591)");
|
|
132
108
|
console.log(` Status: registered`);
|
|
109
|
+
console.log(` Name: ${(0, status_data_js_1.resolveDynamicName)(persisted)}`);
|
|
133
110
|
console.log(` Client ID: ${persisted.clientId}`);
|
|
134
|
-
const subject =
|
|
135
|
-
console.log(` Subject: ${subject}`);
|
|
111
|
+
const subject = (0, subject_js_1.readAgentSubjectOverride)() ?? persisted.clientId;
|
|
112
|
+
console.log(` Subject: ${subject_js_1.AGENT_NAMESPACE}:${subject}`);
|
|
136
113
|
console.log(` Registered: ${new Date(persisted.registeredAt * 1000).toISOString()}`);
|
|
114
|
+
console.log(` Session: ${sessionKey}`);
|
|
115
|
+
console.log(` Retained: ${(0, agent_auth_js_1.countAgentSessions)(harness)} session(s)`);
|
|
116
|
+
if (sessionKey !== config_js_1.SESSIONLESS_KEY) {
|
|
117
|
+
console.log(` Session ID: ${subject_js_1.AGENT_NAMESPACE}:${subject}|${sessionKey}`);
|
|
118
|
+
}
|
|
137
119
|
if (mismatched) {
|
|
138
120
|
console.log(` Warning: registered against ${persisted.projectUrl}, but current project URL is ${resolved.projectUrl}`);
|
|
139
121
|
console.log(" run `agent unregister` to clear stale credentials");
|
|
140
122
|
}
|
|
141
123
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Render the "Sub-agent identities" block — one entry per typed sub-agent
|
|
126
|
+
* (e.g. `Explore`, `general-purpose`) the agent has registered a distinct
|
|
127
|
+
* OAuth2 client for via DCR. All sub-agent identities are dynamic
|
|
128
|
+
* registrations. Scoped to `harness` — sub-agents belong to that harness's
|
|
129
|
+
* agent. A no-op when none exist yet.
|
|
130
|
+
*/
|
|
131
|
+
function printSubAgentIdentitiesSection(harness) {
|
|
132
|
+
const sessionKey = (0, agent_auth_js_1.latestAgentRegistration)(harness)?.sessionKey ?? (0, agent_auth_js_1.latestSubAgentSession)(harness);
|
|
133
|
+
const subAgents = sessionKey
|
|
134
|
+
? (0, agent_auth_js_1.loadAllSubAgentDynamicCredentials)(harness, sessionKey)
|
|
135
|
+
: {};
|
|
136
|
+
const types = Object.keys(subAgents).sort((a, b) => a.localeCompare(b));
|
|
137
|
+
console.log("");
|
|
138
|
+
console.log(`Sub-agent identities${sessionKey ? ` (session ${(0, branding_js_1.shortSessionLabel)(sessionKey)})` : ""}:`);
|
|
139
|
+
if (types.length === 0) {
|
|
140
|
+
console.log(" None registered yet — one is registered the first time the agent");
|
|
141
|
+
console.log(" spawns a typed sub-agent (e.g. a Task / Explore sub-agent).");
|
|
142
|
+
return;
|
|
160
143
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const check = {
|
|
177
|
-
namespace,
|
|
178
|
-
object: tool,
|
|
179
|
-
relation: "use",
|
|
180
|
-
...subject,
|
|
181
|
-
};
|
|
182
|
-
try {
|
|
183
|
-
const probe = await client.checkPermission(check, {
|
|
184
|
-
spanAttributes: { toolName: tool, source: "status_coverage" },
|
|
185
|
-
});
|
|
186
|
-
if (probe.allowed)
|
|
187
|
-
result.allowed++;
|
|
188
|
-
else
|
|
189
|
-
result.denied++;
|
|
190
|
-
}
|
|
191
|
-
catch (err) {
|
|
192
|
-
const ory = err;
|
|
193
|
-
result.errored++;
|
|
194
|
-
result.errorCode = result.errorCode ?? ory.code ?? "unknown";
|
|
144
|
+
const resolved = (0, config_js_1.resolveConfig)();
|
|
145
|
+
types.forEach((type, i) => {
|
|
146
|
+
if (i > 0)
|
|
147
|
+
console.log("");
|
|
148
|
+
const creds = subAgents[type];
|
|
149
|
+
const subject = creds.delegation?.delegatedBy
|
|
150
|
+
? `subagent:${creds.clientId} (delegated by ${creds.delegation.delegatedBy})`
|
|
151
|
+
: `subagent:${creds.clientId}`;
|
|
152
|
+
console.log(` ${type}:`);
|
|
153
|
+
console.log(` Name: ${(0, status_data_js_1.resolveDynamicName)(creds, type)}`);
|
|
154
|
+
console.log(` Client ID: ${creds.clientId}`);
|
|
155
|
+
console.log(` Subject: ${subject}`);
|
|
156
|
+
console.log(` Registered: ${new Date(creds.registeredAt * 1000).toISOString()}`);
|
|
157
|
+
if (resolved.projectUrl && creds.projectUrl !== resolved.projectUrl) {
|
|
158
|
+
console.log(` Warning: registered against ${creds.projectUrl}, but current project URL is ${resolved.projectUrl}`);
|
|
195
159
|
}
|
|
196
|
-
}
|
|
197
|
-
return result;
|
|
160
|
+
});
|
|
198
161
|
}
|
|
199
162
|
/**
|
|
200
|
-
* Render the "Permissions" block
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
163
|
+
* Render the "Permissions" block: the deny posture, the namespace, and the
|
|
164
|
+
* coverage of the harness's built-in tool catalog.
|
|
165
|
+
*
|
|
166
|
+
* The network probe runs only when a project URL is configured *and* a user
|
|
167
|
+
* identity is available (cached PKCE tokens or `ORY_USER_SUBJECT_ID`). When it
|
|
168
|
+
* runs, the reported **Mode is read live from the project** in the same pass, so
|
|
169
|
+
* this line answers "what would a tool call do right now?" rather than echoing a
|
|
170
|
+
* cache that is only refreshed at session start. On every other path the last
|
|
171
|
+
* cached value is reported, annotated as such.
|
|
204
172
|
*/
|
|
205
173
|
async function printPermissionsSection(binName, harness) {
|
|
206
174
|
const resolved = (0, config_js_1.resolveConfig)();
|
|
207
175
|
const namespace = resolveNamespace();
|
|
208
176
|
const catalog = (0, tool_catalog_js_1.getToolCatalog)(harness);
|
|
177
|
+
const cachedMode = `${resolved.permissionMode}${formatModeSuffix(resolved.permissionModeSource)}`;
|
|
209
178
|
console.log("");
|
|
210
179
|
console.log("Permissions:");
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (resolved.
|
|
214
|
-
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
if (!resolved.projectUrl) {
|
|
218
|
-
console.log(" Coverage: n/a (no project URL configured)");
|
|
219
|
-
return;
|
|
180
|
+
// Reasons the probe can't run. Each reports the cached mode, since there is no
|
|
181
|
+
// way to read the live one without reaching the project.
|
|
182
|
+
if (!resolved.security.connected) {
|
|
183
|
+
return printNoCoverage(cachedMode, namespace, `n/a (Agent Security not connected — ${(0, config_js_1.describeSecurityGap)(resolved.security)})`);
|
|
220
184
|
}
|
|
221
185
|
if (catalog.length === 0) {
|
|
222
|
-
|
|
186
|
+
printNoCoverage(cachedMode, namespace, `n/a (no built-in catalog for harness "${harness}")`);
|
|
223
187
|
console.log(` known harnesses: ${tool_catalog_js_1.KNOWN_HARNESSES.join(", ")}`);
|
|
224
188
|
return;
|
|
225
189
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
console.log(
|
|
229
|
-
console.log(` or set ORY_USER_SUBJECT_ID to probe a known subject)`);
|
|
190
|
+
if (!(process.env.ORY_USER_SUBJECT_ID || isUserTokenUsable())) {
|
|
191
|
+
printNoCoverage(cachedMode, namespace, "n/a (no cached user identity — start a session once to sign in,");
|
|
192
|
+
console.log(" or set ORY_USER_SUBJECT_ID to probe a known subject)");
|
|
230
193
|
return;
|
|
231
194
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
//
|
|
235
|
-
|
|
195
|
+
// The probe reads the live mode in the same pass, so hold the Mode line until
|
|
196
|
+
// it returns rather than printing a cached value we are about to supersede.
|
|
197
|
+
//
|
|
198
|
+
// The progress line is carriage-return overwritten, which only renders as
|
|
199
|
+
// intended on a terminal — piped or redirected output would keep the literal
|
|
200
|
+
// \r and the spaces, so skip it entirely when stdout isn't a TTY.
|
|
201
|
+
const spinner = process.stdout.isTTY === true;
|
|
202
|
+
if (spinner)
|
|
203
|
+
process.stdout.write(" checking…\r");
|
|
204
|
+
const probe = await (0, status_data_js_1.probePermissionsCoverage)(harness);
|
|
205
|
+
if (spinner)
|
|
206
|
+
process.stdout.write(" ".repeat(40) + "\r");
|
|
236
207
|
if (!probe) {
|
|
237
|
-
|
|
238
|
-
return;
|
|
208
|
+
return printNoCoverage(cachedMode, namespace, "unavailable (no user identity could be resolved)");
|
|
239
209
|
}
|
|
240
210
|
const { total, allowed, denied, errored } = probe;
|
|
211
|
+
console.log(` Mode: ${probe.mode}${formatModeSuffix(probe.modeSource)}`);
|
|
212
|
+
console.log(` Namespace: ${namespace}`);
|
|
213
|
+
console.log(` Subject: ${probe.subject}`);
|
|
241
214
|
if (errored > 0 && allowed === 0 && denied === 0) {
|
|
242
215
|
console.log(` Coverage: probe failed (${probe.errorCode ?? "unknown"})`);
|
|
243
216
|
return;
|
|
244
217
|
}
|
|
245
218
|
const status = allowed === total
|
|
246
|
-
? `
|
|
219
|
+
? `fully granted (${allowed}/${total} built-in tools)`
|
|
247
220
|
: allowed === 0
|
|
248
|
-
? `
|
|
221
|
+
? `no grants (0/${total} built-in tools)`
|
|
249
222
|
: `partial (${allowed}/${total} built-in tools allowed)`;
|
|
250
223
|
console.log(` Coverage: ${status}`);
|
|
251
224
|
if (denied > 0) {
|
|
252
|
-
console.log(
|
|
225
|
+
console.log(" grant the missing tools in the Ory Console (Agent Security)");
|
|
253
226
|
}
|
|
254
227
|
else if (errored > 0) {
|
|
255
|
-
console.log(` ${errored} probe error(s) — run "${(0, cli_invocation_js_1.oryNpx)(binName)} permissions
|
|
228
|
+
console.log(` ${errored} probe error(s) — run "${(0, cli_invocation_js_1.oryNpx)(binName)} permissions" for details`);
|
|
256
229
|
}
|
|
257
230
|
}
|
|
231
|
+
/** The Mode / Namespace / Coverage lines for every path that can't probe. */
|
|
232
|
+
function printNoCoverage(mode, namespace, coverage) {
|
|
233
|
+
console.log(` Mode: ${mode}`);
|
|
234
|
+
console.log(` Namespace: ${namespace}`);
|
|
235
|
+
console.log(` Coverage: ${coverage}`);
|
|
236
|
+
}
|
|
258
237
|
function isUserTokenUsable() {
|
|
259
238
|
const tokens = (0, auth_store_js_1.loadTokens)();
|
|
260
239
|
return !!tokens && !(0, auth_store_js_1.isExpired)(tokens);
|
|
261
240
|
}
|
|
262
241
|
function formatModeSuffix(source) {
|
|
263
242
|
switch (source) {
|
|
264
|
-
case "
|
|
265
|
-
return " (from
|
|
266
|
-
case "
|
|
267
|
-
return " (
|
|
243
|
+
case "server":
|
|
244
|
+
return " (read from the Ory project)";
|
|
245
|
+
case "cache":
|
|
246
|
+
return " (cached — project unreachable)";
|
|
268
247
|
case "default":
|
|
269
|
-
return " (default)";
|
|
248
|
+
return " (default — not yet read from the project)";
|
|
270
249
|
}
|
|
271
250
|
}
|
|
272
251
|
/**
|
|
273
252
|
* Compose the unified `status` output for a plugin CLI. Sections render
|
|
274
253
|
* in this order: title → configuration → user identity → agent identity
|
|
275
|
-
* → permissions → hooks & plugin → environment →
|
|
276
|
-
*
|
|
254
|
+
* → sub-agent identities → permissions → hooks & plugin → environment →
|
|
255
|
+
* recent activity from the unified activity/debug log.
|
|
277
256
|
*
|
|
278
|
-
* Each section degrades gracefully —
|
|
257
|
+
* Each section degrades gracefully — Agent Security not connected
|
|
279
258
|
* mode, and empty token caches all surface as inline "n/a" lines rather
|
|
280
259
|
* than aborting the command.
|
|
281
260
|
*/
|
|
@@ -292,19 +271,20 @@ async function runStatusCommand(binName, harness, options) {
|
|
|
292
271
|
console.log("");
|
|
293
272
|
(0, cli_js_1.printOryConfig)();
|
|
294
273
|
printUserIdentitySection();
|
|
295
|
-
printAgentIdentitySection();
|
|
274
|
+
printAgentIdentitySection(harness);
|
|
275
|
+
printSubAgentIdentitiesSection(harness);
|
|
296
276
|
await printPermissionsSection(binName, harness);
|
|
297
277
|
if (options.printPluginSection) {
|
|
298
278
|
console.log("");
|
|
299
|
-
options.printPluginSection();
|
|
279
|
+
await options.printPluginSection();
|
|
300
280
|
}
|
|
301
281
|
(0, cli_js_1.printEnvironment)();
|
|
302
282
|
console.log("");
|
|
303
283
|
console.log("Recent activity:");
|
|
304
|
-
(0, cli_js_1.printTraceTail)(harness);
|
|
305
284
|
(0, cli_js_1.printLogTail)(harness);
|
|
306
285
|
console.log("");
|
|
307
|
-
console.log(`
|
|
286
|
+
console.log(` Live activity/debug: ${(0, cli_invocation_js_1.oryNpx)(binName)} watch`);
|
|
287
|
+
console.log(" Include verbose diagnostics: set ORY_AGENT_DEBUG=true before starting the harness");
|
|
308
288
|
console.log("");
|
|
309
289
|
console.log(`Drill into any section with:`);
|
|
310
290
|
console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} agent status`);
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured status data — the data-gathering half of the `status` command,
|
|
3
|
+
* shared by the text renderer ({@link file://./status-cli.ts}) and the local
|
|
4
|
+
* web dashboard. `collectStatusReport(harness)` returns a plain, serializable
|
|
5
|
+
* object mirroring every section `status` prints (configuration, user identity,
|
|
6
|
+
* agent identity, permissions coverage, recent activity), so the two surfaces
|
|
7
|
+
* never drift.
|
|
8
|
+
*
|
|
9
|
+
* The live permission-coverage probe ({@link probePermissionsCoverage}) lives
|
|
10
|
+
* here too and is imported back by `status-cli.ts`, so there is a single probe
|
|
11
|
+
* implementation.
|
|
12
|
+
*/
|
|
13
|
+
import { type PermissionMode, type SecurityConnection } from "./config.js";
|
|
14
|
+
import { type PermissionModeSource } from "./permission-mode.js";
|
|
15
|
+
import { type StatusSystemSection } from "./status-system.js";
|
|
16
|
+
export interface PermissionsCoverage {
|
|
17
|
+
total: number;
|
|
18
|
+
allowed: number;
|
|
19
|
+
denied: number;
|
|
20
|
+
errored: number;
|
|
21
|
+
errorCode?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The **live** deny posture, read from the project during the same probe.
|
|
24
|
+
* `status` reports this rather than the cached `config.permissionMode`: the
|
|
25
|
+
* two can disagree (the cache is only refreshed at session start), and the
|
|
26
|
+
* cached one is the misleading answer to "what would a tool call do now?".
|
|
27
|
+
*/
|
|
28
|
+
mode: PermissionMode;
|
|
29
|
+
modeSource: PermissionModeSource;
|
|
30
|
+
/** The subject the probe actually checked as, e.g. `User:<id>`. */
|
|
31
|
+
subject: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Probe the harness's built-in tool catalog against Ory, returning how many
|
|
35
|
+
* tools the resolved user subject is allowed / denied / errored on, plus the
|
|
36
|
+
* live permission mode and the subject that was checked. Returns undefined when
|
|
37
|
+
* a probe can't run (no project URL, empty catalog, no user identity). Never
|
|
38
|
+
* throws.
|
|
39
|
+
*
|
|
40
|
+
* Checks route through {@link resolveCheckRelation}, i.e. the `access` permit —
|
|
41
|
+
* the same relation the runtime gate evaluates — so a tool carrying an explicit
|
|
42
|
+
* block is reported as denied here too, exactly as a tool call would be.
|
|
43
|
+
*/
|
|
44
|
+
export declare function probePermissionsCoverage(harness: string): Promise<PermissionsCoverage | undefined>;
|
|
45
|
+
export interface StatusConfigSection {
|
|
46
|
+
configPath: string;
|
|
47
|
+
/** Whether a config file actually exists at `configPath` (vs. where one would be written). */
|
|
48
|
+
configExists: boolean;
|
|
49
|
+
projectUrl?: string;
|
|
50
|
+
projectUrlSource: "env" | "config" | "none";
|
|
51
|
+
projectId?: string;
|
|
52
|
+
projectIdSource: "env" | "config" | "none";
|
|
53
|
+
/** Human-readable project / workspace names captured at install (display only). */
|
|
54
|
+
projectName?: string;
|
|
55
|
+
workspaceName?: string;
|
|
56
|
+
oauth2ClientId?: string;
|
|
57
|
+
oauth2ClientIdSource: "env" | "config" | "default";
|
|
58
|
+
/** Display name of the shared PKCE user-login client. Present only when the
|
|
59
|
+
* configured client id *is* the reserved shared-login id — a project may
|
|
60
|
+
* legitimately be pointed at some other public client (or at one provisioned
|
|
61
|
+
* before the id was reserved), and labelling that one with the shared
|
|
62
|
+
* client's name would claim an identity it does not have. */
|
|
63
|
+
oauth2ClientName?: string;
|
|
64
|
+
/** Whether Agent Security runs, derived from the project and broker URLs. */
|
|
65
|
+
security: SecurityConnection;
|
|
66
|
+
permissionMode: "observe" | "enforce";
|
|
67
|
+
permissionModeSource: "server" | "cache" | "default";
|
|
68
|
+
userSubjectNamespace?: string;
|
|
69
|
+
userSubjectNamespaceSource: "env" | "config" | "none";
|
|
70
|
+
/** The tool namespace tool-use checks are addressed under (`ORY_PERMISSION_NAMESPACE`
|
|
71
|
+
* → default `AgentTool`). This is the namespace the `access` permit is checked in. */
|
|
72
|
+
namespace: string;
|
|
73
|
+
/** The principal namespaces the model addresses subjects under — `User`, `Agent`,
|
|
74
|
+
* `SubAgent`, and the `Session` fallback. These are the subject namespaces the
|
|
75
|
+
* checked `namespace` references; sourced from the canonical OPL constants so the
|
|
76
|
+
* dashboard lists the whole model, not just the tool namespace. */
|
|
77
|
+
principalNamespaces: string[];
|
|
78
|
+
/** Whether debug logging is on (`ORY_AGENT_DEBUG=true`). Env-only, read at
|
|
79
|
+
* process start by the logger — not persisted config, so it's shown read-only. */
|
|
80
|
+
debugEnabled: boolean;
|
|
81
|
+
}
|
|
82
|
+
export interface StatusUserSection {
|
|
83
|
+
tokenCache: "empty" | "present" | "stale";
|
|
84
|
+
subject?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Human-readable name for the signed-in user (email / name /
|
|
87
|
+
* preferred_username), decoded from the persisted id_token. Present only
|
|
88
|
+
* when the id_token carries a profile claim — i.e. the login requested the
|
|
89
|
+
* `profile` / `email` scopes. Absent otherwise; callers fall back to the
|
|
90
|
+
* subject id.
|
|
91
|
+
*/
|
|
92
|
+
displayName?: string;
|
|
93
|
+
expiresInSeconds?: number;
|
|
94
|
+
clientId?: string;
|
|
95
|
+
}
|
|
96
|
+
export type AgentIdentitySource = "static_client_credentials" | "dcr" | "unregistered";
|
|
97
|
+
export interface StatusAgentSection {
|
|
98
|
+
source: AgentIdentitySource;
|
|
99
|
+
/** Human-readable OAuth2 client_name for a DCR agent, when known. */
|
|
100
|
+
name?: string;
|
|
101
|
+
clientId?: string;
|
|
102
|
+
subject?: string;
|
|
103
|
+
registeredAt?: string;
|
|
104
|
+
/**
|
|
105
|
+
* The session whose credential this report describes, if any. Sessionless SDK
|
|
106
|
+
* callers report the reserved `sessionless` key.
|
|
107
|
+
*/
|
|
108
|
+
sessionKey?: string;
|
|
109
|
+
/**
|
|
110
|
+
* The narrower per-session subject for this run. Absent when there is no
|
|
111
|
+
* ambient session (an SDK integration with no session concept).
|
|
112
|
+
*/
|
|
113
|
+
sessionSubject?: string;
|
|
114
|
+
projectUrlMismatch?: {
|
|
115
|
+
registeredAgainst: string;
|
|
116
|
+
current: string;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* A typed sub-agent's persisted DCR identity — one row per sub-agent type
|
|
121
|
+
* (e.g. `Explore`, `general-purpose`) the agent has spawned and registered.
|
|
122
|
+
* All sub-agent identities are dynamic registrations, so this always mirrors
|
|
123
|
+
* an `agent.subAgents[<harness>][<session>][<type>]` entry in the shared config
|
|
124
|
+
* — the report covers the newest session of the harness it is run for, since a
|
|
125
|
+
* sub-agent belongs to one specific run of that harness's agent.
|
|
126
|
+
*/
|
|
127
|
+
export interface StatusSubAgentSection {
|
|
128
|
+
/** Sub-agent type key (the config map key), e.g. `"Explore"`. */
|
|
129
|
+
subAgentType: string;
|
|
130
|
+
/** Human-readable OAuth2 client_name for this sub-agent, when known. */
|
|
131
|
+
name?: string;
|
|
132
|
+
clientId: string;
|
|
133
|
+
subject: string;
|
|
134
|
+
registeredAt?: string;
|
|
135
|
+
/** The delegator recorded at registration (`agent:<sub>`), when known. */
|
|
136
|
+
delegatedBy?: string;
|
|
137
|
+
projectUrlMismatch?: {
|
|
138
|
+
registeredAgainst: string;
|
|
139
|
+
current: string;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export type PermissionsCoverageStatus =
|
|
143
|
+
/** Agent Security isn't connected — no project URL and/or OAuth2 client id. */
|
|
144
|
+
"not_connected" | "no_catalog" | "no_user" | "fully_granted" | "partial" | "no_grants" | "probe_failed";
|
|
145
|
+
export interface StatusPermissionsSection {
|
|
146
|
+
mode: "observe" | "enforce";
|
|
147
|
+
/** Where `mode` came from: a live project read, the local cache, or the default. */
|
|
148
|
+
modeSource: PermissionModeSource;
|
|
149
|
+
namespace: string;
|
|
150
|
+
coverageStatus: PermissionsCoverageStatus;
|
|
151
|
+
coverage?: PermissionsCoverage;
|
|
152
|
+
knownHarnesses?: string[];
|
|
153
|
+
}
|
|
154
|
+
export interface StatusActivityEntry {
|
|
155
|
+
raw: string;
|
|
156
|
+
parsed?: Record<string, unknown>;
|
|
157
|
+
}
|
|
158
|
+
export interface StatusActivitySection {
|
|
159
|
+
logFile?: string;
|
|
160
|
+
logCount: number;
|
|
161
|
+
recentEvents: StatusActivityEntry[];
|
|
162
|
+
}
|
|
163
|
+
export interface StatusReport {
|
|
164
|
+
harness: string;
|
|
165
|
+
config: StatusConfigSection;
|
|
166
|
+
user: StatusUserSection;
|
|
167
|
+
agent: StatusAgentSection;
|
|
168
|
+
/** Persisted per-type sub-agent DCR identities (may be empty). */
|
|
169
|
+
subAgents: StatusSubAgentSection[];
|
|
170
|
+
permissions: StatusPermissionsSection;
|
|
171
|
+
activity: StatusActivitySection;
|
|
172
|
+
/** Core Ory service health (Kratos, Hydra, Keto) — the dashboard's "System information". */
|
|
173
|
+
system: StatusSystemSection;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Human-readable name for a DCR agent / sub-agent credential: the persisted
|
|
177
|
+
* `client_name` when present, else a best-effort reconstruction from the
|
|
178
|
+
* harness and (for sub-agents) type. Reconstruction uses the current hostname,
|
|
179
|
+
* which may differ from the registration host for credentials saved before the
|
|
180
|
+
* name was persisted — acceptable for a display-only label.
|
|
181
|
+
*/
|
|
182
|
+
export declare function resolveDynamicName(creds: {
|
|
183
|
+
clientName?: string;
|
|
184
|
+
harness?: string;
|
|
185
|
+
}, subAgentType?: string, harness?: string): string;
|
|
186
|
+
/**
|
|
187
|
+
* Gather the full structured status report for a harness. The permissions
|
|
188
|
+
* section runs a live network probe when a project URL and user identity are
|
|
189
|
+
* available (same conditions as the text `status` command).
|
|
190
|
+
*
|
|
191
|
+
* `sessionKey` is the run being reported on, when the caller is inside one. The
|
|
192
|
+
* standalone CLI passes none, so the report selects the harness's newest stored
|
|
193
|
+
* session rather than inventing an ambient session.
|
|
194
|
+
*/
|
|
195
|
+
export declare function collectStatusReport(harness: string, sessionKey?: string): Promise<StatusReport>;
|