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,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tacId": "TAC-3701-edge-cloudflare-rate-limiting-manifest-schema",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"name": "Rate-limit rule manifest schema and manifest layout",
|
|
8
|
+
"purpose": "The shipped JSON Schema (draft-07) at blueprints/edge-cloudflare-rate-limiting/contributions/schemas/rate-limit-rule.schema.json is the single source of truth for the shape of one manifest file under the elicited rate-limit-rules-dir. The schema names the seven Cloudflare WAF rate-limiting rules fields per https://developers.cloudflare.com/waf/rate-limiting-rules/ (id, expression, threshold, period, characteristics, action, duration), their types (string, string, positive integer, positive integer, non-empty string array, enum of block/challenge/log/managed_challenge, positive integer), and the additionalProperties: false stance. The manifest-schema-validate probe reads every file in the fixture manifest directory and validates against this schema; the manifest-presence probe asserts the seven required fields are all present. This TAC anchors AC-36101-1, AC-36106-1 and AC-36108-1.",
|
|
9
|
+
"responsibilities": [
|
|
10
|
+
"Ship a JSON Schema (draft-07) at contributions/schemas/rate-limit-rule.schema.json naming the seven required fields, their types and additionalProperties: false (AC-36101-1, AC-36106-1).",
|
|
11
|
+
"Ship the shape used by the manifest-presence probe to assert every manifest file carries the seven required fields (AC-36101-1).",
|
|
12
|
+
"Ship the shape used by the manifest-schema-validate probe to refuse a manifest file with a missing threshold under SIMULATE_SCHEMA_INVALID=true (AC-36106-1).",
|
|
13
|
+
"Ship the layout used by the manifest-presence probe under SIMULATE_MANIFEST_MISSING=true to name the missing file's basename in the detail (AC-36108-1)."
|
|
14
|
+
],
|
|
15
|
+
"internalStructure": "One JSON Schema file (contributions/schemas/rate-limit-rule.schema.json). One shipped example manifest directory in the cf-edge fixture with two files (cloudflare/rate-limits/example.json, cloudflare/rate-limits/api-writes.json). Two induced-failure switches in the fixture: SIMULATE_MANIFEST_MISSING=true moves one manifest file to a scratch location so manifest-presence fails; SIMULATE_SCHEMA_INVALID=true writes a manifest file with a missing threshold so manifest-schema-validate fails. Both switches restore before commit; the anatomy test verifies the negative path.",
|
|
16
|
+
"interfaces": [
|
|
17
|
+
{
|
|
18
|
+
"name": "rate-limit-rule.schema.json",
|
|
19
|
+
"kind": "schema",
|
|
20
|
+
"summary": "JSON Schema (draft-07) for one rate-limit rule manifest file."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "cloudflare/rate-limits/",
|
|
24
|
+
"kind": "layout",
|
|
25
|
+
"summary": "Elicited manifest directory, one JSON file per rule."
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"dependencies": [],
|
|
29
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
30
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
31
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tacId": "TAC-3702-edge-cloudflare-rate-limiting-management-surface-doc",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"name": "Operator-facing management surface documentation (wrangler and Cloudflare dashboard flows)",
|
|
8
|
+
"purpose": "The shipped guide at blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md documents both a wrangler command flow and a Cloudflare dashboard flow for applying one rule from a manifest file to the elicited zone. The guide is the sole management-surface artefact the blueprint ships; no committed script writes rules to the live zone. The elicited rate-limit-management-surface value records the flow the operator chose. The guide also names the composition with security-auth-magic-link per ADR-3702 and shows a copy-paste example. This TAC anchors AC-36102-1 and AC-36105-1.",
|
|
9
|
+
"responsibilities": [
|
|
10
|
+
"Ship a guide with a wrangler command flow and a Cloudflare dashboard flow, both walking through the apply of one rule from a manifest file (AC-36102-1).",
|
|
11
|
+
"Reference https://developers.cloudflare.com/waf/rate-limiting-rules/ as the vendor doc for the rule shape (AC-36102-1).",
|
|
12
|
+
"Ship a Composition with security-auth-magic-link section naming ADR-3702 explicitly, stating the zone rule characteristic (IP-per-URL) and the application rule characteristic (per-email per-minute) with a copy-paste example (AC-36105-1)."
|
|
13
|
+
],
|
|
14
|
+
"internalStructure": "One guide file (guide/edge-cloudflare-rate-limiting.md) with three named sections: Manifest, Management surface (wrangler and dashboard subsections) and Composition with security-auth-magic-link. Every section links back to the corresponding REQ and ADR.",
|
|
15
|
+
"interfaces": [
|
|
16
|
+
{
|
|
17
|
+
"name": "guide/edge-cloudflare-rate-limiting.md",
|
|
18
|
+
"kind": "documentation",
|
|
19
|
+
"summary": "Operator-facing management surface guide with both wrangler and dashboard flows plus the composition example."
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"dependencies": [],
|
|
23
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
24
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tacId": "TAC-3703-edge-cloudflare-rate-limiting-drift-audit-runner",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"tadId": "TAD-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"name": "Drift-audit runner: read live zone rules via the Cloudflare API and diff against the local manifest",
|
|
8
|
+
"purpose": "The single project-side module realising the scheduled drift-audit runner. It fetches the live rate-limiting rules on the elicited zone via the Cloudflare API (GET /client/v4/zones/{zone_id}/rulesets), diffs the returned rule set against the local manifest file-by-file, and constructs one drift-audit record per mismatched rule. Records write through the applied logger's audit sink with the metadata-only shape {ruleId, clientIpHash, outcome, timestamp, diff}; no record carries a full IP, a request body or a user agent (event-secrecy discipline per REQ-004 and AC-36107-1). The runner is factory-driven for testability: probes and the anatomy test inject a fake fetch that returns a synthetic live-zone response. This TAC anchors AC-36104-1 and AC-36107-1.",
|
|
9
|
+
"responsibilities": [
|
|
10
|
+
"Export createDriftAuditRunner({env, eventSink, fetch, clock, cadence}) returning {runOnce, schedule, stop} matching the drift-audit shape (AC-36104-1).",
|
|
11
|
+
"Diff every manifest rule against every live rule and construct one drift record per mismatched rule, with the metadata-only shape {ruleId, outcome, timestamp, diff} (AC-36104-1, AC-36107-1).",
|
|
12
|
+
"Emit exactly one audit event per drift record on the injected sink, Object.frozen at the boundary (AC-36107-1).",
|
|
13
|
+
"Refuse to run when the elicited cadence is off (AC-36104-1)."
|
|
14
|
+
],
|
|
15
|
+
"internalStructure": "One shipped runner module the blueprint contributes at guide-installation time (the runner code is copy-paste from the guide into the applying project; the shipped fixture at packages/rcf-lite/test/fixtures/cf-edge/src/drift-audit-runner.mjs realises the shape the guide names). The runner constructs one drift record per mismatched rule; the record is Object.frozen at the boundary so a downstream handler cannot enrich it with a leaked field.",
|
|
16
|
+
"interfaces": [
|
|
17
|
+
{
|
|
18
|
+
"name": "createDriftAuditRunner",
|
|
19
|
+
"kind": "factory",
|
|
20
|
+
"summary": "Drift-audit runner factory over env, eventSink, fetch, clock and the elicited cadence."
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"dependencies": [],
|
|
24
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
25
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
26
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36101",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Rules manifest present in the applying project as one JSON file per rule under the elicited manifest directory",
|
|
8
|
+
"asA": "shelf consumer applying the edge-cloudflare-rate-limiting v1.0.0 blueprint on a Workers project using the cf-edge fixture",
|
|
9
|
+
"iWant": "the elicited rate-limit-rules-dir to contain at least one committed JSON file per rate-limit rule the applying project intends to run, each file matching the elicited rule shape and none referencing a secret in plaintext",
|
|
10
|
+
"soThat": "the applying project's rate-limit rules are source-controlled and reviewable, and the operator has a stable source of truth to apply to the live zone through the wrangler or dashboard flow",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36101-1",
|
|
14
|
+
"description": "The rate-limit manifest directory (default cloudflare/rate-limits/) exists in the applied project and holds at least one JSON file per rule; every file parses as JSON and carries the seven documented Cloudflare WAF rate-limiting rules fields (id, expression, threshold, period, characteristics, action, duration); no file body contains a plaintext Cloudflare API token or the elicited zone id (the zone id is elicited and stored via the applied secretsManagement companion).",
|
|
15
|
+
"given": "the cf-edge fixture with the two committed manifest files under cloudflare/rate-limits/",
|
|
16
|
+
"when": "the manifest-presence probe scans the fixture directory",
|
|
17
|
+
"then": "every manifest file parses, every file carries the seven required fields, and no file references a secret in plaintext",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3701-edge-cloudflare-rate-limiting-manifest-schema"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36102",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-002",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Guide documents the operator-facing management surface with both wrangler and dashboard flows",
|
|
8
|
+
"asA": "operator on the applying project preparing to push rate-limit rules from the local manifest to the live Cloudflare zone",
|
|
9
|
+
"iWant": "a documented step-by-step flow that walks me through both a wrangler command sequence and a Cloudflare dashboard sequence for applying each manifest rule",
|
|
10
|
+
"soThat": "I can pick the flow that suits the project's operating discipline and reproduce the apply from the manifest at any cadence without inventing a bespoke tool",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36102-1",
|
|
14
|
+
"description": "The blueprint guide at blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md documents an operator-facing management surface with both a wrangler command flow and a Cloudflare dashboard flow; each flow names the exact steps to apply one rule from a manifest file to the elicited zone; the guide references https://developers.cloudflare.com/waf/rate-limiting-rules/ as the vendor doc for the rule shape.",
|
|
15
|
+
"given": "the shipped guide file in the blueprint tree",
|
|
16
|
+
"when": "the anatomy test scans the guide for the wrangler headings, the dashboard headings and the vendor URL",
|
|
17
|
+
"then": "both flow headings are present and the vendor URL appears",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "documentation"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3702-edge-cloudflare-rate-limiting-management-surface-doc"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36103",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-003",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Over-threshold burst returns 429 with Retry-After and Cf-Ray on the (N+1)th request within the elicited duration",
|
|
8
|
+
"asA": "operator running the real-account burst probe against a scheduled HQ-owned URL configured with the manifest rule",
|
|
9
|
+
"iWant": "the probe to fire an undici burst above the rule threshold and observe the (N+1)th and subsequent requests return HTTP 429 with a Retry-After header consistent with the elicited duration and a Cf-Ray header for the CF edge that served the refusal",
|
|
10
|
+
"soThat": "the shipped over-threshold behaviour is verified against a real Cloudflare account and, in CI without CI_HAS_CLOUDFLARE_ACCOUNT, the probe records accountBound: skipped per ruling 6",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36103-1",
|
|
14
|
+
"description": "When CI_HAS_CLOUDFLARE_ACCOUNT is true and CF_RATE_LIMIT_URL is set to a scheduled HQ-owned URL configured with the manifest rule, the real-account-burst-and-429 probe fires the elicited threshold plus one requests within the rule period and observes the (N+1)th and subsequent requests within the elicited duration return HTTP 429 with a Retry-After header value consistent with the elicited duration and a Cf-Ray header naming the CF edge; when either env var is absent the probe records accountBoundSkipped: true and the aggregate verdict is pass per spec section 3.5 and ruling 6.",
|
|
15
|
+
"given": "a scheduled HQ-owned URL configured with the manifest rule (or the accountBound: skipped fallback in CI)",
|
|
16
|
+
"when": "the real-account-burst-and-429 probe fires the burst (or records the skip)",
|
|
17
|
+
"then": "the probe returns 429 with the two required headers on the over-threshold requests, or records accountBoundSkipped: true and aggregates to pass",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3701-edge-cloudflare-rate-limiting-manifest-schema"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36104",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-004",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Drift-audit runner reads live zone rules via the Cloudflare API and diffs against the local manifest, constructing metadata-only records",
|
|
8
|
+
"asA": "operator on the applying project running the scheduled drift-audit runner behind the elicited cadence (daily or hourly)",
|
|
9
|
+
"iWant": "the runner to fetch the live rule set from the Cloudflare API for the elicited zone and diff every rule against the local manifest, constructing one drift-audit record per mismatched rule with the metadata-only shape and writing a report to .rcf/reports/blueprints/edge-cloudflare-rate-limiting/",
|
|
10
|
+
"soThat": "manifest drift (a rule changed on the dashboard without a manifest update, or vice versa) is surfaced through the logging companion at the elicited cadence rather than lingering unnoticed",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36104-1",
|
|
14
|
+
"description": "Given a synthetic drift scenario (a fixture manifest file that names threshold 10 and a fake live-zone response that reports threshold 20 on the same rule id), the drift-audit runner's diff step constructs one drift record per mismatched rule; the record carries {ruleId, outcome: driftDetected, timestamp, diff: [field: threshold, manifestValue: 10, liveValue: 20]} and NO full IP, NO request body, NO user agent; when the cadence elicit is off the runner is not wired and no report is written.",
|
|
15
|
+
"given": "the cf-edge fixture with the committed manifest and a synthetic Cloudflare API response with one mismatched rule",
|
|
16
|
+
"when": "the drift-audit runner's diff step runs against the pair",
|
|
17
|
+
"then": "one drift record is constructed per mismatched rule with the metadata-only shape and the report writes to .rcf/reports/blueprints/edge-cloudflare-rate-limiting/",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3703-edge-cloudflare-rate-limiting-drift-audit-runner"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36105",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-005",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Composition with security-auth-magic-link: zone rate rule layers over the per-email application rule",
|
|
8
|
+
"asA": "operator applying both edge-cloudflare-rate-limiting and security-auth-magic-link on the same project",
|
|
9
|
+
"iWant": "the guide to name the ADR-3702 layering explicitly, showing that the zone rule refuses IP-per-URL bursts at the CF edge before they reach the origin and the security-auth-magic-link per-email application rule continues to run on requests that pass the edge gate",
|
|
10
|
+
"soThat": "I understand the composition at apply time rather than discovering that both blueprints operate on separate characteristic sets by trial and error",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36105-1",
|
|
14
|
+
"description": "The guide contains a section titled Composition with security-auth-magic-link that names ADR-3702 explicitly, states the zone rule characteristic (IP-per-URL) and the application rule characteristic (per-email per-minute) verbatim, and shows a copy-paste example of both blueprints applied on the same project.",
|
|
15
|
+
"given": "the shipped guide at blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md",
|
|
16
|
+
"when": "the anatomy test scans the guide for the composition section and ADR-3702 reference",
|
|
17
|
+
"then": "the section heading, ADR-3702 reference, both characteristic strings and the copy-paste example are present",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "documentation"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3702-edge-cloudflare-rate-limiting-management-surface-doc"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36106",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Manifest schema validates every rule file against the shipped JSON Schema and refuses invalid shapes",
|
|
8
|
+
"asA": "operator on the applying project committing new rate-limit rule files under the elicited manifest directory",
|
|
9
|
+
"iWant": "the shipped JSON Schema to validate every rule file's shape (the seven required fields with the correct types) and the manifest-schema-validate probe to surface any file that violates the shape",
|
|
10
|
+
"soThat": "invalid manifest changes are caught in the fixture probe rather than at operator apply time against a live zone",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36106-1",
|
|
14
|
+
"description": "Given the shipped rate-limit-rule JSON Schema (blueprints/edge-cloudflare-rate-limiting/contributions/schemas/rate-limit-rule.schema.json, draft-07), the manifest-schema-validate probe reads every manifest file in the fixture manifest directory and validates each against the schema; every valid file passes; a manifest file with a missing threshold field (simulated via SIMULATE_SCHEMA_INVALID=true) fails validation and the probe returns aggregateVerdict: fail with the offending field named in the detail.",
|
|
15
|
+
"given": "the cf-edge fixture with the two committed manifest files and the shipped JSON Schema",
|
|
16
|
+
"when": "the manifest-schema-validate probe validates every manifest file",
|
|
17
|
+
"then": "every valid file passes; the SIMULATE_SCHEMA_INVALID=true switch surfaces the missing threshold field and the aggregate verdict is fail",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3701-edge-cloudflare-rate-limiting-manifest-schema"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36107",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-004",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Drift-audit records carry metadata-only fields (ruleId, clientIpHash, outcome, timestamp) with no full IP, no body, no user agent",
|
|
8
|
+
"asA": "operator on the applying project reading drift-audit reports and rate-limit event records through the applied logging companion",
|
|
9
|
+
"iWant": "every drift-audit record and every rate-limit event record to carry only metadata-safe fields (ruleId, clientIpHash, outcome, timestamp, plus the drift diff fields where applicable), never a full client IP, never a request body, never a user agent string",
|
|
10
|
+
"soThat": "the audit trail is safe to store, forward and read without additional PII scrubbing at the audit sink",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36107-1",
|
|
14
|
+
"description": "The event-secrecy probe drives a synthetic drift-audit payload constructed from a fixture rule and a fake live-zone response; every record on the sink carries only {ruleId, clientIpHash, outcome, timestamp} plus (for drift records) a diff array with the schema-safe fields; the probe asserts NO full IP (regex 4-octet dotted quad or v6 group), NO request body key, NO user-agent key; the SIMULATE_EVENT_LEAK_IP=true switch injects a full IP into the drift record and the probe returns aggregateVerdict: fail with the leaked key named in the detail.",
|
|
15
|
+
"given": "the shipped drift-audit runner and a synthetic input pair",
|
|
16
|
+
"when": "the event-secrecy probe drives the runner and inspects the resulting records",
|
|
17
|
+
"then": "every record carries only the metadata-safe fields; SIMULATE_EVENT_LEAK_IP=true surfaces a leaked key and the aggregate verdict is fail",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3703-edge-cloudflare-rate-limiting-drift-audit-runner"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "edge-cloudflare-rate-limiting-US-36108",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Manifest-presence probe refuses a missing manifest file and names the missing file in the detail",
|
|
8
|
+
"asA": "operator on the applying project accidentally deleting or moving a manifest file under the elicited manifest directory",
|
|
9
|
+
"iWant": "the manifest-presence probe to surface the missing file at fixture probe time rather than at operator apply time against a live zone",
|
|
10
|
+
"soThat": "a manifest under-population defect is caught in the CI probe rather than lingering until an operator notices a missing rule at the dashboard",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-36108-1",
|
|
14
|
+
"description": "Given the cf-edge fixture with the SIMULATE_MANIFEST_MISSING=true switch, one committed manifest file is treated as absent by the probe; the manifest-presence probe returns aggregateVerdict: fail with the missing file's basename named in the detail; without the switch the probe passes and both manifest files are inspected.",
|
|
15
|
+
"given": "the cf-edge fixture with two committed manifest files and the SIMULATE_MANIFEST_MISSING=true switch",
|
|
16
|
+
"when": "the manifest-presence probe scans the fixture manifest directory",
|
|
17
|
+
"then": "the probe returns aggregateVerdict: fail and the missing file basename is present in the detail",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"tacIds": [
|
|
23
|
+
"TAC-3701-edge-cloudflare-rate-limiting-manifest-schema"
|
|
24
|
+
],
|
|
25
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
27
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# edge-cloudflare-rate-limiting blueprint coordination vocabulary
|
|
2
|
+
|
|
3
|
+
This file is the edge-cloudflare-rate-limiting half of the cross-blueprint contract. The Phase 1 conflict detector matches scope:global ADR topics by EXACT string equality, and AC ids are unnamespaced by the 0.4.4 grammar. Any blueprint intended to compose with this one must reuse these exact strings and respect these bands.
|
|
4
|
+
|
|
5
|
+
## Global ADR topics this blueprint contributes (exact strings)
|
|
6
|
+
|
|
7
|
+
| Topic string | edge-cloudflare-rate-limiting contribution | Origin | Composition note |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| `edgeThrottleContract` | ADR-3701-edge-cloudflare-rate-limiting-throttle-contract | Minted by this blueprint. Names the wire-shape contract for the project-wide edge throttle; the shipped answer is Cloudflare WAF rate-limiting rules per `https://developers.cloudflare.com/waf/rate-limiting-rules/`. | The one project-wide decision on the edge throttle at the shipped-shape boundary. A future non-Cloudflare sibling (Fastly rate-limits, Vercel Edge Config throttles) would contribute the same topic string with a different answer, forcing a DELIBERATE conflict the operator resolves with a project-level ADR. |
|
|
10
|
+
|
|
11
|
+
The edge-cloudflare-rate-limiting blueprint claims one global topic (minted here, shipped as the Cloudflare WAF rate-limiting rules manifest and drift-audit). ADR-3702 layering, ADR-3703 manifest shape and ADR-3704 drift-audit cadence do not contribute global topics; a composing blueprint that holds an opinion on either authors its own project-level ADR.
|
|
12
|
+
|
|
13
|
+
Rules for new topics: lower camel case, one concept per topic, no version suffixes. A topic names the decision area, not the chosen answer.
|
|
14
|
+
|
|
15
|
+
## Id number bands (registry bootstrap)
|
|
16
|
+
|
|
17
|
+
This table is maintained shelf-wide across every blueprint's `docs/topics.md`. Rows are recorded at ship, never predicted.
|
|
18
|
+
|
|
19
|
+
| Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| application-spa | 1101-1899 | 2xx | shipped v1.3.0 | `clientRouting`, `theming`, `clientState`, `errorEnvelope`, `authModel` |
|
|
22
|
+
| application-api-rest | 2101-2899 | 3xx | shipped v1.0.0 | `errorEnvelope`, `authModel`, `apiVersioning`, `logging` |
|
|
23
|
+
| security-auth-magic-link | 3101-3899 | 5xx | shipped v1.2.0 | `authModel` |
|
|
24
|
+
| email-smtp-resend | 4101-4899 | 4xx | shipped v1.0.0 | none |
|
|
25
|
+
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
26
|
+
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
27
|
+
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
28
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
29
|
+
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.1 | `secretsSource` |
|
|
30
|
+
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
31
|
+
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
32
|
+
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
33
|
+
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.2.0 | `deploymentTarget` |
|
|
34
|
+
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
35
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
36
|
+
| observability-logging | 15101-15899 | 16xx | shipped v1.0.0 | `logging` |
|
|
37
|
+
| application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
|
|
38
|
+
| application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
|
|
39
|
+
| application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
|
|
40
|
+
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
41
|
+
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
42
|
+
| application-admin-console | 21101-21899 | 22xx | shipped v1.1.0 | `adminConsoleSignInSurface` |
|
|
43
|
+
| application-empty-error-states | 22101-22899 | 23xx | shipped v1.0.0 | none |
|
|
44
|
+
| application-file-upload | 23101-23899 | 24xx | shipped v1.0.0 | none |
|
|
45
|
+
| application-forms-wizard | 24101-24899 | 25xx | shipped v1.0.0 | none |
|
|
46
|
+
| application-account-settings | 25101-25899 | 26xx | shipped v1.0.0 | none |
|
|
47
|
+
| application-onboarding-tour | 26101-26899 | 27xx | shipped v1.0.0 | none |
|
|
48
|
+
| persistence-data-postgres | 27101-27899 | 28xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
49
|
+
| object-storage-s3 | 28101-28899 | 29xx | shipped v1.0.0 | `objectStorageContract` |
|
|
50
|
+
| messaging-queue-cloudflare | 29101-29899 | 30xx | shipped v1.0.0 | `deliverySemantics` |
|
|
51
|
+
| jobs-background | 30101-30899 | 31xx | shipped v1.0.0 | `backgroundJobModel` |
|
|
52
|
+
| platform-cloudflare-kv | 31101-31899 | 32xx | shipped v1.0.0 | `keyValueStoreContract` |
|
|
53
|
+
| platform-cloudflare-cron-triggers | 32101-32899 | 33xx | shipped v1.0.0 | `scheduledTriggerContract` |
|
|
54
|
+
| platform-cloudflare-durable-objects | 33101-33899 | 34xx | shipped v1.0.0 | `strongConsistencyCellContract`, `websocketHubContract` |
|
|
55
|
+
| edge-cloudflare-access | 34101-34899 | 35xx | shipped v1.0.0 | `edgeAuthenticationGate` |
|
|
56
|
+
| edge-cloudflare-turnstile | 35101-35899 | 36xx | shipped v1.0.0 | `humanVerificationGate` |
|
|
57
|
+
| edge-cloudflare-rate-limiting | 36101-36899 | 37xx | shipped v1.0.0 | `edgeThrottleContract` |
|
|
58
|
+
|
|
59
|
+
US 36101-36108 sit at the LOW end of the 36101-36899 band on purpose (watchpost run-4 lesson). ADR/TAC suffixes for this blueprint use the 3701-3799 block, continuing the shelf pattern.
|
|
60
|
+
|
|
61
|
+
## Shared expectations for future composing blueprints
|
|
62
|
+
|
|
63
|
+
- Reuse `edgeThrottleContract` exactly as spelled here when your blueprint holds an opinion on the edge throttle contract; contribute your own scope:global ADR on that string and let composition surface the pairing.
|
|
64
|
+
- Consumer blueprints reading the `edgeRateLimit` capability declared on `blueprint.json` per section 6a of `blueprint-authoring.md` obtain the shipped rate-limit surface at apply time via the capability-declaration mechanism.
|
|
65
|
+
|
|
66
|
+
## Deliberate-conflict statement
|
|
67
|
+
|
|
68
|
+
This blueprint's ADR-3701 on `edgeThrottleContract` is the first shipped answer to a topic that will conflict, by design, with future non-Cloudflare siblings. Applying `edge-cloudflare-rate-limiting` alongside such a sibling would raise a `globalAdrTopic` conflict the operator resolves via one of the four documented resolutions (adopt one, keep the existing one, author a project-level supersede ADR, or `--resolve <topic>=project:<ADR-id>` on the add).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# edge-cloudflare-rate-limiting guide
|
|
2
|
+
|
|
3
|
+
Round 6 T-6 of the Cloudflare-first blueprint line. Ships zone-level rate limiting as an edge gate in front of Worker handlers. The rule set is a local manifest the applying project commits, and an operator applies it to the live Cloudflare zone through either a wrangler command flow or the Cloudflare dashboard flow, both walked below.
|
|
4
|
+
|
|
5
|
+
## Manifest
|
|
6
|
+
|
|
7
|
+
The applying project holds its rate-limit rule set as one JSON file per rule under the elicited `rate-limit-rules-dir` (default `cloudflare/rate-limits/`) per ADR-3703. Every file matches the shipped JSON Schema (`contributions/schemas/rate-limit-rule.schema.json`, draft-07) and carries the seven Cloudflare WAF rate-limiting rules documented fields per `https://developers.cloudflare.com/waf/rate-limiting-rules/`.
|
|
8
|
+
|
|
9
|
+
Example (`cloudflare/rate-limits/public-api-per-ip.json`):
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{
|
|
13
|
+
"id": "public-api-per-ip",
|
|
14
|
+
"expression": "(http.request.uri.path matches \"^/api/\")",
|
|
15
|
+
"threshold": 60,
|
|
16
|
+
"period": 60,
|
|
17
|
+
"characteristics": ["ip.src", "cf.colo.id"],
|
|
18
|
+
"action": "block",
|
|
19
|
+
"duration": 60,
|
|
20
|
+
"description": "Per-IP-per-colo throttle on /api/*; the (N+1)th request in 60s is blocked for 60s."
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The zone id is elicited (`rate-limit-zone-id`) and stored through the applied `secretsManagement` companion; a manifest file never inlines a zone id or an API token.
|
|
25
|
+
|
|
26
|
+
## Management surface
|
|
27
|
+
|
|
28
|
+
The blueprint ships no committed script that writes rules to the live zone. The operator applies each rule through one of two documented flows, or both. The elicited `rate-limit-management-surface` value records the choice.
|
|
29
|
+
|
|
30
|
+
### wrangler flow
|
|
31
|
+
|
|
32
|
+
The wrangler flow uses the Cloudflare API through a hand-run command sequence. The steps for one rule are:
|
|
33
|
+
|
|
34
|
+
1. Set `CLOUDFLARE_API_TOKEN` (and `CLOUDFLARE_ACCOUNT_ID` for the account scope) in the operator's environment. Store both through the applied `secretsManagement` companion; never commit them to the git tree.
|
|
35
|
+
2. Load the elicited zone id: `export CF_ZONE_ID=$(cat rcf/blueprints/edge-cloudflare-rate-limiting.applied.json | jq -r .elicits.rateLimitZoneId)` or read it from the applied vault seam.
|
|
36
|
+
3. Fetch the existing rate-limiting ruleset id for the zone via the wrangler-installed API-fetch helper: `wrangler api curl "/zones/${CF_ZONE_ID}/rulesets?phase=http_ratelimit" --method GET` and note the `id` on the returned ruleset (create one if none exists per the vendor doc).
|
|
37
|
+
4. For each rule file, `POST` the rule shape to the ruleset's `/rules` endpoint. The rule body is built from the manifest file by mapping each field one-to-one: `expression`, `action`, and a `ratelimit` object carrying `characteristics`, `period`, `requests_per_period` (from `threshold`), and `mitigation_timeout` (from `duration`).
|
|
38
|
+
5. Verify by listing the ruleset again and confirming every manifest rule appears with the expected fields.
|
|
39
|
+
|
|
40
|
+
The vendor doc `https://developers.cloudflare.com/waf/rate-limiting-rules/` names the endpoint shape verbatim; the wrangler flow is a hand-run reproduction of that shape.
|
|
41
|
+
|
|
42
|
+
### Cloudflare dashboard flow
|
|
43
|
+
|
|
44
|
+
The dashboard flow applies each rule through the Cloudflare zone dashboard. The steps for one rule are:
|
|
45
|
+
|
|
46
|
+
1. Open the target zone in the Cloudflare dashboard.
|
|
47
|
+
2. Navigate to Security -> WAF -> Rate limiting rules.
|
|
48
|
+
3. Click Create rule; give the rule the manifest file's `id` as the operator-facing name.
|
|
49
|
+
4. In When incoming requests match, set the Custom filter expression to the manifest `expression` (Edit expression toggle to paste raw).
|
|
50
|
+
5. In Then take action, set the action to the manifest `action` (Block, Managed challenge, JS challenge or Log). Set the Duration to the manifest `duration` in seconds.
|
|
51
|
+
6. In With the following properties, set the counting period to the manifest `period` seconds, the requests per period to the manifest `threshold`, and the characteristics to the manifest `characteristics` array (each string mapped to the dashboard's Same request property selectors).
|
|
52
|
+
7. Save the rule. Repeat for every file in the manifest directory.
|
|
53
|
+
|
|
54
|
+
Both flows produce the same shape on the live zone; the operator picks the flow that fits the project's operating discipline. The elicited `rate-limit-management-surface` records which flow the operator committed to at apply time.
|
|
55
|
+
|
|
56
|
+
## Composition with security-auth-magic-link
|
|
57
|
+
|
|
58
|
+
Per ADR-3702, when both `edge-cloudflare-rate-limiting` and `security-auth-magic-link` apply on the same project, the zone-level rate rule layers OVER the per-email application rule. The two rules operate on different characteristic sets and are additive:
|
|
59
|
+
|
|
60
|
+
| Rule | Characteristic set | Where it runs |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| Zone rule (this blueprint) | IP-per-URL (e.g. `ip.src` + `http.request.uri.path`) | Cloudflare edge, before any origin Worker code |
|
|
63
|
+
| Application rule (magic-link) | per-email per-minute | Origin Worker mint-surface handler |
|
|
64
|
+
|
|
65
|
+
Copy-paste example (applying both blueprints in the same project):
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
rcf define blueprint add ./blueprints/edge-cloudflare-rate-limiting \
|
|
69
|
+
--answer rate-limit-rules-dir=cloudflare/rate-limits \
|
|
70
|
+
--answer rate-limit-zone-id=<vault-ref> \
|
|
71
|
+
--answer rate-limit-management-surface=both \
|
|
72
|
+
--answer rate-limit-drift-audit-cadence=daily
|
|
73
|
+
|
|
74
|
+
rcf define blueprint add ./blueprints/security-auth-magic-link \
|
|
75
|
+
--answer magic-link-mint-rate-limit=5perMinute
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The applied recorder records both blueprints so the operator sees the two-rule shape at apply time.
|
|
79
|
+
|
|
80
|
+
## Drift audit
|
|
81
|
+
|
|
82
|
+
The blueprint ships a scheduled drift-audit runner realisation in the `cf-edge` fixture at `packages/rcf-lite/test/fixtures/cf-edge/src/drift-audit-runner.mjs`. The runner exports `createDriftAuditRunner({env, eventSink, fetch, clock, cadence, manifestLoader})` per TAC-3703 and fetches the live rules on the elicited zone via `https://api.cloudflare.com/client/v4/zones/{zone_id}/rulesets`, diffs field-by-field against the local manifest, and constructs one drift-audit record per mismatched rule with the metadata-only shape `{ruleId, clientIpHash, outcome, timestamp, diff}`. No record carries a full client IP, a request body or a user agent (event-secrecy discipline per REQ-005 and AC-36107-1).
|
|
83
|
+
|
|
84
|
+
The elicited `rate-limit-drift-audit-cadence` per ADR-3704 picks `off` (runner not wired), `daily` (24-hour cadence, `recommendedDefault`), or `hourly`.
|
|
85
|
+
|
|
86
|
+
## Runtime observable and CI
|
|
87
|
+
|
|
88
|
+
Per spec section 3.1 and ruling 6, the runtime observable for `AC-rateLimiting-overThresholdBlocks` (US-36103/AC-36103-1) is the real-account burst probe. In CI without `CI_HAS_CLOUDFLARE_ACCOUNT` and `CF_RATE_LIMIT_URL`, the probe records `accountBoundSkipped: true` and aggregates to `pass`; this IS the accepted CI verdict. The three local probes (manifest presence, manifest schema validate, event secrecy) always run and always gate the ship.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `edge-cloudflare-turnstile` are recorded here. The shape follows Keep a Changelog and Semantic Versioning per the blueprint authoring standard.
|
|
4
|
+
|
|
5
|
+
## 1.0.0 (2026-09-07)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- v1.0.0 mint of the `edge-cloudflare-turnstile` blueprint, category `edge`, capabilities `["humanCheck"]`. Ships a client widget mount, a server-side siteverify verifier that POSTs to `https://challenges.cloudflare.com/turnstile/v0/siteverify` with the elicited secret, a refuse-if-token-missing guard on every elicited surface, and a composition hook into `security-auth-magic-link` mint surface.
|
|
10
|
+
- 5 REQs (`edge-cloudflare-turnstile-REQ-001..005`), 8 USs (`edge-cloudflare-turnstile-US-35101..35108`), 3 TACs (`TAC-3601` widget mount, `TAC-3602` server verifier plus token-required guard, `TAC-3603` magic-link hook), 3 ADRs (`ADR-3601` scope-global on new topic `humanVerificationGate` with `standardsTraceClause: Cloudflare Turnstile siteverify endpoint documented shape`; `ADR-3602` widget mode enum elicit with `recommendedDefault: managed`; `ADR-3603` refuse shape 400 with error-code body and no sitekey leak).
|
|
11
|
+
- 4 Node-only probes under `contributions/probes/`: `secret-shape-scan` (source-tree AST scan asserts `TURNSTILE_SECRET` is only read through the env facade and refuses non-test secret literals), `siteverify-fixture` (drives the LIVE `challenges.cloudflare.com/turnstile/v0/siteverify` endpoint with the pinned always-pass and always-fail Cloudflare test secrets and asserts `success:true` and `success:false` respectively), `guard-shape-scan` (source scan plus live missing-token POST against every guarded surface), `event-secrecy` (asserts every event record carries `{sitekeyHash, outcome, timestamp}` keys only; no token, no secret leak).
|
|
12
|
+
- 1 Playwright probe pack (`probe-packs/edge-cloudflare-turnstile.pack.mjs`) with 4 surface-observable checks per spec section 3.2: `AC-turnstile-widgetRendered` (widget mounts, iframe/script from the Cloudflare Turnstile origin only, `cf-turnstile-response` token populated, no third-party script), `AC-turnstile-serverVerified-pass` (`/api/submit` 200 on always-pass secret), `AC-turnstile-serverVerified-fail` (`/api/submit` 400 on always-fail secret with `errorCodes` and no sitekey leak), `AC-turnstile-magicLinkGuard` (mint refuses missing-token and always-fail-secret with 400 and no mint side-effect).
|
|
13
|
+
- 4 elicited parameters on `blueprint.json`: `turnstile-sitekey`, `turnstile-secret` (routed through `security-secrets-management` when applied), `turnstile-widget-mode` (enum default `managed`), `turnstile-guarded-surfaces`.
|
|
14
|
+
- `suggestedCompanions`: `logging` (for the metadata-only event sink retention), `errorHandling` (for the verifier failure boundary), `secretsManagement` (for the paired sitekey and secret).
|
|
15
|
+
- Ships the dedicated pack fixture at `packages/rcf-lite/test/fixtures/probe-pack-edge-cloudflare-turnstile/` per spec section 3.3. The fixture pins the Cloudflare public test keys documented at `https://developers.cloudflare.com/turnstile/troubleshooting/testing/` as environment defaults so the pack runs without real Turnstile credentials.
|
|
16
|
+
- Anatomy test at `packages/rcf-lite/test/blueprint/edge-cloudflare-turnstile-anatomy.test.js` covers TS-120..127 on the T-5 repo-chain slice.
|
|
17
|
+
|
|
18
|
+
### Known limitations
|
|
19
|
+
|
|
20
|
+
- No account-bound probe. Cloudflare Turnstile documents its endpoint and test keys as public; the live siteverify calls in the shipped probes route through Cloudflare with no operator account required. A real-account variant would gate on a specific applying-project sitekey and secret pair; the shipped test-key runs cover the wire-shape contract.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# edge-cloudflare-turnstile
|
|
2
|
+
|
|
3
|
+
Cloudflare Turnstile as a CAPTCHA-alternative on public-facing forms. Ships the client widget mount, the server-side siteverify verifier (POST to `https://challenges.cloudflare.com/turnstile/v0/siteverify` with the elicited secret), a refuse-if-token-missing guard on every elicited surface, and a composition hook into the `security-auth-magic-link` mint surface.
|
|
4
|
+
|
|
5
|
+
- Slug: `edge-cloudflare-turnstile`
|
|
6
|
+
- Category: `edge`
|
|
7
|
+
- Version: `1.0.0`
|
|
8
|
+
- Capabilities: `["humanCheck"]`
|
|
9
|
+
- Standards: Cloudflare Turnstile (`https://developers.cloudflare.com/turnstile/`), Cloudflare Turnstile testing (`https://developers.cloudflare.com/turnstile/troubleshooting/testing/`)
|
|
10
|
+
|
|
11
|
+
## What this blueprint commits
|
|
12
|
+
|
|
13
|
+
| REQ | Commits |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `edge-cloudflare-turnstile-REQ-001` | Client widget mount: the elicited sitekey renders the Turnstile widget; the mount injects no third-party script beyond the Cloudflare Turnstile JS host. |
|
|
16
|
+
| `edge-cloudflare-turnstile-REQ-002` | Server-side siteverify: POST to `https://challenges.cloudflare.com/turnstile/v0/siteverify` with the elicited secret; on `success:true` the handler proceeds; on `success:false` the handler rejects with 400. |
|
|
17
|
+
| `edge-cloudflare-turnstile-REQ-003` | Refuse-if-token-missing guard on elicited surfaces: a submit without a token rejects with 400 before hitting downstream logic. |
|
|
18
|
+
| `edge-cloudflare-turnstile-REQ-004` | Composition with `security-auth-magic-link`: when both are applied, the magic-link mint surface refuses a submit without a valid Turnstile token. |
|
|
19
|
+
| `edge-cloudflare-turnstile-REQ-005` | Widget mode is an elicited enum: `managed`, `non-interactive`, `invisible` per Cloudflare's documented modes. `recommendedDefault: managed`. |
|
|
20
|
+
|
|
21
|
+
## Contract at a glance
|
|
22
|
+
|
|
23
|
+
- **Client widget mount** (TAC-3601) injects Cloudflare Turnstile JS from `https://challenges.cloudflare.com` and no other origin; renders the widget for the elicited sitekey; populates the hidden `Cf-Turnstile-Response` token field on submit.
|
|
24
|
+
- **Server-side siteverify verifier** (TAC-3602) POSTs `{secret, response}` to `https://challenges.cloudflare.com/turnstile/v0/siteverify`. On `success:true` the handler proceeds. On `success:false` the handler rejects with 400 and the refusal body carries the documented `error-codes` value; the sitekey is never in the refusal body.
|
|
25
|
+
- **Refuse-if-token-missing guard** (TAC-3602) is the sole reader of the `Cf-Turnstile-Response` payload field; a submit without a token rejects with `400 {"errorCode":"turnstile.token-missing"}` before any downstream handler runs.
|
|
26
|
+
- **Composition with security-auth-magic-link** (TAC-3603) registers the magic-link mint route under the Turnstile guard so a mint submit reads through the same token check.
|
|
27
|
+
- **Widget mode** (ADR-3602) is an elicited enum: `managed`, `non-interactive`, `invisible`. Default: `managed`.
|
|
28
|
+
|
|
29
|
+
## Elicited parameters
|
|
30
|
+
|
|
31
|
+
| Id | Purpose |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `turnstile-sitekey` | Cloudflare Turnstile sitekey the widget renders with. Public per Cloudflare's testing docs when a test sitekey is applied. |
|
|
34
|
+
| `turnstile-secret` | Cloudflare Turnstile secret the server-side verifier POSTs with. Delegated to `security-secrets-management` when applied. |
|
|
35
|
+
| `turnstile-widget-mode` | Enum `managed` \| `non-interactive` \| `invisible`. `recommendedDefault: managed`. |
|
|
36
|
+
| `turnstile-guarded-surfaces` | List of applied route ids the token-required guard registers on. |
|
|
37
|
+
|
|
38
|
+
## Companions
|
|
39
|
+
|
|
40
|
+
- **`suggestedCompanions[logging]`**: every siteverify call and every refuse-if-token-missing rejection writes through the applied logger.
|
|
41
|
+
- **`suggestedCompanions[errorHandling]`**: siteverify network failure, malformed token, missing sitekey/secret build an internal error record.
|
|
42
|
+
- **`suggestedCompanions[secretsManagement]`**: the paired sitekey and secret are stored in the operator's applied `secretsManagement` companion.
|
|
43
|
+
|
|
44
|
+
## Composition
|
|
45
|
+
|
|
46
|
+
- Consumes `security-secrets-management` for the sitekey/secret pair when applied.
|
|
47
|
+
- Composes with `security-auth-magic-link` at the mint surface via `TAC-3603`.
|
|
48
|
+
- Provides capability `humanCheck` per section 6a of `blueprint-authoring.md`.
|
|
49
|
+
- One scope-global ADR (`ADR-3601`) on new topic `humanVerificationGate`. A future hCaptcha or reCAPTCHA sibling contributes the same topic string with a different answer and forces a deliberate operator-resolved conflict.
|
|
50
|
+
|
|
51
|
+
## Probes and pack
|
|
52
|
+
|
|
53
|
+
Four Node-only probes under `contributions/probes/`:
|
|
54
|
+
|
|
55
|
+
| Probe | Anchors | Engine |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `secret-shape-scan` | `AC-35107-1` | Source-tree AST scan over the pack fixture. |
|
|
58
|
+
| `siteverify-fixture` | `AC-35102-1` | Live POST to `https://challenges.cloudflare.com/turnstile/v0/siteverify` with pinned Cloudflare public test secrets. |
|
|
59
|
+
| `guard-shape-scan` | `AC-35104-1` | Source-tree scan plus a live missing-token POST against every guarded surface. |
|
|
60
|
+
| `event-secrecy` | `AC-35108-1` | Live pass + fail runs through the verifier; asserts every event carries `sitekeyHash`, `outcome`, `timestamp` and no token or secret substring. |
|
|
61
|
+
|
|
62
|
+
One Playwright pack at `probe-packs/edge-cloudflare-turnstile.pack.mjs` with four surface-observable checks: `AC-turnstile-widgetRendered`, `AC-turnstile-serverVerified-pass`, `AC-turnstile-serverVerified-fail`, `AC-turnstile-magicLinkGuard`. The pack ships no `appliesTo` gate; every fixture that applies the blueprint fires every check.
|
|
63
|
+
|
|
64
|
+
The dedicated pack fixture at `packages/rcf-lite/test/fixtures/probe-pack-edge-cloudflare-turnstile/` pins the Cloudflare public test keys (documented at `https://developers.cloudflare.com/turnstile/troubleshooting/testing/`) as environment defaults so the pack runs without real Turnstile credentials.
|
|
65
|
+
|
|
66
|
+
## Pinned Cloudflare public test keys
|
|
67
|
+
|
|
68
|
+
Per Cloudflare's testing page (`https://developers.cloudflare.com/turnstile/troubleshooting/testing/`):
|
|
69
|
+
|
|
70
|
+
| Sitekey | Behaviour |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `1x00000000000000000000AA` | Always passes |
|
|
73
|
+
| `2x00000000000000000000AB` | Always blocks |
|
|
74
|
+
| `3x00000000000000000000FF` | Forces an interactive challenge |
|
|
75
|
+
| `1x00000000000000000000BB` | Invisible widget, always passes |
|
|
76
|
+
| `2x00000000000000000000BB` | Invisible widget, always blocks |
|
|
77
|
+
|
|
78
|
+
| Secret | Behaviour |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `1x0000000000000000000000000000000AA` | Always passes on siteverify |
|
|
81
|
+
| `2x0000000000000000000000000000000AA` | Always fails on siteverify |
|
|
82
|
+
| `3x0000000000000000000000000000000AA` | Token already spent |
|
|
83
|
+
|
|
84
|
+
These keys are public per Cloudflare's documentation; they are safe to pin as fixture defaults and are not operational secrets.
|
|
85
|
+
|
|
86
|
+
## Risks
|
|
87
|
+
|
|
88
|
+
1. Client-side widget mounts a third-party script. The `AC-turnstile-widgetRendered` pack check pins the mount to `https://challenges.cloudflare.com` only and fails if any other origin is contacted (see the `?break=other-origin` negative proof in the fixture `proof/` directory).
|
|
89
|
+
2. Test sitekeys are the only always-green option for CI. The guide names the pass, block and forced-interactive modes per Cloudflare's testing page so an operator can pick a mode for staging.
|
|
90
|
+
|
|
91
|
+
## Standards trace
|
|
92
|
+
|
|
93
|
+
- Cloudflare Turnstile: `https://developers.cloudflare.com/turnstile/`
|
|
94
|
+
- Cloudflare Turnstile testing: `https://developers.cloudflare.com/turnstile/troubleshooting/testing/`
|
|
95
|
+
- Cloudflare Turnstile siteverify endpoint: `https://challenges.cloudflare.com/turnstile/v0/siteverify`
|