@jaypie/mcp 0.8.159 → 0.8.160
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.js +3 -3
- package/package.json +1 -1
- package/release-notes/constructs/1.2.88.md +67 -0
- package/release-notes/mcp/0.8.160.md +19 -0
- package/skills/JaypieDatadogForwarder.md +15 -0
- package/skills/cdk.md +44 -2
- package/skills/migrations.md +6 -0
- package/skills/waf.md +45 -0
- package/skills/web.md +25 -1
package/dist/assets.js
CHANGED
|
@@ -55,11 +55,11 @@ function getMcpAssetPaths() {
|
|
|
55
55
|
*/
|
|
56
56
|
function getMcpBuildInfo() {
|
|
57
57
|
return {
|
|
58
|
-
commit: "
|
|
58
|
+
commit: "b6d2f24e"
|
|
59
59
|
,
|
|
60
|
-
version: "0.8.
|
|
60
|
+
version: "0.8.160"
|
|
61
61
|
,
|
|
62
|
-
versionString: "@jaypie/mcp@0.8.
|
|
62
|
+
versionString: "@jaypie/mcp@0.8.160#b6d2f24e"
|
|
63
63
|
,
|
|
64
64
|
};
|
|
65
65
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 1.2.88
|
|
3
|
+
date: 2026-09-15
|
|
4
|
+
summary: Datadog forwarder invoke permissions, hardened log buckets, origin access control, WAF header redaction, and JaypieMigration log props
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **Datadog forwarder invoke permissions.** `resolveDatadogForwarderFunction`
|
|
10
|
+
and `JaypieDatadogForwarder` import the forwarder with
|
|
11
|
+
`fromFunctionAttributes({ sameEnvironment: true })`. `fromFunctionArn` on a
|
|
12
|
+
token ARN yields an unresolved environment, so `addPermission()` was a silent
|
|
13
|
+
no-op and every trigger deployed without invoke permission (#560).
|
|
14
|
+
`JaypieDatadogForwarder` acknowledges
|
|
15
|
+
`@aws-cdk/aws-events:ruleUnresolvedEnvironment` on its own events rule.
|
|
16
|
+
- **Hardened default log buckets.** The CloudFront access log bucket and WAF log
|
|
17
|
+
bucket that `JaypieDistribution` and `JaypieWebDeploymentBucket` create now
|
|
18
|
+
block all public access, enforce SSL, are versioned, use SSE-S3, expire
|
|
19
|
+
objects after `logRetention` (365 days by default, new prop), and carry
|
|
20
|
+
`RemovalPolicy.RETAIN` with no auto-delete. The WAF bucket policy declares the
|
|
21
|
+
`delivery.logs.amazonaws.com` statements so CloudFormation owns it (#561).
|
|
22
|
+
- **`JaypieDistribution` origin access control.** `originAccessControl: true`
|
|
23
|
+
creates an `AWS_IAM` Function URL, uses
|
|
24
|
+
`FunctionUrlOrigin.withOriginAccessControl`, and adds the
|
|
25
|
+
`lambda:InvokeFunction` permission Lambda requires alongside
|
|
26
|
+
`lambda:InvokeFunctionUrl`. Opt-in; the default stays `authType: NONE` (#562).
|
|
27
|
+
- **`JaypieWebDeploymentBucket` origin access control.**
|
|
28
|
+
`originAccessControl: true` serves a private bucket through the S3 REST
|
|
29
|
+
endpoint with OAC, `BLOCK_ALL`, `enforceSSL`, no website configuration, and
|
|
30
|
+
`defaultRootObject: "index.html"`. Opt-in; the default stays the public S3
|
|
31
|
+
website bucket (#563).
|
|
32
|
+
- **WAF log redaction.** `authorization`, `cookie`, `x-amz-content-sha256`, and
|
|
33
|
+
`x-api-key` are always redacted from WAF logs. The `waf` config accepts
|
|
34
|
+
`redactedHeaders`, which merges with that default rather than replacing it,
|
|
35
|
+
and a `redactedFields` passthrough for query strings, URI paths, and JSON body
|
|
36
|
+
fields (#564).
|
|
37
|
+
- **`waf.logRetention`** overrides the construct's `logRetention` for the WAF
|
|
38
|
+
log bucket alone.
|
|
39
|
+
- **`JaypieDistribution` warns** (`@jaypie/constructs:originAccessControlIgnored`)
|
|
40
|
+
when `originAccessControl` is set with a handler that supplies its own
|
|
41
|
+
Function URL or origin, where the prop has no effect.
|
|
42
|
+
- **`JaypieMigration` rejects `reservedConcurrentExecutions: 0`** with a
|
|
43
|
+
`ConfigurationError`. The migration Lambda is both `onEventHandler` and
|
|
44
|
+
`isCompleteHandler`, so a reservation of 0 means it is never invoked.
|
|
45
|
+
- **`JaypieDatadogForwarder` throws `ConfigurationError`** rather than a vanilla
|
|
46
|
+
`Error` when the Datadog API key is missing.
|
|
47
|
+
- **`JaypieMigration` log props.** `logGroup`, `logRetention`, and
|
|
48
|
+
`reservedConcurrentExecutions` forward to the wrapped `JaypieLambda` (#565).
|
|
49
|
+
|
|
50
|
+
## Upgrade
|
|
51
|
+
|
|
52
|
+
- **Log buckets survive stack deletion.** The CloudFront log bucket moves from
|
|
53
|
+
`DESTROY` with auto-delete to `RETAIN`. Deleting a stack now leaves the bucket
|
|
54
|
+
and its objects behind as a billable resource to remove by hand.
|
|
55
|
+
- **Retention rises from 90 to 365 days** on the construct-created log buckets,
|
|
56
|
+
roughly quadrupling retained volume. Pass `logRetention: 90` to keep the old
|
|
57
|
+
value. Versioning is a one-way door on an existing bucket.
|
|
58
|
+
- **The WAF log bucket gains a CloudFormation-owned bucket policy.** Any
|
|
59
|
+
statement added to that bucket out of band is discarded on the next deploy.
|
|
60
|
+
- **Existing WAF logging configurations gain `RedactedFields`** on the next
|
|
61
|
+
deploy. The four default headers are always redacted; there is no opt-out.
|
|
62
|
+
- **Datadog forwarder triggers gain `AWS::Lambda::Permission` resources** on the
|
|
63
|
+
next deploy, and S3 notification configurations that previously failed
|
|
64
|
+
validation now apply.
|
|
65
|
+
- `originAccessControl` is opt-in on both constructs; no existing deployment
|
|
66
|
+
changes without setting it. With it enabled on `JaypieDistribution`, clients
|
|
67
|
+
must send the body SHA-256 in `x-amz-content-sha256` on POST and PUT.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
version: 0.8.160
|
|
3
|
+
date: 2026-09-15
|
|
4
|
+
summary: Document forwarder invoke permissions, hardened log buckets, origin access control, WAF redaction, and JaypieMigration log props
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Changes
|
|
8
|
+
|
|
9
|
+
- **`skill("JaypieDatadogForwarder")`** gains an "Invoke Permissions" section
|
|
10
|
+
covering token-ARN imports and the events-rule warning acknowledgement.
|
|
11
|
+
- **`skill("cdk")`** gains "Origin Access Control" and "Importing a Lambda by
|
|
12
|
+
Token ARN" sections, and the WAF summary lists the new config keys.
|
|
13
|
+
- **`skill("waf")`** documents the hardened log bucket, `waf.logRetention`, and
|
|
14
|
+
the merge semantics of `redactedHeaders` / `redactedFields`.
|
|
15
|
+
- **`skill("web")`** gains an "Origin Access Control" section and documents
|
|
16
|
+
`logRetention` and the hardened log buckets.
|
|
17
|
+
- **`skill("migrations")`** documents `logGroup`, `logRetention`, and
|
|
18
|
+
`reservedConcurrentExecutions`, including the inert-`logRetention` gap
|
|
19
|
+
deferred to 2.0 (#568) and the zero-concurrency throw.
|
|
@@ -72,6 +72,21 @@ const forwarderFunction = resolveDatadogForwarderFunction(this);
|
|
|
72
72
|
|
|
73
73
|
This imports the Lambda via `Fn.importValue("account-datadog-forwarder")` and caches per scope (WeakMap), so multiple calls in the same stack return the same reference.
|
|
74
74
|
|
|
75
|
+
## Invoke Permissions
|
|
76
|
+
|
|
77
|
+
The forwarder ARN is always an unresolved token: a cross-stack export or a nested-stack output. `lambda.Function.fromFunctionArn` on a token ARN produces an import with an unknown environment, and `addPermission()` on such an import is a silent no-op that only emits an `UnclearLambdaEnvironment` warning. Every trigger wired to the forwarder then deploys with no invoke permission, and S3 rejects the notification configuration because it cannot validate the destination.
|
|
78
|
+
|
|
79
|
+
Both import sites use `lambda.Function.fromFunctionAttributes(scope, id, { functionArn, sameEnvironment: true })`. The flag is correct here because the forwarder is always in the same account and region as its consumers.
|
|
80
|
+
|
|
81
|
+
`JaypieDatadogForwarder` acknowledges `@aws-cdk/aws-events:ruleUnresolvedEnvironment` on its own `CloudFormationEventsRule`. Acknowledgements resolve by construct path, so a consumer creating a rule that targets `forwarder.forwarderFunction` sees that warning on their own rule and should acknowledge it with the same justification:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
Annotations.of(rule).acknowledgeWarning(
|
|
85
|
+
"@aws-cdk/aws-events:ruleUnresolvedEnvironment",
|
|
86
|
+
"The Datadog forwarder is always in the same account and region",
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
75
90
|
### For Log Subscription Filters
|
|
76
91
|
|
|
77
92
|
Use `resolveDatadogLoggingDestination` to get a `LambdaDestination`:
|
package/skills/cdk.md
CHANGED
|
@@ -440,8 +440,50 @@ KnownBadInputsRuleSet, IP rate limiting, and WAF logging to S3 with Datadog
|
|
|
440
440
|
forwarding.
|
|
441
441
|
|
|
442
442
|
See **`skill("waf")`** for configuration: `rateLimitPerIp`, `webAclArn`,
|
|
443
|
-
`logBucket`, `managedRuleOverrides`, `managedRuleScopeDowns`,
|
|
444
|
-
path-scoped relaxation prop,
|
|
443
|
+
`logBucket`, `logRetention`, `managedRuleOverrides`, `managedRuleScopeDowns`,
|
|
444
|
+
`redactedFields`, `redactedHeaders`, the `allow` path-scoped relaxation prop,
|
|
445
|
+
and the rule-name ↔ label casing trap.
|
|
446
|
+
|
|
447
|
+
WAF logs always redact `authorization`, `cookie`, `x-amz-content-sha256`, and
|
|
448
|
+
`x-api-key`. A `redactedHeaders` list merges with that default rather than
|
|
449
|
+
replacing it, so adding a header can only ever redact more.
|
|
450
|
+
|
|
451
|
+
## Origin Access Control
|
|
452
|
+
|
|
453
|
+
`JaypieDistribution` with an `IFunction` handler creates a Function URL with
|
|
454
|
+
`authType: NONE`, so the Lambda is invokable around CloudFront and the WAF.
|
|
455
|
+
`originAccessControl: true` makes CloudFront the only caller:
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
new JaypieDistribution(this, "Dist", {
|
|
459
|
+
handler,
|
|
460
|
+
originAccessControl: true,
|
|
461
|
+
});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
- The Function URL becomes `AWS_IAM`, the origin becomes
|
|
465
|
+
`origins.FunctionUrlOrigin.withOriginAccessControl(...)`, and the construct
|
|
466
|
+
adds the `lambda:InvokeFunction` permission that `withOriginAccessControl`
|
|
467
|
+
omits (Lambda requires both it and `lambda:InvokeFunctionUrl`).
|
|
468
|
+
- **Client requirement:** with OAC, Lambda rejects a POST or PUT unless the
|
|
469
|
+
client sends the body SHA-256 in `x-amz-content-sha256`. For a body carrying
|
|
470
|
+
low-entropy secrets, salt it with a nonce so the hash is not reversible. That
|
|
471
|
+
header is redacted from WAF logs by default.
|
|
472
|
+
- The prop applies only to the `IFunction` path. A caller-supplied
|
|
473
|
+
`IFunctionUrl` or `IOrigin` owns its own auth; setting the prop there warns
|
|
474
|
+
at synth (`@jaypie/constructs:originAccessControlIgnored`).
|
|
475
|
+
- `JaypieWebDeploymentBucket` has its own `originAccessControl` prop for the S3
|
|
476
|
+
case; see `skill("web")`.
|
|
477
|
+
|
|
478
|
+
## Importing a Lambda by Token ARN
|
|
479
|
+
|
|
480
|
+
`lambda.Function.fromFunctionArn` on an ARN that is a token (`Fn.importValue`,
|
|
481
|
+
a nested-stack output) yields an import with an unresolved environment.
|
|
482
|
+
`addPermission()` on it is a silent no-op that only warns
|
|
483
|
+
(`UnclearLambdaEnvironment`), so every trigger deploys without invoke
|
|
484
|
+
permission. Use
|
|
485
|
+
`lambda.Function.fromFunctionAttributes(scope, id, { functionArn, sameEnvironment: true })`
|
|
486
|
+
whenever the function is known to be in the same account and region.
|
|
445
487
|
|
|
446
488
|
## Organization Trail Security Baseline
|
|
447
489
|
|
package/skills/migrations.md
CHANGED
|
@@ -35,7 +35,10 @@ new JaypieMigration(this, "SeedData", {
|
|
|
35
35
|
| `dependencies` | `Construct[]` | `[]` | Constructs that must be created before the migration runs |
|
|
36
36
|
| `environment` | `Record<string, string> \| (Record<string, string> \| string)[]` | - | Environment variables for the migration Lambda |
|
|
37
37
|
| `handler` | `string` | `"index.handler"` | Lambda entry point |
|
|
38
|
+
| `logGroup` | `logs.ILogGroup` | - | Log group for the migration Lambda; forwarded to `JaypieLambda`. Supply one to control KMS encryption and retention |
|
|
39
|
+
| `logRetention` | `logs.RetentionDays \| number` | `90` days | Retention for the log group `JaypieLambda` creates. Ignored when `logGroup` is supplied |
|
|
38
40
|
| `queryInterval` | `cdk.Duration` | `Duration.seconds(60)` | Polling interval between `isCompleteHandler` invocations |
|
|
41
|
+
| `reservedConcurrentExecutions` | `number` | - | Reserved concurrency for the migration Lambda. `0` throws at synth; `1` leaves no headroom if onEvent overlaps a waiter poll |
|
|
39
42
|
| `secrets` | `SecretsArrayItem[]` | `[]` | Secrets to make available to the Lambda |
|
|
40
43
|
| `tables` | `dynamodb.ITable[]` | `[]` | DynamoDB tables to grant read/write access |
|
|
41
44
|
| `timeout` | `cdk.Duration` | `Duration.minutes(15)` | Per-invocation Lambda timeout |
|
|
@@ -45,6 +48,9 @@ new JaypieMigration(this, "SeedData", {
|
|
|
45
48
|
|
|
46
49
|
- **Timeout**: 15 minutes per invocation (Lambda max); `totalTimeout` controls the end-to-end ceiling across all polling invocations (default 2 hours)
|
|
47
50
|
- **Role**: Tagged as `CDK.ROLE.PROCESSING`
|
|
51
|
+
- **Logging**: `logGroup`, `logRetention`, and `reservedConcurrentExecutions` forward to the wrapped `JaypieLambda`. Pass `logGroup` when a compliance baseline requires a KMS-encrypted group or 12-month retention. The `cr.Provider` framework functions keep service-created log groups
|
|
52
|
+
- **`logRetention` is inert when `logGroup` is supplied.** `JaypieLambda` resolves `logGroup ?? new logs.LogGroup(..., { retention: logRetention })`, so passing both silently drops the retention value. Set retention on the group you pass. Jaypie 2.0 will throw on that combination (#568)
|
|
53
|
+
- **Concurrency**: the migration Lambda is both `onEventHandler` and `isCompleteHandler`. `reservedConcurrentExecutions: 0` blocks every invocation and throws `ConfigurationError` at synth
|
|
48
54
|
- **Execution**: Uses `cr.Provider` with both `onEventHandler` and `isCompleteHandler` pointing to the same Lambda. The `onEventHandler` returns `PhysicalResourceId` immediately; the migration code runs in `isCompleteHandler` invocations, which are polled by Step Functions until `IsComplete: true`. `Delete` requests skip the migration entirely.
|
|
49
55
|
- **Dependencies**: Use `dependencies` to ensure tables and other resources exist before the migration executes
|
|
50
56
|
- **Permissions**: Tables passed via `tables` get data-plane (`grantReadWriteData`), `Query` and `Scan` on `${tableArn}/index/*`, plus `DescribeTable`, `DescribeTimeToLive`, and `DescribeContinuousBackups` scoped to the table ARN and its indexes. Migrations read and write data. They do not change table shape
|
package/skills/waf.md
CHANGED
|
@@ -53,6 +53,51 @@ new JaypieDistribution(this, "Dist", {
|
|
|
53
53
|
Cost: $5/month per WebACL + $1/month per rule + $0.60 per million requests. That
|
|
54
54
|
cost is why WAF is opt-in; set `waf: true` (or a config object) to opt in.
|
|
55
55
|
|
|
56
|
+
## Log bucket
|
|
57
|
+
|
|
58
|
+
The construct-created WAF log bucket blocks all public access, enforces SSL, is
|
|
59
|
+
versioned, uses SSE-S3, retains objects for `logRetention` (365 days by
|
|
60
|
+
default), and carries `RemovalPolicy.RETAIN` with no auto-delete. It survives
|
|
61
|
+
stack deletion; delete it by hand when tearing an environment down.
|
|
62
|
+
|
|
63
|
+
CloudFormation owns the whole bucket policy, including the two
|
|
64
|
+
`delivery.logs.amazonaws.com` delivery statements. A policy statement added to
|
|
65
|
+
that bucket out of band (console, CLI, another stack) is discarded on the next
|
|
66
|
+
deploy.
|
|
67
|
+
|
|
68
|
+
A consumer-supplied `logBucket` is used as given: it needs its own hardening and
|
|
69
|
+
its own delivery policy.
|
|
70
|
+
|
|
71
|
+
## Redact headers from WAF logs
|
|
72
|
+
|
|
73
|
+
WAF logs record every request header. Jaypie always redacts
|
|
74
|
+
`authorization`, `cookie`, `x-amz-content-sha256`, and `x-api-key`
|
|
75
|
+
(`DEFAULT_WAF_REDACTED_HEADERS`). `redactedHeaders` names more:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
new JaypieDistribution(this, "Dist", {
|
|
79
|
+
handler,
|
|
80
|
+
waf: { name: "api", redactedHeaders: ["x-session-token"] },
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- The list **merges** with the defaults rather than replacing them, so adding a
|
|
85
|
+
header can only ever redact more. There is no way to un-redact a default.
|
|
86
|
+
- Names are compared case-insensitively, as WAF matches them, so naming a
|
|
87
|
+
default again does not duplicate it.
|
|
88
|
+
- `x-amz-content-sha256` is in the default because `originAccessControl`
|
|
89
|
+
requires clients to send a SHA-256 of the request body. For a low-entropy body
|
|
90
|
+
that hash is a body fingerprint.
|
|
91
|
+
- `redactedFields` passes `wafv2.CfnLoggingConfiguration.FieldToMatchProperty`
|
|
92
|
+
entries (query string, URI path, JSON body) through and layers on top of the
|
|
93
|
+
redacted headers.
|
|
94
|
+
- WAF caps the combined list at 100 entries; exceeding it throws a
|
|
95
|
+
`ConfigurationError` at synth.
|
|
96
|
+
|
|
97
|
+
`waf.logRetention` overrides the construct's `logRetention` for the WAF log
|
|
98
|
+
bucket alone, so WAF logs and CloudFront access logs can keep different
|
|
99
|
+
retention.
|
|
100
|
+
|
|
56
101
|
## Override specific managed rule actions
|
|
57
102
|
|
|
58
103
|
Flip a named sub-rule from `block` to `count` everywhere (e.g. allow large
|
package/skills/web.md
CHANGED
|
@@ -42,14 +42,16 @@ new JaypieWebDeploymentBucket(this, "Web", {
|
|
|
42
42
|
| `defaultBehavior` | `Partial<BehaviorOptions>` | undefined — merged over the construct's default behavior; keys given win |
|
|
43
43
|
| `destination` | `LambdaDestination \| boolean` | `true` (Datadog forwarder for access-log bucket notifications) |
|
|
44
44
|
| `logBucket` | `IBucket \| string \| { exportName } \| true` | undefined — creates a new bucket if `destination !== false` |
|
|
45
|
+
| `logRetention` | `Duration \| number` | `Duration.days(365)` — retention for the log buckets the construct creates; `waf.logRetention` overrides it for the WAF bucket |
|
|
45
46
|
| `name` | `string` | `constructEnvName(component)` |
|
|
47
|
+
| `originAccessControl` | `boolean` | `false` — serve the bucket privately through the S3 REST endpoint with CloudFront OAC |
|
|
46
48
|
| `responseHeadersPolicy` | `IResponseHeadersPolicy` | undefined — full override; bypasses default security headers |
|
|
47
49
|
| `roleTag` | `string` | `CDK.ROLE.HOSTING` |
|
|
48
50
|
| `securityHeaders` | `boolean \| SecurityHeadersOverrides` | `true` |
|
|
49
51
|
| `spa` | `boolean` | `false` — viewer-request rewrite of extension-less URIs to `/index.html` |
|
|
50
52
|
| `waf` | `boolean \| JaypieWebDeploymentBucketWafConfig` | `false` (when enabled, WAF name defaults to construct id) |
|
|
51
53
|
|
|
52
|
-
Also accepts all `s3.BucketProps`
|
|
54
|
+
Also accepts all `s3.BucketProps`. With `originAccessControl: false` (the default) the bucket is a public S3 website: `autoDeleteObjects: true`, `publicReadAccess: true`, `websiteIndexDocument: "index.html"`, `websiteErrorDocument: "index.html"` — which renders an SPA deep link but answers 404; see [Single-Page App](#single-page-app). With `originAccessControl: true` the bucket is private; see [Origin Access Control](#origin-access-control).
|
|
53
55
|
|
|
54
56
|
### Bucket Name
|
|
55
57
|
|
|
@@ -67,6 +69,7 @@ Changing `component` or `name` on a deployed stack renames the bucket, which rep
|
|
|
67
69
|
- Default behavior: S3 static website origin, `REDIRECT_TO_HTTPS`. `CACHING_DISABLED` outside production; `CACHING_OPTIMIZED` in production (`isProductionEnv()`), so hashed assets get edge cache. The response headers policy sets `Cache-Control: no-store` so browsers still revalidate.
|
|
68
70
|
- No `/*` behavior is created. Paths registered afterward with `distribution.addBehavior("/app/*", origin)` are evaluated ahead of the default behavior and match in every environment — a static site and a Lambda surface can share one distribution.
|
|
69
71
|
- Access logs land in a CloudFront log bucket with Datadog forwarding by default. Set `destination: false` to skip notifications, or pass `logBucket: <existing>` to reuse a bucket.
|
|
72
|
+
- The construct-created log buckets block all public access, enforce SSL, are versioned, use SSE-S3, retain objects for `logRetention` (365 days by default), and carry `RemovalPolicy.RETAIN` with no auto-delete. They survive stack deletion; delete them by hand when tearing an environment down.
|
|
70
73
|
|
|
71
74
|
```typescript
|
|
72
75
|
const web = new JaypieWebDeploymentBucket(this, "Web", { host, zone });
|
|
@@ -107,6 +110,27 @@ new JaypieWebDeploymentBucket(this, "App", {
|
|
|
107
110
|
- Exposed as `.spaFunction`. Works without `host` and `zone`, so a deep link resolves on the CloudFront default domain before DNS is wired.
|
|
108
111
|
- Combining `spa: true` with a caller-supplied **viewer-request** association throws `ConfigurationError` at synth; CloudFront permits one function per event type. Other event types (for example viewer-response) compose, with the rewrite appended last.
|
|
109
112
|
|
|
113
|
+
### Origin Access Control
|
|
114
|
+
|
|
115
|
+
The default bucket is a public S3 website endpoint. CloudFront cannot use origin access control against a website endpoint, so the bucket stays readable around CloudFront and the WAF.
|
|
116
|
+
|
|
117
|
+
`originAccessControl: true` serves the bucket privately:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
new JaypieWebDeploymentBucket(this, "Web", {
|
|
121
|
+
host,
|
|
122
|
+
originAccessControl: true,
|
|
123
|
+
spa: true,
|
|
124
|
+
zone,
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- The bucket gets `BlockPublicAccess.BLOCK_ALL` and `enforceSSL: true`, with no ACL, no public read, and no website configuration.
|
|
129
|
+
- The default behavior uses `origins.S3BucketOrigin.withOriginAccessControl(bucket)`, and the distribution sets `defaultRootObject: "index.html"`.
|
|
130
|
+
- Combining it with `publicReadAccess: true`, `websiteIndexDocument`, or `websiteErrorDocument` through `bucketProps` throws `ConfigurationError` at synth. Other bucket props still compose.
|
|
131
|
+
- **Pair it with `spa: true`.** The REST endpoint has no error document, and OAC grants only `s3:GetObject`, so a miss returns `403 AccessDenied` rather than the app shell. The SPA function rewrites extension-less deep links before they reach the origin, so they never miss.
|
|
132
|
+
- `isWebsite` is `false` and `bucketWebsiteUrl` no longer addresses a live endpoint.
|
|
133
|
+
|
|
110
134
|
### Security Headers
|
|
111
135
|
|
|
112
136
|
Same defaults as `JaypieDistribution`: HSTS, X-Frame-Options, CSP, Referrer-Policy, Permissions-Policy, Cross-Origin-* headers, and Server header removal (applied via a `ResponseHeadersPolicy` on the default behavior). Override the same way:
|