@friggframework/devtools 2.0.0--canary.461.849e166.0 → 2.0.0--canary.474.aa465e4.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/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/domains/database/aurora-builder.js +234 -57
- package/infrastructure/domains/database/aurora-builder.test.js +7 -2
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +256 -215
- package/infrastructure/domains/database/migration-builder.test.js +5 -111
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/integration/integration-builder.js +258 -84
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/networking/vpc-builder.js +856 -135
- package/infrastructure/domains/networking/vpc-builder.test.js +10 -6
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/security/kms-builder.js +179 -22
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +26 -1
- package/infrastructure/domains/shared/types/app-definition.js +205 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/package.json +6 -6
- package/infrastructure/REFACTOR.md +0 -532
- package/infrastructure/TRANSFORMATION-VISUAL.md +0 -239
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Resource Resolver
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for resource ownership resolution.
|
|
5
|
+
* Each builder has its own resolver (VpcResolver, AuroraResolver, etc.)
|
|
6
|
+
* that extends this base class.
|
|
7
|
+
*
|
|
8
|
+
* Resolver Layer - Hexagonal Architecture
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
ResourceOwnership,
|
|
13
|
+
resolveOwnership,
|
|
14
|
+
findStackResource,
|
|
15
|
+
findExternalResource,
|
|
16
|
+
findAllExternalResources,
|
|
17
|
+
isResourceInStack
|
|
18
|
+
} = require('./types');
|
|
19
|
+
|
|
20
|
+
class BaseResourceResolver {
|
|
21
|
+
/**
|
|
22
|
+
* Find resource in CloudFormation stack
|
|
23
|
+
* @protected
|
|
24
|
+
* @param {string} logicalId - Logical resource ID
|
|
25
|
+
* @param {Object} discovery - Discovery result
|
|
26
|
+
* @returns {Object|null} Stack resource or null
|
|
27
|
+
*/
|
|
28
|
+
findInStack(logicalId, discovery) {
|
|
29
|
+
return findStackResource(discovery, logicalId);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Find external resource by type
|
|
34
|
+
* @protected
|
|
35
|
+
* @param {string} resourceType - CloudFormation resource type
|
|
36
|
+
* @param {Object} discovery - Discovery result
|
|
37
|
+
* @returns {Object|null} External resource or null
|
|
38
|
+
*/
|
|
39
|
+
findExternal(resourceType, discovery) {
|
|
40
|
+
return findExternalResource(discovery, resourceType);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Find all external resources by type
|
|
45
|
+
* @protected
|
|
46
|
+
* @param {Object} discovery - Discovery result
|
|
47
|
+
* @param {string} resourceType - CloudFormation resource type
|
|
48
|
+
* @returns {Object[]} Array of external resources
|
|
49
|
+
*/
|
|
50
|
+
findAllExternalResources(discovery, resourceType) {
|
|
51
|
+
return findAllExternalResources(discovery, resourceType);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if resource is in stack
|
|
56
|
+
* @protected
|
|
57
|
+
* @param {string} logicalId - Logical resource ID
|
|
58
|
+
* @param {Object} discovery - Discovery result
|
|
59
|
+
* @returns {boolean}
|
|
60
|
+
*/
|
|
61
|
+
isInStack(logicalId, discovery) {
|
|
62
|
+
return isResourceInStack(discovery, logicalId);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validate that external resource IDs are provided when required
|
|
67
|
+
* @protected
|
|
68
|
+
* @param {*} resourceIds - Resource IDs to validate
|
|
69
|
+
* @param {string} resourceName - Name for error message
|
|
70
|
+
* @throws {Error} If resourceIds is not provided
|
|
71
|
+
*/
|
|
72
|
+
requireExternalIds(resourceIds, resourceName) {
|
|
73
|
+
if (!resourceIds || (Array.isArray(resourceIds) && resourceIds.length === 0)) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`ownership='external' for ${resourceName} requires external.${resourceName} to be provided in app definition`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Resolve ownership for a resource
|
|
82
|
+
* @protected
|
|
83
|
+
* @param {string} userIntent - User's ownership intent ('stack' | 'external' | 'auto')
|
|
84
|
+
* @param {string} logicalId - CloudFormation logical ID
|
|
85
|
+
* @param {string} resourceType - CloudFormation resource type
|
|
86
|
+
* @param {Object} discovery - Discovery result
|
|
87
|
+
* @returns {Object} Resource decision
|
|
88
|
+
*/
|
|
89
|
+
resolveResourceOwnership(userIntent, logicalId, resourceType, discovery) {
|
|
90
|
+
// Use helper to work with both old flat structure and new structured
|
|
91
|
+
const structured = discovery._structured || discovery;
|
|
92
|
+
|
|
93
|
+
const inStack = this.isInStack(logicalId, structured);
|
|
94
|
+
const externalResource = this.findExternal(resourceType, structured);
|
|
95
|
+
|
|
96
|
+
const ownership = resolveOwnership(
|
|
97
|
+
userIntent || ResourceOwnership.AUTO,
|
|
98
|
+
inStack,
|
|
99
|
+
externalResource !== null
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const stackResource = inStack ? this.findInStack(logicalId, structured) : null;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
ownership,
|
|
106
|
+
physicalId: stackResource?.physicalId || externalResource?.physicalId,
|
|
107
|
+
reason: this._buildReasonString(ownership, inStack, externalResource, userIntent),
|
|
108
|
+
metadata: {
|
|
109
|
+
logicalId,
|
|
110
|
+
resourceType,
|
|
111
|
+
userIntent: userIntent || 'auto',
|
|
112
|
+
inStack,
|
|
113
|
+
foundExternal: externalResource !== null
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Build human-readable reason string
|
|
120
|
+
* @private
|
|
121
|
+
*/
|
|
122
|
+
_buildReasonString(ownership, inStack, externalResource, userIntent) {
|
|
123
|
+
if (userIntent === 'stack') {
|
|
124
|
+
return 'User explicitly specified ownership=stack';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (userIntent === 'external') {
|
|
128
|
+
return 'User explicitly specified ownership=external';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Auto-decided
|
|
132
|
+
if (ownership === ResourceOwnership.STACK) {
|
|
133
|
+
if (inStack) {
|
|
134
|
+
return 'Found in CloudFormation stack (must keep in template to avoid deletion)';
|
|
135
|
+
}
|
|
136
|
+
return 'No existing resource found - will create in stack';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (ownership === ResourceOwnership.EXTERNAL) {
|
|
140
|
+
return 'Found external resource via discovery';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return 'Ownership resolved via auto-detection';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create a resource decision for explicit external reference
|
|
148
|
+
* @protected
|
|
149
|
+
* @param {string|string[]} physicalIds - Physical resource ID(s)
|
|
150
|
+
* @param {string} reason - Reason string
|
|
151
|
+
* @returns {Object} Resource decision
|
|
152
|
+
*/
|
|
153
|
+
createExternalDecision(physicalIds, reason = 'Using external resource reference') {
|
|
154
|
+
const ids = Array.isArray(physicalIds) ? physicalIds : [physicalIds];
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
ownership: ResourceOwnership.EXTERNAL,
|
|
158
|
+
physicalId: ids[0],
|
|
159
|
+
physicalIds: ids,
|
|
160
|
+
reason,
|
|
161
|
+
metadata: {
|
|
162
|
+
source: 'user-provided'
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Create a resource decision for stack-managed resource
|
|
169
|
+
* @protected
|
|
170
|
+
* @param {string} [physicalId] - Physical ID if resource already exists
|
|
171
|
+
* @param {string} reason - Reason string
|
|
172
|
+
* @returns {Object} Resource decision
|
|
173
|
+
*/
|
|
174
|
+
createStackDecision(physicalId = null, reason = 'Managed by CloudFormation stack') {
|
|
175
|
+
return {
|
|
176
|
+
ownership: ResourceOwnership.STACK,
|
|
177
|
+
physicalId,
|
|
178
|
+
reason,
|
|
179
|
+
metadata: {
|
|
180
|
+
source: physicalId ? 'discovered' : 'new'
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = BaseResourceResolver;
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
const BaseResourceResolver = require('./base-resolver');
|
|
2
|
+
const { ResourceOwnership } = require('./types');
|
|
3
|
+
|
|
4
|
+
describe('BaseResourceResolver', () => {
|
|
5
|
+
let resolver;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
resolver = new BaseResourceResolver();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('helper methods', () => {
|
|
12
|
+
const mockDiscovery = {
|
|
13
|
+
stackManaged: [
|
|
14
|
+
{ logicalId: 'FriggVPC', physicalId: 'vpc-123', resourceType: 'AWS::EC2::VPC' },
|
|
15
|
+
{ logicalId: 'FriggLambdaSecurityGroup', physicalId: 'sg-456', resourceType: 'AWS::EC2::SecurityGroup' }
|
|
16
|
+
],
|
|
17
|
+
external: [
|
|
18
|
+
{ physicalId: 'vpc-external', resourceType: 'AWS::EC2::VPC', source: 'tag-search' }
|
|
19
|
+
],
|
|
20
|
+
fromCloudFormation: true
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('findInStack', () => {
|
|
24
|
+
it('should find resource in stack', () => {
|
|
25
|
+
const resource = resolver.findInStack('FriggVPC', mockDiscovery);
|
|
26
|
+
|
|
27
|
+
expect(resource).toEqual({
|
|
28
|
+
logicalId: 'FriggVPC',
|
|
29
|
+
physicalId: 'vpc-123',
|
|
30
|
+
resourceType: 'AWS::EC2::VPC'
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return null if not found', () => {
|
|
35
|
+
const resource = resolver.findInStack('NonExistent', mockDiscovery);
|
|
36
|
+
expect(resource).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('findExternal', () => {
|
|
41
|
+
it('should find external resource by type', () => {
|
|
42
|
+
const resource = resolver.findExternal('AWS::EC2::VPC', mockDiscovery);
|
|
43
|
+
|
|
44
|
+
expect(resource).toEqual({
|
|
45
|
+
physicalId: 'vpc-external',
|
|
46
|
+
resourceType: 'AWS::EC2::VPC',
|
|
47
|
+
source: 'tag-search'
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return null if not found', () => {
|
|
52
|
+
const resource = resolver.findExternal('AWS::RDS::DBCluster', mockDiscovery);
|
|
53
|
+
expect(resource).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('isInStack', () => {
|
|
58
|
+
it('should return true if resource is in stack', () => {
|
|
59
|
+
expect(resolver.isInStack('FriggVPC', mockDiscovery)).toBe(true);
|
|
60
|
+
expect(resolver.isInStack('FriggLambdaSecurityGroup', mockDiscovery)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should return false if resource is not in stack', () => {
|
|
64
|
+
expect(resolver.isInStack('NonExistent', mockDiscovery)).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('requireExternalIds', () => {
|
|
69
|
+
it('should not throw if IDs are provided', () => {
|
|
70
|
+
expect(() => resolver.requireExternalIds('vpc-123', 'vpcId')).not.toThrow();
|
|
71
|
+
expect(() => resolver.requireExternalIds(['sg-1', 'sg-2'], 'securityGroupIds')).not.toThrow();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should throw if IDs are missing', () => {
|
|
75
|
+
expect(() => resolver.requireExternalIds(undefined, 'vpcId')).toThrow(
|
|
76
|
+
"ownership='external' for vpcId requires external.vpcId"
|
|
77
|
+
);
|
|
78
|
+
expect(() => resolver.requireExternalIds(null, 'vpcId')).toThrow();
|
|
79
|
+
expect(() => resolver.requireExternalIds([], 'securityGroupIds')).toThrow();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('resolveResourceOwnership', () => {
|
|
85
|
+
describe('with explicit stack intent', () => {
|
|
86
|
+
it('should return STACK ownership', () => {
|
|
87
|
+
const discovery = {
|
|
88
|
+
stackManaged: [],
|
|
89
|
+
external: [{ physicalId: 'vpc-ext', resourceType: 'AWS::EC2::VPC', source: 'tag-search' }],
|
|
90
|
+
fromCloudFormation: false
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const decision = resolver.resolveResourceOwnership(
|
|
94
|
+
'stack',
|
|
95
|
+
'FriggVPC',
|
|
96
|
+
'AWS::EC2::VPC',
|
|
97
|
+
discovery
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
101
|
+
expect(decision.reason).toContain('User explicitly specified ownership=stack');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('with explicit external intent', () => {
|
|
106
|
+
it('should return EXTERNAL ownership', () => {
|
|
107
|
+
const discovery = {
|
|
108
|
+
stackManaged: [
|
|
109
|
+
{ logicalId: 'FriggVPC', physicalId: 'vpc-123', resourceType: 'AWS::EC2::VPC' }
|
|
110
|
+
],
|
|
111
|
+
external: [],
|
|
112
|
+
fromCloudFormation: true
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const decision = resolver.resolveResourceOwnership(
|
|
116
|
+
'external',
|
|
117
|
+
'FriggVPC',
|
|
118
|
+
'AWS::EC2::VPC',
|
|
119
|
+
discovery
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
123
|
+
expect(decision.reason).toContain('User explicitly specified ownership=external');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('with auto intent', () => {
|
|
128
|
+
it('should return STACK if resource is in stack (CRITICAL)', () => {
|
|
129
|
+
const discovery = {
|
|
130
|
+
stackManaged: [
|
|
131
|
+
{ logicalId: 'FriggLambdaSecurityGroup', physicalId: 'sg-069629001ade41c9a', resourceType: 'AWS::EC2::SecurityGroup' }
|
|
132
|
+
],
|
|
133
|
+
external: [],
|
|
134
|
+
fromCloudFormation: true
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const decision = resolver.resolveResourceOwnership(
|
|
138
|
+
'auto',
|
|
139
|
+
'FriggLambdaSecurityGroup',
|
|
140
|
+
'AWS::EC2::SecurityGroup',
|
|
141
|
+
discovery
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
145
|
+
expect(decision.physicalId).toBe('sg-069629001ade41c9a');
|
|
146
|
+
expect(decision.reason).toContain('Found in CloudFormation stack');
|
|
147
|
+
expect(decision.reason).toContain('must keep in template to avoid deletion');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should return EXTERNAL if found externally but not in stack', () => {
|
|
151
|
+
const discovery = {
|
|
152
|
+
stackManaged: [],
|
|
153
|
+
external: [
|
|
154
|
+
{ physicalId: 'vpc-external', resourceType: 'AWS::EC2::VPC', source: 'tag-search' }
|
|
155
|
+
],
|
|
156
|
+
fromCloudFormation: false
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const decision = resolver.resolveResourceOwnership(
|
|
160
|
+
'auto',
|
|
161
|
+
'FriggVPC',
|
|
162
|
+
'AWS::EC2::VPC',
|
|
163
|
+
discovery
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(decision.ownership).toBe(ResourceOwnership.EXTERNAL);
|
|
167
|
+
expect(decision.physicalId).toBe('vpc-external');
|
|
168
|
+
expect(decision.reason).toContain('Found external resource via discovery');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should return STACK if not found anywhere (create new)', () => {
|
|
172
|
+
const discovery = {
|
|
173
|
+
stackManaged: [],
|
|
174
|
+
external: [],
|
|
175
|
+
fromCloudFormation: false
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const decision = resolver.resolveResourceOwnership(
|
|
179
|
+
'auto',
|
|
180
|
+
'FriggVPC',
|
|
181
|
+
'AWS::EC2::VPC',
|
|
182
|
+
discovery
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
186
|
+
expect(decision.physicalId).toBeUndefined();
|
|
187
|
+
expect(decision.reason).toContain('No existing resource found - will create in stack');
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('metadata', () => {
|
|
192
|
+
it('should include complete metadata', () => {
|
|
193
|
+
const discovery = {
|
|
194
|
+
stackManaged: [
|
|
195
|
+
{ logicalId: 'FriggVPC', physicalId: 'vpc-123', resourceType: 'AWS::EC2::VPC' }
|
|
196
|
+
],
|
|
197
|
+
external: [],
|
|
198
|
+
fromCloudFormation: true
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const decision = resolver.resolveResourceOwnership(
|
|
202
|
+
'auto',
|
|
203
|
+
'FriggVPC',
|
|
204
|
+
'AWS::EC2::VPC',
|
|
205
|
+
discovery
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
expect(decision.metadata).toEqual({
|
|
209
|
+
logicalId: 'FriggVPC',
|
|
210
|
+
resourceType: 'AWS::EC2::VPC',
|
|
211
|
+
userIntent: 'auto',
|
|
212
|
+
inStack: true,
|
|
213
|
+
foundExternal: false
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe('createExternalDecision', () => {
|
|
220
|
+
it('should create external decision with single ID', () => {
|
|
221
|
+
const decision = resolver.createExternalDecision('vpc-external');
|
|
222
|
+
|
|
223
|
+
expect(decision).toEqual({
|
|
224
|
+
ownership: ResourceOwnership.EXTERNAL,
|
|
225
|
+
physicalId: 'vpc-external',
|
|
226
|
+
physicalIds: ['vpc-external'],
|
|
227
|
+
reason: 'Using external resource reference',
|
|
228
|
+
metadata: {
|
|
229
|
+
source: 'user-provided'
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should create external decision with multiple IDs', () => {
|
|
235
|
+
const decision = resolver.createExternalDecision(['sg-1', 'sg-2'], 'Custom reason');
|
|
236
|
+
|
|
237
|
+
expect(decision).toEqual({
|
|
238
|
+
ownership: ResourceOwnership.EXTERNAL,
|
|
239
|
+
physicalId: 'sg-1',
|
|
240
|
+
physicalIds: ['sg-1', 'sg-2'],
|
|
241
|
+
reason: 'Custom reason',
|
|
242
|
+
metadata: {
|
|
243
|
+
source: 'user-provided'
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
describe('createStackDecision', () => {
|
|
250
|
+
it('should create stack decision for new resource', () => {
|
|
251
|
+
const decision = resolver.createStackDecision();
|
|
252
|
+
|
|
253
|
+
expect(decision).toEqual({
|
|
254
|
+
ownership: ResourceOwnership.STACK,
|
|
255
|
+
physicalId: null,
|
|
256
|
+
reason: 'Managed by CloudFormation stack',
|
|
257
|
+
metadata: {
|
|
258
|
+
source: 'new'
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should create stack decision for existing resource', () => {
|
|
264
|
+
const decision = resolver.createStackDecision('vpc-123', 'Found in stack');
|
|
265
|
+
|
|
266
|
+
expect(decision).toEqual({
|
|
267
|
+
ownership: ResourceOwnership.STACK,
|
|
268
|
+
physicalId: 'vpc-123',
|
|
269
|
+
reason: 'Found in stack',
|
|
270
|
+
metadata: {
|
|
271
|
+
source: 'discovered'
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe('backwards compatibility with flat discovery', () => {
|
|
278
|
+
it('should work with old flat discovery structure', () => {
|
|
279
|
+
const flatDiscovery = {
|
|
280
|
+
fromCloudFormationStack: true,
|
|
281
|
+
existingLogicalIds: ['FriggVPC', 'FriggLambdaSecurityGroup'],
|
|
282
|
+
defaultVpcId: 'vpc-123',
|
|
283
|
+
securityGroupId: 'sg-456',
|
|
284
|
+
_structured: {
|
|
285
|
+
stackManaged: [
|
|
286
|
+
{ logicalId: 'FriggVPC', physicalId: 'vpc-123', resourceType: 'AWS::EC2::VPC' },
|
|
287
|
+
{ logicalId: 'FriggLambdaSecurityGroup', physicalId: 'sg-456', resourceType: 'AWS::EC2::SecurityGroup' }
|
|
288
|
+
],
|
|
289
|
+
external: [],
|
|
290
|
+
fromCloudFormation: true
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const decision = resolver.resolveResourceOwnership(
|
|
295
|
+
'auto',
|
|
296
|
+
'FriggLambdaSecurityGroup',
|
|
297
|
+
'AWS::EC2::SecurityGroup',
|
|
298
|
+
flatDiscovery
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
expect(decision.ownership).toBe(ResourceOwnership.STACK);
|
|
302
|
+
expect(decision.physicalId).toBe('sg-456');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|