@ory/argus 0.14.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -46
- package/assets/commands/temporal-up.md +1 -1
- package/assets/skills/auth-setup/SKILL.md +1 -1
- package/assets/skills/local-dev/SKILL.md +17 -7
- package/assets/skills/ory-build-agent/SKILL.md +39 -91
- package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
- package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
- package/assets/skills/permissions-onboarding/SKILL.md +131 -104
- package/dist/adapters.d.ts +88 -32
- package/dist/adapters.js +443 -164
- package/dist/agent-auth.d.ts +226 -67
- package/dist/agent-auth.js +951 -205
- package/dist/auth-store.d.ts +37 -2
- package/dist/auth-store.js +37 -3
- package/dist/auth.d.ts +33 -4
- package/dist/auth.js +163 -20
- package/dist/bash-parser.d.ts +98 -0
- package/dist/bash-parser.js +396 -0
- package/dist/branding.d.ts +77 -16
- package/dist/branding.js +93 -23
- package/dist/build-info.json +4 -4
- package/dist/cli-invocation.d.ts +1 -1
- package/dist/cli-invocation.js +2 -1
- package/dist/cli.d.ts +20 -29
- package/dist/cli.js +271 -239
- package/dist/client.d.ts +175 -138
- package/dist/client.js +672 -391
- package/dist/config.d.ts +217 -54
- package/dist/config.js +461 -42
- package/dist/context.d.ts +10 -0
- package/dist/context.js +21 -0
- package/dist/contract-suite.d.ts +3 -5
- package/dist/contract-suite.js +75 -47
- package/dist/denial.d.ts +36 -3
- package/dist/denial.js +79 -10
- package/dist/event-reporter.d.ts +77 -0
- package/dist/event-reporter.js +776 -0
- package/dist/external-registrations-main.d.ts +10 -0
- package/dist/external-registrations-main.js +38 -0
- package/dist/external-registrations.d.ts +79 -0
- package/dist/external-registrations.js +188 -0
- package/dist/help-cli.d.ts +39 -0
- package/dist/help-cli.js +55 -0
- package/dist/hook-timeout.d.ts +64 -0
- package/dist/hook-timeout.js +88 -0
- package/dist/index.d.ts +28 -23
- package/dist/index.js +173 -58
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +38 -6
- package/dist/local/cli.js +11 -6
- package/dist/local/configs.d.ts +74 -18
- package/dist/local/configs.js +291 -84
- package/dist/local/health.js +7 -7
- package/dist/local/index.d.ts +2 -2
- package/dist/local/index.js +24 -10
- package/dist/local/manager.d.ts +20 -1
- package/dist/local/manager.js +159 -36
- package/dist/local/ports.d.ts +158 -0
- package/dist/local/ports.js +443 -0
- package/dist/local/seed.d.ts +13 -5
- package/dist/local/seed.js +62 -38
- package/dist/logger.d.ts +54 -25
- package/dist/logger.js +329 -63
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +10 -5
- package/dist/mirror-bootstrap.d.ts +48 -0
- package/dist/mirror-bootstrap.js +254 -0
- package/dist/opl.d.ts +289 -0
- package/dist/opl.js +446 -0
- package/dist/permission-mode.d.ts +87 -0
- package/dist/permission-mode.js +307 -0
- package/dist/permissions-cli.d.ts +13 -49
- package/dist/permissions-cli.js +154 -348
- package/dist/permissions.d.ts +148 -38
- package/dist/permissions.js +591 -45
- package/dist/post-install.d.ts +33 -0
- package/dist/post-install.js +127 -0
- package/dist/read-credential.d.ts +65 -0
- package/dist/read-credential.js +86 -0
- package/dist/registry/cli.js +5 -2
- package/dist/registry/config.d.ts +0 -17
- package/dist/registry/config.js +0 -23
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +2 -2
- package/dist/registry/manager.d.ts +4 -21
- package/dist/registry/manager.js +21 -37
- package/dist/runtime-credential.d.ts +140 -0
- package/dist/runtime-credential.js +572 -0
- package/dist/runtime.d.ts +413 -0
- package/dist/runtime.js +825 -0
- package/dist/setup.d.ts +23 -47
- package/dist/setup.js +59 -116
- package/dist/skills.js +0 -7
- package/dist/status-cli.d.ts +27 -11
- package/dist/status-cli.js +121 -115
- package/dist/status-data.d.ts +116 -17
- package/dist/status-data.js +121 -38
- package/dist/subject.d.ts +126 -20
- package/dist/subject.js +215 -30
- package/dist/testing.d.ts +74 -38
- package/dist/testing.js +185 -68
- package/dist/tool-catalog.d.ts +53 -11
- package/dist/tool-catalog.js +164 -13
- package/dist/tool-metadata.d.ts +7 -6
- package/dist/tool-metadata.js +6 -5
- package/dist/types.d.ts +11 -1
- package/dist/uninstall.d.ts +71 -34
- package/dist/uninstall.js +217 -85
- package/dist/user-login.d.ts +9 -10
- package/dist/user-login.js +56 -75
- package/dist/watch-cli.d.ts +6 -0
- package/dist/watch-cli.js +217 -0
- package/package.json +4 -27
- package/assets/commands/dashboard.md +0 -34
- package/dist/dashboard-cli.d.ts +0 -8
- package/dist/dashboard-cli.js +0 -70
- package/dist/dev.d.ts +0 -103
- package/dist/dev.js +0 -583
- package/dist/interactive-setup.d.ts +0 -286
- package/dist/interactive-setup.js +0 -1734
- package/dist/local/jaeger-main.d.ts +0 -13
- package/dist/local/jaeger-main.js +0 -85
- package/dist/local/jaeger.d.ts +0 -50
- package/dist/local/jaeger.js +0 -162
- package/dist/otel/exporter.d.ts +0 -17
- package/dist/otel/exporter.js +0 -12
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js +0 -8
- package/dist/otel/otlp.d.ts +0 -103
- package/dist/otel/otlp.js +0 -385
- package/dist/project-api-key.d.ts +0 -69
- package/dist/project-api-key.js +0 -147
- package/dist/setup-actions.d.ts +0 -232
- package/dist/setup-actions.js +0 -507
- package/dist/tracer.d.ts +0 -190
- package/dist/tracer.js +0 -481
- package/dist/watch-sandbox.d.ts +0 -9
- package/dist/watch-sandbox.js +0 -81
- package/dist/web/api.d.ts +0 -33
- package/dist/web/api.js +0 -294
- package/dist/web/launch.d.ts +0 -11
- package/dist/web/launch.js +0 -96
- package/dist/web/server.d.ts +0 -20
- package/dist/web/server.js +0 -233
- package/dist/web/types.d.ts +0 -65
- package/dist/web/types.js +0 -2
- package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
- package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
- package/dist/webapp/favicon.ico +0 -0
- package/dist/webapp/index.html +0 -15
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runCredentialStoreCommand = exports.CredentialStoreCommandError = void 0;
|
|
37
|
+
exports.configureSystemCaTrustForDefaultFetch = configureSystemCaTrustForDefaultFetch;
|
|
38
|
+
exports.canonicalProjectUrl = canonicalProjectUrl;
|
|
39
|
+
exports.canonicalCredentialIdentity = canonicalCredentialIdentity;
|
|
40
|
+
exports.credentialAccount = credentialAccount;
|
|
41
|
+
exports.createOsTalosCredentialStore = createOsTalosCredentialStore;
|
|
42
|
+
exports.talosRuntimeCredential = talosRuntimeCredential;
|
|
43
|
+
exports.resolveRuntimeCredential = resolveRuntimeCredential;
|
|
44
|
+
exports.enrollTalosRuntimeCredential = enrollTalosRuntimeCredential;
|
|
45
|
+
exports.enrollTalosChildRuntimeCredential = enrollTalosChildRuntimeCredential;
|
|
46
|
+
exports.authenticatedRuntimeRequest = authenticatedRuntimeRequest;
|
|
47
|
+
const node_child_process_1 = require("node:child_process");
|
|
48
|
+
const node_crypto_1 = require("node:crypto");
|
|
49
|
+
const nodeTls = __importStar(require("node:tls"));
|
|
50
|
+
const CREDENTIAL_SERVICE = "com.ory.agent-security.runtime-credential";
|
|
51
|
+
const MACOS_CREDENTIAL_SCRIPT = String.raw `
|
|
52
|
+
ObjC.import('Foundation');
|
|
53
|
+
ObjC.import('Security');
|
|
54
|
+
ObjC.bindFunction('CFDataGetLength', ['long', ['void *']]);
|
|
55
|
+
ObjC.bindFunction('CFDataGetBytePtr', ['void *', ['void *']]);
|
|
56
|
+
|
|
57
|
+
const inputData = $.NSFileHandle.fileHandleWithStandardInput.readDataToEndOfFile;
|
|
58
|
+
const input = $.NSString.alloc.initWithDataEncoding(inputData, $.NSUTF8StringEncoding);
|
|
59
|
+
const request = JSON.parse(ObjC.unwrap(input));
|
|
60
|
+
// JXA exposes Security's CFString globals as pointer refs, so use their stable values.
|
|
61
|
+
const query = $.NSMutableDictionary.alloc.init;
|
|
62
|
+
query.setObjectForKey($('genp'), $('class'));
|
|
63
|
+
query.setObjectForKey($(request.service), $('svce'));
|
|
64
|
+
query.setObjectForKey($(request.account), $('acct'));
|
|
65
|
+
|
|
66
|
+
if (request.operation === 'load') {
|
|
67
|
+
query.setObjectForKey($(true), $('r_Data'));
|
|
68
|
+
query.setObjectForKey($('m_LimitOne'), $('m_Limit'));
|
|
69
|
+
const result = Ref();
|
|
70
|
+
const status = $.SecItemCopyMatching(query, result);
|
|
71
|
+
if (Number(status) !== -25300) {
|
|
72
|
+
if (Number(status) !== 0) throw new Error('Keychain read failed with status ' + status);
|
|
73
|
+
const length = $.CFDataGetLength(result[0]);
|
|
74
|
+
const bytes = $.CFDataGetBytePtr(result[0]);
|
|
75
|
+
const data = $.NSData.dataWithBytesLength(bytes, length);
|
|
76
|
+
$.NSFileHandle.fileHandleWithStandardOutput.writeData(data);
|
|
77
|
+
}
|
|
78
|
+
} else if (request.operation === 'save') {
|
|
79
|
+
const value = $(request.payload).dataUsingEncoding($.NSUTF8StringEncoding);
|
|
80
|
+
const attributes = $.NSMutableDictionary.alloc.init;
|
|
81
|
+
attributes.setObjectForKey(value, $('v_Data'));
|
|
82
|
+
let status = $.SecItemUpdate(query, attributes);
|
|
83
|
+
if (Number(status) === -25300) {
|
|
84
|
+
query.setObjectForKey(value, $('v_Data'));
|
|
85
|
+
status = $.SecItemAdd(query, null);
|
|
86
|
+
}
|
|
87
|
+
if (Number(status) !== 0) throw new Error('Keychain write failed with status ' + status);
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error('Unsupported credential operation');
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
const WINDOWS_CREDENTIAL_SCRIPT = String.raw `
|
|
93
|
+
Add-Type @'
|
|
94
|
+
using System;
|
|
95
|
+
using System.ComponentModel;
|
|
96
|
+
using System.Runtime.InteropServices;
|
|
97
|
+
using System.Text;
|
|
98
|
+
|
|
99
|
+
public static class OryCredentialManager {
|
|
100
|
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
101
|
+
private struct Credential {
|
|
102
|
+
public uint Flags;
|
|
103
|
+
public uint Type;
|
|
104
|
+
public string TargetName;
|
|
105
|
+
public string Comment;
|
|
106
|
+
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
|
|
107
|
+
public uint CredentialBlobSize;
|
|
108
|
+
public IntPtr CredentialBlob;
|
|
109
|
+
public uint Persist;
|
|
110
|
+
public uint AttributeCount;
|
|
111
|
+
public IntPtr Attributes;
|
|
112
|
+
public string TargetAlias;
|
|
113
|
+
public string UserName;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
[DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
117
|
+
private static extern bool CredRead(string target, uint type, uint flags, out IntPtr credential);
|
|
118
|
+
|
|
119
|
+
[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
120
|
+
private static extern bool CredWrite(ref Credential credential, uint flags);
|
|
121
|
+
|
|
122
|
+
[DllImport("Advapi32.dll", SetLastError = false)]
|
|
123
|
+
private static extern void CredFree(IntPtr credential);
|
|
124
|
+
|
|
125
|
+
public static string Read(string target) {
|
|
126
|
+
IntPtr pointer;
|
|
127
|
+
if (!CredRead(target, 1, 0, out pointer)) {
|
|
128
|
+
int error = Marshal.GetLastWin32Error();
|
|
129
|
+
if (error == 1168) return null;
|
|
130
|
+
throw new Win32Exception(error);
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
Credential credential = (Credential)Marshal.PtrToStructure(pointer, typeof(Credential));
|
|
134
|
+
int size = checked((int)credential.CredentialBlobSize);
|
|
135
|
+
byte[] bytes = new byte[size];
|
|
136
|
+
Marshal.Copy(credential.CredentialBlob, bytes, 0, bytes.Length);
|
|
137
|
+
return Encoding.UTF8.GetString(bytes);
|
|
138
|
+
} finally {
|
|
139
|
+
CredFree(pointer);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public static void Write(string target, string account, string value) {
|
|
144
|
+
byte[] bytes = Encoding.UTF8.GetBytes(value);
|
|
145
|
+
IntPtr blob = Marshal.AllocHGlobal(bytes.Length);
|
|
146
|
+
try {
|
|
147
|
+
Marshal.Copy(bytes, 0, blob, bytes.Length);
|
|
148
|
+
Credential credential = new Credential {
|
|
149
|
+
Type = 1,
|
|
150
|
+
TargetName = target,
|
|
151
|
+
CredentialBlobSize = (uint)bytes.Length,
|
|
152
|
+
CredentialBlob = blob,
|
|
153
|
+
Persist = 2,
|
|
154
|
+
UserName = account
|
|
155
|
+
};
|
|
156
|
+
if (!CredWrite(ref credential, 0)) {
|
|
157
|
+
throw new Win32Exception(Marshal.GetLastWin32Error());
|
|
158
|
+
}
|
|
159
|
+
} finally {
|
|
160
|
+
for (int i = 0; i < bytes.Length; i++) bytes[i] = 0;
|
|
161
|
+
Marshal.Copy(bytes, 0, blob, bytes.Length);
|
|
162
|
+
Marshal.FreeHGlobal(blob);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
'@
|
|
167
|
+
$request = [Console]::In.ReadToEnd() | ConvertFrom-Json
|
|
168
|
+
$target = $request.service + ':' + $request.account
|
|
169
|
+
if ($request.operation -eq 'load') {
|
|
170
|
+
$value = [OryCredentialManager]::Read($target)
|
|
171
|
+
if ($null -eq $value) { exit 44 }
|
|
172
|
+
[Console]::Out.Write($value)
|
|
173
|
+
} elseif ($request.operation -eq 'save') {
|
|
174
|
+
[OryCredentialManager]::Write($target, $request.account, $request.payload)
|
|
175
|
+
} else {
|
|
176
|
+
throw 'Unsupported credential operation'
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
const WINDOWS_POWERSHELL_ARGS = [
|
|
180
|
+
"-NoLogo",
|
|
181
|
+
"-NoProfile",
|
|
182
|
+
"-NonInteractive",
|
|
183
|
+
"-EncodedCommand",
|
|
184
|
+
Buffer.from(WINDOWS_CREDENTIAL_SCRIPT, "utf16le").toString("base64"),
|
|
185
|
+
];
|
|
186
|
+
const configuredTlsProviders = new WeakSet();
|
|
187
|
+
/**
|
|
188
|
+
* Make subsequent default Node TLS connections trust both Node's existing CA
|
|
189
|
+
* set and the operating system trust store. This is process-local and does not
|
|
190
|
+
* disable certificate verification.
|
|
191
|
+
*/
|
|
192
|
+
function configureSystemCaTrustForDefaultFetch(provider = nodeTls) {
|
|
193
|
+
const providerKey = provider;
|
|
194
|
+
if (configuredTlsProviders.has(providerKey))
|
|
195
|
+
return false;
|
|
196
|
+
if (!provider.getCACertificates || !provider.setDefaultCACertificates)
|
|
197
|
+
return false;
|
|
198
|
+
const certificates = new Set([
|
|
199
|
+
...provider.getCACertificates("default"),
|
|
200
|
+
...provider.getCACertificates("system"),
|
|
201
|
+
]);
|
|
202
|
+
provider.setDefaultCACertificates([...certificates]);
|
|
203
|
+
configuredTlsProviders.add(providerKey);
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
function safeFetchFailure(operation, error) {
|
|
207
|
+
const cause = error instanceof Error
|
|
208
|
+
? error.cause
|
|
209
|
+
: undefined;
|
|
210
|
+
const rawCode = cause && typeof cause === "object" && "code" in cause
|
|
211
|
+
? cause.code
|
|
212
|
+
: undefined;
|
|
213
|
+
const code = typeof rawCode === "string" && /^[A-Z0-9_]+$/.test(rawCode)
|
|
214
|
+
? rawCode
|
|
215
|
+
: undefined;
|
|
216
|
+
return new Error(`${operation} failed${code ? ` (${code})` : ""}`);
|
|
217
|
+
}
|
|
218
|
+
class CredentialStoreCommandError extends Error {
|
|
219
|
+
exitCode;
|
|
220
|
+
causeCode;
|
|
221
|
+
constructor(message, exitCode, causeCode) {
|
|
222
|
+
super(message);
|
|
223
|
+
this.exitCode = exitCode;
|
|
224
|
+
this.causeCode = causeCode;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.CredentialStoreCommandError = CredentialStoreCommandError;
|
|
228
|
+
const runCredentialStoreCommand = (command, args, options = {}) => new Promise((resolve, reject) => {
|
|
229
|
+
const child = (0, node_child_process_1.spawn)(command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
230
|
+
let stdout = "";
|
|
231
|
+
child.stdout.setEncoding("utf8");
|
|
232
|
+
child.stdout.on("data", (chunk) => { stdout += chunk; });
|
|
233
|
+
child.on("error", (error) => {
|
|
234
|
+
reject(new CredentialStoreCommandError(`Could not execute ${command}`, undefined, error.code));
|
|
235
|
+
});
|
|
236
|
+
child.on("close", (code) => {
|
|
237
|
+
if (code === 0)
|
|
238
|
+
resolve({ stdout });
|
|
239
|
+
else
|
|
240
|
+
reject(new CredentialStoreCommandError(`${command} exited unsuccessfully`, code ?? undefined));
|
|
241
|
+
});
|
|
242
|
+
child.stdin.end(options.input);
|
|
243
|
+
});
|
|
244
|
+
exports.runCredentialStoreCommand = runCredentialStoreCommand;
|
|
245
|
+
/** Normalize equivalent project URLs before deriving their credential-store key. */
|
|
246
|
+
function canonicalProjectUrl(projectUrl) {
|
|
247
|
+
const value = projectUrl.trim();
|
|
248
|
+
if (value.includes("\\"))
|
|
249
|
+
throw new Error("Project URL must not contain backslashes");
|
|
250
|
+
const authority = value.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]+)/i)?.[1];
|
|
251
|
+
if (authority && /[^\x00-\x7f]/.test(authority)) {
|
|
252
|
+
throw new Error("Project URL hostname must use ASCII notation");
|
|
253
|
+
}
|
|
254
|
+
const rawHost = authority?.startsWith("[") ? undefined : authority?.split("@").pop()?.split(":")[0];
|
|
255
|
+
if (rawHost && /^[0-9.]+$/.test(rawHost)) {
|
|
256
|
+
const octets = rawHost.split(".");
|
|
257
|
+
if (octets.length !== 4 ||
|
|
258
|
+
octets.some((octet) => !octet || String(Number(octet)) !== octet || Number(octet) > 255)) {
|
|
259
|
+
throw new Error("Project URL must use canonical IPv4 notation");
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const url = new URL(value);
|
|
263
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
264
|
+
throw new Error("Project URL must use HTTP or HTTPS");
|
|
265
|
+
}
|
|
266
|
+
if (url.username || url.password)
|
|
267
|
+
throw new Error("Project URL must not contain user information");
|
|
268
|
+
url.hash = "";
|
|
269
|
+
url.search = "";
|
|
270
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
271
|
+
return `${url.origin}${path}`;
|
|
272
|
+
}
|
|
273
|
+
function canonicalCredentialIdentity(identity) {
|
|
274
|
+
if (typeof identity === "string") {
|
|
275
|
+
return {
|
|
276
|
+
projectUrl: canonicalProjectUrl(identity),
|
|
277
|
+
harness: "unknown",
|
|
278
|
+
sessionId: "sessionless",
|
|
279
|
+
kind: "agent",
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const base = {
|
|
283
|
+
projectUrl: canonicalProjectUrl(identity.projectUrl),
|
|
284
|
+
harness: identity.harness.trim() || "unknown",
|
|
285
|
+
sessionId: identity.sessionId.trim() || "sessionless",
|
|
286
|
+
};
|
|
287
|
+
if (identity.kind === "agent")
|
|
288
|
+
return { ...base, kind: "agent" };
|
|
289
|
+
const subAgentType = identity.subAgentType.trim();
|
|
290
|
+
const perSpawnId = identity.perSpawnId.trim();
|
|
291
|
+
if (!subAgentType || !perSpawnId) {
|
|
292
|
+
throw new Error("A sub-agent credential requires type and spawn identifiers");
|
|
293
|
+
}
|
|
294
|
+
return { ...base, kind: "subagent", subAgentType, perSpawnId };
|
|
295
|
+
}
|
|
296
|
+
function credentialAccount(identity) {
|
|
297
|
+
return (0, node_crypto_1.createHash)("sha256")
|
|
298
|
+
.update(JSON.stringify(canonicalCredentialIdentity(identity)))
|
|
299
|
+
.digest("hex");
|
|
300
|
+
}
|
|
301
|
+
function parseStoredCredential(value, expectedIdentity) {
|
|
302
|
+
let parsed;
|
|
303
|
+
try {
|
|
304
|
+
parsed = JSON.parse(value);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
throw new Error("Stored Talos credential is not valid JSON");
|
|
308
|
+
}
|
|
309
|
+
if (!parsed || typeof parsed !== "object"
|
|
310
|
+
|| typeof parsed.credential !== "string"
|
|
311
|
+
|| !parsed.credential
|
|
312
|
+
|| typeof parsed.actorId !== "string"
|
|
313
|
+
|| !parsed.actorId) {
|
|
314
|
+
throw new Error("Stored Talos credential has an unsupported format");
|
|
315
|
+
}
|
|
316
|
+
if (parsed.version === 1) {
|
|
317
|
+
return parsed;
|
|
318
|
+
}
|
|
319
|
+
if (parsed.version !== 2
|
|
320
|
+
|| typeof parsed.identity !== "object") {
|
|
321
|
+
throw new Error("Stored Talos credential has an unsupported format");
|
|
322
|
+
}
|
|
323
|
+
const stored = parsed;
|
|
324
|
+
if (JSON.stringify(canonicalCredentialIdentity(stored.identity))
|
|
325
|
+
!== JSON.stringify(canonicalCredentialIdentity(expectedIdentity))) {
|
|
326
|
+
throw new Error("Stored Talos credential belongs to another runtime identity");
|
|
327
|
+
}
|
|
328
|
+
return stored;
|
|
329
|
+
}
|
|
330
|
+
/** OS-backed Talos store. Secrets are never placed in process arguments. */
|
|
331
|
+
function createOsTalosCredentialStore(options = {}) {
|
|
332
|
+
const platform = options.platform ?? process.platform;
|
|
333
|
+
const run = options.runCommand ?? exports.runCredentialStoreCommand;
|
|
334
|
+
if (platform !== "darwin" && platform !== "linux" && platform !== "win32") {
|
|
335
|
+
throw new Error(`No supported OS credential store is available on ${platform}`);
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
async load(identity) {
|
|
339
|
+
const account = credentialAccount(identity);
|
|
340
|
+
try {
|
|
341
|
+
const result = platform === "darwin"
|
|
342
|
+
? await run("osascript", ["-l", "JavaScript", "-e", MACOS_CREDENTIAL_SCRIPT], {
|
|
343
|
+
input: JSON.stringify({
|
|
344
|
+
operation: "load",
|
|
345
|
+
service: CREDENTIAL_SERVICE,
|
|
346
|
+
account,
|
|
347
|
+
}),
|
|
348
|
+
})
|
|
349
|
+
: platform === "linux"
|
|
350
|
+
? await run("secret-tool", [
|
|
351
|
+
"lookup", "service", CREDENTIAL_SERVICE, "project", account,
|
|
352
|
+
])
|
|
353
|
+
: await run("powershell.exe", WINDOWS_POWERSHELL_ARGS, {
|
|
354
|
+
input: JSON.stringify({
|
|
355
|
+
operation: "load",
|
|
356
|
+
service: CREDENTIAL_SERVICE,
|
|
357
|
+
account,
|
|
358
|
+
}),
|
|
359
|
+
});
|
|
360
|
+
if (!result.stdout.trim())
|
|
361
|
+
return undefined;
|
|
362
|
+
return parseStoredCredential(result.stdout.trim(), identity);
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
if (error instanceof CredentialStoreCommandError) {
|
|
366
|
+
const missing = platform === "linux" ? error.exitCode === 1 : error.exitCode === 44;
|
|
367
|
+
if (missing)
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
throw error;
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
async save(identity, secret) {
|
|
374
|
+
const account = credentialAccount(identity);
|
|
375
|
+
const input = `${JSON.stringify(secret)}\n`;
|
|
376
|
+
if (platform === "darwin") {
|
|
377
|
+
await run("osascript", ["-l", "JavaScript", "-e", MACOS_CREDENTIAL_SCRIPT], {
|
|
378
|
+
input: JSON.stringify({
|
|
379
|
+
operation: "save",
|
|
380
|
+
service: CREDENTIAL_SERVICE,
|
|
381
|
+
account,
|
|
382
|
+
payload: input.trim(),
|
|
383
|
+
}),
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
else if (platform === "linux") {
|
|
387
|
+
await run("secret-tool", [
|
|
388
|
+
"store", `--label=Ory Agent Security runtime credential`,
|
|
389
|
+
"service", CREDENTIAL_SERVICE, "project", account,
|
|
390
|
+
], { input });
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
await run("powershell.exe", WINDOWS_POWERSHELL_ARGS, {
|
|
394
|
+
input: JSON.stringify({
|
|
395
|
+
operation: "save",
|
|
396
|
+
service: CREDENTIAL_SERVICE,
|
|
397
|
+
account,
|
|
398
|
+
payload: input.trim(),
|
|
399
|
+
}),
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function talosRuntimeCredential(apiKey, options = {}) {
|
|
406
|
+
const key = apiKey.trim();
|
|
407
|
+
return {
|
|
408
|
+
kind: "talos",
|
|
409
|
+
...(options.subject ? { subject: options.subject } : {}),
|
|
410
|
+
authenticate: async ({ url, init, authorizationHeader, fetch: requestFetch, usesDefaultFetch, }) => {
|
|
411
|
+
const headerName = authorizationHeader === "authorization"
|
|
412
|
+
? "authorization"
|
|
413
|
+
: "X-Ory-Agent-Authorization";
|
|
414
|
+
const headers = {
|
|
415
|
+
...Object.fromEntries(new Headers(init.headers)),
|
|
416
|
+
[headerName]: `Bearer ${key}`,
|
|
417
|
+
};
|
|
418
|
+
const fetchImpl = options.fetch ?? requestFetch;
|
|
419
|
+
try {
|
|
420
|
+
if (!options.fetch && usesDefaultFetch) {
|
|
421
|
+
(options.configureSystemCaTrust ?? configureSystemCaTrustForDefaultFetch)();
|
|
422
|
+
}
|
|
423
|
+
return await fetchImpl(url, { ...init, headers });
|
|
424
|
+
}
|
|
425
|
+
catch (error) {
|
|
426
|
+
if (options.fetch || !usesDefaultFetch)
|
|
427
|
+
throw error;
|
|
428
|
+
throw safeFetchFailure("Talos runtime request", error);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
/** Resolve only noninteractive runtime credentials. No persisted state is read. */
|
|
434
|
+
function resolveRuntimeCredential(options = {}) {
|
|
435
|
+
if (options.requestAuthenticator) {
|
|
436
|
+
return {
|
|
437
|
+
kind: "injected",
|
|
438
|
+
...(options.subject ? { subject: options.subject } : {}),
|
|
439
|
+
authenticate: options.requestAuthenticator,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const apiKey = (options.env ?? process.env).ORY_AGENT_API_KEY?.trim();
|
|
443
|
+
if (!apiKey)
|
|
444
|
+
return undefined;
|
|
445
|
+
return talosRuntimeCredential(apiKey, { subject: options.subject, fetch: options.fetch });
|
|
446
|
+
}
|
|
447
|
+
/** Explicitly enroll a Talos credential and optionally persist it in an OS store. */
|
|
448
|
+
async function enrollTalosRuntimeCredential(options) {
|
|
449
|
+
let response;
|
|
450
|
+
try {
|
|
451
|
+
if (!options.fetch) {
|
|
452
|
+
(options.configureSystemCaTrust ?? configureSystemCaTrustForDefaultFetch)();
|
|
453
|
+
}
|
|
454
|
+
response = await (options.fetch ?? globalThis.fetch)(`${options.agentSecurityUrl.replace(/\/+$/, "")}/agent-security/v1/agents:enroll`, {
|
|
455
|
+
method: "POST",
|
|
456
|
+
headers: {
|
|
457
|
+
"content-type": "application/json",
|
|
458
|
+
authorization: `Bearer ${options.userToken}`,
|
|
459
|
+
"Idempotency-Key": options.idempotencyKey,
|
|
460
|
+
},
|
|
461
|
+
body: JSON.stringify({
|
|
462
|
+
project_url: options.projectUrl,
|
|
463
|
+
name: options.name,
|
|
464
|
+
method: "talos_api_key",
|
|
465
|
+
}),
|
|
466
|
+
signal: options.signal ?? AbortSignal.timeout(30_000),
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
if (options.fetch)
|
|
471
|
+
throw error;
|
|
472
|
+
throw safeFetchFailure("Talos enrollment request", error);
|
|
473
|
+
}
|
|
474
|
+
if (!response.ok) {
|
|
475
|
+
throw Object.assign(new Error(`HTTP ${response.status}`), { status: response.status });
|
|
476
|
+
}
|
|
477
|
+
const body = await response.json();
|
|
478
|
+
if (typeof body.credential !== "string" || body.credential.length === 0) {
|
|
479
|
+
throw new Error("Enrollment response missing credential");
|
|
480
|
+
}
|
|
481
|
+
if (typeof body.actor_id !== "string" || body.actor_id.length === 0) {
|
|
482
|
+
throw new Error("Enrollment response missing actor_id");
|
|
483
|
+
}
|
|
484
|
+
const stored = {
|
|
485
|
+
version: 2,
|
|
486
|
+
credential: body.credential,
|
|
487
|
+
actorId: body.actor_id,
|
|
488
|
+
...(typeof body.credential_id === "string" ? { credentialId: body.credential_id } : {}),
|
|
489
|
+
...(typeof body.expires_at === "string" ? { expiresAt: body.expires_at } : {}),
|
|
490
|
+
identity: canonicalCredentialIdentity(options.identity ?? options.projectUrl),
|
|
491
|
+
};
|
|
492
|
+
const warnings = [];
|
|
493
|
+
if (options.credentialStore) {
|
|
494
|
+
try {
|
|
495
|
+
await options.credentialStore.save(options.identity ?? options.projectUrl, stored);
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
warnings.push("The Talos runtime credential was issued but could not be saved to the OS credential store; it will remain available only in this process");
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
actorId: body.actor_id,
|
|
503
|
+
warnings,
|
|
504
|
+
credential: talosRuntimeCredential(body.credential, {
|
|
505
|
+
subject: body.actor_id,
|
|
506
|
+
fetch: options.fetch,
|
|
507
|
+
}),
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
/** Enroll a separately keyed child using the authenticated parent runtime. */
|
|
511
|
+
async function enrollTalosChildRuntimeCredential(options) {
|
|
512
|
+
const response = await authenticatedRuntimeRequest(options.parentCredential, {
|
|
513
|
+
url: `${options.agentSecurityUrl.replace(/\/+$/, "")}/agent-security/v1/agents:enroll-child`,
|
|
514
|
+
init: {
|
|
515
|
+
method: "POST",
|
|
516
|
+
headers: {
|
|
517
|
+
"content-type": "application/json",
|
|
518
|
+
"Idempotency-Key": options.idempotencyKey,
|
|
519
|
+
},
|
|
520
|
+
body: JSON.stringify({
|
|
521
|
+
project_url: options.projectUrl,
|
|
522
|
+
name: options.name,
|
|
523
|
+
type_name: options.subAgentType,
|
|
524
|
+
}),
|
|
525
|
+
signal: options.signal ?? AbortSignal.timeout(30_000),
|
|
526
|
+
},
|
|
527
|
+
authorizationHeader: "authorization",
|
|
528
|
+
fetch: options.fetch,
|
|
529
|
+
});
|
|
530
|
+
if (!response.ok) {
|
|
531
|
+
throw Object.assign(new Error(`HTTP ${response.status}`), { status: response.status });
|
|
532
|
+
}
|
|
533
|
+
const body = await response.json();
|
|
534
|
+
if (typeof body.credential !== "string" || !body.credential) {
|
|
535
|
+
throw new Error("Child enrollment response missing credential");
|
|
536
|
+
}
|
|
537
|
+
if (typeof body.actor_id !== "string" || !body.actor_id) {
|
|
538
|
+
throw new Error("Child enrollment response missing actor_id");
|
|
539
|
+
}
|
|
540
|
+
const stored = {
|
|
541
|
+
version: 2,
|
|
542
|
+
credential: body.credential,
|
|
543
|
+
actorId: body.actor_id,
|
|
544
|
+
...(typeof body.credential_id === "string" ? { credentialId: body.credential_id } : {}),
|
|
545
|
+
...(typeof body.expires_at === "string" ? { expiresAt: body.expires_at } : {}),
|
|
546
|
+
identity: canonicalCredentialIdentity(options.identity),
|
|
547
|
+
};
|
|
548
|
+
const warnings = [];
|
|
549
|
+
if (options.credentialStore) {
|
|
550
|
+
try {
|
|
551
|
+
await options.credentialStore.save(options.identity, stored);
|
|
552
|
+
}
|
|
553
|
+
catch {
|
|
554
|
+
warnings.push("The child Talos credential was issued but could not be saved to the OS credential store; it will remain available only in this process");
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
actorId: body.actor_id,
|
|
559
|
+
warnings,
|
|
560
|
+
credential: talosRuntimeCredential(body.credential, {
|
|
561
|
+
subject: body.actor_id,
|
|
562
|
+
fetch: options.fetch,
|
|
563
|
+
}),
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
async function authenticatedRuntimeRequest(credential, request) {
|
|
567
|
+
return credential.authenticate({
|
|
568
|
+
...request,
|
|
569
|
+
fetch: request.fetch ?? globalThis.fetch,
|
|
570
|
+
usesDefaultFetch: request.fetch === undefined,
|
|
571
|
+
});
|
|
572
|
+
}
|