@friggframework/devtools 2.0.0-next.44 → 2.0.0-next.46
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/HEALTH.md +468 -0
- package/infrastructure/README.md +51 -0
- package/infrastructure/__tests__/postgres-config.test.js +914 -0
- package/infrastructure/__tests__/template-generation.test.js +687 -0
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-builder.js +809 -0
- package/infrastructure/domains/database/aurora-builder.test.js +950 -0
- package/infrastructure/domains/database/aurora-discovery.js +87 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- 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 +633 -0
- package/infrastructure/domains/database/migration-builder.test.js +294 -0
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
- package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
- package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
- package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
- package/infrastructure/domains/health/application/ports/index.js +26 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
- package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
- package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
- package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
- package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
- package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
- package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
- package/infrastructure/domains/health/domain/entities/issue.js +299 -0
- package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
- package/infrastructure/domains/health/domain/entities/resource.js +159 -0
- package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
- package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
- package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
- package/infrastructure/domains/integration/integration-builder.js +397 -0
- package/infrastructure/domains/integration/integration-builder.test.js +593 -0
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-builder.js +1829 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
- package/infrastructure/domains/networking/vpc-discovery.js +177 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +366 -0
- package/infrastructure/domains/security/kms-builder.test.js +374 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +177 -0
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
- package/infrastructure/domains/shared/environment-builder.js +119 -0
- package/infrastructure/domains/shared/environment-builder.test.js +247 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +192 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
- 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/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
- package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +87 -0
- package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
- package/infrastructure/scripts/build-prisma-layer.js +553 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
- package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/cliIntegration.js +1 -1
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +11 -11
- package/frigg-cli/.eslintrc.js +0 -141
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
- package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
- package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
- package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
- package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
- package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
- package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
- package/frigg-cli/__tests__/utils/test-setup.js +0 -287
- package/frigg-cli/build-command/index.js +0 -65
- package/frigg-cli/db-setup-command/index.js +0 -193
- package/frigg-cli/deploy-command/index.js +0 -175
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
- package/frigg-cli/generate-command/azure-generator.js +0 -43
- package/frigg-cli/generate-command/gcp-generator.js +0 -47
- package/frigg-cli/generate-command/index.js +0 -332
- package/frigg-cli/generate-command/terraform-generator.js +0 -555
- package/frigg-cli/generate-iam-command.js +0 -118
- package/frigg-cli/index.js +0 -75
- package/frigg-cli/index.test.js +0 -158
- package/frigg-cli/init-command/backend-first-handler.js +0 -756
- package/frigg-cli/init-command/index.js +0 -93
- package/frigg-cli/init-command/template-handler.js +0 -143
- package/frigg-cli/install-command/backend-js.js +0 -33
- package/frigg-cli/install-command/commit-changes.js +0 -16
- package/frigg-cli/install-command/environment-variables.js +0 -127
- package/frigg-cli/install-command/environment-variables.test.js +0 -136
- package/frigg-cli/install-command/index.js +0 -54
- package/frigg-cli/install-command/install-package.js +0 -13
- package/frigg-cli/install-command/integration-file.js +0 -30
- package/frigg-cli/install-command/logger.js +0 -12
- package/frigg-cli/install-command/template.js +0 -90
- package/frigg-cli/install-command/validate-package.js +0 -75
- package/frigg-cli/jest.config.js +0 -124
- package/frigg-cli/package.json +0 -54
- package/frigg-cli/start-command/index.js +0 -149
- package/frigg-cli/start-command/start-command.test.js +0 -297
- package/frigg-cli/test/init-command.test.js +0 -180
- package/frigg-cli/test/npm-registry.test.js +0 -319
- package/frigg-cli/ui-command/index.js +0 -154
- package/frigg-cli/utils/app-resolver.js +0 -319
- package/frigg-cli/utils/backend-path.js +0 -25
- package/frigg-cli/utils/database-validator.js +0 -161
- package/frigg-cli/utils/error-messages.js +0 -257
- package/frigg-cli/utils/npm-registry.js +0 -167
- package/frigg-cli/utils/prisma-runner.js +0 -280
- package/frigg-cli/utils/process-manager.js +0 -199
- package/frigg-cli/utils/repo-detection.js +0 -405
- package/infrastructure/aws-discovery.js +0 -1176
- package/infrastructure/aws-discovery.test.js +0 -1220
- package/infrastructure/serverless-template.js +0 -2074
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
# Template Comparison Implementation - Fix for frigg repair --import
|
|
2
|
+
|
|
3
|
+
**Date**: 2025-10-27
|
|
4
|
+
**Status**: ✅ Core implementation completed
|
|
5
|
+
**Branch**: claude/investigate-deployment-issue-011CUQnhtGchP5yhseqHN7ch
|
|
6
|
+
|
|
7
|
+
## Problem Summary
|
|
8
|
+
|
|
9
|
+
`frigg repair --import` was broken and generating incorrect logical IDs:
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
// ❌ WRONG (before fix)
|
|
13
|
+
const resourcesToImport = orphanedResources.map((resource, idx) => ({
|
|
14
|
+
logicalId: `ImportedResource${idx + 1}`, // Generic sequential ID
|
|
15
|
+
physicalId: resource.physicalId,
|
|
16
|
+
resourceType: resource.resourceType,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
// Result: ImportedResource1, ImportedResource2, etc.
|
|
20
|
+
// CloudFormation import would fail because these don't match template
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Why This Was Broken:**
|
|
24
|
+
1. Logical IDs didn't match build template expectations (FriggVPC vs ImportedResource1)
|
|
25
|
+
2. No template parsing to find correct logical IDs
|
|
26
|
+
3. No relationship analysis between orphaned resources
|
|
27
|
+
4. No warning system for multiple resources of same type
|
|
28
|
+
5. CloudFormation import would fail with ID mismatch errors
|
|
29
|
+
|
|
30
|
+
## Solution Architecture
|
|
31
|
+
|
|
32
|
+
### Three-Layer Implementation
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
┌──────────────────────────────────────────────────────────┐
|
|
36
|
+
│ Use Case Layer (RepairViaImportUseCase) │
|
|
37
|
+
│ - Orchestrates template comparison workflow │
|
|
38
|
+
│ - Validates build template exists │
|
|
39
|
+
│ - Generates import-resources.json │
|
|
40
|
+
│ - Detects multi-resource conflicts │
|
|
41
|
+
└────────────────┬─────────────────────────────────────────┘
|
|
42
|
+
│
|
|
43
|
+
┌────────┴────────┐
|
|
44
|
+
│ │
|
|
45
|
+
┌───────▼──────┐ ┌──────▼──────┐
|
|
46
|
+
│ TemplateParser│ │LogicalIdMapper│
|
|
47
|
+
│ - Parse templates│ │ - Match orphans │
|
|
48
|
+
│ - Extract IDs │ │ - Tag analysis │
|
|
49
|
+
│ - Find Refs │ │ - Containment │
|
|
50
|
+
└─────────────────┘ └─────────────────┘
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Implementation Details
|
|
54
|
+
|
|
55
|
+
### 1. TemplateParser Service
|
|
56
|
+
|
|
57
|
+
**File**: `domains/health/domain/services/template-parser.js`
|
|
58
|
+
|
|
59
|
+
**Purpose**: Parse and compare CloudFormation templates to extract resource mappings
|
|
60
|
+
|
|
61
|
+
**Key Methods**:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
class TemplateParser {
|
|
65
|
+
// Parse template from file or object
|
|
66
|
+
parseTemplate(template) {
|
|
67
|
+
// Returns: { resources, version, description, outputs }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Get VPC-related resources
|
|
71
|
+
getVpcResources(template) {
|
|
72
|
+
// Returns: [{ logicalId, resourceType, properties }]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Extract hardcoded physical IDs from deployed template
|
|
76
|
+
extractHardcodedIds(template) {
|
|
77
|
+
// Returns: { vpcIds: [], subnetIds: [], securityGroupIds: [] }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Extract Refs from build template
|
|
81
|
+
extractRefs(template) {
|
|
82
|
+
// Returns: { vpcRefs: [], subnetRefs: [], securityGroupRefs: [] }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Find logical ID for physical ID by comparison
|
|
86
|
+
findLogicalIdForPhysicalId(physicalId, deployedTemplate, buildTemplate) {
|
|
87
|
+
// Returns: 'FriggVPC' | null
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Template Comparison Logic**:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Build Template (.serverless/cloudformation-template-update-stack.json)
|
|
96
|
+
{
|
|
97
|
+
"Resources": {
|
|
98
|
+
"FriggVPC": { "Type": "AWS::EC2::VPC" },
|
|
99
|
+
"FriggPrivateSubnet1": { "Type": "AWS::EC2::Subnet" }
|
|
100
|
+
},
|
|
101
|
+
"AttioLambdaFunction": {
|
|
102
|
+
"Properties": {
|
|
103
|
+
"VpcConfig": {
|
|
104
|
+
"SubnetIds": [{ "Ref": "FriggPrivateSubnet1" }] // ← Ref
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Deployed Template (from CloudFormation)
|
|
111
|
+
{
|
|
112
|
+
"AttioLambdaFunction": {
|
|
113
|
+
"Properties": {
|
|
114
|
+
"VpcConfig": {
|
|
115
|
+
"SubnetIds": ["subnet-00ab9e0502e66aac3"] // ← Hardcoded
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Parser extracts:
|
|
122
|
+
// - Build template has Ref: FriggPrivateSubnet1
|
|
123
|
+
// - Deployed template has hardcoded: subnet-00ab9e0502e66aac3
|
|
124
|
+
// - Therefore: FriggPrivateSubnet1 → subnet-00ab9e0502e66aac3
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 2. LogicalIdMapper Service
|
|
128
|
+
|
|
129
|
+
**File**: `domains/health/domain/services/logical-id-mapper.js`
|
|
130
|
+
|
|
131
|
+
**Purpose**: Match orphaned resources to their correct logical IDs using multiple strategies
|
|
132
|
+
|
|
133
|
+
**Matching Strategies**:
|
|
134
|
+
|
|
135
|
+
1. **CloudFormation Tags** (Primary, highest confidence)
|
|
136
|
+
```javascript
|
|
137
|
+
// Check for aws:cloudformation:logical-id tag
|
|
138
|
+
const logicalIdTag = tags.find(t => t.Key === 'aws:cloudformation:logical-id');
|
|
139
|
+
// Confidence: HIGH
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
2. **VPC Containment Analysis** (For VPCs)
|
|
143
|
+
```javascript
|
|
144
|
+
// Check if VPC contains expected subnets from template
|
|
145
|
+
const expectedSubnetIds = extractSubnetIdsFromTemplate(deployedTemplate);
|
|
146
|
+
const actualSubnets = await getSubnetsInVpc(vpc.physicalId);
|
|
147
|
+
|
|
148
|
+
const containsExpectedSubnets = expectedSubnetIds.every(expectedId =>
|
|
149
|
+
actualSubnets.some(subnet => subnet.SubnetId === expectedId)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// If matches: FriggVPC → vpc-0eadd96976d29ede7
|
|
153
|
+
// Confidence: HIGH
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
3. **Lambda VPC Usage** (For Subnets/Security Groups)
|
|
157
|
+
```javascript
|
|
158
|
+
// Check if subnet is referenced in Lambda VPC configs
|
|
159
|
+
const templateSubnetIds = extractSubnetIdsFromTemplate(deployedTemplate);
|
|
160
|
+
|
|
161
|
+
if (templateSubnetIds.includes(subnet.physicalId)) {
|
|
162
|
+
const subnetIndex = templateSubnetIds.indexOf(subnet.physicalId);
|
|
163
|
+
const subnetRefs = extractSubnetRefsFromTemplate(buildTemplate);
|
|
164
|
+
return subnetRefs[subnetIndex]; // FriggPrivateSubnet1
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Confidence: MEDIUM
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Mapping Result Format**:
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
{
|
|
174
|
+
logicalId: 'FriggVPC',
|
|
175
|
+
physicalId: 'vpc-0eadd96976d29ede7',
|
|
176
|
+
resourceType: 'AWS::EC2::VPC',
|
|
177
|
+
matchMethod: 'contained-resources',
|
|
178
|
+
confidence: 'high'
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### 3. Updated RepairViaImportUseCase
|
|
183
|
+
|
|
184
|
+
**File**: `domains/health/application/use-cases/repair-via-import-use-case.js`
|
|
185
|
+
|
|
186
|
+
**New Method**: `importWithLogicalIdMapping()`
|
|
187
|
+
|
|
188
|
+
**Workflow**:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
async importWithLogicalIdMapping({ stackIdentifier, orphanedResources, buildTemplatePath }) {
|
|
192
|
+
// 1. Validate build template exists
|
|
193
|
+
if (!fs.existsSync(buildTemplatePath)) {
|
|
194
|
+
throw new Error('Build template not found. Run serverless package first.');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 2. Parse build template
|
|
198
|
+
const buildTemplate = this.templateParser.parseTemplate(buildTemplatePath);
|
|
199
|
+
|
|
200
|
+
// 3. Get deployed template from CloudFormation
|
|
201
|
+
const deployedTemplate = await this.stackRepository.getTemplate(stackIdentifier);
|
|
202
|
+
|
|
203
|
+
// 4. Map orphaned resources to logical IDs
|
|
204
|
+
const mappings = await this.logicalIdMapper.mapOrphanedResourcesToLogicalIds({
|
|
205
|
+
orphanedResources,
|
|
206
|
+
buildTemplate,
|
|
207
|
+
deployedTemplate,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// 5. Check for multiple resources of same type
|
|
211
|
+
const multiResourceWarnings = this._checkForMultipleResources(mappings);
|
|
212
|
+
|
|
213
|
+
// 6. Filter mapped vs unmapped resources
|
|
214
|
+
const mappedResources = mappings.filter(m => m.logicalId !== null);
|
|
215
|
+
const unmappedResources = mappings.filter(m => m.logicalId === null);
|
|
216
|
+
|
|
217
|
+
// 7. Generate CloudFormation import format
|
|
218
|
+
const resourcesToImport = mappedResources.map(mapping => ({
|
|
219
|
+
ResourceType: mapping.resourceType,
|
|
220
|
+
LogicalResourceId: mapping.logicalId, // ✅ Correct: FriggVPC
|
|
221
|
+
ResourceIdentifier: this._getResourceIdentifier(mapping),
|
|
222
|
+
}));
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
success: true,
|
|
226
|
+
mappedCount: mappedResources.length,
|
|
227
|
+
unmappedCount: unmappedResources.length,
|
|
228
|
+
mappings: mappedResources,
|
|
229
|
+
resourcesToImport,
|
|
230
|
+
warnings: multiResourceWarnings,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Multi-Resource Detection**:
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
_checkForMultipleResources(mappings) {
|
|
239
|
+
const warnings = [];
|
|
240
|
+
const byType = {};
|
|
241
|
+
|
|
242
|
+
// Group by resource type
|
|
243
|
+
mappings.forEach(mapping => {
|
|
244
|
+
if (!byType[mapping.resourceType]) {
|
|
245
|
+
byType[mapping.resourceType] = [];
|
|
246
|
+
}
|
|
247
|
+
byType[mapping.resourceType].push(mapping);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Check for multiples
|
|
251
|
+
Object.entries(byType).forEach(([type, resources]) => {
|
|
252
|
+
if (resources.length > 1) {
|
|
253
|
+
warnings.push({
|
|
254
|
+
type: 'MULTIPLE_RESOURCES',
|
|
255
|
+
resourceType: type,
|
|
256
|
+
count: resources.length,
|
|
257
|
+
message: `Multiple VPCs detected (${resources.length}). Review relationships before importing.`,
|
|
258
|
+
resources: resources.map(r => ({
|
|
259
|
+
physicalId: r.physicalId,
|
|
260
|
+
logicalId: r.logicalId,
|
|
261
|
+
matchMethod: r.matchMethod,
|
|
262
|
+
confidence: r.confidence,
|
|
263
|
+
})),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return warnings;
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Resource Identifier Mapping**:
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
_getResourceIdentifier(mapping) {
|
|
276
|
+
const identifierMap = {
|
|
277
|
+
'AWS::EC2::VPC': { VpcId: physicalId },
|
|
278
|
+
'AWS::EC2::Subnet': { SubnetId: physicalId },
|
|
279
|
+
'AWS::EC2::SecurityGroup': { GroupId: physicalId },
|
|
280
|
+
'AWS::EC2::InternetGateway': { InternetGatewayId: physicalId },
|
|
281
|
+
'AWS::EC2::NatGateway': { NatGatewayId: physicalId },
|
|
282
|
+
'AWS::EC2::RouteTable': { RouteTableId: physicalId },
|
|
283
|
+
'AWS::EC2::VPCEndpoint': { VpcEndpointId: physicalId },
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
return identifierMap[resourceType] || { Id: physicalId };
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Example Output
|
|
291
|
+
|
|
292
|
+
### Successful Mapping
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"success": true,
|
|
297
|
+
"mappedCount": 4,
|
|
298
|
+
"unmappedCount": 0,
|
|
299
|
+
"mappings": [
|
|
300
|
+
{
|
|
301
|
+
"logicalId": "FriggVPC",
|
|
302
|
+
"physicalId": "vpc-0eadd96976d29ede7",
|
|
303
|
+
"resourceType": "AWS::EC2::VPC",
|
|
304
|
+
"matchMethod": "contained-resources",
|
|
305
|
+
"confidence": "high"
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"logicalId": "FriggPrivateSubnet1",
|
|
309
|
+
"physicalId": "subnet-00ab9e0502e66aac3",
|
|
310
|
+
"resourceType": "AWS::EC2::Subnet",
|
|
311
|
+
"matchMethod": "vpc-usage",
|
|
312
|
+
"confidence": "high"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"logicalId": "FriggPrivateSubnet2",
|
|
316
|
+
"physicalId": "subnet-00d085a52937aaf91",
|
|
317
|
+
"resourceType": "AWS::EC2::Subnet",
|
|
318
|
+
"matchMethod": "vpc-usage",
|
|
319
|
+
"confidence": "high"
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
"logicalId": "FriggLambdaSecurityGroup",
|
|
323
|
+
"physicalId": "sg-07c01370e830b6ad6",
|
|
324
|
+
"resourceType": "AWS::EC2::SecurityGroup",
|
|
325
|
+
"matchMethod": "usage",
|
|
326
|
+
"confidence": "medium"
|
|
327
|
+
}
|
|
328
|
+
],
|
|
329
|
+
"resourcesToImport": [
|
|
330
|
+
{
|
|
331
|
+
"ResourceType": "AWS::EC2::VPC",
|
|
332
|
+
"LogicalResourceId": "FriggVPC",
|
|
333
|
+
"ResourceIdentifier": { "VpcId": "vpc-0eadd96976d29ede7" }
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"ResourceType": "AWS::EC2::Subnet",
|
|
337
|
+
"LogicalResourceId": "FriggPrivateSubnet1",
|
|
338
|
+
"ResourceIdentifier": { "SubnetId": "subnet-00ab9e0502e66aac3" }
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"ResourceType": "AWS::EC2::Subnet",
|
|
342
|
+
"LogicalResourceId": "FriggPrivateSubnet2",
|
|
343
|
+
"ResourceIdentifier": { "SubnetId": "subnet-00d085a52937aaf91" }
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"ResourceType": "AWS::EC2::SecurityGroup",
|
|
347
|
+
"LogicalResourceId": "FriggLambdaSecurityGroup",
|
|
348
|
+
"ResourceIdentifier": { "GroupId": "sg-07c01370e830b6ad6" }
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
"warnings": []
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Multiple Resources Warning
|
|
356
|
+
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"success": true,
|
|
360
|
+
"mappedCount": 3,
|
|
361
|
+
"warnings": [
|
|
362
|
+
{
|
|
363
|
+
"type": "MULTIPLE_RESOURCES",
|
|
364
|
+
"resourceType": "AWS::EC2::VPC",
|
|
365
|
+
"count": 3,
|
|
366
|
+
"message": "Multiple VPCs detected (3). Review relationships before importing.",
|
|
367
|
+
"resources": [
|
|
368
|
+
{
|
|
369
|
+
"physicalId": "vpc-0eadd96976d29ede7",
|
|
370
|
+
"logicalId": "FriggVPC",
|
|
371
|
+
"matchMethod": "contained-resources",
|
|
372
|
+
"confidence": "high"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"physicalId": "vpc-0e2351eac99adcb83",
|
|
376
|
+
"logicalId": "FriggVPC",
|
|
377
|
+
"matchMethod": "tag",
|
|
378
|
+
"confidence": "high"
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"physicalId": "vpc-020a0365610c05f0b",
|
|
382
|
+
"logicalId": "FriggVPC",
|
|
383
|
+
"matchMethod": "tag",
|
|
384
|
+
"confidence": "high"
|
|
385
|
+
}
|
|
386
|
+
]
|
|
387
|
+
}
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Benefits
|
|
393
|
+
|
|
394
|
+
### 1. Correct Logical IDs
|
|
395
|
+
✅ **Before**: `ImportedResource1`, `ImportedResource2`
|
|
396
|
+
✅ **After**: `FriggVPC`, `FriggPrivateSubnet1`, `FriggLambdaSecurityGroup`
|
|
397
|
+
|
|
398
|
+
### 2. Template-Aware Mapping
|
|
399
|
+
- Compares build template with deployed template
|
|
400
|
+
- Understands CloudFormation Refs vs hardcoded IDs
|
|
401
|
+
- Matches orphaned resources to template expectations
|
|
402
|
+
|
|
403
|
+
### 3. Multi-Resource Detection
|
|
404
|
+
- Warns when multiple VPCs detected
|
|
405
|
+
- Shows confidence level for each match
|
|
406
|
+
- Helps users choose correct resource to import
|
|
407
|
+
|
|
408
|
+
### 4. Confidence Levels
|
|
409
|
+
- **HIGH**: CloudFormation tags or VPC containment match
|
|
410
|
+
- **MEDIUM**: Lambda VPC usage pattern match
|
|
411
|
+
- **NONE**: No match found (unmapped resource)
|
|
412
|
+
|
|
413
|
+
### 5. Error Handling
|
|
414
|
+
```
|
|
415
|
+
❌ Build template not found at: /path/to/.serverless/cloudformation-template-update-stack.json
|
|
416
|
+
|
|
417
|
+
Please run one of:
|
|
418
|
+
• serverless package
|
|
419
|
+
• frigg build
|
|
420
|
+
• frigg deploy --stage dev
|
|
421
|
+
|
|
422
|
+
Then try again:
|
|
423
|
+
frigg repair --import acme-integrations-dev
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Remaining Work
|
|
427
|
+
|
|
428
|
+
### 1. Update frigg repair CLI Command
|
|
429
|
+
|
|
430
|
+
**File**: `packages/frigg-cli/repair-command/index.js`
|
|
431
|
+
|
|
432
|
+
**Required Changes**:
|
|
433
|
+
```javascript
|
|
434
|
+
// Replace broken logic at lines 94-98
|
|
435
|
+
async function handleImportRepair(stackIdentifier, report, options) {
|
|
436
|
+
const orphanedResources = report.getOrphanedResources();
|
|
437
|
+
|
|
438
|
+
// Find build template
|
|
439
|
+
const buildTemplatePath = path.join(
|
|
440
|
+
process.cwd(),
|
|
441
|
+
'.serverless',
|
|
442
|
+
'cloudformation-template-update-stack.json'
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
if (!fs.existsSync(buildTemplatePath)) {
|
|
446
|
+
throw new Error('Build template not found. Run `serverless package` first.');
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Use new method with template comparison
|
|
450
|
+
const result = await repairUseCase.importWithLogicalIdMapping({
|
|
451
|
+
stackIdentifier,
|
|
452
|
+
orphanedResources,
|
|
453
|
+
buildTemplatePath
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Handle warnings (multiple resources)
|
|
457
|
+
if (result.warnings.length > 0) {
|
|
458
|
+
console.log('\n⚠️ WARNINGS:\n');
|
|
459
|
+
result.warnings.forEach(warning => {
|
|
460
|
+
console.log(` ${warning.message}`);
|
|
461
|
+
// Show user selection prompt for multiple resources
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Show mappings
|
|
466
|
+
console.log(`\n✓ Mapped ${result.mappedCount} resources to logical IDs:`);
|
|
467
|
+
result.mappings.forEach(m => {
|
|
468
|
+
console.log(` • ${m.logicalId} → ${m.physicalId} (${m.matchMethod}, ${m.confidence})`);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Save import-resources.json
|
|
472
|
+
fs.writeFileSync(
|
|
473
|
+
'import-resources.json',
|
|
474
|
+
JSON.stringify(result.resourcesToImport, null, 2)
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
console.log('\n📦 Generated: import-resources.json');
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### 2. Add User Selection Prompt for Multiple Resources
|
|
482
|
+
|
|
483
|
+
When multiple VPCs detected, prompt user to choose:
|
|
484
|
+
|
|
485
|
+
```javascript
|
|
486
|
+
if (warning.type === 'MULTIPLE_RESOURCES') {
|
|
487
|
+
console.log(`\n⚠️ Multiple ${warning.resourceType}s detected (${warning.count}):`);
|
|
488
|
+
|
|
489
|
+
warning.resources.forEach((resource, idx) => {
|
|
490
|
+
console.log(` ${idx + 1}. ${resource.physicalId}`);
|
|
491
|
+
console.log(` Logical ID: ${resource.logicalId}`);
|
|
492
|
+
console.log(` Match Method: ${resource.matchMethod}`);
|
|
493
|
+
console.log(` Confidence: ${resource.confidence}\n`);
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
const selection = await promptUser('Select resource number to import (or "skip" to skip): ');
|
|
497
|
+
|
|
498
|
+
if (selection === 'skip') {
|
|
499
|
+
// Remove all resources of this type from import
|
|
500
|
+
} else {
|
|
501
|
+
// Keep only selected resource
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### 3. Test with Real Stack
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
# Test with acme-integrations-dev
|
|
510
|
+
cd /path/to/acme-integrations-dev/backend
|
|
511
|
+
frigg doctor acme-integrations-dev
|
|
512
|
+
frigg repair --import acme-integrations-dev
|
|
513
|
+
|
|
514
|
+
# Expected output:
|
|
515
|
+
# ✓ Found build template: .serverless/cloudformation-template-update-stack.json
|
|
516
|
+
# ✓ Retrieved deployed template from CloudFormation
|
|
517
|
+
# ✓ Mapped 4 resources to logical IDs:
|
|
518
|
+
# • FriggVPC → vpc-0eadd96976d29ede7 (contained-resources, high)
|
|
519
|
+
# • FriggPrivateSubnet1 → subnet-00ab9e0502e66aac3 (vpc-usage, high)
|
|
520
|
+
# • FriggPrivateSubnet2 → subnet-00d085a52937aaf91 (vpc-usage, high)
|
|
521
|
+
# • FriggLambdaSecurityGroup → sg-07c01370e830b6ad6 (usage, medium)
|
|
522
|
+
#
|
|
523
|
+
# ⚠️ Multiple VPCs detected (3):
|
|
524
|
+
# 1. vpc-0eadd96976d29ede7 (contained-resources, high)
|
|
525
|
+
# 2. vpc-0e2351eac99adcb83 (tag, high)
|
|
526
|
+
# 3. vpc-020a0365610c05f0b (tag, high)
|
|
527
|
+
#
|
|
528
|
+
# Select VPC to import [1]: 1
|
|
529
|
+
#
|
|
530
|
+
# 📦 Generated: import-resources.json
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
## Related Documentation
|
|
534
|
+
|
|
535
|
+
- **Problem Analysis**: `FRIGG-REPAIR-FIXES-NEEDED.md`
|
|
536
|
+
- **Import Strategy**: `IMPORT-STRATEGY.md`
|
|
537
|
+
- **Template Comparison**: `BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md`
|
|
538
|
+
- **Orphan Detection**: `ORPHAN-DETECTION-ANALYSIS.md`
|
|
539
|
+
- **Drift Analysis**: `ACME-DEV-DRIFT-ANALYSIS.md`
|
|
540
|
+
|
|
541
|
+
## Summary
|
|
542
|
+
|
|
543
|
+
This implementation fixes the core issue with `frigg repair --import` by:
|
|
544
|
+
|
|
545
|
+
1. ✅ **Parsing templates** to find correct logical IDs
|
|
546
|
+
2. ✅ **Comparing templates** to understand drift and mappings
|
|
547
|
+
3. ✅ **Mapping orphaned resources** using multiple strategies
|
|
548
|
+
4. ✅ **Detecting multi-resource conflicts** with confidence levels
|
|
549
|
+
5. ✅ **Generating proper CloudFormation import format**
|
|
550
|
+
|
|
551
|
+
The remaining work is to integrate this into the CLI command and add user selection prompts for multiple resources. The core logic is complete and ready for testing.
|