@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/user-login.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 1. Resolve config (env + ~/.config/ory-agent-plugins/config.json).
|
|
7
7
|
* 2. If no project URL, prompt for one when a TTY is available;
|
|
8
|
-
* otherwise skip with an audit
|
|
8
|
+
* otherwise skip with an audit event.
|
|
9
9
|
* 3. If a session/oauth2 token is already in env, short-circuit ok.
|
|
10
10
|
* 4. If persisted tokens are valid, return ok.
|
|
11
11
|
* 5. If they are expired with a refresh_token, refresh.
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* paste the URL into any browser that can reach 127.0.0.1. Only
|
|
16
16
|
* truly unattended (CI=true) environments short-circuit early.
|
|
17
17
|
*
|
|
18
|
-
* Every terminal path emits exactly one `user.auth`
|
|
18
|
+
* Every terminal path emits exactly one `user.auth` activity event so that
|
|
19
19
|
* the audit trail is complete regardless of outcome.
|
|
20
20
|
*
|
|
21
21
|
* The flow runs on **every** session and is **never** blocking: it
|
|
@@ -23,8 +23,10 @@
|
|
|
23
23
|
* and permission-subject resolution, but a failure to authenticate never
|
|
24
24
|
* stops the session. Enforcement is governed solely by `permissionMode`
|
|
25
25
|
* (observe/enforce) at tool-call time — see `checkAndDecide`. The one
|
|
26
|
-
* exception is
|
|
27
|
-
*
|
|
26
|
+
* exception is Agent Security not being connected at all (no project URL
|
|
27
|
+
* and OAuth2 client id), in which case there is nothing to sign in to and
|
|
28
|
+
* the flow no-ops with mode `not_connected`. When the user can't be
|
|
29
|
+
* authenticated the session still
|
|
28
30
|
* proceeds; under `enforce` a missing user identity naturally denies at
|
|
29
31
|
* the tool (no matching tuples), and under `observe` it is audited.
|
|
30
32
|
*
|
|
@@ -38,7 +40,6 @@ exports.ensureAuthenticated = void 0;
|
|
|
38
40
|
exports.ensureUserAuthenticated = ensureUserAuthenticated;
|
|
39
41
|
const config_js_1 = require("./config.js");
|
|
40
42
|
const cli_js_1 = require("./cli.js");
|
|
41
|
-
const cli_invocation_js_1 = require("./cli-invocation.js");
|
|
42
43
|
const auth_store_js_1 = require("./auth-store.js");
|
|
43
44
|
const auth_js_1 = require("./auth.js");
|
|
44
45
|
function clientId() {
|
|
@@ -47,7 +48,7 @@ function clientId() {
|
|
|
47
48
|
// status CLI, and configure command in lockstep on resolution order.
|
|
48
49
|
return (0, config_js_1.resolveConfig)().oauth2ClientId;
|
|
49
50
|
}
|
|
50
|
-
function
|
|
51
|
+
function recordAuthActivity(client, decision) {
|
|
51
52
|
const status = decision.mode === "ok" || decision.mode === "refreshed" || decision.mode === "env_token"
|
|
52
53
|
? "ok"
|
|
53
54
|
: decision.mode === "declined"
|
|
@@ -55,7 +56,7 @@ function recordAuthSpan(client, decision) {
|
|
|
55
56
|
: decision.mode === "error"
|
|
56
57
|
? "error"
|
|
57
58
|
: "skipped";
|
|
58
|
-
client.
|
|
59
|
+
client.logger.activity("user.auth", status, {
|
|
59
60
|
attributes: {
|
|
60
61
|
mode: decision.mode,
|
|
61
62
|
reason: decision.reason,
|
|
@@ -72,7 +73,7 @@ async function ensureUserAuthenticated(client, options) {
|
|
|
72
73
|
try {
|
|
73
74
|
const decision = await runUserLogin(client, options);
|
|
74
75
|
attachUserPrincipal(client, decision);
|
|
75
|
-
|
|
76
|
+
recordAuthActivity(client, decision);
|
|
76
77
|
return decision;
|
|
77
78
|
}
|
|
78
79
|
catch (err) {
|
|
@@ -81,13 +82,13 @@ async function ensureUserAuthenticated(client, options) {
|
|
|
81
82
|
mode: "error",
|
|
82
83
|
reason: err instanceof Error ? err.message : String(err),
|
|
83
84
|
};
|
|
84
|
-
|
|
85
|
+
recordAuthActivity(client, decision);
|
|
85
86
|
return decision;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
/**
|
|
89
90
|
* Attach the resolved user identity to the client so downstream
|
|
90
|
-
* permission checks and
|
|
91
|
+
* permission checks and activity events can reference it. Only fires for
|
|
91
92
|
* modes that actually authenticated a user — declined/skipped/error
|
|
92
93
|
* leave the principal alone.
|
|
93
94
|
*/
|
|
@@ -109,69 +110,43 @@ function attachUserPrincipal(client, decision) {
|
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
112
|
if (decision.mode === "env_token") {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
process.env.ORY_SESSION_TOKEN ??
|
|
116
|
-
process.env.ORY_OAUTH2_TOKEN;
|
|
117
|
-
client.setUserPrincipal({
|
|
118
|
-
...(subject ? { subject } : {}),
|
|
119
|
-
...(token ? { token } : {}),
|
|
120
|
-
});
|
|
113
|
+
// Same reader the per-client rehydration uses, so the credential this gate
|
|
114
|
+
// attaches is exactly the one later lifecycle events will pick up.
|
|
115
|
+
client.setUserPrincipal((0, auth_store_js_1.readEnvUserCredential)());
|
|
121
116
|
}
|
|
122
117
|
}
|
|
123
118
|
async function runUserLogin(client, options) {
|
|
124
119
|
const ttyCheck = options.isTtyAvailableFn ?? cli_js_1.isTtyAvailable;
|
|
125
120
|
const tty = ttyCheck();
|
|
126
121
|
let resolved = (0, config_js_1.resolveConfig)();
|
|
127
|
-
|
|
122
|
+
// Agent Security isn't connected, so there is no project to sign in to.
|
|
123
|
+
// Nothing is lost: the plugin's developer-experience half doesn't need an
|
|
124
|
+
// identity.
|
|
125
|
+
if (!resolved.security.connected) {
|
|
128
126
|
return {
|
|
129
127
|
proceed: true,
|
|
130
|
-
mode: "
|
|
131
|
-
reason:
|
|
128
|
+
mode: "not_connected",
|
|
129
|
+
reason: `Ory Agent Security is not connected (${(0, config_js_1.describeSecurityGap)(resolved.security)}); user login is a no-op`,
|
|
132
130
|
};
|
|
133
131
|
}
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (!url) {
|
|
146
|
-
return {
|
|
147
|
-
proceed: true,
|
|
148
|
-
mode: "declined",
|
|
149
|
-
reason: "User declined to enter an Ory project URL",
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
resolved = (0, config_js_1.resolveConfig)();
|
|
153
|
-
if (!resolved.projectUrl) {
|
|
154
|
-
return {
|
|
155
|
-
proceed: true,
|
|
156
|
-
mode: "error",
|
|
157
|
-
reason: "Project URL was entered but config did not persist",
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
// 2. Pre-supplied env tokens short-circuit the browser flow (CI, scripted
|
|
162
|
-
// runs). ORY_USER_* are the documented names; the legacy single-identity
|
|
163
|
-
// ORY_SESSION_TOKEN / ORY_OAUTH2_TOKEN are still honored.
|
|
164
|
-
if (process.env.ORY_USER_SESSION_TOKEN ||
|
|
165
|
-
process.env.ORY_USER_OAUTH2_TOKEN ||
|
|
166
|
-
process.env.ORY_SESSION_TOKEN ||
|
|
167
|
-
process.env.ORY_OAUTH2_TOKEN) {
|
|
132
|
+
// `security.connected` guarantees both values are non-empty; narrow once
|
|
133
|
+
// here so the rest of the flow doesn't re-check what the gate established.
|
|
134
|
+
const projectUrl = resolved.projectUrl;
|
|
135
|
+
// Past this point both connection values are present, which is why there is
|
|
136
|
+
// no "prompt for a project URL" or "missing client id" branch here: either
|
|
137
|
+
// one absent means not connected, and that is handled above as a normal
|
|
138
|
+
// state rather than something to interrupt the user about.
|
|
139
|
+
// 1. A pre-supplied OAuth2 access token short-circuits the browser flow
|
|
140
|
+
// (CI, scripted runs). `ORY_USER_OAUTH2_TOKEN` is the only accepted
|
|
141
|
+
// variable — see `readEnvUserCredential`.
|
|
142
|
+
if ((0, auth_store_js_1.readEnvUserCredential)().token) {
|
|
168
143
|
return {
|
|
169
144
|
proceed: true,
|
|
170
145
|
mode: "env_token",
|
|
171
|
-
reason: "
|
|
146
|
+
reason: "OAuth2 access token supplied via environment",
|
|
172
147
|
};
|
|
173
148
|
}
|
|
174
|
-
//
|
|
149
|
+
// 2. Persisted tokens.
|
|
175
150
|
const existing = (0, auth_store_js_1.loadTokens)();
|
|
176
151
|
if (existing && !(0, auth_store_js_1.isExpired)(existing)) {
|
|
177
152
|
return {
|
|
@@ -186,7 +161,7 @@ async function runUserLogin(client, options) {
|
|
|
186
161
|
if (cid) {
|
|
187
162
|
try {
|
|
188
163
|
const refreshed = await (0, auth_store_js_1.refreshAndSave)({
|
|
189
|
-
projectUrl
|
|
164
|
+
projectUrl,
|
|
190
165
|
clientId: cid,
|
|
191
166
|
current: existing,
|
|
192
167
|
});
|
|
@@ -205,19 +180,9 @@ async function runUserLogin(client, options) {
|
|
|
205
180
|
}
|
|
206
181
|
}
|
|
207
182
|
}
|
|
208
|
-
//
|
|
183
|
+
// 3. Browser flow. The client id is guaranteed present — it is half of what
|
|
184
|
+
// "connected" means, checked at the top of this function.
|
|
209
185
|
const cid = clientId();
|
|
210
|
-
if (!cid) {
|
|
211
|
-
return {
|
|
212
|
-
proceed: true,
|
|
213
|
-
mode: "skipped",
|
|
214
|
-
reason: "ORY_OAUTH2_CLIENT_ID is not set; cannot start browser login (run `" +
|
|
215
|
-
(0, cli_invocation_js_1.oryNpx)(options.binName) +
|
|
216
|
-
" configure --oauth2-client-id <id>` after registering a public OAuth2 client " +
|
|
217
|
-
"in your Ory project with all four loopback redirect URIs: " +
|
|
218
|
-
"http://127.0.0.1:47823..47826/callback)",
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
186
|
// No TTY check here on purpose: PKCE only needs a browser that can reach
|
|
222
187
|
// the loopback callback port, not stdin. `pkceLogin` prints the
|
|
223
188
|
// authorize URL to stderr so users in non-TTY environments (SSH without
|
|
@@ -225,7 +190,7 @@ async function runUserLogin(client, options) {
|
|
|
225
190
|
// complete sign-in by pasting the URL into any browser that can reach
|
|
226
191
|
// 127.0.0.1. Truly unattended runs (CI=true) are short-circuited by
|
|
227
192
|
// `pkceLogin` itself via `detectHeadless`, and operators can bypass
|
|
228
|
-
// login entirely by supplying `
|
|
193
|
+
// login entirely by supplying `ORY_USER_OAUTH2_TOKEN`, and enforcement
|
|
229
194
|
// consequences are governed by `permissionMode`, not by this gate.
|
|
230
195
|
// PKCE-flight lock so concurrent processes share a single browser flow.
|
|
231
196
|
const lock = (0, auth_store_js_1.tryAcquirePkceFlightLock)();
|
|
@@ -249,7 +214,7 @@ async function runUserLogin(client, options) {
|
|
|
249
214
|
try {
|
|
250
215
|
const loginFn = options.loginFn ?? auth_js_1.pkceLogin;
|
|
251
216
|
const outcome = await loginFn({
|
|
252
|
-
projectUrl
|
|
217
|
+
projectUrl,
|
|
253
218
|
clientId: cid,
|
|
254
219
|
});
|
|
255
220
|
if (outcome.kind === "ok") {
|
|
@@ -264,13 +229,17 @@ async function runUserLogin(client, options) {
|
|
|
264
229
|
return {
|
|
265
230
|
proceed: true,
|
|
266
231
|
mode: declineToMode(outcome.reason),
|
|
267
|
-
reason: declineMessage(outcome.reason),
|
|
232
|
+
reason: appendDetail(declineMessage(outcome.reason), outcome.detail),
|
|
268
233
|
};
|
|
269
234
|
}
|
|
270
235
|
finally {
|
|
271
236
|
lock.release();
|
|
272
237
|
}
|
|
273
238
|
}
|
|
239
|
+
/** Append a secret-free diagnostic to a decline message when one is present. */
|
|
240
|
+
function appendDetail(message, detail) {
|
|
241
|
+
return detail ? `${message} — ${detail}` : message;
|
|
242
|
+
}
|
|
274
243
|
function declineToMode(reason) {
|
|
275
244
|
switch (reason) {
|
|
276
245
|
case "user_denied":
|
|
@@ -283,6 +252,8 @@ function declineToMode(reason) {
|
|
|
283
252
|
return "skipped";
|
|
284
253
|
case "state_mismatch":
|
|
285
254
|
case "token_exchange_failed":
|
|
255
|
+
case "invalid_scope":
|
|
256
|
+
case "oauth_error":
|
|
286
257
|
return "error";
|
|
287
258
|
}
|
|
288
259
|
}
|
|
@@ -291,7 +262,13 @@ function declineMessage(reason) {
|
|
|
291
262
|
case "headless":
|
|
292
263
|
return "Browser login skipped: environment is headless (CI/SSH/no DISPLAY)";
|
|
293
264
|
case "timeout":
|
|
294
|
-
|
|
265
|
+
// Name the consequence, not just the event. This is the one decline the
|
|
266
|
+
// user can fix by simply retrying, and under `enforce` its after-effect
|
|
267
|
+
// (every tool denied, for want of a user identity) is otherwise
|
|
268
|
+
// unattributable to a sign-in that quietly ran out of time (#220).
|
|
269
|
+
return (`Browser login timed out after ${Math.round(auth_js_1.DEFAULT_LOGIN_TIMEOUT_MS / 1000)}s ` +
|
|
270
|
+
"before sign-in completed — the session has no Ory user identity. " +
|
|
271
|
+
"Start a new session to sign in again");
|
|
295
272
|
case "user_denied":
|
|
296
273
|
return "User declined the OAuth2 consent screen";
|
|
297
274
|
case "state_mismatch":
|
|
@@ -304,6 +281,10 @@ function declineMessage(reason) {
|
|
|
304
281
|
return "Login was aborted by the caller";
|
|
305
282
|
case "token_exchange_failed":
|
|
306
283
|
return "Authorization code exchange failed at /oauth2/token";
|
|
284
|
+
case "invalid_scope":
|
|
285
|
+
return "Ory rejected the requested OAuth2 scope (invalid_scope) — the login client isn't allowed it";
|
|
286
|
+
case "oauth_error":
|
|
287
|
+
return "Ory returned an OAuth2 error on the login redirect";
|
|
307
288
|
}
|
|
308
289
|
}
|
|
309
290
|
/**
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface WatchCommandOptions {
|
|
2
|
+
signal?: AbortSignal;
|
|
3
|
+
pollIntervalMs?: number;
|
|
4
|
+
}
|
|
5
|
+
/** Follow one harness's unified activity/debug log until interrupted. */
|
|
6
|
+
export declare function runWatchCommand(binName: string, harness: string, args: readonly string[], options?: WatchCommandOptions): Promise<number>;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runWatchCommand = runWatchCommand;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const client_js_1 = require("./client.js");
|
|
39
|
+
const logger_js_1 = require("./logger.js");
|
|
40
|
+
const ui_js_1 = require("./ui.js");
|
|
41
|
+
const DEFAULT_HISTORY_LINES = 10;
|
|
42
|
+
const DEFAULT_POLL_INTERVAL_MS = 250;
|
|
43
|
+
const MAX_HISTORY_BYTES = 64 * 1024;
|
|
44
|
+
function parseWatchArgs(binName, args) {
|
|
45
|
+
let json = false;
|
|
46
|
+
let lines = DEFAULT_HISTORY_LINES;
|
|
47
|
+
for (let index = 0; index < args.length; index++) {
|
|
48
|
+
const arg = args[index];
|
|
49
|
+
if (arg === "--json") {
|
|
50
|
+
json = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (arg === "--lines") {
|
|
54
|
+
const value = Number(args[++index]);
|
|
55
|
+
if (Number.isInteger(value) && value >= 0) {
|
|
56
|
+
lines = value;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
console.error(`Usage: ${binName} watch [--json] [--lines <count>]`);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return { json, lines };
|
|
64
|
+
}
|
|
65
|
+
const WATCH_LABEL_WIDTH = 13;
|
|
66
|
+
const WATCH_EVENT_WIDTH = 30;
|
|
67
|
+
function colorLabel(label) {
|
|
68
|
+
if (label === "ALLOW" || label === "OK")
|
|
69
|
+
return ui_js_1.brand.green(label);
|
|
70
|
+
if (label === "DENY" || label === "DENIED" || label === "ERROR")
|
|
71
|
+
return ui_js_1.brand.rose(label);
|
|
72
|
+
if (label === "OBSERVE" || label === "FAIL OPEN" || label === "WARN") {
|
|
73
|
+
return ui_js_1.brand.yellow(label);
|
|
74
|
+
}
|
|
75
|
+
return ui_js_1.style.gray(label);
|
|
76
|
+
}
|
|
77
|
+
function detailLabel(detail) {
|
|
78
|
+
const separator = detail.indexOf("=");
|
|
79
|
+
if (separator < 0)
|
|
80
|
+
return detail;
|
|
81
|
+
return `${ui_js_1.style.gray(detail.slice(0, separator))}=${detail.slice(separator + 1)}`;
|
|
82
|
+
}
|
|
83
|
+
function renderEntry(entry) {
|
|
84
|
+
const { time, event, marker, details } = (0, logger_js_1.formatLogEntryParts)(entry);
|
|
85
|
+
const decision = details.find((detail) => detail.startsWith("decision="))?.slice(9);
|
|
86
|
+
const status = details.find((detail) => detail.startsWith("status="))?.slice(7);
|
|
87
|
+
const label = (decision ?? status ?? marker.replaceAll(/[\[\]]/g, "")).replaceAll("_", " ").toUpperCase();
|
|
88
|
+
const remaining = details.filter((detail) => !detail.startsWith("decision=") && !detail.startsWith("status="));
|
|
89
|
+
const labelPadding = " ".repeat(Math.max(1, WATCH_LABEL_WIDTH - label.length));
|
|
90
|
+
const eventPadding = " ".repeat(Math.max(1, WATCH_EVENT_WIDTH - event.length));
|
|
91
|
+
const metadata = remaining.length > 0
|
|
92
|
+
? remaining.map(detailLabel).join(ui_js_1.style.dim(" | "))
|
|
93
|
+
: "";
|
|
94
|
+
console.log(`${ui_js_1.style.dim(time)} ${colorLabel(label)}${labelPadding}${ui_js_1.style.bold(event)}` +
|
|
95
|
+
`${eventPadding}${metadata}`);
|
|
96
|
+
}
|
|
97
|
+
function renderLine(line, json) {
|
|
98
|
+
if (json) {
|
|
99
|
+
console.log(line);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
renderEntry(JSON.parse(line));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
console.log(ui_js_1.brand.rose("INVALID") + ` ${line.slice(0, 160)}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function readHistory(logFile, lines, json) {
|
|
110
|
+
const stat = fs.statSync(logFile);
|
|
111
|
+
if (lines === 0 || stat.size === 0)
|
|
112
|
+
return stat.size;
|
|
113
|
+
const start = Math.max(0, stat.size - MAX_HISTORY_BYTES);
|
|
114
|
+
const length = stat.size - start;
|
|
115
|
+
const buffer = Buffer.alloc(length);
|
|
116
|
+
const fd = fs.openSync(logFile, "r");
|
|
117
|
+
try {
|
|
118
|
+
fs.readSync(fd, buffer, 0, length, start);
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
fs.closeSync(fd);
|
|
122
|
+
}
|
|
123
|
+
let history = buffer.toString("utf8").split("\n");
|
|
124
|
+
if (start > 0)
|
|
125
|
+
history = history.slice(1);
|
|
126
|
+
for (const line of history.filter(Boolean).slice(-lines))
|
|
127
|
+
renderLine(line, json);
|
|
128
|
+
return stat.size;
|
|
129
|
+
}
|
|
130
|
+
function readRange(logFile, start, end) {
|
|
131
|
+
const length = end - start;
|
|
132
|
+
const buffer = Buffer.alloc(length);
|
|
133
|
+
const fd = fs.openSync(logFile, "r");
|
|
134
|
+
try {
|
|
135
|
+
fs.readSync(fd, buffer, 0, length, start);
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
fs.closeSync(fd);
|
|
139
|
+
}
|
|
140
|
+
return buffer.toString("utf8");
|
|
141
|
+
}
|
|
142
|
+
function delay(ms) {
|
|
143
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
144
|
+
}
|
|
145
|
+
/** Follow one harness's unified activity/debug log until interrupted. */
|
|
146
|
+
async function runWatchCommand(binName, harness, args, options = {}) {
|
|
147
|
+
const parsed = parseWatchArgs(binName, args);
|
|
148
|
+
if (!parsed)
|
|
149
|
+
return 1;
|
|
150
|
+
const logFile = (0, client_js_1.resolveDebugLogPath)(harness);
|
|
151
|
+
if (!logFile) {
|
|
152
|
+
console.error("Activity/debug logging is disabled because ORY_AGENT_LOG_FILE is empty.");
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
const controller = options.signal ? undefined : new AbortController();
|
|
156
|
+
const signal = options.signal ?? controller?.signal;
|
|
157
|
+
const stop = () => controller?.abort();
|
|
158
|
+
if (controller) {
|
|
159
|
+
process.once("SIGINT", stop);
|
|
160
|
+
process.once("SIGTERM", stop);
|
|
161
|
+
}
|
|
162
|
+
if (parsed.json) {
|
|
163
|
+
console.log(`Watching ${logFile} (Ctrl-C to stop)`);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log(ui_js_1.style.bold("Watching plugin activity"));
|
|
167
|
+
console.log(`${ui_js_1.style.gray("file")} ${logFile}`);
|
|
168
|
+
console.log(`${ui_js_1.style.gray("stop")} Ctrl-C`);
|
|
169
|
+
console.log("");
|
|
170
|
+
}
|
|
171
|
+
let offset = 0;
|
|
172
|
+
let fileIdentity;
|
|
173
|
+
let remainder = "";
|
|
174
|
+
try {
|
|
175
|
+
try {
|
|
176
|
+
const stat = fs.statSync(logFile);
|
|
177
|
+
fileIdentity = `${stat.dev}:${stat.ino}`;
|
|
178
|
+
offset = readHistory(logFile, parsed.lines, parsed.json);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
console.log("Waiting for the first plugin event...");
|
|
182
|
+
}
|
|
183
|
+
while (!signal?.aborted) {
|
|
184
|
+
await delay(options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS);
|
|
185
|
+
if (signal?.aborted || !fs.existsSync(logFile))
|
|
186
|
+
continue;
|
|
187
|
+
try {
|
|
188
|
+
const stat = fs.statSync(logFile);
|
|
189
|
+
const nextIdentity = `${stat.dev}:${stat.ino}`;
|
|
190
|
+
if (fileIdentity !== nextIdentity || stat.size < offset) {
|
|
191
|
+
offset = 0;
|
|
192
|
+
remainder = "";
|
|
193
|
+
fileIdentity = nextIdentity;
|
|
194
|
+
}
|
|
195
|
+
if (stat.size === offset)
|
|
196
|
+
continue;
|
|
197
|
+
const chunk = remainder + readRange(logFile, offset, stat.size);
|
|
198
|
+
offset = stat.size;
|
|
199
|
+
const complete = chunk.split("\n");
|
|
200
|
+
remainder = complete.pop() ?? "";
|
|
201
|
+
for (const line of complete)
|
|
202
|
+
if (line)
|
|
203
|
+
renderLine(line, parsed.json);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// The writer may replace the file between stat and read; retry next poll.
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
if (controller) {
|
|
213
|
+
process.off("SIGINT", stop);
|
|
214
|
+
process.off("SIGTERM", stop);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ory/argus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Ory Argus: the core API for building authentication, authorization, and audit into AI agent harness plugins, extensions, and custom integrations",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://ory.com",
|
|
@@ -36,8 +36,6 @@
|
|
|
36
36
|
"agent-security",
|
|
37
37
|
"guardrails",
|
|
38
38
|
"llm",
|
|
39
|
-
"tracing",
|
|
40
|
-
"distributed-tracing",
|
|
41
39
|
"observability",
|
|
42
40
|
"kratos",
|
|
43
41
|
"keto",
|
|
@@ -61,40 +59,19 @@
|
|
|
61
59
|
"files": [
|
|
62
60
|
"dist",
|
|
63
61
|
"assets",
|
|
64
|
-
"!dist/dev",
|
|
65
62
|
"!dist/**/*.tsbuildinfo"
|
|
66
63
|
],
|
|
67
64
|
"dependencies": {
|
|
68
|
-
"@opentelemetry/api": "^1.9.0",
|
|
69
|
-
"@opentelemetry/core": "^2.8.0",
|
|
70
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
|
|
71
|
-
"@opentelemetry/exporter-trace-otlp-proto": "^0.219.0",
|
|
72
|
-
"@opentelemetry/resources": "^2.8.0",
|
|
73
|
-
"@opentelemetry/sdk-trace-base": "^2.8.0",
|
|
74
65
|
"@ory/client": "^1.22.37",
|
|
66
|
+
"@vscode/tree-sitter-wasm": "^0.3.1",
|
|
75
67
|
"open": "^11.0.0",
|
|
76
|
-
"
|
|
77
|
-
},
|
|
78
|
-
"devDependencies": {
|
|
79
|
-
"@tailwindcss/vite": "^4.1.0",
|
|
80
|
-
"@types/react": "^19.0.0",
|
|
81
|
-
"@types/react-dom": "^19.0.0",
|
|
82
|
-
"@vitejs/plugin-react": "^4.3.0",
|
|
83
|
-
"class-variance-authority": "^0.7.1",
|
|
84
|
-
"clsx": "^2.1.1",
|
|
85
|
-
"react": "^19.0.0",
|
|
86
|
-
"react-dom": "^19.0.0",
|
|
87
|
-
"tailwind-merge": "^3.0.0",
|
|
88
|
-
"tailwindcss": "^4.1.0",
|
|
89
|
-
"vite": "^6.0.0"
|
|
68
|
+
"web-tree-sitter": "^0.26.11"
|
|
90
69
|
},
|
|
91
70
|
"engines": {
|
|
92
71
|
"node": ">=22"
|
|
93
72
|
},
|
|
94
73
|
"scripts": {
|
|
95
|
-
"build": "tsc && node ./scripts/gen-build-info.mjs
|
|
96
|
-
"build:webapp": "vite build --config webapp/vite.config.ts",
|
|
97
|
-
"dev:webapp": "node webapp/dev-server.mjs",
|
|
74
|
+
"build": "tsc && node ./scripts/gen-build-info.mjs",
|
|
98
75
|
"clean": "rm -rf dist *.tsbuildinfo",
|
|
99
76
|
"test": "vitest run",
|
|
100
77
|
"test:watch": "vitest",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Open the Ory Plugin Dashboard
|
|
2
|
-
|
|
3
|
-
Open a live, browser-based control panel for the Ory agent plugin. It shows
|
|
4
|
-
the health of the core Ory services the plugin uses (Kratos, Hydra, Keto) and
|
|
5
|
-
the plugin's current configuration (project URL, permission mode, audit mode,
|
|
6
|
-
user-login flag, namespaces, and the resolved user/agent identities),
|
|
7
|
-
refreshing the health status live.
|
|
8
|
-
|
|
9
|
-
Run:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
{{NPX}} dashboard
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
This will:
|
|
16
|
-
|
|
17
|
-
1. Start a small local web server bound to `127.0.0.1`
|
|
18
|
-
2. Open your default browser at the dashboard
|
|
19
|
-
3. Refresh the service health live
|
|
20
|
-
|
|
21
|
-
The dashboard is the read-only status view of the Ory Agent web app — the same
|
|
22
|
-
local React UI, loopback server, and styleguide that power the guided web
|
|
23
|
-
installer. It never changes configuration. Stop it with `Ctrl-C` in the
|
|
24
|
-
terminal (or the "Close" button in the page).
|
|
25
|
-
|
|
26
|
-
When no browser is available (CI, SSH, headless), or with `--json`, it prints a
|
|
27
|
-
machine-readable status report instead:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
{{NPX}} dashboard --json
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
If the core services show as unreachable, start the local stack with
|
|
34
|
-
{{REF_LOCAL_UP}} (or check state with `{{NPX}} local status`).
|
package/dist/dashboard-cli.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entry point invoked by each harness CLI's `dashboard` case. Returns the
|
|
3
|
-
* intended process exit code; never throws. With `--json` (or when no browser
|
|
4
|
-
* can be opened) it prints the report and resolves immediately; otherwise it
|
|
5
|
-
* opens the web app in `status` mode and resolves when the SPA requests
|
|
6
|
-
* shutdown or the user interrupts (Ctrl+C).
|
|
7
|
-
*/
|
|
8
|
-
export declare function runDashboardCommand(binName: string, harness: string, args: string[]): Promise<number>;
|
package/dist/dashboard-cli.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runDashboardCommand = runDashboardCommand;
|
|
4
|
-
/**
|
|
5
|
-
* Shared `dashboard` CLI implementation. Each harness's `cli/main.ts`
|
|
6
|
-
* delegates `<bin> dashboard` here.
|
|
7
|
-
*
|
|
8
|
-
* The dashboard is the live status view of the plugin, and one of the two
|
|
9
|
-
* surfaces of the Ory Agent web app (the other being the guided installer): it
|
|
10
|
-
* opens that app in `status` mode via {@link file://./web/launch.ts}'s
|
|
11
|
-
* `launchWebDashboard`, reusing the same loopback server + React SPA. The data
|
|
12
|
-
* it renders is the shared {@link file://./status-data.ts} `StatusReport`,
|
|
13
|
-
* which the dashboard extends with a "System information" section — the health
|
|
14
|
-
* of the core Ory services (Kratos, Hydra, Keto) from
|
|
15
|
-
* {@link file://./status-system.ts}.
|
|
16
|
-
*
|
|
17
|
-
* Besides reading status, the dashboard exposes a "Change stack" action that
|
|
18
|
-
* hands off to the same guided wizard the installer uses (embedded, starting on
|
|
19
|
-
* the stack chooser) so the user can reconfigure which Ory stack the plugin runs
|
|
20
|
-
* against — Ory Network, the local stack, or audit-only — without leaving the
|
|
21
|
-
* browser. It reuses the shared install API and reloads status on return.
|
|
22
|
-
*
|
|
23
|
-
* Flags:
|
|
24
|
-
* --json Print the status report as JSON and exit (no server). Also the
|
|
25
|
-
* automatic fallback when a browser can't be opened (headless / CI).
|
|
26
|
-
*/
|
|
27
|
-
const launch_js_1 = require("./web/launch.js");
|
|
28
|
-
const status_data_js_1 = require("./status-data.js");
|
|
29
|
-
const cli_invocation_js_1 = require("./cli-invocation.js");
|
|
30
|
-
function printDashboardHelp(binName) {
|
|
31
|
-
console.log(`Usage: ${binName} dashboard [options]`);
|
|
32
|
-
console.log("");
|
|
33
|
-
console.log("Open the Ory Agent dashboard in your browser — a live view of the");
|
|
34
|
-
console.log("plugin's configuration and the health of the core Ory services (Kratos,");
|
|
35
|
-
console.log("Hydra, Keto), refreshing live. It is the status surface of the same web");
|
|
36
|
-
console.log("app that powers the guided installer, and its \"Change stack\" action lets");
|
|
37
|
-
console.log("you reconfigure which Ory stack the plugin runs against.");
|
|
38
|
-
console.log("");
|
|
39
|
-
console.log("Options:");
|
|
40
|
-
console.log(" --json Print the status report as JSON and exit (no server)");
|
|
41
|
-
console.log("");
|
|
42
|
-
console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} dashboard`);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Entry point invoked by each harness CLI's `dashboard` case. Returns the
|
|
46
|
-
* intended process exit code; never throws. With `--json` (or when no browser
|
|
47
|
-
* can be opened) it prints the report and resolves immediately; otherwise it
|
|
48
|
-
* opens the web app in `status` mode and resolves when the SPA requests
|
|
49
|
-
* shutdown or the user interrupts (Ctrl+C).
|
|
50
|
-
*/
|
|
51
|
-
async function runDashboardCommand(binName, harness, args) {
|
|
52
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
53
|
-
printDashboardHelp(binName);
|
|
54
|
-
return 0;
|
|
55
|
-
}
|
|
56
|
-
// `--json`, or any environment where we can't open a browser (CI, no TTY,
|
|
57
|
-
// no display), falls back to the machine-readable report on stdout.
|
|
58
|
-
if (args.includes("--json") || !(0, launch_js_1.canLaunchBrowser)()) {
|
|
59
|
-
const report = await (0, status_data_js_1.collectStatusReport)(harness);
|
|
60
|
-
console.log(JSON.stringify(report, null, 2));
|
|
61
|
-
return 0;
|
|
62
|
-
}
|
|
63
|
-
const launched = await (0, launch_js_1.launchWebDashboard)(binName, harness);
|
|
64
|
-
if (!launched) {
|
|
65
|
-
console.error("Could not start the dashboard server.");
|
|
66
|
-
console.error(`Use "${(0, cli_invocation_js_1.oryNpx)(binName)} dashboard --json" for the raw report instead.`);
|
|
67
|
-
return 1;
|
|
68
|
-
}
|
|
69
|
-
return 0;
|
|
70
|
-
}
|