1import * as CloudHSMV2 from "@/AWS/CloudHSMV2";
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// Well-formed-but-nonexistent identifiers — every route drives its binding
12// against these so the fixture exercises IAM grants + typed error decoding
13// at zero cost (no cluster, no HSM, no backup is ever created).
14const NONEXISTENT_CLUSTER_ID = "cluster-aaaaaaaaaaa";
15const NONEXISTENT_BACKUP_ID = "backup-aaaaaaaaaaa";
16
17// Placeholder PEM material for InitializeCluster — the nonexistent cluster
18// id is rejected before the certificates are parsed.
19const PLACEHOLDER_PEM =
20 "-----BEGIN CERTIFICATE-----\nMIIB\n-----END CERTIFICATE-----";
21
22export class CloudHSMV2TestFunction extends Lambda.Function<Lambda.Function>()(
23 "CloudHSMV2TestFunction",
24) {}
25
26export default CloudHSMV2TestFunction.make(
27 {
28 main,
29 functionUrl: true,
30 },
31 Effect.gen(function* () {
32 const describeClusters = yield* CloudHSMV2.DescribeClusters();
33 const describeBackups = yield* CloudHSMV2.DescribeBackups();
34 const deleteBackup = yield* CloudHSMV2.DeleteBackup();
35 const restoreBackup = yield* CloudHSMV2.RestoreBackup();
36 const modifyBackupAttributes = yield* CloudHSMV2.ModifyBackupAttributes();
37 const copyBackupToRegion = yield* CloudHSMV2.CopyBackupToRegion();
38 const initializeCluster = yield* CloudHSMV2.InitializeCluster();
39 const getResourcePolicy = yield* CloudHSMV2.GetResourcePolicy();
40 const putResourcePolicy = yield* CloudHSMV2.PutResourcePolicy();
41 const deleteResourcePolicy = yield* CloudHSMV2.DeleteResourcePolicy();
42
43 const bound = {
44 describeClusters,
45 describeBackups,
46 deleteBackup,
47 restoreBackup,
48 modifyBackupAttributes,
49 copyBackupToRegion,
50 initializeCluster,
51 getResourcePolicy,
52 putResourcePolicy,
53 deleteResourcePolicy,
54 };
55
56 return {
57 fetch: Effect.gen(function* () {
58 const request = yield* HttpServerRequest;
59 const url = new URL(request.originalUrl);
60 const pathname = url.pathname;
61
62 if (request.method === "GET" && pathname === "/bindings") {
63 return yield* HttpServerResponse.json({
64 bound: Object.keys(bound),
65 });
66 }
67
68 if (request.method === "GET" && pathname === "/clusters") {
69 // A filter on a nonexistent id yields an empty page — proves the
70 // grant and the response schema decode deterministically.
71 const result = yield* describeClusters({
72 Filters: { clusterIds: [NONEXISTENT_CLUSTER_ID] },
73 });
74 return yield* HttpServerResponse.json({
75 count: (result.Clusters ?? []).length,
76 });
77 }
78
79 if (request.method === "GET" && pathname === "/backups") {
80 const result = yield* describeBackups({
81 Filters: { backupIds: [NONEXISTENT_BACKUP_ID] },
82 });
83 return yield* HttpServerResponse.json({
84 count: (result.Backups ?? []).length,
85 });
86 }
87
88 if (request.method === "GET" && pathname === "/backup-delete") {
89 // A nonexistent backup id must surface the service's typed
90 // not-found tag — an IAM gap would surface AccessDeniedException
91 // and fail the route with an opaque 500 instead.
92 const tag = yield* deleteBackup({
93 BackupId: NONEXISTENT_BACKUP_ID,
94 }).pipe(
95 Effect.map(() => "Deleted"),
96 Effect.catchTag("CloudHsmResourceNotFoundException", (e) =>
97 Effect.succeed(e._tag),
98 ),
99 );
100 return yield* HttpServerResponse.json({ tag });
101 }
102
103 if (request.method === "GET" && pathname === "/backup-restore") {
104 const tag = yield* restoreBackup({
105 BackupId: NONEXISTENT_BACKUP_ID,
106 }).pipe(
107 Effect.map(() => "Restored"),
108 Effect.catchTag("CloudHsmResourceNotFoundException", (e) =>
109 Effect.succeed(e._tag),
110 ),
111 );
112 return yield* HttpServerResponse.json({ tag });
113 }
114
115 if (request.method === "GET" && pathname === "/backup-modify") {
116 const tag = yield* modifyBackupAttributes({
117 BackupId: NONEXISTENT_BACKUP_ID,
118 NeverExpires: true,
119 }).pipe(
120 Effect.map(() => "Modified"),
121 Effect.catchTag("CloudHsmResourceNotFoundException", (e) =>
122 Effect.succeed(e._tag),
123 ),
124 );
125 return yield* HttpServerResponse.json({ tag });
126 }
127
128 if (request.method === "GET" && pathname === "/backup-copy") {
129 const region = yield* Effect.sync(
130 () => process.env.AWS_REGION ?? "us-west-2",
131 );
132 const tag = yield* copyBackupToRegion({
133 DestinationRegion:
134 region === "us-east-1" ? "us-west-2" : "us-east-1",
135 BackupId: NONEXISTENT_BACKUP_ID,
136 }).pipe(
137 Effect.map(() => "Copied"),
138 Effect.catchTag(
139 [
140 "CloudHsmResourceNotFoundException",
141 "CloudHsmInvalidRequestException",
142 ],
143 (e) => Effect.succeed(e._tag),
144 ),
145 );
146 return yield* HttpServerResponse.json({ tag });
147 }
148
149 if (request.method === "GET" && pathname === "/cluster-init") {
150 const tag = yield* initializeCluster({
151 ClusterId: NONEXISTENT_CLUSTER_ID,
152 SignedCert: PLACEHOLDER_PEM,
153 TrustAnchor: PLACEHOLDER_PEM,
154 }).pipe(
155 Effect.map(() => "Initialized"),
156 Effect.catchTag(
157 [
158 "CloudHsmResourceNotFoundException",
159 "CloudHsmInvalidRequestException",
160 ],
161 (e) => Effect.succeed(e._tag),
162 ),
163 );
164 return yield* HttpServerResponse.json({ tag });
165 }
166
167 if (request.method === "GET" && pathname === "/policy-get") {
168 // An empty request fails service-side validation — reaching the
169 // service's validator at all proves the IAM grant.
170 const tag = yield* getResourcePolicy().pipe(
171 Effect.map(() => "Found"),
172 Effect.catchTag(
173 [
174 "CloudHsmInvalidRequestException",
175 "CloudHsmResourceNotFoundException",
176 ],
177 (e) => Effect.succeed(e._tag),
178 ),
179 );
180 return yield* HttpServerResponse.json({ tag });
181 }
182
183 if (request.method === "GET" && pathname === "/policy-put") {
184 const tag = yield* putResourcePolicy({}).pipe(
185 Effect.map(() => "Put"),
186 Effect.catchTag(
187 [
188 "CloudHsmInvalidRequestException",
189 "CloudHsmResourceNotFoundException",
190 ],
191 (e) => Effect.succeed(e._tag),
192 ),
193 );
194 return yield* HttpServerResponse.json({ tag });
195 }
196
197 if (request.method === "GET" && pathname === "/policy-delete") {
198 const tag = yield* deleteResourcePolicy({}).pipe(
199 Effect.map(() => "PolicyDeleted"),
200 Effect.catchTag(
201 [
202 "CloudHsmInvalidRequestException",
203 "CloudHsmResourceNotFoundException",
204 ],
205 (e) => Effect.succeed(e._tag),
206 ),
207 );
208 return yield* HttpServerResponse.json({ tag });
209 }
210
211 return yield* HttpServerResponse.json(
212 { error: "Not found", method: request.method, pathname },
213 { status: 404 },
214 );
215 }).pipe(Effect.orDie),
216 };
217 }).pipe(
218 Effect.provide(
219 Layer.mergeAll(
220 CloudHSMV2.DescribeClustersHttp,
221 CloudHSMV2.DescribeBackupsHttp,
222 CloudHSMV2.DeleteBackupHttp,
223 CloudHSMV2.RestoreBackupHttp,
224 CloudHSMV2.ModifyBackupAttributesHttp,
225 CloudHSMV2.CopyBackupToRegionHttp,
226 CloudHSMV2.InitializeClusterHttp,
227 CloudHSMV2.GetResourcePolicyHttp,
228 CloudHSMV2.PutResourcePolicyHttp,
229 CloudHSMV2.DeleteResourcePolicyHttp,
230 ),
231 ),
232 ),
233);