@fjall/components-infrastructure 2.15.0 → 2.17.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/config/aws/scpPreset.js +9 -0
- package/dist/lib/patterns/aws/storage.d.ts +4 -2
- package/dist/lib/patterns/aws/storage.js +1 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +13 -3
- package/dist/lib/resources/aws/compute/ecsImages.js +2 -2
- package/dist/lib/resources/aws/compute/persistentDataVolume.js +5 -1
- package/dist/lib/resources/aws/messaging/sns.d.ts +5 -0
- package/dist/lib/resources/aws/messaging/sns.js +7 -1
- package/dist/lib/resources/aws/messaging/sqs.d.ts +6 -0
- package/dist/lib/resources/aws/messaging/sqs.js +10 -2
- package/dist/lib/resources/aws/networking/hostedZone.js +12 -1
- package/dist/lib/resources/aws/storage/s3.d.ts +25 -0
- package/dist/lib/resources/aws/storage/s3.js +22 -1
- package/package.json +4 -4
|
@@ -32,6 +32,12 @@ function buildFoundationGuardrails(allowedRegions) {
|
|
|
32
32
|
// Deny + NotAction denies everything except the policy-management
|
|
33
33
|
// scopes a root-task unlock session needs; the AWS root-task policies
|
|
34
34
|
// constrain those sessions further.
|
|
35
|
+
// iam:CreateLoginProfile/GetLoginProfile (root-credential recovery on
|
|
36
|
+
// assume-root sessions) are deliberately NOT carved out — recovery on
|
|
37
|
+
// this tier is a break-glass SCP detach, not a standing carve-out. Do
|
|
38
|
+
// not add them without revisiting the decision:
|
|
39
|
+
// aiDocs/troubleshooting/centralised-root-access-break-glass-runbook.md
|
|
40
|
+
// § Scenario 3.
|
|
35
41
|
NotAction: [
|
|
36
42
|
"s3:GetBucketPolicy",
|
|
37
43
|
"s3:PutBucketPolicy",
|
|
@@ -214,6 +220,9 @@ function buildEncryptionAndAccess() {
|
|
|
214
220
|
{
|
|
215
221
|
Sid: "DenyIamUserCreation",
|
|
216
222
|
Effect: "Deny",
|
|
223
|
+
// Also blocks iam:CreateLoginProfile for assume-root recovery
|
|
224
|
+
// sessions (they match none of EXEMPT_ROLE_PATTERNS) — deliberate;
|
|
225
|
+
// see the DenyRootUserActions note + break-glass runbook § Scenario 3.
|
|
217
226
|
Action: [
|
|
218
227
|
"iam:CreateUser",
|
|
219
228
|
"iam:CreateAccessKey",
|
|
@@ -2,12 +2,12 @@ import { Construct } from "constructs";
|
|
|
2
2
|
import { type IBucket, type EventType, type IBucketNotificationDestination, type NotificationKeyFilter } from "aws-cdk-lib/aws-s3";
|
|
3
3
|
import { type IGrantable, type Grant } from "aws-cdk-lib/aws-iam";
|
|
4
4
|
import type App from "../../app.js";
|
|
5
|
-
import { BucketDeployment, type WebsiteHostingConfig } from "../../resources/aws/storage/index.js";
|
|
5
|
+
import { BucketDeployment, type ResourcePolicyStatement, type WebsiteHostingConfig } from "../../resources/aws/storage/index.js";
|
|
6
6
|
import { type BackupTier } from "../../utils/backupTierMapping.js";
|
|
7
7
|
import { type IStorage } from "./interfaces/storage.js";
|
|
8
8
|
import { type IStorageConnector } from "./interfaces/connector.js";
|
|
9
9
|
export { type IStorage, isStorage } from "./interfaces/storage.js";
|
|
10
|
-
export { type WebsiteHostingConfig } from "../../resources/aws/storage/index.js";
|
|
10
|
+
export { type ResourcePolicyStatement, type WebsiteHostingConfig } from "../../resources/aws/storage/index.js";
|
|
11
11
|
export interface CorsRule {
|
|
12
12
|
readonly allowedOrigins: string[];
|
|
13
13
|
readonly allowedMethods: string[];
|
|
@@ -40,6 +40,8 @@ export interface S3Props {
|
|
|
40
40
|
readonly deployment?: S3DeploymentConfig;
|
|
41
41
|
/** When true, sets RemovalPolicy.RETAIN (overriding the env-aware default). Used for imported buckets. */
|
|
42
42
|
readonly retain?: boolean;
|
|
43
|
+
/** Declarative bucket-policy statements appended to the bucket's resource policy. */
|
|
44
|
+
readonly resourcePolicyStatements?: ResourcePolicyStatement[];
|
|
43
45
|
}
|
|
44
46
|
export interface StorageBuildProps extends S3Props {
|
|
45
47
|
readonly stackPlacement?: "storage" | "cdn" | "compute";
|
|
@@ -66,6 +66,7 @@ export class Storage extends Construct {
|
|
|
66
66
|
backupVaultTier: props.backupVaultTier,
|
|
67
67
|
publicReadAccess: props.publicReadAccess,
|
|
68
68
|
websiteHosting: props.websiteHosting,
|
|
69
|
+
resourcePolicyStatements: props.resourcePolicyStatements,
|
|
69
70
|
...(props.cors && { cors: toCorsRules(props.cors) }),
|
|
70
71
|
...(props.retain && { removalPolicy: RemovalPolicy.RETAIN })
|
|
71
72
|
});
|
|
@@ -43,8 +43,13 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
43
43
|
const dataVolumeOwnerLogicalId = resolveOptionalString(props.dataVolumeOwnerLogicalId);
|
|
44
44
|
this.queue = new SQSQueue(this, `${id}Queue`, {
|
|
45
45
|
visibilityTimeout: QUEUE_VISIBILITY_TIMEOUT_SECONDS,
|
|
46
|
-
deadLetterQueue: { enabled: true, maxReceiveCount: 5 }
|
|
46
|
+
deadLetterQueue: { enabled: true, maxReceiveCount: 5 },
|
|
47
|
+
// Transient instance-drain signals — no durable state. Pinned DESTROY
|
|
48
|
+
// (now also the SQSQueue wrapper default) so a replacing deploy of the
|
|
49
|
+
// parent Ec2Instance reclaims this queue + DLQ instead of orphaning them.
|
|
50
|
+
removalPolicy: "DESTROY"
|
|
47
51
|
});
|
|
52
|
+
const stack = Stack.of(this);
|
|
48
53
|
const ecsPolicies = ecsClusterArn !== undefined
|
|
49
54
|
? [
|
|
50
55
|
new PolicyStatement({
|
|
@@ -66,6 +71,9 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
66
71
|
})
|
|
67
72
|
]
|
|
68
73
|
: [];
|
|
74
|
+
// EIP/ENI mutations cannot be ARN-scoped (the resources are not known at
|
|
75
|
+
// synth), but the Lambda only ever drains instances in its own region — a
|
|
76
|
+
// region clamp removes the cross-region blast radius a bare "*" would allow.
|
|
69
77
|
const ec2Policies = new PolicyStatement({
|
|
70
78
|
effect: Effect.ALLOW,
|
|
71
79
|
actions: [
|
|
@@ -74,7 +82,10 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
74
82
|
"ec2:DescribeNetworkInterfaces",
|
|
75
83
|
"ec2:DetachNetworkInterface"
|
|
76
84
|
],
|
|
77
|
-
resources: ["*"]
|
|
85
|
+
resources: ["*"],
|
|
86
|
+
conditions: {
|
|
87
|
+
StringEquals: { "aws:RequestedRegion": stack.region }
|
|
88
|
+
}
|
|
78
89
|
});
|
|
79
90
|
const elbReadPolicy = new PolicyStatement({
|
|
80
91
|
effect: Effect.ALLOW,
|
|
@@ -94,7 +105,6 @@ export class Ec2GracefulTerminationHandler extends Construct {
|
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
107
|
});
|
|
97
|
-
const stack = Stack.of(this);
|
|
98
108
|
// Account/region-scoped wildcard rather than the specific ASG ARN —
|
|
99
109
|
// see PersistentDataVolume for the full deadlock writeup. Same gotcha:
|
|
100
110
|
// a specific ARN creates a CFN Ref to the ASG, the Lambda's IAM Policy
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { CfnParameter, Stack } from "aws-cdk-lib";
|
|
2
2
|
import { ContainerImage } from "aws-cdk-lib/aws-ecs";
|
|
3
3
|
import { Repository } from "aws-cdk-lib/aws-ecr";
|
|
4
|
+
import { imageTagParameterName } from "@fjall/util";
|
|
4
5
|
import { DEFAULT_ECS_FALLBACK_IMAGE } from "./ecsConstants.js";
|
|
5
|
-
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
6
6
|
function buildImageTagDescription(serviceName) {
|
|
7
7
|
return `Image tag for ECS service ${serviceName}. Set by fjall deploy to the content-hash tag.`;
|
|
8
8
|
}
|
|
9
9
|
function getOrCreateImageTagParameter(ctx, serviceName) {
|
|
10
10
|
const stack = Stack.of(ctx.scope);
|
|
11
|
-
const paramLogicalId =
|
|
11
|
+
const paramLogicalId = imageTagParameterName(serviceName);
|
|
12
12
|
const description = buildImageTagDescription(serviceName);
|
|
13
13
|
const existing = stack.node.tryFindChild(paramLogicalId);
|
|
14
14
|
if (existing instanceof CfnParameter) {
|
|
@@ -105,7 +105,11 @@ export class PersistentDataVolume extends Construct {
|
|
|
105
105
|
Tags.of(this.volume).add(PERSISTENT_DATA_VOLUME_TAG_STACK_ID, Aws.STACK_ID);
|
|
106
106
|
this.queue = new SQSQueue(this, `${id}Queue`, {
|
|
107
107
|
visibilityTimeout: QUEUE_VISIBILITY_TIMEOUT_SECONDS,
|
|
108
|
-
deadLetterQueue: { enabled: true, maxReceiveCount: 5 }
|
|
108
|
+
deadLetterQueue: { enabled: true, maxReceiveCount: 5 },
|
|
109
|
+
// Transient volume-attach signals — no durable state (the EBS volume
|
|
110
|
+
// itself is SNAPSHOT above). Pinned DESTROY (now also the SQSQueue wrapper
|
|
111
|
+
// default) so a replacing deploy reclaims this queue + DLQ, not orphans.
|
|
112
|
+
removalPolicy: "DESTROY"
|
|
109
113
|
});
|
|
110
114
|
const sourcePath = path.resolve(__dirname, LAUNCHING_LAMBDA_SOURCE_FILE);
|
|
111
115
|
const source = readFileSync(sourcePath, "utf-8");
|
|
@@ -7,6 +7,11 @@ export interface SNSTopicProps {
|
|
|
7
7
|
displayName?: string;
|
|
8
8
|
fifo?: boolean;
|
|
9
9
|
contentBasedDeduplication?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Removal policy for the topic. Defaults to DESTROY — a topic is a transient
|
|
12
|
+
* fan-out medium with no durable state (see the constructor). Pass "RETAIN"
|
|
13
|
+
* only for a topic that must survive stack deletion.
|
|
14
|
+
*/
|
|
10
15
|
removalPolicy?: RemovalPolicyString;
|
|
11
16
|
}
|
|
12
17
|
export declare class SNSTopic extends Construct {
|
|
@@ -22,7 +22,13 @@ export class SNSTopic extends Construct {
|
|
|
22
22
|
? (props.contentBasedDeduplication ?? true)
|
|
23
23
|
: undefined
|
|
24
24
|
});
|
|
25
|
-
|
|
25
|
+
// An SNS topic is a transient fan-out medium: it holds no durable state
|
|
26
|
+
// (subscriptions are re-created by the next deploy), so the wrapper defaults
|
|
27
|
+
// to DESTROY — deliberately NOT the env-aware production->RETAIN of
|
|
28
|
+
// data-bearing wrappers (S3, EventBus). RETAIN here buys no protection and
|
|
29
|
+
// orphans the topic on a parent construct's logical-ID churn (the same leak
|
|
30
|
+
// class fixed for SQS). Durable topics opt into RETAIN via props.removalPolicy.
|
|
31
|
+
this.topic.applyRemovalPolicy(toRemovalPolicy(props.removalPolicy ?? "DESTROY"));
|
|
26
32
|
new CfnOutput(this, `${id}TopicArn`, {
|
|
27
33
|
key: `${id}TopicArn`,
|
|
28
34
|
value: this.topic.topicArn,
|
|
@@ -60,6 +60,12 @@ export interface SQSQueueProps {
|
|
|
60
60
|
contentBasedDeduplication?: boolean;
|
|
61
61
|
fifoThroughputLimit?: "perQueue" | "perMessageGroupId";
|
|
62
62
|
deduplicationScope?: "queue" | "messageGroup";
|
|
63
|
+
/**
|
|
64
|
+
* Removal policy for the queue (and its auto-created DLQ, which tracks it).
|
|
65
|
+
* Defaults to DESTROY — a queue is a transient work medium (see the
|
|
66
|
+
* constructor). Pass "RETAIN" only for a queue whose contents are
|
|
67
|
+
* irreplaceable and must survive stack deletion.
|
|
68
|
+
*/
|
|
63
69
|
removalPolicy?: RemovalPolicyString;
|
|
64
70
|
}
|
|
65
71
|
export declare class SQSQueue extends Construct {
|
|
@@ -83,6 +83,14 @@ export class SQSQueue extends Construct {
|
|
|
83
83
|
this.id = id;
|
|
84
84
|
// Sanitise id for CloudFormation output keys (must be alphanumeric)
|
|
85
85
|
const outputName = toPascalCase(id);
|
|
86
|
+
// SQS queues are transient work mediums: their contents (job messages,
|
|
87
|
+
// failed-delivery copies) regenerate from a source of truth held elsewhere
|
|
88
|
+
// (Postgres, the producing schedule/rule), so the wrapper defaults to
|
|
89
|
+
// DESTROY — deliberately NOT the env-aware production->RETAIN of
|
|
90
|
+
// data-bearing wrappers (S3, EventBus). RETAIN here buys no protection and
|
|
91
|
+
// orphans the queue on a parent construct's logical-ID churn (the prod
|
|
92
|
+
// orphan leak). Durable queues opt into RETAIN via props.removalPolicy.
|
|
93
|
+
const resolvedRemovalPolicy = toRemovalPolicy(props.removalPolicy ?? "DESTROY");
|
|
86
94
|
const isFifo = props.queueType === "fifo";
|
|
87
95
|
const queueName = props.queueName
|
|
88
96
|
? isFifo
|
|
@@ -110,7 +118,7 @@ export class SQSQueue extends Construct {
|
|
|
110
118
|
fifo: isFifo,
|
|
111
119
|
encryption: toEncryption(props.encryption),
|
|
112
120
|
retentionPeriod: Duration.days(SQS_LIMITS.DEAD_LETTER_QUEUE.DEFAULT_RETENTION_DAYS),
|
|
113
|
-
removalPolicy:
|
|
121
|
+
removalPolicy: resolvedRemovalPolicy
|
|
114
122
|
});
|
|
115
123
|
deadLetterQueue = {
|
|
116
124
|
queue: this.dlq,
|
|
@@ -156,7 +164,7 @@ export class SQSQueue extends Construct {
|
|
|
156
164
|
deduplicationScope: isFifo
|
|
157
165
|
? toDeduplicationScope(props.deduplicationScope)
|
|
158
166
|
: undefined,
|
|
159
|
-
removalPolicy:
|
|
167
|
+
removalPolicy: resolvedRemovalPolicy
|
|
160
168
|
});
|
|
161
169
|
new CfnOutput(this, `${outputName}QueueUrl`, {
|
|
162
170
|
key: `${outputName}QueueUrl`,
|
|
@@ -5,6 +5,7 @@ import { getDomainExportNames } from "@fjall/util";
|
|
|
5
5
|
import { toPascalCase, getSafeZoneName } from "../../../utils/capitaliseString.js";
|
|
6
6
|
import { DelegationRole } from "../iam/delegationRole.js";
|
|
7
7
|
import { applyCostAllocationTags } from "../../../utils/costAllocationTags.js";
|
|
8
|
+
import { resolveOrgId } from "../../../utils/cdkContext.js";
|
|
8
9
|
export class HostedZoneFactory {
|
|
9
10
|
static import(stack, hostedZoneId, zoneName, opts) {
|
|
10
11
|
const safeZone = toPascalCase(getSafeZoneName(zoneName));
|
|
@@ -49,7 +50,17 @@ export class HostedZone extends Construct {
|
|
|
49
50
|
value: Fn.join(",", created.hostedZoneNameServers ?? []),
|
|
50
51
|
exportName: exportNames.nameservers
|
|
51
52
|
});
|
|
52
|
-
|
|
53
|
+
// Org-gate: a single account has no OrganisationId export, so an org-trusting
|
|
54
|
+
// delegation role would leave an unresolved Fn::ImportValue and roll the stack
|
|
55
|
+
// back. Default follows org presence; explicit `true` opts in (and fails fast).
|
|
56
|
+
const inOrganisation = resolveOrgId(this.node) !== undefined;
|
|
57
|
+
if (props.createDelegationRole === true && !inOrganisation) {
|
|
58
|
+
throw new Error(`HostedZone "${props.zoneName}": createDelegationRole was requested but ` +
|
|
59
|
+
`this account is not part of an AWS Organization (no "orgId" context). ` +
|
|
60
|
+
`Cross-account DNS delegation requires an organisation — omit ` +
|
|
61
|
+
`createDelegationRole for single-account setups, or connect an organisation.`);
|
|
62
|
+
}
|
|
63
|
+
if (props.createDelegationRole ?? inOrganisation) {
|
|
53
64
|
this.delegationRole = new DelegationRole(this, `${safeZone}DelegationRole`, {
|
|
54
65
|
zoneName: props.zoneName,
|
|
55
66
|
hostedZone: created,
|
|
@@ -6,6 +6,25 @@ export interface WebsiteHostingConfig {
|
|
|
6
6
|
readonly indexDocument: string;
|
|
7
7
|
readonly errorDocument?: string;
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* A single bucket-policy statement expressed declaratively. {@link S3Bucket}
|
|
11
|
+
* turns each entry into an `addToResourcePolicy` call at synth.
|
|
12
|
+
*
|
|
13
|
+
* Principals are either `"*"` (anonymous / public) or an IAM ARN (account root,
|
|
14
|
+
* role, or user). Service and Federated principals are not yet modelled — a
|
|
15
|
+
* remediation that meets one must fall back to report-only rather than dropping
|
|
16
|
+
* it silently. Mirrors the codemod's `S3ResourcePlanSchema.resourcePolicyStatements`
|
|
17
|
+
* in `@fjall/generator` — the two shapes must move together.
|
|
18
|
+
*/
|
|
19
|
+
export interface ResourcePolicyStatement {
|
|
20
|
+
readonly sid?: string;
|
|
21
|
+
readonly effect: "Allow" | "Deny";
|
|
22
|
+
readonly principals: string[];
|
|
23
|
+
readonly actions: string[];
|
|
24
|
+
/** Defaults to the bucket itself and its objects when omitted. */
|
|
25
|
+
readonly resources?: string[];
|
|
26
|
+
readonly conditions?: Record<string, Record<string, string | string[]>>;
|
|
27
|
+
}
|
|
9
28
|
/**
|
|
10
29
|
* Props for {@link S3Bucket}.
|
|
11
30
|
*
|
|
@@ -17,6 +36,12 @@ export interface S3BucketProps extends BucketProps {
|
|
|
17
36
|
backupVaultTier?: BackupTier;
|
|
18
37
|
publicReadAccess?: boolean;
|
|
19
38
|
websiteHosting?: WebsiteHostingConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Declarative bucket-policy statements, each appended via
|
|
41
|
+
* `addToResourcePolicy`. The TLS-only `enforceSSL` deny is always applied
|
|
42
|
+
* separately and must NOT be listed here.
|
|
43
|
+
*/
|
|
44
|
+
resourcePolicyStatements?: ResourcePolicyStatement[];
|
|
20
45
|
}
|
|
21
46
|
export declare class S3Bucket extends Bucket {
|
|
22
47
|
readonly backupVaultTier?: BackupTier;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
|
|
2
2
|
import { Annotations, CfnOutput, Duration, RemovalPolicy, Tags } from "aws-cdk-lib";
|
|
3
3
|
import { BlockPublicAccess, Bucket } from "aws-cdk-lib/aws-s3";
|
|
4
|
+
import { ArnPrincipal, Effect, PolicyStatement, StarPrincipal } from "aws-cdk-lib/aws-iam";
|
|
4
5
|
import { RegionInfo } from "aws-cdk-lib/region-info";
|
|
5
6
|
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
6
7
|
import { envAwareRemovalPolicyDefault, toRemovalPolicy } from "../../../utils/removalPolicy.js";
|
|
@@ -8,10 +9,15 @@ export { SDK_PRE_EMPTY_TAG_KEY } from "@fjall/util/aws";
|
|
|
8
9
|
function shouldAutoVersion(tier) {
|
|
9
10
|
return tier === "resilient" || tier === "enterprise";
|
|
10
11
|
}
|
|
12
|
+
function toResourcePolicyPrincipal(identifier) {
|
|
13
|
+
return identifier === "*"
|
|
14
|
+
? new StarPrincipal()
|
|
15
|
+
: new ArnPrincipal(identifier);
|
|
16
|
+
}
|
|
11
17
|
export class S3Bucket extends Bucket {
|
|
12
18
|
backupVaultTier;
|
|
13
19
|
constructor(scope, id, props = {}) {
|
|
14
|
-
const { websiteHosting, backupVaultTier, ...cdkProps } = props;
|
|
20
|
+
const { websiteHosting, backupVaultTier, resourcePolicyStatements, ...cdkProps } = props;
|
|
15
21
|
const isPublic = props.publicReadAccess === true || websiteHosting !== undefined;
|
|
16
22
|
const versioned = props.versioned ?? shouldAutoVersion(backupVaultTier);
|
|
17
23
|
const removalPolicy = props.removalPolicy ?? toRemovalPolicy(envAwareRemovalPolicyDefault());
|
|
@@ -42,6 +48,21 @@ export class S3Bucket extends Bucket {
|
|
|
42
48
|
: props.lifecycleRules
|
|
43
49
|
});
|
|
44
50
|
this.backupVaultTier = backupVaultTier;
|
|
51
|
+
for (const statement of resourcePolicyStatements ?? []) {
|
|
52
|
+
this.addToResourcePolicy(new PolicyStatement({
|
|
53
|
+
...(statement.sid !== undefined && { sid: statement.sid }),
|
|
54
|
+
effect: statement.effect === "Deny" ? Effect.DENY : Effect.ALLOW,
|
|
55
|
+
principals: statement.principals.map(toResourcePolicyPrincipal),
|
|
56
|
+
actions: statement.actions,
|
|
57
|
+
resources: statement.resources ?? [
|
|
58
|
+
this.bucketArn,
|
|
59
|
+
this.arnForObjects("*")
|
|
60
|
+
],
|
|
61
|
+
...(statement.conditions !== undefined && {
|
|
62
|
+
conditions: statement.conditions
|
|
63
|
+
})
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
45
66
|
if (props.autoDeleteObjects === true) {
|
|
46
67
|
Annotations.of(this).addWarningV2("@fjall/components-infrastructure:s3:autoDeleteObjectsIgnored", "autoDeleteObjects: true is ignored — the CDK auto-delete custom " +
|
|
47
68
|
"resource is retired (ADR D4.3). DESTROY buckets are emptied " +
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.17.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.17.0",
|
|
67
|
+
"@fjall/util": "^2.17.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": "21cfe1aae339e12183af2813ec81f581b9b77d49"
|
|
83
83
|
}
|