@intentius/chant-lexicon-aws 0.124.31 → 0.124.32
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/actions/dynamodb.js +41 -0
- package/dist/actions/ecr.js +9 -0
- package/dist/actions/ecs.js +5 -0
- package/dist/actions/iam.js +3 -0
- package/dist/actions/index.js +9 -0
- package/dist/actions/lambda.js +11 -0
- package/dist/actions/logs.js +4 -0
- package/dist/actions/s3.js +40 -0
- package/dist/actions/sns.js +5 -0
- package/dist/actions/sqs.js +15 -0
- package/dist/agentcore/trace-fetch.d.ts.map +1 -1
- package/dist/agentcore/trace-fetch.js +472 -0
- package/dist/agentcore/trace-render.js +359 -0
- package/dist/ambient.js +148 -0
- package/dist/api/credential-chain.d.ts +30 -3
- package/dist/api/credential-chain.d.ts.map +1 -1
- package/dist/api/credential-chain.js +509 -0
- package/dist/api/read-client.d.ts +16 -43
- package/dist/api/read-client.d.ts.map +1 -1
- package/dist/api/read-client.js +458 -0
- package/dist/api/sigv4.d.ts +4 -4
- package/dist/api/sigv4.js +185 -0
- package/dist/behaviour-kinds.js +114 -0
- package/dist/caller-identity.d.ts +3 -5
- package/dist/caller-identity.d.ts.map +1 -1
- package/dist/caller-identity.js +146 -0
- package/dist/codegen/docs-cli.js +2 -0
- package/dist/codegen/docs.js +120 -0
- package/dist/codegen/enum-overlay.js +162 -0
- package/dist/codegen/extensions.js +139 -0
- package/dist/codegen/fallback.js +32 -0
- package/dist/codegen/generate-cli.js +15 -0
- package/dist/codegen/generate-lexicon.js +70 -0
- package/dist/codegen/generate-typescript.js +226 -0
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/codegen/generate.js +234 -0
- package/dist/codegen/naming.js +135 -0
- package/dist/codegen/package.js +67 -0
- package/dist/codegen/patches.d.ts +26 -1
- package/dist/codegen/patches.d.ts.map +1 -1
- package/dist/codegen/patches.js +90 -0
- package/dist/codegen/property-overlay.js +85 -0
- package/dist/codegen/property-overlay.json +1 -16
- package/dist/codegen/sam.js +402 -0
- package/dist/codegen/typecheck.js +4 -0
- package/dist/codegen/versions.js +31 -0
- package/dist/components/__tests__/mock-cloud-executor.js +326 -0
- package/dist/components/apply.d.ts +44 -1
- package/dist/components/apply.d.ts.map +1 -1
- package/dist/components/apply.js +752 -0
- package/dist/components/builders.js +37 -0
- package/dist/components/capability-plugin.js +66 -0
- package/dist/components/cloud-executor.d.ts +35 -0
- package/dist/components/cloud-executor.d.ts.map +1 -1
- package/dist/components/cloud-executor.js +576 -0
- package/dist/components/config-bom.js +207 -0
- package/dist/components/host-delivery.js +117 -0
- package/dist/components/index.js +18 -0
- package/dist/components/job-submission.js +77 -0
- package/dist/components/publish.js +234 -0
- package/dist/components/safety.js +62 -0
- package/dist/components/wait-aws.js +68 -0
- package/dist/composites/agentcore-agent.js +187 -0
- package/dist/composites/agentcore-trust-policy.js +13 -0
- package/dist/composites/alb-shared.js +84 -0
- package/dist/composites/bucket-deployment.js +93 -0
- package/dist/composites/catalog.js +2714 -0
- package/dist/composites/dynamodb-table.js +66 -0
- package/dist/composites/ec2-instance-bundle.js +75 -0
- package/dist/composites/ec2-instance-role.js +26 -0
- package/dist/composites/ecr-repository.js +64 -0
- package/dist/composites/ecs-trust-policy.js +10 -0
- package/dist/composites/efs-with-access-point.js +44 -0
- package/dist/composites/eks-cluster.js +118 -0
- package/dist/composites/fargate-alb.js +216 -0
- package/dist/composites/fargate-service.js +222 -0
- package/dist/composites/index.js +28 -0
- package/dist/composites/lambda-api.js +15 -0
- package/dist/composites/lambda-dynamodb.js +77 -0
- package/dist/composites/lambda-eventbridge.js +27 -0
- package/dist/composites/lambda-function.js +54 -0
- package/dist/composites/lambda-s3.js +93 -0
- package/dist/composites/lambda-sns.js +23 -0
- package/dist/composites/lambda-sqs.js +34 -0
- package/dist/composites/landing-zone.js +82 -0
- package/dist/composites/microvm-app.js +293 -0
- package/dist/composites/minimal-vpc.js +40 -0
- package/dist/composites/monitoring-stack.js +105 -0
- package/dist/composites/nlb-service.js +61 -0
- package/dist/composites/rds-instance.js +98 -0
- package/dist/composites/scheduled-lambda.js +28 -0
- package/dist/composites/solr-fargate-service.js +33 -0
- package/dist/composites/step-functions-workflow.js +78 -0
- package/dist/composites/vpc-default.js +132 -0
- package/dist/condition.js +43 -0
- package/dist/coverage.js +4 -0
- package/dist/deep-observe.d.ts.map +1 -1
- package/dist/deep-observe.js +709 -0
- package/dist/deep-topology.js +226 -0
- package/dist/default-tags.js +50 -0
- package/dist/defaults.js +85 -0
- package/dist/dependencies.js +269 -0
- package/dist/detect.js +21 -0
- package/dist/disruption.d.ts.map +1 -1
- package/dist/disruption.js +129 -0
- package/dist/effect-receipt-row.js +107 -0
- package/dist/generated/index.d.ts +1297 -82
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +12382 -0
- package/dist/generated/runtime.js +4 -0
- package/dist/governance.js +131 -0
- package/dist/identity-observe.d.ts.map +1 -1
- package/dist/identity-observe.js +127 -0
- package/dist/import/generator.js +757 -0
- package/dist/import/live-export.js +34 -0
- package/dist/import/parser.js +394 -0
- package/dist/index.js +69 -0
- package/dist/integrity.json +6 -6
- package/dist/intrinsics.js +393 -0
- package/dist/lint/audit-catalog.js +87 -0
- package/dist/lint/audit-lineage.js +150 -0
- package/dist/lint/post-synth/cf-refs.js +247 -0
- package/dist/lint/post-synth/cor020.js +60 -0
- package/dist/lint/post-synth/ext001.d.ts.map +1 -1
- package/dist/lint/post-synth/ext001.js +197 -0
- package/dist/lint/post-synth/index.js +124 -0
- package/dist/lint/post-synth/waw010.js +41 -0
- package/dist/lint/post-synth/waw011.js +41 -0
- package/dist/lint/post-synth/waw013.js +38 -0
- package/dist/lint/post-synth/waw014.js +42 -0
- package/dist/lint/post-synth/waw015.js +88 -0
- package/dist/lint/post-synth/waw016.d.ts.map +1 -1
- package/dist/lint/post-synth/waw016.js +116 -0
- package/dist/lint/post-synth/waw017.js +43 -0
- package/dist/lint/post-synth/waw018.js +61 -0
- package/dist/lint/post-synth/waw019.js +64 -0
- package/dist/lint/post-synth/waw020.js +56 -0
- package/dist/lint/post-synth/waw021.js +44 -0
- package/dist/lint/post-synth/waw022.js +36 -0
- package/dist/lint/post-synth/waw023.js +40 -0
- package/dist/lint/post-synth/waw024.js +46 -0
- package/dist/lint/post-synth/waw025.js +36 -0
- package/dist/lint/post-synth/waw026.js +38 -0
- package/dist/lint/post-synth/waw027.js +41 -0
- package/dist/lint/post-synth/waw028.js +39 -0
- package/dist/lint/post-synth/waw029.js +54 -0
- package/dist/lint/post-synth/waw030.js +282 -0
- package/dist/lint/post-synth/waw031.js +58 -0
- package/dist/lint/post-synth/waw032.js +45 -0
- package/dist/lint/post-synth/waw033.js +75 -0
- package/dist/lint/post-synth/waw034.js +52 -0
- package/dist/lint/post-synth/waw035.js +56 -0
- package/dist/lint/post-synth/waw036.js +79 -0
- package/dist/lint/post-synth/waw037.js +67 -0
- package/dist/lint/post-synth/waw038.js +42 -0
- package/dist/lint/post-synth/waw039.js +42 -0
- package/dist/lint/post-synth/waw040.js +45 -0
- package/dist/lint/post-synth/waw041.js +40 -0
- package/dist/lint/post-synth/waw042.js +99 -0
- package/dist/lint/post-synth/waw043.js +51 -0
- package/dist/lint/post-synth/waw044.js +64 -0
- package/dist/lint/post-synth/waw045.js +49 -0
- package/dist/lint/post-synth/waw046.js +52 -0
- package/dist/lint/post-synth/waw047.js +43 -0
- package/dist/lint/post-synth/waw048.js +40 -0
- package/dist/lint/post-synth/waw049.js +78 -0
- package/dist/lint/post-synth/waw050.js +44 -0
- package/dist/lint/post-synth/waw051.js +41 -0
- package/dist/lint/post-synth/waw052.js +43 -0
- package/dist/lint/post-synth/waw053.js +43 -0
- package/dist/lint/post-synth/waw054.js +41 -0
- package/dist/lint/post-synth/waw055.js +41 -0
- package/dist/lint/post-synth/waw056.js +65 -0
- package/dist/lint/post-synth/waw057.js +43 -0
- package/dist/lint/post-synth/waw058.js +61 -0
- package/dist/lint/post-synth/waw059.js +338 -0
- package/dist/lint/post-synth/waw060.js +83 -0
- package/dist/lint/post-synth/waw061.js +60 -0
- package/dist/lint/post-synth/waw062.js +0 -0
- package/dist/lint/post-synth/waw063.js +0 -0
- package/dist/lint/post-synth/waw064.js +45 -0
- package/dist/lint/post-synth/waw065.js +104 -0
- package/dist/lint/post-synth/waw066.js +145 -0
- package/dist/lint/post-synth/waw067.js +115 -0
- package/dist/lint/post-synth/waw068.js +69 -0
- package/dist/lint/post-synth/waw069.js +0 -0
- package/dist/lint/rules/hardcoded-region.js +38 -0
- package/dist/lint/rules/iam-wildcard.js +60 -0
- package/dist/lint/rules/index.js +6 -0
- package/dist/lint/rules/s3-encryption.js +60 -0
- package/dist/live-attrs.js +42 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +18 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +66 -0
- package/dist/manifest.json +1 -1
- package/dist/mapping.js +33 -0
- package/dist/meta.json +17359 -784
- package/dist/nested-stack.js +95 -0
- package/dist/okf/index.md +203 -0
- package/dist/okf/rules/EXT001.md +1 -0
- package/dist/okf/rules/WAW016.md +2 -0
- package/dist/okf/rules/WAW019.md +1 -0
- package/dist/okf/rules/WAW028.md +1 -0
- package/dist/okf/rules/WAW030.md +2 -0
- package/dist/okf/rules/WAW039.md +1 -0
- package/dist/okf/rules/WAW049.md +1 -0
- package/dist/okf/rules/WAW056.md +1 -0
- package/dist/okf/rules/WAW058.md +1 -0
- package/dist/okf/rules/WAW062.md +1 -0
- package/dist/okf/rules/WAW064.md +1 -0
- package/dist/okf/rules/WAW065.md +1 -0
- package/dist/okf/rules/WAW066.md +1 -0
- package/dist/okf/rules/WAW067.md +1 -0
- package/dist/okf/rules/WAW068.md +1 -0
- package/dist/okf/rules/WAW069.md +4 -0
- package/dist/okf/types/AIWorkloadConfig.md +23 -0
- package/dist/okf/types/ARCRegionSwitchPlan.md +1 -0
- package/dist/okf/types/AccountAccessApplication.md +28 -0
- package/dist/okf/types/AccountAccessEntitlement.md +22 -0
- package/dist/okf/types/ActionTarget.md +20 -0
- package/dist/okf/types/AdConfiguration.md +21 -0
- package/dist/okf/types/Adapter.md +26 -0
- package/dist/okf/types/AgentContext.md +35 -0
- package/dist/okf/types/AgentGoal.md +31 -0
- package/dist/okf/types/AgentProfile.md +34 -0
- package/dist/okf/types/Alarm.md +3 -1
- package/dist/okf/types/AlarmModel.md +14 -9
- package/dist/okf/types/AmplifyWebhook.md +25 -0
- package/dist/okf/types/ApiCache.md +8 -8
- package/dist/okf/types/ApiGatewayManagedOverrides.md +5 -5
- package/dist/okf/types/AppAuthorization.md +35 -0
- package/dist/okf/types/AppBlockBuilder.md +1 -0
- package/dist/okf/types/AppInstance.md +2 -2
- package/dist/okf/types/AppInstanceBot.md +2 -2
- package/dist/okf/types/AppStreamFleet.md +3 -2
- package/dist/okf/types/AppSyncApiKey.md +6 -6
- package/dist/okf/types/AppSyncType.md +22 -0
- package/dist/okf/types/ApplicationStatusCheck.md +36 -0
- package/dist/okf/types/ApplicationVersion.md +4 -1
- package/dist/okf/types/ApplicationsList.md +26 -0
- package/dist/okf/types/ApprovalPolicy.md +28 -0
- package/dist/okf/types/ArchiveRule.md +24 -0
- package/dist/okf/types/Asset.md +30 -0
- package/dist/okf/types/Backup.md +31 -0
- package/dist/okf/types/BedrockAgentCoreDataset.md +1 -1
- package/dist/okf/types/BedrockAgentCoreGateway.md +3 -0
- package/dist/okf/types/BedrockSession.md +28 -0
- package/dist/okf/types/BillEstimate.md +35 -0
- package/dist/okf/types/Brand.md +32 -0
- package/dist/okf/types/CallAnalyticsCategory.md +25 -0
- package/dist/okf/types/Campaign.md +28 -0
- package/dist/okf/types/CapacityProvider.md +30 -0
- package/dist/okf/types/Case.md +24 -0
- package/dist/okf/types/CertificateAssociation.md +13 -0
- package/dist/okf/types/ChangeSet.md +36 -0
- package/dist/okf/types/ChannelFlow.md +29 -0
- package/dist/okf/types/ChimeChannel.md +39 -0
- package/dist/okf/types/Classifier.md +6 -6
- package/dist/okf/types/ClientVpnAuthorizationRule.md +6 -6
- package/dist/okf/types/ClientVpnEndpoint.md +2 -0
- package/dist/okf/types/ClientVpnRoute.md +5 -5
- package/dist/okf/types/CloudConnector.md +29 -0
- package/dist/okf/types/Cluster.md +39 -0
- package/dist/okf/types/ClusterSchedulerConfig.md +30 -0
- package/dist/okf/types/CodeCommitRepository.md +12 -12
- package/dist/okf/types/CodeConnectionsHost.md +26 -0
- package/dist/okf/types/CodeRepository.md +5 -5
- package/dist/okf/types/CompositeAlarm.md +1 -0
- package/dist/okf/types/ComputeEnvironment.md +2 -0
- package/dist/okf/types/ComputeNodeGroup.md +1 -1
- package/dist/okf/types/ComputeQuota.md +34 -0
- package/dist/okf/types/ConfigRule.md +1 -1
- package/dist/okf/types/ConfigurationRecorder.md +7 -6
- package/dist/okf/types/ConnectAttachment.md +2 -0
- package/dist/okf/types/ConnectQueue.md +5 -1
- package/dist/okf/types/ConnectVocabulary.md +28 -0
- package/dist/okf/types/ConnectionType.md +24 -0
- package/dist/okf/types/ConsentPortal.md +33 -0
- package/dist/okf/types/ContactMethod.md +29 -0
- package/dist/okf/types/ContainerAssociation.md +26 -0
- package/dist/okf/types/ContainerFleet.md +1 -1
- package/dist/okf/types/ContainerGroupDefinition.md +1 -1
- package/dist/okf/types/Content.md +40 -0
- package/dist/okf/types/ContentAssociation.md +28 -0
- package/dist/okf/types/CustomDetectionRuleAssociation.md +28 -0
- package/dist/okf/types/CustomEntityType.md +4 -9
- package/dist/okf/types/Customization.md +22 -0
- package/dist/okf/types/CwIntegration.md +31 -0
- package/dist/okf/types/DAXParameterGroup.md +3 -8
- package/dist/okf/types/DAXSubnetGroup.md +0 -5
- package/dist/okf/types/DBClusterEndpoint.md +31 -0
- package/dist/okf/types/DBProxyTargetGroup.md +1 -0
- package/dist/okf/types/DBSnapshot.md +62 -0
- package/dist/okf/types/DLMLifecyclePolicy.md +12 -12
- package/dist/okf/types/DLPSetting.md +31 -0
- package/dist/okf/types/DMSInstanceProfile.md +1 -1
- package/dist/okf/types/DRSLaunchConfigurationTemplate.md +28 -0
- package/dist/okf/types/Daemon.md +1 -0
- package/dist/okf/types/DataExchangeDataSet.md +29 -0
- package/dist/okf/types/DataIntegrationFlow.md +27 -0
- package/dist/okf/types/DataMigration.md +1 -1
- package/dist/okf/types/DataProvider.md +2 -1
- package/dist/okf/types/DataQualityRuleset.md +6 -11
- package/dist/okf/types/DataSource.md +23 -0
- package/dist/okf/types/Dataset.md +20 -0
- package/dist/okf/types/DatasetIntegration.md +23 -0
- package/dist/okf/types/DbCluster.md +1 -1
- package/dist/okf/types/DbInstance.md +8 -2
- package/dist/okf/types/DeadlineBudget.md +29 -0
- package/dist/okf/types/DelegationSet.md +23 -0
- package/dist/okf/types/DeliveryChannel.md +6 -11
- package/dist/okf/types/DevOpsAgentAgentSpace.md +4 -0
- package/dist/okf/types/DevOpsAgentService.md +1 -0
- package/dist/okf/types/DevOpsAgentTrigger.md +28 -0
- package/dist/okf/types/DirectConnectGatewayAttachment.md +2 -0
- package/dist/okf/types/Directory.md +60 -0
- package/dist/okf/types/DocDBDBClusterParameterGroup.md +5 -10
- package/dist/okf/types/DocDBDBSubnetGroup.md +4 -9
- package/dist/okf/types/DocDBElasticClusterSnapshot.md +36 -0
- package/dist/okf/types/DocumentClassifierEndpoint.md +27 -0
- package/dist/okf/types/Domain.md +27 -0
- package/dist/okf/types/EKSCertificateAuthority.md +42 -0
- package/dist/okf/types/EKSCluster.md +8 -0
- package/dist/okf/types/EcSnapshot.md +66 -0
- package/dist/okf/types/EmailIdentityCertificate.md +15 -0
- package/dist/okf/types/EndpointConfig.md +14 -13
- package/dist/okf/types/EntityRecognizer.md +27 -0
- package/dist/okf/types/EntityRecognizerEndpoint.md +31 -0
- package/dist/okf/types/EnvironmentEC2.md +13 -13
- package/dist/okf/types/EvaluationForm.md +1 -0
- package/dist/okf/types/Evaluator.md +6 -2
- package/dist/okf/types/EventAction.md +26 -0
- package/dist/okf/types/EventRule.md +2 -0
- package/dist/okf/types/EventSource.md +30 -0
- package/dist/okf/types/EventTracker.md +22 -0
- package/dist/okf/types/EventsV2EventBus.md +28 -0
- package/dist/okf/types/EventsV2ResourcePolicy.md +19 -0
- package/dist/okf/types/EventsV2Subscriber.md +39 -0
- package/dist/okf/types/ExperimentDefinition.md +39 -0
- package/dist/okf/types/ExperimentRun.md +33 -0
- package/dist/okf/types/ExperimentTrialComponent.md +13 -11
- package/dist/okf/types/FHIRDatastore.md +3 -0
- package/dist/okf/types/FSxSnapshot.md +5 -5
- package/dist/okf/types/FSxVolume.md +9 -9
- package/dist/okf/types/FeaturedResultsSet.md +26 -0
- package/dist/okf/types/Feed.md +1 -0
- package/dist/okf/types/FieldLevelEncryptionConfig.md +25 -0
- package/dist/okf/types/FieldLevelEncryptionProfile.md +22 -0
- package/dist/okf/types/FileCache.md +45 -0
- package/dist/okf/types/Filter.md +27 -0
- package/dist/okf/types/Firewall.md +6 -0
- package/dist/okf/types/FlowMediaStream.md +28 -0
- package/dist/okf/types/FlowOutput.md +1 -0
- package/dist/okf/types/FpgaImage.md +38 -0
- package/dist/okf/types/Function.md +2 -2
- package/dist/okf/types/Gateway.md +41 -0
- package/dist/okf/types/GatewayClusterAssociations.md +23 -0
- package/dist/okf/types/GatewayRateLimit.md +26 -0
- package/dist/okf/types/GatewayRule.md +32 -0
- package/dist/okf/types/GlobalReplicationGroup.md +3 -0
- package/dist/okf/types/GlobalResolver.md +1 -1
- package/dist/okf/types/GlobalTable.md +1 -0
- package/dist/okf/types/GlueConnection.md +5 -4
- package/dist/okf/types/GlueSecurityConfiguration.md +1 -6
- package/dist/okf/types/GlueSession.md +38 -0
- package/dist/okf/types/GlueTable.md +5 -10
- package/dist/okf/types/GlueWorkflow.md +5 -10
- package/dist/okf/types/Group.md +27 -0
- package/dist/okf/types/Harness.md +1 -0
- package/dist/okf/types/HostKey.md +33 -0
- package/dist/okf/types/HostedZone.md +1 -0
- package/dist/okf/types/HttpApi.md +2 -0
- package/dist/okf/types/HttpNamespace.md +5 -5
- package/dist/okf/types/HubV2.md +1 -0
- package/dist/okf/types/HumanTaskUi.md +22 -0
- package/dist/okf/types/IPv4Pool.md +28 -0
- package/dist/okf/types/ImageBuilder.md +1 -0
- package/dist/okf/types/ImageBuilderImage.md +1 -1
- package/dist/okf/types/ImagePipeline.md +1 -1
- package/dist/okf/types/InferenceComponent.md +5 -1
- package/dist/okf/types/InfluxDBBackup.md +65 -0
- package/dist/okf/types/InfluxDBCluster.md +3 -0
- package/dist/okf/types/InfrastructureConfiguration.md +2 -0
- package/dist/okf/types/IngestionDestination.md +28 -0
- package/dist/okf/types/InputSecurityGroup.md +6 -4
- package/dist/okf/types/InspectorV2Connector.md +38 -0
- package/dist/okf/types/InstanceEventWindow.md +25 -0
- package/dist/okf/types/InstanceFleetConfig.md +10 -10
- package/dist/okf/types/InstanceGroupConfig.md +3 -3
- package/dist/okf/types/InstrumentationConfig.md +31 -0
- package/dist/okf/types/IntegrationAssociation.md +3 -0
- package/dist/okf/types/IoTSiteWiseApplication.md +34 -0
- package/dist/okf/types/IoTSiteWiseDataset.md +5 -2
- package/dist/okf/types/IoTSiteWiseTask.md +24 -0
- package/dist/okf/types/IpamExternalResourceVerificationToken.md +35 -0
- package/dist/okf/types/IpamInternetRegistryAssociation.md +32 -0
- package/dist/okf/types/Job.md +35 -0
- package/dist/okf/types/JobTemplate.md +26 -0
- package/dist/okf/types/KinesisChannel.md +31 -0
- package/dist/okf/types/KinesisStream.md +1 -0
- package/dist/okf/types/LambdaResourcePolicy.md +14 -0
- package/dist/okf/types/Lexicon.md +34 -0
- package/dist/okf/types/LicenseAssetGroup.md +23 -0
- package/dist/okf/types/LicenseConfiguration.md +33 -0
- package/dist/okf/types/LicenseServerEndpoint.md +32 -0
- package/dist/okf/types/LightsailKeyPair.md +29 -0
- package/dist/okf/types/LimitsProfile.md +27 -0
- package/dist/okf/types/LocationAzureBlob.md +2 -1
- package/dist/okf/types/LocationObjectStorage.md +1 -0
- package/dist/okf/types/LogAlarm.md +2 -0
- package/dist/okf/types/MGNConnector.md +23 -0
- package/dist/okf/types/MGNLaunchConfigurationTemplate.md +37 -0
- package/dist/okf/types/MLTransform.md +15 -15
- package/dist/okf/types/MWAAServerlessWorkflow.md +3 -0
- package/dist/okf/types/ManagedNotificationAccountContactAssociation.md +1 -0
- package/dist/okf/types/ManagedNotificationAdditionalChannelAssociation.md +1 -0
- package/dist/okf/types/MediaConvertJobTemplate.md +11 -13
- package/dist/okf/types/MediaConvertQueue.md +8 -10
- package/dist/okf/types/MediaInsightsPipelineConfiguration.md +28 -0
- package/dist/okf/types/MediaLiveInput.md +41 -18
- package/dist/okf/types/MediaPackageV2Channel.md +3 -0
- package/dist/okf/types/MediaPackageV2OriginEndpoint.md +1 -0
- package/dist/okf/types/MediaPipelineKinesisVideoStreamPool.md +28 -0
- package/dist/okf/types/MediaTailorFunction.md +27 -0
- package/dist/okf/types/MedicalVocabulary.md +21 -0
- package/dist/okf/types/Member.md +26 -0
- package/dist/okf/types/Memory.md +6 -0
- package/dist/okf/types/MemoryDBSnapshot.md +29 -0
- package/dist/okf/types/Metric.md +59 -0
- package/dist/okf/types/MetricAttribution.md +23 -0
- package/dist/okf/types/MicrosoftAD.md +11 -11
- package/dist/okf/types/MigrationProject.md +8 -1
- package/dist/okf/types/Monitor.md +26 -0
- package/dist/okf/types/NFSFileShare.md +44 -0
- package/dist/okf/types/NeptuneGraphGraph.md +1 -0
- package/dist/okf/types/NetworkConnector.md +4 -0
- package/dist/okf/types/NetworkFlowMonitorScope.md +23 -0
- package/dist/okf/types/NetworkMigrationDefinition.md +31 -0
- package/dist/okf/types/NetworkSecurityManagerDeployment.md +31 -0
- package/dist/okf/types/NetworkSecurityManagerPolicy.md +32 -0
- package/dist/okf/types/NetworkSecurityManagerScope.md +29 -0
- package/dist/okf/types/NotebookInstance.md +18 -18
- package/dist/okf/types/NotebookInstanceLifecycleConfig.md +6 -5
- package/dist/okf/types/NotifyConfiguration.md +35 -0
- package/dist/okf/types/OTelEnrichment.md +2 -0
- package/dist/okf/types/OnlineEvaluationConfig.md +0 -1
- package/dist/okf/types/OrganizationConfigRule.md +7 -7
- package/dist/okf/types/Outpost.md +32 -0
- package/dist/okf/types/ParallelData.md +40 -0
- package/dist/okf/types/Partition.md +5 -5
- package/dist/okf/types/PaymentConnector.md +4 -1
- package/dist/okf/types/Pentest.md +1 -0
- package/dist/okf/types/PerfReports.md +28 -0
- package/dist/okf/types/PermissionAssociation.md +30 -0
- package/dist/okf/types/PersonalizeDataset.md +1 -0
- package/dist/okf/types/PersonalizeDatasetGroup.md +1 -0
- package/dist/okf/types/PersonalizeSchema.md +1 -0
- package/dist/okf/types/Pipeline.md +25 -0
- package/dist/okf/types/PlaybackConfiguration.md +1 -0
- package/dist/okf/types/PolicyAssociation.md +1 -1
- package/dist/okf/types/PolicyGrant.md +2 -2
- package/dist/okf/types/PolicyPrincipalAttachment.md +2 -7
- package/dist/okf/types/PortalProduct.md +24 -0
- package/dist/okf/types/PrefetchSchedule.md +25 -0
- package/dist/okf/types/PricingPlanManagerSubscription.md +31 -0
- package/dist/okf/types/PrincipalAssociation.md +27 -0
- package/dist/okf/types/PrivateDnsNamespace.md +8 -8
- package/dist/okf/types/PrivateVirtualInterface.md +1 -0
- package/dist/okf/types/ProcurementPortalPreference.md +45 -0
- package/dist/okf/types/Program.md +33 -0
- package/dist/okf/types/ProjectMembership.md +1 -1
- package/dist/okf/types/ProtocolsList.md +26 -0
- package/dist/okf/types/PublicDnsNamespace.md +7 -7
- package/dist/okf/types/PublicVirtualInterface.md +1 -0
- package/dist/okf/types/QEV2IdcApplication.md +25 -0
- package/dist/okf/types/QueryLoggingConfig.md +21 -0
- package/dist/okf/types/QuerySuggestionsBlockList.md +25 -0
- package/dist/okf/types/QuickSightAssignment.md +24 -0
- package/dist/okf/types/RAMResourceAssociation.md +27 -0
- package/dist/okf/types/RDSClusterSnapshot.md +54 -0
- package/dist/okf/types/RDSDBParameterGroup.md +5 -0
- package/dist/okf/types/RDSDeployment.md +41 -0
- package/dist/okf/types/RcsAgent.md +38 -0
- package/dist/okf/types/ReceiptRule.md +5 -5
- package/dist/okf/types/ReceiptRuleSet.md +1 -6
- package/dist/okf/types/RecommenderFilter.md +27 -0
- package/dist/okf/types/RecommenderSchema.md +25 -0
- package/dist/okf/types/RecordSet.md +16 -22
- package/dist/okf/types/RecoveryPlan.md +28 -0
- package/dist/okf/types/RedshiftIdcApplication.md +31 -0
- package/dist/okf/types/RedshiftSnapshot.md +59 -0
- package/dist/okf/types/RegistrationAttachment.md +28 -0
- package/dist/okf/types/Registry.md +41 -0
- package/dist/okf/types/RegistryRecord.md +38 -0
- package/dist/okf/types/RelatedItem.md +24 -0
- package/dist/okf/types/ReplicationConfigurationTemplate.md +35 -0
- package/dist/okf/types/ReplicationSubnetGroup.md +4 -9
- package/dist/okf/types/ReplicationTask.md +14 -14
- package/dist/okf/types/ReportGenerator.md +29 -0
- package/dist/okf/types/ReportGroup.md +1 -3
- package/dist/okf/types/ResilienceHubV2Policy.md +1 -0
- package/dist/okf/types/ResilienceHubV2Service.md +1 -0
- package/dist/okf/types/ResourceConfiguration.md +1 -1
- package/dist/okf/types/ResourceMetricsConfiguration.md +21 -0
- package/dist/okf/types/RestApi.md +1 -0
- package/dist/okf/types/RetrievalInstruction.md +32 -0
- package/dist/okf/types/RouterOutput.md +1 -0
- package/dist/okf/types/Rule.md +31 -0
- package/dist/okf/types/RunCache.md +29 -0
- package/dist/okf/types/Runtime.md +2 -1
- package/dist/okf/types/SCNInstance.md +33 -0
- package/dist/okf/types/SDBDomain.md +2 -2
- package/dist/okf/types/SMBFileShare.md +49 -0
- package/dist/okf/types/SageMakerArtifact.md +27 -0
- package/dist/okf/types/SageMakerEndpoint.md +0 -1
- package/dist/okf/types/ScalableTarget.md +1 -0
- package/dist/okf/types/ScalingPlan.md +6 -6
- package/dist/okf/types/ScheduledReport.md +31 -0
- package/dist/okf/types/SecondaryNetwork.md +26 -0
- package/dist/okf/types/SecurityAgentArtifact.md +25 -0
- package/dist/okf/types/SecurityAgentIntegration.md +31 -0
- package/dist/okf/types/Server.md +1 -0
- package/dist/okf/types/ServerlessCache.md +2 -0
- package/dist/okf/types/ServerlessCacheSnapshot.md +31 -0
- package/dist/okf/types/ServerlessRepoApplication.md +32 -0
- package/dist/okf/types/ServiceDiscoveryInstance.md +3 -7
- package/dist/okf/types/SipMediaApplication.md +27 -0
- package/dist/okf/types/SiteToSiteVpnAttachment.md +2 -0
- package/dist/okf/types/SnapshotCopyGrant.md +20 -0
- package/dist/okf/types/Solution.md +1 -0
- package/dist/okf/types/SourceAssociation.md +25 -0
- package/dist/okf/types/SourceCredential.md +6 -6
- package/dist/okf/types/SourceNetwork.md +23 -0
- package/dist/okf/types/StackFleetAssociation.md +2 -7
- package/dist/okf/types/StorageTierPolicy.md +20 -0
- package/dist/okf/types/StorageVirtualMachine.md +9 -9
- package/dist/okf/types/Stream.md +28 -0
- package/dist/okf/types/SubnetCidrReservation.md +26 -0
- package/dist/okf/types/SubscriptionProvider.md +26 -0
- package/dist/okf/types/SupportPermit.md +29 -0
- package/dist/okf/types/Table.md +2 -1
- package/dist/okf/types/TableOptimizer.md +5 -10
- package/dist/okf/types/Tape.md +31 -0
- package/dist/okf/types/Template.md +36 -0
- package/dist/okf/types/Tenant.md +2 -0
- package/dist/okf/types/Terminology.md +39 -0
- package/dist/okf/types/Thesaurus.md +25 -0
- package/dist/okf/types/ThingPrincipalAttachment.md +3 -8
- package/dist/okf/types/Topic.md +1 -0
- package/dist/okf/types/TopicRuleDestination.md +1 -0
- package/dist/okf/types/TrafficPolicy.md +26 -0
- package/dist/okf/types/TrafficPolicyInstance.md +28 -0
- package/dist/okf/types/TranscribeVocabulary.md +27 -0
- package/dist/okf/types/TransitGatewayRouteTableAttachment.md +2 -0
- package/dist/okf/types/TransitVirtualInterface.md +1 -0
- package/dist/okf/types/Tunnel.md +25 -0
- package/dist/okf/types/UsageLimit.md +26 -0
- package/dist/okf/types/UseCase.md +23 -0
- package/dist/okf/types/User.md +47 -0
- package/dist/okf/types/VPCEndpoint.md +1 -1
- package/dist/okf/types/VPCEndpointService.md +6 -0
- package/dist/okf/types/VPCPeeringConnection.md +2 -2
- package/dist/okf/types/VPNConcentrator.md +1 -1
- package/dist/okf/types/VPNConnection.md +1 -1
- package/dist/okf/types/VerifiedDestinationNumber.md +25 -0
- package/dist/okf/types/View.md +27 -0
- package/dist/okf/types/VoiceConnector.md +30 -0
- package/dist/okf/types/Volume.md +44 -0
- package/dist/okf/types/Vpc.md +1 -1
- package/dist/okf/types/VpcAttachment.md +2 -0
- package/dist/okf/types/WebFunction.md +27 -0
- package/dist/okf/types/WebFunctionEndpoint.md +44 -0
- package/dist/okf/types/WebFunctionRevision.md +32 -0
- package/dist/okf/types/WickrNetwork.md +27 -0
- package/dist/okf/types/Worker.md +29 -0
- package/dist/okf/types/Workforce.md +26 -0
- package/dist/okf/types/Workload.md +35 -0
- package/dist/okf/types/WorkloadEstimate.md +35 -0
- package/dist/okf/types/Workspace.md +28 -0
- package/dist/okf/types/Workteam.md +8 -8
- package/dist/op/activities/aws-apply.js +214 -0
- package/dist/op/activities/floci.js +97 -0
- package/dist/op/activities/index.js +32 -0
- package/dist/op/builders.js +50 -0
- package/dist/ownership.js +52 -0
- package/dist/package-cli.js +25 -0
- package/dist/parameter.js +19 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +1006 -0
- package/dist/properties.js +166 -0
- package/dist/pseudo.js +25 -0
- package/dist/receipt-store.d.ts.map +1 -1
- package/dist/receipt-store.js +233 -0
- package/dist/reference-catalog.js +106 -0
- package/dist/rules/ext001.ts +3 -3
- package/dist/rules/waw016.ts +2 -2
- package/dist/serializer.js +529 -0
- package/dist/spec/fetch.js +193 -0
- package/dist/spec/parse.js +259 -0
- package/dist/spec/pin.js +185 -0
- package/dist/spec/pinned-types.json +203 -0
- package/dist/stack-errors.js +14 -0
- package/dist/taggable.d.ts.map +1 -1
- package/dist/taggable.js +33 -0
- package/dist/teardown.js +199 -0
- package/dist/template-sections.js +53 -0
- package/dist/template-transform.js +50 -0
- package/dist/types/index.d.ts +18847 -1124
- package/dist/validate-cli.js +16 -0
- package/dist/validate.js +33 -0
- package/package.json +9 -9
- package/src/agentcore/trace-fetch.ts +2 -1
- package/src/api/credential-chain.ts +119 -9
- package/src/api/credential-isolation.test.ts +72 -0
- package/src/api/read-client-chain.test.ts +159 -0
- package/src/api/read-client.ts +42 -6
- package/src/api/sigv4.ts +4 -4
- package/src/caller-identity.ts +3 -5
- package/src/codegen/any-budget.test.ts +12 -2
- package/src/codegen/generate.ts +9 -0
- package/src/codegen/package.ts +2 -2
- package/src/codegen/patches.test.ts +95 -0
- package/src/codegen/patches.ts +53 -9
- package/src/codegen/property-overlay.json +1 -16
- package/src/components/apply.ts +218 -6
- package/src/components/cfn-plan-floci.e2e.test.ts +76 -0
- package/src/components/cfn-plan.test.ts +225 -16
- package/src/components/cloud-executor.ts +73 -25
- package/src/deep-observe.ts +2 -1
- package/src/disruption.ts +2 -1
- package/src/generated/index.d.ts +18847 -1124
- package/src/generated/index.ts +1376 -161
- package/src/generated/lexicon-aws.json +17359 -784
- package/src/identity-observe.ts +2 -1
- package/src/lint/post-synth/ext001.ts +3 -3
- package/src/lint/post-synth/waw016.ts +2 -2
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
- package/src/plugin.ts +2 -1
- package/src/receipt-store.ts +2 -1
- package/src/spec/pin.ts +3 -3
- package/src/spec/pinned-types.json +203 -0
- package/src/taggable.ts +2 -2
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS deep observation (#1015) — the reference implementation of the epic's
|
|
3
|
+
* deep-observe contract (#1014).
|
|
4
|
+
*
|
|
5
|
+
* `describeResources` reads `cloudformation describe-stack-resources`, which
|
|
6
|
+
* returns a status, a physical id and a timestamp per resource. That is
|
|
7
|
+
* CloudFormation's view of the world, and CloudFormation only compares
|
|
8
|
+
* properties it was told about. A property somebody edited in the console — an
|
|
9
|
+
* inline policy, a bucket setting, a security-group rule — is invisible to it.
|
|
10
|
+
* That gap is why go-to-k/cdk-real-drift exists, and it is what this reader
|
|
11
|
+
* closes: the live resource model comes from the **Cloud Control API**, which
|
|
12
|
+
* bypasses CloudFormation entirely and returns the resource as the service
|
|
13
|
+
* actually holds it.
|
|
14
|
+
*
|
|
15
|
+
* Correlation is unchanged: Cloud Control is addressed by the physical id that
|
|
16
|
+
* `describe-stack-resources` already reports per logical id, so the results
|
|
17
|
+
* line up with the same IR node ids `live-attrs.ts` relies on.
|
|
18
|
+
*
|
|
19
|
+
* ## One reader, several sources (#1269)
|
|
20
|
+
*
|
|
21
|
+
* Cloud Control is the default source, not the only one. It has the property
|
|
22
|
+
* this reader wants most — it returns the *CloudFormation resource model*, so
|
|
23
|
+
* its payload lines up with the declared side without translation — but its
|
|
24
|
+
* coverage is not the same as the provider's. A security group read through
|
|
25
|
+
* Cloud Control comes back as identity and a description; read through
|
|
26
|
+
* `ec2 describe-security-groups` it comes back with every ingress and egress
|
|
27
|
+
* rule, which is the property people actually edit out of band.
|
|
28
|
+
*
|
|
29
|
+
* So each type names its source in {@link DEEP_SOURCES}, and a source that is
|
|
30
|
+
* not Cloud Control supplies a `toModel` that maps the provider's shape onto
|
|
31
|
+
* the CloudFormation one. Translation is the price of the richer read, and it
|
|
32
|
+
* belongs next to the type it translates rather than inside the diff.
|
|
33
|
+
*
|
|
34
|
+
* A declared resource of a type with no source reports NOT-OBSERVED with
|
|
35
|
+
* `unsupported-kind` — it may well exist, and saying nothing about it is the
|
|
36
|
+
* only honest answer.
|
|
37
|
+
*
|
|
38
|
+
* ## Nothing here talks to real AWS on its own terms
|
|
39
|
+
*
|
|
40
|
+
* Every call goes through `./api/read-client.ts` — the applier's own transport,
|
|
41
|
+
* pointed at the read APIs (#1206) — so `AWS_ENDPOINT_URL` redirects the whole
|
|
42
|
+
* reader at a local emulator, with no CLI to spawn and typed failures instead of
|
|
43
|
+
* parsed stderr.
|
|
44
|
+
*/
|
|
45
|
+
import { AwsReadError, describeStackResources, getResource, listResources, } from "./api/read-client.js";
|
|
46
|
+
import { declaredIdentifier } from "./identity-observe.js";
|
|
47
|
+
import { AWS_TAG_OWNERSHIP_KEYS } from "./ownership.js";
|
|
48
|
+
import { AWS_DEEP_BLIND_SPOTS, EC2_TOPOLOGY_GENERATED_NAMES, EC2_TOPOLOGY_SERVICE_DEFAULTS, EC2_TOPOLOGY_SOURCES, } from "./deep-topology.js";
|
|
49
|
+
import { applyAwsEndpointArgv } from "./components/cloud-executor.js";
|
|
50
|
+
import { toIngressRules } from "./dependencies.js";
|
|
51
|
+
import { createRequire } from "node:module";
|
|
52
|
+
import { moduleSourceUrl } from "@intentius/chant/module-source";
|
|
53
|
+
const require = createRequire(moduleSourceUrl(import.meta.url));
|
|
54
|
+
export const DEEP_SOURCES = {
|
|
55
|
+
"AWS::S3::Bucket": { via: "cloud-control" },
|
|
56
|
+
"AWS::IAM::Role": { via: "cloud-control" },
|
|
57
|
+
"AWS::IAM::ManagedPolicy": { via: "cloud-control" },
|
|
58
|
+
// Cloud Control returns a security group's identity and description and none
|
|
59
|
+
// of its rules (#1269). The EC2 API returns the whole thing, so the drift
|
|
60
|
+
// people care about — an ingress rule edited in the console — is legible.
|
|
61
|
+
"AWS::EC2::SecurityGroup": {
|
|
62
|
+
via: "ec2",
|
|
63
|
+
argv: ["ec2", "describe-security-groups"],
|
|
64
|
+
idFlag: "--group-ids",
|
|
65
|
+
key: "SecurityGroups",
|
|
66
|
+
id: "GroupId",
|
|
67
|
+
toModel: securityGroupToModel,
|
|
68
|
+
},
|
|
69
|
+
// The EC2 topology types the folds fold over (#1269), sources and
|
|
70
|
+
// translations alongside their type in ./deep-topology.ts.
|
|
71
|
+
...EC2_TOPOLOGY_SOURCES,
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Types this reader can read live. Derived from {@link DEEP_SOURCES} so the two
|
|
75
|
+
* cannot drift apart — the shape of bug #1280 is about.
|
|
76
|
+
*/
|
|
77
|
+
export const DEEP_READABLE_TYPES = new Set(Object.keys(DEEP_SOURCES));
|
|
78
|
+
/**
|
|
79
|
+
* Parent type → the child types worth listing under it. Scoped like
|
|
80
|
+
* {@link DEEP_SOURCES}: the high-signal cases first — the issue's own
|
|
81
|
+
* examples — and widened per type, not by wildcard. A child type Cloud
|
|
82
|
+
* Control cannot list parent-scoped does not belong here.
|
|
83
|
+
*/
|
|
84
|
+
export const DEEP_CHILD_SOURCES = {
|
|
85
|
+
"AWS::IAM::Role": [
|
|
86
|
+
{
|
|
87
|
+
childType: "AWS::IAM::RolePolicy",
|
|
88
|
+
model: (roleName) => ({ RoleName: roleName }),
|
|
89
|
+
// A RolePolicy identifier is `PolicyName|RoleName` — the schema's own
|
|
90
|
+
// primaryIdentifier order, which is what the manifest records and what
|
|
91
|
+
// `declaredIdentifier` joins by. The legacy type's physical id is the
|
|
92
|
+
// policy name, the first part.
|
|
93
|
+
declaredVia: [{ type: "AWS::IAM::Policy", part: (id) => id.split("|")[0] }],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
"AWS::SNS::Topic": [
|
|
97
|
+
{
|
|
98
|
+
childType: "AWS::SNS::Subscription",
|
|
99
|
+
model: (topicArn) => ({ TopicArn: topicArn }),
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* The name an out-of-band child reports under. There is no chant entity name
|
|
105
|
+
* to use — nobody declared it — so the name has to carry the finding on its
|
|
106
|
+
* own: what kind of thing, and which one.
|
|
107
|
+
*/
|
|
108
|
+
export function outOfBandChildName(childType, identifier) {
|
|
109
|
+
return `${childType}:${identifier}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `describe-security-groups` -> the `AWS::EC2::SecurityGroup` resource model.
|
|
113
|
+
*
|
|
114
|
+
* The two surfaces disagree about names and about nesting. EC2 says
|
|
115
|
+
* `Description` where the template says `GroupDescription`, and nests rule
|
|
116
|
+
* sources under `IpRanges[]` / `Ipv6Ranges[]` / `UserIdGroupPairs[]` where the
|
|
117
|
+
* template writes one flat rule per source. `toIngressRules` already resolves
|
|
118
|
+
* the nesting for the topology fold (#1273); this reuses it so there is one
|
|
119
|
+
* translation of that shape in the lexicon, not two.
|
|
120
|
+
*
|
|
121
|
+
* Rules are matched by their whole canonical value (the `orderKey` hook below),
|
|
122
|
+
* so a field the template carries and this mapping drops is not a smaller diff —
|
|
123
|
+
* it is every rule reported twice, once absent and once undeclared. That is why
|
|
124
|
+
* a range's own `Description` is carried through.
|
|
125
|
+
*/
|
|
126
|
+
export function securityGroupToModel(row) {
|
|
127
|
+
const ingress = toIngressRules((row.IpPermissions ?? []));
|
|
128
|
+
const egress = toIngressRules((row.IpPermissionsEgress ?? []));
|
|
129
|
+
return {
|
|
130
|
+
...(typeof row.Description === "string" ? { GroupDescription: row.Description } : {}),
|
|
131
|
+
...(typeof row.GroupName === "string" ? { GroupName: row.GroupName } : {}),
|
|
132
|
+
...(typeof row.VpcId === "string" ? { VpcId: row.VpcId } : {}),
|
|
133
|
+
...(typeof row.GroupId === "string" ? { GroupId: row.GroupId } : {}),
|
|
134
|
+
// An empty tag set is the absence of tags, not a value. EC2 always sends
|
|
135
|
+
// the key, so carrying it through reports `Tags: <undeclared> -> []` on
|
|
136
|
+
// every untagged group — agreement rendered as drift.
|
|
137
|
+
...(Array.isArray(row.Tags) && row.Tags.length > 0 ? { Tags: row.Tags } : {}),
|
|
138
|
+
...(ingress.length > 0 ? { SecurityGroupIngress: ingress } : {}),
|
|
139
|
+
...(egress.length > 0 ? { SecurityGroupEgress: egress } : {}),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Property names that are server-populated wherever they appear — identifiers
|
|
144
|
+
* the service mints, timestamps it stamps, counters it maintains. Matched on
|
|
145
|
+
* the final path segment, because AWS repeats these names at every nesting
|
|
146
|
+
* depth and a per-type list of full paths would be a maintenance trap.
|
|
147
|
+
*
|
|
148
|
+
* Deliberately excludes ambiguous names like `Id` and `Name`: `VpcId` and
|
|
149
|
+
* `BucketName` are declared inputs, and pruning a declared input is how a
|
|
150
|
+
* normalization pass starts hiding real drift.
|
|
151
|
+
*/
|
|
152
|
+
export const AWS_READ_ONLY_NAMES = new Set([
|
|
153
|
+
"Arn",
|
|
154
|
+
"RoleId",
|
|
155
|
+
"PolicyId",
|
|
156
|
+
"GroupId",
|
|
157
|
+
"OwnerId",
|
|
158
|
+
"AttachmentCount",
|
|
159
|
+
"PermissionsBoundaryUsageCount",
|
|
160
|
+
"DefaultVersionId",
|
|
161
|
+
"IsAttachable",
|
|
162
|
+
"CreateDate",
|
|
163
|
+
"CreationDate",
|
|
164
|
+
"UpdateDate",
|
|
165
|
+
"LastModified",
|
|
166
|
+
"LastModifiedTime",
|
|
167
|
+
"DualStackDomainName",
|
|
168
|
+
"RegionalDomainName",
|
|
169
|
+
"WebsiteURL",
|
|
170
|
+
]);
|
|
171
|
+
/**
|
|
172
|
+
* Service defaults, per type, as index-erased property paths. A live value
|
|
173
|
+
* equal to its default is subtracted **only when source never declared that
|
|
174
|
+
* property** — cdk-real-drift's default subtraction, and the reason
|
|
175
|
+
* {@link DeepNode.counterpart} exists. Declaring the default explicitly keeps
|
|
176
|
+
* the property in the diff, so a later change to it still reports.
|
|
177
|
+
*/
|
|
178
|
+
export const AWS_SERVICE_DEFAULTS = {
|
|
179
|
+
"AWS::S3::Bucket": {
|
|
180
|
+
"VersioningConfiguration.Status": "Suspended",
|
|
181
|
+
"AccelerateConfiguration.AccelerationStatus": "Suspended",
|
|
182
|
+
"ObjectLockEnabled": false,
|
|
183
|
+
},
|
|
184
|
+
"AWS::IAM::Role": {
|
|
185
|
+
"Path": "/",
|
|
186
|
+
"MaxSessionDuration": 3600,
|
|
187
|
+
},
|
|
188
|
+
"AWS::IAM::ManagedPolicy": {
|
|
189
|
+
"Path": "/",
|
|
190
|
+
},
|
|
191
|
+
"AWS::EC2::SecurityGroup": {
|
|
192
|
+
"GroupDescription": "default VPC security group",
|
|
193
|
+
// EC2 gives every group an allow-all egress rule when the template declares
|
|
194
|
+
// none (#1269). Patterns are index-erased, so these two match the default
|
|
195
|
+
// rule wherever it lands in the set — and only while source declares no
|
|
196
|
+
// egress at all, which is what `counterpart: "absent"` checks.
|
|
197
|
+
"SecurityGroupEgress[].CidrIp": "0.0.0.0/0",
|
|
198
|
+
"SecurityGroupEgress[].IpProtocol": "-1",
|
|
199
|
+
},
|
|
200
|
+
...EC2_TOPOLOGY_SERVICE_DEFAULTS,
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Names the service mints when a template does not supply one (#1269).
|
|
204
|
+
*
|
|
205
|
+
* Unlike {@link AWS_SERVICE_DEFAULTS} there is no fixed value to compare: a
|
|
206
|
+
* CloudFormation-generated security-group name is a different random string on
|
|
207
|
+
* every deploy. Pruned on the live side only, and only where source is silent —
|
|
208
|
+
* a template that names the group keeps the property in the diff, so a later
|
|
209
|
+
* rename still reports.
|
|
210
|
+
*/
|
|
211
|
+
export const AWS_GENERATED_NAMES = {
|
|
212
|
+
"AWS::EC2::SecurityGroup": new Set(["GroupName"]),
|
|
213
|
+
...EC2_TOPOLOGY_GENERATED_NAMES,
|
|
214
|
+
};
|
|
215
|
+
/** Stable JSON with sorted keys — the fallback ordering key for a set-like array. */
|
|
216
|
+
function canonicalJson(value) {
|
|
217
|
+
return JSON.stringify(value, (_k, v) => v && typeof v === "object" && !Array.isArray(v)
|
|
218
|
+
? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)))
|
|
219
|
+
: v) ?? "";
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The read-only properties of one type, as index-erased patterns, straight from
|
|
223
|
+
* the CloudFormation schema's `readOnlyProperties` (#1641).
|
|
224
|
+
*
|
|
225
|
+
* The codegen already turns that list into each class's GetAtt attributes
|
|
226
|
+
* (`attrs` in `lexicon-aws.json`), so this reads the same registry from the
|
|
227
|
+
* other side: a path the schema says only the service can write is an
|
|
228
|
+
* attribute, and an attribute the live read reports is not property drift. No
|
|
229
|
+
* declaration can contain one, so `<undeclared> -> value` is the shape every
|
|
230
|
+
* clean apply would otherwise produce. `AWS::IAM::ManagedPolicy.PolicyArn`,
|
|
231
|
+
* which is also the type's Cloud Control primary identifier, is the case that
|
|
232
|
+
* surfaced it.
|
|
233
|
+
*
|
|
234
|
+
* The manifest spells an array element `Subscribers.*.Status`; the
|
|
235
|
+
* normalization pass spells the same thing `Subscribers[].Status`.
|
|
236
|
+
*
|
|
237
|
+
* Complements {@link AWS_READ_ONLY_NAMES} rather than replacing it: the
|
|
238
|
+
* name-based list also covers translated models (an EC2 row mapped onto the
|
|
239
|
+
* CloudFormation shape) and nested documents the schema never enumerates.
|
|
240
|
+
*/
|
|
241
|
+
export function schemaReadOnlyPatterns(entityType) {
|
|
242
|
+
const cached = readOnlyByType.get(entityType);
|
|
243
|
+
if (cached)
|
|
244
|
+
return cached;
|
|
245
|
+
const entry = manifestByType().get(entityType);
|
|
246
|
+
const patterns = new Set();
|
|
247
|
+
for (const attr of Object.values(entry?.attrs ?? {})) {
|
|
248
|
+
patterns.add(attr.replace(/\.\*(?=\.|$)/g, "[]"));
|
|
249
|
+
}
|
|
250
|
+
readOnlyByType.set(entityType, patterns);
|
|
251
|
+
return patterns;
|
|
252
|
+
}
|
|
253
|
+
const readOnlyByType = new Map();
|
|
254
|
+
let manifestIndex;
|
|
255
|
+
function manifestByType() {
|
|
256
|
+
if (!manifestIndex) {
|
|
257
|
+
const manifest = require("./generated/lexicon-aws.json");
|
|
258
|
+
manifestIndex = new Map(Object.values(manifest)
|
|
259
|
+
.filter((e) => e.kind === "resource")
|
|
260
|
+
.map((e) => [e.resourceType, e]));
|
|
261
|
+
}
|
|
262
|
+
return manifestIndex;
|
|
263
|
+
}
|
|
264
|
+
/** The final segment of an index-erased pattern (`Policies[].PolicyName` → `PolicyName`). */
|
|
265
|
+
function lastSegment(pattern) {
|
|
266
|
+
const withoutIndex = pattern.replace(/\[\]$/, "");
|
|
267
|
+
const dot = withoutIndex.lastIndexOf(".");
|
|
268
|
+
return dot === -1 ? withoutIndex : withoutIndex.slice(dot + 1);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The aws lexicon's noise rules. The three classes the epic names for AWS —
|
|
272
|
+
* server-populated fields, unstable ordering (tags, policy statements), and
|
|
273
|
+
* provider defaults — plus nothing else: a rule that is not one of those is a
|
|
274
|
+
* rule that hides drift.
|
|
275
|
+
*/
|
|
276
|
+
export const awsDeepNormalizationHooks = {
|
|
277
|
+
prune(node) {
|
|
278
|
+
// Read-only / server-populated. Pruned on both sides: if source somehow
|
|
279
|
+
// declares an arn-shaped output, comparing it to the live one is still
|
|
280
|
+
// meaningless. The schema's own `readOnlyProperties` first (#1641), then
|
|
281
|
+
// the name-based list for what the schema does not enumerate.
|
|
282
|
+
if (schemaReadOnlyPatterns(node.entityType).has(node.pattern))
|
|
283
|
+
return true;
|
|
284
|
+
if (AWS_READ_ONLY_NAMES.has(lastSegment(node.pattern)))
|
|
285
|
+
return true;
|
|
286
|
+
// A declared property this type's source cannot see (#1269). With nothing
|
|
287
|
+
// live to stand against it would report `value -> <absent>` on every clean
|
|
288
|
+
// apply — a blind spot rendered as drift. Counterpart-gated the other way
|
|
289
|
+
// round: a live tree that does carry the field is still compared.
|
|
290
|
+
if (node.side === "declared" &&
|
|
291
|
+
node.counterpart === "absent" &&
|
|
292
|
+
AWS_DEEP_BLIND_SPOTS[node.entityType]?.has(node.pattern)) {
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
// Provider defaults, on the live side only, and only where source is silent
|
|
296
|
+
// about the property. `"unknown"` (a one-sided normalization) never prunes:
|
|
297
|
+
// the reader must not decide this before the declared tree is in hand.
|
|
298
|
+
if (node.side !== "live" || node.counterpart !== "absent")
|
|
299
|
+
return false;
|
|
300
|
+
// chant's own ownership marker. The serializer stamps it onto the template,
|
|
301
|
+
// so it is live on every managed resource and absent from the declared
|
|
302
|
+
// *properties* the diff compares — chant reading its own signature back as
|
|
303
|
+
// drift. Counterpart-gated, so a template that declares the tag itself is
|
|
304
|
+
// still compared against what is live.
|
|
305
|
+
if (isOwnershipTag(node.value))
|
|
306
|
+
return true;
|
|
307
|
+
// A name the service generated because source did not supply one.
|
|
308
|
+
if (AWS_GENERATED_NAMES[node.entityType]?.has(node.pattern))
|
|
309
|
+
return true;
|
|
310
|
+
const defaults = AWS_SERVICE_DEFAULTS[node.entityType];
|
|
311
|
+
if (!defaults)
|
|
312
|
+
return false;
|
|
313
|
+
if (!Object.prototype.hasOwnProperty.call(defaults, node.pattern))
|
|
314
|
+
return false;
|
|
315
|
+
return defaults[node.pattern] === node.value;
|
|
316
|
+
},
|
|
317
|
+
/**
|
|
318
|
+
* The key doubles as a path segment (`Tags[#env].Value`), so it is the
|
|
319
|
+
* element's own identity where AWS gives one — a tag key, a statement Sid, an
|
|
320
|
+
* action string — and canonical JSON only as a fallback.
|
|
321
|
+
*/
|
|
322
|
+
orderKey(element) {
|
|
323
|
+
const name = lastSegment(element.pattern);
|
|
324
|
+
const el = element.element;
|
|
325
|
+
// Tags are a set. AWS returns them in whatever order it likes, and a
|
|
326
|
+
// reordered tag list is the single loudest false positive in a raw diff.
|
|
327
|
+
if (name === "Tags") {
|
|
328
|
+
const key = isRecord(el) ? el.Key : undefined;
|
|
329
|
+
return typeof key === "string" ? key : canonicalJson(el);
|
|
330
|
+
}
|
|
331
|
+
// IAM policy statements are a set, and so are the Action/Resource lists
|
|
332
|
+
// inside them. `Sid` is the natural identity when the author gave one.
|
|
333
|
+
if (name === "Statement") {
|
|
334
|
+
const sid = isRecord(el) ? el.Sid : undefined;
|
|
335
|
+
return typeof sid === "string" ? sid : canonicalJson(el);
|
|
336
|
+
}
|
|
337
|
+
if (name === "Action" || name === "NotAction" || name === "Resource" || name === "NotResource") {
|
|
338
|
+
return typeof el === "string" ? el : canonicalJson(el);
|
|
339
|
+
}
|
|
340
|
+
// Security-group rules are a set — the console appends, chant declares in
|
|
341
|
+
// source order, and neither order means anything to EC2.
|
|
342
|
+
if (name === "SecurityGroupIngress" || name === "SecurityGroupEgress") {
|
|
343
|
+
return securityGroupRuleKey(el) ?? canonicalJson(el);
|
|
344
|
+
}
|
|
345
|
+
if (name === "IpRanges") {
|
|
346
|
+
return canonicalJson(el);
|
|
347
|
+
}
|
|
348
|
+
return undefined;
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
function isRecord(value) {
|
|
352
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Classify a failed read the same way the thin path does — off the API's own
|
|
356
|
+
* error code where there is one (#1206), falling back to the message for a
|
|
357
|
+
* transport-level failure that never reached the service.
|
|
358
|
+
*/
|
|
359
|
+
function classifyFailure(err) {
|
|
360
|
+
const code = err instanceof AwsReadError ? err.code ?? "" : "";
|
|
361
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
362
|
+
return /credential|token|expired|AccessDenied|NotAuthorized|Unauthorized/i.test(`${code} ${message}`)
|
|
363
|
+
? "no-credentials"
|
|
364
|
+
: "read-failed";
|
|
365
|
+
}
|
|
366
|
+
/** The message a failed read reports, without a stack trace or a stderr tail. */
|
|
367
|
+
function failureDetail(err) {
|
|
368
|
+
if (err instanceof AwsReadError)
|
|
369
|
+
return err.code ? `${err.code}: ${err.message}` : err.message;
|
|
370
|
+
return err instanceof Error ? err.message : String(err);
|
|
371
|
+
}
|
|
372
|
+
/** True when a CloudFormation read failed only because the stack isn't there yet. */
|
|
373
|
+
function isStackMissing(err) {
|
|
374
|
+
return err instanceof AwsReadError && /does not exist/i.test(err.message);
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* What identifies a security-group rule, as a path segment.
|
|
378
|
+
*
|
|
379
|
+
* `canonicalJson` of a rule runs past the length a path segment may carry
|
|
380
|
+
* (`MAX_KEYED_SEGMENT`, 60), so keying by it makes the flattener give up and
|
|
381
|
+
* compare the set positionally. A rule added at the top then shifts every rule
|
|
382
|
+
* below it, and one added rule reports as "the first rule changed, and a new
|
|
383
|
+
* one appeared at the end" — detection is right, attribution is not.
|
|
384
|
+
*
|
|
385
|
+
* Identity is protocol, port range and source, which is what EC2 itself
|
|
386
|
+
* enforces uniqueness on. `Description` is deliberately excluded: editing a
|
|
387
|
+
* rule's description is a change *to that rule*, not the removal of one rule
|
|
388
|
+
* and the addition of another.
|
|
389
|
+
*/
|
|
390
|
+
function securityGroupRuleKey(element) {
|
|
391
|
+
if (!isRecord(element))
|
|
392
|
+
return undefined;
|
|
393
|
+
const source = typeof element.CidrIp === "string"
|
|
394
|
+
? element.CidrIp
|
|
395
|
+
: typeof element.CidrIpv6 === "string"
|
|
396
|
+
? element.CidrIpv6
|
|
397
|
+
: typeof element.SourceSecurityGroupId === "string"
|
|
398
|
+
? element.SourceSecurityGroupId
|
|
399
|
+
: undefined;
|
|
400
|
+
// No recognisable source is not a rule this can identify; the caller falls
|
|
401
|
+
// back rather than keying every such rule to the same segment.
|
|
402
|
+
if (source === undefined)
|
|
403
|
+
return undefined;
|
|
404
|
+
const protocol = typeof element.IpProtocol === "string" ? element.IpProtocol : "-1";
|
|
405
|
+
const from = element.FromPort ?? "*";
|
|
406
|
+
const to = element.ToPort ?? "*";
|
|
407
|
+
return `${protocol}:${String(from)}:${String(to)}:${source}`;
|
|
408
|
+
}
|
|
409
|
+
/** Every tag key the serializer stamps as chant's ownership marker. */
|
|
410
|
+
const OWNERSHIP_TAG_KEYS = new Set(Object.values(AWS_TAG_OWNERSHIP_KEYS));
|
|
411
|
+
/** True when `value` is a `{Key, Value}` tag whose key is one chant stamps itself. */
|
|
412
|
+
function isOwnershipTag(value) {
|
|
413
|
+
return isRecord(value) && typeof value.Key === "string" && OWNERSHIP_TAG_KEYS.has(value.Key);
|
|
414
|
+
}
|
|
415
|
+
/** True when the live property tree carries chant's ownership marker tag. */
|
|
416
|
+
export function hasOwnershipMarker(properties) {
|
|
417
|
+
const tags = properties.Tags;
|
|
418
|
+
if (!Array.isArray(tags))
|
|
419
|
+
return false;
|
|
420
|
+
return tags.some((t) => isRecord(t) && t.Key === AWS_TAG_OWNERSHIP_KEYS.managedBy);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Read the live property tree for each declared entity via Cloud Control.
|
|
424
|
+
*
|
|
425
|
+
* Two reads per run plus one per readable resource: `DescribeStackResources`
|
|
426
|
+
* resolves logical id → (type, physical id), then `GetResource` fetches each
|
|
427
|
+
* model. The first read's failure modes are the thin path's, verbatim — a stack
|
|
428
|
+
* that does not exist yet is a real absence (nothing is deployed, so there are
|
|
429
|
+
* no properties to drift), anything else is a hole for every declared entity.
|
|
430
|
+
*
|
|
431
|
+
* The per-resource reads run concurrently (#1201/#1206). They were serial when
|
|
432
|
+
* each one was a process spawn, which made a deep snapshot of a large stack
|
|
433
|
+
* cost N round trips end to end.
|
|
434
|
+
*/
|
|
435
|
+
export async function observeResourcesDeepAws(options) {
|
|
436
|
+
const { deepObservation, normalizeDeepProperties } = await import("@intentius/chant/deep-observation");
|
|
437
|
+
const { unobservedAll, boundedConcurrently } = await import("@intentius/chant/observation");
|
|
438
|
+
const stackName = options.stack ?? options.environment;
|
|
439
|
+
const client = {
|
|
440
|
+
...(options.region ? { region: options.region } : {}),
|
|
441
|
+
...(options.http ? { http: options.http } : {}),
|
|
442
|
+
};
|
|
443
|
+
let stackResources;
|
|
444
|
+
try {
|
|
445
|
+
stackResources = await describeStackResources(stackName, client);
|
|
446
|
+
}
|
|
447
|
+
catch (err) {
|
|
448
|
+
if (isStackMissing(err))
|
|
449
|
+
return deepObservation({});
|
|
450
|
+
return deepObservation({}, unobservedAll(options.entityNames, classifyFailure(err), `DescribeStackResources failed for stack "${stackName}": ${failureDetail(err)}`));
|
|
451
|
+
}
|
|
452
|
+
const byLogicalId = new Map(stackResources.map((r) => [r.logicalId, r]));
|
|
453
|
+
const resources = {};
|
|
454
|
+
const unobserved = {};
|
|
455
|
+
// Types with a bulk source are read once for the whole stack, before the
|
|
456
|
+
// per-entity pass — one `describe-security-groups` for every group, not one
|
|
457
|
+
// call per group.
|
|
458
|
+
const bulk = await readBulkSources(options.entityNames.flatMap((name) => {
|
|
459
|
+
const r = byLogicalId.get(name);
|
|
460
|
+
return r?.physicalId ? [{ type: r.type, id: r.physicalId }] : [];
|
|
461
|
+
}), options.region);
|
|
462
|
+
await boundedConcurrently(options.entityNames, async (entityName) => {
|
|
463
|
+
const stackResource = byLogicalId.get(entityName);
|
|
464
|
+
// Not in the stack at all. The thin read reports that absence; restating it
|
|
465
|
+
// here as a property hole would turn one finding into two.
|
|
466
|
+
if (!stackResource)
|
|
467
|
+
return;
|
|
468
|
+
const type = stackResource.type;
|
|
469
|
+
const source = DEEP_SOURCES[type];
|
|
470
|
+
if (!source) {
|
|
471
|
+
unobserved[entityName] = {
|
|
472
|
+
type,
|
|
473
|
+
reason: "unsupported-kind",
|
|
474
|
+
detail: `no deep reader for ${type} — coverage is opt-in per type`,
|
|
475
|
+
};
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
const identifier = stackResource.physicalId;
|
|
479
|
+
if (!identifier) {
|
|
480
|
+
unobserved[entityName] = {
|
|
481
|
+
type,
|
|
482
|
+
reason: "read-failed",
|
|
483
|
+
detail: "the stack reports no physical id, so the live resource cannot be addressed",
|
|
484
|
+
};
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
let properties;
|
|
488
|
+
if (source.via === "ec2") {
|
|
489
|
+
const answer = bulk.get(type);
|
|
490
|
+
if (!answer) {
|
|
491
|
+
unobserved[entityName] = {
|
|
492
|
+
type,
|
|
493
|
+
reason: "read-failed",
|
|
494
|
+
detail: `${source.argv.join(" ")} failed, so ${type} could not be read deeply`,
|
|
495
|
+
};
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const row = answer.get(identifier);
|
|
499
|
+
// The describe answered, and this id was not in it. That is absence, and
|
|
500
|
+
// the thin read already reports it — same reasoning as a resource missing
|
|
501
|
+
// from the stack.
|
|
502
|
+
if (!row)
|
|
503
|
+
return;
|
|
504
|
+
properties = source.toModel(row);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
let parsed;
|
|
508
|
+
try {
|
|
509
|
+
parsed = await getResource(type, identifier, client);
|
|
510
|
+
}
|
|
511
|
+
catch (err) {
|
|
512
|
+
unobserved[entityName] = {
|
|
513
|
+
type,
|
|
514
|
+
reason: classifyFailure(err),
|
|
515
|
+
detail: `GetResource failed for ${type} "${identifier}": ${failureDetail(err)}`,
|
|
516
|
+
};
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (!parsed) {
|
|
520
|
+
unobserved[entityName] = {
|
|
521
|
+
type,
|
|
522
|
+
reason: "read-failed",
|
|
523
|
+
detail: `unparseable GetResource response for ${type} "${identifier}"`,
|
|
524
|
+
};
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
properties = parsed.properties;
|
|
528
|
+
}
|
|
529
|
+
// Both sources return tags where the service carries them, so unlike the
|
|
530
|
+
// thin path this one can answer the ownership question (#1015's open note).
|
|
531
|
+
// A resource withheld by the filter is `filtered`, never absent: it exists,
|
|
532
|
+
// it just isn't chant's.
|
|
533
|
+
const owned = hasOwnershipMarker(properties);
|
|
534
|
+
if (options.owned && !owned) {
|
|
535
|
+
unobserved[entityName] = {
|
|
536
|
+
type,
|
|
537
|
+
reason: "filtered",
|
|
538
|
+
detail: `live resource carries no ${AWS_TAG_OWNERSHIP_KEYS.managedBy} tag`,
|
|
539
|
+
};
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
resources[entityName] = {
|
|
543
|
+
type,
|
|
544
|
+
physicalId: identifier,
|
|
545
|
+
properties: normalizeDeepProperties(properties, {
|
|
546
|
+
entityType: type,
|
|
547
|
+
side: "live",
|
|
548
|
+
hooks: awsDeepNormalizationHooks,
|
|
549
|
+
}),
|
|
550
|
+
};
|
|
551
|
+
});
|
|
552
|
+
// The out-of-band pass (#1015): under each declared parent whose type names
|
|
553
|
+
// child sources, list what actually exists and keep what nothing declared.
|
|
554
|
+
// A parent `--owned` withheld keeps its children out too — reporting a
|
|
555
|
+
// foreign resource's children while withholding the resource itself would
|
|
556
|
+
// be the filter half-applied. A parent with no deep reader of its own
|
|
557
|
+
// (`unsupported-kind`) still gets its children enumerated: listing under it
|
|
558
|
+
// needs only the physical id the stack already resolved.
|
|
559
|
+
const parents = [];
|
|
560
|
+
for (const entityName of options.entityNames) {
|
|
561
|
+
const resource = byLogicalId.get(entityName);
|
|
562
|
+
const sources = resource ? DEEP_CHILD_SOURCES[resource.type] : undefined;
|
|
563
|
+
if (!resource?.physicalId || !sources)
|
|
564
|
+
continue;
|
|
565
|
+
if (unobserved[entityName]?.reason === "filtered")
|
|
566
|
+
continue;
|
|
567
|
+
parents.push({ resource, sources });
|
|
568
|
+
}
|
|
569
|
+
const children = await enumerateOutOfBandChildren({
|
|
570
|
+
parents,
|
|
571
|
+
allStackResources: stackResources,
|
|
572
|
+
entities: options.entities,
|
|
573
|
+
client,
|
|
574
|
+
normalize: (childType, properties) => normalizeDeepProperties(properties, {
|
|
575
|
+
entityType: childType,
|
|
576
|
+
side: "live",
|
|
577
|
+
hooks: awsDeepNormalizationHooks,
|
|
578
|
+
}),
|
|
579
|
+
concurrently: boundedConcurrently,
|
|
580
|
+
});
|
|
581
|
+
for (const [name, child] of Object.entries(children)) {
|
|
582
|
+
if (!resources[name])
|
|
583
|
+
resources[name] = child;
|
|
584
|
+
}
|
|
585
|
+
return deepObservation(resources, unobserved);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* List every child-sourced type under its declared parents and return the
|
|
589
|
+
* resources nothing declared, named by {@link outOfBandChildName}.
|
|
590
|
+
*
|
|
591
|
+
* "Declared" is answered three ways, in order of how directly the stack says
|
|
592
|
+
* it: the child identifier is some stack resource's physical id (the normal
|
|
593
|
+
* case — a declared `AWS::SNS::Subscription` deploys under its ARN); a
|
|
594
|
+
* `declaredVia` legacy form's physical id is the identifier's relevant part;
|
|
595
|
+
* or a declared entity's props spell the identifier (`declaredIdentifier`,
|
|
596
|
+
* the carve case — declared in source, not yet in any stack).
|
|
597
|
+
*
|
|
598
|
+
* A listing that fails is silence about that parent's children, never a
|
|
599
|
+
* finding and never a hole: there is no declared entity to hang a hole on,
|
|
600
|
+
* and fabricating one would put an undeclared name in the unobserved report.
|
|
601
|
+
* `UnsupportedOperation` — an emulator without parent-scoped listing — lands
|
|
602
|
+
* here too, which is what keeps the Floci lanes quiet.
|
|
603
|
+
*/
|
|
604
|
+
async function enumerateOutOfBandChildren(args) {
|
|
605
|
+
const out = {};
|
|
606
|
+
if (args.parents.length === 0)
|
|
607
|
+
return out;
|
|
608
|
+
// Physical ids by type, over the WHOLE stack — a stack resource that is not
|
|
609
|
+
// a declared chant entity (a nested stack's row, a resource another tool
|
|
610
|
+
// added to the same stack) is still stack-managed, not out-of-band.
|
|
611
|
+
const addTo = (map, key, value) => {
|
|
612
|
+
const set = map.get(key) ?? new Set();
|
|
613
|
+
set.add(value);
|
|
614
|
+
map.set(key, set);
|
|
615
|
+
};
|
|
616
|
+
const stackIdsByType = new Map();
|
|
617
|
+
for (const r of args.allStackResources) {
|
|
618
|
+
if (r.physicalId)
|
|
619
|
+
addTo(stackIdsByType, r.type, r.physicalId);
|
|
620
|
+
}
|
|
621
|
+
const declaredIdsByType = new Map();
|
|
622
|
+
for (const entity of args.entities?.values() ?? []) {
|
|
623
|
+
const id = declaredIdentifier(entity.entityType, entity.props ?? {});
|
|
624
|
+
if (id)
|
|
625
|
+
addTo(declaredIdsByType, entity.entityType, id);
|
|
626
|
+
}
|
|
627
|
+
const isDeclared = (source, identifier) => {
|
|
628
|
+
if (stackIdsByType.get(source.childType)?.has(identifier))
|
|
629
|
+
return true;
|
|
630
|
+
if (declaredIdsByType.get(source.childType)?.has(identifier))
|
|
631
|
+
return true;
|
|
632
|
+
for (const via of source.declaredVia ?? []) {
|
|
633
|
+
const part = via.part(identifier);
|
|
634
|
+
if (part && stackIdsByType.get(via.type)?.has(part))
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
return false;
|
|
638
|
+
};
|
|
639
|
+
const listings = args.parents.flatMap(({ resource, sources }) => sources.map((source) => ({ physicalId: resource.physicalId, source })));
|
|
640
|
+
await args.concurrently(listings, async ({ physicalId, source }) => {
|
|
641
|
+
let listed;
|
|
642
|
+
try {
|
|
643
|
+
listed = await listResources(source.childType, args.client, source.model(physicalId));
|
|
644
|
+
}
|
|
645
|
+
catch {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
for (const child of listed) {
|
|
649
|
+
if (!child.identifier || isDeclared(source, child.identifier))
|
|
650
|
+
continue;
|
|
651
|
+
out[outOfBandChildName(source.childType, child.identifier)] = {
|
|
652
|
+
type: source.childType,
|
|
653
|
+
physicalId: child.identifier,
|
|
654
|
+
properties: args.normalize(source.childType, child.properties),
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
return out;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Read every `ec2`-sourced type in bulk, keyed by physical id.
|
|
662
|
+
*
|
|
663
|
+
* A type whose describe fails is absent from the returned map, which the caller
|
|
664
|
+
* turns into a hole for each of its resources — never into an absence, because
|
|
665
|
+
* a failed read establishes nothing about what exists.
|
|
666
|
+
*
|
|
667
|
+
* These reads still shell the CLI, unlike the Cloud Control path (#1206). The
|
|
668
|
+
* EC2 API speaks the Query protocol with its own lowerCamelCase XML, so going
|
|
669
|
+
* native here is a second wire format rather than a reuse of the existing
|
|
670
|
+
* client, and it belongs with the port of `properties.ts` / `ambient.ts` /
|
|
671
|
+
* `dependencies.ts` — the modules that already read EC2 this way.
|
|
672
|
+
*/
|
|
673
|
+
async function readBulkSources(wanted, region) {
|
|
674
|
+
const byType = new Map();
|
|
675
|
+
for (const { type, id } of wanted) {
|
|
676
|
+
if (DEEP_SOURCES[type]?.via !== "ec2")
|
|
677
|
+
continue;
|
|
678
|
+
byType.set(type, [...(byType.get(type) ?? []), id]);
|
|
679
|
+
}
|
|
680
|
+
const out = new Map();
|
|
681
|
+
if (byType.size === 0)
|
|
682
|
+
return out;
|
|
683
|
+
const { getRuntime } = await import("@intentius/chant/runtime-adapter");
|
|
684
|
+
const rt = getRuntime();
|
|
685
|
+
const regionArgs = region ? ["--region", region] : [];
|
|
686
|
+
for (const [type, ids] of byType) {
|
|
687
|
+
const source = DEEP_SOURCES[type];
|
|
688
|
+
if (source?.via !== "ec2")
|
|
689
|
+
continue;
|
|
690
|
+
try {
|
|
691
|
+
const result = await rt.spawn(applyAwsEndpointArgv(["aws", ...source.argv, source.idFlag, ...ids, ...regionArgs, "--output", "json"], process.env.AWS_ENDPOINT_URL));
|
|
692
|
+
if (result.exitCode !== 0)
|
|
693
|
+
continue;
|
|
694
|
+
const rows = (JSON.parse(result.stdout)[source.key] ?? []);
|
|
695
|
+
const byId = new Map();
|
|
696
|
+
for (const row of rows) {
|
|
697
|
+
const id = row[source.id];
|
|
698
|
+
if (typeof id === "string")
|
|
699
|
+
byId.set(id, row);
|
|
700
|
+
}
|
|
701
|
+
out.set(type, byId);
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
// One type's transport failing is that type's hole, not the whole read's.
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return out;
|
|
709
|
+
}
|