@prism-d1/cli 1.2.0 → 1.3.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/dist/assets/github-workflows/prism-eval-gate-kiro.yml +2 -2
- package/dist/assets/infra/bin/app.ts +61 -37
- package/dist/assets/infra/lib/constructs/security-agent-construct.ts +35 -30
- package/dist/assets/infra/lib/metrics-pipeline-stack.ts +2 -110
- package/dist/assets/infra/lib/security-agent-resources.ts +136 -0
- package/dist/assets/infra/lib/security-agent-stack.ts +69 -0
- package/dist/assets/pentest-cdk/bin/app.ts +12 -0
- package/dist/assets/pentest-cdk/cdk.json +7 -0
- package/dist/assets/pentest-cdk/lib/pentest-target-stack.ts +206 -0
- package/dist/assets/pentest-cdk/package.json +18 -0
- package/dist/assets/pentest-cdk/tsconfig.json +12 -0
- package/dist/src/codewatch/results.d.ts +124 -4
- package/dist/src/codewatch/results.d.ts.map +1 -1
- package/dist/src/codewatch/results.js +8 -2
- package/dist/src/codewatch/results.js.map +1 -1
- package/dist/src/commands/_top/version.d.ts +62 -0
- package/dist/src/commands/_top/version.d.ts.map +1 -0
- package/dist/src/commands/_top/version.js +175 -0
- package/dist/src/commands/_top/version.js.map +1 -0
- package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts +12 -6
- package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/setup-otel-sync.js +18 -409
- package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
- package/dist/src/commands/enable/codeburn.d.ts +59 -0
- package/dist/src/commands/enable/codeburn.d.ts.map +1 -0
- package/dist/src/commands/enable/codeburn.js +531 -0
- package/dist/src/commands/enable/codeburn.js.map +1 -0
- package/dist/src/commands/enable/security.d.ts +41 -0
- package/dist/src/commands/enable/security.d.ts.map +1 -0
- package/dist/src/commands/enable/security.js +130 -0
- package/dist/src/commands/enable/security.js.map +1 -0
- package/dist/src/commands/export/otel.d.ts +31 -0
- package/dist/src/commands/export/otel.d.ts.map +1 -0
- package/dist/src/commands/export/otel.js +52 -0
- package/dist/src/commands/export/otel.js.map +1 -0
- package/dist/src/commands/security/code-review.d.ts +22 -0
- package/dist/src/commands/security/code-review.d.ts.map +1 -0
- package/dist/src/commands/security/code-review.js +43 -0
- package/dist/src/commands/security/code-review.js.map +1 -0
- package/dist/src/commands/security/findings.d.ts +15 -0
- package/dist/src/commands/security/findings.d.ts.map +1 -0
- package/dist/src/commands/security/findings.js +31 -0
- package/dist/src/commands/security/findings.js.map +1 -0
- package/dist/src/commands/security/pentest.d.ts +18 -0
- package/dist/src/commands/security/pentest.d.ts.map +1 -0
- package/dist/src/commands/security/pentest.js +32 -0
- package/dist/src/commands/security/pentest.js.map +1 -0
- package/dist/src/commands/security/threat-model.d.ts +16 -0
- package/dist/src/commands/security/threat-model.d.ts.map +1 -0
- package/dist/src/commands/security/threat-model.js +24 -0
- package/dist/src/commands/security/threat-model.js.map +1 -0
- package/dist/src/commands/security/threats.d.ts +12 -0
- package/dist/src/commands/security/threats.d.ts.map +1 -0
- package/dist/src/commands/security/threats.js +23 -0
- package/dist/src/commands/security/threats.js.map +1 -0
- package/dist/src/commands/securityagent/setup.d.ts +19 -5
- package/dist/src/commands/securityagent/setup.d.ts.map +1 -1
- package/dist/src/commands/securityagent/setup.js +25 -189
- package/dist/src/commands/securityagent/setup.js.map +1 -1
- package/dist/src/dashboard/codewatch.d.ts.map +1 -1
- package/dist/src/dashboard/codewatch.js +2 -1
- package/dist/src/dashboard/codewatch.js.map +1 -1
- package/dist/src/dashboard/page.d.ts.map +1 -1
- package/dist/src/dashboard/page.js +159 -4
- package/dist/src/dashboard/page.js.map +1 -1
- package/dist/src/dashboard/payload.d.ts +8 -5
- package/dist/src/dashboard/payload.d.ts.map +1 -1
- package/dist/src/dashboard/payload.js +5 -2
- package/dist/src/dashboard/payload.js.map +1 -1
- package/dist/src/dashboard/security.d.ts +130 -0
- package/dist/src/dashboard/security.d.ts.map +1 -0
- package/dist/src/dashboard/security.js +144 -0
- package/dist/src/dashboard/security.js.map +1 -0
- package/dist/src/dashboard/setup.d.ts +15 -0
- package/dist/src/dashboard/setup.d.ts.map +1 -1
- package/dist/src/dashboard/setup.js +20 -3
- package/dist/src/dashboard/setup.js.map +1 -1
- package/dist/src/dashboard/usage.js +1 -1
- package/dist/src/dashboard/usage.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/security/cfn-diff.d.ts +57 -0
- package/dist/src/security/cfn-diff.d.ts.map +1 -0
- package/dist/src/security/cfn-diff.js +112 -0
- package/dist/src/security/cfn-diff.js.map +1 -0
- package/dist/src/security/errors.d.ts +45 -0
- package/dist/src/security/errors.d.ts.map +1 -0
- package/dist/src/security/errors.js +116 -0
- package/dist/src/security/errors.js.map +1 -0
- package/dist/src/security/marker.d.ts +46 -0
- package/dist/src/security/marker.d.ts.map +1 -0
- package/dist/src/security/marker.js +120 -0
- package/dist/src/security/marker.js.map +1 -0
- package/dist/src/security/pentest-dockerfile.d.ts +8 -0
- package/dist/src/security/pentest-dockerfile.d.ts.map +1 -0
- package/dist/src/security/pentest-dockerfile.js +163 -0
- package/dist/src/security/pentest-dockerfile.js.map +1 -0
- package/dist/src/security/pentest.d.ts +233 -0
- package/dist/src/security/pentest.d.ts.map +1 -0
- package/dist/src/security/pentest.js +1057 -0
- package/dist/src/security/pentest.js.map +1 -0
- package/dist/src/security/repo.d.ts +25 -0
- package/dist/src/security/repo.d.ts.map +1 -0
- package/dist/src/security/repo.js +38 -0
- package/dist/src/security/repo.js.map +1 -0
- package/dist/src/security/review.d.ts +202 -0
- package/dist/src/security/review.d.ts.map +1 -0
- package/dist/src/security/review.js +706 -0
- package/dist/src/security/review.js.map +1 -0
- package/dist/src/security/setup.d.ts +193 -0
- package/dist/src/security/setup.d.ts.map +1 -0
- package/dist/src/security/setup.js +728 -0
- package/dist/src/security/setup.js.map +1 -0
- package/dist/src/security/threat-model.d.ts +133 -0
- package/dist/src/security/threat-model.d.ts.map +1 -0
- package/dist/src/security/threat-model.js +653 -0
- package/dist/src/security/threat-model.js.map +1 -0
- package/dist/src/utils/exec.d.ts +6 -0
- package/dist/src/utils/exec.d.ts.map +1 -1
- package/dist/src/utils/exec.js +12 -1
- package/dist/src/utils/exec.js.map +1 -1
- package/dist/src/utils/otel-sync-schedule.d.ts +19 -0
- package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -1
- package/dist/src/utils/otel-sync-schedule.js +24 -2
- package/dist/src/utils/otel-sync-schedule.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The temporary pentest TARGET environment, deployed per run by
|
|
3
|
+
* `prism-cli security pentest` (dockerfile adapter). Generalized from the
|
|
4
|
+
* hand-run spike stack (removed once this replaced it); see
|
|
5
|
+
* docs/DESIGN-prism-cli-pentest.md. Test target: cli/test/fixtures/pentest-sample.
|
|
6
|
+
*
|
|
7
|
+
* Private VPC only: private isolated subnets, no public subnet, no internet
|
|
8
|
+
* gateway, no NAT, no 0.0.0.0/0 ingress anywhere. The app runs on Fargate
|
|
9
|
+
* behind an INTERNAL ALB; the pentest agent's ENI reaches it over local VPC
|
|
10
|
+
* routing. VPC endpoints (ECR api+dkr, S3 gateway, CloudWatch Logs) let Fargate
|
|
11
|
+
* run with no internet path.
|
|
12
|
+
*
|
|
13
|
+
* Context (all from `cdk -c key=value`, set by the adapter):
|
|
14
|
+
* slug run id; names the stack's resources and the private zone
|
|
15
|
+
* appDir absolute path to the Docker build context -> image asset
|
|
16
|
+
* dockerfile Dockerfile path relative to appDir (default: Dockerfile)
|
|
17
|
+
* port container port the app listens on
|
|
18
|
+
* healthPath ALB health-check path
|
|
19
|
+
* zoneName private hosted-zone name (host is app.<zoneName>)
|
|
20
|
+
* ttlHours hours from synth for the prism:expires-at tag
|
|
21
|
+
*/
|
|
22
|
+
import * as cdk from 'aws-cdk-lib';
|
|
23
|
+
import * as ec2 from 'aws-cdk-lib/aws-ec2';
|
|
24
|
+
import * as ecs from 'aws-cdk-lib/aws-ecs';
|
|
25
|
+
import * as ecrAssets from 'aws-cdk-lib/aws-ecr-assets';
|
|
26
|
+
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
|
|
27
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
28
|
+
import * as logs from 'aws-cdk-lib/aws-logs';
|
|
29
|
+
import * as route53 from 'aws-cdk-lib/aws-route53';
|
|
30
|
+
import * as targets from 'aws-cdk-lib/aws-route53-targets';
|
|
31
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
32
|
+
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
33
|
+
import { Construct } from 'constructs';
|
|
34
|
+
|
|
35
|
+
const ALB_PORT = 80;
|
|
36
|
+
|
|
37
|
+
/** A JSON context value (the adapter passes env, secrets and actor ARNs this way); absent = fallback. */
|
|
38
|
+
function ctxJson<T>(scope: Construct, key: string, fallback: T): T {
|
|
39
|
+
const v = scope.node.tryGetContext(key);
|
|
40
|
+
if (v === undefined || v === null || v === '') return fallback;
|
|
41
|
+
return (typeof v === 'string' ? JSON.parse(v) : v) as T;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A Secrets Manager ARN with its random 6-character suffix is complete; without it, partial. */
|
|
45
|
+
const isCompleteSecretArn = (arn: string) => /-[A-Za-z0-9]{6}$/.test(arn);
|
|
46
|
+
|
|
47
|
+
function ctxStr(scope: Construct, key: string, fallback?: string): string {
|
|
48
|
+
const v = scope.node.tryGetContext(key);
|
|
49
|
+
if (v === undefined || v === null || v === '') {
|
|
50
|
+
if (fallback !== undefined) return fallback;
|
|
51
|
+
throw new Error(`pentest-cdk: required context "${key}" is not set`);
|
|
52
|
+
}
|
|
53
|
+
return String(v);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class PentestTargetStack extends cdk.Stack {
|
|
57
|
+
constructor(scope: Construct, id: string, props: cdk.StackProps) {
|
|
58
|
+
super(scope, id, props);
|
|
59
|
+
|
|
60
|
+
const slug = ctxStr(this, 'slug');
|
|
61
|
+
const appDir = ctxStr(this, 'appDir');
|
|
62
|
+
const port = Number(ctxStr(this, 'port', '8080'));
|
|
63
|
+
const healthPath = ctxStr(this, 'healthPath', '/health');
|
|
64
|
+
const zoneName = ctxStr(this, 'zoneName', `${slug}.prism.internal`);
|
|
65
|
+
const ttlHours = Number(ctxStr(this, 'ttlHours', '24'));
|
|
66
|
+
const logGroupName = `/aws/securityagent/prism-pentest-${slug}`;
|
|
67
|
+
|
|
68
|
+
cdk.Tags.of(this).add('prism:purpose', 'pentest');
|
|
69
|
+
cdk.Tags.of(this).add('prism:pentest-run', slug);
|
|
70
|
+
cdk.Tags.of(this).add('prism:expires-at', new Date(Date.now() + ttlHours * 3_600_000).toISOString());
|
|
71
|
+
|
|
72
|
+
// --- Network: private isolated subnets only (no IGW, no NAT) ---------
|
|
73
|
+
const vpc = new ec2.Vpc(this, 'Vpc', {
|
|
74
|
+
ipAddresses: ec2.IpAddresses.cidr('10.80.0.0/16'),
|
|
75
|
+
maxAzs: 2,
|
|
76
|
+
natGateways: 0,
|
|
77
|
+
subnetConfiguration: [{ name: 'private', subnetType: ec2.SubnetType.PRIVATE_ISOLATED, cidrMask: 24 }],
|
|
78
|
+
restrictDefaultSecurityGroup: true,
|
|
79
|
+
});
|
|
80
|
+
const privateSubnets = { subnetType: ec2.SubnetType.PRIVATE_ISOLATED };
|
|
81
|
+
|
|
82
|
+
const sg = (name: string, description: string) => new ec2.SecurityGroup(this, name, { vpc, description, allowAllOutbound: false });
|
|
83
|
+
const agentSg = sg('AgentSg', 'Pentest agent ENI: may reach the internal ALB on 80 only');
|
|
84
|
+
const albSg = sg('AlbSg', 'Internal ALB: accepts the pentest agent only');
|
|
85
|
+
const appSg = sg('AppSg', 'App tasks: accept the ALB only');
|
|
86
|
+
const endpointSg = sg('EndpointSg', 'VPC interface endpoints: accept the app tasks only');
|
|
87
|
+
|
|
88
|
+
agentSg.addEgressRule(albSg, ec2.Port.tcp(ALB_PORT), 'to the internal ALB');
|
|
89
|
+
albSg.addIngressRule(agentSg, ec2.Port.tcp(ALB_PORT), 'from the pentest agent');
|
|
90
|
+
appSg.addEgressRule(endpointSg, ec2.Port.tcp(443), 'to VPC interface endpoints');
|
|
91
|
+
endpointSg.addIngressRule(appSg, ec2.Port.tcp(443), 'from the app tasks');
|
|
92
|
+
|
|
93
|
+
vpc.addGatewayEndpoint('S3', { service: ec2.GatewayVpcEndpointAwsService.S3, subnets: [privateSubnets] });
|
|
94
|
+
const s3PrefixList = ec2.PrefixList.fromLookup(this, 'S3PrefixList', { prefixListName: `com.amazonaws.${this.region}.s3` });
|
|
95
|
+
appSg.addEgressRule(ec2.Peer.prefixList(s3PrefixList.prefixListId), ec2.Port.tcp(443), 'to S3 (ECR image layers)');
|
|
96
|
+
|
|
97
|
+
const appEnv = ctxJson<Record<string, string>>(this, 'env', {});
|
|
98
|
+
const appSecrets = ctxJson<Record<string, string>>(this, 'secrets', {});
|
|
99
|
+
const actorSecrets = ctxJson<string[]>(this, 'actorSecrets', []);
|
|
100
|
+
const actorLambdas = ctxJson<string[]>(this, 'actorLambdas', []);
|
|
101
|
+
|
|
102
|
+
const endpoints: [string, ec2.InterfaceVpcEndpointAwsService][] = [
|
|
103
|
+
['EcrApi', ec2.InterfaceVpcEndpointAwsService.ECR],
|
|
104
|
+
['EcrDkr', ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER],
|
|
105
|
+
['Logs', ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS],
|
|
106
|
+
];
|
|
107
|
+
// With no internet path, a task reads its secrets at start through this endpoint.
|
|
108
|
+
if (Object.keys(appSecrets).length) endpoints.push(['SecretsManager', ec2.InterfaceVpcEndpointAwsService.SECRETS_MANAGER]);
|
|
109
|
+
for (const [cid, service] of endpoints) {
|
|
110
|
+
vpc.addInterfaceEndpoint(cid, { service, subnets: privateSubnets, securityGroups: [endpointSg], open: false, privateDnsEnabled: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// --- App: Fargate behind an internal ALB -----------------------------
|
|
114
|
+
// dockerfile: path relative to appDir (the build context); may be in a subfolder.
|
|
115
|
+
const dockerfile = ctxStr(this, 'dockerfile', 'Dockerfile');
|
|
116
|
+
const image = new ecrAssets.DockerImageAsset(this, 'Image', { directory: appDir, file: dockerfile, platform: ecrAssets.Platform.LINUX_AMD64 });
|
|
117
|
+
const appLogs = new logs.LogGroup(this, 'AppLogs', { retention: logs.RetentionDays.ONE_WEEK, removalPolicy: cdk.RemovalPolicy.DESTROY });
|
|
118
|
+
const cluster = new ecs.Cluster(this, 'Cluster', { vpc });
|
|
119
|
+
const task = new ecs.FargateTaskDefinition(this, 'Task', {
|
|
120
|
+
cpu: 256, memoryLimitMiB: 512,
|
|
121
|
+
runtimePlatform: { cpuArchitecture: ecs.CpuArchitecture.X86_64, operatingSystemFamily: ecs.OperatingSystemFamily.LINUX },
|
|
122
|
+
});
|
|
123
|
+
task.addContainer('app', {
|
|
124
|
+
image: ecs.ContainerImage.fromDockerImageAsset(image),
|
|
125
|
+
portMappings: [{ containerPort: port }],
|
|
126
|
+
environment: { ...appEnv, PORT: String(port) },
|
|
127
|
+
// Injected by ECS at task start; the execution role is granted read on exactly these secrets.
|
|
128
|
+
secrets: Object.fromEntries(Object.entries(appSecrets).map(([name, arn], i) => [name, ecs.Secret.fromSecretsManager(
|
|
129
|
+
isCompleteSecretArn(arn) ? secretsmanager.Secret.fromSecretCompleteArn(this, `AppSecret${i}`, arn) : secretsmanager.Secret.fromSecretPartialArn(this, `AppSecret${i}`, arn),
|
|
130
|
+
)])),
|
|
131
|
+
logging: ecs.LogDrivers.awsLogs({ logGroup: appLogs, streamPrefix: 'app' }),
|
|
132
|
+
});
|
|
133
|
+
const service = new ecs.FargateService(this, 'Service', {
|
|
134
|
+
cluster, taskDefinition: task, desiredCount: 1, minHealthyPercent: 100,
|
|
135
|
+
assignPublicIp: false, vpcSubnets: privateSubnets, securityGroups: [appSg], circuitBreaker: { rollback: true },
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const alb = new elbv2.ApplicationLoadBalancer(this, 'Alb', {
|
|
139
|
+
vpc, internetFacing: false, vpcSubnets: privateSubnets, securityGroup: albSg, dropInvalidHeaderFields: true,
|
|
140
|
+
});
|
|
141
|
+
const listener = alb.addListener('Http', { port: ALB_PORT, protocol: elbv2.ApplicationProtocol.HTTP, open: false });
|
|
142
|
+
// Faster than the 5 x 30s default, so a new task turns healthy in ~20s; the
|
|
143
|
+
// command waits for a healthy target before starting the pentest.
|
|
144
|
+
const targetGroup = listener.addTargets('App', {
|
|
145
|
+
port, protocol: elbv2.ApplicationProtocol.HTTP, targets: [service],
|
|
146
|
+
healthCheck: { path: healthPath, interval: cdk.Duration.seconds(10), timeout: cdk.Duration.seconds(5), healthyThresholdCount: 2, unhealthyThresholdCount: 3 },
|
|
147
|
+
deregistrationDelay: cdk.Duration.seconds(10),
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// --- Private hostname -------------------------------------------------
|
|
151
|
+
const zone = new route53.PrivateHostedZone(this, 'Zone', { zoneName, vpc });
|
|
152
|
+
new route53.ARecord(this, 'AppRecord', { zone, recordName: 'app', target: route53.RecordTarget.fromAlias(new targets.LoadBalancerTarget(alb)) });
|
|
153
|
+
|
|
154
|
+
// --- Source zip bucket and agent log group ---------------------------
|
|
155
|
+
const source = new s3.Bucket(this, 'Source', {
|
|
156
|
+
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, encryption: s3.BucketEncryption.S3_MANAGED,
|
|
157
|
+
enforceSSL: true, removalPolicy: cdk.RemovalPolicy.DESTROY, autoDeleteObjects: true,
|
|
158
|
+
});
|
|
159
|
+
const agentLogs = new logs.LogGroup(this, 'AgentLogs', { logGroupName, retention: logs.RetentionDays.ONE_WEEK, removalPolicy: cdk.RemovalPolicy.DESTROY });
|
|
160
|
+
|
|
161
|
+
// --- Pentest service role (scoped ENI permissions; spike-confirmed) ---
|
|
162
|
+
const subnetArns = vpc.isolatedSubnets.map((s) => this.formatArn({ service: 'ec2', resource: 'subnet', resourceName: s.subnetId }));
|
|
163
|
+
const agentSgArn = this.formatArn({ service: 'ec2', resource: 'security-group', resourceName: agentSg.securityGroupId });
|
|
164
|
+
const eniArn = this.formatArn({ service: 'ec2', resource: 'network-interface', resourceName: '*' });
|
|
165
|
+
|
|
166
|
+
const role = new iam.Role(this, 'ServiceRole', {
|
|
167
|
+
assumedBy: new iam.ServicePrincipal('securityagent.amazonaws.com', { conditions: { StringEquals: { 'aws:SourceAccount': this.account } } }),
|
|
168
|
+
description: 'prism-cli security pentest: Security Agent service role for one private VPC pentest',
|
|
169
|
+
});
|
|
170
|
+
role.addToPolicy(new iam.PolicyStatement({
|
|
171
|
+
sid: 'DescribeNetwork',
|
|
172
|
+
actions: ['ec2:DescribeDhcpOptions', 'ec2:DescribeNetworkInterfaces', 'ec2:DescribeNetworkInterfaceAttribute', 'ec2:DescribeSubnets', 'ec2:DescribeSecurityGroups', 'ec2:DescribeVpcs'],
|
|
173
|
+
resources: ['*'],
|
|
174
|
+
}));
|
|
175
|
+
role.addToPolicy(new iam.PolicyStatement({ sid: 'EniCreateScoped', actions: ['ec2:CreateNetworkInterface'], resources: [eniArn, agentSgArn, ...subnetArns] }));
|
|
176
|
+
role.addToPolicy(new iam.PolicyStatement({ sid: 'EniManageScoped', actions: ['ec2:ModifyNetworkInterfaceAttribute', 'ec2:DeleteNetworkInterface'], resources: [eniArn, agentSgArn], conditions: { StringEquals: { 'ec2:Vpc': vpc.vpcArn } } }));
|
|
177
|
+
role.addToPolicy(new iam.PolicyStatement({ sid: 'EniPermission', actions: ['ec2:CreateNetworkInterfacePermission'], resources: [eniArn], conditions: { ArnEquals: { 'ec2:Subnet': subnetArns } } }));
|
|
178
|
+
// Logs: create/describe the configured group (spike: PREFLIGHT fails CLIENT_ERROR without CreateLogGroup on the group ARN).
|
|
179
|
+
role.addToPolicy(new iam.PolicyStatement({ sid: 'LogsGroup', actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', 'logs:DescribeLogStreams'], resources: [
|
|
180
|
+
// logGroupArn already ends in ':*', which does NOT match the bare group ARN
|
|
181
|
+
// CreateLogGroup is authorized against (the spike's second PREFLIGHT failure).
|
|
182
|
+
this.formatArn({ service: 'logs', resource: 'log-group', resourceName: logGroupName, arnFormat: cdk.ArnFormat.COLON_RESOURCE_NAME }),
|
|
183
|
+
agentLogs.logGroupArn,
|
|
184
|
+
] }));
|
|
185
|
+
role.addToPolicy(new iam.PolicyStatement({ sid: 'LogsDescribe', actions: ['logs:DescribeLogGroups'], resources: ['*'] }));
|
|
186
|
+
source.grantRead(role);
|
|
187
|
+
// Test actors (.prism/pentest.json "actors"): the agent reads their credentials with this role.
|
|
188
|
+
actorSecrets.forEach((arn, i) => (isCompleteSecretArn(arn)
|
|
189
|
+
? secretsmanager.Secret.fromSecretCompleteArn(this, `ActorSecret${i}`, arn)
|
|
190
|
+
: secretsmanager.Secret.fromSecretPartialArn(this, `ActorSecret${i}`, arn)).grantRead(role));
|
|
191
|
+
if (actorLambdas.length) role.addToPolicy(new iam.PolicyStatement({ sid: 'ActorCredentials', actions: ['lambda:InvokeFunction'], resources: actorLambdas }));
|
|
192
|
+
|
|
193
|
+
const out = (oid: string, value: string) => new cdk.CfnOutput(this, oid, { value });
|
|
194
|
+
out('VpcArn', vpc.vpcArn);
|
|
195
|
+
out('SubnetArns', cdk.Fn.join(',', subnetArns));
|
|
196
|
+
out('AgentSecurityGroupArn', agentSgArn);
|
|
197
|
+
out('AlbDnsName', alb.loadBalancerDnsName);
|
|
198
|
+
out('PrivateHost', `app.${zoneName}`);
|
|
199
|
+
out('ServiceRoleArn', role.roleArn);
|
|
200
|
+
out('SourceBucket', source.bucketName);
|
|
201
|
+
out('AgentLogGroup', agentLogs.logGroupName);
|
|
202
|
+
out('TargetGroupArn', targetGroup.targetGroupArn);
|
|
203
|
+
out('AppLogGroup', appLogs.logGroupName);
|
|
204
|
+
out('ExpiresAt', new Date(Date.now() + ttlHours * 3_600_000).toISOString());
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "prism-pentest-target-cdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"cdk": "cdk"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"aws-cdk-lib": "^2.265.0",
|
|
10
|
+
"constructs": "^10.4.2"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"@types/node": "^20.17.0",
|
|
14
|
+
"aws-cdk": "^2.1000.0",
|
|
15
|
+
"ts-node": "^10.9.2",
|
|
16
|
+
"typescript": "~5.6.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -12,17 +12,127 @@ export interface Finding {
|
|
|
12
12
|
file: string;
|
|
13
13
|
line: number | null;
|
|
14
14
|
message: string;
|
|
15
|
+
/** security-review / security-pentest: the Security Agent risk level (CRITICAL ... UNKNOWN), finding title, CWE and id. */
|
|
16
|
+
risk_level?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
cwe?: string | null;
|
|
19
|
+
finding_id?: string;
|
|
20
|
+
/** security-review only: the path exactly as the service reported it (file is repo-relative). */
|
|
21
|
+
raw_file?: string;
|
|
22
|
+
/** security-threat-model only: the threat's id, STRIDE categories, mitigation and every evidence path (repo-relative). */
|
|
23
|
+
threat_id?: string;
|
|
24
|
+
stride?: string[];
|
|
25
|
+
recommendation?: string;
|
|
26
|
+
evidence?: string[];
|
|
27
|
+
/** security-pentest only: the agent's confidence (HIGH | MEDIUM | LOW | FALSE_POSITIVE). */
|
|
28
|
+
confidence?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `secrets` = gitleaks; `review` = the reviewer (kiro-cli / Claude Code);
|
|
32
|
+
* `security-review` = an AWS Security Agent code review job;
|
|
33
|
+
* `security-threat-model` = an AWS Security Agent threat model job;
|
|
34
|
+
* `security-pentest` = an AWS Security Agent penetration test job.
|
|
35
|
+
*/
|
|
36
|
+
export type ResultKind = 'secrets' | 'review' | 'security-review' | 'security-threat-model' | 'security-pentest';
|
|
37
|
+
/** security-threat-model only: the job behind the result. */
|
|
38
|
+
export interface ThreatModelInfo {
|
|
39
|
+
job_id: string;
|
|
40
|
+
threat_model_id: string;
|
|
41
|
+
agent_space_id: string;
|
|
42
|
+
region: string;
|
|
43
|
+
account?: string;
|
|
44
|
+
job_status: string;
|
|
45
|
+
/** Threats per severity (CRITICAL ... INFO). */
|
|
46
|
+
counts: Record<string, number>;
|
|
47
|
+
/** Threats per STRIDE category. */
|
|
48
|
+
stride_counts: Record<string, number>;
|
|
49
|
+
/** Repo paths of the scope docs, as read from the commit. */
|
|
50
|
+
scope_docs: string[];
|
|
51
|
+
/** The agent's system overview, in full; null until the job completes. */
|
|
52
|
+
system_overview: string | null;
|
|
53
|
+
service_created_at?: string | null;
|
|
54
|
+
service_updated_at?: string | null;
|
|
55
|
+
}
|
|
56
|
+
/** security-review only: the job behind the result. */
|
|
57
|
+
export interface SecurityReviewInfo {
|
|
58
|
+
job_id: string;
|
|
59
|
+
code_review_id: string;
|
|
60
|
+
agent_space_id: string;
|
|
61
|
+
region: string;
|
|
62
|
+
/** The AWS account the job ran in, so `security findings` only completes its own account's pending records. */
|
|
63
|
+
account?: string;
|
|
64
|
+
/** diff: the branch diff base...tip. full: the whole repo at tip. unknown: fetched later by `security findings`. */
|
|
65
|
+
scope: 'diff' | 'full' | 'unknown';
|
|
66
|
+
/**
|
|
67
|
+
* The commit the code review's source asset (repo/<slug>/latest.zip) held
|
|
68
|
+
* when the job started: the code a diff job reads around the patch. null
|
|
69
|
+
* when unknown (a job `security findings` fetched with no pending record).
|
|
70
|
+
*/
|
|
71
|
+
context_commit?: string | null;
|
|
72
|
+
job_status: string;
|
|
73
|
+
/** Findings per Security Agent risk level. */
|
|
74
|
+
counts: Record<string, number>;
|
|
75
|
+
/** The service's job timestamps, and updatedAt - createdAt (queue plus run time), when it reported them. */
|
|
76
|
+
service_created_at?: string | null;
|
|
77
|
+
service_updated_at?: string | null;
|
|
78
|
+
service_duration_s?: number | null;
|
|
79
|
+
/** Our wall time from starting the job to seeing it finish (code-review only; includes polling). */
|
|
80
|
+
wall_s?: number | null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* security-pentest only: the penetration-test job behind the result, and the
|
|
84
|
+
* temporary environment it ran against. Mirrors SecurityReviewInfo; a pentest
|
|
85
|
+
* finding has no file/line, carries a `confidence`, and the environment handle
|
|
86
|
+
* is what `security pentest --cleanup` tears down.
|
|
87
|
+
*/
|
|
88
|
+
export interface PentestInfo {
|
|
89
|
+
job_id: string;
|
|
90
|
+
pentest_id: string;
|
|
91
|
+
agent_space_id: string;
|
|
92
|
+
/** True when this run created a dedicated agent space (teardown deletes it); false when it reused a shared one. */
|
|
93
|
+
agent_space_dedicated: boolean;
|
|
94
|
+
region: string;
|
|
95
|
+
/** The AWS account the job ran in, so findings only completes its own account's pending records. */
|
|
96
|
+
account?: string;
|
|
97
|
+
/** The verified target domain the pentest ran against (app.<zone>). */
|
|
98
|
+
target_host: string;
|
|
99
|
+
job_status: string;
|
|
100
|
+
/** Findings per Security Agent risk level, after dropping FALSE_POSITIVE confidence (unless --include-false-positives). */
|
|
101
|
+
counts: Record<string, number>;
|
|
102
|
+
/** First paragraph of the job's `overview` text, when the service reported one. */
|
|
103
|
+
overview?: string | null;
|
|
104
|
+
/** The CloudFormation stack and run slug of the temporary environment, for --cleanup. */
|
|
105
|
+
stack?: string | null;
|
|
106
|
+
slug?: string | null;
|
|
107
|
+
/** When the environment is set to auto-expire (the prism:expires-at tag), ISO. */
|
|
108
|
+
expires_at?: string | null;
|
|
109
|
+
/** The agent ENIs' security group id: teardown waits for its ENIs to drain before destroying the stack. */
|
|
110
|
+
agent_security_group_id?: string | null;
|
|
111
|
+
/** The app container's log group, for debugging hints. */
|
|
112
|
+
app_log_group?: string | null;
|
|
113
|
+
/** The PRIVATE_VPC target domain this run created; teardown deletes it. */
|
|
114
|
+
target_domain_id?: string | null;
|
|
115
|
+
/** Set when the last teardown left the stack up (destroy failed twice); --cleanup retries it. */
|
|
116
|
+
teardown_failed?: {
|
|
117
|
+
at: string;
|
|
118
|
+
reason: string;
|
|
119
|
+
} | null;
|
|
120
|
+
service_created_at?: string | null;
|
|
121
|
+
service_updated_at?: string | null;
|
|
122
|
+
service_duration_s?: number | null;
|
|
123
|
+
wall_s?: number | null;
|
|
15
124
|
}
|
|
16
|
-
/** `secrets` = gitleaks; `review` = the reviewer (kiro-cli / Claude Code). */
|
|
17
|
-
export type ResultKind = 'secrets' | 'review';
|
|
18
125
|
export type ResultHook = 'pre-commit' | 'pre-push' | 'ci' | 'manual';
|
|
19
126
|
/**
|
|
20
127
|
* ok ran, nothing found
|
|
21
128
|
* findings ran, found something
|
|
22
129
|
* error could not produce a verdict (tool missing, crashed, unparseable output)
|
|
23
130
|
* skipped did not run: no changes to review, or the hook was bypassed (`--no-verify`)
|
|
131
|
+
* pending security-review / security-pentest: the job was started and has no
|
|
132
|
+
* verdict yet. finished_at equals started_at until the record is
|
|
133
|
+
* completed in place.
|
|
24
134
|
*/
|
|
25
|
-
export type ResultStatus = 'ok' | 'findings' | 'error' | 'skipped';
|
|
135
|
+
export type ResultStatus = 'ok' | 'findings' | 'error' | 'skipped' | 'pending';
|
|
26
136
|
export interface PrismResult {
|
|
27
137
|
schema_version: typeof RESULT_SCHEMA_VERSION;
|
|
28
138
|
kind: ResultKind;
|
|
@@ -55,6 +165,12 @@ export interface PrismResult {
|
|
|
55
165
|
* consumers (the dashboard, CI) match on exactly: see REASON_*.
|
|
56
166
|
*/
|
|
57
167
|
reason: string | null;
|
|
168
|
+
/** Present on kind security-review. */
|
|
169
|
+
security?: SecurityReviewInfo;
|
|
170
|
+
/** Present on kind security-threat-model. */
|
|
171
|
+
threat_model?: ThreatModelInfo;
|
|
172
|
+
/** Present on kind security-pentest. */
|
|
173
|
+
pentest?: PentestInfo;
|
|
58
174
|
}
|
|
59
175
|
export type ResultInit = Omit<PrismResult, 'schema_version' | 'tool_version' | 'model' | 'commit' | 'tree' | 'branch' | 'upstream' | 'base' | 'summary' | 'score' | 'reason' | 'findings'> & Partial<Pick<PrismResult, 'tool_version' | 'model' | 'commit' | 'tree' | 'branch' | 'upstream' | 'base' | 'summary' | 'score' | 'reason' | 'findings'>>;
|
|
60
176
|
export declare function makeResult(init: ResultInit): PrismResult;
|
|
@@ -76,7 +192,11 @@ export declare function resultFileName(r: PrismResult): string;
|
|
|
76
192
|
* clean without touching any tracked file. Outside a git repo it does nothing.
|
|
77
193
|
*/
|
|
78
194
|
export declare function ensureResultsExcluded(repoRoot: string): boolean;
|
|
79
|
-
|
|
195
|
+
/**
|
|
196
|
+
* `id` (a ResultEntry id) rewrites that existing file in place instead of
|
|
197
|
+
* naming a new one: how a pending security-review record is completed.
|
|
198
|
+
*/
|
|
199
|
+
export declare function writeResult(repoRoot: string, r: PrismResult, id?: string): string;
|
|
80
200
|
export interface ResultEntry {
|
|
81
201
|
/** File name without `.json`: the result's stable id (used by report links). */
|
|
82
202
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/codewatch/results.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,qBAAqB,IAAI,CAAC;AACvC,eAAO,MAAM,WAAW,mBAAmB,CAAC;AAE5C,8FAA8F;AAC9F,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAE1D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AACjD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,eAAe,CAAC;IAC1B,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/codewatch/results.ts"],"names":[],"mappings":"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"}
|
|
@@ -72,7 +72,13 @@ export function ensureResultsExcluded(repoRoot) {
|
|
|
72
72
|
appendFileSync(p.stdout, `${prefix}# prism-cli codewatch results (local)\n/${RESULTS_DIR}/\n`);
|
|
73
73
|
return true;
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
/**
|
|
76
|
+
* `id` (a ResultEntry id) rewrites that existing file in place instead of
|
|
77
|
+
* naming a new one: how a pending security-review record is completed.
|
|
78
|
+
*/
|
|
79
|
+
export function writeResult(repoRoot, r, id) {
|
|
80
|
+
if (id !== undefined && !/^[A-Za-z0-9_-]{1,200}$/.test(id))
|
|
81
|
+
throw new Error(`invalid result id: ${id}`);
|
|
76
82
|
const dir = resolve(repoRoot, RESULTS_DIR);
|
|
77
83
|
if (!fileExists(dir)) {
|
|
78
84
|
try {
|
|
@@ -81,7 +87,7 @@ export function writeResult(repoRoot, r) {
|
|
|
81
87
|
catch { /* never fail a write over this */ }
|
|
82
88
|
}
|
|
83
89
|
mkdirSync(dir, { recursive: true });
|
|
84
|
-
const dest = join(dir, resultFileName(r));
|
|
90
|
+
const dest = join(dir, id !== undefined ? `${id}.json` : resultFileName(r));
|
|
85
91
|
const tmp = `${dest}.${process.pid}.tmp`;
|
|
86
92
|
writeFileSync(tmp, JSON.stringify(r, null, 2) + '\n', { mode: 0o600 });
|
|
87
93
|
renameSync(tmp, dest);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/codewatch/results.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,UAAU,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAE5C,8FAA8F;AAC9F,MAAM,CAAC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/codewatch/results.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare const PACKAGE_NAME = "@prism-d1/cli";
|
|
2
|
+
export interface Install {
|
|
3
|
+
/** The PATH entry. */
|
|
4
|
+
path: string;
|
|
5
|
+
/** Where it resolves after symlinks. */
|
|
6
|
+
realpath: string;
|
|
7
|
+
/** From the package.json next to it; null when it cannot be found. */
|
|
8
|
+
version: string | null;
|
|
9
|
+
/** True when it is this running CLI. */
|
|
10
|
+
isThis: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface VersionReport {
|
|
13
|
+
schema: 'prism.version.v1';
|
|
14
|
+
version: string;
|
|
15
|
+
node: string;
|
|
16
|
+
latest: string | null;
|
|
17
|
+
updateAvailable: boolean | null;
|
|
18
|
+
/** Why latest is null: 'offline', or the npm failure. */
|
|
19
|
+
latestNote: string | null;
|
|
20
|
+
onPath: Install[];
|
|
21
|
+
warnings: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface VersionDeps {
|
|
24
|
+
/** The directory holding this CLI's package.json. */
|
|
25
|
+
ownPackageDir: string;
|
|
26
|
+
pathEnv: string;
|
|
27
|
+
/** `npm view @prism-d1/cli version`: the version, or an error message. */
|
|
28
|
+
npmLatest: () => {
|
|
29
|
+
version: string | null;
|
|
30
|
+
error?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Walks up from `start` to the package.json of @prism-d1/cli, at most 6 levels. */
|
|
34
|
+
export declare function findPackageDir(start: string): string | null;
|
|
35
|
+
/** -1, 0 or 1, comparing dotted numeric versions; pre-release tags are ignored. */
|
|
36
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
37
|
+
/**
|
|
38
|
+
* Every prism-cli on PATH, in PATH order, deduplicated by real path (e.g.
|
|
39
|
+
* /bin -> /usr/bin).
|
|
40
|
+
*
|
|
41
|
+
* shortcut: on Windows, npm's .cmd shims do not resolve to their package, so
|
|
42
|
+
* other installs there show version unknown; parse the shim if that matters.
|
|
43
|
+
*/
|
|
44
|
+
export declare function installsOnPath(pathEnv: string, ownPackageDir: string): Install[];
|
|
45
|
+
export declare function buildReport(opts: {
|
|
46
|
+
offline?: boolean;
|
|
47
|
+
}, d: VersionDeps): VersionReport;
|
|
48
|
+
export declare function defaultDeps(): VersionDeps;
|
|
49
|
+
export declare function printReport(r: VersionReport, log?: (l: string) => void): void;
|
|
50
|
+
declare const _default: {
|
|
51
|
+
description: string;
|
|
52
|
+
options: {
|
|
53
|
+
flags: string;
|
|
54
|
+
description: string;
|
|
55
|
+
}[];
|
|
56
|
+
action(opts: {
|
|
57
|
+
json?: boolean;
|
|
58
|
+
offline?: boolean;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
};
|
|
61
|
+
export default _default;
|
|
62
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../../src/commands/_top/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAK5C,MAAM,WAAW,OAAO;IACtB,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,wCAAwC;IACxC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,yDAAyD;IACzD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,OAAO,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,SAAS,EAAE,MAAM;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc3D;AAWD,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,EAAE,CAoBhF;AAMD,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,CAAC,EAAE,WAAW,GAAG,aAAa,CA4BtF;AAeD,wBAAgB,WAAW,IAAI,WAAW,CAMzC;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,EAAE,GAAG,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAO1F;;;;;;;iBAQoB;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;;AAN1D,wBAWE"}
|