rcf-lite 0.23.0 → 0.24.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/CHANGELOG.md +18 -0
- package/blueprints/application-account-settings/docs/topics.md +7 -1
- package/blueprints/application-admin-console/CHANGELOG.md +12 -0
- package/blueprints/application-admin-console/blueprint.json +34 -1
- package/blueprints/application-admin-console/contributions/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +25 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-014.json +17 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +32 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21815.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21816.json +27 -0
- package/blueprints/application-admin-console/docs/topics.md +7 -1
- package/blueprints/application-admin-console/guide/application-admin-console.md +24 -0
- package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +26 -1
- package/blueprints/application-api-rest/docs/topics.md +7 -1
- package/blueprints/application-charts/docs/topics.md +7 -1
- package/blueprints/application-dashboard/docs/topics.md +7 -1
- package/blueprints/application-datatable/docs/topics.md +7 -1
- package/blueprints/application-empty-error-states/docs/topics.md +7 -1
- package/blueprints/application-error-handling/docs/topics.md +7 -1
- package/blueprints/application-file-upload/docs/topics.md +7 -1
- package/blueprints/application-forms-wizard/docs/topics.md +7 -1
- package/blueprints/application-notifications-in-app/docs/topics.md +7 -1
- package/blueprints/application-onboarding-tour/docs/topics.md +7 -1
- package/blueprints/application-spa/docs/topics.md +7 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +7 -1
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +7 -1
- package/blueprints/edge-cloudflare-access/CHANGELOG.md +23 -0
- package/blueprints/edge-cloudflare-access/README.md +141 -0
- package/blueprints/edge-cloudflare-access/blueprint.json +197 -0
- package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3501-edge-cloudflare-access-jwt-gate.json +14 -0
- package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3502-edge-cloudflare-access-identity-provider.json +25 -0
- package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3503-edge-cloudflare-access-policy-scope.json +12 -0
- package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3504-edge-cloudflare-access-audit-retention.json +12 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +100 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/audit-event-secrecy.mjs +70 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/jwt-validator-fixture.mjs +63 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/jwt-validator-reject.mjs +95 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/probe-utils.mjs +90 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/real-account-gated-url.mjs +65 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-admin-console-gate-surface.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-audit-event-secrecy.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-jwt-validator-fixture.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-jwt-validator-reject.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-real-account-gated-url.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/run-wrangler-seam.mjs +5 -0
- package/blueprints/edge-cloudflare-access/contributions/probes/wrangler-seam.mjs +203 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-001.json +17 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-002.json +17 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-003.json +17 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-004.json +17 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-005.json +17 -0
- package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-006.json +18 -0
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3501-edge-cloudflare-access-jwt-validator.json +31 -0
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3502-edge-cloudflare-access-application-declaration.json +33 -0
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3503-edge-cloudflare-access-policy-shape.json +25 -0
- package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3504-edge-cloudflare-access-audit-sink.json +25 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34101.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34102.json +28 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34103.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34104.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34105.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34106.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34107.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34108.json +27 -0
- package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34109.json +27 -0
- package/blueprints/edge-cloudflare-access/docs/topics.md +68 -0
- package/blueprints/edge-cloudflare-access/guide/edge-cloudflare-access.md +180 -0
- package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +10 -0
- package/blueprints/edge-cloudflare-rate-limiting/README.md +73 -0
- package/blueprints/edge-cloudflare-rate-limiting/blueprint.json +174 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3701-edge-cloudflare-rate-limiting-throttle-contract.json +14 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3702-edge-cloudflare-rate-limiting-layering.json +14 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3703-edge-cloudflare-rate-limiting-manifest-shape.json +14 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3704-edge-cloudflare-rate-limiting-drift-audit-cadence.json +14 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/event-secrecy.mjs +104 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/manifest-presence.mjs +95 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/manifest-schema-validate.mjs +130 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/probe-utils.mjs +111 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/real-account-burst-and-429.mjs +104 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-event-secrecy.mjs +5 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-manifest-presence.mjs +5 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-manifest-schema-validate.mjs +5 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-real-account-burst-and-429.mjs +5 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-001.json +17 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-002.json +17 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-003.json +17 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-004.json +17 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-005.json +17 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/schemas/rate-limit-rule.schema.json +67 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +31 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json +25 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +26 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36101.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36102.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36103.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36104.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36105.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36106.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36107.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36108.json +27 -0
- package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +68 -0
- package/blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md +88 -0
- package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +20 -0
- package/blueprints/edge-cloudflare-turnstile/README.md +95 -0
- package/blueprints/edge-cloudflare-turnstile/blueprint.json +161 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3601-edge-cloudflare-turnstile-verifier-contract.json +14 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3602-edge-cloudflare-turnstile-widget-mode.json +14 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3603-edge-cloudflare-turnstile-refuse-shape.json +14 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/event-secrecy.mjs +51 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/guard-shape-scan.mjs +48 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/probe-utils.mjs +139 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-event-secrecy.mjs +5 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-guard-shape-scan.mjs +5 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-secret-shape-scan.mjs +5 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-siteverify-fixture.mjs +5 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/secret-shape-scan.mjs +77 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/probes/siteverify-fixture.mjs +53 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-001.json +17 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-002.json +17 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-003.json +17 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-004.json +17 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-005.json +17 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +26 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +36 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3603-edge-cloudflare-turnstile-magic-link-hook.json +25 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35101.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35102.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35103.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35104.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35105.json +36 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35106.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35107.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35108.json +27 -0
- package/blueprints/edge-cloudflare-turnstile/docs/topics.md +68 -0
- package/blueprints/edge-cloudflare-turnstile/guide/edge-cloudflare-turnstile.md +104 -0
- package/blueprints/edge-cloudflare-turnstile/probe-packs/edge-cloudflare-turnstile.pack.mjs +146 -0
- package/blueprints/email-smtp-resend/docs/topics.md +7 -1
- package/blueprints/jobs-background/docs/topics.md +7 -1
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +7 -1
- package/blueprints/object-storage-s3/docs/topics.md +7 -1
- package/blueprints/observability-essentials/docs/topics.md +7 -1
- package/blueprints/observability-logging/docs/topics.md +7 -1
- package/blueprints/observability-probe-endpoints/docs/topics.md +7 -1
- package/blueprints/persistence-data-d1/docs/topics.md +7 -1
- package/blueprints/persistence-data-postgres/docs/topics.md +7 -1
- package/blueprints/persistence-data-sqlite/docs/topics.md +7 -1
- package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +22 -0
- package/blueprints/platform-cloudflare-cron-triggers/README.md +117 -0
- package/blueprints/platform-cloudflare-cron-triggers/blueprint.json +85 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3301-platform-cloudflare-cron-triggers-scheduled-trigger-contract.json +14 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3302-platform-cloudflare-cron-triggers-dispatcher-mode.json +14 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3303-platform-cloudflare-cron-triggers-skew-tolerance-default.json +14 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/dispatcher-routing.mjs +64 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/event-secrecy.mjs +100 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/probe-utils.mjs +70 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/real-account-scheduled-smoke.mjs +100 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-dispatcher-routing.mjs +5 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-event-secrecy.mjs +5 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-real-account-scheduled-smoke.mjs +5 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-skew-tolerance.mjs +5 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-wrangler-test-scheduled.mjs +5 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/skew-tolerance.mjs +130 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/wrangler-test-scheduled.mjs +129 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-001.json +17 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-002.json +17 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-003.json +17 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-004.json +17 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3301-platform-cloudflare-cron-triggers-scheduled-handler.json +22 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3302-platform-cloudflare-cron-triggers-expression-router.json +22 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3303-platform-cloudflare-cron-triggers-event-sink.json +21 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32101.json +25 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32102.json +34 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32103.json +34 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32104.json +34 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32105.json +25 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32106.json +25 -0
- package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32107.json +25 -0
- package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +71 -0
- package/blueprints/platform-cloudflare-cron-triggers/guide/platform-cloudflare-cron-triggers.md +119 -0
- package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +23 -0
- package/blueprints/platform-cloudflare-durable-objects/README.md +200 -0
- package/blueprints/platform-cloudflare-durable-objects/blueprint.json +243 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3401-platform-cloudflare-durable-objects-single-cell-contract.json +14 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3402-platform-cloudflare-durable-objects-websocket-hub-contract.json +14 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3403-platform-cloudflare-durable-objects-storage-backend.json +14 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3404-platform-cloudflare-durable-objects-migrations-shape.json +14 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3405-platform-cloudflare-durable-objects-hibernation-posture.json +14 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/alarm-fires-once.mjs +63 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/namespace-facade-ready.mjs +60 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +105 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +58 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-alarm-fires-once.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-namespace-facade-ready.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-real-account-storage-smoke.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-single-cell-concurrent-increment.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-sole-reader-scan.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-storage-round-trip.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-websocket-hub-broadcast.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-wrangler-seam.mjs +5 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/single-cell-concurrent-increment.mjs +56 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +117 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +87 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +112 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/probes/wrangler-seam.mjs +257 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-001.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-002.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-003.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-004.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-005.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-006.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-007.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-008.json +17 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3401-platform-cloudflare-durable-objects-namespace-facade.json +31 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3402-platform-cloudflare-durable-objects-single-cell-shape.json +30 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3403-platform-cloudflare-durable-objects-alarm-handler.json +29 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3404-platform-cloudflare-durable-objects-websocket-hub.json +31 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3405-platform-cloudflare-durable-objects-event-sink.json +24 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33101.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33102.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33103.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33104.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33105.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33106.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33107.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33108.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33109.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33110.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33111.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33112.json +27 -0
- package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33113.json +25 -0
- package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +73 -0
- package/blueprints/platform-cloudflare-durable-objects/guide/platform-cloudflare-durable-objects.md +237 -0
- package/blueprints/platform-cloudflare-kv/CHANGELOG.md +21 -0
- package/blueprints/platform-cloudflare-kv/README.md +159 -0
- package/blueprints/platform-cloudflare-kv/blueprint.json +87 -0
- package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3201-platform-cloudflare-kv-key-value-store-contract.json +14 -0
- package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3202-platform-cloudflare-kv-default-cache-ttl.json +14 -0
- package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3203-platform-cloudflare-kv-key-naming-convention.json +14 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +82 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +102 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/facade-round-trip.mjs +92 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/list-with-prefix.mjs +52 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/probe-utils.mjs +73 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +102 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/run-cache-aside-hit-then-miss.mjs +5 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/run-event-secrecy.mjs +5 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/run-facade-round-trip.mjs +5 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/run-list-with-prefix.mjs +5 -0
- package/blueprints/platform-cloudflare-kv/contributions/probes/run-real-account-eventual-consistency-smoke.mjs +5 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-001.json +18 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-002.json +18 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-003.json +18 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-004.json +18 -0
- package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-005.json +18 -0
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3201-platform-cloudflare-kv-facade.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3202-platform-cloudflare-kv-cache-aside.json +26 -0
- package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3203-platform-cloudflare-kv-event-sink.json +25 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31101.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31102.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31103.json +36 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31104.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31105.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31106.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31107.json +27 -0
- package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31108.json +27 -0
- package/blueprints/platform-cloudflare-kv/docs/topics.md +71 -0
- package/blueprints/platform-cloudflare-kv/guide/platform-cloudflare-kv.md +138 -0
- package/blueprints/security-auth-clerk/docs/topics.md +7 -1
- package/blueprints/security-auth-keycloak/docs/topics.md +7 -1
- package/blueprints/security-auth-magic-link/docs/topics.md +7 -1
- package/blueprints/security-auth-oauth2/docs/topics.md +7 -1
- package/blueprints/security-secrets-management/docs/topics.md +7 -1
- package/fixtures/canary-manifest.json +6 -6
- package/package.json +1 -1
- package/rcf/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +13 -0
- package/rcf/adrs/adr-3501-edge-cloudflare-access-jwt-gate.json +13 -0
- package/rcf/adrs/adr-3502-edge-cloudflare-access-identity-provider.json +13 -0
- package/rcf/adrs/adr-3503-edge-cloudflare-access-policy-scope.json +13 -0
- package/rcf/adrs/adr-3504-edge-cloudflare-access-audit-retention.json +13 -0
- package/rcf/adrs/adr-3601-edge-cloudflare-turnstile-verifier-contract.json +13 -0
- package/rcf/adrs/adr-3602-edge-cloudflare-turnstile-widget-mode.json +13 -0
- package/rcf/adrs/adr-3603-edge-cloudflare-turnstile-refuse-shape.json +13 -0
- package/rcf/adrs/adr-3701-edge-cloudflare-rate-limiting-throttle-contract.json +13 -0
- package/rcf/adrs/adr-3702-edge-cloudflare-rate-limiting-layering.json +13 -0
- package/rcf/adrs/adr-3703-edge-cloudflare-rate-limiting-manifest-shape.json +13 -0
- package/rcf/adrs/adr-3704-edge-cloudflare-rate-limiting-drift-audit-cadence.json +13 -0
- package/rcf/code-nodes/cn-230.json +13 -0
- package/rcf/code-nodes/cn-231.json +14 -0
- package/rcf/code-nodes/cn-232.json +13 -0
- package/rcf/code-nodes/cn-233.json +14 -0
- package/rcf/code-nodes/cn-234.json +13 -0
- package/rcf/code-nodes/cn-260.json +21 -0
- package/rcf/code-nodes/cn-261.json +14 -0
- package/rcf/code-nodes/cn-262.json +18 -0
- package/rcf/code-nodes/cn-263.json +12 -0
- package/rcf/code-nodes/cn-264.json +13 -0
- package/rcf/code-nodes/cn-265.json +15 -0
- package/rcf/code-nodes/cn-266.json +12 -0
- package/rcf/code-nodes/cn-267.json +12 -0
- package/rcf/code-nodes/cn-290.json +21 -0
- package/rcf/code-nodes/cn-291.json +12 -0
- package/rcf/code-nodes/cn-292.json +13 -0
- package/rcf/code-nodes/cn-293.json +13 -0
- package/rcf/code-nodes/cn-294.json +13 -0
- package/rcf/code-nodes/cn-295.json +12 -0
- package/rcf/code-nodes/cn-296.json +12 -0
- package/rcf/code-nodes/cn-297.json +12 -0
- package/rcf/code-nodes/cn-298.json +12 -0
- package/rcf/code-nodes/cn-299.json +12 -0
- package/rcf/code-nodes/cn-300.json +12 -0
- package/rcf/code-nodes/cn-301.json +14 -0
- package/rcf/code-nodes/cn-302.json +12 -0
- package/rcf/code-nodes/cn-303.json +12 -0
- package/rcf/code-nodes/cn-304.json +21 -0
- package/rcf/code-nodes/cn-320.json +20 -0
- package/rcf/code-nodes/cn-321.json +14 -0
- package/rcf/code-nodes/cn-350.json +19 -0
- package/rcf/code-nodes/cn-380.json +19 -0
- package/rcf/fbs/fbs-070.json +24 -0
- package/rcf/fbs/fbs-080.json +24 -0
- package/rcf/fbs/fbs-090.json +24 -0
- package/rcf/fbs/fbs-100.json +23 -0
- package/rcf/fbs/fbs-101.json +16 -0
- package/rcf/fbs/fbs-110.json +23 -0
- package/rcf/fbs/fbs-120.json +22 -0
- package/rcf/requirements/req-050.json +18 -0
- package/rcf/requirements/req-051.json +18 -0
- package/rcf/requirements/req-052.json +18 -0
- package/rcf/requirements/req-053.json +18 -0
- package/rcf/requirements/req-054.json +18 -0
- package/rcf/requirements/req-060.json +20 -0
- package/rcf/requirements/req-061.json +18 -0
- package/rcf/requirements/req-062.json +20 -0
- package/rcf/requirements/req-063.json +20 -0
- package/rcf/requirements/req-070.json +18 -0
- package/rcf/requirements/req-071.json +18 -0
- package/rcf/requirements/req-072.json +18 -0
- package/rcf/requirements/req-073.json +18 -0
- package/rcf/requirements/req-074.json +18 -0
- package/rcf/requirements/req-075.json +18 -0
- package/rcf/requirements/req-076.json +18 -0
- package/rcf/requirements/req-077.json +18 -0
- package/rcf/requirements/req-080.json +18 -0
- package/rcf/requirements/req-081.json +18 -0
- package/rcf/requirements/req-082.json +18 -0
- package/rcf/requirements/req-083.json +18 -0
- package/rcf/requirements/req-084.json +18 -0
- package/rcf/requirements/req-085.json +18 -0
- package/rcf/requirements/req-086.json +18 -0
- package/rcf/requirements/req-090.json +44 -0
- package/rcf/requirements/req-091.json +53 -0
- package/rcf/requirements/req-092.json +32 -0
- package/rcf/requirements/req-093.json +52 -0
- package/rcf/requirements/req-094.json +32 -0
- package/rcf/requirements/req-100.json +13 -0
- package/rcf/requirements/req-101.json +13 -0
- package/rcf/requirements/req-102.json +13 -0
- package/rcf/requirements/req-103.json +13 -0
- package/rcf/requirements/req-104.json +13 -0
- package/rcf/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +15 -0
- package/rcf/tacs/tac-3501-edge-cloudflare-access-jwt-validator.json +15 -0
- package/rcf/tacs/tac-3502-edge-cloudflare-access-application-declaration.json +15 -0
- package/rcf/tacs/tac-3503-edge-cloudflare-access-policy-shape.json +15 -0
- package/rcf/tacs/tac-3504-edge-cloudflare-access-audit-sink.json +15 -0
- package/rcf/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +15 -0
- package/rcf/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +15 -0
- package/rcf/tacs/tac-3603-edge-cloudflare-turnstile-magic-link-hook.json +15 -0
- package/rcf/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +16 -0
- package/rcf/tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json +15 -0
- package/rcf/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +16 -0
- package/rcf/test-suites/ts-052.json +58 -8
- package/rcf/test-suites/ts-080.json +22 -0
- package/rcf/test-suites/ts-081.json +22 -0
- package/rcf/test-suites/ts-082.json +30 -0
- package/rcf/test-suites/ts-083.json +22 -0
- package/rcf/test-suites/ts-084.json +30 -0
- package/rcf/test-suites/ts-085.json +22 -0
- package/rcf/test-suites/ts-086.json +22 -0
- package/rcf/test-suites/ts-087.json +22 -0
- package/rcf/test-suites/ts-090.json +22 -0
- package/rcf/test-suites/ts-091.json +22 -0
- package/rcf/test-suites/ts-092.json +22 -0
- package/rcf/test-suites/ts-093.json +30 -0
- package/rcf/test-suites/ts-094.json +30 -0
- package/rcf/test-suites/ts-095.json +30 -0
- package/rcf/test-suites/ts-096.json +22 -0
- package/rcf/test-suites/ts-100.json +22 -0
- package/rcf/test-suites/ts-101.json +22 -0
- package/rcf/test-suites/ts-102.json +22 -0
- package/rcf/test-suites/ts-103.json +22 -0
- package/rcf/test-suites/ts-104.json +22 -0
- package/rcf/test-suites/ts-105.json +22 -0
- package/rcf/test-suites/ts-106.json +22 -0
- package/rcf/test-suites/ts-107.json +22 -0
- package/rcf/test-suites/ts-108.json +22 -0
- package/rcf/test-suites/ts-109.json +22 -0
- package/rcf/test-suites/ts-110.json +22 -0
- package/rcf/test-suites/ts-111.json +22 -0
- package/rcf/test-suites/ts-112.json +22 -0
- package/rcf/test-suites/ts-113.json +22 -0
- package/rcf/test-suites/ts-114.json +22 -0
- package/rcf/test-suites/ts-115.json +22 -0
- package/rcf/test-suites/ts-116.json +22 -0
- package/rcf/test-suites/ts-117.json +22 -0
- package/rcf/test-suites/ts-118.json +22 -0
- package/rcf/test-suites/ts-119.json +30 -0
- package/rcf/test-suites/ts-120.json +22 -0
- package/rcf/test-suites/ts-121.json +22 -0
- package/rcf/test-suites/ts-122.json +22 -0
- package/rcf/test-suites/ts-123.json +22 -0
- package/rcf/test-suites/ts-124.json +22 -0
- package/rcf/test-suites/ts-125.json +22 -0
- package/rcf/test-suites/ts-126.json +22 -0
- package/rcf/test-suites/ts-127.json +22 -0
- package/rcf/test-suites/ts-130.json +22 -0
- package/rcf/test-suites/ts-131.json +22 -0
- package/rcf/test-suites/ts-132.json +22 -0
- package/rcf/test-suites/ts-133.json +22 -0
- package/rcf/test-suites/ts-134.json +22 -0
- package/rcf/test-suites/ts-135.json +22 -0
- package/rcf/test-suites/ts-136.json +22 -0
- package/rcf/test-suites/ts-137.json +22 -0
- package/rcf/user-stories/us-10001.json +23 -0
- package/rcf/user-stories/us-10101.json +23 -0
- package/rcf/user-stories/us-10201.json +23 -0
- package/rcf/user-stories/us-10301.json +23 -0
- package/rcf/user-stories/us-10401.json +23 -0
- package/rcf/user-stories/us-10601.json +23 -0
- package/rcf/user-stories/us-10701.json +23 -0
- package/rcf/user-stories/us-10801.json +23 -0
- package/rcf/user-stories/us-5001.json +27 -0
- package/rcf/user-stories/us-5002.json +27 -0
- package/rcf/user-stories/us-5101.json +36 -0
- package/rcf/user-stories/us-5102.json +27 -0
- package/rcf/user-stories/us-5201.json +36 -0
- package/rcf/user-stories/us-5301.json +27 -0
- package/rcf/user-stories/us-5302.json +27 -0
- package/rcf/user-stories/us-5401.json +27 -0
- package/rcf/user-stories/us-6001.json +27 -0
- package/rcf/user-stories/us-6002.json +27 -0
- package/rcf/user-stories/us-6003.json +27 -0
- package/rcf/user-stories/us-6101.json +36 -0
- package/rcf/user-stories/us-6201.json +36 -0
- package/rcf/user-stories/us-6301.json +36 -0
- package/rcf/user-stories/us-6302.json +27 -0
- package/rcf/user-stories/us-7001.json +27 -0
- package/rcf/user-stories/us-7002.json +27 -0
- package/rcf/user-stories/us-7101.json +27 -0
- package/rcf/user-stories/us-7201.json +27 -0
- package/rcf/user-stories/us-7301.json +27 -0
- package/rcf/user-stories/us-7401.json +27 -0
- package/rcf/user-stories/us-7402.json +27 -0
- package/rcf/user-stories/us-7501.json +27 -0
- package/rcf/user-stories/us-7601.json +27 -0
- package/rcf/user-stories/us-7701.json +27 -0
- package/rcf/user-stories/us-8001.json +24 -0
- package/rcf/user-stories/us-8002.json +24 -0
- package/rcf/user-stories/us-8003.json +24 -0
- package/rcf/user-stories/us-8101.json +24 -0
- package/rcf/user-stories/us-8201.json +24 -0
- package/rcf/user-stories/us-8301.json +24 -0
- package/rcf/user-stories/us-8401.json +24 -0
- package/rcf/user-stories/us-8501.json +24 -0
- package/rcf/user-stories/us-8502.json +24 -0
- package/rcf/user-stories/us-8601.json +24 -0
- package/rcf/user-stories/us-8602.json +24 -0
- package/rcf/user-stories/us-9001.json +27 -0
- package/rcf/user-stories/us-9002.json +27 -0
- package/rcf/user-stories/us-9101.json +27 -0
- package/rcf/user-stories/us-9102.json +27 -0
- package/rcf/user-stories/us-9201.json +27 -0
- package/rcf/user-stories/us-9301.json +27 -0
- package/rcf/user-stories/us-9302.json +27 -0
- package/rcf/user-stories/us-9401.json +27 -0
- package/releases/releases.yaml +11 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# edge-cloudflare-access guide
|
|
2
|
+
|
|
3
|
+
## When to reach for this blueprint
|
|
4
|
+
|
|
5
|
+
You reach for `edge-cloudflare-access` when your Workers project
|
|
6
|
+
needs an authenticated edge (only authenticated principals reach
|
|
7
|
+
the origin Worker), when you have adopted the Zero Trust posture,
|
|
8
|
+
and when you want a vendor-neutral seam (`request.auth`) between
|
|
9
|
+
Cloudflare's Access edge and your downstream handlers.
|
|
10
|
+
|
|
11
|
+
If you are shipping a fully-public Worker (no authentication at all),
|
|
12
|
+
this blueprint is not for you. If you are running a security-auth-*
|
|
13
|
+
blueprint inside the Worker (in-app authentication), you probably
|
|
14
|
+
also want Cloudflare Access as a second layer to keep unauthenticated
|
|
15
|
+
traffic off the origin; the composition is straightforward.
|
|
16
|
+
|
|
17
|
+
## Composition with application-admin-console
|
|
18
|
+
|
|
19
|
+
Applying `application-admin-console` v1.1.0 alongside this blueprint
|
|
20
|
+
flips the admin-console sign-in surface (`/admin/sign-in`):
|
|
21
|
+
|
|
22
|
+
- With `zeroTrustGate` in the applied capability set (this
|
|
23
|
+
blueprint declares it): the sign-in page renders
|
|
24
|
+
`[data-surface=access-gated]` with no local form.
|
|
25
|
+
- Without `zeroTrustGate` (this blueprint not applied): the
|
|
26
|
+
sign-in page renders `[data-surface=local-login]` with the local
|
|
27
|
+
`security-auth-*` form unchanged from v1.0.0.
|
|
28
|
+
|
|
29
|
+
The Q4 default (spec section 5.4.1) is: consumption is OPTIONAL.
|
|
30
|
+
The v1.1.0 admin-console remains backward-compatible with every
|
|
31
|
+
v1.0.0 deployment.
|
|
32
|
+
|
|
33
|
+
## Elicited parameters at apply
|
|
34
|
+
|
|
35
|
+
- `access-application-host` OR `access-selfhosted-app-id`: pick
|
|
36
|
+
exactly one. The dashboard walk-through follows the hostname
|
|
37
|
+
path when the first is set and the self-hosted-app id path
|
|
38
|
+
when the second is set.
|
|
39
|
+
- `access-audience`: the JWT audience tag the Access policy issues.
|
|
40
|
+
Every JWT the validator accepts must carry this string as its
|
|
41
|
+
`aud` claim.
|
|
42
|
+
- `access-jwks-url`: the JWKS endpoint URL the validator fetches.
|
|
43
|
+
Cloudflare Access publishes this at
|
|
44
|
+
`https://<team>.cloudflareaccess.com/cdn-cgi/access/certs`.
|
|
45
|
+
- `access-policy-shape` (default `email-domain`): one of the four
|
|
46
|
+
values in the enum below.
|
|
47
|
+
- `access-bypass-service-auth-id`: leave blank to disable
|
|
48
|
+
break-glass. When set, the paired secret is delegated to the
|
|
49
|
+
applied `secretsManagement` companion.
|
|
50
|
+
|
|
51
|
+
## Policy shape enum
|
|
52
|
+
|
|
53
|
+
| Shape | What it allows | Suited to |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `email-domain` | Any principal whose email ends `@<domain>` on the Access-managed identity provider. | Solo, small team, workspace-wide access on a company domain. |
|
|
56
|
+
| `service-token-only` | Only the elicited bypass-service-auth pair; no browser principals. | CI-only endpoints (webhooks, ingest APIs). |
|
|
57
|
+
| `service-token-plus-email-domain` | Either the paired service-auth or an on-domain email principal. | Endpoints reached by CI AND humans. |
|
|
58
|
+
| `group-membership` | Only principals whose identity-provider group claim contains an elicited group name (Okta, Entra ID, Google Groups). | Enterprise SSO with role-based access. |
|
|
59
|
+
|
|
60
|
+
The Cloudflare edge enforces the shape before a request reaches
|
|
61
|
+
the origin Worker; the shipped validator receives the JWT the
|
|
62
|
+
Access edge signs and verifies the audience, the expiry and the
|
|
63
|
+
signature.
|
|
64
|
+
|
|
65
|
+
## Zero Trust dashboard walk-through
|
|
66
|
+
|
|
67
|
+
Screen-by-screen path for a fresh Cloudflare account. Vendor URL:
|
|
68
|
+
`https://developers.cloudflare.com/cloudflare-one/policies/access/`.
|
|
69
|
+
|
|
70
|
+
1. Sign in to `dash.cloudflare.com` and select your account.
|
|
71
|
+
2. In the left nav, open `Zero Trust`. If the dashboard prompts
|
|
72
|
+
you to create a team, do so with the elicited team name (the
|
|
73
|
+
`<team>` in `https://<team>.cloudflareaccess.com/`).
|
|
74
|
+
3. In the Zero Trust dashboard, open `Access` -> `Applications`,
|
|
75
|
+
then `Add an application`.
|
|
76
|
+
4. Pick `Self-hosted` (both for hostname-scoped applications and
|
|
77
|
+
for self-hosted-app id-based applications).
|
|
78
|
+
5. Enter the application name (`admin.example.com` for the
|
|
79
|
+
hostname path or the app id string for the self-hosted-app id
|
|
80
|
+
path), the session duration (default 24h is fine for an
|
|
81
|
+
internal console) and the application domain (the hostname
|
|
82
|
+
the Worker binds to).
|
|
83
|
+
6. On the `Add policies` screen, `Add a policy`.
|
|
84
|
+
7. On the policy screen, pick the `Action` (`Allow` for the
|
|
85
|
+
principal set the shape names above), then add one `Include`
|
|
86
|
+
selector matching the shape:
|
|
87
|
+
- `email-domain`: `Include -> Email ending in` -> your domain.
|
|
88
|
+
- `service-token-only`: `Include -> Service Auth Token` -> the
|
|
89
|
+
token generated in `Zero Trust` -> `Access` -> `Service Auth`.
|
|
90
|
+
- `service-token-plus-email-domain`: add both selectors.
|
|
91
|
+
- `group-membership`: `Include -> IdP Group name` -> the group
|
|
92
|
+
the elicited identity-provider claims.
|
|
93
|
+
8. Save the policy, save the application. The dashboard prints
|
|
94
|
+
the `Application audience tag` at the top of the application
|
|
95
|
+
card; copy it verbatim into the `access-audience` elicit
|
|
96
|
+
answer on apply.
|
|
97
|
+
9. Confirm the JWKS endpoint at
|
|
98
|
+
`https://<team>.cloudflareaccess.com/cdn-cgi/access/certs`
|
|
99
|
+
returns a valid JWKS document; copy the URL into the
|
|
100
|
+
`access-jwks-url` elicit answer.
|
|
101
|
+
|
|
102
|
+
The blueprint is now ready to apply on the Worker project.
|
|
103
|
+
|
|
104
|
+
## API alternative
|
|
105
|
+
|
|
106
|
+
If you prefer to script the policy issuance rather than click
|
|
107
|
+
through the dashboard, use the Cloudflare API. Vendor URL:
|
|
108
|
+
`https://developers.cloudflare.com/cloudflare-one/policies/access/`.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
curl -X POST \
|
|
112
|
+
https://api.cloudflare.com/client/v4/accounts/{account_id}/access/apps/{app_id}/policies \
|
|
113
|
+
-H "Authorization: Bearer $CF_API_TOKEN" \
|
|
114
|
+
-H "Content-Type: application/json" \
|
|
115
|
+
-d '{
|
|
116
|
+
"name": "Access policy for admin.example.com",
|
|
117
|
+
"decision": "allow",
|
|
118
|
+
"include": [
|
|
119
|
+
{ "email_domain": { "domain": "example.com" } }
|
|
120
|
+
],
|
|
121
|
+
"session_duration": "24h"
|
|
122
|
+
}'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Replace the `include` block with the shape you picked from the
|
|
126
|
+
enum. The `app_id` is the value the dashboard printed when the
|
|
127
|
+
application was created; the `account_id` is the standard
|
|
128
|
+
Cloudflare account id from your account settings. The endpoint is
|
|
129
|
+
idempotent when the policy name matches an existing policy per
|
|
130
|
+
Cloudflare's documented semantics.
|
|
131
|
+
|
|
132
|
+
## Break-glass posture
|
|
133
|
+
|
|
134
|
+
Set `access-bypass-service-auth-id` at apply to enable break-glass.
|
|
135
|
+
The paired secret is delegated to the applied `secretsManagement`
|
|
136
|
+
companion via `security-secrets-management`; the CI runner then
|
|
137
|
+
supplies both values as `CF-Access-Client-Id` and
|
|
138
|
+
`CF-Access-Client-Secret` headers on every request that would
|
|
139
|
+
otherwise fail Access at the browser boundary. The validator
|
|
140
|
+
observes the pair, records `outcome: bypass` on the audit sink
|
|
141
|
+
with the metadata-only shape, and delegates to the handler with
|
|
142
|
+
`request.auth.email = 'service:'+id`.
|
|
143
|
+
|
|
144
|
+
The break-glass code path is disabled unless an elicited pair is
|
|
145
|
+
applied; a request presenting the paired headers when no pair is
|
|
146
|
+
elicited is rejected as `missing` (fall through to the JWT path).
|
|
147
|
+
|
|
148
|
+
## Composed apply-line
|
|
149
|
+
|
|
150
|
+
One project, admin-console v1.1.0 plus edge-cloudflare-access
|
|
151
|
+
v1.0.0, `email-domain` policy shape:
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
rcf define blueprint add application-admin-console --version 1.1.0
|
|
155
|
+
rcf define blueprint add edge-cloudflare-access --version 1.0.0 \
|
|
156
|
+
--answer access-application-host=admin.example.com \
|
|
157
|
+
--answer access-audience=<audience-copied-from-dashboard> \
|
|
158
|
+
--answer access-jwks-url=https://<team>.cloudflareaccess.com/cdn-cgi/access/certs \
|
|
159
|
+
--answer access-policy-shape=email-domain
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The admin-console applies first (its `principalDirectory`
|
|
163
|
+
requirement is met by whatever `security-auth-*` you have
|
|
164
|
+
applied). The Access blueprint applies second, records
|
|
165
|
+
`zeroTrustGate` on `rcf/blueprints/edge-cloudflare-access.applied.json`,
|
|
166
|
+
and the admin-console's next surface render picks the Access-gated
|
|
167
|
+
branch on `/admin/sign-in`.
|
|
168
|
+
|
|
169
|
+
## Standards trace
|
|
170
|
+
|
|
171
|
+
- `ADR-3501-edge-cloudflare-access-jwt-gate` carries
|
|
172
|
+
`standardsTraceClause: Cloudflare Access policy actions and rule
|
|
173
|
+
selectors` per
|
|
174
|
+
https://developers.cloudflare.com/cloudflare-one/policies/access/.
|
|
175
|
+
- `ADR-3503-edge-cloudflare-access-policy-scope` carries the same
|
|
176
|
+
clause.
|
|
177
|
+
- `ADR-3502-edge-cloudflare-access-identity-provider` and
|
|
178
|
+
`ADR-3504-edge-cloudflare-access-audit-retention` carry the
|
|
179
|
+
sentinel `generic enterprise practice` (no vendor documentation
|
|
180
|
+
constrains identity provider or audit retention).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# edge-cloudflare-rate-limiting changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (round 6 T-6, 2026-09-07)
|
|
4
|
+
|
|
5
|
+
- First shipped version. Zone-level rate limiting as an edge gate in front of Worker handlers per the ratified `cloudflare-round-6-spec-2026-09-06.md` section 5.6.
|
|
6
|
+
- Five REQs, eight USs, three TACs, four ADRs. Twenty contributions total.
|
|
7
|
+
- Ships the local rate-limit rules manifest schema (draft-07), the operator-facing management surface guide with both wrangler and dashboard flows, the drift-audit runner realisation on the `cf-edge` fixture and the composition ADR with `security-auth-magic-link`.
|
|
8
|
+
- Mints capability `edgeRateLimit` and global topic `edgeThrottleContract` (ADR-3701, scope global).
|
|
9
|
+
- Four Node-only probes: `manifest-presence`, `manifest-schema-validate`, `event-secrecy`, `real-account-burst-and-429`. The last carries `accountBound: true` and records `accountBoundSkipped: true` in CI without `CI_HAS_CLOUDFLARE_ACCOUNT` per spec section 3.5 and ruling 6.
|
|
10
|
+
- `cf-edge` fixture extended additively: `cloudflare/rate-limits/example.json`, `cloudflare/rate-limits/api-writes.json`, `src/drift-audit-runner.mjs`, three induced-failure switches (`SIMULATE_MANIFEST_MISSING`, `SIMULATE_SCHEMA_INVALID`, `SIMULATE_EVENT_LEAK_IP`).
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# edge-cloudflare-rate-limiting
|
|
2
|
+
|
|
3
|
+
Zone-level rate limiting as an edge gate in front of Worker handlers, configured through a local manifest the applying project commits and applies to the live Cloudflare zone via a documented wrangler or dashboard flow. Ships v1.0.0 of the round-6 T-6 track per `projects/blueprint-library/specs/cloudflare-round-6-spec-2026-09-06.md` section 5.6.
|
|
4
|
+
|
|
5
|
+
- **Category:** `edge`.
|
|
6
|
+
- **Capability provided:** `edgeRateLimit`.
|
|
7
|
+
- **Global topic minted:** `edgeThrottleContract` (ADR-3701, scope global).
|
|
8
|
+
- **Suggested companions:** `logging`, `errorHandling`, `secretsManagement`.
|
|
9
|
+
|
|
10
|
+
## The five REQs
|
|
11
|
+
|
|
12
|
+
| Id | What it commits |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| REQ-001 | Local rules manifest: one JSON file per rule under the elicited `rate-limit-rules-dir` (default `cloudflare/rate-limits/`) carries the seven documented fields. |
|
|
15
|
+
| REQ-002 | Operator-facing management surface: a documented wrangler or Cloudflare-dashboard flow the operator runs to apply the manifest to the live zone. No committed script. |
|
|
16
|
+
| REQ-003 | Over-threshold behaviour: over the rule limit within the period, the (N+1)th and subsequent requests within the elicited duration return 429 with `Retry-After` and `Cf-Ray`; the origin never sees them. |
|
|
17
|
+
| REQ-004 | Drift audit: an opt-in scheduled runner reads live zone rules via the Cloudflare API and diffs against the local manifest, constructing metadata-only records per REQ-005 event-secrecy. |
|
|
18
|
+
| REQ-005 | Composition with `security-auth-magic-link`: the zone rule sits OVER the per-email application rule per ADR-3702 layering. |
|
|
19
|
+
|
|
20
|
+
## Elicited parameters
|
|
21
|
+
|
|
22
|
+
- `rate-limit-rules-dir` (default `cloudflare/rate-limits`): where the applying project commits manifest files.
|
|
23
|
+
- `rate-limit-zone-id` (default empty): the Cloudflare zone id the rules apply to. Never inlined in a manifest file; stored via the applied `secretsManagement` companion.
|
|
24
|
+
- `rate-limit-management-surface` (default `both`): `wrangler`, `dashboard`, or `both`. Records the operator's flow choice; the guide walks both.
|
|
25
|
+
- `rate-limit-drift-audit-cadence` (default `daily`): `off`, `daily`, `hourly`. Per ADR-3704.
|
|
26
|
+
|
|
27
|
+
## Manifest shape (TAC-3701)
|
|
28
|
+
|
|
29
|
+
The shipped JSON Schema at `contributions/schemas/rate-limit-rule.schema.json` (draft-07) names the seven required fields per `https://developers.cloudflare.com/waf/rate-limiting-rules/`:
|
|
30
|
+
|
|
31
|
+
| Field | Type | Meaning |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `id` | string | Stable operator-facing rule id (kebab-case). Used as `ruleId` in drift-audit records. |
|
|
34
|
+
| `expression` | string | Cloudflare WAF rules-language expression scoping the rule. |
|
|
35
|
+
| `threshold` | integer >=1 | Requests permitted per period on the characteristic set. |
|
|
36
|
+
| `period` | integer >=1 | Window in seconds the threshold applies over. |
|
|
37
|
+
| `characteristics` | string[] (non-empty) | Characteristic strings the rule keys on (e.g. `ip.src`, `cf.colo.id`). |
|
|
38
|
+
| `action` | enum | `block`, `challenge`, `log`, `managed_challenge`. |
|
|
39
|
+
| `duration` | integer >=1 | Block window in seconds the (N+1)th and subsequent requests are refused for. |
|
|
40
|
+
|
|
41
|
+
`additionalProperties: false`; a `description` field is optional.
|
|
42
|
+
|
|
43
|
+
## Probes
|
|
44
|
+
|
|
45
|
+
Four Node-only probes under `contributions/probes/`; three run in CI, one is account-bound and skips per ruling 6.
|
|
46
|
+
|
|
47
|
+
| Probe | Anchor AC | `accountBound` | What it drives |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `manifest-presence.mjs` | AC-36101-1 (also AC-36108-1 under `SIMULATE_MANIFEST_MISSING=true`) | false | Reads `cf-edge/cloudflare/rate-limits/`, asserts every file parses, carries the seven required fields and holds no plaintext secret. |
|
|
50
|
+
| `manifest-schema-validate.mjs` | AC-36106-1 | false | Validates every manifest file against the shipped JSON Schema. Under `SIMULATE_SCHEMA_INVALID=true` writes a scratch file missing `threshold` and fails. |
|
|
51
|
+
| `event-secrecy.mjs` | AC-36107-1 | false | Drives the shipped drift-audit runner realisation with a synthetic manifest and a fake fetch; asserts every drift record carries only `{ruleId, clientIpHash, outcome, timestamp, diff}`. Under `SIMULATE_EVENT_LEAK_IP=true` the runner injects a full IP and the probe fails. |
|
|
52
|
+
| `real-account-burst-and-429.mjs` | AC-36103-1 | true | Fires an in-process burst against `CF_RATE_LIMIT_URL` under `CI_HAS_CLOUDFLARE_ACCOUNT=true` and asserts the (N+1)th and subsequent responses return 429 with `Retry-After` and `Cf-Ray`. Without either env var records `accountBoundSkipped: true` and aggregates to `pass` per spec section 3.5 and ruling 6. |
|
|
53
|
+
|
|
54
|
+
### Ruling 6 restated
|
|
55
|
+
|
|
56
|
+
Spec section 1, verbatim: "If the rate-limiting real-account burst probe is not CI-feasible, ship with the local manifest AC and mark the burst check account-bound skipped." Without `CI_HAS_CLOUDFLARE_ACCOUNT` the CI verdict for `real-account-burst-and-429` is `accountBoundSkipped: true` and this IS the accepted verdict; the aggregate flips to `pass`. The local manifest ACs (AC-36101-1, AC-36106-1, AC-36107-1) always run and always gate the ship.
|
|
57
|
+
|
|
58
|
+
## Composition with `security-auth-magic-link` (ADR-3702)
|
|
59
|
+
|
|
60
|
+
When both blueprints apply, the zone-level rate rule (characteristic set: IP-per-URL) sits at the CF edge and refuses the (N+1)th request for the elicited duration before it reaches the origin; the `security-auth-magic-link` per-email application rate limiter (characteristic set: per-email per-minute) continues to run on requests that pass the edge gate at the mint-surface. The two rules operate on different characteristic sets and are additive, not overlapping. See the guide for a copy-paste example.
|
|
61
|
+
|
|
62
|
+
## Standards trace
|
|
63
|
+
|
|
64
|
+
- ADR-3701: `Cloudflare WAF rate-limiting rules documented shape` (`https://developers.cloudflare.com/waf/rate-limiting-rules/`).
|
|
65
|
+
- ADR-3702, ADR-3703, ADR-3704: `generic enterprise practice`.
|
|
66
|
+
|
|
67
|
+
## Vendor citations
|
|
68
|
+
|
|
69
|
+
- Cloudflare WAF rate-limiting rules: `https://developers.cloudflare.com/waf/rate-limiting-rules/` (documents `expression`, `threshold`, `period`, `characteristics`, `action`, `duration`; fetched 200 on 2026-09-07 for the round-6 T-6 ship).
|
|
70
|
+
|
|
71
|
+
## Known mechanism-reach gaps
|
|
72
|
+
|
|
73
|
+
- The over-threshold observable (AC-36103-1) is only proven at the runtime seam with a real Cloudflare account. In CI without `CI_HAS_CLOUDFLARE_ACCOUNT` the probe records `accountBoundSkipped: true` per ruling 6; the local manifest and event-secrecy ACs cover source-observable correctness.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "edge-cloudflare-rate-limiting",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "edge",
|
|
5
|
+
"capabilities": [
|
|
6
|
+
"edgeRateLimit"
|
|
7
|
+
],
|
|
8
|
+
"suggestedCompanions": [
|
|
9
|
+
{
|
|
10
|
+
"role": "logging",
|
|
11
|
+
"reason": "Every drift-audit report and every rate-limit event writes through the applied logger; a logging companion supplies the sink factory."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"role": "errorHandling",
|
|
15
|
+
"reason": "A drift-audit failure, a Cloudflare API error, a manifest schema violation constructs an internal error record; an error-handling companion supplies the record factory and the boundary."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"role": "secretsManagement",
|
|
19
|
+
"reason": "The Cloudflare API token that the drift-audit runner and any wrangler-based apply flow use is stored via the applied secretsManagement companion; the elicited zone id may also be projected through the vault when the operator wants a single source of truth."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"elicits": [
|
|
23
|
+
{
|
|
24
|
+
"id": "rate-limit-rules-dir",
|
|
25
|
+
"prompt": "Directory the applying project commits its rate-limit rule manifest files into. One file per rule per ADR-3703. The manifest is source-of-truth; the operator applies it via wrangler or the Cloudflare dashboard per REQ-002.",
|
|
26
|
+
"kind": "string",
|
|
27
|
+
"default": "cloudflare/rate-limits"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "rate-limit-zone-id",
|
|
31
|
+
"prompt": "Cloudflare zone id the rules apply to. Never inline in a rule manifest; store via the applied secretsManagement companion and reference at apply time. Empty string leaves the zone id unresolved (the drift audit and any wrangler flow surface the omission).",
|
|
32
|
+
"kind": "string",
|
|
33
|
+
"default": ""
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"id": "rate-limit-management-surface",
|
|
37
|
+
"prompt": "Operator-facing management surface per REQ-002 and TAC-3702. wrangler names the command flow the guide walks through; dashboard names the Cloudflare dashboard flow; both records both flows and lets the operator pick per rule.",
|
|
38
|
+
"kind": "enum",
|
|
39
|
+
"options": [
|
|
40
|
+
"wrangler",
|
|
41
|
+
"dashboard",
|
|
42
|
+
"both"
|
|
43
|
+
],
|
|
44
|
+
"default": "both"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "rate-limit-drift-audit-cadence",
|
|
48
|
+
"prompt": "Drift-audit cadence per ADR-3704. off disables the runner; daily runs it every 24 hours; hourly runs it every hour. daily is the recommended default.",
|
|
49
|
+
"kind": "enum",
|
|
50
|
+
"options": [
|
|
51
|
+
"off",
|
|
52
|
+
"daily",
|
|
53
|
+
"hourly"
|
|
54
|
+
],
|
|
55
|
+
"default": "daily"
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"contributions": [
|
|
59
|
+
{
|
|
60
|
+
"id": "edge-cloudflare-rate-limiting-REQ-001",
|
|
61
|
+
"kind": "req",
|
|
62
|
+
"path": "requirements/edge-cloudflare-rate-limiting-req-001.json"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"id": "edge-cloudflare-rate-limiting-REQ-002",
|
|
66
|
+
"kind": "req",
|
|
67
|
+
"path": "requirements/edge-cloudflare-rate-limiting-req-002.json"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "edge-cloudflare-rate-limiting-REQ-003",
|
|
71
|
+
"kind": "req",
|
|
72
|
+
"path": "requirements/edge-cloudflare-rate-limiting-req-003.json"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "edge-cloudflare-rate-limiting-REQ-004",
|
|
76
|
+
"kind": "req",
|
|
77
|
+
"path": "requirements/edge-cloudflare-rate-limiting-req-004.json"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "edge-cloudflare-rate-limiting-REQ-005",
|
|
81
|
+
"kind": "req",
|
|
82
|
+
"path": "requirements/edge-cloudflare-rate-limiting-req-005.json"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "edge-cloudflare-rate-limiting-US-36101",
|
|
86
|
+
"kind": "us",
|
|
87
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36101.json"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "edge-cloudflare-rate-limiting-US-36102",
|
|
91
|
+
"kind": "us",
|
|
92
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36102.json"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "edge-cloudflare-rate-limiting-US-36103",
|
|
96
|
+
"kind": "us",
|
|
97
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36103.json"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "edge-cloudflare-rate-limiting-US-36104",
|
|
101
|
+
"kind": "us",
|
|
102
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36104.json"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "edge-cloudflare-rate-limiting-US-36105",
|
|
106
|
+
"kind": "us",
|
|
107
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36105.json"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "edge-cloudflare-rate-limiting-US-36106",
|
|
111
|
+
"kind": "us",
|
|
112
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36106.json"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "edge-cloudflare-rate-limiting-US-36107",
|
|
116
|
+
"kind": "us",
|
|
117
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36107.json"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "edge-cloudflare-rate-limiting-US-36108",
|
|
121
|
+
"kind": "us",
|
|
122
|
+
"path": "user-stories/edge-cloudflare-rate-limiting-us-36108.json"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "TAC-3701-edge-cloudflare-rate-limiting-manifest-schema",
|
|
126
|
+
"kind": "tac",
|
|
127
|
+
"path": "tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"id": "TAC-3702-edge-cloudflare-rate-limiting-management-surface-doc",
|
|
131
|
+
"kind": "tac",
|
|
132
|
+
"path": "tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "TAC-3703-edge-cloudflare-rate-limiting-drift-audit-runner",
|
|
136
|
+
"kind": "tac",
|
|
137
|
+
"path": "tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "ADR-3701-edge-cloudflare-rate-limiting-throttle-contract",
|
|
141
|
+
"kind": "adr",
|
|
142
|
+
"path": "adrs/adr-3701-edge-cloudflare-rate-limiting-throttle-contract.json",
|
|
143
|
+
"scope": "global",
|
|
144
|
+
"topic": "edgeThrottleContract",
|
|
145
|
+
"recommendedDefault": true,
|
|
146
|
+
"elicited": false,
|
|
147
|
+
"standardsTraceClause": "Cloudflare WAF rate-limiting rules documented shape"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"id": "ADR-3702-edge-cloudflare-rate-limiting-layering",
|
|
151
|
+
"kind": "adr",
|
|
152
|
+
"path": "adrs/adr-3702-edge-cloudflare-rate-limiting-layering.json",
|
|
153
|
+
"recommendedDefault": true,
|
|
154
|
+
"elicited": false,
|
|
155
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"id": "ADR-3703-edge-cloudflare-rate-limiting-manifest-shape",
|
|
159
|
+
"kind": "adr",
|
|
160
|
+
"path": "adrs/adr-3703-edge-cloudflare-rate-limiting-manifest-shape.json",
|
|
161
|
+
"recommendedDefault": true,
|
|
162
|
+
"elicited": false,
|
|
163
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"id": "ADR-3704-edge-cloudflare-rate-limiting-drift-audit-cadence",
|
|
167
|
+
"kind": "adr",
|
|
168
|
+
"path": "adrs/adr-3704-edge-cloudflare-rate-limiting-drift-audit-cadence.json",
|
|
169
|
+
"recommendedDefault": true,
|
|
170
|
+
"elicited": true,
|
|
171
|
+
"standardsTraceClause": "generic enterprise practice"
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-3701-edge-cloudflare-rate-limiting-throttle-contract",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Edge throttle contract: Cloudflare WAF rate-limiting rules as the shipped shape (scope global, new topic edgeThrottleContract)",
|
|
8
|
+
"context": "An applying Workers project that fronts a public surface needs a zone-level guard that refuses over-threshold bursts at the CF edge before they reach the origin Worker. Cloudflare's WAF rate-limiting rules provide the native answer: a set of rules on the zone, each with expression, threshold, period, characteristics, action and duration per https://developers.cloudflare.com/waf/rate-limiting-rules/. Every applied Worker needs one project-wide answer to the edgeThrottleContract topic; a future non-Cloudflare edge-throttle sibling (Fastly rate-limits, Vercel edge config throttles) would conflict on the same topic by design.",
|
|
9
|
+
"decision": "The shipped v1.0.0 default is Cloudflare WAF rate-limiting rules as the zone-level edge throttle. The rule shape (id, expression, threshold, period, characteristics, action, duration) matches the Cloudflare-documented shape per https://developers.cloudflare.com/waf/rate-limiting-rules/. The edgeThrottleContract topic scope is global on this blueprint; the topic string is edgeThrottleContract (lower camel case, one concept per topic, no version suffix). A future non-Cloudflare adapter contributes the same topic string with a different answer, forcing a DELIBERATE conflict the operator resolves with a project-level ADR. Standards trace clause: Cloudflare WAF rate-limiting rules documented shape.",
|
|
10
|
+
"consequences": "The applying project inherits Cloudflare's documented rule shape and the platform-imposed limits on rules per zone. The rule state lives on the Cloudflare account, not in the project git tree; the local manifest under cloudflare/rate-limits/ is the source of truth an operator applies via the wrangler or dashboard flow per REQ-002. Drift risk is addressed via ADR-3704 (drift-audit cadence) and TAC-3703 (drift-audit runner). Consumers deploying to a non-Cloudflare edge reach for a sibling adapter blueprint that would land as a v1.x minor on this shelf.",
|
|
11
|
+
"alternativesConsidered": [],
|
|
12
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
13
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-3702-edge-cloudflare-rate-limiting-layering",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Layering with security-auth-magic-link: zone rate rule sits OVER the per-email application rule",
|
|
8
|
+
"context": "The security-auth-magic-link blueprint ships a per-email per-minute application-level rate limiter on the mint surface. The edge-cloudflare-rate-limiting blueprint ships a zone-level rate rule characterised by IP-per-URL at the CF edge. Applying both blueprints without an explicit layering ADR would leave two rate rules whose characteristic sets an operator could easily mistake for overlapping.",
|
|
9
|
+
"decision": "When both blueprints are applied, the zone-level rate rule sits at the CF edge and refuses the (N+1)th request for the elicited duration before it reaches the origin Worker; the security-auth-magic-link per-email application limiter continues to run on requests that pass the edge gate, applying per-email per-minute limits at the mint-surface. The two rules operate on different characteristic sets (IP-per-URL at the zone, email at the application) and are additive, not overlapping. recommendedDefault: true. Standards trace clause: generic enterprise practice.",
|
|
10
|
+
"consequences": "The composition is documented in the blueprint guide with a copy-paste example (AC-36105-1). The applied recorder records both blueprints so the operator sees the two-rule shape at apply time; a subsequent change to either rule's characteristic that would drift the composition into overlap is caught in the drift-audit runner (TAC-3703).",
|
|
11
|
+
"alternativesConsidered": [],
|
|
12
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
13
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-3703-edge-cloudflare-rate-limiting-manifest-shape",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Manifest lives at cloudflare/rate-limits/, one JSON file per rule; the operator applies via wrangler or dashboard, not via a committed script",
|
|
8
|
+
"context": "The rule set could be committed as a wrangler-shape script, a bespoke apply tool, a single manifest file, or one file per rule. The single-file shape hides diff signal when one rule changes; the committed script couples the source of truth to a specific tool. The one-file-per-rule shape keeps a rule change to one file diff, makes review straightforward, and leaves the apply flow to the operator's choice of wrangler or dashboard.",
|
|
9
|
+
"decision": "The manifest lives at the elicited rate-limit-rules-dir (default cloudflare/rate-limits/), with one JSON file per rule. The blueprint ships no committed script that writes rules to the live zone; the operator applies through the documented wrangler or dashboard flow per REQ-002 and TAC-3702. recommendedDefault: true. Standards trace clause: generic enterprise practice.",
|
|
10
|
+
"consequences": "One-file-per-rule keeps each rule diff scoped; the operator can review a rule change in isolation. No committed apply script means the shipped blueprint does not couple to a specific tool version and does not require a Cloudflare API token at build time. Operator applies the manifest at a cadence they set; drift risk is addressed via ADR-3704 and TAC-3703.",
|
|
11
|
+
"alternativesConsidered": [],
|
|
12
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
13
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"adrId": "ADR-3704-edge-cloudflare-rate-limiting-drift-audit-cadence",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "accepted",
|
|
7
|
+
"title": "Drift-audit cadence: off, daily or hourly (elicited; recommendedDefault daily)",
|
|
8
|
+
"context": "Rate-limit rules live on the Cloudflare account, not in the project git tree. An operator that changes a rule on the dashboard without a matching manifest update leaves the source of truth behind; a manifest edit that is not applied to the live zone leaves the live behaviour behind. Both directions of drift are runtime-observable but only if the applying project runs the drift-audit runner at a cadence.",
|
|
9
|
+
"decision": "The drift-audit cadence is elicited (rate-limit-drift-audit-cadence) with three options: off (disables the runner), daily (24-hour cadence), hourly (60-minute cadence). recommendedDefault: daily. elicited: true. Standards trace clause: generic enterprise practice.",
|
|
10
|
+
"consequences": "daily is the safe default for the typical operator (a manifest change that misses the live zone is surfaced within 24 hours through the applied logging companion's audit sink). hourly is the safe default for a high-cadence operation (the applying project makes rule changes multiple times a week and wants a same-day signal). off is safe only when the operator has an alternative drift-check discipline (a manual review after every change); the elicit prompts for the operator's choice at apply time.",
|
|
11
|
+
"alternativesConsidered": [],
|
|
12
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
13
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
14
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Probe: drift-audit event secrecy.
|
|
2
|
+
//
|
|
3
|
+
// anchorAcId: AC-36107-1. accountBound: false.
|
|
4
|
+
//
|
|
5
|
+
// Drives the shipped drift-audit runner realisation
|
|
6
|
+
// (packages/rcf-lite/test/fixtures/cf-edge/src/drift-audit-runner.mjs)
|
|
7
|
+
// with a synthetic manifest loader and a fake fetch that returns a
|
|
8
|
+
// live-zone response with one mismatched rule. Asserts every record
|
|
9
|
+
// on the sink carries only {ruleId, clientIpHash, outcome, timestamp,
|
|
10
|
+
// diff} keys and NO full IPv4 or IPv6 address, NO body key, NO user
|
|
11
|
+
// agent key. Under SIMULATE_EVENT_LEAK_IP=true the runner injects a
|
|
12
|
+
// full client IP into the outcome so the probe surfaces the leak.
|
|
13
|
+
|
|
14
|
+
import { FIXTURE_DIR } from './probe-utils.mjs';
|
|
15
|
+
|
|
16
|
+
export const anchorAcId = 'AC-36107-1';
|
|
17
|
+
export const accountBound = false;
|
|
18
|
+
|
|
19
|
+
const IPV4 = /\b(?:25[0-5]|2[0-4]\d|[01]?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)){3}\b/;
|
|
20
|
+
const IPV6 = /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/;
|
|
21
|
+
const ALLOWED_KEYS = new Set(['ruleId', 'clientIpHash', 'outcome', 'timestamp', 'diff']);
|
|
22
|
+
const FORBIDDEN_KEYS = new Set(['body', 'userAgent', 'user-agent', 'clientIp', 'ip', 'sourceIp']);
|
|
23
|
+
|
|
24
|
+
function containsIp(text) {
|
|
25
|
+
if (typeof text !== 'string') return null;
|
|
26
|
+
const v4 = text.match(IPV4);
|
|
27
|
+
if (v4) return v4[0];
|
|
28
|
+
const v6 = text.match(IPV6);
|
|
29
|
+
if (v6) return v6[0];
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default async function runProbe() {
|
|
34
|
+
const runnerMod = await import(`${FIXTURE_DIR}/src/drift-audit-runner.mjs`);
|
|
35
|
+
const manifestRule = {
|
|
36
|
+
id: 'public-api-per-ip',
|
|
37
|
+
expression: '(http.request.uri.path matches "^/api/")',
|
|
38
|
+
threshold: 60,
|
|
39
|
+
period: 60,
|
|
40
|
+
characteristics: ['ip.src', 'cf.colo.id'],
|
|
41
|
+
action: 'block',
|
|
42
|
+
duration: 60,
|
|
43
|
+
};
|
|
44
|
+
const liveRule = { ...manifestRule, threshold: 90 };
|
|
45
|
+
const captured = [];
|
|
46
|
+
const eventSink = (record) => captured.push(record);
|
|
47
|
+
const fakeFetch = async () => ({
|
|
48
|
+
ok: true,
|
|
49
|
+
status: 200,
|
|
50
|
+
async json() { return { result: [liveRule] }; },
|
|
51
|
+
});
|
|
52
|
+
const runner = runnerMod.createDriftAuditRunner({
|
|
53
|
+
env: {
|
|
54
|
+
CF_ZONE_ID: 'fixture-zone-id',
|
|
55
|
+
SIMULATE_EVENT_LEAK_IP: process.env.SIMULATE_EVENT_LEAK_IP,
|
|
56
|
+
},
|
|
57
|
+
eventSink,
|
|
58
|
+
fetch: fakeFetch,
|
|
59
|
+
clock: () => '2026-09-07T22:00:00.000Z',
|
|
60
|
+
cadence: 'daily',
|
|
61
|
+
manifestLoader: async () => [manifestRule],
|
|
62
|
+
});
|
|
63
|
+
const report = await runner.runOnce();
|
|
64
|
+
const results = [];
|
|
65
|
+
if (captured.length === 0) {
|
|
66
|
+
results.push({ anchorAcId: 'AC-36107-1', verdict: 'fail', detail: 'drift-audit runner produced zero records; expected one for the threshold drift.' });
|
|
67
|
+
return { results };
|
|
68
|
+
}
|
|
69
|
+
let ipLeak = null;
|
|
70
|
+
let keyLeak = null;
|
|
71
|
+
for (const rec of captured) {
|
|
72
|
+
for (const k of Object.keys(rec)) {
|
|
73
|
+
if (FORBIDDEN_KEYS.has(k)) keyLeak = k;
|
|
74
|
+
if (!ALLOWED_KEYS.has(k)) keyLeak = keyLeak || `unexpected-key:${k}`;
|
|
75
|
+
}
|
|
76
|
+
for (const v of Object.values(rec)) {
|
|
77
|
+
if (typeof v === 'string') {
|
|
78
|
+
const hit = containsIp(v);
|
|
79
|
+
if (hit) ipLeak = hit;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (keyLeak) {
|
|
84
|
+
results.push({ anchorAcId: 'AC-36107-1', verdict: 'fail', detail: `drift-audit record carries a forbidden or unexpected key: ${keyLeak}` });
|
|
85
|
+
}
|
|
86
|
+
if (ipLeak) {
|
|
87
|
+
results.push({ anchorAcId: 'AC-36107-1', verdict: 'fail', detail: `drift-audit record leaked a full IP address in a string field: ${ipLeak}` });
|
|
88
|
+
}
|
|
89
|
+
if (results.length === 0) {
|
|
90
|
+
results.push({
|
|
91
|
+
anchorAcId: 'AC-36107-1',
|
|
92
|
+
verdict: 'pass',
|
|
93
|
+
detail: `drift-audit runner produced ${captured.length} record(s); every record carries only ${[...ALLOWED_KEYS].join(', ')} and no full IP, body or user-agent field appears.`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
results,
|
|
98
|
+
extra: {
|
|
99
|
+
recordCount: captured.length,
|
|
100
|
+
driftCount: report.driftCount,
|
|
101
|
+
allowedKeys: [...ALLOWED_KEYS],
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|