t3-code-android-nightly/.repos/alchemy-effect/packages/alchemy/test/AWS/IAM/PolicyDocument.test.ts
Julius Marminge 6f9cea00ae
chore(refs): sync Effect and Alchemy references to 4.0.1 and beta.80 (#16170)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-05 13:22:30 -07:00

192 lines
6 KiB
TypeScript

import type { IamAction } from "@/AWS/IAM/actions.generated.ts";
import {
normalizePolicyDocument,
stringifyPolicyDocument,
type PolicyDocument,
type ServiceControlPolicyDocument,
} from "@/AWS/IAM/Policy.ts";
import { describe, expect, it } from "alchemy-test";
const document: PolicyDocument = {
Version: "2012-10-17",
Statement: [
{
Sid: "ReadObjects",
Effect: "Allow",
Action: ["s3:GetObject", "s3:ListBucket"],
Resource: ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
Condition: {
StringEquals: { "aws:PrincipalOrgID": "o-example" },
},
},
],
};
describe(
"stringifyPolicyDocument",
{ tags: ["unit", "provider:aws", "provider:aws:iam", "local"] },
() => {
it("round-trips through JSON.parse", () => {
expect(JSON.parse(stringifyPolicyDocument(document))).toEqual(document);
});
},
);
describe(
"normalizePolicyDocument",
{ tags: ["unit", "provider:aws", "provider:aws:iam", "local"] },
() => {
it("makes two equivalent documents with different key order equal", () => {
const reordered = {
Statement: [
{
Condition: {
StringEquals: { "aws:PrincipalOrgID": "o-example" },
},
Resource: ["arn:aws:s3:::my-bucket", "arn:aws:s3:::my-bucket/*"],
Action: ["s3:GetObject", "s3:ListBucket"],
Effect: "Allow",
Sid: "ReadObjects",
},
],
Version: "2012-10-17",
};
expect(normalizePolicyDocument(reordered)).toBe(
normalizePolicyDocument(document),
);
});
it("treats a JSON string and the equivalent object identically", () => {
const json = JSON.stringify(document, null, 2);
expect(normalizePolicyDocument(json)).toBe(
normalizePolicyDocument(document),
);
});
it("handles the URL-encoded documents IAM returns", () => {
const encoded = encodeURIComponent(JSON.stringify(document));
expect(normalizePolicyDocument(encoded)).toBe(
normalizePolicyDocument(document),
);
});
it("is deterministic for the same document", () => {
expect(normalizePolicyDocument(document)).toBe(
normalizePolicyDocument(JSON.parse(stringifyPolicyDocument(document))),
);
});
it("returns unparseable strings unchanged so drift diffs still fire", () => {
expect(normalizePolicyDocument("not-json{")).toBe("not-json{");
});
it("treats singleton arrays and scalars as equivalent (AWS collapses them)", () => {
// The IAM grammar accepts `"x"` wherever `["x"]` is legal, and several
// services (e.g. Secrets Manager `GetResourcePolicy`) return the scalar
// form for a stored singleton array — the two must canonicalize equal or
// every re-deploy spuriously re-puts the policy.
const arrays: PolicyDocument = {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Principal: { AWS: ["arn:aws:iam::123456789012:root"] },
Action: ["secretsmanager:GetSecretValue"],
Resource: "*",
},
],
};
const scalars = {
Version: "2012-10-17",
Statement: {
Effect: "Allow",
Principal: { AWS: "arn:aws:iam::123456789012:root" },
Action: "secretsmanager:GetSecretValue",
Resource: "*",
},
};
expect(normalizePolicyDocument(arrays)).toBe(
normalizePolicyDocument(scalars),
);
// Multi-element arrays are untouched (order still significant).
expect(normalizePolicyDocument(document)).toContain(
'"Action":["s3:GetObject","s3:ListBucket"]',
);
});
},
);
describe(
"IamAction",
{ tags: ["unit", "provider:aws", "provider:aws:iam", "local"] },
() => {
it("accepts generated literals, wildcards, and arbitrary strings", () => {
// Compile-time assertions: generated ops autocomplete, `service:*`
// wildcards exist, and the `(string & {})` escape hatch never hard-breaks.
const actions: IamAction[] = [
"s3:GetObject",
"iam:CreateRole",
"states:StartExecution",
"cloudwatch:PutMetricData",
"dynamodb:*",
"some-future-service:SomeUnknownAction",
];
expect(actions).toHaveLength(6);
// PolicyStatement.Action accepts both typed and plain-string arrays.
const typed: PolicyDocument = {
Version: "2012-10-17",
Statement: [
{ Effect: "Allow", Action: ["lambda:InvokeFunction"], Resource: "*" },
],
};
const plain: string[] = ["s3:GetObject"];
const fromStrings: PolicyDocument = {
Version: "2012-10-17",
Statement: [{ Effect: "Allow", Action: plain, Resource: "*" }],
};
expect(typed.Statement).toHaveLength(1);
expect(fromStrings.Statement).toHaveLength(1);
});
},
);
describe(
"ServiceControlPolicyDocument",
{ tags: ["unit", "provider:aws", "provider:aws:iam", "local"] },
() => {
it("types the SCP-legal subset (no Principal) and normalizes like any doc", () => {
const scp: ServiceControlPolicyDocument = {
Version: "2012-10-17",
Statement: [
{ Sid: "AllowAll", Effect: "Allow", Action: ["*"], Resource: "*" },
{
Sid: "DenyLeaveOrg",
Effect: "Deny",
Action: ["organizations:LeaveOrganization"],
Resource: "*",
Condition: {
StringNotEquals: { "aws:PrincipalOrgID": "o-example" },
},
},
],
};
const illegal: ServiceControlPolicyDocument = {
Version: "2012-10-17",
Statement: [
{
Effect: "Deny",
Action: ["s3:*"],
Resource: "*",
// @ts-expect-error — SCP statements never carry a Principal
Principal: { AWS: "*" },
},
],
};
expect(illegal).toBeDefined();
expect(normalizePolicyDocument(scp)).toBe(
normalizePolicyDocument(JSON.parse(JSON.stringify(scp))),
);
});
},
);