1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import type { PolicyStatement } from "../IAM/Policy.ts";
4import { isBindingHost } from "../Lambda/Function.ts";
5
6/**
7 * Shared HTTP scaffolding for the IAM Roles Anywhere runtime bindings.
8 *
9 * Subjects (the certificate identities Roles Anywhere records for every
10 * authentication attempt) are account-scoped audit records chosen per request
11 * at runtime, so every binding is account-level and grants its action(s) on
12 * `Resource: ["*"]`.
13 *
14 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
15 * a `Layer.effect(Cap, makeRolesAnywhereHttpBinding({ … }))` over the builder
16 * below. Everything except the operation and the IAM action list is
17 * boilerplate.
18 */
19export const makeRolesAnywhereHttpBinding = <I, A, E, R>(options: {
20 /**
21 * Short capability name used in the binding sid and runtime span, e.g.
22 * `"ListSubjects"`.
23 */
24 capability: string;
25 /**
26 * IAM actions granted on `Resource: ["*"]` (the target subjects are chosen
27 * per request at runtime and unknowable at deploy time).
28 */
29 iamActions: readonly string[];
30 /**
31 * The distilled operation implementing the capability.
32 */
33 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
34}) =>
35 Effect.gen(function* () {
36 const op = yield* options.operation;
37
38 return Effect.fn(function* () {
39 if (!globalThis.__ALCHEMY_RUNTIME__) {
40 const host = yield* Binding.Host;
41 if (isBindingHost(host)) {
42 const policyStatements: PolicyStatement[] = [
43 {
44 Effect: "Allow",
45 Action: [...options.iamActions],
46 // The target subjects are chosen per request at runtime.
47 Resource: ["*"],
48 },
49 ];
50 yield* host.bind`Allow(${host}, AWS.RolesAnywhere.${options.capability}())`(
51 {
52 policyStatements,
53 },
54 );
55 }
56 }
57 return Effect.fn(`AWS.RolesAnywhere.${options.capability}`)(function* (
58 request?: I,
59 ) {
60 return yield* op((request ?? {}) as I);
61 });
62 });
63 });