experimental-ash 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/docs/public/auth-and-route-protection.md +9 -0
- package/dist/docs/public/sandbox.md +42 -19
- package/dist/docs/public/session-context.md +1 -1
- package/dist/src/compiled/.vendor-stamp.json +2 -2
- package/dist/src/compiled/@vercel/sandbox/index.d.ts +11 -2
- package/dist/src/compiled/@vercel/sandbox/index.js +3 -3
- package/dist/src/compiled/@vercel/sandbox/package.json +1 -1
- package/dist/src/compiled/_chunks/node/{auth-ZhCJAHxl.js → auth-CVVvWjaK.js} +1 -1
- package/dist/src/compiled/_chunks/node/{version-D4IYmfaS.js → version-nR4RSpFw.js} +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.d.ts +1 -1
- package/dist/src/execution/sandbox/session.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/logging.js +1 -1
- package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
- package/dist/src/packages/ash-scaffold/src/web-template.js +2 -2
- package/dist/src/public/channels/auth.d.ts +22 -11
- package/dist/src/public/channels/auth.js +1 -1
- package/dist/src/public/definitions/sandbox.d.ts +1 -1
- package/dist/src/public/sandbox/index.d.ts +1 -1
- package/dist/src/public/sandbox/vercel-sandbox.d.ts +4 -4
- package/dist/src/runtime/governance/auth/oidc.js +1 -1
- package/dist/src/runtime/governance/auth/token-claims.d.ts +2 -0
- package/dist/src/runtime/governance/auth/token-claims.js +1 -1
- package/dist/src/runtime/governance/auth/types.d.ts +6 -0
- package/dist/src/shared/sandbox-session.d.ts +0 -17
- package/package.json +2 -2
|
@@ -6,9 +6,9 @@ import type { Sandbox as SdkSandbox, SandboxUpdateParams } from "#compiled/@verc
|
|
|
6
6
|
* session-create). Skipped on resume (`Sandbox.get`) since no create
|
|
7
7
|
* happens there.
|
|
8
8
|
*
|
|
9
|
-
* Framework-injected fields (`name`, `persistent`, `signal`)
|
|
10
|
-
* excluded — the framework owns those and overrides any
|
|
11
|
-
* values.
|
|
9
|
+
* Framework-injected fields (`name`, `onResume`, `persistent`, `signal`)
|
|
10
|
+
* are excluded — the framework owns those and overrides any
|
|
11
|
+
* author-supplied values.
|
|
12
12
|
*
|
|
13
13
|
* `source` is honored only on the template create at prewarm time, so
|
|
14
14
|
* an author-supplied snapshot, git revision, or tarball becomes the
|
|
@@ -20,7 +20,7 @@ import type { Sandbox as SdkSandbox, SandboxUpdateParams } from "#compiled/@verc
|
|
|
20
20
|
* snapshot, force a template rebuild (e.g. by changing the sandbox
|
|
21
21
|
* definition so its template key changes).
|
|
22
22
|
*/
|
|
23
|
-
export type VercelSandboxCreateOptions = Omit<NonNullable<Parameters<typeof SdkSandbox.create>[0]>, "name" | "persistent" | "signal">;
|
|
23
|
+
export type VercelSandboxCreateOptions = Omit<NonNullable<Parameters<typeof SdkSandbox.create>[0]>, "name" | "onResume" | "persistent" | "signal">;
|
|
24
24
|
/**
|
|
25
25
|
* Options accepted by the Vercel backend's `bootstrap({ use })` hook.
|
|
26
26
|
* Aliases the Vercel SDK's `SandboxUpdateParams` because bootstrap
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{createRemoteJWKSet,jwtVerify}from"#compiled/jose/index.js";import{areTokenClaimMatchersSatisfied,createJwtAuthenticatedCallerPrincipal}from"#runtime/governance/auth/token-claims.js";const oidcDiscoveryDocumentSchema=z.object({issuer:z.string().optional(),jwks_uri:z.string().url()}).passthrough(),oidcDiscoveryDocumentCache=new Map,oidcJwksCache=new Map;async function authenticateOidcStrategy(e){let t;try{t=await getOidcRemoteJwks(e.strategy)}catch(e){return{kind:`misconfigured`,message:`Failed to load OIDC discovery metadata. ${e instanceof Error?e.message:`Unknown discovery failure.`}`}}try{let a=await jwtVerify(e.token,t,{audience:[...e.strategy.audiences],clockTolerance:e.strategy.clockSkewSeconds,issuer:e.strategy.issuer});if(typeof a.payload.sub!=`string`||a.payload.sub.length===0)return{kind:`not-authenticated`};let o=e.strategy.acceptCurrentVercelProject&&
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{createRemoteJWKSet,jwtVerify}from"#compiled/jose/index.js";import{areTokenClaimMatchersSatisfied,createJwtAuthenticatedCallerPrincipal}from"#runtime/governance/auth/token-claims.js";const oidcDiscoveryDocumentSchema=z.object({issuer:z.string().optional(),jwks_uri:z.string().url()}).passthrough(),oidcDiscoveryDocumentCache=new Map,oidcJwksCache=new Map;async function authenticateOidcStrategy(e){let t;try{t=await getOidcRemoteJwks(e.strategy)}catch(e){return{kind:`misconfigured`,message:`Failed to load OIDC discovery metadata. ${e instanceof Error?e.message:`Unknown discovery failure.`}`}}try{let a=await jwtVerify(e.token,t,{audience:[...e.strategy.audiences],clockTolerance:e.strategy.clockSkewSeconds,issuer:e.strategy.issuer});if(e.strategy.acceptCurrentVercelProject&&e.strategy.issuer.startsWith(`https://oidc.vercel.com/`)&&a.payload.external_sub!==void 0)return typeof a.payload.external_sub!=`string`||a.payload.external_sub.length===0||!satisfiesCurrentVercelProjectConstraint({payload:a.payload})||!satisfiesCurrentVercelEnvironmentConstraint({payload:a.payload})?{kind:`caller-not-allowed`}:{kind:`authenticated`,principal:createJwtAuthenticatedCallerPrincipal({authenticator:`oidc`,issuerClaims:[`external_iss`,`connector_id`],payload:a.payload,principalType:`user`,subjectClaim:`external_sub`})};if(typeof a.payload.sub!=`string`||a.payload.sub.length===0)return{kind:`not-authenticated`};let o=e.strategy.acceptCurrentVercelProject&&isCurrentVercelProjectToken({issuer:e.strategy.issuer,payload:a.payload}),s=o&&isCurrentVercelEnvironmentToken({payload:a.payload});return!o&&!areTokenClaimMatchersSatisfied(a.payload,e.strategy)?{kind:`caller-not-allowed`}:{kind:`authenticated`,principal:createJwtAuthenticatedCallerPrincipal({authenticator:`oidc`,payload:a.payload,principalType:s?`runtime`:`service`})}}catch{return{kind:`not-authenticated`}}}async function getOidcRemoteJwks(e){let n=await getOidcDiscoveryDocument(e.discoveryUrl),r=oidcJwksCache.get(n.jwks_uri);if(r!==void 0)return r;let i=createRemoteJWKSet(new URL(n.jwks_uri));return oidcJwksCache.set(n.jwks_uri,i),i}async function getOidcDiscoveryDocument(e){let t=oidcDiscoveryDocumentCache.get(e);if(t!==void 0)return await t;let n=fetch(e,{headers:{accept:`application/json`}}).then(async e=>{if(!e.ok)throw Error(`Discovery route returned HTTP ${e.status}.`);return oidcDiscoveryDocumentSchema.parse(await e.json())}).catch(t=>{throw oidcDiscoveryDocumentCache.delete(e),t});return oidcDiscoveryDocumentCache.set(e,n),await n}function isCurrentVercelProjectToken(e){if(!e.issuer.startsWith(`https://oidc.vercel.com`))return!1;let t=process.env.VERCEL_PROJECT_ID?.trim();return t===void 0||t.length===0?!1:typeof e.payload.project_id==`string`&&e.payload.project_id===t}function satisfiesCurrentVercelProjectConstraint(e){let t=process.env.VERCEL_PROJECT_ID?.trim();return t===void 0||t.length===0?!0:typeof e.payload.project_id==`string`&&e.payload.project_id===t}function isCurrentVercelEnvironmentToken(e){let t=getCurrentVercelEnvironment();return t===void 0||t.length===0?!1:typeof e.payload.environment==`string`&&e.payload.environment===t}function satisfiesCurrentVercelEnvironmentConstraint(e){let t=getCurrentVercelEnvironment();return t===void 0||t.length===0?!0:typeof e.payload.environment==`string`&&e.payload.environment===t}function getCurrentVercelEnvironment(){return process.env.VERCEL_TARGET_ENV?.trim()||process.env.VERCEL_ENV?.trim()||void 0}export{authenticateOidcStrategy};
|
|
@@ -10,6 +10,8 @@ export declare function areTokenClaimMatchersSatisfied(payload: JWTPayload, matc
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function createJwtAuthenticatedCallerPrincipal(input: {
|
|
12
12
|
readonly authenticator: AuthenticatedCallerPrincipal["authenticator"];
|
|
13
|
+
readonly issuerClaims?: readonly string[];
|
|
13
14
|
readonly payload: JWTPayload;
|
|
14
15
|
readonly principalType: AuthenticatedCallerPrincipal["principalType"];
|
|
16
|
+
readonly subjectClaim?: string;
|
|
15
17
|
}): AuthenticatedCallerPrincipal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const STANDARD_PROJECTED_CLAIM_KEYS=new Set([`aud`,`exp`,`iat`,`iss`,`jti`,`nbf`,`sub`]);function normalizeJwtClaims(e){let t={};for(let[n,r]of Object.entries(e)){if(typeof r==`string`){t[n]=r;continue}Array.isArray(r)&&r.every(e=>typeof e==`string`)&&(t[n]=Object.freeze([...r]))}return Object.freeze(t)}function createJwtAttributeProjection(t){let n=normalizeJwtClaims(t);return Object.freeze(Object.fromEntries(Object.entries(n).filter(([t])=>!STANDARD_PROJECTED_CLAIM_KEYS.has(t))))}function areTokenClaimMatchersSatisfied(e,t){let n=normalizeJwtClaims(e);if(t.subjects!==void 0){let n=typeof e.sub==`string`?e.sub:null;if(n===null||!t.subjects.some(e=>matchesWildcardPattern(e,n)))return!1}return t.claims===void 0?!0:Object.entries(t.claims).every(([e,t])=>{let r=n[e];return r===void 0?!1:typeof r==`string`?t.includes(r):r.some(e=>t.includes(e))})}function createJwtAuthenticatedCallerPrincipal(e){let t=
|
|
1
|
+
const STANDARD_PROJECTED_CLAIM_KEYS=new Set([`aud`,`exp`,`iat`,`iss`,`jti`,`nbf`,`sub`]);function normalizeJwtClaims(e){let t={};for(let[n,r]of Object.entries(e)){if(typeof r==`string`){t[n]=r;continue}Array.isArray(r)&&r.every(e=>typeof e==`string`)&&(t[n]=Object.freeze([...r]))}return Object.freeze(t)}function createJwtAttributeProjection(t){let n=normalizeJwtClaims(t);return Object.freeze(Object.fromEntries(Object.entries(n).filter(([t])=>!STANDARD_PROJECTED_CLAIM_KEYS.has(t))))}function areTokenClaimMatchersSatisfied(e,t){let n=normalizeJwtClaims(e);if(t.subjects!==void 0){let n=typeof e.sub==`string`?e.sub:null;if(n===null||!t.subjects.some(e=>matchesWildcardPattern(e,n)))return!1}return t.claims===void 0?!0:Object.entries(t.claims).every(([e,t])=>{let r=n[e];return r===void 0?!1:typeof r==`string`?t.includes(r):r.some(e=>t.includes(e))})}function createJwtAuthenticatedCallerPrincipal(e){let t=readFirstStringClaim(e.payload,[...e.issuerClaims??[],`iss`]),n=e.subjectClaim??`sub`,r=readFirstStringClaim(e.payload,[n]);if(t===void 0||r===void 0)throw Error(`Expected verified JWT payloads to include string iss and ${n} claims.`);let i=normalizeJwtClaims(e.payload);return{attributes:createJwtAttributeProjection(e.payload),authenticator:e.authenticator,claims:i,issuer:t,principalId:`${t}:${r}`,principalType:e.principalType,subject:r}}function readFirstStringClaim(e,t){for(let n of t){let t=e[n];if(typeof t==`string`&&t.length>0)return t}}function matchesWildcardPattern(e,t){if(!e.includes(`*`))return e===t;let n=e.replaceAll(/[.+?^${}()|[\]\\]/g,`\\$&`).replaceAll(`*`,`.*`);return RegExp(`^${n}$`).test(t)}export{areTokenClaimMatchersSatisfied,createJwtAuthenticatedCallerPrincipal};
|
|
@@ -67,6 +67,12 @@ export interface ResolvedOidcAuthStrategy extends ResolvedTokenClaimMatchers {
|
|
|
67
67
|
* `principalType: "runtime"`; other current-project tokens are
|
|
68
68
|
* tagged `"service"`.
|
|
69
69
|
*
|
|
70
|
+
* Vercel OIDC tokens with an `external_sub` claim are user tokens.
|
|
71
|
+
* They must satisfy the current project/environment constraints when
|
|
72
|
+
* those environment variables are configured, and then authenticate as
|
|
73
|
+
* `principalType: "user"` with `external_sub` as their subject and
|
|
74
|
+
* `external_iss` / `connector_id` as their issuer when present.
|
|
75
|
+
*
|
|
70
76
|
* Set exclusively by `verifyVercelOidc`. The generic public
|
|
71
77
|
* `verifyOidc` always passes `false`.
|
|
72
78
|
*/
|
|
@@ -19,11 +19,6 @@ export type SandboxSpawnOptions = Parameters<AiSdkSandbox["spawn"]>[0];
|
|
|
19
19
|
* Mirrors the AI SDK `Experimental_SandboxProcess` type.
|
|
20
20
|
*/
|
|
21
21
|
export type SandboxProcess = Awaited<ReturnType<AiSdkSandbox["spawn"]>>;
|
|
22
|
-
/**
|
|
23
|
-
* @deprecated Use {@link SandboxRunOptions} instead. Kept as an alias
|
|
24
|
-
* for source compatibility; will be removed in a future release.
|
|
25
|
-
*/
|
|
26
|
-
export type SandboxRunCommandOptions = SandboxRunOptions;
|
|
27
22
|
/**
|
|
28
23
|
* Options for reading one file as a stream of bytes.
|
|
29
24
|
*/
|
|
@@ -67,8 +62,6 @@ export type SandboxWriteTextFileOptions = Parameters<AiSdkSandbox["writeTextFile
|
|
|
67
62
|
* Relative paths resolve from `/workspace`, the live working directory
|
|
68
63
|
* for every backend. Absolute paths pass through unchanged.
|
|
69
64
|
*
|
|
70
|
-
* `runCommand` is preserved as a deprecated alias for `run`. It emits a
|
|
71
|
-
* one-time warning per session when called.
|
|
72
65
|
*/
|
|
73
66
|
export interface SandboxSession extends Pick<AiSdkSandbox, "run" | "spawn" | "readFile" | "readBinaryFile" | "readTextFile" | "writeFile" | "writeBinaryFile" | "writeTextFile"> {
|
|
74
67
|
/**
|
|
@@ -90,16 +83,6 @@ export interface SandboxSession extends Pick<AiSdkSandbox, "run" | "spawn" | "re
|
|
|
90
83
|
* The read and write methods already apply this internally.
|
|
91
84
|
*/
|
|
92
85
|
resolvePath(path: string): string;
|
|
93
|
-
/**
|
|
94
|
-
* @deprecated Use {@link SandboxSession.run} instead. This alias wraps
|
|
95
|
-
* `run` and emits a one-time deprecation warning per session on call.
|
|
96
|
-
*
|
|
97
|
-
* Marked optional on the public type so authored code that constructs
|
|
98
|
-
* its own session-like fixtures isn't forced to mock the deprecated
|
|
99
|
-
* path. Runtime sessions built through `buildSandboxSession` always
|
|
100
|
-
* provide it.
|
|
101
|
-
*/
|
|
102
|
-
runCommand?: AiSdkSandbox["run"];
|
|
103
86
|
}
|
|
104
87
|
/**
|
|
105
88
|
* Internal sandbox session, used to construct the public {@link SandboxSession}.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "experimental-ash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"bin": {
|
|
5
5
|
"ash": "./bin/ash.js",
|
|
6
6
|
"experimental-ash": "./bin/ash.js"
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
"@types/react": "19.2.15",
|
|
191
191
|
"@types/react-test-renderer": "19.1.0",
|
|
192
192
|
"@vercel/oidc": "3.4.1",
|
|
193
|
-
"@vercel/sandbox": "2.0.
|
|
193
|
+
"@vercel/sandbox": "2.0.1",
|
|
194
194
|
"@workflow/core": "5.0.0-beta.7",
|
|
195
195
|
"@workflow/errors": "5.0.0-beta.4",
|
|
196
196
|
"@workflow/world-local": "5.0.0-beta.6",
|