1import * as AWS from "@/AWS";
2import { Enabler } from "@/AWS/Inspector2/Enabler.ts";
3import * as Provider from "@/Provider";
4import * as Test from "@/Test/Alchemy";
5import * as inspector2 from "@distilled.cloud/aws/inspector2";
6import { expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11const accountStatus = inspector2
12 .batchGetAccountStatus({})
13 .pipe(Effect.map((r) => r.accounts?.[0]));
14
15const typeStatus = (
16 account: inspector2.AccountState | undefined,
17 key: "ec2" | "ecr" | "lambda",
18) => account?.resourceState?.[key]?.status;
19
20test.provider(
21 "account scan status is observable",
22 () =>
23 Effect.gen(function* () {
24 const account = yield* accountStatus;
25 expect(account?.accountId).toBeTruthy();
26 expect(
27 ["ENABLED", "ENABLING", "DISABLED", "DISABLING"].includes(
28 typeStatus(account, "ec2") ?? "",
29 ),
30 ).toBe(true);
31 expect(
32 ["ENABLED", "ENABLING", "DISABLED", "DISABLING"].includes(
33 typeStatus(account, "ecr") ?? "",
34 ),
35 ).toBe(true);
36 }),
37 { tags: ["provider:aws", "provider:aws:inspector2", "live"] },
38);
39
40// The Inspector enabler is an account/region singleton. This test only runs
41// when Inspector is fully disabled — it must never disable scan types the user
42// already enabled (capture-and-restore safety).
43test.provider.skipIf(!process.env.INSPECTOR2_TEST_ENABLER)(
44 "lifecycle: enable EC2/ECR, add LAMBDA, disable",
45 (stack) =>
46 Effect.gen(function* () {
47 const preexisting = yield* accountStatus;
48 if (preexisting && preexisting.state?.status !== "DISABLED") {
49 yield* Effect.logInfo(
50 `Inspector already enabled (${preexisting.state?.status}) — skipping destructive lifecycle test`,
51 );
52 return;
53 }
54
55 yield* stack.destroy();
56
57 // Create — enable EC2 + ECR scanning.
58 const created = yield* stack.deploy(
59 Effect.gen(function* () {
60 return yield* Enabler("Inspector", {
61 resourceTypes: ["EC2", "ECR"],
62 });
63 }),
64 );
65 expect(created.accountId).toBeTruthy();
66 expect(created.resourceTypes.sort()).toEqual(["EC2", "ECR"]);
67
68 // Out-of-band verification.
69 const live = yield* accountStatus;
70 expect(typeStatus(live, "ec2")).toBe("ENABLED");
71 expect(typeStatus(live, "ecr")).toBe("ENABLED");
72
73 // Canonical list() coverage.
74 const provider = yield* Provider.findProvider(Enabler);
75 const all = yield* provider.list();
76 expect(all.some((e) => e.accountId === created.accountId)).toBe(true);
77
78 // Update — add LAMBDA scanning.
79 const updated = yield* stack.deploy(
80 Effect.gen(function* () {
81 return yield* Enabler("Inspector", {
82 resourceTypes: ["EC2", "ECR", "LAMBDA"],
83 });
84 }),
85 );
86 expect(updated.resourceTypes.sort()).toEqual(["EC2", "ECR", "LAMBDA"]);
87 const afterUpdate = yield* accountStatus;
88 expect(typeStatus(afterUpdate, "lambda")).toBe("ENABLED");
89
90 // Destroy — Inspector scanning is disabled again.
91 yield* stack.destroy();
92 const after = yield* accountStatus;
93 expect(typeStatus(after, "ec2")).not.toBe("ENABLED");
94 expect(typeStatus(after, "ecr")).not.toBe("ENABLED");
95 expect(typeStatus(after, "lambda")).not.toBe("ENABLED");
96 }),
97 {
98 tags: ["provider:aws", "provider:aws:inspector2", "live"],
99 timeout: 240_000,
100 },
101);