@@ -11,6 +11,7 @@ import { GatewayStack } from "../lib/gateway-stack";
1111import { GovernanceStack } from "../lib/governance-stack" ;
1212import { TelemetryStack } from "../lib/telemetry-stack" ;
1313import { ProjectsStack } from "../lib/projects-stack" ;
14+ import { RegistryStack } from "../lib/registry-stack" ;
1415
1516const app = new cdk . App ( ) ;
1617
@@ -64,6 +65,39 @@ const projectsStack = new ProjectsStack(
6465) ;
6566projectsStack . addDependency ( backendStack ) ;
6667
68+ // Registry satellite stack — backend-stack-split phase 2 (decision 30e6d067).
69+ // Owns the registry/agent-import/fabricator-request/fabricator-queue/
70+ // fabrication-event/app-CRUD-and-api-key domain, moved out of BackendStack.
71+ // Depends on backend only, for the shared API/bus/tables/registry/pool/
72+ // codeBucket passed in as props; resolvers attach to BackendStack's AppSync
73+ // API via the same L1 cross-stack pattern as ProjectsStack. Instantiated
74+ // before ServicesStack/GovernanceStack — no dependency on either — and
75+ // before GatewayStack, which it does NOT depend on: the publishApp/
76+ // unpublishApp resolvers (targeting a GatewayStack-owned function) stay in
77+ // BackendStack (documented exclusion in registry-stack.ts), so no
78+ // RegistryStack -> GatewayStack edge is introduced and ordering vs
79+ // GatewayStack is a non-issue.
80+ const registryStack = new RegistryStack (
81+ app ,
82+ `citadel-registry-${ environment } ` ,
83+ {
84+ ...stackProps ,
85+ description : `Registry domain satellite for Citadel - ${ environment } ` ,
86+ appSyncApi : backendStack . appSyncApi ,
87+ agentEventBus : backendStack . agentEventBus ,
88+ appsTable : backendStack . appsTable ,
89+ workflowsTable : backendStack . workflowsTable ,
90+ agentConfigTable : backendStack . agentConfigTable ,
91+ modelCatalogTable : backendStack . modelCatalogTable ,
92+ idempotencyTable : backendStack . idempotencyTable ,
93+ userPool : backendStack . userPool ,
94+ registryArn : backendStack . registryArn ,
95+ registryId : backendStack . registryId ,
96+ adrsTable : backendStack . adrsTable ,
97+ } ,
98+ ) ;
99+ registryStack . addDependency ( backendStack ) ;
100+
67101// Services stack (depends on backend)
68102const servicesStack = new ServicesStack (
69103 app ,
@@ -361,6 +395,7 @@ if (app.node.tryGetContext("nag") !== "false") {
361395 for ( const stack of [
362396 backendStack ,
363397 projectsStack ,
398+ registryStack ,
364399 servicesStack ,
365400 arbiterStack ,
366401 frontendStack ,
@@ -519,7 +554,7 @@ if (app.node.tryGetContext("nag") !== "false") {
519554 "RegistryProvisionerFunction/ServiceRole/DefaultPolicy/Resource" ,
520555 ] ,
521556 [
522- backendStack ,
557+ registryStack ,
523558 "RegistryAgentRecordResolverFunction/ServiceRole/DefaultPolicy/Resource" ,
524559 ] ,
525560 ] ;
@@ -634,8 +669,8 @@ if (app.node.tryGetContext("nag") !== "false") {
634669
635670 // SQS3 — RegistrySyncDLQ is itself a dead-letter queue; adding a DLQ to a DLQ is unnecessary.
636671 NagSuppressions . addResourceSuppressionsByPath (
637- backendStack ,
638- `/${ backendStack . stackName } /RegistrySyncDLQ/Resource` ,
672+ registryStack ,
673+ `/${ registryStack . stackName } /RegistrySyncDLQ/Resource` ,
639674 [
640675 {
641676 id : "AwsSolutions-SQS3" ,
@@ -673,13 +708,13 @@ if (app.node.tryGetContext("nag") !== "false") {
673708 } ,
674709 ] ;
675710 const registryArnPaths : Array < [ cdk . Stack , string ] > = [
676- [ backendStack , "RegistrySyncLambda/ServiceRole/DefaultPolicy/Resource" ] ,
711+ [ registryStack , "RegistrySyncLambda/ServiceRole/DefaultPolicy/Resource" ] ,
677712 [
678713 backendStack ,
679714 "AgentConfigResolverFunction/ServiceRole/DefaultPolicy/Resource" ,
680715 ] ,
681716 [
682- backendStack ,
717+ registryStack ,
683718 "AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource" ,
684719 ] ,
685720 [
@@ -691,7 +726,7 @@ if (app.node.tryGetContext("nag") !== "false") {
691726 [ arbiterStack , "WorkerAgentWrapper/ServiceRole/DefaultPolicy/Resource" ] ,
692727 [ arbiterStack , "GovernanceUiResolverFn/ServiceRole/DefaultPolicy/Resource" ] ,
693728 [
694- backendStack ,
729+ registryStack ,
695730 "RegistryAgentRecordResolverFunction/ServiceRole/DefaultPolicy/Resource" ,
696731 ] ,
697732 [
@@ -703,7 +738,7 @@ if (app.node.tryGetContext("nag") !== "false") {
703738 // (GetRegistryRecord + UpdateRegistryRecord), scoped to the
704739 // registry ARN + its records (<AgentCoreRegistry.RegistryArn>/*).
705740 [
706- backendStack ,
741+ registryStack ,
707742 "AgentImportManifestResultHandler/ServiceRole/DefaultPolicy/Resource" ,
708743 ] ,
709744 [
@@ -733,8 +768,8 @@ if (app.node.tryGetContext("nag") !== "false") {
733768 // Additive to the registry-ARN suppression already registered for
734769 // this role above.
735770 NagSuppressions . addResourceSuppressionsByPath (
736- backendStack ,
737- `/${ backendStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
771+ registryStack ,
772+ `/${ registryStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
738773 [
739774 {
740775 id : "AwsSolutions-IAM5" ,
@@ -753,8 +788,8 @@ if (app.node.tryGetContext("nag") !== "false") {
753788 // resource-level scoping, so they require Resource '*'. Additive to
754789 // the discovery suppression registered just above; read-only only.
755790 NagSuppressions . addResourceSuppressionsByPath (
756- backendStack ,
757- `/${ backendStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
791+ registryStack ,
792+ `/${ registryStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
758793 [
759794 {
760795 id : "AwsSolutions-IAM5" ,
@@ -773,8 +808,8 @@ if (app.node.tryGetContext("nag") !== "false") {
773808 // wildcards are already covered by the stack-level IAM5 suppression.
774809 // Additive to the discovery suppression registered just above.
775810 NagSuppressions . addResourceSuppressionsByPath (
776- backendStack ,
777- `/${ backendStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
811+ registryStack ,
812+ `/${ registryStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
778813 [
779814 {
780815 id : "AwsSolutions-IAM5" ,
@@ -804,8 +839,8 @@ if (app.node.tryGetContext("nag") !== "false") {
804839 // the discovery + test-invoke suppressions already registered for
805840 // this role above.
806841 NagSuppressions . addResourceSuppressionsByPath (
807- backendStack ,
808- `/${ backendStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
842+ registryStack ,
843+ `/${ registryStack . stackName } /AgentImportResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
809844 [
810845 {
811846 id : "AwsSolutions-IAM5" ,
@@ -816,4 +851,31 @@ if (app.node.tryGetContext("nag") !== "false") {
816851 } ,
817852 ] ,
818853 ) ;
854+
855+ // IAM5 — AgentCodeResolverFunction's S3 grant on the code bucket's agents/*
856+ // prefix (read/write/list agent code artifacts). The base bucket ARN grant
857+ // (list) plus the agents/* prefix grant (get/put/version) is the same
858+ // narrowing pattern the generic appLambdaSuppressions S3-prefix regex
859+ // (`Resource::arn:aws:s3:::.+\/\*$`) already covers for LITERAL ARN
860+ // strings — this one is a CDK token reference (`<CodeBucketFF4C7AD6.Arn>
861+ // /agents/*`), which the literal-string regex does not match. Same IAM5
862+ // category, same narrowing rationale (prefix-scoped, not bucket-wide *).
863+ NagSuppressions . addResourceSuppressionsByPath (
864+ registryStack ,
865+ `/${ registryStack . stackName } /AgentCodeResolverFunction/ServiceRole/DefaultPolicy/Resource` ,
866+ [
867+ {
868+ id : "AwsSolutions-IAM5" ,
869+ reason :
870+ "S3 grant scoped to the code bucket's agents/* prefix (CDK token " +
871+ "resource, not a literal ARN string) for get/put/version/list of " +
872+ "agent code artifacts. Narrow prefix, not bucket-wide wildcard." ,
873+ appliesTo : [
874+ {
875+ regex : "/^Resource::<CodeBucket[A-F0-9]+\\.Arn>\\/agents\\/\\*$/g" ,
876+ } ,
877+ ] ,
878+ } ,
879+ ] ,
880+ ) ;
819881}
0 commit comments