165 lines
5.9 KiB
TypeScript
165 lines
5.9 KiB
TypeScript
import { beforeEach, describe, expect, it, mock } from "bun:test";
|
|
|
|
const mockStsGetCallerIdentity = mock();
|
|
const mockFromEnv = mock();
|
|
const mockFromTokenFile = mock();
|
|
const mockFromContainerMetadata = mock();
|
|
const mockFromInstanceMetadata = mock();
|
|
const mockFromProfile = mock();
|
|
const mockGetAvailableProfiles = mock();
|
|
|
|
mock.module("../../../src/providers/aws/client", () => ({
|
|
stsGetCallerIdentity: mockStsGetCallerIdentity,
|
|
}));
|
|
|
|
mock.module("../../../src/providers/aws/credentials", () => ({
|
|
fromEnv: mockFromEnv,
|
|
fromTokenFile: mockFromTokenFile,
|
|
fromContainerMetadata: mockFromContainerMetadata,
|
|
fromInstanceMetadata: mockFromInstanceMetadata,
|
|
fromProfile: mockFromProfile,
|
|
getAvailableProfiles: mockGetAvailableProfiles,
|
|
}));
|
|
|
|
import { AwsAccountService } from "../../../src/providers/aws/awsAccount";
|
|
|
|
function makeCredentialSource(
|
|
label: string,
|
|
resolve: () => Promise<{ accessKeyId: string; secretAccessKey: string; sessionToken?: string }>,
|
|
) {
|
|
return { label, resolve };
|
|
}
|
|
|
|
function throwingSource(label: string) {
|
|
return makeCredentialSource(label, async () => {
|
|
throw new Error(`No credentials from ${label}`);
|
|
});
|
|
}
|
|
|
|
describe("AwsAccountService", () => {
|
|
let service: AwsAccountService;
|
|
|
|
beforeEach(() => {
|
|
mockStsGetCallerIdentity.mockReset();
|
|
mockFromEnv.mockReset();
|
|
mockFromTokenFile.mockReset();
|
|
mockFromContainerMetadata.mockReset();
|
|
mockFromInstanceMetadata.mockReset();
|
|
mockFromProfile.mockReset();
|
|
mockGetAvailableProfiles.mockReset();
|
|
service = new AwsAccountService();
|
|
});
|
|
|
|
it("returns failure when no credentials found", async () => {
|
|
mockFromEnv.mockReturnValue(throwingSource("env"));
|
|
mockFromTokenFile.mockReturnValue(throwingSource("token-file"));
|
|
mockFromContainerMetadata.mockReturnValue(throwingSource("container-metadata"));
|
|
mockFromInstanceMetadata.mockReturnValue(throwingSource("instance-metadata"));
|
|
mockGetAvailableProfiles.mockResolvedValue([]);
|
|
|
|
const result = await service.execute();
|
|
|
|
expect(result.success).toBe(false);
|
|
expect(result.error?.message).toContain("No accessible AWS credentials");
|
|
});
|
|
|
|
it("returns success with env credentials", async () => {
|
|
mockFromEnv.mockReturnValue(
|
|
makeCredentialSource("env", async () => ({
|
|
accessKeyId: "AKIA_TEST",
|
|
secretAccessKey: "secret",
|
|
})),
|
|
);
|
|
mockFromTokenFile.mockReturnValue(throwingSource("token-file"));
|
|
mockFromContainerMetadata.mockReturnValue(throwingSource("container-metadata"));
|
|
mockFromInstanceMetadata.mockReturnValue(throwingSource("instance-metadata"));
|
|
mockGetAvailableProfiles.mockResolvedValue([]);
|
|
mockStsGetCallerIdentity.mockResolvedValue({
|
|
account: "123456789012",
|
|
arn: "arn:aws:iam::123456789012:user/test",
|
|
userId: "AIDACKCEVSQ6C2EXAMPLE",
|
|
});
|
|
|
|
const result = await service.execute();
|
|
|
|
expect(result.success).toBe(true);
|
|
expect((result.data as any[])[0].source).toBe("env");
|
|
expect((result.data as any[])[0].account).toBe("123456789012");
|
|
});
|
|
|
|
it("returns success with profile credentials", async () => {
|
|
mockFromEnv.mockReturnValue(throwingSource("env"));
|
|
mockFromTokenFile.mockReturnValue(throwingSource("token-file"));
|
|
mockFromContainerMetadata.mockReturnValue(throwingSource("container-metadata"));
|
|
mockFromInstanceMetadata.mockReturnValue(throwingSource("instance-metadata"));
|
|
mockGetAvailableProfiles.mockResolvedValue(["dev", "prod"]);
|
|
mockFromProfile.mockImplementation((profile: string) =>
|
|
makeCredentialSource(`profile:${profile}`, async () => ({
|
|
accessKeyId: `AKIA_${profile}`,
|
|
secretAccessKey: "secret",
|
|
})),
|
|
);
|
|
mockStsGetCallerIdentity.mockResolvedValue({
|
|
account: "123456789012",
|
|
arn: "arn:aws:iam::123456789012:user/test",
|
|
userId: "AIDACKCEVSQ6C2EXAMPLE",
|
|
});
|
|
|
|
const result = await service.execute();
|
|
|
|
expect(result.success).toBe(true);
|
|
expect((result.data as any[]).length).toBe(2);
|
|
expect((result.data as any[])[0].source).toBe("profile:dev");
|
|
expect((result.data as any[])[1].source).toBe("profile:prod");
|
|
});
|
|
|
|
it("continues on profile failure", async () => {
|
|
mockFromEnv.mockReturnValue(throwingSource("env"));
|
|
mockFromTokenFile.mockReturnValue(throwingSource("token-file"));
|
|
mockFromContainerMetadata.mockReturnValue(throwingSource("container-metadata"));
|
|
mockFromInstanceMetadata.mockReturnValue(throwingSource("instance-metadata"));
|
|
mockGetAvailableProfiles.mockResolvedValue(["bad", "good"]);
|
|
mockFromProfile.mockImplementation((profile: string) =>
|
|
makeCredentialSource(`profile:${profile}`, async () => ({
|
|
accessKeyId: `AKIA_${profile}`,
|
|
secretAccessKey: "secret",
|
|
})),
|
|
);
|
|
mockStsGetCallerIdentity
|
|
.mockRejectedValueOnce(new Error("STS failure"))
|
|
.mockResolvedValueOnce({
|
|
account: "123456789012",
|
|
arn: "arn:aws:iam::123456789012:user/test",
|
|
userId: "AIDACKCEVSQ6C2EXAMPLE",
|
|
});
|
|
|
|
const result = await service.execute();
|
|
|
|
expect(result.success).toBe(true);
|
|
expect((result.data as any[]).length).toBe(1);
|
|
expect((result.data as any[])[0].source).toBe("profile:good");
|
|
});
|
|
|
|
it("detects static credentials", async () => {
|
|
mockFromEnv.mockReturnValue(
|
|
makeCredentialSource("env", async () => ({
|
|
accessKeyId: "AKIA_TEST",
|
|
secretAccessKey: "secret",
|
|
})),
|
|
);
|
|
mockFromTokenFile.mockReturnValue(throwingSource("token-file"));
|
|
mockFromContainerMetadata.mockReturnValue(throwingSource("container-metadata"));
|
|
mockFromInstanceMetadata.mockReturnValue(throwingSource("instance-metadata"));
|
|
mockGetAvailableProfiles.mockResolvedValue([]);
|
|
mockStsGetCallerIdentity.mockResolvedValue({
|
|
account: "123456789012",
|
|
arn: "arn:aws:iam::123456789012:user/test",
|
|
userId: "AIDACKCEVSQ6C2EXAMPLE",
|
|
});
|
|
|
|
const result = await service.execute();
|
|
|
|
expect(result.success).toBe(true);
|
|
expect((result.data as any[])[0].staticCredentials).toBe(true);
|
|
});
|
|
}); |