1import * as AWS from "@/AWS";
2import { ServiceSpecificCredential, User } from "@/AWS/IAM";
3import * as Provider from "@/Provider";
4import * as Test from "@/Test/Alchemy";
5import * as IAM from "@distilled.cloud/aws/iam";
6import { describe, expect } from "alchemy-test";
7import * as Effect from "effect/Effect";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11describe(
12 "AWS.IAM.ServiceSpecificCredential",
13 { tags: ["provider:aws", "provider:aws:iam", "live"] },
14 () => {
15 // Canonical `list()` test: IAM is a global service and service-specific
16 // credentials are owned per IAM user, so the provider enumerates every user
17 // first and then lists credentials per user. Deploy a real user + credential,
18 // resolve the provider from context with the typed `findProvider`, call
19 // `list()`, and assert the deployed credential appears in the result.
20 test.provider(
21 "list enumerates the deployed service-specific credential",
22 (stack) =>
23 Effect.gen(function* () {
24 yield* stack.destroy();
25
26 const deployed = yield* stack.deploy(
27 Effect.gen(function* () {
28 const user = yield* User("SsCredListOwner", {});
29 const credential = yield* ServiceSpecificCredential(
30 "SsCredListCred",
31 {
32 userName: user.userName,
33 serviceName: "codecommit.amazonaws.com",
34 // Duration.Input prop — converted to whole wire days.
35 credentialAge: "30 days",
36 },
37 );
38 return { user, credential };
39 }),
40 );
41
42 // The Duration prop round-trips as an expiration ~30 days out, and
43 // the creation-only secret is captured as a Redacted output.
44 expect(deployed.credential.expirationDate).toBeDefined();
45 expect(deployed.credential.servicePassword).toBeDefined();
46
47 const provider = yield* Provider.findProvider(
48 ServiceSpecificCredential,
49 );
50 const all = yield* provider.list();
51
52 const found = all.find(
53 (entry) =>
54 entry.serviceSpecificCredentialId ===
55 deployed.credential.serviceSpecificCredentialId,
56 );
57 expect(found).toBeDefined();
58 expect(found?.userName).toBe(deployed.user.userName);
59 expect(found?.serviceName).toBe("codecommit.amazonaws.com");
60 expect(found?.servicePassword).toBeUndefined();
61 expect(found?.serviceCredentialSecret).toBeUndefined();
62
63 yield* stack.destroy();
64
65 // The user (and with it the service-specific credential) is gone.
66 const deletedUser = yield* IAM.getUser({
67 UserName: deployed.user.userName,
68 }).pipe(Effect.option);
69 expect(deletedUser._tag).toBe("None");
70 }),
71 );
72 },
73);