mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-30 23:34:27 +00:00
95 lines
3.1 KiB
TypeScript
95 lines
3.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
ORG_FLOW_TYPES,
|
|
ORG_SECRET_TYPE,
|
|
ORGANIZATION_TYPE,
|
|
OrgFlowType,
|
|
} from "@/types/organizations";
|
|
|
|
import {
|
|
bindOrgSetupStrategy,
|
|
OrgSetupSubmissionData,
|
|
} from "./org-setup-strategy";
|
|
|
|
/**
|
|
* One submission per onboarding flow, only as filled in as binding a strategy
|
|
* needs. `satisfies Record<OrgFlowType, …>` keeps a new flow from slipping past
|
|
* the table below.
|
|
*/
|
|
const SETUP_DATA = {
|
|
[ORGANIZATION_TYPE.AWS]: {
|
|
orgType: ORGANIZATION_TYPE.AWS,
|
|
awsOrgId: "o-abc123def4",
|
|
roleArn: "arn:aws:iam::123456789012:role/ProwlerOrgRole",
|
|
},
|
|
[ORGANIZATION_TYPE.AZURE]: {
|
|
orgType: ORGANIZATION_TYPE.AZURE,
|
|
tenantId: "11111111-1111-4111-8111-111111111111",
|
|
clientId: "client-id",
|
|
clientSecret: "client-secret",
|
|
},
|
|
[ORGANIZATION_TYPE.GCP]: {
|
|
orgType: ORGANIZATION_TYPE.GCP,
|
|
gcpOrgId: "123456789012",
|
|
credentialMethod: ORG_SECRET_TYPE.STATIC,
|
|
clientId: "client-id",
|
|
clientSecret: "client-secret",
|
|
refreshToken: "refresh-token",
|
|
},
|
|
} as const satisfies Record<OrgFlowType, OrgSetupSubmissionData>;
|
|
|
|
/** The structure each flow's hierarchy is made of — a tenant has no folders. */
|
|
const HIERARCHY_WORDING = {
|
|
[ORGANIZATION_TYPE.AWS]: "organizational unit hierarchy",
|
|
[ORGANIZATION_TYPE.AZURE]: "Management Group hierarchy",
|
|
[ORGANIZATION_TYPE.GCP]: "folder hierarchy",
|
|
} as const satisfies Record<OrgFlowType, string>;
|
|
|
|
describe("bindOrgSetupStrategy", () => {
|
|
// `hierarchy_depth_exceeded` is one API code for every provider. The precedence
|
|
// chain is covered by the submission hook's suite; only an exhaustive per-flow
|
|
// check catches one flow being told about another cloud's structure.
|
|
it.each(ORG_FLOW_TYPES)(
|
|
"describes %s's own hierarchy for the shared hierarchy_depth_exceeded code",
|
|
(orgType) => {
|
|
const message = bindOrgSetupStrategy(
|
|
SETUP_DATA[orgType],
|
|
).discoveryFailureMessage("hierarchy_depth_exceeded");
|
|
|
|
expect(message).toContain(HIERARCHY_WORDING[orgType]);
|
|
|
|
const otherClouds = ORG_FLOW_TYPES.filter((other) => other !== orgType);
|
|
for (const other of otherClouds) {
|
|
expect(message).not.toContain(HIERARCHY_WORDING[other]);
|
|
}
|
|
},
|
|
);
|
|
|
|
it.each(ORG_FLOW_TYPES)(
|
|
"prefers %s's shared-code copy over the server's own message",
|
|
(orgType) => {
|
|
// Curated copy stays ahead of `error_message`: it is the actionable one.
|
|
const message = bindOrgSetupStrategy(
|
|
SETUP_DATA[orgType],
|
|
).discoveryFailureMessage(
|
|
"hierarchy_depth_exceeded",
|
|
"Hierarchy too deep.",
|
|
);
|
|
|
|
expect(message).toContain(HIERARCHY_WORDING[orgType]);
|
|
},
|
|
);
|
|
|
|
// `filter[external_id]` is an exact lookup, so an uppercase-typed tenant would
|
|
// miss its own organization on a second run and then collide on the POST.
|
|
it("folds an uppercase Azure tenant ID to the API's canonical form", () => {
|
|
const bound = bindOrgSetupStrategy({
|
|
...SETUP_DATA[ORGANIZATION_TYPE.AZURE],
|
|
tenantId: " AAAAAAAA-1111-4111-8111-BBBBBBBBBBBB ",
|
|
});
|
|
|
|
expect(bound.externalId).toBe("aaaaaaaa-1111-4111-8111-bbbbbbbbbbbb");
|
|
});
|
|
});
|