1import * as AWS from "@/AWS";
2import type { SubnetId } from "@/AWS/EC2/Subnet.ts";
3import {
4 DeregisterTargets,
5 DeregisterTargetsHttp,
6 DescribeCapacityReservation,
7 DescribeCapacityReservationHttp,
8 DescribeTargetHealth,
9 DescribeTargetHealthHttp,
10 GetTrustStoreCaCertificatesBundle,
11 GetTrustStoreCaCertificatesBundleHttp,
12 GetTrustStoreRevocationContent,
13 GetTrustStoreRevocationContentHttp,
14 LoadBalancer,
15 ModifyCapacityReservation,
16 ModifyCapacityReservationHttp,
17 RegisterTargets,
18 RegisterTargetsHttp,
19 TargetGroup,
20 TrustStore,
21} from "@/AWS/ELBv2";
22import { Bucket } from "@/AWS/S3";
23import * as ec2 from "@distilled.cloud/aws/ec2";
24import * as Context from "effect/Context";
25import * as Effect from "effect/Effect";
26import * as Layer from "effect/Layer";
27import { HttpServerRequest } from "effect/http/HttpServerRequest";
28import * as HttpServerResponse from "effect/http/HttpServerResponse";
29
30/**
31 * An RFC1918 IP outside the default VPC's CIDR. RegisterTargets accepts
32 * out-of-VPC private addresses when `AvailabilityZone: "all"` is specified —
33 * no live target is needed (this TG isn't attached to a listener, so the
34 * health state is `unused`).
35 */
36export const testTargetIp = "192.168.100.10";
37
38/** S3 key of the trust store's CA bundle (uploaded out-of-band by the test). */
39export const bundleKey = "ca-bundle.pem";
40
41// A self-signed CA certificate generated once and checked in (never created
42// at test time, per the fixture convention). X.509 v3 with basicConstraints
43// CA:TRUE + keyCertSign — ELBv2 trust stores reject v1 certs.
44export const CA_BUNDLE_PEM = `-----BEGIN CERTIFICATE-----
45MIIC2jCCAcKgAwIBAgIJAJyM/Dvd55qtMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV
46BAMMD2FsY2hlbXktdGVzdC1jYTAeFw0yNjA2MTcwNjA5MDlaFw0zNjA2MTQwNjA5
47MDlaMBoxGDAWBgNVBAMMD2FsY2hlbXktdGVzdC1jYTCCASIwDQYJKoZIhvcNAQEB
48BQADggEPADCCAQoCggEBANgo7XPCQMpyecXg2SCj6Tn6R1snlmhSA1vKGQnHoQBS
49QA11DMpv+iFRT9s1d3izaGA4GEcxfrXOsmUBkzYIHJIYakCWdr6qcUXs6lS2uhnZ
50qcyR0CamDtHTqAxRKEK+QPaISoxyD3BIwQqE0I8yNzV3/6osIE513e+7tp9E+J04
51dBhyG5goSwR3ueqs53gQioYVp/fgLKo4MqFcsA3p7anEE9hyeq1Q/lGAXxQwZmXT
523kQli/JjMoF8OfccpA3aBx9Y2aDTCU8HXTscVYmPSHbnTGkTARGBwnag+Jwq5Uni
53YvM2OeDUPwvszgpi3JgiblZQhZQAy4/MeNhmE8qgIa8CAwEAAaMjMCEwDwYDVR0T
54AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAJnp
55el0xBbL/eQY87evhy0o+ZTHMVCdI9Uc+kDK0XPMi4hc5OfjWNIy8u5/s33kPkNYS
56Y5Jhm5KtGtMb9kXioCWjSi0aREA8zijGrXn1jC+0rksMQmJka63bKsJ4TjFaHMcc
57m/xt25xX1Ssp/gWr9YX3MzbPhcn57Uu9OTtzf13F6CMv1XtRS1RKFYtkLZrhvzBR
58WPdos3xvn3D0Fjd5H5AgVKTkeb2YPhINfN4jyzn3J09teKZpNN/qHTAQewIh2FnO
59MeplcuT3eQVUZNTBelvUE7VKHe11AUc8TkvVMS/XOFeN6OHAJtq08EegbTcjwz9Z
60lyGGetkNMmdhGRV6AlY=
61-----END CERTIFICATE-----
62`;
63
64export class ElbBindingsFunction extends AWS.Lambda.Function<AWS.Lambda.Function>()(
65 "ElbBindingsFunction",
66) {}
67
68/**
69 * Shared fleet for the bindings E2E: an unattached `ip` target group (targets
70 * register/deregister without a listener) plus an internal ALB for the
71 * capacity-reservation bindings. VPC/subnets are resolved only at deploy
72 * time — at runtime the resources resolve to references, so the lookups are
73 * guarded off inside the deployed Lambda.
74 */
75export class BindingsFleet extends Context.Service<
76 BindingsFleet,
77 {
78 targetGroup: TargetGroup;
79 loadBalancer: LoadBalancer;
80 trustStore: TrustStore;
81 }
82>()("ELBv2BindingsFleet") {}
83
84export const BindingsFleetLive = Layer.effect(
85 BindingsFleet,
86 Effect.gen(function* () {
87 const isDeploy = !globalThis.__ALCHEMY_RUNTIME__;
88 const vpcId = isDeploy
89 ? yield* ec2
90 .describeVpcs({
91 Filters: [{ Name: "isDefault", Values: ["true"] }],
92 })
93 .pipe(
94 Effect.map((r) => r.Vpcs?.[0]?.VpcId ?? "vpc-0"),
95 // Deploy-time lookup only; a failure here is a fixture defect, not
96 // a typed error the Function impl contract can carry.
97 Effect.orDie,
98 )
99 : "vpc-0";
100 const subnetIds = isDeploy
101 ? yield* ec2
102 .describeSubnets({
103 Filters: [
104 { Name: "vpc-id", Values: [vpcId] },
105 { Name: "default-for-az", Values: ["true"] },
106 ],
107 })
108 .pipe(
109 Effect.map((r) =>
110 (r.Subnets ?? [])
111 .flatMap((s) => (s.SubnetId ? [s.SubnetId as SubnetId] : []))
112 .slice(0, 2),
113 ),
114 Effect.orDie,
115 )
116 : (["subnet-0", "subnet-1"] as SubnetId[]);
117
118 const targetGroup = yield* TargetGroup("ElbBindingsTg", {
119 vpcId,
120 port: 80,
121 protocol: "HTTP",
122 targetType: "ip",
123 });
124 const loadBalancer = yield* LoadBalancer("ElbBindingsLb", {
125 type: "application",
126 scheme: "internal",
127 subnets: subnetIds,
128 });
129 // The CA bundle object is uploaded out-of-band by the test between the
130 // bucket-only phase-1 deploy and the full fixture deploy (there is no
131 // declarative S3 object resource yet).
132 const bucket = yield* Bucket("ElbBindingsBundleBucket", {
133 forceDestroy: true,
134 });
135 const trustStore = yield* TrustStore("ElbBindingsTrustStore", {
136 caCertificatesBundleS3Bucket: bucket.bucketName,
137 caCertificatesBundleS3Key: bundleKey,
138 });
139 return { targetGroup, loadBalancer, trustStore };
140 }),
141);
142
143export default ElbBindingsFunction.make(
144 {
145 main: import.meta.url,
146 functionUrl: true,
147 },
148 Effect.gen(function* () {
149 const { targetGroup, loadBalancer, trustStore } = yield* BindingsFleet;
150
151 const registerTargets = yield* RegisterTargets(targetGroup);
152 const deregisterTargets = yield* DeregisterTargets(targetGroup);
153 const describeTargetHealth = yield* DescribeTargetHealth(targetGroup);
154 const describeCapacityReservation =
155 yield* DescribeCapacityReservation(loadBalancer);
156 const modifyCapacityReservation =
157 yield* ModifyCapacityReservation(loadBalancer);
158 const getCaCertificatesBundle =
159 yield* GetTrustStoreCaCertificatesBundle(trustStore);
160 const getRevocationContent =
161 yield* GetTrustStoreRevocationContent(trustStore);
162
163 return {
164 fetch: Effect.gen(function* () {
165 const request = yield* HttpServerRequest;
166 const pathname = new URL(request.originalUrl).pathname;
167
168 if (request.method === "GET" && pathname === "/health") {
169 return yield* HttpServerResponse.json({ ok: true });
170 }
171
172 if (request.method === "POST" && pathname === "/register") {
173 const result = yield* registerTargets({
174 Targets: [{ Id: testTargetIp, Port: 80, AvailabilityZone: "all" }],
175 }).pipe(Effect.result);
176 return yield* HttpServerResponse.json({
177 ok: result._tag === "Success",
178 tag: result._tag === "Failure" ? result.failure._tag : "Success",
179 message:
180 result._tag === "Failure" ? String(result.failure) : undefined,
181 });
182 }
183
184 if (request.method === "GET" && pathname === "/target-health") {
185 const result = yield* describeTargetHealth({}).pipe(Effect.result);
186 return yield* HttpServerResponse.json({
187 ok: result._tag === "Success",
188 tag: result._tag === "Failure" ? result.failure._tag : "Success",
189 targets:
190 result._tag === "Success"
191 ? (result.success.TargetHealthDescriptions ?? []).map((d) => ({
192 id: d.Target?.Id,
193 state: d.TargetHealth?.State,
194 }))
195 : undefined,
196 });
197 }
198
199 if (request.method === "POST" && pathname === "/deregister") {
200 const result = yield* deregisterTargets({
201 Targets: [{ Id: testTargetIp, Port: 80, AvailabilityZone: "all" }],
202 }).pipe(Effect.result);
203 return yield* HttpServerResponse.json({
204 ok: result._tag === "Success",
205 tag: result._tag === "Failure" ? result.failure._tag : "Success",
206 });
207 }
208
209 if (request.method === "GET" && pathname === "/capacity") {
210 const result = yield* describeCapacityReservation().pipe(
211 Effect.result,
212 );
213 return yield* HttpServerResponse.json({
214 ok: result._tag === "Success",
215 tag: result._tag === "Failure" ? result.failure._tag : "Success",
216 states:
217 result._tag === "Success"
218 ? (result.success.CapacityReservationState ?? []).map(
219 (s) => s.State,
220 )
221 : undefined,
222 });
223 }
224
225 // Resets a reservation that was never set — a no-op that proves the
226 // write grant end-to-end without reserving billable LCUs.
227 if (request.method === "POST" && pathname === "/capacity-reset") {
228 const result = yield* modifyCapacityReservation({
229 ResetCapacityReservation: true,
230 }).pipe(Effect.result);
231 return yield* HttpServerResponse.json({
232 ok: result._tag === "Success",
233 tag: result._tag === "Failure" ? result.failure._tag : "Success",
234 });
235 }
236
237 if (request.method === "GET" && pathname === "/truststore-bundle") {
238 const result = yield* getCaCertificatesBundle().pipe(Effect.result);
239 return yield* HttpServerResponse.json({
240 ok: result._tag === "Success",
241 tag: result._tag === "Failure" ? result.failure._tag : "Success",
242 // A presigned S3 URL, valid for ten minutes.
243 location:
244 result._tag === "Success" ? result.success.Location : undefined,
245 });
246 }
247
248 // Queries a revocation id that was never added — proves the IAM grant
249 // and that the miss surfaces as the typed tag, without needing a CRL
250 // fixture.
251 if (
252 request.method === "GET" &&
253 pathname === "/truststore-revocation-missing"
254 ) {
255 const result = yield* getRevocationContent({
256 RevocationId: 424242,
257 }).pipe(Effect.result);
258 return yield* HttpServerResponse.json({
259 ok: result._tag === "Success",
260 tag: result._tag === "Failure" ? result.failure._tag : "Success",
261 });
262 }
263
264 return yield* HttpServerResponse.json(
265 { error: "Not found", method: request.method, pathname },
266 { status: 404 },
267 );
268 }).pipe(Effect.orDie),
269 };
270 }).pipe(
271 Effect.provide(
272 Layer.mergeAll(
273 RegisterTargetsHttp,
274 DeregisterTargetsHttp,
275 DescribeTargetHealthHttp,
276 DescribeCapacityReservationHttp,
277 ModifyCapacityReservationHttp,
278 GetTrustStoreCaCertificatesBundleHttp,
279 GetTrustStoreRevocationContentHttp,
280 BindingsFleetLive,
281 ),
282 ),
283 ),
284);