-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Staging cluster deployment #1183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8b976e4
b12b221
fe273ee
dc2f22b
84c21bb
921549e
8c8f599
1bcee3a
fe3180e
40ee84f
b4361e4
2a91e42
b489244
96a6aa0
bf1d661
9435124
039b88b
9e02df8
c512587
1cdc863
71f9f74
3052627
0c9d8db
7ebeb56
4edf301
a6024a5
21f5b0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| target/ | ||
| node_modules/ | ||
| crates/ | ||
| target | ||
| crates | ||
| **/node_modules | ||
| **/.next |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| auto-install-peers = true | ||
| force-legacy-deploy = true | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -16,13 +16,14 @@ import { | |||
| import { type HttpAuthMiddleware, Video } from "@cap/web-domain"; | ||||
| import { | ||||
| FetchHttpClient, | ||||
| Headers, | ||||
| type HttpApi, | ||||
| HttpApiBuilder, | ||||
| HttpApiClient, | ||||
| HttpMiddleware, | ||||
| HttpServer, | ||||
| } from "@effect/platform"; | ||||
| import { RpcClient } from "@effect/rpc"; | ||||
| import { RpcClient, RpcMessage, RpcMiddleware } from "@effect/rpc"; | ||||
| import { | ||||
| Cause, | ||||
| Config, | ||||
|
|
@@ -31,6 +32,7 @@ import { | |||
| Layer, | ||||
| ManagedRuntime, | ||||
| Option, | ||||
| Redacted, | ||||
| } from "effect"; | ||||
| import { cookies } from "next/headers"; | ||||
|
|
||||
|
|
@@ -50,11 +52,21 @@ const CookiePasswordAttachmentLive = Layer.effect( | |||
| }), | ||||
| ); | ||||
|
|
||||
| class WorkflowRpcSecret extends Effect.Service<WorkflowRpcSecret>()( | ||||
| "WorkflowRpcSecret", | ||||
| { | ||||
| effect: Effect.map( | ||||
| Config.redacted(Config.string("WORKFLOWS_RPC_SECRET")), | ||||
| (v) => ({ authSecret: v }), | ||||
| ), | ||||
| }, | ||||
| ) {} | ||||
|
|
||||
| const WorkflowRpcLive = Layer.scoped( | ||||
| Workflows.RpcClient, | ||||
| Effect.gen(function* () { | ||||
| const url = Option.getOrElse( | ||||
| yield* Config.option(Config.string("REMOTE_WORKFLOW_URL")), | ||||
| yield* Config.option(Config.string("WORKFLOWS_RPC_URL")), | ||||
| () => "http://127.0.0.1:42169", | ||||
| ); | ||||
|
|
||||
|
|
@@ -66,6 +78,22 @@ const WorkflowRpcLive = Layer.scoped( | |||
| ), | ||||
| ); | ||||
| }), | ||||
| ).pipe( | ||||
| Layer.provide( | ||||
| RpcMiddleware.layerClient(Workflows.SecretAuthMiddleware, ({ request }) => | ||||
| Effect.gen(function* () { | ||||
| const { authSecret } = yield* WorkflowRpcSecret; | ||||
| return { | ||||
| ...request, | ||||
| headers: Headers.set( | ||||
| request.headers, | ||||
| "authorization", | ||||
| Redacted.value(authSecret), | ||||
| ), | ||||
| }; | ||||
| }), | ||||
| ), | ||||
| ), | ||||
| ); | ||||
|
|
||||
| export const Dependencies = Layer.mergeAll( | ||||
|
|
@@ -79,7 +107,13 @@ export const Dependencies = Layer.mergeAll( | |||
| WorkflowRpcLive, | ||||
| layerTracer, | ||||
| ).pipe( | ||||
| Layer.provideMerge(Layer.mergeAll(Database.Default, FetchHttpClient.layer)), | ||||
| Layer.provideMerge( | ||||
| Layer.mergeAll( | ||||
| Database.Default, | ||||
| FetchHttpClient.layer, | ||||
| WorkflowRpcSecret.Default, | ||||
| ), | ||||
| ), | ||||
| ); | ||||
|
|
||||
| // purposefully not exposed | ||||
|
|
@@ -132,6 +166,7 @@ export const apiToHandler = ( | |||
| Layer.provide( | ||||
| HttpApiBuilder.middleware(Effect.provide(CookiePasswordAttachmentLive)), | ||||
| ), | ||||
| Layer.provide(layerTracer), | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove duplicate tracer provision layerTracer is already part of Dependencies; providing it again is redundant. Apply: - Layer.provide(layerTracer),📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||
| Layer.provideMerge(Dependencies), | ||||
| HttpApiBuilder.toWebHandler, | ||||
| (v) => (req: Request) => v.handler(req), | ||||
|
|
||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| /// <reference path="./.sst/platform/config.d.ts" /> | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| import type { Input, Output } from "@pulumi/pulumi"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const GITHUB_ORG = "CapSoftware"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const GITHUB_REPO = "Cap"; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const GITHUB_APP_ID = "1196731"; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -30,6 +32,7 @@ export default $config({ | |||||||||||||||||||||||||||||||||||||||||||||||
| aws: {}, | ||||||||||||||||||||||||||||||||||||||||||||||||
| planetscale: true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| awsx: "2.21.1", | ||||||||||||||||||||||||||||||||||||||||||||||||
| random: true, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -151,7 +154,11 @@ export default $config({ | |||||||||||||||||||||||||||||||||||||||||||||||
| if ($app.stage === "staging" || $app.stage === "production") { | ||||||||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...vercelVariables, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { key: "REMOTE_WORKFLOW_URL", value: workflowCluster.api.url }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { key: "WORKFLOWS_RPC_URL", value: workflowCluster.api.url }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| key: "WORKFLOWS_RPC_SECRET", | ||||||||||||||||||||||||||||||||||||||||||||||||
| value: secrets.WORKFLOWS_RPC_SECRET.result, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { key: "VERCEL_AWS_ROLE_ARN", value: vercelAwsAccessRole.arn }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ].map( | ||||||||||||||||||||||||||||||||||||||||||||||||
| (v) => | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -178,6 +185,9 @@ function Secrets() { | |||||||||||||||||||||||||||||||||||||||||||||||
| CAP_AWS_ACCESS_KEY: new sst.Secret("CAP_AWS_ACCESS_KEY"), | ||||||||||||||||||||||||||||||||||||||||||||||||
| CAP_AWS_SECRET_KEY: new sst.Secret("CAP_AWS_SECRET_KEY"), | ||||||||||||||||||||||||||||||||||||||||||||||||
| GITHUB_PAT: new sst.Secret("GITHUB_PAT"), | ||||||||||||||||||||||||||||||||||||||||||||||||
| WORKFLOWS_RPC_SECRET: new random.RandomString("WORKFLOWS_RPC_SECRET", { | ||||||||||||||||||||||||||||||||||||||||||||||||
| length: 48, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }), | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -289,11 +299,10 @@ async function WorkflowCluster(bucket: aws.s3.BucketV2, secrets: Secrets) { | |||||||||||||||||||||||||||||||||||||||||||||||
| CAP_AWS_BUCKET: bucket.bucket, | ||||||||||||||||||||||||||||||||||||||||||||||||
| SHARD_DATABASE_URL: $interpolate`mysql://${db.username}:${db.password}@${db.host}:${db.port}/${db.database}`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| DATABASE_URL: secrets.DATABASE_URL_MYSQL.value, | ||||||||||||||||||||||||||||||||||||||||||||||||
| CAP_AWS_ACCESS_KEY: secrets.CAP_AWS_ACCESS_KEY.value, | ||||||||||||||||||||||||||||||||||||||||||||||||
| CAP_AWS_SECRET_KEY: secrets.CAP_AWS_SECRET_KEY.value, | ||||||||||||||||||||||||||||||||||||||||||||||||
| AXIOM_API_TOKEN, | ||||||||||||||||||||||||||||||||||||||||||||||||
| AXIOM_DOMAIN: "api.axiom.co", | ||||||||||||||||||||||||||||||||||||||||||||||||
| AXIOM_DATASET, | ||||||||||||||||||||||||||||||||||||||||||||||||
| WORKFLOWS_RPC_SECRET: secrets.WORKFLOWS_RPC_SECRET.result, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const ghcrCredentialsSecret = new aws.secretsmanager.Secret( | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -408,6 +417,12 @@ async function WorkflowCluster(bucket: aws.s3.BucketV2, secrets: Secrets) { | |||||||||||||||||||||||||||||||||||||||||||||||
| ghcrCredentialsTransform.taskDefinition(args); | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||
| actions: ["s3:*"], | ||||||||||||||||||||||||||||||||||||||||||||||||
| resources: [bucket.arn, $interpolate`${bucket.arn}/*`], | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+420
to
+425
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Overbroad S3 permissions; tighten to least privilege s3:* on bucket and objects is excessive. Restrict to the specific actions needed (ListBucket on bucket; GetObject/PutObject/DeleteObject/CreateMultipartUpload/AbortMultipartUpload/ListMultipartUploadParts on objects). Apply: - permissions: [
- {
- actions: ["s3:*"],
- resources: [bucket.arn, $interpolate`${bucket.arn}/*`],
- },
- ],
+ permissions: [
+ {
+ actions: ["s3:ListBucket"],
+ resources: [bucket.arn],
+ },
+ {
+ actions: [
+ "s3:GetObject",
+ "s3:PutObject",
+ "s3:DeleteObject",
+ "s3:CreateMultipartUpload",
+ "s3:AbortMultipartUpload",
+ "s3:ListMultipartUploadParts"
+ ],
+ resources: [$interpolate`${bucket.arn}/*`],
+ },
+ ],📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const api = new sst.aws.ApiGatewayV2("MyApi", { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
force-legacy-deployis not a supported npm/pnpm config.Neither npm nor pnpm exposes a
force-legacy-deploysetting, so this line will just emit warnings at install time and won’t change behavior. If you meant to opt into the legacy peer dependency resolver, uselegacy-peer-deps = true; otherwise please clarify the intended knob.🤖 Prompt for AI Agents