@open-everywhere/adapters 0.1.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.
Files changed (156) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +21 -0
  3. package/README.md +43 -0
  4. package/agent/aws/cli.ts +121 -0
  5. package/agent/aws/config.ts +71 -0
  6. package/agent/aws/register.ts +65 -0
  7. package/agent/aws/sso.ts +567 -0
  8. package/agent/aws/sts.ts +191 -0
  9. package/agent/blob/hosting.ts +24 -0
  10. package/agent/browser/config.ts +62 -0
  11. package/agent/browser/register.ts +66 -0
  12. package/agent/browser/sandbox.ts +39 -0
  13. package/agent/contributions.ts +12 -0
  14. package/agent/directory/config.ts +138 -0
  15. package/agent/directory/okta.ts +226 -0
  16. package/agent/directory/register.ts +16 -0
  17. package/agent/instrumentation.ts +42 -0
  18. package/agent/model/approval-judge.ts +57 -0
  19. package/agent/model/dream-judge.ts +105 -0
  20. package/agent/model/gateway-vision.ts +162 -0
  21. package/agent/model/gateway.ts +85 -0
  22. package/agent/oe-oauth/config.ts +246 -0
  23. package/agent/oe-oauth/errors.ts +77 -0
  24. package/agent/oe-oauth/oauth-client.ts +376 -0
  25. package/agent/oe-oauth/pkce.ts +21 -0
  26. package/agent/oe-oauth/register.ts +32 -0
  27. package/agent/oe-oauth/token-vault.ts +652 -0
  28. package/agent/oe-oauth/user-auth-flow.ts +76 -0
  29. package/agent/postgres/neon.ts +108 -0
  30. package/agent/sandbox/backend-stop.ts +259 -0
  31. package/agent/sandbox/created-sandbox-registry.ts +27 -0
  32. package/agent/sandbox/extend-workspace-time.ts +77 -0
  33. package/agent/sandbox/vercel-lifecycle.ts +252 -0
  34. package/dist/agent/aws/cli.d.ts +24 -0
  35. package/dist/agent/aws/cli.d.ts.map +1 -0
  36. package/dist/agent/aws/cli.js +89 -0
  37. package/dist/agent/aws/cli.js.map +1 -0
  38. package/dist/agent/aws/config.d.ts +27 -0
  39. package/dist/agent/aws/config.d.ts.map +1 -0
  40. package/dist/agent/aws/config.js +46 -0
  41. package/dist/agent/aws/config.js.map +1 -0
  42. package/dist/agent/aws/register.d.ts +23 -0
  43. package/dist/agent/aws/register.d.ts.map +1 -0
  44. package/dist/agent/aws/register.js +39 -0
  45. package/dist/agent/aws/register.js.map +1 -0
  46. package/dist/agent/aws/sso.d.ts +109 -0
  47. package/dist/agent/aws/sso.d.ts.map +1 -0
  48. package/dist/agent/aws/sso.js +421 -0
  49. package/dist/agent/aws/sso.js.map +1 -0
  50. package/dist/agent/aws/sts.d.ts +27 -0
  51. package/dist/agent/aws/sts.d.ts.map +1 -0
  52. package/dist/agent/aws/sts.js +135 -0
  53. package/dist/agent/aws/sts.js.map +1 -0
  54. package/dist/agent/blob/hosting.d.ts +4 -0
  55. package/dist/agent/blob/hosting.d.ts.map +1 -0
  56. package/dist/agent/blob/hosting.js +20 -0
  57. package/dist/agent/blob/hosting.js.map +1 -0
  58. package/dist/agent/browser/config.d.ts +24 -0
  59. package/dist/agent/browser/config.d.ts.map +1 -0
  60. package/dist/agent/browser/config.js +50 -0
  61. package/dist/agent/browser/config.js.map +1 -0
  62. package/dist/agent/browser/register.d.ts +7 -0
  63. package/dist/agent/browser/register.d.ts.map +1 -0
  64. package/dist/agent/browser/register.js +47 -0
  65. package/dist/agent/browser/register.js.map +1 -0
  66. package/dist/agent/browser/sandbox.d.ts +23 -0
  67. package/dist/agent/browser/sandbox.d.ts.map +1 -0
  68. package/dist/agent/browser/sandbox.js +27 -0
  69. package/dist/agent/browser/sandbox.js.map +1 -0
  70. package/dist/agent/contributions.d.ts +16 -0
  71. package/dist/agent/contributions.d.ts.map +1 -0
  72. package/dist/agent/contributions.js +11 -0
  73. package/dist/agent/contributions.js.map +1 -0
  74. package/dist/agent/directory/config.d.ts +39 -0
  75. package/dist/agent/directory/config.d.ts.map +1 -0
  76. package/dist/agent/directory/config.js +101 -0
  77. package/dist/agent/directory/config.js.map +1 -0
  78. package/dist/agent/directory/okta.d.ts +19 -0
  79. package/dist/agent/directory/okta.d.ts.map +1 -0
  80. package/dist/agent/directory/okta.js +178 -0
  81. package/dist/agent/directory/okta.js.map +1 -0
  82. package/dist/agent/directory/register.d.ts +6 -0
  83. package/dist/agent/directory/register.d.ts.map +1 -0
  84. package/dist/agent/directory/register.js +16 -0
  85. package/dist/agent/directory/register.js.map +1 -0
  86. package/dist/agent/instrumentation.d.ts +5 -0
  87. package/dist/agent/instrumentation.d.ts.map +1 -0
  88. package/dist/agent/instrumentation.js +39 -0
  89. package/dist/agent/instrumentation.js.map +1 -0
  90. package/dist/agent/model/approval-judge.d.ts +15 -0
  91. package/dist/agent/model/approval-judge.d.ts.map +1 -0
  92. package/dist/agent/model/approval-judge.js +46 -0
  93. package/dist/agent/model/approval-judge.js.map +1 -0
  94. package/dist/agent/model/dream-judge.d.ts +40 -0
  95. package/dist/agent/model/dream-judge.d.ts.map +1 -0
  96. package/dist/agent/model/dream-judge.js +80 -0
  97. package/dist/agent/model/dream-judge.js.map +1 -0
  98. package/dist/agent/model/gateway-vision.d.ts +53 -0
  99. package/dist/agent/model/gateway-vision.d.ts.map +1 -0
  100. package/dist/agent/model/gateway-vision.js +129 -0
  101. package/dist/agent/model/gateway-vision.js.map +1 -0
  102. package/dist/agent/model/gateway.d.ts +30 -0
  103. package/dist/agent/model/gateway.d.ts.map +1 -0
  104. package/dist/agent/model/gateway.js +55 -0
  105. package/dist/agent/model/gateway.js.map +1 -0
  106. package/dist/agent/oe-oauth/config.d.ts +69 -0
  107. package/dist/agent/oe-oauth/config.d.ts.map +1 -0
  108. package/dist/agent/oe-oauth/config.js +182 -0
  109. package/dist/agent/oe-oauth/config.js.map +1 -0
  110. package/dist/agent/oe-oauth/errors.d.ts +63 -0
  111. package/dist/agent/oe-oauth/errors.d.ts.map +1 -0
  112. package/dist/agent/oe-oauth/errors.js +73 -0
  113. package/dist/agent/oe-oauth/errors.js.map +1 -0
  114. package/dist/agent/oe-oauth/oauth-client.d.ts +124 -0
  115. package/dist/agent/oe-oauth/oauth-client.d.ts.map +1 -0
  116. package/dist/agent/oe-oauth/oauth-client.js +262 -0
  117. package/dist/agent/oe-oauth/oauth-client.js.map +1 -0
  118. package/dist/agent/oe-oauth/pkce.d.ts +8 -0
  119. package/dist/agent/oe-oauth/pkce.d.ts.map +1 -0
  120. package/dist/agent/oe-oauth/pkce.js +18 -0
  121. package/dist/agent/oe-oauth/pkce.js.map +1 -0
  122. package/dist/agent/oe-oauth/register.d.ts +17 -0
  123. package/dist/agent/oe-oauth/register.d.ts.map +1 -0
  124. package/dist/agent/oe-oauth/register.js +24 -0
  125. package/dist/agent/oe-oauth/register.js.map +1 -0
  126. package/dist/agent/oe-oauth/token-vault.d.ts +107 -0
  127. package/dist/agent/oe-oauth/token-vault.d.ts.map +1 -0
  128. package/dist/agent/oe-oauth/token-vault.js +498 -0
  129. package/dist/agent/oe-oauth/token-vault.js.map +1 -0
  130. package/dist/agent/oe-oauth/user-auth-flow.d.ts +10 -0
  131. package/dist/agent/oe-oauth/user-auth-flow.d.ts.map +1 -0
  132. package/dist/agent/oe-oauth/user-auth-flow.js +66 -0
  133. package/dist/agent/oe-oauth/user-auth-flow.js.map +1 -0
  134. package/dist/agent/postgres/neon.d.ts +29 -0
  135. package/dist/agent/postgres/neon.d.ts.map +1 -0
  136. package/dist/agent/postgres/neon.js +76 -0
  137. package/dist/agent/postgres/neon.js.map +1 -0
  138. package/dist/agent/sandbox/backend-stop.d.ts +98 -0
  139. package/dist/agent/sandbox/backend-stop.d.ts.map +1 -0
  140. package/dist/agent/sandbox/backend-stop.js +188 -0
  141. package/dist/agent/sandbox/backend-stop.js.map +1 -0
  142. package/dist/agent/sandbox/created-sandbox-registry.d.ts +15 -0
  143. package/dist/agent/sandbox/created-sandbox-registry.d.ts.map +1 -0
  144. package/dist/agent/sandbox/created-sandbox-registry.js +26 -0
  145. package/dist/agent/sandbox/created-sandbox-registry.js.map +1 -0
  146. package/dist/agent/sandbox/extend-workspace-time.d.ts +31 -0
  147. package/dist/agent/sandbox/extend-workspace-time.d.ts.map +1 -0
  148. package/dist/agent/sandbox/extend-workspace-time.js +63 -0
  149. package/dist/agent/sandbox/extend-workspace-time.js.map +1 -0
  150. package/dist/agent/sandbox/vercel-lifecycle.d.ts +38 -0
  151. package/dist/agent/sandbox/vercel-lifecycle.d.ts.map +1 -0
  152. package/dist/agent/sandbox/vercel-lifecycle.js +244 -0
  153. package/dist/agent/sandbox/vercel-lifecycle.js.map +1 -0
  154. package/package.json +204 -0
  155. package/tsconfig.build.json +22 -0
  156. package/tsconfig.json +22 -0
@@ -0,0 +1,135 @@
1
+ // The AWS-IDENTITY provider adapter — the ONE place OIDC→STS federation is named. Zero npm deps: the
2
+ // web-identity token IS the auth, so the STS call is an unsigned form POST. A failure throws, never empty.
3
+ import { warmCredential } from "@open-everywhere/core/agent/adapter-api.js";
4
+ import { readFileSync } from "node:fs";
5
+ /** Env var naming the OIDC token file (AWS-standard, set by Vercel/IRSA/projected SA token). */
6
+ const AWS_WEB_IDENTITY_TOKEN_FILE_ENV = "AWS_WEB_IDENTITY_TOKEN_FILE";
7
+ /** OE fallback: the raw OIDC token inline (no file), used only when the file env is absent. */
8
+ const OE_AWS_WEB_IDENTITY_TOKEN_ENV = "OE_AWS_WEB_IDENTITY_TOKEN";
9
+ /** Minimal single-tag extract from an AWS XML response — deliberately NOT an XML dependency (the four
10
+ * fields we need are flat, non-nested leaf tags). Returns the first tag body, trimmed, or undefined. */
11
+ function xmlTag(xml, tag) {
12
+ const m = xml.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "u"));
13
+ return m?.[1]?.trim();
14
+ }
15
+ /** Resolve the region for a mint: the grant's region, then the operator default (OE_AWS_REGION),
16
+ * then AWS_REGION, then us-east-1. */
17
+ function regionFor(req, defaultRegion) {
18
+ return req.region ?? defaultRegion ?? process.env.AWS_REGION ?? "us-east-1";
19
+ }
20
+ /** Read the deployment's OIDC web-identity token: the file named by AWS_WEB_IDENTITY_TOKEN_FILE
21
+ * (fail LOUD if unreadable), else the inline OE_AWS_WEB_IDENTITY_TOKEN, else throw. */
22
+ function readWebIdentityToken(readTokenFile) {
23
+ const path = process.env[AWS_WEB_IDENTITY_TOKEN_FILE_ENV]?.trim();
24
+ if (path) {
25
+ let raw;
26
+ try {
27
+ raw = readTokenFile(path);
28
+ }
29
+ catch (err) {
30
+ throw new Error(`AWS OIDC token file (${AWS_WEB_IDENTITY_TOKEN_FILE_ENV}=${path}) is unreadable: ${err instanceof Error ? err.message : String(err)}. Fail-closed: no AWS access.`);
31
+ }
32
+ const token = raw.trim();
33
+ if (!token)
34
+ throw new Error(`AWS OIDC token file (${path}) is empty. Fail-closed: no AWS access.`);
35
+ return token;
36
+ }
37
+ const inline = process.env[OE_AWS_WEB_IDENTITY_TOKEN_ENV]?.trim();
38
+ if (inline)
39
+ return inline;
40
+ throw new Error(`no AWS OIDC token available — set ${AWS_WEB_IDENTITY_TOKEN_FILE_ENV} (the deployment's web-identity ` +
41
+ `token file) or ${OE_AWS_WEB_IDENTITY_TOKEN_ENV}. Fail-closed: no AWS access.`);
42
+ }
43
+ /** Federate the OIDC token into STS credentials via an UNSIGNED AssumeRoleWithWebIdentity POST. Throws
44
+ * (never returns empty) on a transport error, a non-2xx STS response, an `<Error>` body, or a
45
+ * response missing any of the four credential fields. */
46
+ async function assumeRoleWithWebIdentity(req, fetchImpl, readTokenFile, durationSeconds, defaultRegion) {
47
+ const token = readWebIdentityToken(readTokenFile);
48
+ const region = regionFor(req, defaultRegion);
49
+ const endpoint = `https://sts.${region}.amazonaws.com/`;
50
+ const body = new URLSearchParams({
51
+ Action: "AssumeRoleWithWebIdentity",
52
+ Version: "2011-06-15",
53
+ RoleArn: req.roleArn,
54
+ RoleSessionName: req.roleSessionName,
55
+ WebIdentityToken: token,
56
+ DurationSeconds: String(durationSeconds),
57
+ // The STS SESSION POLICY (OPE-296 §8.3) — the grant's allow grammar compiled by core
58
+ // (access/aws-screen.ts) and INTERSECTED with the role's own policy at mint time, so the
59
+ // narrowing is AWS-enforced, not merely host-checked. Only this path can take one: the
60
+ // per-user sso:GetRoleCredentials API has no session-policy parameter (sso.ts).
61
+ ...(req.sessionPolicy !== undefined ? { Policy: req.sessionPolicy } : {}),
62
+ });
63
+ let res;
64
+ try {
65
+ res = await fetchImpl(endpoint, {
66
+ method: "POST",
67
+ headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/xml" },
68
+ body: body.toString(),
69
+ });
70
+ }
71
+ catch (err) {
72
+ throw new Error(`STS AssumeRoleWithWebIdentity transport error against ${endpoint}: ${err instanceof Error ? err.message : String(err)}. Fail-closed: no AWS access.`);
73
+ }
74
+ const text = await res.text();
75
+ if (!res.ok || xmlTag(text, "Error") !== undefined || /<ErrorResponse[\s>]/u.test(text)) {
76
+ const code = xmlTag(text, "Code");
77
+ const message = xmlTag(text, "Message");
78
+ throw new Error(`STS AssumeRoleWithWebIdentity failed (HTTP ${res.status}${code ? `, ${code}` : ""})${message ? `: ${message}` : `: ${text.slice(0, 300)}`}. Fail-closed: no AWS access.`);
79
+ }
80
+ const accessKeyId = xmlTag(text, "AccessKeyId");
81
+ const secretAccessKey = xmlTag(text, "SecretAccessKey");
82
+ const sessionToken = xmlTag(text, "SessionToken");
83
+ const expiration = xmlTag(text, "Expiration");
84
+ if (!accessKeyId || !secretAccessKey || !sessionToken) {
85
+ throw new Error(`STS response missing credential fields (AccessKeyId/SecretAccessKey/SessionToken): ${text.slice(0, 300)}. Fail-closed: no AWS access.`);
86
+ }
87
+ const expiresAtMs = expiration ? Date.parse(expiration) : NaN;
88
+ return {
89
+ accessKeyId,
90
+ secretAccessKey,
91
+ sessionToken,
92
+ ...(Number.isFinite(expiresAtMs) ? { expiresAtMs } : {}),
93
+ };
94
+ }
95
+ /**
96
+ * Build the STS-federation identity provider. The warm cache is keyed by kind, org, roleArn, roleSessionName,
97
+ * principalSubject and sessionPolicy — drop any one and a caller silently receives another caller's creds.
98
+ */
99
+ export function makeAwsStsProvider(opts = {}) {
100
+ const fetchImpl = opts.fetch ?? fetch;
101
+ const readTokenFile = opts.readTokenFile ?? ((path) => readFileSync(path, "utf-8"));
102
+ const durationSeconds = opts.durationSeconds ?? 3600;
103
+ const defaultRegion = opts.defaultRegion;
104
+ const mintUserSso = opts.mintUserSso;
105
+ // Cache holds the JSON-serialised AwsCredentials as the warm-seam `value`, stamped with the STS
106
+ // `Expiration` so the seam refreshes ahead of it (fallback TTL = the requested duration).
107
+ const warm = warmCredential({
108
+ name: "aws.sts-web-identity",
109
+ platform: "aws",
110
+ auditAction: "aws.sts.mint_failed",
111
+ refresh: "re-mint",
112
+ fallbackTtlSeconds: durationSeconds,
113
+ // Every component earns its place — see the constructor's docblock for what each one separates.
114
+ key: (req) => `${req.kind}:${req.org ?? ""}:${req.roleArn}:${req.roleSessionName}:${req.principalSubject ?? ""}:${req.sessionPolicy ?? ""}`,
115
+ mint: async (req) => {
116
+ const creds = await assumeRoleWithWebIdentity(req, fetchImpl, readTokenFile, durationSeconds, defaultRegion);
117
+ return { value: JSON.stringify(creds), ...(creds.expiresAtMs !== undefined ? { expiresAtMs: creds.expiresAtMs } : {}) };
118
+ },
119
+ });
120
+ return {
121
+ async mint(req) {
122
+ if (req.kind === "user-sso") {
123
+ // Phase 1 (per-user AWS SSO linking): delegate to the Identity Center minter when wired. Absent
124
+ // ⇒ refuse clearly rather than attempt a flow (the domain-role STS path stays available).
125
+ if (mintUserSso)
126
+ return mintUserSso(req);
127
+ throw new Error("AWS SSO per-user identity linking is not configured (Phase 1). " +
128
+ "Use the domain role.");
129
+ }
130
+ const serialised = await warm.get(req);
131
+ return JSON.parse(serialised);
132
+ },
133
+ };
134
+ }
135
+ //# sourceMappingURL=sts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sts.js","sourceRoot":"","sources":["../../../agent/aws/sts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { BlobPutter } from "@open-everywhere/core/agent/adapter-api.js";
2
+ /** The real putter — `put` with public access, OIDC auth and a random filename suffix. */
3
+ export declare const vercelBlobPutter: BlobPutter;
4
+ //# sourceMappingURL=hosting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosting.d.ts","sourceRoot":"","sources":["../../../agent/blob/hosting.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4CAA4C,CAAC;AAE7E,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,EAAE,UAiB9B,CAAC"}
@@ -0,0 +1,20 @@
1
+ // Vercel Blob putter — the vendor half of core's BlobPutter seam. Auth is OIDC and never a read-write token;
2
+ // with the OIDC env absent it FAILS LOUD, because an opted-in unconfigured deployment is a misconfiguration.
3
+ /** The real putter — `put` with public access, OIDC auth and a random filename suffix. */
4
+ export const vercelBlobPutter = async ({ pathname, body, contentType }) => {
5
+ if (!process.env.VERCEL_OIDC_TOKEN || !process.env.BLOB_STORE_ID) {
6
+ throw new Error("blob hosting is opted in but not configured — VERCEL_OIDC_TOKEN and BLOB_STORE_ID must be present " +
7
+ "(Vercel populates them once a Blob store is connected to this project). This deployment writes Blobs " +
8
+ "via OIDC, never a BLOB_READ_WRITE_TOKEN.");
9
+ }
10
+ // Dynamic import keeps the vendor SDK off any bundling path that never hosts an artifact
11
+ // (same discipline as post_file's node:fs import). OIDC creds are read from the environment.
12
+ const { put } = await import("@vercel/blob");
13
+ const res = await put(pathname, Buffer.from(body), {
14
+ access: "public",
15
+ contentType,
16
+ addRandomSuffix: true, // namespace safety inside the reserved prefix — no collisions/guessing.
17
+ });
18
+ return { url: res.url };
19
+ };
20
+ //# sourceMappingURL=hosting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosting.js","sourceRoot":"","sources":["../../../agent/blob/hosting.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,6GAA6G;AAI7G,0FAA0F;AAC1F,MAAM,CAAC,MAAM,gBAAgB,GAAe,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE;IACpF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CACb,oGAAoG;YAClG,uGAAuG;YACvG,0CAA0C,CAC7C,CAAC;IACJ,CAAC;IACD,yFAAyF;IACzF,6FAA6F;IAC7F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACjD,MAAM,EAAE,QAAQ;QAChB,WAAW;QACX,eAAe,EAAE,IAAI,EAAE,wEAAwE;KAChG,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;AAC1B,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type BrowserHostDeclaration } from "@open-everywhere/core/agent/adapter-api.js";
2
+ export interface AgentBrowserConfig {
3
+ /** The operator's declared browse targets — the whole reach of the capability. */
4
+ readonly hosts: readonly BrowserHostDeclaration[];
5
+ /** Just the hostnames, in declaration order: what agent-browser's `--allowed-domains` wants. */
6
+ readonly domains: readonly string[];
7
+ }
8
+ /** Is the master flag armed? */
9
+ export declare function agentBrowserEnabled(): boolean;
10
+ /**
11
+ * Resolve the armed config, or undefined when the capability must stay off; an empty declaration logs LOUDLY
12
+ * once. Memoized. A MALFORMED declaration never reaches here — `defineBrowserHosts` throws at module load.
13
+ *
14
+ * 🔴 IT IS THE PLATFORM GATE FOR THE WHOLE PLANE (OPE-1793). Every arming path reads this one config —
15
+ * the tool mount and the egress-host opening (agent/lib/register-adapters.ts → browser/register.ts) and
16
+ * the sandbox bake (browser/sandbox.ts) — so refusing HERE is what makes the plane fail closed off
17
+ * Vercel on all three at once. It previously refused only the BAKE, and a self-host deployment with
18
+ * `browser.enabled: true` then mounted all 20 `browser_*` tools and opened the declared egress hosts
19
+ * for a browser that cannot run.
20
+ */
21
+ export declare function loadAgentBrowserConfig(): AgentBrowserConfig | undefined;
22
+ /** TEST SEAM: drop the memoized config so a test can vary the declaration. */
23
+ export declare function resetAgentBrowserConfigForTest(): void;
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../agent/browser/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6D,KAAK,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAMpJ,MAAM,WAAW,kBAAkB;IACjC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAC;IAClD,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,gCAAgC;AAChC,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI,kBAAkB,GAAG,SAAS,CAoBvE;AAED,8EAA8E;AAC9E,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
@@ -0,0 +1,50 @@
1
+ // The agent-browser config, parsed FAIL-CLOSED: the flag arms the plane and the HOST DECLARATION is its
2
+ // reach. Flag on with an EMPTY declaration does NOT arm. A loopback target must still be declared.
3
+ import { getSettings, browserHostDeclarations, browserPlaneRefusal } from "@open-everywhere/core/agent/adapter-api.js";
4
+ // The master flag is a BEHAVIOUR SETTING (OPE-371 t2). Docs, tests and the loud misconfiguration
5
+ // message quote this exact STRING, so the name below holds it once for this module.
6
+ const AGENT_BROWSER_FLAG = "browser.enabled";
7
+ /** Is the master flag armed? */
8
+ export function agentBrowserEnabled() {
9
+ return getSettings().browser.enabled;
10
+ }
11
+ let cached;
12
+ let cachedResolved = false;
13
+ /**
14
+ * Resolve the armed config, or undefined when the capability must stay off; an empty declaration logs LOUDLY
15
+ * once. Memoized. A MALFORMED declaration never reaches here — `defineBrowserHosts` throws at module load.
16
+ *
17
+ * 🔴 IT IS THE PLATFORM GATE FOR THE WHOLE PLANE (OPE-1793). Every arming path reads this one config —
18
+ * the tool mount and the egress-host opening (agent/lib/register-adapters.ts → browser/register.ts) and
19
+ * the sandbox bake (browser/sandbox.ts) — so refusing HERE is what makes the plane fail closed off
20
+ * Vercel on all three at once. It previously refused only the BAKE, and a self-host deployment with
21
+ * `browser.enabled: true` then mounted all 20 `browser_*` tools and opened the declared egress hosts
22
+ * for a browser that cannot run.
23
+ */
24
+ export function loadAgentBrowserConfig() {
25
+ if (cachedResolved)
26
+ return cached;
27
+ cachedResolved = true;
28
+ cached = undefined;
29
+ if (!agentBrowserEnabled())
30
+ return undefined;
31
+ const refusal = browserPlaneRefusal();
32
+ if (refusal !== undefined) {
33
+ console.error(`[open-everywhere:agent-browser] ${AGENT_BROWSER_FLAG}: true but ${refusal} NOT arming (fail closed): no tools mount, no egress host opens, no browser bakes.`);
34
+ return undefined;
35
+ }
36
+ const hosts = browserHostDeclarations();
37
+ if (hosts.length === 0) {
38
+ console.error(`[open-everywhere:agent-browser] ${AGENT_BROWSER_FLAG}: true but no browser host is declared — NOT arming (fail closed). ` +
39
+ "Declare the browse targets in agent/access/browser-hosts.ts.");
40
+ return undefined;
41
+ }
42
+ cached = { hosts, domains: hosts.map((h) => h.host) };
43
+ return cached;
44
+ }
45
+ /** TEST SEAM: drop the memoized config so a test can vary the declaration. */
46
+ export function resetAgentBrowserConfigForTest() {
47
+ cached = undefined;
48
+ cachedResolved = false;
49
+ }
50
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../agent/browser/config.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,mGAAmG;AAEnG,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,mBAAmB,EAA+B,MAAM,4CAA4C,CAAC;AAEpJ,iGAAiG;AACjG,oFAAoF;AACpF,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAS7C,gCAAgC;AAChC,MAAM,UAAU,mBAAmB;IACjC,OAAO,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;AACvC,CAAC;AAED,IAAI,MAAsC,CAAC;AAC3C,IAAI,cAAc,GAAG,KAAK,CAAC;AAE3B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB;IACpC,IAAI,cAAc;QAAE,OAAO,MAAM,CAAC;IAClC,cAAc,GAAG,IAAI,CAAC;IACtB,MAAM,GAAG,SAAS,CAAC;IACnB,IAAI,CAAC,mBAAmB,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,mCAAmC,kBAAkB,cAAc,OAAO,oFAAoF,CAAC,CAAC;QAC9K,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,uBAAuB,EAAE,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CACX,mCAAmC,kBAAkB,qEAAqE;YACxH,8DAA8D,CACjE,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACtD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,8BAA8B;IAC5C,MAAM,GAAG,SAAS,CAAC;IACnB,cAAc,GAAG,KAAK,CAAC;AACzB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type AgentBrowserConfig } from "./config.js";
2
+ /**
3
+ * Arm the toolkit for a validated config. Returns false, LOUDLY, when the extension-config binding did not
4
+ * take: unbound tools would run auto-install on and UNCONTAINED, so they are not registered at all.
5
+ */
6
+ export declare function registerAgentBrowser(cfg: AgentBrowserConfig): boolean;
7
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../agent/browser/register.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAUtD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CA6CrE"}
@@ -0,0 +1,47 @@
1
+ // The agent-browser adapter — flag-gated and FAIL-CLOSED, so flag-off is byte-identical. Containment is two
2
+ // walls: the vendor's allowed-domains, and the egress firewall where a declared credential is stamped.
3
+ import browserExtension from "@agent-browser/eve";
4
+ import * as vendorTools from "@agent-browser/eve/tools";
5
+ import { registerBrowserToolkit, openBrowserEgressHosts, isLoopbackBrowseHost } from "@open-everywhere/core/agent/adapter-api.js";
6
+ /**
7
+ * Arm the toolkit for a validated config. Returns false, LOUDLY, when the extension-config binding did not
8
+ * take: unbound tools would run auto-install on and UNCONTAINED, so they are not registered at all.
9
+ */
10
+ export function registerAgentBrowser(cfg) {
11
+ browserExtension({
12
+ allowedDomains: [...cfg.domains],
13
+ autoInstall: false,
14
+ contentBoundaries: true,
15
+ inlineScreenshots: false,
16
+ });
17
+ const bound = browserExtension.config;
18
+ const domainsBound = Array.isArray(bound.allowedDomains) &&
19
+ bound.allowedDomains.length === cfg.domains.length &&
20
+ cfg.domains.every((d, i) => bound.allowedDomains[i] === d);
21
+ if (bound.autoInstall !== false || !domainsBound) {
22
+ console.error("[open-everywhere:agent-browser] extension config binding FAILED (namespace patch missing? see patches/@agent-browser+eve+*.patch) — " +
23
+ "REFUSING to arm the browser toolkit: unbound tools would run with vendor defaults (auto-install on, no domain containment).");
24
+ return false;
25
+ }
26
+ // Mount every vendor tool under `browser_<name>` (single underscore — `__` is the
27
+ // connector-op separator). Guard structurally: only defineTool-shaped exports ride.
28
+ const entries = {};
29
+ for (const [name, tool] of Object.entries(vendorTools)) {
30
+ const t = tool;
31
+ if (t && typeof t.execute === "function" && typeof t.description === "string") {
32
+ entries[`browser_${name}`] = t;
33
+ }
34
+ }
35
+ registerBrowserToolkit(entries);
36
+ // The outer wall's UNCREDENTIALED half: only a row declaring no credential rides this bare allow. A
37
+ // credentialed row is compiled by access/egress.ts — registering it here drops its narrowing and credential.
38
+ // 🔴 THROUGH CORE'S OWN OPENER (OPE-1793), which carries the platform refusal, so the hosts cannot open
39
+ // on a platform with no browser even if a registrar reached here without the config loader's gate.
40
+ openBrowserEgressHosts(cfg.hosts.filter((h) => h.credential === undefined && !isLoopbackBrowseHost(h.host)).map((h) => h.host));
41
+ const credentialed = cfg.hosts.filter((h) => h.credential !== undefined).length;
42
+ console.log(`[open-everywhere:agent-browser] armed: ${Object.keys(entries).length} browser tools, ` +
43
+ `hosts [${cfg.domains.join(", ")}] (${credentialed} credentialed at the firewall) ` +
44
+ `(containment: agent-browser allowed-domains + egress firewall)`);
45
+ return true;
46
+ }
47
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../agent/browser/register.ts"],"names":[],"mappings":"AAAA,4GAA4G;AAC5G,uGAAuG;AAEvG,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,WAAW,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,oBAAoB,EAAyB,MAAM,4CAA4C,CAAC;AAWzJ;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAuB;IAC1D,gBAAgB,CAAC;QACf,cAAc,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;QAChC,WAAW,EAAE,KAAK;QAClB,iBAAiB,EAAE,IAAI;QACvB,iBAAiB,EAAE,KAAK;KACzB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAuC,CAAC;IACvE,MAAM,YAAY,GAChB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;QACnC,KAAK,CAAC,cAAc,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,MAAM;QAClD,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,cAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CACX,sIAAsI;YACpI,6HAA6H,CAChI,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kFAAkF;IAClF,oFAAoF;IACpF,MAAM,OAAO,GAAqC,EAAE,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,GAAG,IAA6C,CAAC;QACxD,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC9E,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,GAAG,CAAqB,CAAC;QACrD,CAAC;IACH,CAAC;IACD,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,oGAAoG;IACpG,6GAA6G;IAC7G,wGAAwG;IACxG,mGAAmG;IACnG,sBAAsB,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhI,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAChF,OAAO,CAAC,GAAG,CACT,0CAA0C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,kBAAkB;QACrF,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,YAAY,iCAAiC;QACnF,gEAAgE,CACnE,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,23 @@
1
+ /** Minimal structural sandbox the installer needs (matches @agent-browser/eve's EveSandboxSession). */
2
+ export interface BakeableSandbox {
3
+ readonly id: string;
4
+ run(options: {
5
+ readonly command: string;
6
+ }): PromiseLike<{
7
+ readonly exitCode?: number;
8
+ readonly stderr?: string;
9
+ readonly stdout?: string;
10
+ }>;
11
+ }
12
+ export interface AgentBrowserSandboxHooks {
13
+ readonly revalidationKey: () => string;
14
+ readonly bootstrap: (input: {
15
+ use: () => Promise<BakeableSandbox>;
16
+ }) => Promise<void>;
17
+ }
18
+ /**
19
+ * The flag-gated sandbox hook pair. Injectable install fn for the unit test (the default is the
20
+ * vendor installer: system deps → `npm install -g agent-browser@<pinned>` → `agent-browser install`).
21
+ */
22
+ export declare function agentBrowserSandboxHooks(install?: (sandbox: BakeableSandbox) => Promise<unknown>): AgentBrowserSandboxHooks | Record<string, never>;
23
+ //# sourceMappingURL=sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../../agent/browser/sandbox.ts"],"names":[],"mappings":"AAMA,uGAAuG;AACvG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW,CAAC;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7I;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,MAAM,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvF;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAA6C,GAClG,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAelD"}
@@ -0,0 +1,27 @@
1
+ // The agent-browser sandbox pre-bake — Vercel-only, and mandatory: a session sits behind the deny-all egress
2
+ // firewall, so no mid-turn install can work. eve freezes `revalidationKey` at BUILD, so arm it there too.
3
+ import { agentBrowserRevalidationKey, installAgentBrowser } from "@agent-browser/eve/sandbox";
4
+ import { agentBrowserEnabled, loadAgentBrowserConfig } from "./config.js";
5
+ /**
6
+ * The flag-gated sandbox hook pair. Injectable install fn for the unit test (the default is the
7
+ * vendor installer: system deps → `npm install -g agent-browser@<pinned>` → `agent-browser install`).
8
+ */
9
+ export function agentBrowserSandboxHooks(install = (sandbox) => installAgentBrowser(sandbox)) {
10
+ if (!agentBrowserEnabled())
11
+ return {};
12
+ // 🔴 ONE ROAD, NOT TWO (OPE-1793). The platform refusal lives in the config loader, which every
13
+ // arming path reads, so an off-Vercel deployment gets `undefined` here and logs the SAME one
14
+ // sentence the tool mount and the egress-host opening log. This file used to hold its own
15
+ // `onVercel()` check, and that is exactly how the bake came to be the only gated path.
16
+ const cfg = loadAgentBrowserConfig(); // logs loudly itself when flag-on-but-unusable
17
+ if (cfg === undefined)
18
+ return {};
19
+ return {
20
+ revalidationKey: () => agentBrowserRevalidationKey(),
21
+ bootstrap: async ({ use }) => {
22
+ const sandbox = await use();
23
+ await install(sandbox);
24
+ },
25
+ };
26
+ }
27
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../../agent/browser/sandbox.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,0GAA0G;AAE1G,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAa1E;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAO,GAAmD,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,CAAC;IAEnG,IAAI,CAAC,mBAAmB,EAAE;QAAE,OAAO,EAAE,CAAC;IACtC,gGAAgG;IAChG,6FAA6F;IAC7F,0FAA0F;IAC1F,uFAAuF;IACvF,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC,CAAC,+CAA+C;IACrF,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO;QACL,eAAe,EAAE,GAAG,EAAE,CAAC,2BAA2B,EAAE;QACpD,SAAS,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;YAC3B,MAAM,OAAO,GAAG,MAAM,GAAG,EAAE,CAAC;YAC5B,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ export declare const CONTRIBUTIONS: {
2
+ readonly schemaVersion: 1;
3
+ readonly package: "@open-everywhere/adapters";
4
+ readonly contributions: readonly [{
5
+ readonly kind: "tool";
6
+ readonly name: "extend_workspace_time";
7
+ readonly module: "agent/sandbox/extend-workspace-time.js";
8
+ readonly summary: "Extend your workspace VM's lifetime by N minutes.";
9
+ }, {
10
+ readonly kind: "hook";
11
+ readonly name: "sandbox-lifecycle";
12
+ readonly module: "agent/sandbox/vercel-lifecycle.js";
13
+ readonly summary: "Stop-after-turn sandbox lifecycle — stop the session's sandbox compute the moment a turn finishes instead of letting it idle out its timeout window. Backend-aware: Vercel and docker each own a stop, just-bash has none and says so.";
14
+ }];
15
+ };
16
+ //# sourceMappingURL=contributions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contributions.d.ts","sourceRoot":"","sources":["../../agent/contributions.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa;aACxB,aAAa,EAAE,CAAC;aAChB,OAAO,EAAE,2BAA2B;aACpC,aAAa;iBACT,IAAI,EAAE,MAAM;iBAAE,IAAI,EAAE,uBAAuB;iBAAE,MAAM,EAAE,wCAAwC;iBAAE,OAAO,EAAE,mDAAmD;;iBAE3J,IAAI,EAAE,MAAM;iBAAE,IAAI,EAAE,mBAAmB;iBAAE,MAAM,EAAE,mCAAmC;iBAAE,OAAO,EAAE,wOAAwO;;CAEnU,CAAC"}
@@ -0,0 +1,11 @@
1
+ // THE CONTRIBUTION MANIFEST for this package — CURATED, never scanned: a directory scan cannot tell a
2
+ // contribution from its neighbours. Import-free DATA (the boundary lock), and erasable syntax only.
3
+ export const CONTRIBUTIONS = {
4
+ schemaVersion: 1,
5
+ package: "@open-everywhere/adapters",
6
+ contributions: [
7
+ { kind: "tool", name: "extend_workspace_time", module: "agent/sandbox/extend-workspace-time.js", summary: "Extend your workspace VM's lifetime by N minutes." },
8
+ { kind: "hook", name: "sandbox-lifecycle", module: "agent/sandbox/vercel-lifecycle.js", summary: "Stop-after-turn sandbox lifecycle — stop the session's sandbox compute the moment a turn finishes instead of letting it idle out its timeout window. Backend-aware: Vercel and docker each own a stop, just-bash has none and says so." },
9
+ ],
10
+ };
11
+ //# sourceMappingURL=contributions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contributions.js","sourceRoot":"","sources":["../../agent/contributions.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,oGAAoG;AAEpG,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,aAAa,EAAE,CAAC;IAChB,OAAO,EAAE,2BAA2B;IACpC,aAAa,EAAE;QACb,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,wCAAwC,EAAE,OAAO,EAAE,mDAAmD,EAAE;QAE/J,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,EAAE,mCAAmC,EAAE,OAAO,EAAE,wOAAwO,EAAE;KAC5U;CACO,CAAC"}
@@ -0,0 +1,39 @@
1
+ /** Which app-assignment field carries the app-side identity for one mapped app. */
2
+ export type OktaAppIdField = "externalId" | "userName";
3
+ /** One configured Okta application → one of OUR platform tokens. */
4
+ export interface OktaAppMapping {
5
+ /** Our platform token ("slack", "github", "linear") — the namespace `principalKey` qualifies with. */
6
+ readonly platform: string;
7
+ /**
8
+ * WHICH WORKSPACE this app's ids belong to; absent means this deployment's sole admitted workspace.
9
+ * 🔴 OPERATOR CONFIG, never an IdP answer — and the sync still refuses a tenant this deployment never admitted.
10
+ */
11
+ readonly tenant?: string;
12
+ /** The Okta application id (`0oa…`). */
13
+ readonly appId: string;
14
+ /**
15
+ * Where the app-side user id lives. DEFAULT `externalId` — the SCIM write-back, and the only field graded
16
+ * `attested`. `userName` is usually an EMAIL, is app-admin-editable, and is therefore emitted `asserted`.
17
+ */
18
+ readonly field: OktaAppIdField;
19
+ }
20
+ export interface OktaDirectoryConfig {
21
+ readonly orgUrl: string;
22
+ readonly tokenRef: string;
23
+ readonly tokenBroker: string;
24
+ readonly apps: readonly OktaAppMapping[];
25
+ }
26
+ /** True iff the selector names the Okta adapter. Exact match, trimmed, case-insensitive — a typo
27
+ * leaves the plane OFF rather than half-arming something. */
28
+ export declare function oktaDirectoryEnabled(env?: NodeJS.ProcessEnv): boolean;
29
+ /**
30
+ * Parse the app map: `<platform>[/<tenant>]:<oktaAppId>[:<field>]`, comma-separated. The workspace rung uses
31
+ * `/`, matching the principal-key grammar. FAIL-LOUD on a malformed entry — a dropped entry is a silent gap.
32
+ */
33
+ export declare function parseOktaAppMap(raw: string | undefined): readonly OktaAppMapping[];
34
+ /**
35
+ * Load the Okta config block. FAIL-LOUD when the selector is armed but a required field is missing. An unset
36
+ * SELECTOR stays silent — that is a deployment with no IdP, not a broken one.
37
+ */
38
+ export declare function loadOktaDirectoryConfig(env?: NodeJS.ProcessEnv): OktaDirectoryConfig;
39
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../agent/directory/config.ts"],"names":[],"mappings":"AAgBA,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,UAAU,CAAC;AAEvD,oEAAoE;AACpE,MAAM,WAAW,cAAc;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;CAC1C;AAED;8DAC8D;AAC9D,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAElF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,cAAc,EAAE,CAwClF;AAsBD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,mBAAmB,CAiBjG"}
@@ -0,0 +1,101 @@
1
+ // The directory-adapter SELECTION and Okta config. Selector-off or config-absent ⇒ NOTHING registers, with no
2
+ // partial arming. 🔴 The API token is a `secretRef` through a broker (default `db`), never a raw env read.
3
+ /** Which directory adapter to arm ("okta"). Unset ⇒ the directory plane stays off. */
4
+ const OE_DIRECTORY_PROVIDER_ENV = "OE_DIRECTORY_PROVIDER";
5
+ /** The Okta org URL, e.g. `https://acme.okta.com` (or an `*.oktapreview.com` sandbox). MUST be
6
+ * `https://` — see {@link requireHttpsOrgUrl}; a plaintext origin would put the SSWS token on the
7
+ * wire in clear on every request. */
8
+ const OE_DIRECTORY_OKTA_ORG_URL_ENV = "OE_DIRECTORY_OKTA_ORG_URL";
9
+ /** The credential REF for the Okta API token — resolved through a broker, never read as a value. */
10
+ const OE_DIRECTORY_OKTA_TOKEN_REF_ENV = "OE_DIRECTORY_OKTA_TOKEN_REF";
11
+ /** Which broker holds that ref. Default "db" (the encrypted credential store — OPE-408 step 2). */
12
+ const OE_DIRECTORY_OKTA_TOKEN_BROKER_ENV = "OE_DIRECTORY_OKTA_TOKEN_BROKER";
13
+ /** App map: `"<platform>[/<tenant>]:<oktaAppId>[:<field>], …"` — see {@link parseOktaAppMap}. */
14
+ const OE_DIRECTORY_OKTA_APPS_ENV = "OE_DIRECTORY_OKTA_APPS";
15
+ /** True iff the selector names the Okta adapter. Exact match, trimmed, case-insensitive — a typo
16
+ * leaves the plane OFF rather than half-arming something. */
17
+ export function oktaDirectoryEnabled(env = process.env) {
18
+ return (env[OE_DIRECTORY_PROVIDER_ENV] ?? "").trim().toLowerCase() === "okta";
19
+ }
20
+ /**
21
+ * Parse the app map: `<platform>[/<tenant>]:<oktaAppId>[:<field>]`, comma-separated. The workspace rung uses
22
+ * `/`, matching the principal-key grammar. FAIL-LOUD on a malformed entry — a dropped entry is a silent gap.
23
+ */
24
+ export function parseOktaAppMap(raw) {
25
+ const out = [];
26
+ const seen = new Set();
27
+ for (const entry of (raw ?? "").split(",").map((s) => s.trim()).filter(Boolean)) {
28
+ const parts = entry.split(":").map((s) => s.trim());
29
+ const [head, appId, field] = parts;
30
+ if (parts.length < 2 || parts.length > 3 || !head || !appId) {
31
+ throw new Error(`${OE_DIRECTORY_OKTA_APPS_ENV} entry "${entry}" is malformed — expected "<platform>[/<tenant>]:<oktaAppId>" ` +
32
+ `with an optional ":externalId"/":userName" suffix, e.g. "slack:0oa1a2b3c4d5" or "slack/T0AB1CD2E:0oa1a2b3c4d5".`);
33
+ }
34
+ if (field !== undefined && field !== "externalId" && field !== "userName") {
35
+ throw new Error(`${OE_DIRECTORY_OKTA_APPS_ENV} entry "${entry}" names field "${field}" — only "externalId" (default) or "userName" are valid.`);
36
+ }
37
+ const slash = head.indexOf("/");
38
+ const platform = (slash < 0 ? head : head.slice(0, slash)).toLowerCase();
39
+ const tenant = slash < 0 ? undefined : head.slice(slash + 1).trim();
40
+ if (!platform || (tenant !== undefined && (tenant.length === 0 || tenant.includes("/")))) {
41
+ throw new Error(`${OE_DIRECTORY_OKTA_APPS_ENV} entry "${entry}" has an unusable platform/workspace half ("${head}") — write "<platform>" ` +
42
+ `or "<platform>/<workspace-id>" with exactly one slash, e.g. "slack/T0AB1CD2E".`);
43
+ }
44
+ // Two apps mapped to the SAME (platform, workspace) is a genuine misconfiguration rather than a
45
+ // widening: the two would write suggestions that are indistinguishable downstream, and whichever
46
+ // ran second would silently redefine the first's ids. Refused here, where the operator can see
47
+ // both entries, rather than as a mystery in a sync warning.
48
+ const key = `${platform}/${tenant ?? ""}`;
49
+ if (seen.has(key)) {
50
+ throw new Error(`${OE_DIRECTORY_OKTA_APPS_ENV} maps two apps to the same target "${key.replace(/\/$/u, "")}" — an app map entry names WHERE ` +
51
+ "the ids land, so two entries for one place cannot both be right. Give each workspace its own rung " +
52
+ '("slack/T0AB1CD2E:…,slack/T9ZYX8W7V:…"), or remove the duplicate.');
53
+ }
54
+ seen.add(key);
55
+ out.push({ platform, ...(tenant !== undefined ? { tenant } : {}), appId, field: field ?? "externalId" });
56
+ }
57
+ return out;
58
+ }
59
+ /**
60
+ * 🔴 The org URL MUST be `https://`: every request carries the SSWS API token in an `authorization` header.
61
+ * Rejected at LOAD time, with no localhost carve-out; an unparseable URL is refused here for the same reason.
62
+ */
63
+ function requireHttpsOrgUrl(raw) {
64
+ let parsed;
65
+ try {
66
+ parsed = new URL(raw);
67
+ }
68
+ catch {
69
+ throw new Error(`${OE_DIRECTORY_OKTA_ORG_URL_ENV}="${raw}" is not a URL — expected your Okta org URL, e.g. "https://acme.okta.com".`);
70
+ }
71
+ if (parsed.protocol !== "https:") {
72
+ throw new Error(`${OE_DIRECTORY_OKTA_ORG_URL_ENV}="${raw}" is not https — refusing to arm directory sync. Every Okta request carries the ` +
73
+ `SSWS API token in an authorization header, so a plaintext org URL would put an admin credential on the wire on every ` +
74
+ `sync. Use "https://<your-org>.okta.com".`);
75
+ }
76
+ }
77
+ /**
78
+ * Load the Okta config block. FAIL-LOUD when the selector is armed but a required field is missing. An unset
79
+ * SELECTOR stays silent — that is a deployment with no IdP, not a broken one.
80
+ */
81
+ export function loadOktaDirectoryConfig(env = process.env) {
82
+ const orgUrl = env[OE_DIRECTORY_OKTA_ORG_URL_ENV]?.trim();
83
+ const tokenRef = env[OE_DIRECTORY_OKTA_TOKEN_REF_ENV]?.trim();
84
+ const missing = [];
85
+ if (!orgUrl)
86
+ missing.push(OE_DIRECTORY_OKTA_ORG_URL_ENV);
87
+ if (!tokenRef)
88
+ missing.push(OE_DIRECTORY_OKTA_TOKEN_REF_ENV);
89
+ if (missing.length) {
90
+ throw new Error(`${OE_DIRECTORY_PROVIDER_ENV}="okta" but ${missing.join(" and ")} ${missing.length > 1 ? "are" : "is"} not set — directory sync cannot be armed.`);
91
+ }
92
+ requireHttpsOrgUrl(orgUrl);
93
+ const apps = parseOktaAppMap(env[OE_DIRECTORY_OKTA_APPS_ENV]);
94
+ return {
95
+ orgUrl: orgUrl.replace(/\/+$/u, ""),
96
+ tokenRef: tokenRef,
97
+ tokenBroker: env[OE_DIRECTORY_OKTA_TOKEN_BROKER_ENV]?.trim() || "db",
98
+ apps,
99
+ };
100
+ }
101
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../agent/directory/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type DirectoryProvider } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import type { OktaDirectoryConfig } from "./config.js";
3
+ /** A `fetch`-shaped transport — the DI seam the offline test injects (defaults to global fetch). */
4
+ export type FetchLike = typeof fetch;
5
+ export interface OktaDirectoryDeps {
6
+ readonly config: OktaDirectoryConfig;
7
+ /** Transport for every Okta call. Default: global `fetch`. */
8
+ readonly fetch?: FetchLike;
9
+ /** Resolve the API token. Default: core's broker seam — see config.ts's header. */
10
+ readonly resolveToken?: (broker: string, ref: string) => Promise<string>;
11
+ }
12
+ /**
13
+ * The `rel="next"` URL from the RFC-5988 `Link` header. Okta paginates with an opaque cursor and no total
14
+ * count, so following the header is the ONLY correct way to page — an offset would truncate or duplicate.
15
+ */
16
+ export declare function nextLink(header: string | null | undefined): string | undefined;
17
+ /** Build the Okta directory provider. Every edge is injected, so the whole mapping is offline-testable. */
18
+ export declare function makeOktaDirectoryProvider(deps: OktaDirectoryDeps): DirectoryProvider;
19
+ //# sourceMappingURL=okta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okta.d.ts","sourceRoot":"","sources":["../../../agent/directory/okta.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6D,KAAK,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/I,OAAO,KAAK,EAAkB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvE,oGAAoG;AACpG,MAAM,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC;AAoDrC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1E;AAUD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAO9E;AAED,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CA8HpF"}