@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.
Files changed (150) hide show
  1. package/README.md +31 -46
  2. package/assets/commands/temporal-up.md +1 -1
  3. package/assets/skills/auth-setup/SKILL.md +1 -1
  4. package/assets/skills/local-dev/SKILL.md +17 -7
  5. package/assets/skills/ory-build-agent/SKILL.md +39 -91
  6. package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
  7. package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
  8. package/assets/skills/permissions-onboarding/SKILL.md +131 -104
  9. package/dist/adapters.d.ts +88 -32
  10. package/dist/adapters.js +443 -164
  11. package/dist/agent-auth.d.ts +226 -67
  12. package/dist/agent-auth.js +951 -205
  13. package/dist/auth-store.d.ts +37 -2
  14. package/dist/auth-store.js +37 -3
  15. package/dist/auth.d.ts +33 -4
  16. package/dist/auth.js +163 -20
  17. package/dist/bash-parser.d.ts +98 -0
  18. package/dist/bash-parser.js +396 -0
  19. package/dist/branding.d.ts +77 -16
  20. package/dist/branding.js +93 -23
  21. package/dist/build-info.json +4 -4
  22. package/dist/cli-invocation.d.ts +1 -1
  23. package/dist/cli-invocation.js +2 -1
  24. package/dist/cli.d.ts +20 -29
  25. package/dist/cli.js +271 -239
  26. package/dist/client.d.ts +175 -138
  27. package/dist/client.js +672 -391
  28. package/dist/config.d.ts +217 -54
  29. package/dist/config.js +461 -42
  30. package/dist/context.d.ts +10 -0
  31. package/dist/context.js +21 -0
  32. package/dist/contract-suite.d.ts +3 -5
  33. package/dist/contract-suite.js +75 -47
  34. package/dist/denial.d.ts +36 -3
  35. package/dist/denial.js +79 -10
  36. package/dist/event-reporter.d.ts +77 -0
  37. package/dist/event-reporter.js +776 -0
  38. package/dist/external-registrations-main.d.ts +10 -0
  39. package/dist/external-registrations-main.js +38 -0
  40. package/dist/external-registrations.d.ts +79 -0
  41. package/dist/external-registrations.js +188 -0
  42. package/dist/help-cli.d.ts +39 -0
  43. package/dist/help-cli.js +55 -0
  44. package/dist/hook-timeout.d.ts +64 -0
  45. package/dist/hook-timeout.js +88 -0
  46. package/dist/index.d.ts +28 -23
  47. package/dist/index.js +173 -58
  48. package/dist/lifecycle.d.ts +3 -3
  49. package/dist/lifecycle.js +38 -6
  50. package/dist/local/cli.js +11 -6
  51. package/dist/local/configs.d.ts +74 -18
  52. package/dist/local/configs.js +291 -84
  53. package/dist/local/health.js +7 -7
  54. package/dist/local/index.d.ts +2 -2
  55. package/dist/local/index.js +24 -10
  56. package/dist/local/manager.d.ts +20 -1
  57. package/dist/local/manager.js +159 -36
  58. package/dist/local/ports.d.ts +158 -0
  59. package/dist/local/ports.js +443 -0
  60. package/dist/local/seed.d.ts +13 -5
  61. package/dist/local/seed.js +62 -38
  62. package/dist/logger.d.ts +54 -25
  63. package/dist/logger.js +329 -63
  64. package/dist/mcp.d.ts +2 -2
  65. package/dist/mcp.js +10 -5
  66. package/dist/mirror-bootstrap.d.ts +48 -0
  67. package/dist/mirror-bootstrap.js +254 -0
  68. package/dist/opl.d.ts +289 -0
  69. package/dist/opl.js +446 -0
  70. package/dist/permission-mode.d.ts +87 -0
  71. package/dist/permission-mode.js +307 -0
  72. package/dist/permissions-cli.d.ts +13 -49
  73. package/dist/permissions-cli.js +154 -348
  74. package/dist/permissions.d.ts +148 -38
  75. package/dist/permissions.js +591 -45
  76. package/dist/post-install.d.ts +33 -0
  77. package/dist/post-install.js +127 -0
  78. package/dist/read-credential.d.ts +65 -0
  79. package/dist/read-credential.js +86 -0
  80. package/dist/registry/cli.js +5 -2
  81. package/dist/registry/config.d.ts +0 -17
  82. package/dist/registry/config.js +0 -23
  83. package/dist/registry/index.d.ts +1 -1
  84. package/dist/registry/index.js +2 -2
  85. package/dist/registry/manager.d.ts +4 -21
  86. package/dist/registry/manager.js +21 -37
  87. package/dist/runtime-credential.d.ts +140 -0
  88. package/dist/runtime-credential.js +572 -0
  89. package/dist/runtime.d.ts +408 -0
  90. package/dist/runtime.js +748 -0
  91. package/dist/setup.d.ts +23 -47
  92. package/dist/setup.js +59 -116
  93. package/dist/skills.js +0 -7
  94. package/dist/status-cli.d.ts +27 -11
  95. package/dist/status-cli.js +121 -115
  96. package/dist/status-data.d.ts +116 -17
  97. package/dist/status-data.js +121 -38
  98. package/dist/subject.d.ts +126 -20
  99. package/dist/subject.js +215 -30
  100. package/dist/testing.d.ts +74 -38
  101. package/dist/testing.js +185 -68
  102. package/dist/tool-catalog.d.ts +53 -11
  103. package/dist/tool-catalog.js +164 -13
  104. package/dist/tool-metadata.d.ts +7 -6
  105. package/dist/tool-metadata.js +6 -5
  106. package/dist/types.d.ts +11 -1
  107. package/dist/uninstall.d.ts +71 -34
  108. package/dist/uninstall.js +217 -85
  109. package/dist/user-login.d.ts +9 -10
  110. package/dist/user-login.js +56 -75
  111. package/dist/watch-cli.d.ts +6 -0
  112. package/dist/watch-cli.js +217 -0
  113. package/package.json +4 -27
  114. package/assets/commands/dashboard.md +0 -34
  115. package/dist/dashboard-cli.d.ts +0 -8
  116. package/dist/dashboard-cli.js +0 -70
  117. package/dist/dev.d.ts +0 -103
  118. package/dist/dev.js +0 -583
  119. package/dist/interactive-setup.d.ts +0 -286
  120. package/dist/interactive-setup.js +0 -1734
  121. package/dist/local/jaeger-main.d.ts +0 -13
  122. package/dist/local/jaeger-main.js +0 -85
  123. package/dist/local/jaeger.d.ts +0 -50
  124. package/dist/local/jaeger.js +0 -162
  125. package/dist/otel/exporter.d.ts +0 -17
  126. package/dist/otel/exporter.js +0 -12
  127. package/dist/otel/index.d.ts +0 -2
  128. package/dist/otel/index.js +0 -8
  129. package/dist/otel/otlp.d.ts +0 -103
  130. package/dist/otel/otlp.js +0 -385
  131. package/dist/project-api-key.d.ts +0 -69
  132. package/dist/project-api-key.js +0 -147
  133. package/dist/setup-actions.d.ts +0 -232
  134. package/dist/setup-actions.js +0 -507
  135. package/dist/tracer.d.ts +0 -190
  136. package/dist/tracer.js +0 -481
  137. package/dist/watch-sandbox.d.ts +0 -9
  138. package/dist/watch-sandbox.js +0 -81
  139. package/dist/web/api.d.ts +0 -33
  140. package/dist/web/api.js +0 -294
  141. package/dist/web/launch.d.ts +0 -11
  142. package/dist/web/launch.js +0 -96
  143. package/dist/web/server.d.ts +0 -20
  144. package/dist/web/server.js +0 -233
  145. package/dist/web/types.d.ts +0 -65
  146. package/dist/web/types.js +0 -2
  147. package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
  148. package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
  149. package/dist/webapp/favicon.ico +0 -0
  150. package/dist/webapp/index.html +0 -15
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * 1. Runs the check.
10
10
  * 2. On a Keto deny (`result.allowed === false`), applies the mode:
11
- * - `observe` — record a `permission.observe_deny` audit span,
11
+ * - `observe` — record a `permission.observe_deny` audit event,
12
12
  * return `{ kind: "observe", … }` so the caller allows the
13
13
  * tool through.
14
14
  * - `enforce` — return `{ kind: "deny", … }` so the caller blocks.
@@ -30,14 +30,38 @@
30
30
  import type { OryAgentClient } from "./client.js";
31
31
  import { type PermissionMode } from "./config.js";
32
32
  import type { OryError, OryErrorCode, PermissionCheck, PermissionResult } from "./types.js";
33
+ /**
34
+ * Why a permission check came back denied, once the block-aware OPL schema is
35
+ * in play:
36
+ *
37
+ * - `not_granted` — the subject simply has no `use` grant on the object
38
+ * (the legacy "deny by absence" case).
39
+ * - `explicit_block` — a `blocked` relation matched the subject, so the
40
+ * `access` permit's deny-override fired even if a `use` grant exists.
41
+ *
42
+ * Threaded onto the decision's activity attributes and into the observe-mode
43
+ * audit event so "explicitly blocked" is distinguishable from "never granted"
44
+ * in activity logs, mirroring how `checkRejected` distinguishes an auth-rejected
45
+ * deny.
46
+ */
47
+ export type BlockReason = "not_granted" | "explicit_block";
48
+ /**
49
+ * Map the logical grant relation a caller passes (`use`) onto the relation or
50
+ * permit Argus actually checks. A `use` check always routes through the
51
+ * block-aware `access` permit (`use && !blocked`), so an explicit block is
52
+ * always respected — the permission model must therefore be applied to the
53
+ * project (done in the Ory Console, Agent Security) for checks to resolve. Any
54
+ * other relation passes through unchanged.
55
+ */
56
+ export declare function resolveCheckRelation(relation: string): string;
33
57
  /**
34
58
  * Attributes describing *what was checked* and *under which posture*.
35
- * Plugins spread this onto their `tool.invoke` / `tool.block` spans so
59
+ * Plugins spread this onto their `tool.invoke` / `tool.block` activity events so
36
60
  * the audit trail makes the observe-vs-enforce posture and the checked
37
- * subject visible at a glance — without that, a span with `allowed=false`
61
+ * subject visible at a glance — without that, an event with `allowed=false`
38
62
  * status=ok is ambiguous (observe pass-through? fail-open? bug?).
39
63
  */
40
- export interface DecisionSpanAttributes {
64
+ export interface DecisionActivityAttributes {
41
65
  permissionMode: PermissionMode;
42
66
  /** Direct subject ID when the check used `subjectId`. */
43
67
  subjectId?: string;
@@ -50,27 +74,62 @@ export interface DecisionSpanAttributes {
50
74
  * distinguishable from a normal Keto deny in the audit trail.
51
75
  */
52
76
  checkRejected?: OryErrorCode;
77
+ /**
78
+ * Shell decomposition (issue #76): the specific denied command word that
79
+ * caused a `Bash` deny (`curl`), so denial text and `tool.block` events name
80
+ * it. {@link shellDeniedWords} carries the full set when more than one.
81
+ */
82
+ shellWord?: string;
83
+ shellDeniedWords?: string[];
84
+ /**
85
+ * The parsed decomposition, attached to activity so the shell breakdown is
86
+ * observable in real time: every command word extracted, and how many. These
87
+ * are binary/builtin *names* only — the **raw** command is NEVER placed in a
88
+ * activity event; it goes only to the local debug log, gated by
89
+ * `ORY_AGENT_DEBUG`.
90
+ */
91
+ shellWords?: string[];
92
+ shellCommandCount?: number;
93
+ /**
94
+ * Set when a shell command could not be safely parsed (dynamic name /
95
+ * unparseable) and enforce mode denied it, or observe logged it.
96
+ */
97
+ shellTooComplex?: true;
98
+ /**
99
+ * Set on a deny: whether the deny was an explicit block or a plain missing
100
+ * grant. See {@link BlockReason}.
101
+ */
102
+ blockReason?: BlockReason;
103
+ /**
104
+ * The machine principal an explicit block matched — the exact subject string
105
+ * (`Agent:<clientId>|<session>`, …), so the audit trail names the relation an
106
+ * admin would go edit. Set whenever a principal block fired, including on a
107
+ * deny the user's own check had already produced.
108
+ */
109
+ blockedPrincipal?: string;
110
+ /** Which level of the identity model the block was written at. */
111
+ blockedPrincipalLevel?: string;
53
112
  }
54
113
  export type PermissionDecision = {
55
114
  kind: "allow";
56
115
  result: PermissionResult;
57
116
  mode: PermissionMode;
58
- spanAttributes: DecisionSpanAttributes;
117
+ activityAttributes: DecisionActivityAttributes;
59
118
  } | {
60
119
  kind: "deny";
61
120
  result: PermissionResult;
62
121
  mode: "enforce";
63
- spanAttributes: DecisionSpanAttributes;
122
+ activityAttributes: DecisionActivityAttributes;
64
123
  } | {
65
124
  kind: "observe";
66
125
  result: PermissionResult;
67
126
  mode: "observe";
68
- spanAttributes: DecisionSpanAttributes;
127
+ activityAttributes: DecisionActivityAttributes;
69
128
  } | {
70
129
  kind: "fail_open";
71
130
  error: OryError;
72
131
  mode: PermissionMode;
73
- spanAttributes: DecisionSpanAttributes;
132
+ activityAttributes: DecisionActivityAttributes;
74
133
  };
75
134
  /**
76
135
  * The "what should the caller do?" half of a decision, independent of
@@ -81,23 +140,23 @@ export type PermissionDecision = {
81
140
  export type ModeDecision = {
82
141
  kind: "allow";
83
142
  mode: PermissionMode;
84
- spanAttributes: DecisionSpanAttributes;
143
+ activityAttributes: DecisionActivityAttributes;
85
144
  } | {
86
145
  kind: "deny";
87
146
  mode: "enforce";
88
- spanAttributes: DecisionSpanAttributes;
147
+ activityAttributes: DecisionActivityAttributes;
89
148
  } | {
90
149
  kind: "observe";
91
150
  mode: "observe";
92
- spanAttributes: DecisionSpanAttributes;
151
+ activityAttributes: DecisionActivityAttributes;
93
152
  };
94
153
  export interface CheckAndDecideOptions {
95
154
  /**
96
- * Span attributes merged into the underlying `permission.check` span
97
- * and into the synthetic `permission.observe_deny` span when emitted.
155
+ * Activity attributes merged into the underlying `permission.check` event
156
+ * and into the synthetic `permission.observe_deny` event when emitted.
98
157
  * Same shape and semantics as `client.checkPermission`'s option.
99
158
  */
100
- spanAttributes?: Record<string, unknown>;
159
+ activityAttributes?: Record<string, unknown>;
101
160
  /**
102
161
  * Override the resolved {@link PermissionMode}. Tests use this to
103
162
  * exercise both branches without mutating env or config state.
@@ -107,7 +166,7 @@ export interface CheckAndDecideOptions {
107
166
  export interface ApplyPermissionModeContext {
108
167
  /**
109
168
  * Namespace / object / relation that produced the `allowed` boolean.
110
- * Logged on observe-deny and attached to the audit span. All optional
169
+ * Logged on observe-deny and attached to the audit event. All optional
111
170
  * — the helper still works without them, but populated values make
112
171
  * the audit trail searchable.
113
172
  */
@@ -118,37 +177,44 @@ export interface ApplyPermissionModeContext {
118
177
  subjectId?: string;
119
178
  /** SubjectSet for the observe-deny log line, if available. */
120
179
  subjectSet?: PermissionCheck["subjectSet"];
121
- /** Attributes merged into the `permission.observe_deny` span. */
122
- spanAttributes?: Record<string, unknown>;
180
+ /** Attributes merged into the `permission.observe_deny` activity event. */
181
+ activityAttributes?: Record<string, unknown>;
123
182
  /** Override the resolved mode (tests). */
124
183
  modeOverride?: PermissionMode;
184
+ /**
185
+ * Why the check denied, when known (block-aware schema path). When
186
+ * `explicit_block`, observe mode records a distinct `permission.block_observed`
187
+ * audit event instead of the generic `permission.observe_deny`, and the
188
+ * reason is attached to the decision activity attributes in every mode.
189
+ */
190
+ blockReason?: BlockReason;
125
191
  }
126
192
  /**
127
193
  * Map an `allowed` boolean from any permission check (plain or MCP)
128
194
  * onto a {@link ModeDecision}. When `allowed === false` and the mode
129
- * is `observe`, emits the `permission.observe_deny` audit span and
195
+ * is `observe`, emits the `permission.observe_deny` audit event and
130
196
  * returns `{ kind: "observe" }` so the caller knows to let the action
131
197
  * proceed despite the deny.
132
198
  */
133
199
  export declare function applyPermissionMode(client: OryAgentClient, allowed: boolean, context?: ApplyPermissionModeContext): ModeDecision;
134
200
  /**
135
- * Outcome of {@link gateToolCall}. Either Ory is disabled entirely
136
- * (`config.auditOnly` kill switch), the tool is a user-interaction
137
- * primitive (`AskUserQuestion`, `ExitPlanMode`, `TodoWrite`, …) and we
138
- * pass through with a single audit span, or it's a real tool execution
139
- * and the caller gets the standard {@link PermissionDecision}.
201
+ * Outcome of {@link gateToolCall}. Either Agent Security isn't connected so no
202
+ * check runs, the tool is a user-interaction primitive (`AskUserQuestion`,
203
+ * `ExitPlanMode`, `TodoWrite`, …) and we pass through with one audit event,
204
+ * or it's a real tool execution and the caller gets the standard
205
+ * {@link PermissionDecision}.
140
206
  */
141
207
  export type ToolGateOutcome = {
142
- kind: "audit_only";
143
- /** Attributes to attach to the caller's pass-through trace, if any. */
144
- spanAttributes: {
145
- auditOnly: true;
208
+ kind: "not_connected";
209
+ /** Attributes to attach to the caller's pass-through activity, if any. */
210
+ activityAttributes: {
211
+ securityConnected: false;
146
212
  toolName: string;
147
213
  };
148
214
  } | {
149
215
  kind: "interactive";
150
- /** Attributes to attach to the caller's pass-through trace, if any. */
151
- spanAttributes: {
216
+ /** Attributes to attach to the caller's pass-through activity, if any. */
217
+ activityAttributes: {
152
218
  interactive: true;
153
219
  toolName: string;
154
220
  };
@@ -161,18 +227,33 @@ export interface GateToolCallArgs {
161
227
  /** Permission check to run when the tool is a real execution. */
162
228
  check: PermissionCheck;
163
229
  /**
164
- * Attributes merged into the permission span (real path) and the
165
- * `user.interaction` span (interactive path).
230
+ * Attributes merged into permission activity (real path) and the
231
+ * `user.interaction` event (interactive path).
166
232
  */
167
- spanAttributes?: Record<string, unknown>;
233
+ activityAttributes?: Record<string, unknown>;
168
234
  /** Override the resolved {@link PermissionMode}. Tests use this. */
169
235
  modeOverride?: PermissionMode;
236
+ /**
237
+ * Raw shell command string when {@link toolName} is the harness's shell tool
238
+ * (issue #76). When present and the tool is a shell tool, the gate decomposes
239
+ * the command into `ShellTool:<word>#use` sub-checks in addition to the
240
+ * top-level tool check. Absent / undefined ⇒ decomposition is skipped and the
241
+ * gate behaves exactly as before.
242
+ */
243
+ shellCommand?: string;
244
+ /**
245
+ * The acting machine principals, so an explicit block on the agent install,
246
+ * this session, the sub-agent kind, or this spawn can deny the call. Omitted ⇒
247
+ * only the agent principal already on the client is considered (there is no
248
+ * sub-agent context to check).
249
+ */
250
+ principals?: PrincipalBlockSubjects;
170
251
  }
171
252
  /**
172
- * Single entry point for the pre-tool-use gate. Applies the
173
- * `config.auditOnly` kill switch first — when set, Ory is disabled
174
- * entirely and the caller gets `{ kind: "audit_only" }` back without any
175
- * permission check (record the invocation as an audit span and proceed).
253
+ * Single entry point for the pre-tool-use gate. Checks whether Agent Security
254
+ * is connected first — with no project URL there is
255
+ * nothing to check against, so the caller gets `{ kind: "not_connected" }`
256
+ * back and should record the invocation as an audit event and proceed.
176
257
  * Otherwise splits the harness's incoming "tool" into two semantic
177
258
  * categories:
178
259
  *
@@ -182,7 +263,7 @@ export interface GateToolCallArgs {
182
263
  * through Ory: the user is the decision-maker, and blocking them in
183
264
  * enforce mode (or logging a misleading observe-deny) hides the very
184
265
  * prompt the user needs to see. We record one `user.interaction`
185
- * audit span and return — no permission check, no `tool.invoke`,
266
+ * audit event and return — no permission check, no `tool.invoke`,
186
267
  * no `tool.block`.
187
268
  *
188
269
  * - **Execution** — every other tool. Delegates to
@@ -194,11 +275,40 @@ export interface GateToolCallArgs {
194
275
  * semantics; the new `interactive` kind means "do nothing else."
195
276
  */
196
277
  export declare function gateToolCall(client: OryAgentClient, args: GateToolCallArgs): Promise<ToolGateOutcome>;
278
+ /**
279
+ * Gate a shell tool by decomposing its command into the program/builtin words
280
+ * that will run and checking each as `ShellTool:<word>#use`, on top of the
281
+ * existing top-level tool check.
282
+ *
283
+ * Aggregation: **any deny → deny** (naming the offending word); else any observe
284
+ * → observe (pass through, per-word `permission.observe_deny` events recorded);
285
+ * else allow. A too-complex / unparseable command is **fail-closed** in enforce
286
+ * (deny + alert) and logged-then-passed in observe. A parser-unavailable or
287
+ * infrastructure error is **fail-open** (top-level decision only) — availability
288
+ * must not hinge on the parser.
289
+ */
290
+ export declare function decomposeAndCheck(client: OryAgentClient, args: GateToolCallArgs): Promise<PermissionDecision>;
197
291
  /**
198
292
  * Run a permission check and resolve the configured mode against the
199
293
  * result. Never throws — infrastructure errors surface as a typed
200
294
  * `{ kind: "fail_open" }` decision, and auth-rejected check calls in
201
295
  * enforce mode as `{ kind: "deny" }` (see
202
- * {@link CHECK_AUTH_REJECTED_CODES}).
296
+ * {@link CHECK_UNTRUSTED_CODES}).
203
297
  */
204
298
  export declare function checkAndDecide(client: OryAgentClient, check: PermissionCheck, opts?: CheckAndDecideOptions): Promise<PermissionDecision>;
299
+ /**
300
+ * The acting machine principals for a tool call, as the subjects a `blocked`
301
+ * relation can name. Built by the caller (a harness handler knows whether it is
302
+ * in a sub-agent and what its type/spawn id are) and threaded into
303
+ * {@link gateToolCall}.
304
+ */
305
+ export interface PrincipalBlockSubjects {
306
+ /** Sub-agent client id, when this call runs inside a sub-agent. */
307
+ subAgentClientId?: string;
308
+ /** Sub-agent type, required for the spawn-level subject to be built. */
309
+ subAgentType?: string;
310
+ /** Per-spawn id, on the harnesses that expose one. */
311
+ perSpawnId?: string;
312
+ /** Override the session; defaults to the client's ambient session. */
313
+ sessionId?: string;
314
+ }