@ory/amp 0.13.8 → 0.14.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 +10 -7
- package/dist/cli/main.js +7 -0
- package/dist/plugin.d.ts +5 -5
- package/dist/plugin.js +14 -127
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,12 +21,14 @@ Run one command. It installs the plugin and walks you through connecting:
|
|
|
21
21
|
npx -y -p @ory/amp ory-amp install
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
It opens a guided setup **in your browser** where you pick how to connect — the default takes just a click:
|
|
25
25
|
|
|
26
26
|
- **Ory Network** *(default)* — sign in, or create a free account, in your browser. The project, keys, permissions, and login are all set up for you. Nothing to configure by hand.
|
|
27
27
|
- **Local** — run a complete Ory on your laptop with Docker. No account, no signup, no keys. Great for trying it out.
|
|
28
28
|
- **Audit-only** — skip Ory entirely and just log what Amp does.
|
|
29
29
|
|
|
30
|
+
> No browser available (CI, SSH, headless)? The same walkthrough runs right in your terminal instead — or force it with `--no-web`.
|
|
31
|
+
|
|
30
32
|
That's it. Confirm everything landed with:
|
|
31
33
|
|
|
32
34
|
```bash
|
|
@@ -52,6 +54,7 @@ If Ory is ever slow or unreachable, the plugin gets out of the way and lets Amp
|
|
|
52
54
|
Everything the plugin does is observable out of the box — no configuration required:
|
|
53
55
|
|
|
54
56
|
- **Status at a glance.** `npx -y -p @ory/amp ory-amp status` shows what's configured, who's signed in, how many built-in tools your permissions cover, and the most recent tool-call activity.
|
|
57
|
+
- **Live dashboard.** `npx -y -p @ory/amp ory-amp dashboard` opens the same picture in your browser — configuration, identities, permission coverage, Ory service health, and the latest tool-call activity, all refreshing live. From there you can flip **enforcement** on or off, toggle **user login**, and use **Change stack** to reconnect to a different Ory — no CLI required.
|
|
55
58
|
- **Live traces.** Every tool call is recorded as an OpenTelemetry-style span. Watch them stream as the agent works:
|
|
56
59
|
|
|
57
60
|
```bash
|
|
@@ -69,7 +72,7 @@ When the watch-mode logs look right, turn on blocking with one command (setup al
|
|
|
69
72
|
npx -y -p @ory/amp ory-amp permissions enforce
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
Now a denied tool is actually blocked and Amp shows why. Go back to watch mode anytime with `permissions observe`. Use `permissions status` to see what's covered and `permissions bootstrap` to (re-)grant the built-in tools.
|
|
75
|
+
Now a denied tool is actually blocked and Amp shows why. Go back to watch mode anytime with `permissions observe`. Prefer clicking? The dashboard has the same **Enforce** switch — flip it on, or back to watch mode, without touching the CLI. Use `permissions status` to see what's covered and `permissions bootstrap` to (re-)grant the built-in tools.
|
|
73
76
|
|
|
74
77
|
<details>
|
|
75
78
|
<summary>How the plugin plugs into Amp</summary>
|
|
@@ -100,22 +103,22 @@ The guided setup covers most people. For scripted or CI setups, or to point at a
|
|
|
100
103
|
```bash
|
|
101
104
|
npx -y -p @ory/amp ory-amp configure \
|
|
102
105
|
--project-url https://<slug>.projects.oryapis.com \
|
|
103
|
-
--oauth2-client-id <sign-in client id>
|
|
104
|
-
--user-login
|
|
106
|
+
--oauth2-client-id <sign-in client id>
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
Amp's own identity registers itself automatically on first run — nothing to create. The `--oauth2-client-id` is the one piece browser sign-in needs (the public client registered with the four loopback callback URLs `http://127.0.0.1:47823..47826/callback`); the guided setup makes it for you. Pass `--api-key ory_pat_...` only to override Amp's auto-created identity with a static token. For logging-only with no checks, use `--audit-only`. The matching env vars are `ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`,
|
|
109
|
+
Amp's own identity registers itself automatically on first run — nothing to create. The `--oauth2-client-id` is the one piece browser sign-in needs (the public client registered with the four loopback callback URLs `http://127.0.0.1:47823..47826/callback`); the guided setup makes it for you. Pass `--api-key ory_pat_...` only to override Amp's auto-created identity with a static token. For logging-only with no checks, use `--audit-only`. The interactive user login runs every session (always on, non-blocking) and only needs `ORY_OAUTH2_CLIENT_ID` to complete the browser flow. The matching env vars are `ORY_PROJECT_URL`, `ORY_OAUTH2_CLIENT_ID`, and `ORY_AGENT_API_KEY`.
|
|
108
110
|
|
|
109
111
|
With nothing configured, the plugin still loads and runs in **pass-through mode**: skills and logging work, but no checks run and nothing is blocked. Perfectly fine if you only want the app-building features.
|
|
110
112
|
|
|
111
113
|
## Commands
|
|
112
114
|
|
|
113
115
|
```
|
|
114
|
-
ory-amp install | uninstall Install/remove; --reconfigure re-runs setup, --no-configure skips it
|
|
116
|
+
ory-amp install | uninstall Install/remove; --reconfigure re-runs setup, --no-web forces the terminal wizard, --no-configure skips it
|
|
115
117
|
ory-amp status Show configuration, identities, permission coverage, and recent activity
|
|
118
|
+
ory-amp dashboard Open the live browser dashboard (status + service health + Change stack)
|
|
116
119
|
ory-amp watch Tail the live trace stream (OTel spans)
|
|
117
120
|
ory-amp permissions <cmd> status | bootstrap | observe (watch) | enforce (block)
|
|
118
|
-
ory-amp configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --
|
|
121
|
+
ory-amp configure <flags> Point at a project by hand (--project-url, --oauth2-client-id, --audit-only)
|
|
119
122
|
ory-amp agent <status|unregister> Manage Amp's own auto-created identity
|
|
120
123
|
```
|
|
121
124
|
|
package/dist/cli/main.js
CHANGED
|
@@ -100,6 +100,12 @@ function main() {
|
|
|
100
100
|
case "watch":
|
|
101
101
|
(0, argus_1.runWatchCommand)("amp", args);
|
|
102
102
|
break;
|
|
103
|
+
case "dashboard":
|
|
104
|
+
(0, argus_1.runDashboardCommand)("ory-amp", "amp", args).then((code) => process.exit(code), (err) => {
|
|
105
|
+
console.error(err.message ?? err);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
break;
|
|
103
109
|
case "version":
|
|
104
110
|
case "--version":
|
|
105
111
|
case "-v":
|
|
@@ -183,6 +189,7 @@ Commands:
|
|
|
183
189
|
(status, bootstrap, observe, enforce)
|
|
184
190
|
setup [--project-dir <path>] Write config directly (fallback)
|
|
185
191
|
status [--project-dir <path>] Show plugin configuration and status
|
|
192
|
+
dashboard Open the Ory Agent dashboard (system health + configuration)
|
|
186
193
|
watch [trace-file] Tail the trace stream (OTel spans) live
|
|
187
194
|
version Show version and the ory-agent-plugins build commit
|
|
188
195
|
local <cmd> Manage local Ory dev environment
|
package/dist/plugin.d.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* Each handler receives the event payload and a `PluginEventContext`. We
|
|
7
7
|
* subscribe to:
|
|
8
8
|
*
|
|
9
|
-
* session.start → run the user gate
|
|
10
|
-
*
|
|
9
|
+
* session.start → run the user gate, the agent gate, and write the
|
|
10
|
+
* user→agent delegation tuple.
|
|
11
11
|
* tool.result → record a `tool.complete` audit span.
|
|
12
12
|
*
|
|
13
13
|
* The BLOCKING permission decision deliberately does NOT live here. Amp's
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
* observational. The delegate runs as its own process and decides by exit
|
|
19
19
|
* code; this module only authenticates and traces.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* The user login runs every session and never blocks — it emits the
|
|
22
|
+
* user.auth audit span, refreshes tokens, and may prompt when interactive.
|
|
23
|
+
* Enforcement is governed solely by permissionMode at tool-call time.
|
|
24
24
|
*/
|
|
25
25
|
import { OryAgentClient, ensureUserAuthenticated, ensureAgentIdentity } from "@ory/argus";
|
|
26
26
|
import type { AmpPlugin } from "./types.js";
|
package/dist/plugin.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Each handler receives the event payload and a `PluginEventContext`. We
|
|
8
8
|
* subscribe to:
|
|
9
9
|
*
|
|
10
|
-
* session.start → run the user gate
|
|
11
|
-
*
|
|
10
|
+
* session.start → run the user gate, the agent gate, and write the
|
|
11
|
+
* user→agent delegation tuple.
|
|
12
12
|
* tool.result → record a `tool.complete` audit span.
|
|
13
13
|
*
|
|
14
14
|
* The BLOCKING permission decision deliberately does NOT live here. Amp's
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* observational. The delegate runs as its own process and decides by exit
|
|
20
20
|
* code; this module only authenticates and traces.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* The user login runs every session and never blocks — it emits the
|
|
23
|
+
* user.auth audit span, refreshes tokens, and may prompt when interactive.
|
|
24
|
+
* Enforcement is governed solely by permissionMode at tool-call time.
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
27
|
exports.createOryPlugin = createOryPlugin;
|
|
@@ -55,95 +55,26 @@ function createSessionStartHandler(client, deps) {
|
|
|
55
55
|
client.tracer.record("session.start", "ok", {
|
|
56
56
|
attributes: sessionId ? { sessionId } : {},
|
|
57
57
|
});
|
|
58
|
-
// Run the user login.
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
// logging.
|
|
58
|
+
// Run the user login. It runs every session and never blocks — the
|
|
59
|
+
// flow emits the user.auth audit span, refreshes tokens, and may
|
|
60
|
+
// prompt when interactive, but never prevents the session from
|
|
61
|
+
// starting. Enforcement is governed solely by permissionMode at
|
|
62
|
+
// tool-call time.
|
|
64
63
|
const userGate = deps.userLogin ?? argus_1.ensureUserAuthenticated;
|
|
65
|
-
|
|
64
|
+
await userGate(client, {
|
|
66
65
|
binName: "ory-amp",
|
|
67
66
|
harness: "amp",
|
|
68
|
-
allowBlock: false,
|
|
69
67
|
});
|
|
70
68
|
// Resolve the agent identity (machine credentials). Never blocks;
|
|
71
69
|
// attaches the agent's bearer token to outgoing Ory API calls.
|
|
72
70
|
const agentGate = deps.agentGate ?? argus_1.ensureAgentIdentity;
|
|
73
71
|
await agentGate(client, { projectUrl: (0, argus_1.resolveConfig)().projectUrl, harness: "amp" });
|
|
74
72
|
// Once both principals are populated, write the user→agent delegation
|
|
75
|
-
// tuple.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const resolved = (0, argus_1.resolveConfig)();
|
|
81
|
-
if (resolved.auditOnly) {
|
|
82
|
-
client.logger.info("config.audit_only", {
|
|
83
|
-
message: "Audit-only mode enabled. Auth and permission checks are disabled.",
|
|
84
|
-
});
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (!resolved.projectUrl) {
|
|
88
|
-
client.logger.warn("config.not_configured", {
|
|
89
|
-
message: "Ory plugin is not configured. Auth and permission checks are disabled. " +
|
|
90
|
-
"Run 'npx ory-amp configure' to connect to an Ory project.",
|
|
91
|
-
});
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const sessionToken = process.env.ORY_SESSION_TOKEN;
|
|
95
|
-
const oauth2Token = process.env.ORY_OAUTH2_TOKEN;
|
|
96
|
-
if (sessionToken) {
|
|
97
|
-
await verifySessionToken(client, sessionToken);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (oauth2Token) {
|
|
101
|
-
await verifyOAuth2Token(client, oauth2Token);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
client.logger.warn("session.no_credentials", {
|
|
105
|
-
message: "Neither ORY_SESSION_TOKEN nor ORY_OAUTH2_TOKEN is set. " +
|
|
106
|
-
"Skipping authentication.",
|
|
107
|
-
});
|
|
73
|
+
// tuple. Written at most once per install + fail-open: audit-trail data
|
|
74
|
+
// only.
|
|
75
|
+
await (0, argus_1.writeUserDelegatesAgent)(client);
|
|
108
76
|
};
|
|
109
77
|
}
|
|
110
|
-
async function verifySessionToken(client, token) {
|
|
111
|
-
try {
|
|
112
|
-
const session = await client.verifySession(token);
|
|
113
|
-
if (!session.active) {
|
|
114
|
-
client.logger.warn("session.inactive", {
|
|
115
|
-
message: "Ory session is not active. Re-authenticate to enable auth checks.",
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
client.logger.warn("session.verify_failed", {
|
|
121
|
-
code: isOryError(err) ? err.code : "unknown",
|
|
122
|
-
message: err instanceof Error ? err.message : String(err),
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
async function verifyOAuth2Token(client, token) {
|
|
127
|
-
try {
|
|
128
|
-
const tokenInfo = await client.introspectToken(token);
|
|
129
|
-
if (!tokenInfo.active) {
|
|
130
|
-
client.logger.warn("oauth2.token_inactive", {
|
|
131
|
-
message: "Ory OAuth2 token is not active. Obtain a new token to enable auth checks.",
|
|
132
|
-
});
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
client.logger.info("oauth2.session_authenticated", {
|
|
136
|
-
clientId: tokenInfo.clientId,
|
|
137
|
-
subject: tokenInfo.subject,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
catch (err) {
|
|
141
|
-
client.logger.warn("oauth2.introspect_failed", {
|
|
142
|
-
code: isOryError(err) ? err.code : "unknown",
|
|
143
|
-
message: err instanceof Error ? err.message : String(err),
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
78
|
// ─── tool.result ───────────────────────────────────────────────────
|
|
148
79
|
function createToolResultHandler(client) {
|
|
149
80
|
return async (event, _ctx) => {
|
|
@@ -171,47 +102,3 @@ function createToolResultHandler(client) {
|
|
|
171
102
|
});
|
|
172
103
|
};
|
|
173
104
|
}
|
|
174
|
-
// ─── Helpers ───────────────────────────────────────────────────────
|
|
175
|
-
function resolveNamespace() {
|
|
176
|
-
return process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTools";
|
|
177
|
-
}
|
|
178
|
-
function isOryError(err) {
|
|
179
|
-
return (typeof err === "object" &&
|
|
180
|
-
err !== null &&
|
|
181
|
-
"code" in err &&
|
|
182
|
-
"message" in err);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Write the user→agent delegation tuple. Idempotent and fail-open:
|
|
186
|
-
* requires both principal subjects to be populated; any error (including
|
|
187
|
-
* an unconfigured projectUrl, which manifests as a network_error) is
|
|
188
|
-
* logged and swallowed. Purely audit-trail data — does not affect
|
|
189
|
-
* enforcement.
|
|
190
|
-
*/
|
|
191
|
-
async function recordUserDelegatesAgent(client) {
|
|
192
|
-
const user = client.userPrincipal.subject;
|
|
193
|
-
const agent = client.agentPrincipal.subject;
|
|
194
|
-
if (!user || !agent) {
|
|
195
|
-
client.logger.debug("delegation.skip", {
|
|
196
|
-
reason: "missing principal",
|
|
197
|
-
hasUser: !!user,
|
|
198
|
-
hasAgent: !!agent,
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
await client.createRelationship({
|
|
204
|
-
namespace: resolveNamespace(),
|
|
205
|
-
object: `agent:${agent}`,
|
|
206
|
-
relation: "delegate",
|
|
207
|
-
subjectId: `user:${user}`,
|
|
208
|
-
}, { spanAttributes: { delegation: "user-to-agent" } });
|
|
209
|
-
}
|
|
210
|
-
catch (err) {
|
|
211
|
-
const oryErr = err;
|
|
212
|
-
client.logger.warn("delegation.user_to_agent.failed", {
|
|
213
|
-
code: oryErr.code,
|
|
214
|
-
message: oryErr.message,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ory/amp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Ory plugin for Amp (Sourcegraph's coding agent): a permission delegate that authorizes every tool call plus an in-process plugin for session auth and audit tracing",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://ory.com",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
],
|
|
69
69
|
"dependencies": {
|
|
70
70
|
"reo-census": "^1.2.8",
|
|
71
|
-
"@ory/argus": "0.
|
|
71
|
+
"@ory/argus": "0.14.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"typescript": "^6.0.2",
|