Skip to content

Commit 373bce5

Browse files
krokokobgagentcursoragentisadeks
authored
chore(cdk): clean no-magic-numbers baseline and flip rule to error (aws-samples#312) (aws-samples#340)
* chore(cdk): clean no-magic-numbers baseline and flip rule to error (aws-samples#312) Promote inline numeric literals across CDK constructs and handlers to named module constants, then make @typescript-eslint/no-magic-numbers blocking to match CLI enforcement from aws-samples#258. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(cdk): extract Lambda memory sizes and orchestrator timeout to constants Address PR aws-samples#340 review feedback by promoting remaining memorySize literals and the orchestrator 60s timeout to named module constants, reusing CEDAR_WASM_MIN_LAMBDA_MEMORY_MB for GetPoliciesFn. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(deps): pin js-yaml to 4.2.0 via yarn resolution Force js-yaml 4.2.0 to remediate GHSA-h67p-54hq-rp68 pulled in transitively by @istanbuljs/load-nyc-config, unblocking security:deps CI. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: bgagent <bgagent@noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Sphia Sadek <isadeks@gmail.com>
1 parent a94959e commit 373bce5

55 files changed

Lines changed: 509 additions & 185 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cdk/eslint.config.mjs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ export default [
158158
// TypeScript rules
159159
// AI007 guard (#258): inline numeric literals should be named constants.
160160
// Values shared across Python/TypeScript belong in contracts/constants.json
161-
// (see contracts/constants.md). Advisory ('warn') until the existing
162-
// baseline is cleaned up, then this becomes 'error' like in cli/.
163-
'@typescript-eslint/no-magic-numbers': ['warn', {
161+
// (see contracts/constants.md). Baseline cleaned in #312; blocking like cli/.
162+
'@typescript-eslint/no-magic-numbers': ['error', {
164163
ignore: [
165164
// Identity / trivial arithmetic
166165
-1, 0, 1, 2,

cdk/src/constructs/agent-memory.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import type * as iam from 'aws-cdk-lib/aws-iam';
2323
import { NagSuppressions } from 'cdk-nag';
2424
import { Construct } from 'constructs';
2525

26+
/** Default short-term memory event expiration (days). */
27+
const DEFAULT_EXPIRATION_DAYS = 365;
28+
2629
/**
2730
* Properties for the AgentMemory construct.
2831
*/
@@ -72,7 +75,7 @@ export class AgentMemory extends Construct {
7275
this.memory = new agentcore.Memory(this, 'Memory', {
7376
memoryName: props?.memoryName,
7477
description: 'Cross-task interaction memory for background coding agents',
75-
expirationDuration: props?.expirationDuration ?? Duration.days(365),
78+
expirationDuration: props?.expirationDuration ?? Duration.days(DEFAULT_EXPIRATION_DAYS),
7679
memoryStrategies: [
7780
agentcore.MemoryStrategy.usingSemantic({
7881
strategyName: 'SemanticKnowledge',

cdk/src/constructs/agent-vpc.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import * as logs from 'aws-cdk-lib/aws-logs';
2323
import { NagSuppressions } from 'cdk-nag';
2424
import { Construct } from 'constructs';
2525

26+
/** HTTPS port — the only egress allowed from the Runtime ENIs. */
27+
const HTTPS_PORT = 443;
28+
2629
/**
2730
* Properties for the AgentVpc construct.
2831
*/
@@ -113,7 +116,7 @@ export class AgentVpc extends Construct {
113116

114117
this.runtimeSecurityGroup.addEgressRule(
115118
ec2.Peer.anyIpv4(),
116-
ec2.Port.tcp(443),
119+
ec2.Port.tcp(HTTPS_PORT),
117120
'Allow HTTPS egress (GitHub + package registries via NAT, AWS services via endpoints)',
118121
);
119122

cdk/src/constructs/approval-metrics-publisher-consumer.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ import * as sqs from 'aws-cdk-lib/aws-sqs';
2828
import { NagSuppressions } from 'cdk-nag';
2929
import { Construct } from 'constructs';
3030

31+
/** DLQ message retention for persistent-failure records (days). */
32+
const DLQ_RETENTION_DAYS = 14;
33+
34+
/** Max batching window before the Lambda is invoked on a partial batch (seconds). */
35+
const DEFAULT_MAX_BATCHING_WINDOW_SECONDS = 5;
36+
37+
/** Approval-metrics publisher Lambda memory (MB). */
38+
const PUBLISHER_MEMORY_MB = 256;
39+
3140
/**
3241
* Properties for ``ApprovalMetricsPublisherConsumer`` — the Chunk 8
3342
* consumer that reads ``TaskEventsTable`` via DynamoDB Streams and
@@ -97,7 +106,7 @@ export class ApprovalMetricsPublisherConsumer extends Construct {
97106
// Chunk 10 follow-ups — until a notification channel is wired
98107
// to SNS, an alarm on ``ApproximateNumberOfMessagesVisible``
99108
// would fire into the void.
100-
retentionPeriod: Duration.days(14),
109+
retentionPeriod: Duration.days(DLQ_RETENTION_DAYS),
101110
enforceSSL: true,
102111
});
103112

@@ -121,7 +130,7 @@ export class ApprovalMetricsPublisherConsumer extends Construct {
121130
// lines) — 256 MB is more than enough. Timeout is 1 minute to
122131
// match fanout; actual invocations should finish in tens of ms.
123132
timeout: Duration.minutes(1),
124-
memorySize: 256,
133+
memorySize: PUBLISHER_MEMORY_MB,
125134
logGroup,
126135
bundling: {
127136
externalModules: ['@aws-sdk/*'],
@@ -146,7 +155,7 @@ export class ApprovalMetricsPublisherConsumer extends Construct {
146155
this.fn.addEventSource(new DynamoEventSource(props.taskEventsTable, {
147156
startingPosition: StartingPosition.LATEST,
148157
batchSize: props.batchSize ?? 100,
149-
maxBatchingWindow: props.maxBatchingWindow ?? Duration.seconds(5),
158+
maxBatchingWindow: props.maxBatchingWindow ?? Duration.seconds(DEFAULT_MAX_BATCHING_WINDOW_SECONDS),
150159
retryAttempts: 3,
151160
onFailure: new SqsDlq(this.dlq),
152161
reportBatchItemFailures: true,

cdk/src/constructs/attachments-bucket.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import { Construct } from 'constructs';
2424
/** Lifecycle expiry for task attachments — matches task record retention. */
2525
export const ATTACHMENT_TTL_DAYS = 90;
2626

27+
/** Noncurrent version expiry — covers the longest-running tasks. */
28+
const NONCURRENT_VERSION_TTL_DAYS = 7;
29+
2730
/** S3 key prefix for all attachments. Layout: attachments/<user_id>/<task_id>/<attachment_id>/<filename> */
2831
export const ATTACHMENT_OBJECT_KEY_PREFIX = 'attachments/';
2932

@@ -77,7 +80,7 @@ export class AttachmentsBucket extends Construct {
7780
id: 'attachments-ttl',
7881
enabled: true,
7982
expiration: Duration.days(ATTACHMENT_TTL_DAYS),
80-
noncurrentVersionExpiration: Duration.days(7),
83+
noncurrentVersionExpiration: Duration.days(NONCURRENT_VERSION_TTL_DAYS),
8184
abortIncompleteMultipartUploadAfter: Duration.days(1),
8285
},
8386
],

cdk/src/constructs/blueprint.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ const DOMAIN_PATTERN = /^(\*\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9
3939
const APPROVAL_GATE_CAP_MIN = sharedConstants.approval_gate_cap.min;
4040
const APPROVAL_GATE_CAP_MAX = sharedConstants.approval_gate_cap.max;
4141

42+
/** Timeout for the RepoConfig custom resource (minutes). */
43+
const REPO_CONFIG_CR_TIMEOUT_MINUTES = 5;
44+
45+
/** TTL (days) applied to a RepoConfig row on blueprint delete before cleanup. */
46+
const REMOVED_REPO_TTL_DAYS = 30;
47+
4248
/**
4349
* Properties for the Blueprint construct.
4450
*/
@@ -244,7 +250,7 @@ export class Blueprint extends Construct {
244250
}
245251

246252
new cr.AwsCustomResource(this, 'RepoConfigCR', {
247-
timeout: Duration.minutes(5),
253+
timeout: Duration.minutes(REPO_CONFIG_CR_TIMEOUT_MINUTES),
248254
onCreate: {
249255
service: 'DynamoDB',
250256
action: 'putItem',
@@ -289,7 +295,7 @@ export class Blueprint extends Construct {
289295
ExpressionAttributeValues: {
290296
':removed': { S: 'removed' },
291297
':now': { S: new Date().toISOString() },
292-
':ttl': { N: String(Math.floor(Date.now() / 1000) + 30 * 86400) },
298+
':ttl': { N: String(Math.floor(Date.now() / 1000) + REMOVED_REPO_TTL_DAYS * 86400) },
293299
},
294300
},
295301
},

cdk/src/constructs/concurrency-reconciler.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
2727
import { NagSuppressions } from 'cdk-nag';
2828
import { Construct } from 'constructs';
2929

30+
/** Reconciler Lambda timeout (minutes). */
31+
const RECONCILER_TIMEOUT_MINUTES = 5;
32+
33+
/** Default reconciliation schedule interval (minutes). */
34+
const DEFAULT_SCHEDULE_MINUTES = 15;
35+
36+
/** Reconciler Lambda memory (MB). */
37+
const RECONCILER_MEMORY_MB = 256;
38+
3039
/**
3140
* Properties for ConcurrencyReconciler construct.
3241
*/
@@ -66,8 +75,8 @@ export class ConcurrencyReconciler extends Construct {
6675
handler: 'handler',
6776
runtime: Runtime.NODEJS_24_X,
6877
architecture: Architecture.ARM_64,
69-
timeout: Duration.minutes(5),
70-
memorySize: 256,
78+
timeout: Duration.minutes(RECONCILER_TIMEOUT_MINUTES),
79+
memorySize: RECONCILER_MEMORY_MB,
7180
environment: {
7281
TASK_TABLE_NAME: props.taskTable.tableName,
7382
USER_CONCURRENCY_TABLE_NAME: props.userConcurrencyTable.tableName,
@@ -80,7 +89,7 @@ export class ConcurrencyReconciler extends Construct {
8089
props.taskTable.grantReadData(this.fn);
8190
props.userConcurrencyTable.grantReadWriteData(this.fn);
8291

83-
const schedule = props.schedule ?? Duration.minutes(15);
92+
const schedule = props.schedule ?? Duration.minutes(DEFAULT_SCHEDULE_MINUTES);
8493
const rule = new events.Rule(this, 'ReconcilerSchedule', {
8594
schedule: events.Schedule.rate(schedule),
8695
});

cdk/src/constructs/ecs-agent-cluster.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ const BEDROCK_MODEL_IDS = [
6262
'anthropic.claude-haiku-4-5-20251001-v1:0',
6363
];
6464

65+
/** HTTPS port — the only egress allowed from the agent task ENIs. */
66+
const HTTPS_PORT = 443;
67+
6568
export class EcsAgentCluster extends Construct {
6669
public readonly cluster: ecs.Cluster;
6770
public readonly taskDefinition: ecs.FargateTaskDefinition;
@@ -90,7 +93,7 @@ export class EcsAgentCluster extends Construct {
9093

9194
this.securityGroup.addEgressRule(
9295
ec2.Peer.anyIpv4(),
93-
ec2.Port.tcp(443),
96+
ec2.Port.tcp(HTTPS_PORT),
9497
'Allow HTTPS egress (GitHub API, AWS services)',
9598
);
9699

cdk/src/constructs/fanout-consumer.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ import * as sqs from 'aws-cdk-lib/aws-sqs';
3131
import { NagSuppressions } from 'cdk-nag';
3232
import { Construct } from 'constructs';
3333

34+
/** DLQ message retention for persistent-failure records (days). */
35+
const DLQ_RETENTION_DAYS = 14;
36+
37+
/** Max batching window before the Lambda is invoked on a partial batch (seconds). */
38+
const DEFAULT_MAX_BATCHING_WINDOW_SECONDS = 5;
39+
40+
/** DLQ-depth alarm metric period (minutes). */
41+
const DLQ_ALARM_PERIOD_MINUTES = 5;
42+
43+
/** Fan-out consumer Lambda memory (MB). */
44+
const FANOUT_MEMORY_MB = 256;
45+
3446
/**
3547
* Properties for `FanOutConsumer` — the Phase 1b §8.9 fan-out plane
3648
* consumer that reads `TaskEventsTable` via DynamoDB Streams and
@@ -137,7 +149,7 @@ export class FanOutConsumer extends Construct {
137149
this.dlq = new sqs.Queue(this, 'FanOutDlq', {
138150
// Persistent failures (e.g., dispatcher throws non-caught error
139151
// five times in a row) land here for operator inspection.
140-
retentionPeriod: Duration.days(14),
152+
retentionPeriod: Duration.days(DLQ_RETENTION_DAYS),
141153
enforceSSL: true,
142154
});
143155

@@ -157,7 +169,7 @@ export class FanOutConsumer extends Construct {
157169
runtime: Runtime.NODEJS_24_X,
158170
architecture: Architecture.ARM_64,
159171
timeout: Duration.minutes(1),
160-
memorySize: 256,
172+
memorySize: FANOUT_MEMORY_MB,
161173
logGroup,
162174
bundling: {
163175
externalModules: ['@aws-sdk/*'],
@@ -226,7 +238,7 @@ export class FanOutConsumer extends Construct {
226238
// record means three Lambda retries already failed.
227239
this.dlqDepthAlarm = new cloudwatch.Alarm(this, 'FanOutDlqDepthAlarm', {
228240
metric: this.dlq.metricApproximateNumberOfMessagesVisible({
229-
period: Duration.minutes(5),
241+
period: Duration.minutes(DLQ_ALARM_PERIOD_MINUTES),
230242
statistic: 'Maximum',
231243
}),
232244
threshold: 1,
@@ -239,7 +251,7 @@ export class FanOutConsumer extends Construct {
239251
this.fn.addEventSource(new DynamoEventSource(props.taskEventsTable, {
240252
startingPosition: StartingPosition.LATEST,
241253
batchSize: props.batchSize ?? 100,
242-
maxBatchingWindow: props.maxBatchingWindow ?? Duration.seconds(5),
254+
maxBatchingWindow: props.maxBatchingWindow ?? Duration.seconds(DEFAULT_MAX_BATCHING_WINDOW_SECONDS),
243255
// Fan-out delivery is best-effort; don't block the stream if one
244256
// poisonous record blows up the Lambda. After 3 retries, send the
245257
// record batch to the DLQ and advance the iterator.

cdk/src/constructs/github-screenshot-integration.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ import { NagSuppressions } from 'cdk-nag';
3131
import { Construct } from 'constructs';
3232
import { ScreenshotBucket } from './screenshot-bucket';
3333

34+
/** Async screenshot-processor Lambda timeout (seconds). */
35+
const PROCESSOR_TIMEOUT_SECONDS = 120;
36+
37+
/** Async-invoke DLQ message retention (days). */
38+
const PROCESSOR_DLQ_RETENTION_DAYS = 14;
39+
40+
/** DLQ-depth alarm metric period (minutes). */
41+
const DLQ_ALARM_PERIOD_MINUTES = 5;
42+
43+
/** Async screenshot-processor Lambda memory (MB). */
44+
const PROCESSOR_MEMORY_MB = 512;
45+
3446
/**
3547
* Properties for GitHubScreenshotIntegration construct.
3648
*/
@@ -161,7 +173,7 @@ export class GitHubScreenshotIntegration extends Construct {
161173
// would otherwise vanish after Lambda's built-in async retries. The
162174
// DLQ keeps the failed invocation payload for operator inspection.
163175
const processorDlq = new sqs.Queue(this, 'WebhookProcessorDlq', {
164-
retentionPeriod: Duration.days(14),
176+
retentionPeriod: Duration.days(PROCESSOR_DLQ_RETENTION_DAYS),
165177
enforceSSL: true,
166178
});
167179

@@ -170,8 +182,8 @@ export class GitHubScreenshotIntegration extends Construct {
170182
handler: 'handler',
171183
runtime: Runtime.NODEJS_24_X,
172184
architecture: Architecture.ARM_64,
173-
timeout: Duration.seconds(120),
174-
memorySize: 512,
185+
timeout: Duration.seconds(PROCESSOR_TIMEOUT_SECONDS),
186+
memorySize: PROCESSOR_MEMORY_MB,
175187
deadLetterQueue: processorDlq,
176188
environment: {
177189
SCREENSHOT_BUCKET_NAME: this.screenshotBucket.bucket.bucketName,
@@ -197,7 +209,7 @@ export class GitHubScreenshotIntegration extends Construct {
197209
// threshold-1 shape as FanOutConsumer.dlqDepthAlarm.
198210
this.processorDlqDepthAlarm = new cloudwatch.Alarm(this, 'WebhookProcessorDlqDepthAlarm', {
199211
metric: processorDlq.metricApproximateNumberOfMessagesVisible({
200-
period: Duration.minutes(5),
212+
period: Duration.minutes(DLQ_ALARM_PERIOD_MINUTES),
201213
statistic: 'Maximum',
202214
}),
203215
threshold: 1,

0 commit comments

Comments
 (0)