@fjall/components-infrastructure 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/app.d.ts +7 -7
- package/dist/lib/app.js +2 -3
- package/dist/lib/config/aws/accountMonitoringRole.js +2 -1
- package/dist/lib/config/aws/cloudTrail.d.ts +13 -0
- package/dist/lib/config/aws/cloudTrail.js +19 -3
- package/dist/lib/config/aws/disasterRecovery.js +1 -1
- package/dist/lib/config/aws/ecrDefaultImage.js +2 -0
- package/dist/lib/config/aws/organisationTrail.d.ts +16 -0
- package/dist/lib/config/aws/organisationTrail.js +32 -0
- package/dist/lib/config/aws/scpPreset.js +10 -1
- package/dist/lib/patterns/aws/account.d.ts +9 -0
- package/dist/lib/patterns/aws/account.js +29 -6
- package/dist/lib/patterns/aws/organisation.d.ts +9 -0
- package/dist/lib/patterns/aws/organisation.js +51 -5
- package/dist/lib/patterns/aws/storage.d.ts +1 -1
- package/dist/lib/patterns/aws/storage.js +5 -1
- package/dist/lib/resources/aws/logging/cloudTrail.d.ts +48 -1
- package/dist/lib/resources/aws/logging/cloudTrail.js +180 -18
- package/dist/lib/resources/aws/messaging/eventbridge.d.ts +3 -2
- package/dist/lib/resources/aws/messaging/eventbridge.js +2 -2
- package/dist/lib/resources/aws/networking/ipamPool.js +6 -3
- package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +4 -3
- package/dist/lib/resources/aws/networking/serviceDiscovery.js +2 -3
- package/dist/lib/resources/aws/storage/s3.d.ts +8 -0
- package/dist/lib/resources/aws/storage/s3.js +19 -4
- package/dist/lib/utils/cdkContext.d.ts +11 -0
- package/dist/lib/utils/cdkContext.js +22 -1
- package/dist/lib/utils/env.d.ts +19 -0
- package/dist/lib/utils/env.js +36 -5
- package/dist/lib/utils/getConfig.js +32 -12
- package/dist/lib/utils/orgConfigParser.d.ts +10 -0
- package/dist/lib/utils/orgConfigParser.js +47 -23
- package/dist/lib/utils/removalPolicy.d.ts +15 -0
- package/dist/lib/utils/removalPolicy.js +32 -0
- package/dist/lib/utils/standardTagsAspect.js +2 -1
- package/package.json +4 -4
|
@@ -5,6 +5,16 @@ export interface ParsedOrgConfig {
|
|
|
5
5
|
secondaryRegions: string[];
|
|
6
6
|
disasterRecoveryRegion?: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a provider account's synth-time environment. The tier/stage
|
|
10
|
+
* separation (decisions/2026-06-07-account-tier-vs-stage-separation.md) nulls
|
|
11
|
+
* the wire `environment` for organisation-tier accounts, but scaffolded org
|
|
12
|
+
* entry points gate on `config.environment === "root"` — decode the tier back
|
|
13
|
+
* to the historical "root" marker via the sanctioned `accountTier()` decoder.
|
|
14
|
+
* Workload stages pass through verbatim; a null stage on any other tier stays
|
|
15
|
+
* unresolved (callers fall back to "unknown").
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveSynthEnvironment(account: Pick<ProviderAccount, "environment" | "tier">): string | undefined;
|
|
8
18
|
/**
|
|
9
19
|
* Parse orgConfig JSON from CDK context into a validated structure.
|
|
10
20
|
*
|
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
import { VAULT_LOCK_MODES, S3_BPA_MODES } from "@fjall/util/config";
|
|
2
|
-
import { maskSensitiveOutput } from "@fjall/util";
|
|
2
|
+
import { ACCOUNT_TIERS, STRUCTURAL_ENVIRONMENTS, accountTier, maskSensitiveOutput } from "@fjall/util";
|
|
3
3
|
import { FjallLogger } from "./validationLogger.js";
|
|
4
|
+
function isProviderAccount(item) {
|
|
5
|
+
if (typeof item !== "object" || item === null)
|
|
6
|
+
return false;
|
|
7
|
+
const rec = item;
|
|
8
|
+
return (typeof rec.id === "string" &&
|
|
9
|
+
typeof rec.name === "string" &&
|
|
10
|
+
// null environment (structural accounts) must survive — rejecting it drops the account at synth.
|
|
11
|
+
(typeof rec.environment === "string" || rec.environment === null) &&
|
|
12
|
+
(rec.tier === undefined || ACCOUNT_TIERS.includes(rec.tier)) &&
|
|
13
|
+
(rec.managed === undefined || typeof rec.managed === "boolean") &&
|
|
14
|
+
(rec.oidcRoleArn === undefined || typeof rec.oidcRoleArn === "string") &&
|
|
15
|
+
(rec.vaultLock === undefined ||
|
|
16
|
+
VAULT_LOCK_MODES.includes(rec.vaultLock)) &&
|
|
17
|
+
(rec.s3BlockPublicAccess === undefined ||
|
|
18
|
+
S3_BPA_MODES.includes(rec.s3BlockPublicAccess)) &&
|
|
19
|
+
(rec.acknowledgeImmutableVaultLock === undefined ||
|
|
20
|
+
typeof rec.acknowledgeImmutableVaultLock === "boolean"));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a provider account's synth-time environment. The tier/stage
|
|
24
|
+
* separation (decisions/2026-06-07-account-tier-vs-stage-separation.md) nulls
|
|
25
|
+
* the wire `environment` for organisation-tier accounts, but scaffolded org
|
|
26
|
+
* entry points gate on `config.environment === "root"` — decode the tier back
|
|
27
|
+
* to the historical "root" marker via the sanctioned `accountTier()` decoder.
|
|
28
|
+
* Workload stages pass through verbatim; a null stage on any other tier stays
|
|
29
|
+
* unresolved (callers fall back to "unknown").
|
|
30
|
+
*/
|
|
31
|
+
export function resolveSynthEnvironment(account) {
|
|
32
|
+
if (accountTier(account) === "organisation") {
|
|
33
|
+
return STRUCTURAL_ENVIRONMENTS.ROOT;
|
|
34
|
+
}
|
|
35
|
+
return account.environment ?? undefined;
|
|
36
|
+
}
|
|
37
|
+
function describeRejectedAccount(item) {
|
|
38
|
+
if (typeof item !== "object" || item === null)
|
|
39
|
+
return "<unidentifiable>";
|
|
40
|
+
const rec = item;
|
|
41
|
+
const parts = [rec.id, rec.name].filter((v) => typeof v === "string");
|
|
42
|
+
return parts.length > 0 ? parts.join(" / ") : "<unidentifiable>";
|
|
43
|
+
}
|
|
4
44
|
/**
|
|
5
45
|
* Parse orgConfig JSON from CDK context into a validated structure.
|
|
6
46
|
*
|
|
@@ -20,28 +60,12 @@ export function parseOrgConfig(raw) {
|
|
|
20
60
|
return empty;
|
|
21
61
|
const obj = parsed;
|
|
22
62
|
const providerAccounts = Array.isArray(obj.providerAccounts)
|
|
23
|
-
? obj.providerAccounts.filter((item) =>
|
|
24
|
-
item
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"string" ||
|
|
30
|
-
item.environment === null) &&
|
|
31
|
-
(item.managed === undefined ||
|
|
32
|
-
typeof item.managed === "boolean") &&
|
|
33
|
-
(item.oidcRoleArn === undefined ||
|
|
34
|
-
typeof item.oidcRoleArn ===
|
|
35
|
-
"string") &&
|
|
36
|
-
(item.vaultLock === undefined ||
|
|
37
|
-
VAULT_LOCK_MODES.includes(item.vaultLock)) &&
|
|
38
|
-
(item.s3BlockPublicAccess ===
|
|
39
|
-
undefined ||
|
|
40
|
-
S3_BPA_MODES.includes(item.s3BlockPublicAccess)) &&
|
|
41
|
-
(item.acknowledgeImmutableVaultLock ===
|
|
42
|
-
undefined ||
|
|
43
|
-
typeof item
|
|
44
|
-
.acknowledgeImmutableVaultLock === "boolean"))
|
|
63
|
+
? obj.providerAccounts.filter((item) => {
|
|
64
|
+
if (isProviderAccount(item))
|
|
65
|
+
return true;
|
|
66
|
+
FjallLogger.warn(`[fjall] Ignoring malformed provider account in orgConfig context: ${describeRejectedAccount(item)}`);
|
|
67
|
+
return false;
|
|
68
|
+
})
|
|
45
69
|
: [];
|
|
46
70
|
const primaryRegion = typeof obj.primaryRegion === "string" ? obj.primaryRegion : undefined;
|
|
47
71
|
const secondaryRegions = Array.isArray(obj.secondaryRegions)
|
|
@@ -1,2 +1,17 @@
|
|
|
1
1
|
import { RemovalPolicy } from "aws-cdk-lib";
|
|
2
2
|
export declare function toRemovalPolicy(value?: "DESTROY" | "RETAIN" | "SNAPSHOT"): RemovalPolicy;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the env-aware removal-policy default (D17): production → RETAIN,
|
|
5
|
+
* every other recognised environment → DESTROY.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the generic `env()` resolver (where unrecognised → default is
|
|
8
|
+
* benign), an unrecognised value here throws at synth: silently landing a
|
|
9
|
+
* typo like `ENVIRONMENT=prod` on DESTROY deletes data when the stack is
|
|
10
|
+
* deleted. The accept-set derives from `ACCOUNT_STAGES_WITH_ROOT` so a new
|
|
11
|
+
* stage added in `@fjall/util` widens it automatically. The no-signal
|
|
12
|
+
* sentinel keeps the historical warn-and-DESTROY behaviour — raw `cdk synth`
|
|
13
|
+
* without context and null-stage cascade synths rely on it. An explicitly
|
|
14
|
+
* supplied `ENVIRONMENT=unknown` collides with the sentinel string and would
|
|
15
|
+
* otherwise ride the silent-DESTROY path, so it is treated as unrecognised.
|
|
16
|
+
*/
|
|
17
|
+
export declare function envAwareRemovalPolicyDefault(): "DESTROY" | "RETAIN";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { ACCOUNT_STAGES_WITH_ROOT } from "@fjall/util";
|
|
1
2
|
import { RemovalPolicy } from "aws-cdk-lib";
|
|
3
|
+
import { getEnvironment, hasExplicitEnvironmentSignal, UNKNOWN_ENVIRONMENT } from "./env.js";
|
|
2
4
|
export function toRemovalPolicy(value) {
|
|
3
5
|
switch (value) {
|
|
4
6
|
case "DESTROY":
|
|
@@ -10,3 +12,33 @@ export function toRemovalPolicy(value) {
|
|
|
10
12
|
return RemovalPolicy.RETAIN;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
15
|
+
const REMOVAL_DEFAULT_ENVIRONMENTS = new Set(ACCOUNT_STAGES_WITH_ROOT);
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the env-aware removal-policy default (D17): production → RETAIN,
|
|
18
|
+
* every other recognised environment → DESTROY.
|
|
19
|
+
*
|
|
20
|
+
* Unlike the generic `env()` resolver (where unrecognised → default is
|
|
21
|
+
* benign), an unrecognised value here throws at synth: silently landing a
|
|
22
|
+
* typo like `ENVIRONMENT=prod` on DESTROY deletes data when the stack is
|
|
23
|
+
* deleted. The accept-set derives from `ACCOUNT_STAGES_WITH_ROOT` so a new
|
|
24
|
+
* stage added in `@fjall/util` widens it automatically. The no-signal
|
|
25
|
+
* sentinel keeps the historical warn-and-DESTROY behaviour — raw `cdk synth`
|
|
26
|
+
* without context and null-stage cascade synths rely on it. An explicitly
|
|
27
|
+
* supplied `ENVIRONMENT=unknown` collides with the sentinel string and would
|
|
28
|
+
* otherwise ride the silent-DESTROY path, so it is treated as unrecognised.
|
|
29
|
+
*/
|
|
30
|
+
export function envAwareRemovalPolicyDefault() {
|
|
31
|
+
const environment = getEnvironment();
|
|
32
|
+
if (environment === UNKNOWN_ENVIRONMENT && !hasExplicitEnvironmentSignal()) {
|
|
33
|
+
return "DESTROY";
|
|
34
|
+
}
|
|
35
|
+
if (!REMOVAL_DEFAULT_ENVIRONMENTS.has(environment)) {
|
|
36
|
+
throw new Error(`Unrecognised environment "${environment}" — refusing to resolve the ` +
|
|
37
|
+
`env-aware removal-policy default (non-production environments ` +
|
|
38
|
+
`default to DESTROY, which deletes data when the stack is deleted). ` +
|
|
39
|
+
`Valid values: ${ACCOUNT_STAGES_WITH_ROOT.join(", ")}. ` +
|
|
40
|
+
`Set ENVIRONMENT or pass -c environment=<value>, or set an explicit ` +
|
|
41
|
+
`removalPolicy on the construct.`);
|
|
42
|
+
}
|
|
43
|
+
return environment === "production" ? "RETAIN" : "DESTROY";
|
|
44
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CfnResource, Stack, Tags } from "aws-cdk-lib";
|
|
2
2
|
import { BACKUP_TIER_TAG_KEY, BACKUP_TIER_TAG_MAP } from "./backupTierMapping.js";
|
|
3
|
+
import { formatIpamPairTagValue, IPAM_OPERATIONS_POOL_TAG_KEY } from "@fjall/util/aws";
|
|
3
4
|
/**
|
|
4
5
|
* Aspect to apply special Fjall tags to specific resource types.
|
|
5
6
|
*
|
|
@@ -49,7 +50,7 @@ export class StandardTagsAspect {
|
|
|
49
50
|
process.env.CDK_DEFAULT_ACCOUNT;
|
|
50
51
|
const region = stack.region || process.env.CDK_DEFAULT_REGION;
|
|
51
52
|
if (accountId && region) {
|
|
52
|
-
Tags.of(vpc).add(
|
|
53
|
+
Tags.of(vpc).add(IPAM_OPERATIONS_POOL_TAG_KEY, formatIpamPairTagValue(accountId, region));
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
66
|
-
"@fjall/generator": "^2.
|
|
67
|
-
"@fjall/util": "^2.
|
|
66
|
+
"@fjall/generator": "^2.14.0",
|
|
67
|
+
"@fjall/util": "^2.14.0",
|
|
68
68
|
"constructs": "^10.0.0",
|
|
69
69
|
"uuid": "^14.0.0"
|
|
70
70
|
},
|
|
@@ -79,5 +79,5 @@
|
|
|
79
79
|
"engines": {
|
|
80
80
|
"node": ">=18.0.0"
|
|
81
81
|
},
|
|
82
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "ce434478f9e3d5e5ccf979c152a237c81e4acee5"
|
|
83
83
|
}
|