1import * as AuditManager from "@/AWS/AuditManager";
2import * as IAM from "@/AWS/IAM";
3import * as Lambda from "@/AWS/Lambda";
4import { Bucket } from "@/AWS/S3/Bucket.ts";
5import * as Output from "@/Output";
6import * as Effect from "effect/Effect";
7import * as Layer from "effect/Layer";
8import { HttpServerRequest } from "effect/http/HttpServerRequest";
9import * as HttpServerResponse from "effect/http/HttpServerResponse";
10import path from "pathe";
11
12const main = path.resolve(import.meta.dirname, "handler-assessment.ts");
13
14export class AuditManagerAssessmentTestFunction extends Lambda.Function<Lambda.Function>()(
15 "AuditManagerAssessmentTestFunction",
16) {}
17
18/**
19 * Assessment-scoped Audit Manager bindings fixture.
20 *
21 * Requires an account registered with Audit Manager — gated behind
22 * `AWS_TEST_AUDITMANAGER=1` because the service entered maintenance mode on
23 * 2026-04-30 and unregistered accounts can never be registered.
24 *
25 * All 22 assessment-scoped capabilities are bound (so their deploy-time IAM
26 * registration is exercised); the read-only ones are additionally driven
27 * over HTTP.
28 */
29export default AuditManagerAssessmentTestFunction.make(
30 {
31 main,
32 functionUrl: true,
33 },
34 Effect.gen(function* () {
35 const control = yield* AuditManager.Control("BindingsControl", {
36 description: "AuditManager bindings fixture control",
37 controlMappingSources: [
38 {
39 sourceName: "manual-evidence",
40 sourceSetUpOption: "Procedural_Controls_Mapping",
41 sourceType: "MANUAL",
42 },
43 ],
44 });
45
46 const framework = yield* AuditManager.Framework("BindingsFramework", {
47 description: "AuditManager bindings fixture framework",
48 controlSets: [
49 { name: "Operations", controls: [{ id: control.controlId }] },
50 ],
51 });
52
53 const reports = yield* Bucket("BindingsReports", { forceDestroy: true });
54
55 const owner = yield* IAM.Role("BindingsAuditOwner", {
56 assumeRolePolicyDocument: {
57 Version: "2012-10-17",
58 Statement: [
59 {
60 Effect: "Allow",
61 Principal: { Service: ["auditmanager.amazonaws.com"] },
62 Action: ["sts:AssumeRole"],
63 },
64 ],
65 },
66 });
67
68 const assessment = yield* AuditManager.Assessment("BindingsAssessment", {
69 description: "AuditManager bindings fixture assessment",
70 frameworkId: framework.frameworkId,
71 assessmentReportsDestination: {
72 destination: Output.interpolate`s3://${reports.bucketName}`,
73 },
74 roles: [{ roleType: "PROCESS_OWNER", roleArn: owner.roleArn }],
75 });
76
77 // --- reads ---
78 const getEvidence = yield* AuditManager.GetEvidence(assessment);
79 const getEvidenceByEvidenceFolder =
80 yield* AuditManager.GetEvidenceByEvidenceFolder(assessment);
81 const getEvidenceFolder = yield* AuditManager.GetEvidenceFolder(assessment);
82 const getEvidenceFoldersByAssessment =
83 yield* AuditManager.GetEvidenceFoldersByAssessment(assessment);
84 const getEvidenceFoldersByAssessmentControl =
85 yield* AuditManager.GetEvidenceFoldersByAssessmentControl(assessment);
86 const getChangeLogs = yield* AuditManager.GetChangeLogs(assessment);
87 const getInsightsByAssessment =
88 yield* AuditManager.GetInsightsByAssessment(assessment);
89 const listControlDomainInsightsByAssessment =
90 yield* AuditManager.ListControlDomainInsightsByAssessment(assessment);
91 const listAssessmentControlInsightsByControlDomain =
92 yield* AuditManager.ListAssessmentControlInsightsByControlDomain(
93 assessment,
94 );
95
96 // --- evidence + reports ---
97 const batchImportEvidenceToAssessmentControl =
98 yield* AuditManager.BatchImportEvidenceToAssessmentControl(assessment);
99 const createAssessmentReport =
100 yield* AuditManager.CreateAssessmentReport(assessment);
101 const deleteAssessmentReport =
102 yield* AuditManager.DeleteAssessmentReport(assessment);
103 const getAssessmentReportUrl =
104 yield* AuditManager.GetAssessmentReportUrl(assessment);
105 const associateAssessmentReportEvidenceFolder =
106 yield* AuditManager.AssociateAssessmentReportEvidenceFolder(assessment);
107 const disassociateAssessmentReportEvidenceFolder =
108 yield* AuditManager.DisassociateAssessmentReportEvidenceFolder(
109 assessment,
110 );
111 const batchAssociateAssessmentReportEvidence =
112 yield* AuditManager.BatchAssociateAssessmentReportEvidence(assessment);
113 const batchDisassociateAssessmentReportEvidence =
114 yield* AuditManager.BatchDisassociateAssessmentReportEvidence(assessment);
115
116 // --- delegations + workflow ---
117 const batchCreateDelegationByAssessment =
118 yield* AuditManager.BatchCreateDelegationByAssessment(assessment);
119 const batchDeleteDelegationByAssessment =
120 yield* AuditManager.BatchDeleteDelegationByAssessment(assessment);
121 const updateAssessmentControl =
122 yield* AuditManager.UpdateAssessmentControl(assessment);
123 const updateAssessmentControlSetStatus =
124 yield* AuditManager.UpdateAssessmentControlSetStatus(assessment);
125 const updateAssessmentStatus =
126 yield* AuditManager.UpdateAssessmentStatus(assessment);
127
128 const bound = {
129 getEvidence,
130 getEvidenceByEvidenceFolder,
131 getEvidenceFolder,
132 getEvidenceFoldersByAssessment,
133 getEvidenceFoldersByAssessmentControl,
134 getChangeLogs,
135 getInsightsByAssessment,
136 listControlDomainInsightsByAssessment,
137 listAssessmentControlInsightsByControlDomain,
138 batchImportEvidenceToAssessmentControl,
139 createAssessmentReport,
140 deleteAssessmentReport,
141 getAssessmentReportUrl,
142 associateAssessmentReportEvidenceFolder,
143 disassociateAssessmentReportEvidenceFolder,
144 batchAssociateAssessmentReportEvidence,
145 batchDisassociateAssessmentReportEvidence,
146 batchCreateDelegationByAssessment,
147 batchDeleteDelegationByAssessment,
148 updateAssessmentControl,
149 updateAssessmentControlSetStatus,
150 updateAssessmentStatus,
151 };
152
153 return {
154 fetch: Effect.gen(function* () {
155 const request = yield* HttpServerRequest;
156 const url = new URL(request.originalUrl);
157 const pathname = url.pathname;
158
159 if (request.method === "GET" && pathname === "/bindings") {
160 return yield* HttpServerResponse.json({
161 bound: Object.keys(bound),
162 });
163 }
164
165 if (request.method === "GET" && pathname === "/evidence-folders") {
166 const result = yield* getEvidenceFoldersByAssessment({
167 maxResults: 20,
168 });
169 return yield* HttpServerResponse.json({
170 count: (result.evidenceFolders ?? []).length,
171 });
172 }
173
174 if (request.method === "GET" && pathname === "/insights") {
175 const result = yield* getInsightsByAssessment();
176 return yield* HttpServerResponse.json({
177 totalAssessmentControlsCount:
178 result.insights?.totalAssessmentControlsCount ?? 0,
179 });
180 }
181
182 if (request.method === "GET" && pathname === "/changelogs") {
183 const result = yield* getChangeLogs({ maxResults: 20 });
184 return yield* HttpServerResponse.json({
185 count: (result.changeLogs ?? []).length,
186 });
187 }
188
189 return yield* HttpServerResponse.json(
190 { error: "Not found", method: request.method, pathname },
191 { status: 404 },
192 );
193 }).pipe(Effect.orDie),
194 };
195 }).pipe(
196 Effect.provide(
197 Layer.mergeAll(
198 AuditManager.GetEvidenceHttp,
199 AuditManager.GetEvidenceByEvidenceFolderHttp,
200 AuditManager.GetEvidenceFolderHttp,
201 AuditManager.GetEvidenceFoldersByAssessmentHttp,
202 AuditManager.GetEvidenceFoldersByAssessmentControlHttp,
203 AuditManager.GetChangeLogsHttp,
204 AuditManager.GetInsightsByAssessmentHttp,
205 AuditManager.ListControlDomainInsightsByAssessmentHttp,
206 AuditManager.ListAssessmentControlInsightsByControlDomainHttp,
207 AuditManager.BatchImportEvidenceToAssessmentControlHttp,
208 AuditManager.CreateAssessmentReportHttp,
209 AuditManager.DeleteAssessmentReportHttp,
210 AuditManager.GetAssessmentReportUrlHttp,
211 AuditManager.AssociateAssessmentReportEvidenceFolderHttp,
212 AuditManager.DisassociateAssessmentReportEvidenceFolderHttp,
213 AuditManager.BatchAssociateAssessmentReportEvidenceHttp,
214 AuditManager.BatchDisassociateAssessmentReportEvidenceHttp,
215 AuditManager.BatchCreateDelegationByAssessmentHttp,
216 AuditManager.BatchDeleteDelegationByAssessmentHttp,
217 AuditManager.UpdateAssessmentControlHttp,
218 AuditManager.UpdateAssessmentControlSetStatusHttp,
219 AuditManager.UpdateAssessmentStatusHttp,
220 ),
221 ),
222 ),
223);