@ory/argus 1.0.1 → 1.2.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/assets/skills/ory-build-agent/SKILL.md +5 -4
- package/assets/skills/ory-temporal-worker/SKILL.md +9 -9
- package/assets/skills/permissions-onboarding/SKILL.md +66 -142
- package/dist/adapters.js +1 -1
- package/dist/auth.d.ts +4 -0
- package/dist/auth.js +4 -0
- package/dist/bash-parser.js +13 -1
- package/dist/build-info.json +4 -4
- package/dist/cli.js +1 -1
- package/dist/contract-suite.js +5 -2
- package/dist/local/manager.js +1 -1
- package/dist/local/seed.d.ts +1 -1
- package/dist/local/seed.js +4 -62
- package/dist/opl.d.ts +11 -18
- package/dist/opl.js +23 -37
- package/dist/permissions-cli.d.ts +2 -2
- package/dist/permissions-cli.js +15 -32
- package/dist/permissions.d.ts +7 -10
- package/dist/permissions.js +16 -28
- package/dist/post-install.d.ts +1 -1
- package/dist/post-install.js +2 -2
- package/dist/setup.js +1 -1
- package/dist/status-cli.d.ts +1 -1
- package/dist/status-cli.js +12 -12
- package/dist/status-data.d.ts +8 -5
- package/dist/status-data.js +12 -11
- package/package.json +1 -1
|
@@ -361,7 +361,8 @@ PKCE flow, permission tuples, and activity events are all visible:
|
|
|
361
361
|
`jq` — you
|
|
362
362
|
should see `user.auth` → `agent.auth` → `permission.check` →
|
|
363
363
|
`tool.complete` for every call.
|
|
364
|
-
5.
|
|
364
|
+
5. Native tools are allowed unless explicitly blocked. Promote to enforce once
|
|
365
|
+
the block policy is ready. The posture is a
|
|
365
366
|
permission on the Ory project, read on every session — an admin sets it
|
|
366
367
|
in the Ory Console (Agent Security); see the resolved value with
|
|
367
368
|
`... permissions` via any harness CLI (same shared config file).
|
|
@@ -376,9 +377,9 @@ For full env-var coverage (including the user/agent split,
|
|
|
376
377
|
- It does not generate the agent. The user owns the agent loop, tool
|
|
377
378
|
catalog, and deployment shape. This skill only drops `@ory/argus` into
|
|
378
379
|
whatever they already have.
|
|
379
|
-
- It does not
|
|
380
|
-
(Agent Security); `@ory/argus` only reads
|
|
381
|
-
seed
|
|
380
|
+
- It does not write permissions. Native-tool blocks and MCP grants are
|
|
381
|
+
provisioned in the Ory Console (Agent Security); `@ory/argus` only reads
|
|
382
|
+
them. The local seed writes no baseline native-tool grants.
|
|
382
383
|
- It does not adapt one of the existing harness plugins (`@ory/claude-code`,
|
|
383
384
|
`@ory/codex`, `@ory/gemini-cli`, `@ory/openclaw`, `@ory/opencode`). Those
|
|
384
385
|
are for users running those harnesses — not building a custom agent.
|
|
@@ -244,19 +244,19 @@ The Workflow itself produces no Ory activity — only its Activities do.
|
|
|
244
244
|
|
|
245
245
|
## Step 6 — Promotion from observe to enforce
|
|
246
246
|
|
|
247
|
-
The worker starts in `observe` mode by default:
|
|
248
|
-
recorded as a `permission.
|
|
249
|
-
the
|
|
247
|
+
The worker starts in `observe` mode by default: explicit blocks pass through but
|
|
248
|
+
each is recorded as a `permission.block_observed` activity event. Once the user
|
|
249
|
+
has confirmed the block set is what they expect, an admin promotes the posture to `enforce` in
|
|
250
250
|
the Ory Console (Agent Security). It is a permission on the project, read on
|
|
251
251
|
every session, so the worker picks it up on its next run with no redeploy.
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
253
|
+
Activities are allowed by default. Add `blockedSubjects` relations for Activity
|
|
254
|
+
names that must not run, then review them before promoting the posture. See
|
|
255
|
+
{{REF_PERMISSIONS_ONBOARDING}}.
|
|
256
256
|
|
|
257
|
-
To exercise the deny path locally,
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
To exercise the deny path locally, add a `blockedSubjects` relation for an
|
|
258
|
+
Activity name, kick the Workflow, and watch the explicit-block error in the
|
|
259
|
+
Temporal Web UI.
|
|
260
260
|
|
|
261
261
|
## Step 7 — Beyond the dev server
|
|
262
262
|
|
|
@@ -1,195 +1,119 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ory-permissions-onboarding
|
|
3
|
-
description: Onboard
|
|
3
|
+
description: Onboard native agent-tool authorization with default allow and explicit deny overrides. Covers connecting the plugin, reviewing allowed and blocked tools, writing blocks in the Ory Console, and promoting the project from observe to enforce. MCP and PermissionMode remain grant-based.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Onboard
|
|
6
|
+
# Onboard Ory Permissions for Agent Tool Calls
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
first-run failure mode of getting every tool call blocked because the
|
|
11
|
-
project has no grants yet.
|
|
8
|
+
Help the user connect Agent Security and roll out explicit native-tool blocks
|
|
9
|
+
without treating missing grants as denials.
|
|
12
10
|
|
|
13
|
-
**The plugin only reads permissions. It never writes them.**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
Console** (Agent Security) by someone with access to the project. That
|
|
17
|
-
split is deliberate: it means installing and connecting a plugin needs
|
|
18
|
-
nothing but project connection details and a public OAuth2 client id, with no
|
|
19
|
-
workspace privilege and no project API key.
|
|
11
|
+
**The plugin only reads permissions. It never writes them.** The permission
|
|
12
|
+
model, native-tool blocks, MCP grants, and observe/enforce posture are managed
|
|
13
|
+
in the **Ory Console** (Agent Security).
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
Native policy is simple:
|
|
22
16
|
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
the MCP server work either way — they don't need a project at all.
|
|
29
|
-
- **`permissionMode`** — `observe` or `enforce`, **read from the Ory
|
|
30
|
-
project** on every session, and only meaningful once connected.
|
|
31
|
-
`observe` (the default) runs every check, records denials, and lets the
|
|
32
|
-
tool proceed. `enforce` blocks on deny. There is no local override — an
|
|
33
|
-
admin sets it in the Console.
|
|
17
|
+
- `AgentTool` and `ShellTool` have no `users` relation.
|
|
18
|
+
- Their `use` permit is `!blockedSubjects.includes(subject)`.
|
|
19
|
+
- No matching block means allowed; a matching block means denied.
|
|
20
|
+
- `observe` logs the block and proceeds; `enforce` vetoes the call.
|
|
21
|
+
- MCP permissions and `PermissionMode#enforcedSubjects` remain grant-based.
|
|
34
22
|
|
|
35
|
-
|
|
36
|
-
enforce in the Console.**
|
|
23
|
+
## 1. Connect Agent Security
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
A fresh install has the developer-experience half working and Agent
|
|
41
|
-
Security not connected. Copy the connection details shown in the Ory Console
|
|
42
|
-
under **Agent Security**:
|
|
25
|
+
Copy the connection details shown in the Ory Console under **Agent Security**:
|
|
43
26
|
|
|
44
27
|
```sh
|
|
45
28
|
{{NPX}} configure --project-url <URL> --agent-security-url <URL>
|
|
46
29
|
```
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
- **Agent Security URL** — the canonical broker origin (`https://agents.console.ory.com` in production).
|
|
50
|
-
- **OAuth2 client id** — the project's public login client, provisioned
|
|
51
|
-
in the Console. The per-session user login needs it to complete its
|
|
52
|
-
PKCE browser flow.
|
|
53
|
-
|
|
54
|
-
Then confirm what the plugin resolved:
|
|
31
|
+
Then inspect the resolved configuration:
|
|
55
32
|
|
|
56
33
|
```sh
|
|
57
34
|
{{NPX}} status
|
|
58
35
|
```
|
|
59
36
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- **Project URL**: a real Ory URL or your local dev gateway (not "NOT SET").
|
|
63
|
-
- **OAuth2 Client**: the project's public login client (not "NOT SET").
|
|
64
|
-
- **Agent Security**: connected. If it says "not connected", it names the
|
|
65
|
-
unresolved connection value.
|
|
66
|
-
|
|
67
|
-
If the user doesn't have those values, they need them from whoever
|
|
68
|
-
administers the project. Don't try to create the client from here — the
|
|
69
|
-
plugin has no privilege to, by design.
|
|
37
|
+
Confirm that Agent Security is connected and the public OAuth2 login client is
|
|
38
|
+
resolved. The plugin needs no workspace privilege or project API key.
|
|
70
39
|
|
|
71
|
-
##
|
|
40
|
+
## 2. Review Native Tool Access
|
|
72
41
|
|
|
73
42
|
```sh
|
|
74
43
|
{{NPX}} permissions
|
|
75
44
|
```
|
|
76
45
|
|
|
77
|
-
|
|
46
|
+
The report shows:
|
|
78
47
|
|
|
79
|
-
- The live
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
blocked / errored**, from a real check against the project right now.
|
|
84
|
-
- A one-line coverage summary for decomposed shell command words.
|
|
48
|
+
- The live permission mode and its source.
|
|
49
|
+
- The user subject being checked.
|
|
50
|
+
- Each built-in native tool as `allowed`, `blocked`, or `errored`.
|
|
51
|
+
- A compact allowed/blocked summary for decomposed shell command words.
|
|
85
52
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
be blocked under enforce.
|
|
53
|
+
A fresh project normally reports native tools as **allowed**. There is no grant
|
|
54
|
+
coverage step and the local seed writes no baseline `AgentTool` or `ShellTool`
|
|
55
|
+
grants.
|
|
90
56
|
|
|
91
|
-
|
|
92
|
-
**are** being blocked right now. The fix is in the Console (grant the
|
|
93
|
-
tools, or move the project back to observe) — not from the CLI.
|
|
57
|
+
## 3. Add Explicit Blocks in the Console
|
|
94
58
|
|
|
95
|
-
|
|
59
|
+
To block a native tool, write a `blockedSubjects` relation in the Ory Console:
|
|
96
60
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
{{NPX}} watch # live event, decision, and error view
|
|
61
|
+
```text
|
|
62
|
+
namespace: AgentTool
|
|
63
|
+
object: <tool name> e.g. WebFetch
|
|
64
|
+
relation: blockedSubjects
|
|
65
|
+
subject: User:<id>
|
|
103
66
|
```
|
|
104
67
|
|
|
105
|
-
|
|
106
|
-
the watched log and stderr. Denials appear as `permission.observe_deny` activity events (and
|
|
107
|
-
`permission.block_observed` for an explicit block), with the tool name
|
|
108
|
-
and the subject. That list is exactly what has to be granted before
|
|
109
|
-
enforce is safe.
|
|
110
|
-
|
|
111
|
-
## Step 4: Grant the tools in the Ory Console
|
|
68
|
+
To block a command word reached through a shell tool:
|
|
112
69
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
object: <tool name> (e.g. Read, Bash, WebFetch)
|
|
119
|
-
relation: use
|
|
120
|
-
subject: User:<id> (a SubjectSet — namespace `User`, object the user id)
|
|
70
|
+
```text
|
|
71
|
+
namespace: ShellTool
|
|
72
|
+
object: <command word> e.g. curl
|
|
73
|
+
relation: blockedSubjects
|
|
74
|
+
subject: User:<id>
|
|
121
75
|
```
|
|
122
76
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Console's *Add relationship* dialog emits and exactly what the runtime
|
|
127
|
-
check uses. A bare subject id will not match.
|
|
128
|
-
- Granting a **group** and putting users in it scales better than
|
|
129
|
-
per-user grants; the check follows subject-set expansion.
|
|
130
|
-
- **Shell command words** are authorized separately in the `ShellTool`
|
|
131
|
-
namespace (`ShellTool:curl#use`, …) because a denied surface is
|
|
132
|
-
otherwise reachable through `bash -c "curl …"`.
|
|
133
|
-
- **MCP server tools** are discovered dynamically per session, so they
|
|
134
|
-
are not in the built-in catalog and need granting as they come into
|
|
135
|
-
scope.
|
|
136
|
-
|
|
137
|
-
Re-run `{{NPX}} permissions` afterwards to confirm coverage.
|
|
77
|
+
Blocks can also target the project, an agent credential, an agent session, a
|
|
78
|
+
sub-agent credential, or a sub-agent spawn. Group/SubjectSet expansion is
|
|
79
|
+
supported. A native deny is always an explicit block, never a missing grant.
|
|
138
80
|
|
|
139
|
-
|
|
81
|
+
MCP is intentionally different: continue granting MCP server/tool access with
|
|
82
|
+
its existing `users`/`use` and `invoke` relations.
|
|
140
83
|
|
|
141
|
-
|
|
142
|
-
the posture in the Console (Agent Security). The mode is a permission on
|
|
143
|
-
the project, so it can be set **project-wide** — covering principals
|
|
144
|
-
that don't exist yet — or **per principal** as an exception.
|
|
84
|
+
## 4. Observe Before Enforcing
|
|
145
85
|
|
|
146
|
-
|
|
147
|
-
reinstalling or reconfiguring anything. Confirm it landed:
|
|
86
|
+
While the project is in `observe`, run normal sessions and inspect:
|
|
148
87
|
|
|
149
88
|
```sh
|
|
150
89
|
{{NPX}} permissions
|
|
90
|
+
{{NPX}} watch
|
|
151
91
|
```
|
|
152
92
|
|
|
153
|
-
|
|
93
|
+
Matching blocks emit `permission.block_observed` but the tool still runs. Review
|
|
94
|
+
those events, then promote the project or selected principals to `enforce` in
|
|
95
|
+
the Ory Console. Every gate reads the project-controlled posture.
|
|
154
96
|
|
|
155
|
-
|
|
97
|
+
## 5. Verify Enforcement
|
|
156
98
|
|
|
157
|
-
|
|
158
|
-
- **Denied tools** are blocked with a clear "Ory: permission denied"
|
|
159
|
-
message naming the tool (or the shell command word).
|
|
160
|
-
- The activity log shows `permission.check` events per tool call and
|
|
161
|
-
`tool.block` events for denials.
|
|
99
|
+
Under `enforce`:
|
|
162
100
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
101
|
+
- Tools without a matching block run normally.
|
|
102
|
+
- Explicitly blocked tools produce a clear "explicitly blocked" message.
|
|
103
|
+
- A blocked `ShellTool` word blocks the outer shell command and names the word.
|
|
104
|
+
- Infrastructure failures retain the core fail-open behavior.
|
|
166
105
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Granting is additive. To express the opposite — a subject is **blocked**
|
|
170
|
-
from a tool, beating any grant, including one inherited through a group —
|
|
171
|
-
an admin writes a `blockedSubjects` relation in the Console. Ory evaluates it
|
|
172
|
-
natively (the `use` permit is "granted AND not blocked"), so it holds
|
|
173
|
-
no matter how the grant was reached.
|
|
174
|
-
|
|
175
|
-
A block behaves like any other deny: under **observe** it is recorded (a
|
|
176
|
-
`permission.block_observed` activity event) but the tool still runs; under
|
|
177
|
-
**enforce** it blocks. `permissions` marks blocked tools so they
|
|
178
|
-
are distinguishable from a plain missing grant at a glance.
|
|
106
|
+
If a tool is unexpectedly blocked, use `{{NPX}} permissions` to identify the
|
|
107
|
+
block and remove or narrow its `blockedSubjects` relation in the Console.
|
|
179
108
|
|
|
180
109
|
## Reference
|
|
181
110
|
|
|
182
111
|
| Command | Effect |
|
|
183
112
|
|---|---|
|
|
184
|
-
| `{{NPX}} configure --project-url <URL> --agent-security-url <URL>` | Connect
|
|
185
|
-
| `{{NPX}} configure --disconnect` |
|
|
186
|
-
| `{{NPX}} permissions` | Print
|
|
187
|
-
| `{{NPX}} status` |
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
and setting the observe/enforce posture.
|
|
192
|
-
|
|
193
|
-
For deeper background on the authentication side of the flow (which
|
|
194
|
-
identity is the subject, how the user gate resolves it), see
|
|
195
|
-
{{REF_AUTH_SETUP}} and {{REF_LOGIN_FLOW}}.
|
|
113
|
+
| `{{NPX}} configure --project-url <URL> --agent-security-url <URL>` | Connect Agent Security. |
|
|
114
|
+
| `{{NPX}} configure --disconnect` | Disconnect sign-in and permission checks. |
|
|
115
|
+
| `{{NPX}} permissions` | Print live mode plus native allowed/blocked state. Read-only. |
|
|
116
|
+
| `{{NPX}} status` | Print configuration, identities, native tool access, and recent activity. |
|
|
117
|
+
|
|
118
|
+
For authentication and subject-resolution details, see {{REF_AUTH_SETUP}} and
|
|
119
|
+
{{REF_LOGIN_FLOW}}.
|
package/dist/adapters.js
CHANGED
|
@@ -366,7 +366,7 @@ async function decideTool(client, opts) {
|
|
|
366
366
|
const label = (0, subject_js_1.subjectLabel)(subjectRef);
|
|
367
367
|
const canBlock = opts.canBlock ?? true;
|
|
368
368
|
const activityAttrs = gateActivityAttributes(opts);
|
|
369
|
-
const check = { namespace, object: opts.toolName, relation: "
|
|
369
|
+
const check = { namespace, object: opts.toolName, relation: "use", ...subjectRef };
|
|
370
370
|
if (!(0, config_js_1.isSecurityConnected)()) {
|
|
371
371
|
const outcome = {
|
|
372
372
|
kind: "not_connected",
|
package/dist/auth.d.ts
CHANGED
|
@@ -52,6 +52,8 @@ export interface PkceLoginOptions {
|
|
|
52
52
|
isHeadless?: () => boolean;
|
|
53
53
|
/** Optional AbortSignal to cancel the login (e.g. on shutdown). */
|
|
54
54
|
signal?: AbortSignal;
|
|
55
|
+
/** @internal Injectable seam for testing default-fetch TLS setup. */
|
|
56
|
+
configureSystemCaTrust?: () => void;
|
|
55
57
|
}
|
|
56
58
|
export type PkceLoginOutcome = {
|
|
57
59
|
kind: "ok";
|
|
@@ -119,6 +121,8 @@ export declare function refreshAccessToken(args: {
|
|
|
119
121
|
projectUrl: string;
|
|
120
122
|
clientId: string;
|
|
121
123
|
refreshToken: string;
|
|
124
|
+
/** @internal Injectable seam for testing default-fetch TLS setup. */
|
|
125
|
+
configureSystemCaTrust?: () => void;
|
|
122
126
|
}): Promise<OryOAuth2Tokens>;
|
|
123
127
|
/**
|
|
124
128
|
* Best-effort human-readable name for the signed-in user, pulled from the
|
package/dist/auth.js
CHANGED
|
@@ -60,6 +60,7 @@ const node_url_1 = require("node:url");
|
|
|
60
60
|
const fs = __importStar(require("node:fs"));
|
|
61
61
|
const path = __importStar(require("node:path"));
|
|
62
62
|
const branding_js_1 = require("./branding.js");
|
|
63
|
+
const runtime_credential_js_1 = require("./runtime-credential.js");
|
|
63
64
|
/** Loopback ports tried in order. All must be registered as redirect URIs on the Ory OAuth2 client. */
|
|
64
65
|
exports.LOOPBACK_PORTS = [47823, 47824, 47825, 47826];
|
|
65
66
|
/**
|
|
@@ -202,6 +203,7 @@ async function runPkceAttempt(options, scope, scopeFallbackPending) {
|
|
|
202
203
|
redirectUri,
|
|
203
204
|
code: result.code,
|
|
204
205
|
codeVerifier,
|
|
206
|
+
configureSystemCaTrust: options.configureSystemCaTrust,
|
|
205
207
|
});
|
|
206
208
|
return { kind: "ok", tokens };
|
|
207
209
|
}
|
|
@@ -516,6 +518,7 @@ async function exchangeCodeForTokens(args) {
|
|
|
516
518
|
code_verifier: args.codeVerifier,
|
|
517
519
|
});
|
|
518
520
|
const tokenUrl = new node_url_1.URL("/oauth2/token", args.projectUrl).toString();
|
|
521
|
+
(args.configureSystemCaTrust ?? runtime_credential_js_1.configureSystemCaTrustForDefaultFetch)();
|
|
519
522
|
const res = await fetch(tokenUrl, {
|
|
520
523
|
method: "POST",
|
|
521
524
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
@@ -558,6 +561,7 @@ async function refreshAccessToken(args) {
|
|
|
558
561
|
refresh_token: args.refreshToken,
|
|
559
562
|
});
|
|
560
563
|
const tokenUrl = new node_url_1.URL("/oauth2/token", args.projectUrl).toString();
|
|
564
|
+
(args.configureSystemCaTrust ?? runtime_credential_js_1.configureSystemCaTrustForDefaultFetch)();
|
|
561
565
|
const res = await fetch(tokenUrl, {
|
|
562
566
|
method: "POST",
|
|
563
567
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
package/dist/bash-parser.js
CHANGED
|
@@ -172,6 +172,16 @@ function resolveCommandName(nameNode) {
|
|
|
172
172
|
return basename(child.text);
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
+
function commandNameIsAmbiguous(nameNode, name) {
|
|
176
|
+
const raw = nameNode.text;
|
|
177
|
+
if (!/[\\'"$]/.test(raw))
|
|
178
|
+
return false;
|
|
179
|
+
if (!name)
|
|
180
|
+
return true;
|
|
181
|
+
if (raw === `"${name}"` || raw === `'${name}'`)
|
|
182
|
+
return false;
|
|
183
|
+
return !raw.endsWith(`/${name}"`) && !raw.endsWith(`/${name}'`);
|
|
184
|
+
}
|
|
175
185
|
function argNodes(cmd) {
|
|
176
186
|
return cmd.childrenForFieldName("argument").filter((n) => n !== null);
|
|
177
187
|
}
|
|
@@ -271,7 +281,7 @@ function walk(node, pipeline, parser, state, depth, treeDepth) {
|
|
|
271
281
|
}
|
|
272
282
|
const pid = pipeline >= 0 ? pipeline : state.pipelineCounter++;
|
|
273
283
|
const name = resolveCommandName(nameNode);
|
|
274
|
-
if (name === null)
|
|
284
|
+
if (name === null || commandNameIsAmbiguous(nameNode, name))
|
|
275
285
|
state.tooComplex = true;
|
|
276
286
|
const args = argNodes(node);
|
|
277
287
|
state.commands.push({
|
|
@@ -361,6 +371,8 @@ async function extractShellCommands(command) {
|
|
|
361
371
|
if (!tree)
|
|
362
372
|
return { commands: [], tooComplex: true };
|
|
363
373
|
const state = { commands: [], tooComplex: false, pipelineCounter: 0 };
|
|
374
|
+
if (command.includes("\\\n"))
|
|
375
|
+
state.tooComplex = true;
|
|
364
376
|
if (tree.rootNode.hasError)
|
|
365
377
|
state.tooComplex = true;
|
|
366
378
|
// The walk must never throw out of this function — an uncaught error would
|
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"repo": "ory-agent-plugins",
|
|
3
|
-
"commit": "
|
|
4
|
-
"commitShort": "
|
|
3
|
+
"commit": "f046260973bf9257c98d5a06e1d6e945f3c291e5",
|
|
4
|
+
"commitShort": "f046260",
|
|
5
5
|
"branch": "main",
|
|
6
|
-
"commitDate": "2026-
|
|
6
|
+
"commitDate": "2026-09-01T17:01:44-07:00",
|
|
7
7
|
"dirty": false,
|
|
8
|
-
"builtAt": "2026-
|
|
8
|
+
"builtAt": "2026-09-02T00:05:01.245Z"
|
|
9
9
|
}
|
package/dist/cli.js
CHANGED
|
@@ -125,7 +125,7 @@ function runConfigureCommand(binName, args) {
|
|
|
125
125
|
console.log(`User subject ns: ${resolved.userSubjectNamespace ?? "User (default)"} [${resolved.userSubjectNamespaceSource}]`);
|
|
126
126
|
console.log("");
|
|
127
127
|
if (resolved.security.connected) {
|
|
128
|
-
console.log("Sign-in and permission checks are running.
|
|
128
|
+
console.log("Sign-in and permission checks are running. Native-tool blocks, MCP grants,");
|
|
129
129
|
console.log("and the observe/enforce posture are managed in the Ory Console (Agent Security).");
|
|
130
130
|
console.log("");
|
|
131
131
|
console.log("To disconnect (skills, commands, the local stack, and activity logging keep working):");
|
package/dist/contract-suite.js
CHANGED
|
@@ -200,9 +200,12 @@ function runHarnessContractSuite(adapter) {
|
|
|
200
200
|
else {
|
|
201
201
|
(0, vitest_1.expect)(blockEvents).toHaveLength(0);
|
|
202
202
|
}
|
|
203
|
-
//
|
|
203
|
+
// Native tools are default-allow, so a denied use check is an
|
|
204
|
+
// explicit block and receives the block-specific observe event.
|
|
204
205
|
const observeEvents = (0, testing_js_1.getActivityEvents)(client, "permission.observe_deny");
|
|
205
|
-
(0,
|
|
206
|
+
const blockObservedEvents = (0, testing_js_1.getActivityEvents)(client, "permission.block_observed");
|
|
207
|
+
(0, vitest_1.expect)(observeEvents).toHaveLength(0);
|
|
208
|
+
(0, vitest_1.expect)(blockObservedEvents).toHaveLength(check === "denied" && mode === "observe" ? 1 : 0);
|
|
206
209
|
});
|
|
207
210
|
(0, vitest_1.it)("records tool.invoke when an interactive tool proceeds", async () => {
|
|
208
211
|
process.env.ORY_INTERACTIVE_TOOLS = adapter.tool;
|
package/dist/local/manager.js
CHANGED
|
@@ -849,7 +849,7 @@ function printSeedResult(result) {
|
|
|
849
849
|
console.log(` User password: ${result.user.password}`);
|
|
850
850
|
console.log(` User OAuth2: ${result.user.client.clientId} (PKCE)`);
|
|
851
851
|
console.log("");
|
|
852
|
-
console.log(`
|
|
852
|
+
console.log(` Native tool grants: none (default allow; explicit blocks only)`);
|
|
853
853
|
console.log("");
|
|
854
854
|
console.log("To use with any Ory agent plugin, set these environment variables:");
|
|
855
855
|
console.log("");
|
package/dist/local/seed.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export interface SeedResult {
|
|
|
53
53
|
/** OAuth2 authorization_code+PKCE client for interactive logins. */
|
|
54
54
|
client: SeededOAuth2Client;
|
|
55
55
|
};
|
|
56
|
-
/**
|
|
56
|
+
/** Native baseline permission tuples written against the user's subject (always zero). */
|
|
57
57
|
permissions: {
|
|
58
58
|
namespace: string;
|
|
59
59
|
subject: string;
|
package/dist/local/seed.js
CHANGED
|
@@ -27,14 +27,11 @@ exports.USER_SUBJECT_NAMESPACE = exports.USER_CLIENT_ID = void 0;
|
|
|
27
27
|
exports.seedLocalEnvironment = seedLocalEnvironment;
|
|
28
28
|
const auth_js_1 = require("../auth.js");
|
|
29
29
|
const branding_js_1 = require("../branding.js");
|
|
30
|
-
const tool_catalog_js_1 = require("../tool-catalog.js");
|
|
31
30
|
const subject_js_1 = require("../subject.js");
|
|
32
|
-
const opl_js_1 = require("../opl.js");
|
|
33
31
|
const configs_js_1 = require("./configs.js");
|
|
34
32
|
const ports_js_1 = require("./ports.js");
|
|
35
33
|
const health_js_1 = require("./health.js");
|
|
36
34
|
const KRATOS_ADMIN = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KRATOS_ADMIN_PORT);
|
|
37
|
-
const KETO_WRITE = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KETO_WRITE_PORT);
|
|
38
35
|
const HYDRA_ADMIN = (0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.HYDRA_ADMIN_PORT);
|
|
39
36
|
const USER_EMAIL = "user@ory-local.dev";
|
|
40
37
|
const USER_PASSWORD = "ory-user-local-dev-password!";
|
|
@@ -49,11 +46,6 @@ const USER_PASSWORD = "ory-user-local-dev-password!";
|
|
|
49
46
|
* dragging the value out of the `local up` banner.
|
|
50
47
|
*/
|
|
51
48
|
exports.USER_CLIENT_ID = branding_js_1.USER_LOGIN_CLIENT_ID;
|
|
52
|
-
/**
|
|
53
|
-
* Tools the explicit local-stack command seeds tuples for. Sourced from the
|
|
54
|
-
* shared catalog so one seed covers every harness's built-in tool set.
|
|
55
|
-
*/
|
|
56
|
-
const COMMON_TOOLS = tool_catalog_js_1.ALL_TOOLS;
|
|
57
49
|
async function jsonFetch(url, opts = {}) {
|
|
58
50
|
const res = await fetch(url, {
|
|
59
51
|
...opts,
|
|
@@ -94,44 +86,6 @@ async function seedIdentity(email, password, name) {
|
|
|
94
86
|
* install config all address the user under the same namespace.
|
|
95
87
|
*/
|
|
96
88
|
exports.USER_SUBJECT_NAMESPACE = subject_js_1.DEFAULT_USER_SUBJECT_NAMESPACE;
|
|
97
|
-
/**
|
|
98
|
-
* Write permission tuples granting the user identity access to all
|
|
99
|
-
* common tools. The subject is written as a SubjectSet
|
|
100
|
-
* `User:<userId>` (no relation) so the Console UI's *Add relationship*
|
|
101
|
-
* dialog — which only emits SubjectSet subjects — can recreate the same
|
|
102
|
-
* tuple by hand during the runbook walkthrough.
|
|
103
|
-
*/
|
|
104
|
-
async function seedPermissions(userId, namespace, objects = COMMON_TOOLS) {
|
|
105
|
-
let created = 0;
|
|
106
|
-
for (const object of objects) {
|
|
107
|
-
try {
|
|
108
|
-
await jsonFetch(`${KETO_WRITE}/admin/relation-tuples`, {
|
|
109
|
-
method: "PUT",
|
|
110
|
-
body: JSON.stringify({
|
|
111
|
-
namespace,
|
|
112
|
-
object,
|
|
113
|
-
relation: opl_js_1.RELATION_USERS,
|
|
114
|
-
subject_set: {
|
|
115
|
-
namespace: exports.USER_SUBJECT_NAMESPACE,
|
|
116
|
-
object: userId,
|
|
117
|
-
relation: "",
|
|
118
|
-
},
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
121
|
-
created++;
|
|
122
|
-
}
|
|
123
|
-
catch (err) {
|
|
124
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
125
|
-
if (!msg.includes("409")) {
|
|
126
|
-
process.stderr.write(` Warning: failed to create permission for ${object}: ${msg}\n`);
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
created++;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return created;
|
|
134
|
-
}
|
|
135
89
|
/**
|
|
136
90
|
* Delete a Hydra OAuth2 client if it exists, then create it at a known
|
|
137
91
|
* client_id (with a known secret, for a confidential client). We always
|
|
@@ -209,22 +163,10 @@ async function seedLocalEnvironment(namespace = "AgentTool") {
|
|
|
209
163
|
process.stderr.write(" Creating user identity...\n");
|
|
210
164
|
const userIdentity = await seedIdentity(USER_EMAIL, USER_PASSWORD, "Local User");
|
|
211
165
|
process.stderr.write(` User: ${userIdentity.id} (${userIdentity.email})\n`);
|
|
212
|
-
// 2.
|
|
213
|
-
//
|
|
214
|
-
// Subject is a SubjectSet `User:<id>` so the Console UI can rewrite
|
|
215
|
-
// the same tuple shape by hand during the runbook demo.
|
|
166
|
+
// 2. Native tools are allowed by default. Seed no AgentTool or ShellTool
|
|
167
|
+
// baseline grants; local behavior must match hosted default-allow policy.
|
|
216
168
|
const subjectLabel = `${exports.USER_SUBJECT_NAMESPACE}:${userIdentity.id}`;
|
|
217
|
-
process.stderr.write(
|
|
218
|
-
const tupleCount = await seedPermissions(userIdentity.id, namespace);
|
|
219
|
-
process.stderr.write(` Permissions: ${tupleCount} entries in '${namespace}' for ${subjectLabel}\n`);
|
|
220
|
-
// Shell-command sub-tools (issue #76): grant every catalog word in the
|
|
221
|
-
// ShellTool namespace so a launched harness can run `bash -c "curl …"`
|
|
222
|
-
// out of the box, and the enforce demo (revoke `ShellTool:curl#users`,
|
|
223
|
-
// watch it block) works without hand-writing tuples first.
|
|
224
|
-
const shellWords = (0, tool_catalog_js_1.getShellCommandCatalog)();
|
|
225
|
-
const shellNamespace = (0, tool_catalog_js_1.resolveShellCommandNamespace)();
|
|
226
|
-
const shellCount = await seedPermissions(userIdentity.id, shellNamespace, shellWords);
|
|
227
|
-
process.stderr.write(` Shell commands: ${shellCount} entries in '${shellNamespace}' for ${subjectLabel}\n`);
|
|
169
|
+
process.stderr.write(" Native tools: allowed unless explicitly blocked (no baseline grants)\n");
|
|
228
170
|
// 3. User OAuth2 client (PKCE) — pre-registered so the user gate's
|
|
229
171
|
// PKCE flow has somewhere to authenticate against. The agent's
|
|
230
172
|
// OAuth2 client is intentionally NOT pre-registered; the harness
|
|
@@ -253,6 +195,6 @@ async function seedLocalEnvironment(namespace = "AgentTool") {
|
|
|
253
195
|
}
|
|
254
196
|
return {
|
|
255
197
|
user: { identity: userIdentity, password: USER_PASSWORD, client: userClient },
|
|
256
|
-
permissions: { namespace, subject: subjectLabel, tuples:
|
|
198
|
+
permissions: { namespace, subject: subjectLabel, tuples: 0 },
|
|
257
199
|
};
|
|
258
200
|
}
|