@jaypie/mcp 0.8.64 → 0.8.65

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.
@@ -9,7 +9,7 @@ import { gt } from 'semver';
9
9
  /**
10
10
  * Docs Suite - Documentation services (skill, version, release_notes)
11
11
  */
12
- const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.64#0a1f765f"
12
+ const BUILD_VERSION_STRING = "@jaypie/mcp@0.8.65#58028ec6"
13
13
  ;
14
14
  const __filename$1 = fileURLToPath(import.meta.url);
15
15
  const __dirname$1 = path.dirname(__filename$1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaypie/mcp",
3
- "version": "0.8.64",
3
+ "version": "0.8.65",
4
4
  "description": "Jaypie MCP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,24 @@
1
+ ---
2
+ version: 1.2.60
3
+ date: 2026-06-04
4
+ summary: Validate WAF managedRuleOverrides/allow rule names at synth, throwing ConfigurationError on unknown names
5
+ ---
6
+
7
+ ## @jaypie/constructs 1.2.60
8
+
9
+ ### Fixed
10
+
11
+ - **WAF rule-name validation** (`JaypieDistribution`, `JaypieWebDeploymentBucket`).
12
+ `waf.allow` and `waf.managedRuleOverrides` rule names are now validated against
13
+ each AWS managed rule group at synth time. AWS WAF matches `RuleActionOverride`
14
+ on the exact rule **name** and silently ignores any name that matches no rule —
15
+ so a typo, or the label/name casing trap (label
16
+ `…:core-rule-set:NoUserAgent_Header` vs rule name `NoUserAgent_HEADER`), used to
17
+ produce a WebACL that looked correct but kept blocking. Jaypie now throws a
18
+ `ConfigurationError` listing the valid rule names for the group. Custom
19
+ (non-AWS) rule groups are not validated.
20
+
21
+ New helper `assertValidWafRuleNames` and the canonical `AWS_MANAGED_RULE_GROUPS`
22
+ map are exported from the package.
23
+
24
+ Issue: [#362](https://github.com/finlaysonstudio/jaypie/issues/362)
@@ -0,0 +1,17 @@
1
+ ---
2
+ version: 0.8.65
3
+ date: 2026-06-04
4
+ summary: Extract WAF guidance into a dedicated skill("waf") with allow prop and rule-name casing trap coverage
5
+ ---
6
+
7
+ ## Changed
8
+
9
+ - **New `waf` skill**. WAF guidance moved out of `skill("cdk")` into a dedicated
10
+ `skill("waf")`, mirroring how `dns`, `secrets`, and `streaming` are split out.
11
+ `skill("cdk")` keeps a one-line **See Also → `skill("waf")`** pointer.
12
+ - **`waf` skill** adds coverage of the `waf.allow` path-scoped relaxation prop
13
+ and the **rule name ≠ label casing trap** (label
14
+ `…:core-rule-set:NoUserAgent_Header` vs rule name `NoUserAgent_HEADER`), noting
15
+ that `@jaypie/constructs` now validates rule names at synth.
16
+
17
+ Issue: [#362](https://github.com/finlaysonstudio/jaypie/issues/362)
package/skills/agents.md CHANGED
@@ -34,7 +34,7 @@ Complete stack styles, techniques, and traditions.
34
34
 
35
35
  Contents: index, releasenotes
36
36
  Development: apikey, documentation, errors, llm, logs, mocks, monorepo, repokit, style, subpackages, tests, tools
37
- Infrastructure: apigateway, aws, cdk, cicd, datadog, dns, dynamodb, express, lambda, migrations, secrets, sqs, streaming, variables, web, websockets
37
+ Infrastructure: apigateway, aws, cdk, cicd, datadog, dns, dynamodb, express, lambda, migrations, secrets, sqs, streaming, variables, waf, web, websockets
38
38
  Patterns: api, fabric, handlers, models, services, vocabulary
39
39
  Recipes: recipe-api-server
40
40
  Meta: issues, jaypie, mcp, skills
package/skills/cdk.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: CDK constructs and deployment patterns
3
- related: apikey, aws, cicd, dynamodb, express, lambda, migrations, secrets, streaming, web, websockets
3
+ related: apikey, aws, cicd, dynamodb, express, lambda, migrations, secrets, streaming, waf, web, websockets
4
4
  ---
5
5
 
6
6
  # CDK Constructs
@@ -347,89 +347,13 @@ new JaypieDistribution(this, "Dist", {
347
347
 
348
348
  ## WAF (Web Application Firewall)
349
349
 
350
- `JaypieDistribution` attaches a WAFv2 WebACL by default with:
350
+ `JaypieDistribution` and `JaypieWebDeploymentBucket` attach a WAFv2 WebACL by
351
+ default (CommonRuleSet, KnownBadInputsRuleSet, IP rate limiting, and WAF logging
352
+ to S3 with Datadog forwarding).
351
353
 
352
- - **AWSManagedRulesCommonRuleSet** OWASP top 10 (SQLi, XSS, etc.)
353
- - **AWSManagedRulesKnownBadInputsRuleSet** known bad patterns (Log4j, etc.)
354
- - **Rate limiting** 2000 requests per 5 minutes per IP
355
- - **WAF logging** — S3 bucket with Datadog forwarder notifications
356
-
357
- ```typescript
358
- // Default: WAF enabled with logging
359
- new JaypieDistribution(this, "Dist", { handler });
360
-
361
- // Disable WAF entirely
362
- new JaypieDistribution(this, "Dist", { handler, waf: false });
363
-
364
- // Customize rate limit (name required on any waf config object)
365
- new JaypieDistribution(this, "Dist", {
366
- handler,
367
- waf: { name: "api", rateLimitPerIp: 500 },
368
- });
369
-
370
- // Multiple distributions in one env — set a unique waf.name on each to
371
- // avoid WebACL/S3 bucket name collisions between stacks.
372
- new JaypieDistribution(this, "Api", { handler: api, waf: { name: "api" } });
373
- new JaypieDistribution(this, "Mcp", { handler: mcp, waf: { name: "mcp" } });
374
-
375
- // Use existing WebACL
376
- new JaypieDistribution(this, "Dist", {
377
- handler,
378
- waf: { name: "api", webAclArn: "arn:aws:wafv2:..." },
379
- });
380
-
381
- // Disable WAF logging only
382
- new JaypieDistribution(this, "Dist", {
383
- handler,
384
- waf: { name: "api", logBucket: false },
385
- });
386
-
387
- // Bring your own WAF logging bucket
388
- new JaypieDistribution(this, "Dist", {
389
- handler,
390
- waf: { name: "api", logBucket: myWafBucket },
391
- });
392
-
393
- // Override specific managed rule actions (e.g., allow large request bodies)
394
- new JaypieDistribution(this, "Dist", {
395
- handler,
396
- waf: {
397
- name: "api",
398
- managedRuleOverrides: {
399
- AWSManagedRulesCommonRuleSet: [
400
- { name: "SizeRestrictions_BODY", actionToUse: { count: {} } },
401
- ],
402
- },
403
- },
404
- });
405
-
406
- // Scope a managed rule group to (or away from) specific URL patterns
407
- new JaypieDistribution(this, "Dist", {
408
- handler,
409
- waf: {
410
- name: "api",
411
- managedRuleScopeDowns: {
412
- // Only run the CommonRuleSet for paths OTHER than /chat — lets /chat
413
- // handle large AI-generated request bodies without weakening protection
414
- // elsewhere.
415
- AWSManagedRulesCommonRuleSet: {
416
- notStatement: {
417
- statement: {
418
- byteMatchStatement: {
419
- fieldToMatch: { uriPath: {} },
420
- positionalConstraint: "STARTS_WITH",
421
- searchString: "/chat",
422
- textTransformations: [{ priority: 0, type: "NONE" }],
423
- },
424
- },
425
- },
426
- },
427
- },
428
- },
429
- });
430
- ```
431
-
432
- Cost: $5/month per WebACL + $1/month per rule + $0.60 per million requests. Use `waf: false` to opt out.
354
+ See **`skill("waf")`** for configuration: `rateLimitPerIp`, `webAclArn`,
355
+ `logBucket`, `managedRuleOverrides`, `managedRuleScopeDowns`, the `allow`
356
+ path-scoped relaxation prop, and the rule-name label casing trap.
433
357
 
434
358
  ## Organization Trail Security Baseline
435
359
 
@@ -465,5 +389,6 @@ new JaypieOrganizationTrail(this, "OrgTrail", {
465
389
  - **`skill("secrets")`** - Secret management with JaypieEnvSecret
466
390
  - **`skill("streaming")`** - JaypieDistribution and JaypieNextJs streaming configuration
467
391
  - **`skill("variables")`** - Environment variables reference
392
+ - **`skill("waf")`** - WAF configuration, managed rule overrides, and the `allow` prop
468
393
  - **`skill("web")`** - JaypieWebDeploymentBucket and JaypieStaticWebBucket for static sites
469
394
  - **`skill("websockets")`** - JaypieWebSocket and JaypieWebSocketTable constructs
package/skills/skills.md CHANGED
@@ -17,7 +17,7 @@ Look up skills by alias: `mcp__jaypie__skill(alias)`
17
17
  |----------|--------|
18
18
  | contents | index, releasenotes |
19
19
  | development | apikey, documentation, errors, llm, logs, mocks, monorepo, repokit, style, subpackages, tests, tools |
20
- | infrastructure | apigateway, aws, cdk, cicd, datadog, dns, dynamodb, express, lambda, migrations, secrets, sqs, streaming, variables, web, websockets |
20
+ | infrastructure | apigateway, aws, cdk, cicd, datadog, dns, dynamodb, express, lambda, migrations, secrets, sqs, streaming, variables, waf, web, websockets |
21
21
  | patterns | api, fabric, handlers, models, services, vocabulary |
22
22
  | recipes | recipe-api-server |
23
23
  | meta | issues, jaypie, mcp, skills |
package/skills/waf.md ADDED
@@ -0,0 +1,154 @@
1
+ ---
2
+ description: WAF (Web Application Firewall) configuration for JaypieDistribution
3
+ related: aws, cdk, web
4
+ ---
5
+
6
+ # WAF (Web Application Firewall)
7
+
8
+ `JaypieDistribution` (and `JaypieWebDeploymentBucket`) attach a WAFv2 WebACL by
9
+ default with:
10
+
11
+ - **AWSManagedRulesCommonRuleSet** — OWASP top 10 (SQLi, XSS, etc.)
12
+ - **AWSManagedRulesKnownBadInputsRuleSet** — known bad patterns (Log4j, etc.)
13
+ - **Rate limiting** — 2000 requests per 5 minutes per IP
14
+ - **WAF logging** — S3 bucket with Datadog forwarder notifications
15
+
16
+ ```typescript
17
+ // Default: WAF enabled with logging
18
+ new JaypieDistribution(this, "Dist", { handler });
19
+
20
+ // Disable WAF entirely
21
+ new JaypieDistribution(this, "Dist", { handler, waf: false });
22
+
23
+ // Customize rate limit (name required on any waf config object)
24
+ new JaypieDistribution(this, "Dist", {
25
+ handler,
26
+ waf: { name: "api", rateLimitPerIp: 500 },
27
+ });
28
+
29
+ // Multiple distributions in one env — set a unique waf.name on each to
30
+ // avoid WebACL/S3 bucket name collisions between stacks.
31
+ new JaypieDistribution(this, "Api", { handler: api, waf: { name: "api" } });
32
+ new JaypieDistribution(this, "Mcp", { handler: mcp, waf: { name: "mcp" } });
33
+
34
+ // Use existing WebACL
35
+ new JaypieDistribution(this, "Dist", {
36
+ handler,
37
+ waf: { name: "api", webAclArn: "arn:aws:wafv2:..." },
38
+ });
39
+
40
+ // Disable WAF logging only
41
+ new JaypieDistribution(this, "Dist", {
42
+ handler,
43
+ waf: { name: "api", logBucket: false },
44
+ });
45
+
46
+ // Bring your own WAF logging bucket
47
+ new JaypieDistribution(this, "Dist", {
48
+ handler,
49
+ waf: { name: "api", logBucket: myWafBucket },
50
+ });
51
+ ```
52
+
53
+ Cost: $5/month per WebACL + $1/month per rule + $0.60 per million requests. Use
54
+ `waf: false` to opt out.
55
+
56
+ ## Override specific managed rule actions
57
+
58
+ Flip a named sub-rule from `block` to `count` everywhere (e.g. allow large
59
+ request bodies):
60
+
61
+ ```typescript
62
+ new JaypieDistribution(this, "Dist", {
63
+ handler,
64
+ waf: {
65
+ name: "api",
66
+ managedRuleOverrides: {
67
+ AWSManagedRulesCommonRuleSet: [
68
+ { name: "SizeRestrictions_BODY", actionToUse: { count: {} } },
69
+ ],
70
+ },
71
+ },
72
+ });
73
+ ```
74
+
75
+ ## Scope a managed rule group to specific URL patterns
76
+
77
+ ```typescript
78
+ new JaypieDistribution(this, "Dist", {
79
+ handler,
80
+ waf: {
81
+ name: "api",
82
+ managedRuleScopeDowns: {
83
+ // Only run the CommonRuleSet for paths OTHER than /chat — lets /chat
84
+ // handle large AI-generated request bodies without weakening protection
85
+ // elsewhere.
86
+ AWSManagedRulesCommonRuleSet: {
87
+ notStatement: {
88
+ statement: {
89
+ byteMatchStatement: {
90
+ fieldToMatch: { uriPath: {} },
91
+ positionalConstraint: "STARTS_WITH",
92
+ searchString: "/chat",
93
+ textTransformations: [{ priority: 0, type: "NONE" }],
94
+ },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ },
100
+ });
101
+ ```
102
+
103
+ ## Relaxing a managed rule for specific paths — `waf.allow`
104
+
105
+ `allow` relaxes named rules to **count** mode for matching paths, leaving full
106
+ blocking everywhere else. Each entry names one or more paths and, per managed
107
+ rule group key, the sub-rule names to flip:
108
+
109
+ ```typescript
110
+ new JaypieDistribution(this, "Dist", {
111
+ handler,
112
+ waf: {
113
+ name: "api",
114
+ allow: [
115
+ {
116
+ path: "/hooks/*", // trailing * → STARTS_WITH; otherwise EXACTLY
117
+ AWSManagedRulesCommonRuleSet: ["NoUserAgent_HEADER"],
118
+ AWSManagedRulesKnownBadInputsRuleSet: ["ExploitablePaths_URIPATH"],
119
+ },
120
+ ],
121
+ },
122
+ });
123
+ ```
124
+
125
+ - A `path` ending in `*` compiles to a `STARTS_WITH` byte-match; otherwise
126
+ `EXACTLY`. `/hooks/*` matches `/hooks/ping` but **not** bare `/hooks`.
127
+ - The key (e.g. `AWSManagedRulesCommonRuleSet`) must be one of the active
128
+ `managedRules`.
129
+ - `allow` composes with `managedRuleOverrides`: the baseline overrides apply to
130
+ both the relaxed and strict emissions of a group; entries in `allow` further
131
+ relax specific (path × sub-rule) intersections. Groups not named in `allow`
132
+ keep their single-rule emission.
133
+
134
+ ## ⚠️ Rule name ≠ label (casing trap)
135
+
136
+ AWS uses different casing for a rule's **label** (seen in WAF logs) and its
137
+ **name**. `managedRuleOverrides` / `allow` match on the **rule name**:
138
+
139
+ | Label (seen in WAF logs) | Rule name (use this) |
140
+ | ----------------------------------------------------- | -------------------- |
141
+ | `awswaf:managed:aws:core-rule-set:NoUserAgent_Header` | `NoUserAgent_HEADER` |
142
+
143
+ Jaypie now validates rule names against each AWS managed rule group at synth and
144
+ throws a `ConfigurationError` listing the valid names on a mismatch (custom rule
145
+ groups are not validated). Historically a name that matched no rule was
146
+ **silently ignored** — the rule kept blocking. If a relaxation "isn't working,"
147
+ read the WAF log `terminatingRule.<NAME>` and copy that exact name (e.g.
148
+ `NoUserAgent_HEADER`, `SizeRestrictions_BODY`, `UserAgent_BadBots_HEADER`).
149
+
150
+ ## See Also
151
+
152
+ - **`skill("cdk")`** - CDK constructs and deployment patterns
153
+ - **`skill("aws")`** - AWS SDK utilities
154
+ - **`skill("web")`** - JaypieWebDeploymentBucket and JaypieStaticWebBucket