1import * as ControlTower from "@/AWS/ControlTower";
2import * as Lambda from "@/AWS/Lambda";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import { HttpServerRequest } from "effect/http/HttpServerRequest";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7import path from "pathe";
8
9const main = path.resolve(import.meta.dirname, "handler.ts");
10
11// A well-formed-but-nonexistent operation id — drives the typed error paths
12// for the operation-status bindings (proving the IAM grant + typed union;
13// an IAM gap would surface AccessDeniedException instead).
14const NONEXISTENT_OPERATION_ID = "00000000-0000-0000-0000-000000000000";
15
16// A well-formed-but-foreign landing zone ARN — the testing account has no
17// landing zone, so any identifier is absent.
18const NONEXISTENT_LANDING_ZONE_ARN =
19 "arn:aws:controltower:us-west-2:111111111111:landingzone/AAAAAAAAAAAAAAAA";
20
21export class ControlTowerTestFunction extends Lambda.Function<Lambda.Function>()(
22 "ControlTowerTestFunction",
23) {}
24
25export default ControlTowerTestFunction.make(
26 {
27 main,
28 functionUrl: true,
29 },
30 Effect.gen(function* () {
31 // --- account-level bindings (Control Tower has no data plane; these
32 // are the read/audit + operation-status APIs a governance function
33 // uses) ---
34 const listBaselines = yield* ControlTower.ListBaselines();
35 const getBaseline = yield* ControlTower.GetBaseline();
36 const listEnabledBaselines = yield* ControlTower.ListEnabledBaselines();
37 const getBaselineOperation = yield* ControlTower.GetBaselineOperation();
38 const listEnabledControls = yield* ControlTower.ListEnabledControls();
39 const getControlOperation = yield* ControlTower.GetControlOperation();
40 const listControlOperations = yield* ControlTower.ListControlOperations();
41 const listLandingZones = yield* ControlTower.ListLandingZones();
42 const getLandingZone = yield* ControlTower.GetLandingZone();
43 const getLandingZoneOperation =
44 yield* ControlTower.GetLandingZoneOperation();
45 const listLandingZoneOperations =
46 yield* ControlTower.ListLandingZoneOperations();
47
48 const bound = {
49 listBaselines,
50 getBaseline,
51 listEnabledBaselines,
52 getBaselineOperation,
53 listEnabledControls,
54 getControlOperation,
55 listControlOperations,
56 listLandingZones,
57 getLandingZone,
58 getLandingZoneOperation,
59 listLandingZoneOperations,
60 };
61
62 return {
63 fetch: Effect.gen(function* () {
64 const request = yield* HttpServerRequest;
65 const url = new URL(request.originalUrl);
66 const pathname = url.pathname;
67
68 if (request.method === "GET" && pathname === "/bindings") {
69 return yield* HttpServerResponse.json({
70 bound: Object.keys(bound),
71 });
72 }
73
74 if (request.method === "GET" && pathname === "/baselines") {
75 // The baseline catalog is served even without a landing zone;
76 // some org configurations reject the call outright — but always
77 // with a typed tag.
78 const result = yield* listBaselines().pipe(
79 Effect.map((r) => ({
80 ok: true as const,
81 names: r.baselines.map((b) => b.name ?? null),
82 })),
83 Effect.catchTag(
84 ["AccessDeniedException", "UnauthorizedException"],
85 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
86 ),
87 );
88 return yield* HttpServerResponse.json(result);
89 }
90
91 if (request.method === "GET" && pathname === "/baseline") {
92 // Discover a baseline ARN from the catalog, then read it back —
93 // proves GetBaseline's grant end-to-end.
94 const result = yield* listBaselines().pipe(
95 Effect.flatMap((r) =>
96 Effect.gen(function* () {
97 const arn = r.baselines.find(
98 (b) => b.name === "AWSControlTowerBaseline",
99 )?.arn;
100 if (arn === undefined) {
101 return { ok: false as const, tag: "NoCatalog" };
102 }
103 const b = yield* getBaseline({ baselineIdentifier: arn });
104 return { ok: true as const, name: b.name };
105 }),
106 ),
107 Effect.catchTag(
108 [
109 "AccessDeniedException",
110 "UnauthorizedException",
111 "ResourceNotFoundException",
112 ],
113 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
114 ),
115 );
116 return yield* HttpServerResponse.json(result);
117 }
118
119 if (request.method === "GET" && pathname === "/enabled-baselines") {
120 // The baseline API family rejects accounts without a landing
121 // zone with the typed UnauthorizedException (distilled patch).
122 const result = yield* listEnabledBaselines().pipe(
123 Effect.map((r) => ({
124 ok: true as const,
125 count: r.enabledBaselines.length,
126 })),
127 Effect.catchTag(
128 [
129 "AccessDeniedException",
130 "UnauthorizedException",
131 "ValidationException",
132 ],
133 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
134 ),
135 );
136 return yield* HttpServerResponse.json(result);
137 }
138
139 if (request.method === "GET" && pathname === "/enabled-controls") {
140 const result = yield* listEnabledControls().pipe(
141 Effect.map((r) => ({
142 ok: true as const,
143 count: r.enabledControls.length,
144 })),
145 Effect.catchTag(
146 [
147 "AccessDeniedException",
148 "ResourceNotFoundException",
149 "ValidationException",
150 ],
151 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
152 ),
153 );
154 return yield* HttpServerResponse.json(result);
155 }
156
157 if (request.method === "GET" && pathname === "/control-operations") {
158 const result = yield* listControlOperations().pipe(
159 Effect.map((r) => ({
160 ok: true as const,
161 count: r.controlOperations.length,
162 })),
163 // ListControlOperations never throws ResourceNotFoundException
164 // (per the distilled union + AWS docs) — only the access/validation
165 // family applies here.
166 Effect.catchTag(
167 ["AccessDeniedException", "ValidationException"],
168 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
169 ),
170 );
171 return yield* HttpServerResponse.json(result);
172 }
173
174 if (request.method === "GET" && pathname === "/landing-zones") {
175 // The testing account has no landing zone — an empty (or
176 // singleton) list, never a crash.
177 const result = yield* listLandingZones().pipe(
178 Effect.map((r) => ({
179 ok: true as const,
180 count: r.landingZones.length,
181 })),
182 Effect.catchTag(
183 ["AccessDeniedException", "UnauthorizedException"],
184 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
185 ),
186 );
187 return yield* HttpServerResponse.json(result);
188 }
189
190 if (
191 request.method === "GET" &&
192 pathname === "/landing-zone-operations"
193 ) {
194 const result = yield* listLandingZoneOperations().pipe(
195 Effect.map((r) => ({
196 ok: true as const,
197 count: r.landingZoneOperations.length,
198 })),
199 Effect.catchTag(
200 [
201 "AccessDeniedException",
202 "UnauthorizedException",
203 "ValidationException",
204 ],
205 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
206 ),
207 );
208 return yield* HttpServerResponse.json(result);
209 }
210
211 if (
212 request.method === "GET" &&
213 pathname === "/landing-zone-not-found"
214 ) {
215 const tag = yield* getLandingZone({
216 landingZoneIdentifier: NONEXISTENT_LANDING_ZONE_ARN,
217 }).pipe(
218 Effect.map(() => "Found"),
219 Effect.catchTag(
220 [
221 "ResourceNotFoundException",
222 "ValidationException",
223 "AccessDeniedException",
224 "UnauthorizedException",
225 ],
226 (e) => Effect.succeed(e._tag),
227 ),
228 );
229 return yield* HttpServerResponse.json({ tag });
230 }
231
232 if (
233 request.method === "GET" &&
234 pathname === "/control-operation-not-found"
235 ) {
236 const tag = yield* getControlOperation({
237 operationIdentifier: NONEXISTENT_OPERATION_ID,
238 }).pipe(
239 Effect.map(() => "Found"),
240 Effect.catchTag(
241 [
242 "ResourceNotFoundException",
243 "ValidationException",
244 "AccessDeniedException",
245 ],
246 (e) => Effect.succeed(e._tag),
247 ),
248 );
249 return yield* HttpServerResponse.json({ tag });
250 }
251
252 if (
253 request.method === "GET" &&
254 pathname === "/baseline-operation-not-found"
255 ) {
256 const result = yield* getBaselineOperation({
257 operationIdentifier: NONEXISTENT_OPERATION_ID,
258 }).pipe(
259 Effect.map(() => ({ tag: "Found", message: "" })),
260 Effect.catchTag(
261 [
262 "ResourceNotFoundException",
263 "ValidationException",
264 "AccessDeniedException",
265 "UnauthorizedException",
266 ],
267 (e) => Effect.succeed({ tag: e._tag, message: e.message }),
268 ),
269 );
270 return yield* HttpServerResponse.json(result);
271 }
272
273 if (
274 request.method === "GET" &&
275 pathname === "/landing-zone-operation-not-found"
276 ) {
277 const result = yield* getLandingZoneOperation({
278 operationIdentifier: NONEXISTENT_OPERATION_ID,
279 }).pipe(
280 Effect.map(() => ({ tag: "Found", message: "" })),
281 Effect.catchTag(
282 [
283 "ResourceNotFoundException",
284 "ValidationException",
285 "AccessDeniedException",
286 "UnauthorizedException",
287 ],
288 (e) => Effect.succeed({ tag: e._tag, message: e.message }),
289 ),
290 );
291 return yield* HttpServerResponse.json(result);
292 }
293
294 return yield* HttpServerResponse.json(
295 { error: "Not found", method: request.method, pathname },
296 { status: 404 },
297 );
298 }).pipe(Effect.orDie),
299 };
300 }).pipe(
301 Effect.provide(
302 Layer.mergeAll(
303 ControlTower.ListBaselinesHttp,
304 ControlTower.GetBaselineHttp,
305 ControlTower.ListEnabledBaselinesHttp,
306 ControlTower.GetBaselineOperationHttp,
307 ControlTower.ListEnabledControlsHttp,
308 ControlTower.GetControlOperationHttp,
309 ControlTower.ListControlOperationsHttp,
310 ControlTower.ListLandingZonesHttp,
311 ControlTower.GetLandingZoneHttp,
312 ControlTower.GetLandingZoneOperationHttp,
313 ControlTower.ListLandingZoneOperationsHttp,
314 ),
315 ),
316 ),
317);