| 1 | import * as secretsmanager from "@distilled.cloud/aws/secrets-manager"; |
| 2 | import * as Effect from "effect/Effect"; |
| 3 | import * as Layer from "effect/Layer"; |
| 4 | import * as Binding from "../../Binding.ts"; |
| 5 | import type { Accessor } from "../../Output.ts"; |
| 6 | import { isBindingHost } from "../Lambda/Function.ts"; |
| 7 | import { |
| 8 | BatchGetSecretValue, |
| 9 | type BatchGetSecretValueRequest, |
| 10 | } from "./BatchGetSecretValue.ts"; |
| 11 | import type { Secret } from "./Secret.ts"; |
| 12 | |
| 13 | /** |
| 14 | * Bespoke (multi-secret) HTTP binding: `BatchGetSecretValue` targets a list |
| 15 | * of secrets, so it can't reuse the single-secret scaffolding — the account |
| 16 | * -level `secretsmanager:BatchGetSecretValue` action is granted on `*` and |
| 17 | * per-secret `GetSecretValue`/`DescribeSecret` on each bound secret's ARN. |
| 18 | */ |
| 19 | export const BatchGetSecretValueHttp = Layer.effect( |
| 20 | BatchGetSecretValue, |
| 21 | Effect.gen(function* () { |
| 22 | const batchGetSecretValue = yield* secretsmanager.batchGetSecretValue; |
| 23 | |
| 24 | return Effect.fn(function* (secrets: readonly Secret[]) { |
| 25 | const SecretIds: Accessor<string>[] = []; |
| 26 | for (const secret of secrets) { |
| 27 | SecretIds.push(yield* secret.secretArn); |
| 28 | } |
| 29 | if (!globalThis.__ALCHEMY_RUNTIME__) { |
| 30 | const host = yield* Binding.Host; |
| 31 | if (isBindingHost(host)) { |
| 32 | yield* host.bind`Allow(${host}, AWS.SecretsManager.BatchGetSecretValue())`( |
| 33 | { |
| 34 | policyStatements: [ |
| 35 | { |
| 36 | Effect: "Allow", |
| 37 | Action: ["secretsmanager:BatchGetSecretValue"], |
| 38 | Resource: ["*"], |
| 39 | }, |
| 40 | ], |
| 41 | }, |
| 42 | ); |
| 43 | for (const secret of secrets) { |
| 44 | yield* host.bind`Allow(${host}, AWS.SecretsManager.BatchGetSecretValue(${secret}))`( |
| 45 | { |
| 46 | policyStatements: [ |
| 47 | { |
| 48 | Effect: "Allow", |
| 49 | Action: [ |
| 50 | "secretsmanager:GetSecretValue", |
| 51 | "secretsmanager:DescribeSecret", |
| 52 | ], |
| 53 | Resource: [secret.secretArn], |
| 54 | }, |
| 55 | ], |
| 56 | }, |
| 57 | ); |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | return Effect.fn( |
| 62 | `AWS.SecretsManager.BatchGetSecretValue(${secrets |
| 63 | .map((secret) => secret.LogicalId) |
| 64 | .join(",")})`, |
| 65 | )(function* (request?: BatchGetSecretValueRequest) { |
| 66 | const secretIdList = []; |
| 67 | for (const secretId of SecretIds) { |
| 68 | secretIdList.push(yield* secretId); |
| 69 | } |
| 70 | return yield* batchGetSecretValue({ |
| 71 | ...request, |
| 72 | SecretIdList: secretIdList, |
| 73 | }); |
| 74 | }); |
| 75 | }); |
| 76 | }), |
| 77 | ); |