@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ory-temporal-worker
|
|
3
|
-
description: Scaffold a [Temporal](https://temporal.io) TypeScript worker where every Activity execution is gated by Ory — the user is authenticated, the worker's agent identity is resolved via DCR, each Activity invocation runs an Ory Permission check, and the full lifecycle emits
|
|
3
|
+
description: Scaffold a [Temporal](https://temporal.io) TypeScript worker where every Activity execution is gated by Ory — the user is authenticated, the worker's agent identity is resolved via DCR, each Activity invocation runs an Ory Permission check, and the full lifecycle emits structured activity events. Use when the user asks to "add Ory to my Temporal worker", "wire Ory permissions into Temporal activities", "create a Temporal worker with Ory auth", "build a Temporal TypeScript project with the Ory agent client", or any close variant. The skill scaffolds the project in the user's repo following <https://docs.temporal.io/develop/typescript/set-up-your-local-typescript> — it does not run the worker.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Ory-authed Temporal TypeScript worker
|
|
@@ -9,7 +9,7 @@ You are helping the user scaffold a [Temporal](https://temporal.io) TypeScript
|
|
|
9
9
|
worker where every Activity execution is gated by Ory: the user is
|
|
10
10
|
authenticated, the worker's agent identity is resolved via OAuth2 Dynamic Client
|
|
11
11
|
Registration, each Activity invocation runs an Ory Permission check, and the
|
|
12
|
-
full lifecycle emits
|
|
12
|
+
full lifecycle emits structured activity events. **Workflows stay deterministic** — only
|
|
13
13
|
Activities call out to Ory.
|
|
14
14
|
|
|
15
15
|
This skill carries the workflow. You generate the files in the user's repo; the
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
} from "@ory/argus";
|
|
71
71
|
|
|
72
72
|
// One client per worker process. `harness` is a label that shows up on
|
|
73
|
-
// every
|
|
73
|
+
// every activity event so worker-originated audit lives in its own namespace
|
|
74
74
|
// alongside the CLI plugins.
|
|
75
75
|
const ory = OryAgentClient.fromEnv("temporal");
|
|
76
76
|
|
|
@@ -83,12 +83,10 @@ function bootstrap(): Promise<void> {
|
|
|
83
83
|
await ensureUserAuthenticated(ory, {
|
|
84
84
|
binName: "temporal-worker",
|
|
85
85
|
harness: "temporal",
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
// enforcement happens at the per-Activity permission check.
|
|
91
|
-
allowBlock: false,
|
|
86
|
+
// The user gate runs every invocation and never blocks: it refreshes
|
|
87
|
+
// tokens and emits the audit event, but the worker proceeds even if the
|
|
88
|
+
// user is unauthenticated. Enforcement happens at the per-Activity
|
|
89
|
+
// permission check (permissionMode).
|
|
92
90
|
});
|
|
93
91
|
await ensureAgentIdentity(ory, {
|
|
94
92
|
projectUrl: process.env.ORY_PROJECT_URL,
|
|
@@ -104,13 +102,13 @@ async function gate(toolName: string, userSubject: string): Promise<void> {
|
|
|
104
102
|
const decision = await checkAndDecide(
|
|
105
103
|
ory,
|
|
106
104
|
{
|
|
107
|
-
namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "
|
|
105
|
+
namespace: process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTool",
|
|
108
106
|
object: toolName,
|
|
109
107
|
relation: "use",
|
|
110
108
|
...subject,
|
|
111
109
|
},
|
|
112
110
|
{
|
|
113
|
-
|
|
111
|
+
activityAttributes: {
|
|
114
112
|
toolName,
|
|
115
113
|
workflowId: Context.current().info.workflowExecution.workflowId,
|
|
116
114
|
activityId: Context.current().info.activityId,
|
|
@@ -145,13 +143,13 @@ Key choices:
|
|
|
145
143
|
|
|
146
144
|
- **Activities call Ory, Workflows don't.** Anything that needs a live decision
|
|
147
145
|
goes in an Activity. Workflows only orchestrate.
|
|
148
|
-
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- **`harness: "temporal"`.** Distinguishes worker-originated
|
|
153
|
-
|
|
154
|
-
- **
|
|
146
|
+
- **The user gate never blocks.** It runs every invocation to refresh the user
|
|
147
|
+
identity, but always proceeds. Enforcement is at the permission check, which
|
|
148
|
+
throws on deny — Temporal will mark the Activity as failed and surface the
|
|
149
|
+
error via the Workflow result or retry policy.
|
|
150
|
+
- **`harness: "temporal"`.** Distinguishes worker-originated events in the
|
|
151
|
+
unified activity log.
|
|
152
|
+
- **Activity attributes carry the Workflow + Activity IDs.** This is how operators
|
|
155
153
|
correlate Ory denials back to Temporal executions in the Web UI.
|
|
156
154
|
|
|
157
155
|
## Step 4 — Pass the user subject through the Workflow
|
|
@@ -217,7 +215,7 @@ cd temporal-worker
|
|
|
217
215
|
export ORY_PROJECT_URL=http://localhost:4000
|
|
218
216
|
export ORY_AUTH_GATE=1
|
|
219
217
|
export ORY_AGENT_DEBUG=true
|
|
220
|
-
export
|
|
218
|
+
export ORY_AGENT_LOG_FILE=$PWD/ory-agent-debug.log
|
|
221
219
|
npm run start # boots the worker, polls task queue
|
|
222
220
|
```
|
|
223
221
|
|
|
@@ -228,49 +226,47 @@ cd temporal-worker
|
|
|
228
226
|
npm run workflow
|
|
229
227
|
```
|
|
230
228
|
|
|
231
|
-
Tail the
|
|
229
|
+
Tail the activity log to confirm the gates fired:
|
|
232
230
|
|
|
233
231
|
```bash
|
|
234
|
-
tail -f ory-
|
|
232
|
+
tail -f ory-agent-debug.log | jq .
|
|
235
233
|
```
|
|
236
234
|
|
|
237
235
|
You should see:
|
|
238
236
|
|
|
239
|
-
- exactly one `user.auth`
|
|
237
|
+
- exactly one `user.auth` activity event (the worker's first Activity triggered
|
|
240
238
|
`bootstrap()`),
|
|
241
|
-
- exactly one `agent.auth`
|
|
242
|
-
- one `tool.invoke` (allow) or `tool.block` (deny)
|
|
239
|
+
- exactly one `agent.auth` activity event,
|
|
240
|
+
- one `tool.invoke` (allow) or `tool.block` (deny) event **per Activity
|
|
243
241
|
execution**.
|
|
244
242
|
|
|
245
|
-
The Workflow itself produces no Ory
|
|
243
|
+
The Workflow itself produces no Ory activity — only its Activities do.
|
|
246
244
|
|
|
247
245
|
## Step 6 — Promotion from observe to enforce
|
|
248
246
|
|
|
249
247
|
The worker starts in `observe` mode by default: denies pass through but each is
|
|
250
|
-
recorded as a `permission.observe_deny`
|
|
251
|
-
the deny set is what they expect,
|
|
248
|
+
recorded as a `permission.observe_deny` activity event. Once the user has confirmed
|
|
249
|
+
the deny set is what they expect, an admin promotes the posture to `enforce` in
|
|
250
|
+
the Ory Console (Agent Security). It is a permission on the project, read on
|
|
251
|
+
every session, so the worker picks it up on its next run with no redeploy.
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
On a fresh Ory project, run the permissions bootstrap once before flipping the
|
|
258
|
-
switch so the `use` tuples for each Activity name (`send_email`, …) exist —
|
|
259
|
-
see {{REF_PERMISSIONS_ONBOARDING}}.
|
|
253
|
+
On a hosted Ory project, grant `use` on each Activity name (`send_email`, …) in
|
|
254
|
+
the Ory Console (Agent Security) before promoting the posture there — otherwise
|
|
255
|
+
enforcement blocks every Activity. See {{REF_PERMISSIONS_ONBOARDING}}.
|
|
260
256
|
|
|
261
|
-
To exercise the deny path locally,
|
|
262
|
-
|
|
263
|
-
|
|
257
|
+
To exercise the deny path locally, kick the Workflow with an Activity name the
|
|
258
|
+
local stack never granted, and watch it fail with the `Ory denied use of …`
|
|
259
|
+
error in the Temporal Web UI.
|
|
264
260
|
|
|
265
261
|
## Step 7 — Beyond the dev server
|
|
266
262
|
|
|
267
263
|
This skill stops at the local dev server. For production:
|
|
268
264
|
|
|
269
|
-
- Pin a static agent identity with `
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
-
|
|
273
|
-
|
|
265
|
+
- Pin a static agent identity with `ORY_AGENT_CLIENT_ID +
|
|
266
|
+
ORY_AGENT_CLIENT_SECRET` (client_credentials) so the worker doesn't
|
|
267
|
+
re-register on every cold start.
|
|
268
|
+
- Set retention and access controls for the worker's unified activity log.
|
|
269
|
+
Ory Agent Security owns service telemetry; the worker does not export traces.
|
|
274
270
|
- Use Temporal Cloud or a self-hosted Temporal cluster instead of
|
|
275
271
|
`temporal server start-dev`; the worker code does not change.
|
|
276
272
|
|
|
@@ -1,32 +1,57 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ory-permissions-onboarding
|
|
3
|
-
description: Onboard a fresh install onto Ory Permissions for AI agent tool calls. Use when the user has just installed the Ory plugin and wants
|
|
3
|
+
description: Onboard a fresh install onto Ory Permissions for AI agent tool calls. Use when the user has just installed the Ory plugin and wants per-tool authorization enforced without first getting blocked by missing permissions. Covers connecting the plugin, reading coverage in observe mode, and what has to happen in the Ory Console (grants, blocks, enforce posture).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Onboard onto Ory Permissions for Agent Tool Calls
|
|
7
7
|
|
|
8
8
|
You are helping a user move a freshly-installed Ory agent plugin from
|
|
9
|
-
"permissions are
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
"disconnected" to "permissions are enforcing", without the common
|
|
10
|
+
first-run failure mode of getting every tool call blocked because the
|
|
11
|
+
project has no grants yet.
|
|
12
|
+
|
|
13
|
+
**The plugin only reads permissions. It never writes them.** Everything
|
|
14
|
+
that provisions the project — the permission model, per-tool grants,
|
|
15
|
+
explicit blocks, and the observe/enforce posture — is done in the **Ory
|
|
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.
|
|
20
|
+
|
|
21
|
+
Two things govern behavior:
|
|
22
|
+
|
|
23
|
+
- **Whether Agent Security is connected** — it runs when a project URL,
|
|
24
|
+
canonical Agent Security origin, and public OAuth2 client id resolve. Existing
|
|
25
|
+
configurations fall back to the project URL when the canonical origin is
|
|
26
|
+
unset. Not connected means no login and no permission checks, with
|
|
27
|
+
tool calls recorded locally. Skills, commands, the local dev stack, and
|
|
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.
|
|
34
|
+
|
|
35
|
+
The journey: **install → connect → observe → grant in the Console →
|
|
36
|
+
enforce in the Console.**
|
|
37
|
+
|
|
38
|
+
## Step 1: Connect the plugin to the project
|
|
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**:
|
|
13
43
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
auth, no permission checks). This is for users who want only audit
|
|
18
|
-
logging of tool invocations. Not what onboarding is about.
|
|
19
|
-
- **`permissionMode`** — the dial this skill is about. `observe` (the
|
|
20
|
-
default) runs every permission check, logs denials, but allows the
|
|
21
|
-
tool to proceed. `enforce` blocks on deny. Mode is read from
|
|
22
|
-
`ORY_PERMISSION_MODE` first, then the shared config file, then
|
|
23
|
-
defaults to `observe`.
|
|
24
|
-
|
|
25
|
-
The journey: **install → observe → bootstrap → enforce.**
|
|
44
|
+
```sh
|
|
45
|
+
{{NPX}} configure --project-url <URL> --agent-security-url <URL>
|
|
46
|
+
```
|
|
26
47
|
|
|
27
|
-
|
|
48
|
+
- **project URL** — the project's SDK URL (`https://<slug>.projects.oryapis.com`).
|
|
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.
|
|
28
53
|
|
|
29
|
-
|
|
54
|
+
Then confirm what the plugin resolved:
|
|
30
55
|
|
|
31
56
|
```sh
|
|
32
57
|
{{NPX}} status
|
|
@@ -35,133 +60,135 @@ Verify the plugin is wired up and pointing at the right Ory project:
|
|
|
35
60
|
What you want to see:
|
|
36
61
|
|
|
37
62
|
- **Project URL**: a real Ory URL or your local dev gateway (not "NOT SET").
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
40
|
-
|
|
41
|
-
If any of those are wrong, fix them before continuing:
|
|
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.
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`--oauth2-client-id` is the public OAuth2 client registered in your Ory project (required when `ORY_USER_LOGIN=true`; see the *Register the user OAuth2 client* section of the plugin README).
|
|
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.
|
|
48
70
|
|
|
49
71
|
## Step 2: Look at the current permission posture
|
|
50
72
|
|
|
51
73
|
```sh
|
|
52
|
-
{{NPX}} permissions
|
|
74
|
+
{{NPX}} permissions
|
|
53
75
|
```
|
|
54
76
|
|
|
55
77
|
This prints:
|
|
56
78
|
|
|
57
|
-
- The
|
|
58
|
-
|
|
59
|
-
- The **subject**
|
|
79
|
+
- The live **permission mode** (`observe` or `enforce`) and whether it
|
|
80
|
+
came from the project, a cached value, or the default.
|
|
81
|
+
- The **subject** — the user identity permissions are checked against.
|
|
60
82
|
- For each tool in this harness's built-in catalog, **allowed / denied /
|
|
61
|
-
errored
|
|
62
|
-
|
|
83
|
+
blocked / errored**, from a real check against the project right now.
|
|
84
|
+
- A one-line coverage summary for decomposed shell command words.
|
|
63
85
|
|
|
64
|
-
On a
|
|
65
|
-
**denied** —
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
blocked once enforce mode is turned on.
|
|
86
|
+
On a freshly-connected project you will usually see every tool reported
|
|
87
|
+
as **denied** — no grants exist for this user yet. In observe mode that
|
|
88
|
+
blocks nobody: tool calls run through, and you are seeing what *would*
|
|
89
|
+
be blocked under enforce.
|
|
69
90
|
|
|
70
|
-
If
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
non-blocking.
|
|
91
|
+
If status prints `Mode: enforce` while tools are denied, tool calls
|
|
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.
|
|
74
94
|
|
|
75
|
-
## Step 3:
|
|
95
|
+
## Step 3: Run a real session in observe mode
|
|
76
96
|
|
|
77
|
-
|
|
97
|
+
Observe mode is the discovery phase. Use the harness normally, then look
|
|
98
|
+
at what was recorded:
|
|
78
99
|
|
|
79
100
|
```sh
|
|
80
|
-
{{NPX}}
|
|
101
|
+
{{NPX}} status # summary + recent activity
|
|
102
|
+
{{NPX}} watch # live event, decision, and error view
|
|
81
103
|
```
|
|
82
104
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
in the harness's known catalog. MCP server tools are *not* covered —
|
|
89
|
-
they are discovered dynamically per session, so they need tuples added
|
|
90
|
-
out-of-band as they come into scope.
|
|
91
|
-
|
|
92
|
-
### When bootstrap can't write tuples
|
|
105
|
+
Launch the harness with `ORY_AGENT_DEBUG=true` to include verbose diagnostics in
|
|
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.
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
## Step 4: Grant the tools in the Ory Console
|
|
95
112
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
no `ORY_USER_SUBJECT_ID`), the command refuses. Run the harness once
|
|
99
|
-
with `ORY_USER_LOGIN=true` to cache a user token, or set
|
|
100
|
-
`ORY_USER_SUBJECT_ID=<id>` to target a known subject.
|
|
101
|
-
2. **Credentials lack write scope on the permission namespace.** The
|
|
102
|
-
command prints the full tuple list so you can apply them manually
|
|
103
|
-
via `keto relation-tuples create`, the Ory Console's *Add
|
|
104
|
-
relationship* dialog, or `curl` against Keto's write API. Hand the
|
|
105
|
-
list to whoever holds write credentials.
|
|
106
|
-
|
|
107
|
-
### Add tuples for non-default tools
|
|
108
|
-
|
|
109
|
-
If the harness has tools beyond the built-in catalog (MCP servers,
|
|
110
|
-
custom commands), grant them by writing tuples directly. Use the same
|
|
111
|
-
shape:
|
|
113
|
+
In the Ory Console → **Agent Security**, grant the subject `use` on the
|
|
114
|
+
tools it needs. The grant shape the runtime checks is:
|
|
112
115
|
|
|
113
116
|
```
|
|
114
|
-
namespace:
|
|
115
|
-
object: <tool name>
|
|
117
|
+
namespace: AgentTool (or whatever ORY_PERMISSION_NAMESPACE is set to)
|
|
118
|
+
object: <tool name> (e.g. Read, Bash, WebFetch)
|
|
116
119
|
relation: use
|
|
117
|
-
subject:
|
|
120
|
+
subject: User:<id> (a SubjectSet — namespace `User`, object the user id)
|
|
118
121
|
```
|
|
119
122
|
|
|
120
|
-
|
|
123
|
+
Notes worth passing on to the user:
|
|
121
124
|
|
|
122
|
-
|
|
125
|
+
- The subject is a **SubjectSet** (`User:<id>`), which is what the
|
|
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.
|
|
123
136
|
|
|
124
|
-
|
|
125
|
-
`allowed`, flip the dial:
|
|
137
|
+
Re-run `{{NPX}} permissions` afterwards to confirm coverage.
|
|
126
138
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
139
|
+
## Step 5: Promote to enforce in the Console
|
|
140
|
+
|
|
141
|
+
Once the tools the user actually needs report `allowed`, an admin flips
|
|
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.
|
|
130
145
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
can always be flipped back:
|
|
146
|
+
Every session reads the live mode, so the change takes effect without
|
|
147
|
+
reinstalling or reconfiguring anything. Confirm it landed:
|
|
134
148
|
|
|
135
149
|
```sh
|
|
136
|
-
{{NPX}} permissions
|
|
150
|
+
{{NPX}} permissions
|
|
137
151
|
```
|
|
138
152
|
|
|
139
|
-
|
|
140
|
-
runs that want enforce regardless of what's persisted, or for one-off
|
|
141
|
-
debugging sessions where you want observe without rewriting config.
|
|
142
|
-
|
|
143
|
-
## Step 5: Verify a real session
|
|
153
|
+
## Step 6: Verify a real session under enforce
|
|
144
154
|
|
|
145
155
|
Start a normal agent session and confirm:
|
|
146
156
|
|
|
147
157
|
- **Allowed tools** invoke without complaint.
|
|
148
|
-
- **Denied tools**
|
|
149
|
-
|
|
150
|
-
- The
|
|
151
|
-
`tool.block`
|
|
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.
|
|
162
|
+
|
|
163
|
+
If a tool is unexpectedly blocked, run `{{NPX}} permissions` to
|
|
164
|
+
see whether it is `denied` (no grant) or `blocked` (an explicit
|
|
165
|
+
deny-override), then fix it in the Console and re-test.
|
|
166
|
+
|
|
167
|
+
## Explicit blocks (deny-override)
|
|
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.
|
|
152
174
|
|
|
153
|
-
|
|
154
|
-
|
|
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.
|
|
155
179
|
|
|
156
|
-
## Reference
|
|
180
|
+
## Reference
|
|
157
181
|
|
|
158
182
|
| Command | Effect |
|
|
159
183
|
|---|---|
|
|
160
|
-
| `{{NPX}}
|
|
161
|
-
| `{{NPX}}
|
|
162
|
-
| `{{NPX}} permissions
|
|
163
|
-
| `{{NPX}}
|
|
164
|
-
|
|
184
|
+
| `{{NPX}} configure --project-url <URL> --agent-security-url <URL>` | Connect the plugin to the canonical Agent Security broker. |
|
|
185
|
+
| `{{NPX}} configure --disconnect` | Turn sign-in and permission checks back off. Skills, commands, the local stack, and activity logging are unaffected. |
|
|
186
|
+
| `{{NPX}} permissions` | Print the live mode + per-tool allowed/denied/blocked breakdown. Read-only. |
|
|
187
|
+
| `{{NPX}} status` | Configuration, identities, permission coverage, recent activity. |
|
|
188
|
+
|
|
189
|
+
Done in the **Ory Console** (Agent Security), not from the CLI: applying
|
|
190
|
+
the permission model, granting `use` on tools, writing explicit blocks,
|
|
191
|
+
and setting the observe/enforce posture.
|
|
165
192
|
|
|
166
193
|
For deeper background on the authentication side of the flow (which
|
|
167
194
|
identity is the subject, how the user gate resolves it), see
|