@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
package/dist/local/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.hostUrl = exports.describePortConflicts = exports.findPortConflicts = exports.isPortAvailable = exports.isLocalDockerDaemon = exports.hostFromDockerHost = exports.resolveLocalHost = exports.resolveLocalPorts = exports.DEFAULT_LOCAL_HOST = exports.PORT_OFFSET_ENV_VAR = exports.LOCAL_HOST_ENV_VAR = exports.LOCAL_PORT_SPECS = exports.LOCAL_PORT_NAMES = exports.getLocalPorts = exports.LOCAL_PORT_WARNINGS = exports.LOCAL_STACK_HOST_SOURCE = exports.LOCAL_STACK_HOST = exports.LOGIN_UI_URL = exports.LOGIN_UI_PORT = exports.CONSOLE_URL = exports.CONSOLE_PORT = exports.HYDRA_TOKEN_USER_PORT = exports.HYDRA_ADMIN_PORT = exports.HYDRA_PUBLIC_PORT = exports.KETO_WRITE_PORT = exports.KETO_READ_PORT = exports.KRATOS_ADMIN_PORT = exports.KRATOS_PUBLIC_PORT = exports.GATEWAY_PORT = exports.GATEWAY_URL = exports.USER_SUBJECT_NAMESPACE = exports.USER_CLIENT_ID = exports.seedLocalEnvironment = exports.waitForGateway = exports.checkAllServices = exports.ensureLocalOryStack = exports.localConfigure = exports.localEnv = exports.localReset = exports.localLogs = exports.localSeed = exports.localStatus = exports.localDown = exports.localUp = exports.runLocalCommand = void 0;
|
|
4
4
|
var cli_js_1 = require("./cli.js");
|
|
5
5
|
Object.defineProperty(exports, "runLocalCommand", { enumerable: true, get: function () { return cli_js_1.runLocalCommand; } });
|
|
6
6
|
var manager_js_1 = require("./manager.js");
|
|
@@ -29,12 +29,26 @@ Object.defineProperty(exports, "KETO_READ_PORT", { enumerable: true, get: functi
|
|
|
29
29
|
Object.defineProperty(exports, "KETO_WRITE_PORT", { enumerable: true, get: function () { return configs_js_1.KETO_WRITE_PORT; } });
|
|
30
30
|
Object.defineProperty(exports, "HYDRA_PUBLIC_PORT", { enumerable: true, get: function () { return configs_js_1.HYDRA_PUBLIC_PORT; } });
|
|
31
31
|
Object.defineProperty(exports, "HYDRA_ADMIN_PORT", { enumerable: true, get: function () { return configs_js_1.HYDRA_ADMIN_PORT; } });
|
|
32
|
-
Object.defineProperty(exports, "
|
|
33
|
-
Object.defineProperty(exports, "
|
|
34
|
-
Object.defineProperty(exports, "
|
|
35
|
-
Object.defineProperty(exports, "
|
|
36
|
-
|
|
37
|
-
Object.defineProperty(exports, "
|
|
38
|
-
Object.defineProperty(exports, "
|
|
39
|
-
Object.defineProperty(exports, "
|
|
40
|
-
Object.defineProperty(exports, "
|
|
32
|
+
Object.defineProperty(exports, "HYDRA_TOKEN_USER_PORT", { enumerable: true, get: function () { return configs_js_1.HYDRA_TOKEN_USER_PORT; } });
|
|
33
|
+
Object.defineProperty(exports, "CONSOLE_PORT", { enumerable: true, get: function () { return configs_js_1.CONSOLE_PORT; } });
|
|
34
|
+
Object.defineProperty(exports, "CONSOLE_URL", { enumerable: true, get: function () { return configs_js_1.CONSOLE_URL; } });
|
|
35
|
+
Object.defineProperty(exports, "LOGIN_UI_PORT", { enumerable: true, get: function () { return configs_js_1.LOGIN_UI_PORT; } });
|
|
36
|
+
Object.defineProperty(exports, "LOGIN_UI_URL", { enumerable: true, get: function () { return configs_js_1.LOGIN_UI_URL; } });
|
|
37
|
+
Object.defineProperty(exports, "LOCAL_STACK_HOST", { enumerable: true, get: function () { return configs_js_1.LOCAL_STACK_HOST; } });
|
|
38
|
+
Object.defineProperty(exports, "LOCAL_STACK_HOST_SOURCE", { enumerable: true, get: function () { return configs_js_1.LOCAL_STACK_HOST_SOURCE; } });
|
|
39
|
+
Object.defineProperty(exports, "LOCAL_PORT_WARNINGS", { enumerable: true, get: function () { return configs_js_1.LOCAL_PORT_WARNINGS; } });
|
|
40
|
+
Object.defineProperty(exports, "getLocalPorts", { enumerable: true, get: function () { return configs_js_1.getLocalPorts; } });
|
|
41
|
+
var ports_js_1 = require("./ports.js");
|
|
42
|
+
Object.defineProperty(exports, "LOCAL_PORT_NAMES", { enumerable: true, get: function () { return ports_js_1.LOCAL_PORT_NAMES; } });
|
|
43
|
+
Object.defineProperty(exports, "LOCAL_PORT_SPECS", { enumerable: true, get: function () { return ports_js_1.LOCAL_PORT_SPECS; } });
|
|
44
|
+
Object.defineProperty(exports, "LOCAL_HOST_ENV_VAR", { enumerable: true, get: function () { return ports_js_1.LOCAL_HOST_ENV_VAR; } });
|
|
45
|
+
Object.defineProperty(exports, "PORT_OFFSET_ENV_VAR", { enumerable: true, get: function () { return ports_js_1.PORT_OFFSET_ENV_VAR; } });
|
|
46
|
+
Object.defineProperty(exports, "DEFAULT_LOCAL_HOST", { enumerable: true, get: function () { return ports_js_1.DEFAULT_LOCAL_HOST; } });
|
|
47
|
+
Object.defineProperty(exports, "resolveLocalPorts", { enumerable: true, get: function () { return ports_js_1.resolveLocalPorts; } });
|
|
48
|
+
Object.defineProperty(exports, "resolveLocalHost", { enumerable: true, get: function () { return ports_js_1.resolveLocalHost; } });
|
|
49
|
+
Object.defineProperty(exports, "hostFromDockerHost", { enumerable: true, get: function () { return ports_js_1.hostFromDockerHost; } });
|
|
50
|
+
Object.defineProperty(exports, "isLocalDockerDaemon", { enumerable: true, get: function () { return ports_js_1.isLocalDockerDaemon; } });
|
|
51
|
+
Object.defineProperty(exports, "isPortAvailable", { enumerable: true, get: function () { return ports_js_1.isPortAvailable; } });
|
|
52
|
+
Object.defineProperty(exports, "findPortConflicts", { enumerable: true, get: function () { return ports_js_1.findPortConflicts; } });
|
|
53
|
+
Object.defineProperty(exports, "describePortConflicts", { enumerable: true, get: function () { return ports_js_1.describePortConflicts; } });
|
|
54
|
+
Object.defineProperty(exports, "hostUrl", { enumerable: true, get: function () { return ports_js_1.hostUrl; } });
|
package/dist/local/manager.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* .ory-dev/registry/ owned by the local npm registry manager.
|
|
13
13
|
*/
|
|
14
14
|
export interface EnsureLocalOryStackResult {
|
|
15
|
-
status: "already-running" | "started" | "skipped:no-docker" | "compose-failed" | "gateway-unhealthy" | "console-misconfigured";
|
|
15
|
+
status: "already-running" | "started" | "skipped:no-docker" | "port-conflict" | "compose-failed" | "gateway-unhealthy" | "console-misconfigured";
|
|
16
16
|
/** Local Ory gateway URL. Set when status is `already-running` or `started`. */
|
|
17
17
|
gatewayUrl?: string;
|
|
18
18
|
/** Filesystem path to the compose project (for log hints). */
|
|
@@ -44,4 +44,23 @@ export declare function localSeed(): Promise<void>;
|
|
|
44
44
|
export declare function localLogs(args: string[]): void;
|
|
45
45
|
export declare function localReset(): Promise<void>;
|
|
46
46
|
export declare function localEnv(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Point the shared config at the local Ory stack.
|
|
49
|
+
*
|
|
50
|
+
* The local stack is part of the plugin's developer-experience surface and
|
|
51
|
+
* runs perfectly well without this: `local up` starts Kratos, Hydra, Keto,
|
|
52
|
+
* and the Console regardless of what any plugin is connected to, and
|
|
53
|
+
* connecting a plugin to a hosted Ory project takes none of that away.
|
|
54
|
+
*
|
|
55
|
+
* This command is the *opt-in* extra step of also pointing the security half
|
|
56
|
+
* at the local stack, so sign-in runs against local Kratos/Hydra and permission
|
|
57
|
+
* checks use the canonical local Agent Security origin. Because that writes the
|
|
58
|
+
* connection values into the config every installed plugin shares, an existing
|
|
59
|
+
* connection is reported before it is replaced — silently repointing someone's
|
|
60
|
+
* hosted project at localhost is the kind of surprise this warns about.
|
|
61
|
+
*
|
|
62
|
+
* The Agent Security service is provided separately at
|
|
63
|
+
* ``https://agents.console.ory:8080``; when it is not running, checks and
|
|
64
|
+
* delegation recording retain their normal classified fail-open behavior.
|
|
65
|
+
*/
|
|
47
66
|
export declare function localConfigure(): void;
|
package/dist/local/manager.js
CHANGED
|
@@ -60,9 +60,11 @@ const path = __importStar(require("node:path"));
|
|
|
60
60
|
const crypto = __importStar(require("node:crypto"));
|
|
61
61
|
const node_child_process_1 = require("node:child_process");
|
|
62
62
|
const configs_js_1 = require("./configs.js");
|
|
63
|
+
const ports_js_1 = require("./ports.js");
|
|
63
64
|
const health_js_1 = require("./health.js");
|
|
64
65
|
const seed_js_1 = require("./seed.js");
|
|
65
66
|
const config_js_1 = require("../config.js");
|
|
67
|
+
const opl_js_1 = require("../opl.js");
|
|
66
68
|
const LOCAL_DIR_NAME = ".ory-dev/ory";
|
|
67
69
|
async function isGatewayHealthy(timeoutMs, url) {
|
|
68
70
|
try {
|
|
@@ -179,6 +181,51 @@ function runCompose(composeArgs, localDir, opts) {
|
|
|
179
181
|
stderr: result.stderr?.toString(),
|
|
180
182
|
};
|
|
181
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Does this compose project have containers (running or stopped)? Used to
|
|
186
|
+
* decide whether a port probe means anything — our own containers hold the
|
|
187
|
+
* stack's ports legitimately, so probing with them present reports the stack
|
|
188
|
+
* as conflicting with itself.
|
|
189
|
+
*
|
|
190
|
+
* Note the compose project name is fixed (`ory-local`), so this also answers
|
|
191
|
+
* "yes" for a stack brought up from a *different* directory. That is the right
|
|
192
|
+
* answer for the preflight anyway — that stack is this stack, and `up` will
|
|
193
|
+
* reconcile it onto the current ports rather than collide with it.
|
|
194
|
+
*
|
|
195
|
+
* Treated as "yes, containers exist" on any failure: skipping the preflight is
|
|
196
|
+
* the safe direction, since the failure path still diagnoses a real conflict
|
|
197
|
+
* after `docker compose up` reports one.
|
|
198
|
+
*/
|
|
199
|
+
function composeProjectHasContainers(localDir) {
|
|
200
|
+
if (!fs.existsSync(path.join(localDir, "docker-compose.yml")))
|
|
201
|
+
return false;
|
|
202
|
+
try {
|
|
203
|
+
const result = runCompose(["ps", "-aq"], localDir, { stdio: "pipe" });
|
|
204
|
+
if (result.status !== 0)
|
|
205
|
+
return true;
|
|
206
|
+
return (result.stdout ?? "").trim().length > 0;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Render the port-conflict report, or `undefined` when there is nothing to
|
|
214
|
+
* report.
|
|
215
|
+
*
|
|
216
|
+
* Returns nothing for a remote Docker daemon (the stack's ports are published
|
|
217
|
+
* on *that* host, so probing this machine's sockets would answer a question
|
|
218
|
+
* nobody asked) or when probing is switched off entirely — see
|
|
219
|
+
* `ORY_LOCAL_SKIP_PORT_CHECK`.
|
|
220
|
+
*/
|
|
221
|
+
async function describeStartupPortConflicts() {
|
|
222
|
+
if ((0, ports_js_1.portCheckDisabled)() || !(0, ports_js_1.isLocalDockerDaemon)())
|
|
223
|
+
return undefined;
|
|
224
|
+
const conflicts = await (0, ports_js_1.findPortConflicts)((0, configs_js_1.getLocalPorts)());
|
|
225
|
+
if (conflicts.length === 0)
|
|
226
|
+
return undefined;
|
|
227
|
+
return (0, ports_js_1.describePortConflicts)(conflicts);
|
|
228
|
+
}
|
|
182
229
|
/**
|
|
183
230
|
* Dump captured output from a failing piped command to stderr so the user
|
|
184
231
|
* can see the underlying error. In non-piped mode, the output already
|
|
@@ -203,11 +250,11 @@ function dumpCapturedOutput(label, result) {
|
|
|
203
250
|
* `writeConfigs` writes these and `configFingerprint` hashes them, so the
|
|
204
251
|
* on-disk stack and its change-detection signal never drift.
|
|
205
252
|
*/
|
|
206
|
-
function renderConfigs(projectRoot, consoleCfg) {
|
|
207
|
-
|
|
253
|
+
function renderConfigs(projectRoot, consoleCfg, oathkeeperCfg) {
|
|
254
|
+
const configs = [
|
|
208
255
|
{
|
|
209
256
|
relPath: "docker-compose.yml",
|
|
210
|
-
content: (0, configs_js_1.dockerComposeYaml)(projectRoot, consoleCfg),
|
|
257
|
+
content: (0, configs_js_1.dockerComposeYaml)(projectRoot, consoleCfg, oathkeeperCfg),
|
|
211
258
|
},
|
|
212
259
|
{ relPath: "kratos/kratos.yml", content: (0, configs_js_1.kratosConfigYaml)() },
|
|
213
260
|
{
|
|
@@ -215,10 +262,20 @@ function renderConfigs(projectRoot, consoleCfg) {
|
|
|
215
262
|
content: (0, configs_js_1.kratosIdentitySchema)(),
|
|
216
263
|
},
|
|
217
264
|
{ relPath: "keto/keto.yml", content: (0, configs_js_1.ketoConfigYaml)() },
|
|
265
|
+
// OPL namespace definitions referenced by keto.yml's `namespaces.location`.
|
|
266
|
+
// Defines the block-aware `access` permit on both the AgentTool and
|
|
267
|
+
// ShellTool namespaces (buildAgentSecurityOpl emits both).
|
|
268
|
+
{ relPath: "keto/namespaces.keto.ts", content: (0, opl_js_1.buildAgentSecurityOpl)() },
|
|
218
269
|
{ relPath: "hydra/hydra.yml", content: (0, configs_js_1.hydraConfigYaml)() },
|
|
219
|
-
// nginx config is always emitted — the gateway is no longer optional.
|
|
220
|
-
|
|
270
|
+
// nginx config is always emitted — the gateway is no longer optional. Its
|
|
271
|
+
// /user/* routing depends on whether Oathkeeper fronts that path.
|
|
272
|
+
{ relPath: "nginx/nginx.conf", content: (0, configs_js_1.nginxConf)(oathkeeperCfg.enabled) },
|
|
221
273
|
];
|
|
274
|
+
// Oathkeeper config is only materialized when the /user override is enabled.
|
|
275
|
+
if (oathkeeperCfg.enabled) {
|
|
276
|
+
configs.push({ relPath: "oathkeeper/oathkeeper.yml", content: (0, configs_js_1.oathkeeperConfigYaml)() }, { relPath: "oathkeeper/access-rules.yml", content: (0, configs_js_1.oathkeeperAccessRulesYaml)() });
|
|
277
|
+
}
|
|
278
|
+
return configs;
|
|
222
279
|
}
|
|
223
280
|
/**
|
|
224
281
|
* Stable content hash of the rendered config set. Used to decide whether an
|
|
@@ -226,9 +283,9 @@ function renderConfigs(projectRoot, consoleCfg) {
|
|
|
226
283
|
* generate; a change (e.g. the login-UI port, a service env var) invalidates
|
|
227
284
|
* the fast-path short-circuit so the stack is reconciled instead of reused.
|
|
228
285
|
*/
|
|
229
|
-
function configFingerprint(projectRoot, consoleCfg) {
|
|
286
|
+
function configFingerprint(projectRoot, consoleCfg, oathkeeperCfg) {
|
|
230
287
|
const hash = crypto.createHash("sha256");
|
|
231
|
-
for (const { relPath, content } of renderConfigs(projectRoot, consoleCfg)) {
|
|
288
|
+
for (const { relPath, content } of renderConfigs(projectRoot, consoleCfg, oathkeeperCfg)) {
|
|
232
289
|
hash.update(relPath);
|
|
233
290
|
hash.update("\0");
|
|
234
291
|
hash.update(content);
|
|
@@ -257,13 +314,16 @@ function writeConfigFingerprint(localDir, fingerprint) {
|
|
|
257
314
|
// Best-effort: a missing fingerprint only costs a reconcile next launch.
|
|
258
315
|
}
|
|
259
316
|
}
|
|
260
|
-
function writeConfigs(localDir, projectRoot, consoleCfg) {
|
|
317
|
+
function writeConfigs(localDir, projectRoot, consoleCfg, oathkeeperCfg) {
|
|
261
318
|
ensureDir(localDir);
|
|
262
319
|
ensureDir(path.join(localDir, "kratos"));
|
|
263
320
|
ensureDir(path.join(localDir, "keto"));
|
|
264
321
|
ensureDir(path.join(localDir, "hydra"));
|
|
265
322
|
ensureDir(path.join(localDir, "nginx"));
|
|
266
|
-
|
|
323
|
+
if (oathkeeperCfg.enabled) {
|
|
324
|
+
ensureDir(path.join(localDir, "oathkeeper"));
|
|
325
|
+
}
|
|
326
|
+
for (const { relPath, content } of renderConfigs(projectRoot, consoleCfg, oathkeeperCfg)) {
|
|
267
327
|
fs.writeFileSync(path.join(localDir, relPath), content);
|
|
268
328
|
}
|
|
269
329
|
}
|
|
@@ -289,6 +349,7 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
289
349
|
if (cfgError) {
|
|
290
350
|
return { status: "console-misconfigured", localDir, detail: cfgError };
|
|
291
351
|
}
|
|
352
|
+
const oathkeeperCfg = (0, configs_js_1.getOathkeeperConfig)();
|
|
292
353
|
const gatewayCfg = (0, configs_js_1.getGatewayConfig)();
|
|
293
354
|
const healthUrl = `${configs_js_1.GATEWAY_URL}${gatewayCfg.healthPath}`;
|
|
294
355
|
// Short-circuit if the gateway is already serving AND the running stack was
|
|
@@ -306,7 +367,7 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
306
367
|
// source tree behind the path may have changed, which the fingerprint of the
|
|
307
368
|
// generated config can't see).
|
|
308
369
|
const explicitConsoleLiteOverride = (process.env.ORY_CONSOLE_LITE_PATH ?? "").trim() !== "";
|
|
309
|
-
const fingerprint = configFingerprint(projectRoot, consoleCfg);
|
|
370
|
+
const fingerprint = configFingerprint(projectRoot, consoleCfg, oathkeeperCfg);
|
|
310
371
|
const configUnchanged = readConfigFingerprint(localDir) === fingerprint;
|
|
311
372
|
if (!explicitConsoleLiteOverride &&
|
|
312
373
|
configUnchanged &&
|
|
@@ -323,10 +384,32 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
323
384
|
detail: "Docker is not running. Start Docker Desktop and try again.",
|
|
324
385
|
};
|
|
325
386
|
}
|
|
326
|
-
|
|
387
|
+
// A typo'd port override would otherwise fall back to a default the user
|
|
388
|
+
// thinks they changed, and only show up as a collision much later.
|
|
389
|
+
for (const warning of configs_js_1.LOCAL_PORT_WARNINGS)
|
|
390
|
+
log(` Warning: ${warning}`);
|
|
391
|
+
// Preflight, but only when the answer is trustworthy: with no containers in
|
|
392
|
+
// this compose project, every host port we want is either free or held by
|
|
393
|
+
// something that isn't us. Once containers exist they legitimately hold
|
|
394
|
+
// those ports and a probe would report the stack as conflicting with itself.
|
|
395
|
+
if (!composeProjectHasContainers(localDir)) {
|
|
396
|
+
const conflictReport = await describeStartupPortConflicts();
|
|
397
|
+
if (conflictReport) {
|
|
398
|
+
return { status: "port-conflict", localDir, detail: conflictReport };
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
writeConfigs(localDir, projectRoot, consoleCfg, oathkeeperCfg);
|
|
327
402
|
log(" Config files written.");
|
|
328
403
|
log(" Gateway: bundled nginx API passthrough.");
|
|
329
404
|
log(" Login UI: oryd/kratos-selfservice-ui-node.");
|
|
405
|
+
if (oathkeeperCfg.enabled) {
|
|
406
|
+
log(" Oathkeeper: /user Keto read path fronted with OAuth2 token " +
|
|
407
|
+
"introspection (default; set ORY_LOCAL_OATHKEEPER=0 to disable).");
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
log(" Oathkeeper: disabled (ORY_LOCAL_OATHKEEPER=0) — /user path is a " +
|
|
411
|
+
"transparent passthrough with no auth.");
|
|
412
|
+
}
|
|
330
413
|
if (consoleCfg.enabled) {
|
|
331
414
|
const sourceLabel = consoleCfg.source === "default"
|
|
332
415
|
? "default sibling checkout"
|
|
@@ -351,21 +434,20 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
351
434
|
stdio: opts.quiet ? "pipe" : "inherit",
|
|
352
435
|
});
|
|
353
436
|
if (buildResult.status !== 0) {
|
|
354
|
-
// Surface the actual build error first
|
|
355
|
-
//
|
|
356
|
-
// output the user only sees "exit N" with no clue why.
|
|
437
|
+
// Surface the actual build error first. In quiet mode the build runs
|
|
438
|
+
// piped, so otherwise the user only sees "exit N" with no clue why.
|
|
357
439
|
dumpCapturedOutput("docker compose build console", buildResult);
|
|
358
440
|
// Graceful fallback: a Console Lite source-tree build failure
|
|
359
441
|
// shouldn't block the rest of the local stack from coming up.
|
|
360
442
|
// Disable Console for this run, regenerate the compose YAML
|
|
361
443
|
// without it, and continue. The rest of the stack (API gateway,
|
|
362
|
-
// login UI
|
|
444
|
+
// login UI and Kratos/Hydra/Keto) is unaffected. The user
|
|
363
445
|
// can fix the cloud repo and rerun to bring Console back.
|
|
364
446
|
log(` Warning: Ory Console Lite build failed (exit ${buildResult.status}). ` +
|
|
365
447
|
`Continuing without Console — the rest of the stack will come up. ` +
|
|
366
448
|
`Re-run the build directly to iterate: cd ${localDir} && docker compose build console`);
|
|
367
449
|
consoleCfg = { enabled: false };
|
|
368
|
-
writeConfigs(localDir, projectRoot, consoleCfg);
|
|
450
|
+
writeConfigs(localDir, projectRoot, consoleCfg, oathkeeperCfg);
|
|
369
451
|
}
|
|
370
452
|
}
|
|
371
453
|
log(" Starting services...");
|
|
@@ -374,6 +456,13 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
374
456
|
});
|
|
375
457
|
if (upResult.status !== 0) {
|
|
376
458
|
dumpCapturedOutput("docker compose up", upResult);
|
|
459
|
+
// Docker's own message names a port but not the service that wanted it,
|
|
460
|
+
// and says nothing about how to move it. Probe now that we know the start
|
|
461
|
+
// failed: at this point a held port is unambiguously someone else's.
|
|
462
|
+
const conflictReport = await describeStartupPortConflicts();
|
|
463
|
+
if (conflictReport) {
|
|
464
|
+
return { status: "port-conflict", localDir, detail: conflictReport };
|
|
465
|
+
}
|
|
377
466
|
return {
|
|
378
467
|
status: "compose-failed",
|
|
379
468
|
localDir,
|
|
@@ -394,7 +483,7 @@ async function ensureLocalOryStack(opts = {}) {
|
|
|
394
483
|
// Record the fingerprint of the config the stack was actually brought up
|
|
395
484
|
// with (consoleCfg may have fallen back to disabled above), so the next
|
|
396
485
|
// launch can short-circuit only while the config is unchanged.
|
|
397
|
-
writeConfigFingerprint(localDir, configFingerprint(projectRoot, consoleCfg));
|
|
486
|
+
writeConfigFingerprint(localDir, configFingerprint(projectRoot, consoleCfg, oathkeeperCfg));
|
|
398
487
|
return { status: "started", gatewayUrl: configs_js_1.GATEWAY_URL, localDir };
|
|
399
488
|
}
|
|
400
489
|
async function localUp(opts = {}) {
|
|
@@ -407,6 +496,12 @@ async function localUp(opts = {}) {
|
|
|
407
496
|
case "console-misconfigured":
|
|
408
497
|
console.error(`Error: ${result.detail}`);
|
|
409
498
|
process.exit(1);
|
|
499
|
+
case "port-conflict":
|
|
500
|
+
// The report is already a complete, actionable message; a log hint would
|
|
501
|
+
// point at containers that were never created.
|
|
502
|
+
console.error("");
|
|
503
|
+
console.error(result.detail);
|
|
504
|
+
process.exit(1);
|
|
410
505
|
case "compose-failed":
|
|
411
506
|
case "gateway-unhealthy":
|
|
412
507
|
console.error(`Error: ${result.detail}`);
|
|
@@ -542,7 +637,7 @@ async function localStatus() {
|
|
|
542
637
|
}
|
|
543
638
|
}
|
|
544
639
|
async function localSeed() {
|
|
545
|
-
const namespace = process.env.ORY_PERMISSION_NAMESPACE ?? "
|
|
640
|
+
const namespace = process.env.ORY_PERMISSION_NAMESPACE ?? "AgentTool";
|
|
546
641
|
try {
|
|
547
642
|
const result = await (0, seed_js_1.seedLocalEnvironment)(namespace);
|
|
548
643
|
printSeedResult(result);
|
|
@@ -687,31 +782,60 @@ async function localReset() {
|
|
|
687
782
|
function localEnv() {
|
|
688
783
|
console.log("# Add these to your shell profile or .env file:");
|
|
689
784
|
console.log(`export ORY_PROJECT_URL=${configs_js_1.GATEWAY_URL}`);
|
|
785
|
+
console.log(`export ORY_AGENT_SECURITY_URL=${config_js_1.LOCAL_AGENT_SECURITY_URL}`);
|
|
690
786
|
console.log("export ORY_AGENT_DEBUG=true");
|
|
691
787
|
console.log("");
|
|
692
|
-
console.log("#
|
|
693
|
-
console.log("# export
|
|
694
|
-
console.log("");
|
|
695
|
-
console.log("#
|
|
696
|
-
console.log(`export OTEL_EXPORTER_OTLP_ENDPOINT=${configs_js_1.JAEGER_OTLP_HTTP_URL}`);
|
|
788
|
+
console.log("# 'local seed' registers the PKCE login client it prints:");
|
|
789
|
+
console.log("# export ORY_OAUTH2_CLIENT_ID=<client id from seed output>");
|
|
790
|
+
console.log("# (sign in with the seeded email + password when the browser opens;");
|
|
791
|
+
console.log("# or set ORY_USER_OAUTH2_TOKEN=<access token> to skip the flow)");
|
|
697
792
|
}
|
|
793
|
+
/**
|
|
794
|
+
* Point the shared config at the local Ory stack.
|
|
795
|
+
*
|
|
796
|
+
* The local stack is part of the plugin's developer-experience surface and
|
|
797
|
+
* runs perfectly well without this: `local up` starts Kratos, Hydra, Keto,
|
|
798
|
+
* and the Console regardless of what any plugin is connected to, and
|
|
799
|
+
* connecting a plugin to a hosted Ory project takes none of that away.
|
|
800
|
+
*
|
|
801
|
+
* This command is the *opt-in* extra step of also pointing the security half
|
|
802
|
+
* at the local stack, so sign-in runs against local Kratos/Hydra and permission
|
|
803
|
+
* checks use the canonical local Agent Security origin. Because that writes the
|
|
804
|
+
* connection values into the config every installed plugin shares, an existing
|
|
805
|
+
* connection is reported before it is replaced — silently repointing someone's
|
|
806
|
+
* hosted project at localhost is the kind of surprise this warns about.
|
|
807
|
+
*
|
|
808
|
+
* The Agent Security service is provided separately at
|
|
809
|
+
* ``https://agents.console.ory:8080``; when it is not running, checks and
|
|
810
|
+
* delegation recording retain their normal classified fail-open behavior.
|
|
811
|
+
*/
|
|
698
812
|
function localConfigure() {
|
|
813
|
+
const previous = (0, config_js_1.loadConfig)();
|
|
814
|
+
const replacing = previous.projectUrl && previous.projectUrl !== configs_js_1.GATEWAY_URL ? previous.projectUrl : undefined;
|
|
815
|
+
if (replacing) {
|
|
816
|
+
console.log(`Note: this replaces the currently configured project URL (${replacing}).`);
|
|
817
|
+
console.log(" That connection is shared by every installed Ory agent plugin.");
|
|
818
|
+
console.log("");
|
|
819
|
+
}
|
|
699
820
|
console.log(`Saving local Ory gateway URL to shared config...`);
|
|
700
|
-
// Persist the
|
|
701
|
-
//
|
|
702
|
-
// require-OAuth2-client check, and the user gate resolves the right
|
|
703
|
-
// client out of the box.
|
|
821
|
+
// Persist the canonical local broker origin instead of falling back to the
|
|
822
|
+
// project gateway, which does not implement Agent Security broker routes.
|
|
704
823
|
(0, config_js_1.saveConfig)({
|
|
705
824
|
projectUrl: configs_js_1.GATEWAY_URL,
|
|
825
|
+
agentSecurityUrl: config_js_1.LOCAL_AGENT_SECURITY_URL,
|
|
706
826
|
oauth2ClientId: seed_js_1.USER_CLIENT_ID,
|
|
707
|
-
auditOnly: false,
|
|
708
827
|
});
|
|
709
828
|
console.log(` Project URL: ${configs_js_1.GATEWAY_URL}`);
|
|
829
|
+
console.log(` Agent Security: ${config_js_1.LOCAL_AGENT_SECURITY_URL}`);
|
|
710
830
|
console.log(` OAuth2 Client ID: ${seed_js_1.USER_CLIENT_ID}`);
|
|
711
831
|
console.log("");
|
|
712
|
-
console.log("
|
|
713
|
-
console.log(
|
|
714
|
-
console.log("
|
|
832
|
+
console.log("Sign-in and permission checks now target the local environment.");
|
|
833
|
+
console.log(`Start local Agent Security at ${config_js_1.LOCAL_AGENT_SECURITY_URL} for broker calls.`);
|
|
834
|
+
console.log("");
|
|
835
|
+
console.log("This persists across sessions. Point at a hosted project with");
|
|
836
|
+
console.log("'configure --project-url <URL> --agent-security-url <URL>',");
|
|
837
|
+
console.log("or turn checks off");
|
|
838
|
+
console.log("with 'configure --disconnect' — the local stack keeps running either way.");
|
|
715
839
|
}
|
|
716
840
|
// ─── Helpers ───────────────────────────────────────────────────────
|
|
717
841
|
function printSeedResult(result) {
|
|
@@ -730,6 +854,7 @@ function printSeedResult(result) {
|
|
|
730
854
|
console.log("To use with any Ory agent plugin, set these environment variables:");
|
|
731
855
|
console.log("");
|
|
732
856
|
console.log(` export ORY_PROJECT_URL=${configs_js_1.GATEWAY_URL}`);
|
|
857
|
+
console.log(` export ORY_AGENT_SECURITY_URL=${config_js_1.LOCAL_AGENT_SECURITY_URL}`);
|
|
733
858
|
console.log(` export ORY_OAUTH2_CLIENT_ID=${result.user.client.clientId}`);
|
|
734
859
|
console.log(` export ORY_USER_SUBJECT_NAMESPACE=User`);
|
|
735
860
|
console.log(` export ORY_USER_SUBJECT_ID=${result.user.identity.id}`);
|
|
@@ -748,11 +873,9 @@ function printConnectionInfo() {
|
|
|
748
873
|
console.log("===============");
|
|
749
874
|
console.log("");
|
|
750
875
|
console.log(` Gateway URL: ${configs_js_1.GATEWAY_URL}`);
|
|
751
|
-
console.log(` Kratos:
|
|
752
|
-
console.log(` Keto:
|
|
753
|
-
console.log(` Hydra:
|
|
754
|
-
console.log(` Jaeger UI: ${configs_js_1.JAEGER_UI_URL}`);
|
|
755
|
-
console.log(` OTLP HTTP: ${configs_js_1.JAEGER_OTLP_HTTP_URL} (set OTEL_EXPORTER_OTLP_ENDPOINT to ship traces)`);
|
|
876
|
+
console.log(` Kratos: ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KRATOS_PUBLIC_PORT)} (public) / ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KRATOS_ADMIN_PORT)} (admin)`);
|
|
877
|
+
console.log(` Keto: ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KETO_READ_PORT)} (read) / ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.KETO_WRITE_PORT)} (write)`);
|
|
878
|
+
console.log(` Hydra: ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.HYDRA_PUBLIC_PORT)} (public) / ${(0, ports_js_1.hostUrl)(configs_js_1.LOCAL_STACK_HOST, configs_js_1.HYDRA_ADMIN_PORT)} (admin)`);
|
|
756
879
|
console.log("");
|
|
757
880
|
console.log("Run 'local seed' to create test data, or 'local env' to print env vars.");
|
|
758
881
|
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-facing addressing for the local Ory stack — which ports it publishes on
|
|
3
|
+
* the host, and which host name everything else should use to reach it.
|
|
4
|
+
*
|
|
5
|
+
* Two kinds of port live in this stack, and conflating them is the bug this
|
|
6
|
+
* module exists to prevent:
|
|
7
|
+
*
|
|
8
|
+
* - **Container-internal ports** are what each service listens on *inside* the
|
|
9
|
+
* compose network, and what one service uses to address another
|
|
10
|
+
* (`http://kratos:4433`). They live on a private bridge network, so they can
|
|
11
|
+
* never collide with anything on the host and there is no reason to make them
|
|
12
|
+
* configurable. They are fixed constants below.
|
|
13
|
+
* - **Host ports** are the left-hand side of a compose `ports:` mapping — the
|
|
14
|
+
* only ports that are actually claimed on the developer's machine, and so the
|
|
15
|
+
* only ones that can collide. Every one of them is overridable.
|
|
16
|
+
*
|
|
17
|
+
* The defaults are the stock upstream Ory ports (4433/4434, 4444/4445,
|
|
18
|
+
* 4466/4467, …), which is deliberate — they are the ports every Ory doc and
|
|
19
|
+
* tutorial uses. It also means a developer who already runs Ory locally, which
|
|
20
|
+
* is precisely this stack's audience, collides on first run. Before #63 there
|
|
21
|
+
* was no override and no diagnosis: `docker compose up` failed with Docker's
|
|
22
|
+
* raw "port is already allocated" and the only apparent fix was to hand-edit
|
|
23
|
+
* the generated compose file, which the next `local up` regenerates away.
|
|
24
|
+
*
|
|
25
|
+
* Three levels of control, cheapest first:
|
|
26
|
+
*
|
|
27
|
+
* 1. `ORY_LOCAL_PORT_OFFSET=100` shifts *every* default by a constant, which is
|
|
28
|
+
* the common case ("something else owns the Ory ports, move the whole
|
|
29
|
+
* stack"). Relative spacing is preserved, so the set stays collision-free
|
|
30
|
+
* with itself.
|
|
31
|
+
* 2. `ORY_LOCAL_<SERVICE>_PORT` pins one service exactly, and wins over the
|
|
32
|
+
* offset.
|
|
33
|
+
* 3. `ORY_LOCAL_HOST` changes the host every generated URL advertises, for a
|
|
34
|
+
* remote Docker daemon or an agent running inside a container. It defaults
|
|
35
|
+
* to the host parsed out of `DOCKER_HOST` when that points somewhere other
|
|
36
|
+
* than this machine, so the remote-daemon case usually needs no flag at all.
|
|
37
|
+
*/
|
|
38
|
+
export declare const KRATOS_PUBLIC_CONTAINER_PORT = 4433;
|
|
39
|
+
export declare const KRATOS_ADMIN_CONTAINER_PORT = 4434;
|
|
40
|
+
export declare const KETO_READ_CONTAINER_PORT = 4466;
|
|
41
|
+
export declare const KETO_WRITE_CONTAINER_PORT = 4467;
|
|
42
|
+
export declare const HYDRA_PUBLIC_CONTAINER_PORT = 4444;
|
|
43
|
+
export declare const HYDRA_ADMIN_CONTAINER_PORT = 4445;
|
|
44
|
+
export declare const HYDRA_TOKEN_USER_CONTAINER_PORT = 5555;
|
|
45
|
+
export declare const GATEWAY_CONTAINER_PORT = 4000;
|
|
46
|
+
export declare const LOGIN_UI_CONTAINER_PORT = 4455;
|
|
47
|
+
export declare const OATHKEEPER_PROXY_CONTAINER_PORT = 4456;
|
|
48
|
+
export declare const OATHKEEPER_API_CONTAINER_PORT = 4457;
|
|
49
|
+
/** Console Lite's Dockerfile sets `ENV PORT=3000`. */
|
|
50
|
+
export declare const CONSOLE_CONTAINER_PORT = 3000;
|
|
51
|
+
/** Every host port the stack publishes, in the order `local status` lists them. */
|
|
52
|
+
export declare const LOCAL_PORT_NAMES: readonly ["gateway", "console", "loginUi", "kratosPublic", "kratosAdmin", "ketoRead", "ketoWrite", "hydraPublic", "hydraAdmin", "hydraTokenUser", "oathkeeperProxy", "oathkeeperApi"];
|
|
53
|
+
export type LocalPortName = (typeof LOCAL_PORT_NAMES)[number];
|
|
54
|
+
export type ResolvedLocalPorts = Record<LocalPortName, number>;
|
|
55
|
+
interface PortSpec {
|
|
56
|
+
/** Default host port — the stock Ory port, and the container port it maps to. */
|
|
57
|
+
default: number;
|
|
58
|
+
/** Env var that pins this port exactly. */
|
|
59
|
+
envVar: string;
|
|
60
|
+
/** Human label used in conflict messages and banners. */
|
|
61
|
+
label: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The port table. `default` doubles as the container-internal port for every
|
|
65
|
+
* service, which is what keeps the generated mapping readable
|
|
66
|
+
* (`"4433:4433"` by default, `"5433:4433"` once overridden).
|
|
67
|
+
*/
|
|
68
|
+
export declare const LOCAL_PORT_SPECS: Record<LocalPortName, PortSpec>;
|
|
69
|
+
/** Shifts every default port by a constant. Overridden per-port by the specific var. */
|
|
70
|
+
export declare const PORT_OFFSET_ENV_VAR = "ORY_LOCAL_PORT_OFFSET";
|
|
71
|
+
/** Overrides the host name every generated URL advertises. */
|
|
72
|
+
export declare const LOCAL_HOST_ENV_VAR = "ORY_LOCAL_HOST";
|
|
73
|
+
/**
|
|
74
|
+
* Skips every port probe — the pre-start preflight *and* the post-failure
|
|
75
|
+
* diagnosis.
|
|
76
|
+
*
|
|
77
|
+
* Both open real sockets, which is the right thing before starting containers
|
|
78
|
+
* and the wrong thing in a unit test (the core suite sets this so no test
|
|
79
|
+
* depends on which ports happen to be free on the machine running it) or in a
|
|
80
|
+
* sandbox that forbids listening. The sandbox case is why this covers the
|
|
81
|
+
* diagnosis too: where binding is denied, `isPortAvailable` answers "taken" for
|
|
82
|
+
* every port, so an unrelated startup failure would otherwise be reported as a
|
|
83
|
+
* confident and completely wrong "every port is in use".
|
|
84
|
+
*/
|
|
85
|
+
export declare const SKIP_PORT_CHECK_ENV_VAR = "ORY_LOCAL_SKIP_PORT_CHECK";
|
|
86
|
+
export declare function portCheckDisabled(env?: Env): boolean;
|
|
87
|
+
type Env = Record<string, string | undefined>;
|
|
88
|
+
/**
|
|
89
|
+
* Resolve every host port from the environment.
|
|
90
|
+
*
|
|
91
|
+
* Invalid values are **ignored with a warning** rather than throwing: this runs
|
|
92
|
+
* on the way into `local up`, and refusing to start because one env var has a
|
|
93
|
+
* typo would be a worse outcome than starting on the documented default and
|
|
94
|
+
* saying so. Warnings are returned rather than printed so the caller controls
|
|
95
|
+
* the output stream.
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveLocalPorts(env?: Env): {
|
|
98
|
+
ports: ResolvedLocalPorts;
|
|
99
|
+
warnings: string[];
|
|
100
|
+
};
|
|
101
|
+
export type LocalHostSource = "env" | "docker-host" | "default";
|
|
102
|
+
export declare const DEFAULT_LOCAL_HOST = "localhost";
|
|
103
|
+
/**
|
|
104
|
+
* Pull the host out of a `DOCKER_HOST` value.
|
|
105
|
+
*
|
|
106
|
+
* `unix://` and `npipe://` sockets are this machine, so they yield nothing and
|
|
107
|
+
* the default stands. A `tcp://` or `ssh://` daemon publishes the stack's ports
|
|
108
|
+
* on *its* host, not ours, so that host is what generated URLs have to
|
|
109
|
+
* advertise — otherwise every URL we print and persist points at a machine that
|
|
110
|
+
* isn't running the stack.
|
|
111
|
+
*/
|
|
112
|
+
export declare function hostFromDockerHost(dockerHost: string | undefined): string | undefined;
|
|
113
|
+
export declare function isLoopbackHost(host: string): boolean;
|
|
114
|
+
/**
|
|
115
|
+
* The host name every generated URL should advertise: config files, banners,
|
|
116
|
+
* the health probe, and the `projectUrl` that `local configure` persists.
|
|
117
|
+
*/
|
|
118
|
+
export declare function resolveLocalHost(env?: Env): {
|
|
119
|
+
host: string;
|
|
120
|
+
source: LocalHostSource;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* True when the Docker daemon publishes ports on *this* machine, which is the
|
|
124
|
+
* only case where probing a local socket says anything about whether the stack
|
|
125
|
+
* will be able to bind. With a remote daemon the probe would test the wrong
|
|
126
|
+
* host, so callers skip the preflight entirely rather than report a conflict
|
|
127
|
+
* that isn't there (or miss one that is).
|
|
128
|
+
*/
|
|
129
|
+
export declare function isLocalDockerDaemon(env?: Env): boolean;
|
|
130
|
+
/** Build an `http://host:port` origin, bracketing bare IPv6 literals. */
|
|
131
|
+
export declare function hostUrl(host: string, port: number): string;
|
|
132
|
+
export interface PortConflict {
|
|
133
|
+
name: LocalPortName;
|
|
134
|
+
port: number;
|
|
135
|
+
label: string;
|
|
136
|
+
envVar: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Can we bind this port? Docker publishes on all interfaces, so we test the
|
|
140
|
+
* same thing it will do. A port held on loopback alone still fails a
|
|
141
|
+
* wildcard bind, so this catches both.
|
|
142
|
+
*
|
|
143
|
+
* Anything other than a clean listen counts as unavailable: `EADDRINUSE` is the
|
|
144
|
+
* case we are looking for, and `EACCES` (a privileged port without rights)
|
|
145
|
+
* would fail the container just the same.
|
|
146
|
+
*/
|
|
147
|
+
export declare function isPortAvailable(port: number, timeoutMs?: number): Promise<boolean>;
|
|
148
|
+
/**
|
|
149
|
+
* Which of the stack's host ports are already taken. Probed concurrently —
|
|
150
|
+
* twelve sequential binds would add noticeable latency to every `local up`.
|
|
151
|
+
*/
|
|
152
|
+
export declare function findPortConflicts(ports: ResolvedLocalPorts): Promise<PortConflict[]>;
|
|
153
|
+
/**
|
|
154
|
+
* The message a user gets instead of Docker's "port is already allocated":
|
|
155
|
+
* which service wanted which port, and the two ways to move it.
|
|
156
|
+
*/
|
|
157
|
+
export declare function describePortConflicts(conflicts: PortConflict[]): string;
|
|
158
|
+
export {};
|