@semiont/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +497 -0
- package/dist/cli.mjs +45524 -0
- package/dist/dashboard/dashboard.css +238 -0
- package/dist/dashboard/dashboard.js +14 -0
- package/dist/dashboard/dashboard.js.map +7 -0
- package/dist/mcp-server/handlers-stubs.d.ts +40 -0
- package/dist/mcp-server/handlers-stubs.d.ts.map +1 -0
- package/dist/mcp-server/handlers-stubs.js +22 -0
- package/dist/mcp-server/handlers-stubs.js.map +1 -0
- package/dist/mcp-server/handlers.d.ts +96 -0
- package/dist/mcp-server/handlers.d.ts.map +1 -0
- package/dist/mcp-server/handlers.js +253 -0
- package/dist/mcp-server/handlers.js.map +1 -0
- package/dist/mcp-server/index.d.ts +3 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +365 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/mcp-server/index.test.d.ts +7 -0
- package/dist/mcp-server/index.test.d.ts.map +1 -0
- package/dist/mcp-server/index.test.js +183 -0
- package/dist/mcp-server/index.test.js.map +1 -0
- package/dist/templates/cdk/app-stack.ts +893 -0
- package/dist/templates/cdk/app.ts +54 -0
- package/dist/templates/cdk/data-stack.ts +416 -0
- package/dist/templates/cdk.json +36 -0
- package/dist/templates/environments/ci.json +52 -0
- package/dist/templates/environments/local.json +82 -0
- package/dist/templates/environments/production.json +57 -0
- package/dist/templates/environments/staging.json +49 -0
- package/dist/templates/environments/test.json +61 -0
- package/dist/templates/inference-claude.json +14 -0
- package/dist/templates/inference-openai.json +16 -0
- package/dist/templates/package.json +23 -0
- package/dist/templates/semiont.json +31 -0
- package/dist/templates/tsconfig.json +27 -0
- package/package.json +91 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as cdk from 'aws-cdk-lib';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { SemiontDataStack } from './data-stack';
|
|
5
|
+
import { SemiontAppStack } from './app-stack';
|
|
6
|
+
|
|
7
|
+
const app = new cdk.App();
|
|
8
|
+
|
|
9
|
+
// Get configuration from context and environment
|
|
10
|
+
const stackType = app.node.tryGetContext('stack-type') || 'all';
|
|
11
|
+
const environment = app.node.tryGetContext('environment') || process.env.SEMIONT_ENV || 'production';
|
|
12
|
+
|
|
13
|
+
// Load configurations using absolute paths from the project root
|
|
14
|
+
// Use process.cwd() which is the project root when CDK executes
|
|
15
|
+
const projectRoot = process.cwd();
|
|
16
|
+
const semiontConfig = require(path.join(projectRoot, 'semiont.json'));
|
|
17
|
+
const envConfig = require(path.join(projectRoot, 'environments', `${environment}.json`));
|
|
18
|
+
|
|
19
|
+
// Stack properties
|
|
20
|
+
const stackProps = {
|
|
21
|
+
env: {
|
|
22
|
+
account: envConfig.aws?.accountId || process.env.CDK_DEFAULT_ACCOUNT,
|
|
23
|
+
region: envConfig.aws?.region || process.env.CDK_DEFAULT_REGION || 'us-east-1',
|
|
24
|
+
},
|
|
25
|
+
synthesizer: new cdk.DefaultStackSynthesizer({
|
|
26
|
+
qualifier: 'hnb659fds'
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Set CDK context with configuration values
|
|
31
|
+
app.node.setContext('environment', environment);
|
|
32
|
+
app.node.setContext('siteName', semiontConfig.site?.siteName || 'Semiont');
|
|
33
|
+
app.node.setContext('domain', semiontConfig.site?.domain || 'example.com');
|
|
34
|
+
app.node.setContext('rootDomain', semiontConfig.site?.domain?.split('.').slice(-2).join('.') || 'example.com');
|
|
35
|
+
app.node.setContext('adminEmail', semiontConfig.site?.adminEmail || 'admin@example.com');
|
|
36
|
+
app.node.setContext('oauthAllowedDomains', semiontConfig.site?.oauthAllowedDomains || ['example.com']);
|
|
37
|
+
app.node.setContext('databaseName', semiontConfig.services?.database?.name || 'semiont');
|
|
38
|
+
app.node.setContext('certificateArn', envConfig.aws?.certificateArn);
|
|
39
|
+
app.node.setContext('hostedZoneId', envConfig.aws?.hostedZoneId);
|
|
40
|
+
app.node.setContext('backendImageUri', envConfig.services?.backend?.image);
|
|
41
|
+
app.node.setContext('frontendImageUri', envConfig.services?.frontend?.image);
|
|
42
|
+
app.node.setContext('nodeEnv', envConfig.env?.NODE_ENV || 'production');
|
|
43
|
+
|
|
44
|
+
// Create stacks based on stack-type context
|
|
45
|
+
if (stackType === 'data' || stackType === 'all') {
|
|
46
|
+
new SemiontDataStack(app, 'SemiontDataStack', stackProps);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (stackType === 'app' || stackType === 'all') {
|
|
50
|
+
// App stack will import resources from data stack via CloudFormation exports
|
|
51
|
+
new SemiontAppStack(app, 'SemiontAppStack', stackProps);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
app.synth();
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
2
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
3
|
+
import * as rds from 'aws-cdk-lib/aws-rds';
|
|
4
|
+
import * as efs from 'aws-cdk-lib/aws-efs';
|
|
5
|
+
import * as neptune from 'aws-cdk-lib/aws-neptune';
|
|
6
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
7
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
8
|
+
import { Construct } from 'constructs';
|
|
9
|
+
|
|
10
|
+
export class SemiontDataStack extends cdk.Stack {
|
|
11
|
+
public readonly vpc: ec2.Vpc;
|
|
12
|
+
public readonly fileSystem: efs.FileSystem;
|
|
13
|
+
public readonly database: rds.DatabaseInstance;
|
|
14
|
+
public readonly neptuneCluster: neptune.CfnDBCluster;
|
|
15
|
+
public readonly neptuneInstance: neptune.CfnDBInstance;
|
|
16
|
+
public readonly dbCredentials: secretsmanager.Secret;
|
|
17
|
+
public readonly appSecrets: secretsmanager.Secret;
|
|
18
|
+
public readonly jwtSecret: secretsmanager.Secret;
|
|
19
|
+
public readonly adminPassword: secretsmanager.Secret;
|
|
20
|
+
public readonly googleOAuth: secretsmanager.Secret;
|
|
21
|
+
public readonly githubOAuth: secretsmanager.Secret;
|
|
22
|
+
public readonly adminEmails: secretsmanager.Secret;
|
|
23
|
+
public readonly dbSecurityGroup: ec2.SecurityGroup;
|
|
24
|
+
public readonly neptuneSecurityGroup: ec2.SecurityGroup;
|
|
25
|
+
public readonly ecsSecurityGroup: ec2.SecurityGroup;
|
|
26
|
+
public readonly albSecurityGroup: ec2.SecurityGroup;
|
|
27
|
+
|
|
28
|
+
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
|
29
|
+
super(scope, id, props);
|
|
30
|
+
|
|
31
|
+
// VPC with proper subnet isolation
|
|
32
|
+
this.vpc = new ec2.Vpc(this, 'SemiontVpc', {
|
|
33
|
+
maxAzs: 2,
|
|
34
|
+
natGateways: 2,
|
|
35
|
+
subnetConfiguration: [
|
|
36
|
+
{
|
|
37
|
+
cidrMask: 24,
|
|
38
|
+
name: 'public',
|
|
39
|
+
subnetType: ec2.SubnetType.PUBLIC,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
cidrMask: 24,
|
|
43
|
+
name: 'private',
|
|
44
|
+
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
cidrMask: 24,
|
|
48
|
+
name: 'database',
|
|
49
|
+
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Database credentials in Secrets Manager
|
|
55
|
+
this.dbCredentials = new secretsmanager.Secret(this, 'DatabaseCredentials', {
|
|
56
|
+
generateSecretString: {
|
|
57
|
+
secretStringTemplate: JSON.stringify({ username: 'semiont' }),
|
|
58
|
+
generateStringKey: 'password',
|
|
59
|
+
excludeCharacters: '"@/\\',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Application secrets (contains both session and NextAuth secrets)
|
|
64
|
+
this.appSecrets = new secretsmanager.Secret(this, 'AppSecrets', {
|
|
65
|
+
description: 'Application secrets for Semiont (session and NextAuth)',
|
|
66
|
+
secretObjectValue: {
|
|
67
|
+
sessionSecret: cdk.SecretValue.unsafePlainText('REPLACE_WITH_SESSION_SECRET_64_CHARS'),
|
|
68
|
+
nextAuthSecret: cdk.SecretValue.unsafePlainText('REPLACE_WITH_NEXTAUTH_SECRET_64_CHARS'),
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
this.jwtSecret = new secretsmanager.Secret(this, 'JwtSecret', {
|
|
73
|
+
generateSecretString: {
|
|
74
|
+
secretStringTemplate: JSON.stringify({}),
|
|
75
|
+
generateStringKey: 'jwtSecret',
|
|
76
|
+
passwordLength: 64,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Admin password in Secrets Manager
|
|
81
|
+
this.adminPassword = new secretsmanager.Secret(this, 'AdminPassword', {
|
|
82
|
+
generateSecretString: {
|
|
83
|
+
secretStringTemplate: JSON.stringify({}),
|
|
84
|
+
generateStringKey: 'password',
|
|
85
|
+
passwordLength: 20,
|
|
86
|
+
excludeCharacters: '"@/\\`\'',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// OAuth credentials for Google
|
|
91
|
+
this.googleOAuth = new secretsmanager.Secret(this, 'GoogleOAuthCredentials', {
|
|
92
|
+
description: 'Google OAuth client credentials for Semiont',
|
|
93
|
+
secretObjectValue: {
|
|
94
|
+
clientId: cdk.SecretValue.unsafePlainText('REPLACE_WITH_GOOGLE_CLIENT_ID'),
|
|
95
|
+
clientSecret: cdk.SecretValue.unsafePlainText('REPLACE_WITH_GOOGLE_CLIENT_SECRET'),
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// OAuth credentials for GitHub (temporary - to maintain CloudFormation exports)
|
|
100
|
+
this.githubOAuth = new secretsmanager.Secret(this, 'GitHubOAuthCredentials', {
|
|
101
|
+
description: 'GitHub OAuth app credentials for Semiont (unused)',
|
|
102
|
+
secretObjectValue: {
|
|
103
|
+
clientId: cdk.SecretValue.unsafePlainText('UNUSED'),
|
|
104
|
+
clientSecret: cdk.SecretValue.unsafePlainText('UNUSED'),
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Admin users list
|
|
109
|
+
const adminEmail = this.node.tryGetContext('adminEmail') || 'admin@example.com';
|
|
110
|
+
this.adminEmails = new secretsmanager.Secret(this, 'AdminEmails', {
|
|
111
|
+
description: 'Comma-separated list of admin email addresses',
|
|
112
|
+
secretObjectValue: {
|
|
113
|
+
emails: cdk.SecretValue.unsafePlainText(adminEmail),
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Security Groups
|
|
118
|
+
this.dbSecurityGroup = new ec2.SecurityGroup(this, 'DatabaseSecurityGroup', {
|
|
119
|
+
vpc: this.vpc,
|
|
120
|
+
description: 'Security group for Semiont database',
|
|
121
|
+
allowAllOutbound: false, // Database should not initiate outbound connections
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
this.ecsSecurityGroup = new ec2.SecurityGroup(this, 'EcsSecurityGroup', {
|
|
125
|
+
vpc: this.vpc,
|
|
126
|
+
description: 'Security group for Semiont ECS tasks',
|
|
127
|
+
// allowAllOutbound: true (default) - needed for internet access, docker pulls, etc.
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
this.albSecurityGroup = new ec2.SecurityGroup(this, 'AlbSecurityGroup', {
|
|
131
|
+
vpc: this.vpc,
|
|
132
|
+
description: 'Security group for Application Load Balancer',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Configure security group rules
|
|
136
|
+
this.dbSecurityGroup.addIngressRule(
|
|
137
|
+
this.ecsSecurityGroup,
|
|
138
|
+
ec2.Port.tcp(5432),
|
|
139
|
+
'Allow ECS to access PostgreSQL'
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
this.albSecurityGroup.addIngressRule(
|
|
143
|
+
ec2.Peer.anyIpv4(),
|
|
144
|
+
ec2.Port.tcp(80),
|
|
145
|
+
'Allow HTTP'
|
|
146
|
+
);
|
|
147
|
+
this.albSecurityGroup.addIngressRule(
|
|
148
|
+
ec2.Peer.anyIpv4(),
|
|
149
|
+
ec2.Port.tcp(443),
|
|
150
|
+
'Allow HTTPS'
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
this.ecsSecurityGroup.addIngressRule(
|
|
154
|
+
this.albSecurityGroup,
|
|
155
|
+
ec2.Port.tcp(80),
|
|
156
|
+
'Allow ALB to reach ECS'
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// PostgreSQL RDS with encryption
|
|
160
|
+
this.database = new rds.DatabaseInstance(this, 'SemiontDatabase', {
|
|
161
|
+
engine: rds.DatabaseInstanceEngine.postgres({
|
|
162
|
+
version: rds.PostgresEngineVersion.VER_15,
|
|
163
|
+
}),
|
|
164
|
+
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T3, ec2.InstanceSize.MICRO),
|
|
165
|
+
credentials: rds.Credentials.fromSecret(this.dbCredentials),
|
|
166
|
+
vpc: this.vpc,
|
|
167
|
+
vpcSubnets: {
|
|
168
|
+
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
|
|
169
|
+
},
|
|
170
|
+
securityGroups: [this.dbSecurityGroup],
|
|
171
|
+
databaseName: this.node.tryGetContext('databaseName') || 'semiont',
|
|
172
|
+
storageEncrypted: true,
|
|
173
|
+
backupRetention: cdk.Duration.days(7),
|
|
174
|
+
deletionProtection: true,
|
|
175
|
+
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
176
|
+
multiAz: false,
|
|
177
|
+
allowMajorVersionUpgrade: false,
|
|
178
|
+
autoMinorVersionUpgrade: true,
|
|
179
|
+
deleteAutomatedBackups: false,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// EFS for persistent file storage
|
|
183
|
+
this.fileSystem = new efs.FileSystem(this, 'SemiontEFS', {
|
|
184
|
+
vpc: this.vpc,
|
|
185
|
+
lifecyclePolicy: efs.LifecyclePolicy.AFTER_30_DAYS,
|
|
186
|
+
performanceMode: efs.PerformanceMode.GENERAL_PURPOSE,
|
|
187
|
+
throughputMode: efs.ThroughputMode.BURSTING,
|
|
188
|
+
encrypted: true,
|
|
189
|
+
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Allow ECS to access EFS
|
|
193
|
+
this.fileSystem.connections.allowDefaultPortFrom(this.ecsSecurityGroup, 'Allow ECS to EFS');
|
|
194
|
+
|
|
195
|
+
// Neptune Graph Database (required for document relationships)
|
|
196
|
+
// Neptune subnet group
|
|
197
|
+
const neptuneSubnetGroup = new neptune.CfnDBSubnetGroup(this, 'NeptuneSubnetGroup', {
|
|
198
|
+
dbSubnetGroupDescription: 'Subnet group for Neptune graph database',
|
|
199
|
+
subnetIds: this.vpc.privateSubnets.map(subnet => subnet.subnetId),
|
|
200
|
+
dbSubnetGroupName: `${this.stackName}-neptune-subnet-group`,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Neptune security group
|
|
204
|
+
this.neptuneSecurityGroup = new ec2.SecurityGroup(this, 'NeptuneSecurityGroup', {
|
|
205
|
+
vpc: this.vpc,
|
|
206
|
+
description: 'Security group for Neptune graph database',
|
|
207
|
+
allowAllOutbound: false,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Allow ECS to access Neptune
|
|
211
|
+
this.neptuneSecurityGroup.addIngressRule(
|
|
212
|
+
this.ecsSecurityGroup,
|
|
213
|
+
ec2.Port.tcp(8182),
|
|
214
|
+
'Allow ECS to access Neptune'
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Neptune parameter group for optimal performance
|
|
218
|
+
const neptuneParameterGroup = new neptune.CfnDBParameterGroup(this, 'NeptuneParameterGroup', {
|
|
219
|
+
family: 'neptune1.3',
|
|
220
|
+
parameters: {
|
|
221
|
+
'neptune_enable_audit_log': '0',
|
|
222
|
+
'neptune_query_timeout': '120000',
|
|
223
|
+
},
|
|
224
|
+
description: 'Neptune parameter group for Semiont',
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Neptune cluster
|
|
228
|
+
this.neptuneCluster = new neptune.CfnDBCluster(this, 'NeptuneCluster', {
|
|
229
|
+
dbSubnetGroupName: neptuneSubnetGroup.dbSubnetGroupName,
|
|
230
|
+
vpcSecurityGroupIds: [this.neptuneSecurityGroup.securityGroupId],
|
|
231
|
+
dbClusterParameterGroupName: neptuneParameterGroup.ref,
|
|
232
|
+
engineVersion: '1.3.0.0',
|
|
233
|
+
storageEncrypted: true,
|
|
234
|
+
backupRetentionPeriod: 7,
|
|
235
|
+
preferredBackupWindow: '03:00-04:00',
|
|
236
|
+
preferredMaintenanceWindow: 'sun:04:00-sun:05:00',
|
|
237
|
+
deletionProtection: true,
|
|
238
|
+
iamDatabaseAuthenticationEnabled: true,
|
|
239
|
+
tags: [
|
|
240
|
+
{ key: 'Application', value: 'Semiont' },
|
|
241
|
+
{ key: 'Component', value: 'GraphDatabase' },
|
|
242
|
+
{ key: 'Environment', value: this.node.tryGetContext('environment') || 'production' },
|
|
243
|
+
],
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Neptune instance (t4g.medium is ARM-based and ~7% cheaper than t3.medium)
|
|
247
|
+
this.neptuneInstance = new neptune.CfnDBInstance(this, 'NeptuneInstance', {
|
|
248
|
+
dbInstanceClass: 'db.t4g.medium',
|
|
249
|
+
dbClusterIdentifier: this.neptuneCluster.ref,
|
|
250
|
+
dbSubnetGroupName: neptuneSubnetGroup.dbSubnetGroupName,
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Outputs for Neptune
|
|
254
|
+
new cdk.CfnOutput(this, 'NeptuneClusterEndpoint', {
|
|
255
|
+
value: this.neptuneCluster.attrEndpoint,
|
|
256
|
+
description: 'Neptune Cluster Endpoint',
|
|
257
|
+
exportName: `${this.stackName}-NeptuneClusterEndpoint`,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
new cdk.CfnOutput(this, 'NeptuneClusterId', {
|
|
261
|
+
value: this.neptuneCluster.attrClusterResourceId,
|
|
262
|
+
description: 'Neptune Cluster ID',
|
|
263
|
+
exportName: `${this.stackName}-NeptuneClusterId`,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
new cdk.CfnOutput(this, 'NeptuneReadEndpoint', {
|
|
267
|
+
value: this.neptuneCluster.attrReadEndpoint,
|
|
268
|
+
description: 'Neptune Read Endpoint',
|
|
269
|
+
exportName: `${this.stackName}-NeptuneReadEndpoint`,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
new cdk.CfnOutput(this, 'NeptunePort', {
|
|
273
|
+
value: this.neptuneCluster.attrPort,
|
|
274
|
+
description: 'Neptune Port',
|
|
275
|
+
exportName: `${this.stackName}-NeptunePort`,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
new cdk.CfnOutput(this, 'NeptuneSecurityGroupId', {
|
|
279
|
+
value: this.neptuneSecurityGroup.securityGroupId,
|
|
280
|
+
description: 'Neptune Security Group ID',
|
|
281
|
+
exportName: `${this.stackName}-NeptuneSecurityGroupId`,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Add explicit EFS filesystem policy to allow access
|
|
285
|
+
this.fileSystem.addToResourcePolicy(
|
|
286
|
+
new iam.PolicyStatement({
|
|
287
|
+
sid: 'AllowClientAccess',
|
|
288
|
+
effect: iam.Effect.ALLOW,
|
|
289
|
+
principals: [new iam.AnyPrincipal()],
|
|
290
|
+
actions: [
|
|
291
|
+
'elasticfilesystem:ClientMount',
|
|
292
|
+
'elasticfilesystem:ClientWrite',
|
|
293
|
+
'elasticfilesystem:ClientRootAccess',
|
|
294
|
+
],
|
|
295
|
+
resources: ['*'],
|
|
296
|
+
conditions: {
|
|
297
|
+
Bool: {
|
|
298
|
+
'aws:SecureTransport': 'false', // Allow non-TLS connections
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
})
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
// Export outputs for cross-stack references
|
|
305
|
+
new cdk.CfnOutput(this, 'VpcId', {
|
|
306
|
+
value: this.vpc.vpcId,
|
|
307
|
+
description: 'VPC ID',
|
|
308
|
+
exportName: `${this.stackName}-VpcId`,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Export subnet IDs for VPC import
|
|
312
|
+
new cdk.CfnOutput(this, 'PublicSubnet1Id', {
|
|
313
|
+
value: this.vpc.publicSubnets[0].subnetId,
|
|
314
|
+
description: 'Public Subnet 1 ID',
|
|
315
|
+
exportName: `${this.stackName}-PublicSubnet1Id`,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
new cdk.CfnOutput(this, 'PublicSubnet2Id', {
|
|
319
|
+
value: this.vpc.publicSubnets[1].subnetId,
|
|
320
|
+
description: 'Public Subnet 2 ID',
|
|
321
|
+
exportName: `${this.stackName}-PublicSubnet2Id`,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
new cdk.CfnOutput(this, 'PrivateSubnet1Id', {
|
|
325
|
+
value: this.vpc.privateSubnets[0].subnetId,
|
|
326
|
+
description: 'Private Subnet 1 ID',
|
|
327
|
+
exportName: `${this.stackName}-PrivateSubnet1Id`,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
new cdk.CfnOutput(this, 'PrivateSubnet2Id', {
|
|
331
|
+
value: this.vpc.privateSubnets[1].subnetId,
|
|
332
|
+
description: 'Private Subnet 2 ID',
|
|
333
|
+
exportName: `${this.stackName}-PrivateSubnet2Id`,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
new cdk.CfnOutput(this, 'DatabaseEndpoint', {
|
|
337
|
+
value: this.database.instanceEndpoint.hostname,
|
|
338
|
+
description: 'RDS Database Endpoint',
|
|
339
|
+
exportName: `${this.stackName}-DatabaseEndpoint`,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
new cdk.CfnOutput(this, 'DatabasePort', {
|
|
343
|
+
value: this.database.instanceEndpoint.port.toString(),
|
|
344
|
+
description: 'RDS Database Port',
|
|
345
|
+
exportName: `${this.stackName}-DatabasePort`,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
new cdk.CfnOutput(this, 'EfsFileSystemId', {
|
|
349
|
+
value: this.fileSystem.fileSystemId,
|
|
350
|
+
description: 'EFS File System ID',
|
|
351
|
+
exportName: `${this.stackName}-EfsFileSystemId`,
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// Security Group IDs for import
|
|
355
|
+
new cdk.CfnOutput(this, 'DbSecurityGroupId', {
|
|
356
|
+
value: this.dbSecurityGroup.securityGroupId,
|
|
357
|
+
description: 'Database Security Group ID',
|
|
358
|
+
exportName: `${this.stackName}-DbSecurityGroupId`,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
new cdk.CfnOutput(this, 'EcsSecurityGroupId', {
|
|
362
|
+
value: this.ecsSecurityGroup.securityGroupId,
|
|
363
|
+
description: 'ECS Security Group ID',
|
|
364
|
+
exportName: `${this.stackName}-EcsSecurityGroupId`,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
new cdk.CfnOutput(this, 'AlbSecurityGroupId', {
|
|
368
|
+
value: this.albSecurityGroup.securityGroupId,
|
|
369
|
+
description: 'ALB Security Group ID',
|
|
370
|
+
exportName: `${this.stackName}-AlbSecurityGroupId`,
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Secret ARNs for import
|
|
374
|
+
new cdk.CfnOutput(this, 'DbCredentialsSecretArn', {
|
|
375
|
+
value: this.dbCredentials.secretArn,
|
|
376
|
+
description: 'Database Credentials Secret ARN',
|
|
377
|
+
exportName: `${this.stackName}-DbCredentialsSecretArn`,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
new cdk.CfnOutput(this, 'AppSecretsSecretArn', {
|
|
381
|
+
value: this.appSecrets.secretArn,
|
|
382
|
+
description: 'App Secrets Secret ARN',
|
|
383
|
+
exportName: `${this.stackName}-AppSecretsSecretArn`,
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
new cdk.CfnOutput(this, 'JwtSecretArn', {
|
|
387
|
+
value: this.jwtSecret.secretArn,
|
|
388
|
+
description: 'JWT Secret ARN',
|
|
389
|
+
exportName: `${this.stackName}-JwtSecretArn`,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
new cdk.CfnOutput(this, 'GoogleOAuthSecretArn', {
|
|
393
|
+
value: this.googleOAuth.secretArn,
|
|
394
|
+
description: 'Google OAuth Secret ARN',
|
|
395
|
+
exportName: `${this.stackName}-GoogleOAuthSecretArn`,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
new cdk.CfnOutput(this, 'GitHubOAuthSecretArn', {
|
|
399
|
+
value: this.githubOAuth.secretArn,
|
|
400
|
+
description: 'GitHub OAuth Secret ARN',
|
|
401
|
+
exportName: `${this.stackName}-GitHubOAuthSecretArn`,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
new cdk.CfnOutput(this, 'AdminEmailsSecretArn', {
|
|
405
|
+
value: this.adminEmails.secretArn,
|
|
406
|
+
description: 'Admin Emails Secret ARN',
|
|
407
|
+
exportName: `${this.stackName}-AdminEmailsSecretArn`,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
new cdk.CfnOutput(this, 'AdminPasswordSecretArn', {
|
|
411
|
+
value: this.adminPassword.secretArn,
|
|
412
|
+
description: 'Admin Password Secret ARN',
|
|
413
|
+
exportName: `${this.stackName}-AdminPasswordSecretArn`,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "npx ts-node --prefer-ts-exts cdk/app.ts",
|
|
3
|
+
"watch": {
|
|
4
|
+
"include": ["**"],
|
|
5
|
+
"exclude": [
|
|
6
|
+
"README.md",
|
|
7
|
+
"cdk*.json",
|
|
8
|
+
"**/*.js",
|
|
9
|
+
"**/*.d.ts",
|
|
10
|
+
"node_modules",
|
|
11
|
+
"test"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"context": {
|
|
15
|
+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
|
|
16
|
+
"@aws-cdk/core:checkSecretUsage": true,
|
|
17
|
+
"@aws-cdk/core:target-partitions": ["aws", "aws-cn"],
|
|
18
|
+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
|
|
19
|
+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
|
|
20
|
+
"@aws-cdk/aws-ecs:arnFormat": true,
|
|
21
|
+
"@aws-cdk/aws-iam:minimizePolicies": true,
|
|
22
|
+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
|
|
23
|
+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
|
|
24
|
+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
|
|
25
|
+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
|
|
26
|
+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
|
|
27
|
+
"@aws-cdk/core:enablePartitionLiterals": true,
|
|
28
|
+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
|
|
29
|
+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
|
|
30
|
+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
|
|
31
|
+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
|
|
32
|
+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
|
|
33
|
+
"@aws-cdk/aws-route53-patters:useCertificate": true,
|
|
34
|
+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ci",
|
|
3
|
+
"site": {
|
|
4
|
+
"domain": "localhost",
|
|
5
|
+
"oauthAllowedDomains": ["example.com", "test.example.com"]
|
|
6
|
+
},
|
|
7
|
+
"platform": {
|
|
8
|
+
"default": "posix"
|
|
9
|
+
},
|
|
10
|
+
"env": {
|
|
11
|
+
"NODE_ENV": "development"
|
|
12
|
+
},
|
|
13
|
+
"services": {
|
|
14
|
+
"backend": {
|
|
15
|
+
"platform": {
|
|
16
|
+
"type": "posix"
|
|
17
|
+
},
|
|
18
|
+
"port": 4000,
|
|
19
|
+
"publicURL": "http://localhost:4000",
|
|
20
|
+
"corsOrigin": "http://localhost:3000"
|
|
21
|
+
},
|
|
22
|
+
"frontend": {
|
|
23
|
+
"platform": {
|
|
24
|
+
"type": "posix"
|
|
25
|
+
},
|
|
26
|
+
"port": 3000,
|
|
27
|
+
"url": "http://localhost:3000",
|
|
28
|
+
"siteName": "CI Test Site"
|
|
29
|
+
},
|
|
30
|
+
"filesystem": {
|
|
31
|
+
"platform": {
|
|
32
|
+
"type": "posix"
|
|
33
|
+
},
|
|
34
|
+
"path": "data",
|
|
35
|
+
"description": "CI filesystem storage"
|
|
36
|
+
},
|
|
37
|
+
"database": {
|
|
38
|
+
"platform": {
|
|
39
|
+
"type": "external"
|
|
40
|
+
},
|
|
41
|
+
"type": "postgres",
|
|
42
|
+
"host": "localhost",
|
|
43
|
+
"port": 5432
|
|
44
|
+
},
|
|
45
|
+
"mcp": {
|
|
46
|
+
"platform": {
|
|
47
|
+
"type": "posix"
|
|
48
|
+
},
|
|
49
|
+
"dependsOn": ["backend"]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "local",
|
|
3
|
+
"platform": {
|
|
4
|
+
"default": "container"
|
|
5
|
+
},
|
|
6
|
+
"deployment": {
|
|
7
|
+
"imageTagStrategy": "mutable"
|
|
8
|
+
},
|
|
9
|
+
"site": {
|
|
10
|
+
"domain": "localhost:3000",
|
|
11
|
+
"oauthAllowedDomains": ["example.com", "localhost:3000"]
|
|
12
|
+
},
|
|
13
|
+
"env": {
|
|
14
|
+
"NODE_ENV": "development"
|
|
15
|
+
},
|
|
16
|
+
"services": {
|
|
17
|
+
"backend": {
|
|
18
|
+
"platform": {
|
|
19
|
+
"type": "posix"
|
|
20
|
+
},
|
|
21
|
+
"command": "npm run dev",
|
|
22
|
+
"port": 4000,
|
|
23
|
+
"publicURL": "http://localhost:4000",
|
|
24
|
+
"corsOrigin": "http://localhost:3000"
|
|
25
|
+
},
|
|
26
|
+
"frontend": {
|
|
27
|
+
"platform": {
|
|
28
|
+
"type": "posix"
|
|
29
|
+
},
|
|
30
|
+
"command": "npm run dev",
|
|
31
|
+
"port": 3000,
|
|
32
|
+
"url": "http://localhost:3000"
|
|
33
|
+
},
|
|
34
|
+
"database": {
|
|
35
|
+
"platform": {
|
|
36
|
+
"type": "container"
|
|
37
|
+
},
|
|
38
|
+
"image": "postgres:15-alpine",
|
|
39
|
+
"name": "semiont-local-db",
|
|
40
|
+
"port": 5432,
|
|
41
|
+
"environment": {
|
|
42
|
+
"POSTGRES_DB": "semiont",
|
|
43
|
+
"POSTGRES_USER": "postgres",
|
|
44
|
+
"POSTGRES_PASSWORD": "localpass"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"graph": {
|
|
48
|
+
"platform": {
|
|
49
|
+
"type": "external"
|
|
50
|
+
},
|
|
51
|
+
"type": "neo4j",
|
|
52
|
+
"name": "neo4j",
|
|
53
|
+
"uri": "${NEO4J_URI}",
|
|
54
|
+
"username": "${NEO4J_USERNAME}",
|
|
55
|
+
"password": "${NEO4J_PASSWORD}",
|
|
56
|
+
"database": "${NEO4J_DATABASE}"
|
|
57
|
+
},
|
|
58
|
+
"mcp": {
|
|
59
|
+
"platform": {
|
|
60
|
+
"type": "posix"
|
|
61
|
+
},
|
|
62
|
+
"dependsOn": ["backend"]
|
|
63
|
+
},
|
|
64
|
+
"filesystem": {
|
|
65
|
+
"platform": {
|
|
66
|
+
"type": "posix"
|
|
67
|
+
},
|
|
68
|
+
"path": "./data/uploads",
|
|
69
|
+
"description": "Local filesystem storage for uploads and assets"
|
|
70
|
+
},
|
|
71
|
+
"inference": {
|
|
72
|
+
"platform": {
|
|
73
|
+
"type": "external"
|
|
74
|
+
},
|
|
75
|
+
"type": "anthropic",
|
|
76
|
+
"model": "claude-sonnet-4-20250514",
|
|
77
|
+
"maxTokens": 8192,
|
|
78
|
+
"endpoint": "https://api.anthropic.com",
|
|
79
|
+
"apiKey": "${ANTHROPIC_API_KEY}"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|