diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/function/package.json | 4 | ||||
| -rw-r--r-- | packages/function/src/api.ts | 40 | ||||
| -rw-r--r-- | packages/function/sst-env.d.ts | 24 | ||||
| -rw-r--r-- | packages/opencode/sst-env.d.ts | 2 | ||||
| -rw-r--r-- | packages/web/sst-env.d.ts | 2 |
5 files changed, 62 insertions, 10 deletions
diff --git a/packages/function/package.json b/packages/function/package.json index 81a1edc92..c033fa058 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -8,5 +8,9 @@ "@cloudflare/workers-types": "4.20250522.0", "typescript": "catalog:", "@types/node": "catalog:" + }, + "dependencies": { + "@octokit/auth-app": "8.0.1", + "jose": "6.0.11" } } diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts index be6ef1923..3ba3d71d1 100644 --- a/packages/function/src/api.ts +++ b/packages/function/src/api.ts @@ -1,5 +1,8 @@ import { DurableObject } from "cloudflare:workers" import { randomUUID } from "node:crypto" +import { jwtVerify, createRemoteJWKSet } from "jose" +import { createAppAuth } from "@octokit/auth-app" +import { Resource } from "sst" type Env = { SYNC_SERVER: DurableObjectNamespace<SyncServer> @@ -218,5 +221,42 @@ export default { }, ) } + + if (request.method === "POST" && method === "exchange_github_app_token") { + const EXPECTED_AUDIENCE = "opencode-github-action" + const GITHUB_ISSUER = "https://token.actions.githubusercontent.com" + const JWKS_URL = `${GITHUB_ISSUER}/.well-known/jwks` + + // get Authorization header + const authHeader = request.headers.get("Authorization") + const token = authHeader?.replace(/^Bearer /, "") + if (!token) return new Response("Error: authorization header is required", { status: 401 }) + + // verify token + const JWKS = createRemoteJWKSet(new URL(JWKS_URL)) + try { + await jwtVerify(token, JWKS, { + issuer: GITHUB_ISSUER, + audience: EXPECTED_AUDIENCE, + }) + } catch (err) { + console.error("Token verification failed:", err) + return new Response(JSON.stringify({ error: "Invalid or expired token" }), { + status: 403, + headers: { "Content-Type": "application/json" }, + }) + } + + // Create app token + const auth = createAppAuth({ + appId: Resource.GITHUB_APP_ID.value, + privateKey: Resource.GITHUB_APP_PRIVATE_KEY.value, + }) + const appAuthentication = await auth({ type: "app" }) + + return new Response(JSON.stringify({ token: appAuthentication.token }), { + headers: { "Content-Type": "application/json" }, + }) + } }, } diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index fd95edbb4..dab7de3f3 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -6,20 +6,28 @@ import "sst" declare module "sst" { export interface Resource { - Web: { - type: "sst.cloudflare.Astro" - url: string + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "Web": { + "type": "sst.cloudflare.Astro" + "url": string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types" +// cloudflare +import * as cloudflare from "@cloudflare/workers-types"; declare module "sst" { export interface Resource { - Api: cloudflare.Service - Bucket: cloudflare.R2Bucket + "Api": cloudflare.Service + "Bucket": cloudflare.R2Bucket } } import "sst" -export {} +export {}
\ No newline at end of file diff --git a/packages/opencode/sst-env.d.ts b/packages/opencode/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/opencode/sst-env.d.ts +++ b/packages/opencode/sst-env.d.ts @@ -6,4 +6,4 @@ /// <reference path="../../sst-env.d.ts" /> import "sst" -export {} +export {}
\ No newline at end of file diff --git a/packages/web/sst-env.d.ts b/packages/web/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/web/sst-env.d.ts +++ b/packages/web/sst-env.d.ts @@ -6,4 +6,4 @@ /// <reference path="../../sst-env.d.ts" /> import "sst" -export {} +export {}
\ No newline at end of file |
