Class CloudForgeSynthesizer
CloudForgeDeployment (specifically AwsDirectDeployer, but the shape is target-
agnostic) needs, without shelling out to the cdk CLI.
Follows the same recipe as cfc-testing's InteractiveDeployer "synthesize
only" / "export template" options: build a CDK App with cfc context set from
DeploymentConfig.toContextMap(), construct the com.cloudforgeci.api.launch stack
for DeploymentConfig.runtime, and call app.synth(). It lives here so that callers
without an interactive CLI, such as CloudForge Manager, need not depend on the sample project.
Account resolution: DeploymentConfig.account wins when set; otherwise
CDK_DEFAULT_ACCOUNT; otherwise the template's Environment is account-agnostic
and CloudFormation resolves AWS::AccountId in whichever account it is deployed to.
Availability-zone resolution: VpcFactory.maxAzs(2) reads
Stack.availabilityZones, which CDK resolves via Fn::GetAZs (a
CloudFormation-time token) only while account+region are both unresolved — true for the
account-agnostic template above. The moment an explicit account is set, CDK instead routes AZ
resolution through its availability-zones *synth-time* context provider — and since
this deploy path never shells out to the cdk CLI to satisfy that lookup, CDK would
silently return its built-in dummy values (dummy1a/dummy1b) baked straight into
the template, which then fails at CloudFormation. Whenever an account is pinned, synthesize(DeploymentConfig, Path) seeds that context key itself first — see seedAvailabilityZoneContext(App, String, String, String[]).
Hosted-zone resolution: the same exposure, a different context provider —
DomainFactory's HostedZone.fromLookup for an SSL+custom-domain deploy has no
CloudFormation-intrinsic fallback the way AZs do, so it always resolves through CDK's
synth-time hosted-zone context provider once a domain is set, and would otherwise
silently bake in CDK's dummy zone id. See seedHostedZoneContext(App, String, String, String).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordsynthesizeAdvisoryDryRun(DeploymentConfig, Path)'s result — every finding cdk-nag and the requestedFrameworkRulesimplementations produced, with nothing filtered out the waysynthesize(DeploymentConfig, Path)'s own ENFORCE-mode check only reads error-level cdk-nag lines.static final record -
Method Summary
Modifier and TypeMethodDescriptionstatic CloudForgeSynthesizer.Resultsynthesize(DeploymentConfig config, Path outputDirectory) Resolvesconfig.applicationSpecviaApplicationLoaderwhen not already set (mutatesconfig— matchesCloudForgeDeployment.deploy()'s existing convention of resolving/preparing the config it's handed rather than requiring the caller to have already done so).synthesizeAdvisoryDryRun(DeploymentConfig config, Path outputDirectory) A synth-only "what would this report" pass — never deploys anything, never writes to CloudFormation, and never throws over a compliance finding the waysynthesize(DeploymentConfig, Path)can inComplianceMode.ENFORCE.static CloudForgeSynthesizer.ResultsynthesizeForMarketplace(DeploymentConfig config, Path outputDirectory) Same assynthesize(DeploymentConfig, Path), but produces the AWS Marketplace CloudFormation listing variant of CloudForge Manager -- seeMarketplaceParameterSupport's own javadoc for what that changes (realAdminEmail/LicenseKeyCloudFormation parameters instead of requiring them via--context/cdk.json, meaningless to a buyer who never runs the CDK CLI).static CloudForgeSynthesizer.ResultsynthesizeForMarketplace(DeploymentConfig config, Path outputDirectory, MarketplaceVariant variant) Same assynthesizeForMarketplace(DeploymentConfig, Path), for an explicitMarketplaceVariant:SSO(Cognito, admin email and domain prefix required) orTOKEN(no Cognito, first administrator created with the one-time setup token).
-
Method Details
-
synthesize
public static CloudForgeSynthesizer.Result synthesize(DeploymentConfig config, Path outputDirectory) throws IOException Resolvesconfig.applicationSpecviaApplicationLoaderwhen not already set (mutatesconfig— matchesCloudForgeDeployment.deploy()'s existing convention of resolving/preparing the config it's handed rather than requiring the caller to have already done so).- Throws:
IllegalArgumentException- when applicationId/stackName/runtime are missing, or noApplicationSpecis registered forconfig.applicationIdIOException- whenapp.synth()fails, or the output directory can't be created
-
synthesizeForMarketplace
public static CloudForgeSynthesizer.Result synthesizeForMarketplace(DeploymentConfig config, Path outputDirectory) throws IOException Same assynthesize(DeploymentConfig, Path), but produces the AWS Marketplace CloudFormation listing variant of CloudForge Manager -- seeMarketplaceParameterSupport's own javadoc for what that changes (realAdminEmail/LicenseKeyCloudFormation parameters instead of requiring them via--context/cdk.json, meaningless to a buyer who never runs the CDK CLI). This is the one and only place Marketplace mode is ever turned on -- deliberately not aDeploymentConfigfield or a CLI flag on the regulardeploycommand, so it can't be set by hand-editing a context file; only whatever builds the actual Marketplace listing artifact calls this method.- Throws:
IllegalArgumentException- whenconfig.applicationIdisn'tcloudforge-manager-- every other application ignores Marketplace mode entirely (seeMarketplaceParameterSupport), so synthesizing one through this entry point would silently produce a template indistinguishable fromsynthesize(DeploymentConfig, Path)'s own output.IOException
-
synthesizeForMarketplace
public static CloudForgeSynthesizer.Result synthesizeForMarketplace(DeploymentConfig config, Path outputDirectory, MarketplaceVariant variant) throws IOException Same assynthesizeForMarketplace(DeploymentConfig, Path), for an explicitMarketplaceVariant:SSO(Cognito, admin email and domain prefix required) orTOKEN(no Cognito, first administrator created with the one-time setup token).- Throws:
IOException
-
synthesizeAdvisoryDryRun
public static CloudForgeSynthesizer.ComplianceCheckResult synthesizeAdvisoryDryRun(DeploymentConfig config, Path outputDirectory) A synth-only "what would this report" pass — never deploys anything, never writes to CloudFormation, and never throws over a compliance finding the waysynthesize(DeploymentConfig, Path)can inComplianceMode.ENFORCE. Built for an on-demand compliance check against an already-deployed stack's reconstructed configuration (CloudForge Manager's Compliance tab): the caller setsconfig.complianceFrameworksto whichever framework(s) the user picked, and this returns every cdk-nag and framework-rule finding for them, instead of only the subset that would block a real deploy.config.complianceModeis forced toADVISORYfor the duration of this call (and restored after) regardless of what the caller set it to — this method's entire point is "report, don't block". Framework-rule findings only reach a caller at all viaComplianceFindingsCollector— see its own javadoc for whyNode.addValidationitself can't carry them out of ADVISORY mode.config.securityProfileandconfig.auditManagerEnabledare likewise forced (toPRODUCTIONandtrue, both restored after) —SecurityRules#install's own gates only ever apply cdk-nag for aPRODUCTIONprofile and only ever install anyFrameworkRulesimplementation at all whenauditManagerEnabledis set, regardless of which frameworks were requested. Without forcing both, a check against a real DEV/STAGING stack's own reconstructed profile would silently come back with zero findings from either engine — not "this stack is compliant", just "these checks never ran" — which would actively mislead the very user this preview exists for. The whole point of an advisory check is "would this pass production-grade scrutiny", independent of whatever the target stack's own real profile happens to be.Never throws — not every validator in this codebase honors
ComplianceMode(several "always load" cross-framework validators hard-block on their ownSecurityProfilegate regardless of mode; seeComplianceCheckResult#error's own javadoc). A caller building a UI around this (CloudForge Manager's Compliance tab) can always render SOMETHING rather than handling a thrown exception on top of the findings lists it otherwise expects.- Parameters:
outputDirectory- a throwaway cloud-assembly directory — the caller owns its lifecycle (create before, delete after); nothing here is meant to persist
-