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,95 @@
|
|
|
1
|
+
// Probe: rate-limit manifest presence.
|
|
2
|
+
//
|
|
3
|
+
// anchorAcId: AC-36101-1 (also surfaces AC-36108-1's missing-file
|
|
4
|
+
// negative through SIMULATE_MANIFEST_MISSING). accountBound: false.
|
|
5
|
+
//
|
|
6
|
+
// Reads the cf-edge fixture manifest directory (cloudflare/rate-limits/),
|
|
7
|
+
// asserts:
|
|
8
|
+
// - at least one JSON file is present under the directory.
|
|
9
|
+
// - every file parses as JSON.
|
|
10
|
+
// - every file carries the seven required Cloudflare WAF rate-limiting
|
|
11
|
+
// rules fields (id, expression, threshold, period, characteristics,
|
|
12
|
+
// action, duration).
|
|
13
|
+
// - no file body carries a plaintext bearer token, private key or
|
|
14
|
+
// inline CF_API_TOKEN reference.
|
|
15
|
+
//
|
|
16
|
+
// Under SIMULATE_MANIFEST_MISSING=true the probe treats the first
|
|
17
|
+
// manifest file as absent and returns aggregateVerdict: fail with
|
|
18
|
+
// the missing basename named in the detail (AC-36108-1).
|
|
19
|
+
|
|
20
|
+
import { readManifestFiles, scanForPlaintextSecrets, REQUIRED_FIELDS } from './probe-utils.mjs';
|
|
21
|
+
|
|
22
|
+
export const anchorAcId = 'AC-36101-1';
|
|
23
|
+
export const accountBound = false;
|
|
24
|
+
|
|
25
|
+
export default async function runProbe() {
|
|
26
|
+
const { present, entries, files = [], hiddenBySimulate = [] } = await readManifestFiles();
|
|
27
|
+
const results = [];
|
|
28
|
+
if (!present) {
|
|
29
|
+
results.push({
|
|
30
|
+
anchorAcId: 'AC-36101-1',
|
|
31
|
+
verdict: 'fail',
|
|
32
|
+
detail: 'manifest directory holds zero JSON files; cf-edge fixture must ship at least one rule file under cloudflare/rate-limits/.',
|
|
33
|
+
});
|
|
34
|
+
return { results };
|
|
35
|
+
}
|
|
36
|
+
if (hiddenBySimulate.length > 0) {
|
|
37
|
+
results.push({
|
|
38
|
+
anchorAcId: 'AC-36108-1',
|
|
39
|
+
verdict: 'fail',
|
|
40
|
+
detail: `manifest file missing: ${hiddenBySimulate.join(', ')} (SIMULATE_MANIFEST_MISSING=true).`,
|
|
41
|
+
});
|
|
42
|
+
return { results };
|
|
43
|
+
}
|
|
44
|
+
let missingFieldCount = 0;
|
|
45
|
+
let plaintextCount = 0;
|
|
46
|
+
const fileFindings = [];
|
|
47
|
+
for (const f of files) {
|
|
48
|
+
let doc;
|
|
49
|
+
try {
|
|
50
|
+
doc = JSON.parse(f.text);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
results.push({
|
|
53
|
+
anchorAcId: 'AC-36101-1',
|
|
54
|
+
verdict: 'fail',
|
|
55
|
+
detail: `manifest file ${f.name} does not parse as JSON: ${err.message}`,
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const missing = REQUIRED_FIELDS.filter((k) => !(k in doc));
|
|
60
|
+
if (missing.length > 0) {
|
|
61
|
+
missingFieldCount += 1;
|
|
62
|
+
results.push({
|
|
63
|
+
anchorAcId: 'AC-36101-1',
|
|
64
|
+
verdict: 'fail',
|
|
65
|
+
detail: `manifest file ${f.name} missing required fields: ${missing.join(', ')}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
const hits = scanForPlaintextSecrets(f.text);
|
|
69
|
+
if (hits.length > 0) {
|
|
70
|
+
plaintextCount += 1;
|
|
71
|
+
results.push({
|
|
72
|
+
anchorAcId: 'AC-36101-1',
|
|
73
|
+
verdict: 'fail',
|
|
74
|
+
detail: `manifest file ${f.name} carries plaintext secret pattern(s): ${hits.join(', ')}`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
fileFindings.push({ name: f.name, ruleId: doc.id ?? null });
|
|
78
|
+
}
|
|
79
|
+
if (results.length === 0) {
|
|
80
|
+
results.push({
|
|
81
|
+
anchorAcId: 'AC-36101-1',
|
|
82
|
+
verdict: 'pass',
|
|
83
|
+
detail: `${files.length} manifest file(s) inspected; every file carries the ${REQUIRED_FIELDS.length} required fields and no plaintext secret pattern was found.`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
results,
|
|
88
|
+
extra: {
|
|
89
|
+
manifestFileCount: files.length,
|
|
90
|
+
manifestFiles: fileFindings,
|
|
91
|
+
missingFieldFileCount: missingFieldCount,
|
|
92
|
+
plaintextHitFileCount: plaintextCount,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/manifest-schema-validate.mjs
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Probe: rate-limit manifest schema-validate.
|
|
2
|
+
//
|
|
3
|
+
// anchorAcId: AC-36106-1. accountBound: false.
|
|
4
|
+
//
|
|
5
|
+
// Reads the cf-edge fixture manifest directory, loads the shipped
|
|
6
|
+
// JSON Schema (contributions/schemas/rate-limit-rule.schema.json,
|
|
7
|
+
// draft-07) and validates every manifest file against it. A minimal
|
|
8
|
+
// dependency-free validator covers the shape the schema commits to:
|
|
9
|
+
// required-fields, type-per-field, integer-minimum, string-min-length,
|
|
10
|
+
// non-empty-array and additionalProperties: false.
|
|
11
|
+
//
|
|
12
|
+
// Under SIMULATE_SCHEMA_INVALID=true the probe writes a scratch
|
|
13
|
+
// manifest file that omits the threshold field so validation fails
|
|
14
|
+
// with the offending field named in the detail.
|
|
15
|
+
|
|
16
|
+
import { readdir, readFile, writeFile, unlink, mkdir } from 'node:fs/promises';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { MANIFEST_DIR, REQUIRED_FIELDS, ACTION_ENUM, loadSchema } from './probe-utils.mjs';
|
|
19
|
+
|
|
20
|
+
export const anchorAcId = 'AC-36106-1';
|
|
21
|
+
export const accountBound = false;
|
|
22
|
+
|
|
23
|
+
function validateDoc(doc, schema, filename) {
|
|
24
|
+
const failures = [];
|
|
25
|
+
if (typeof doc !== 'object' || doc === null || Array.isArray(doc)) {
|
|
26
|
+
failures.push(`${filename}: root is not a JSON object`);
|
|
27
|
+
return failures;
|
|
28
|
+
}
|
|
29
|
+
for (const required of schema.required) {
|
|
30
|
+
if (!(required in doc)) failures.push(`${filename}: missing required field ${required}`);
|
|
31
|
+
}
|
|
32
|
+
const props = schema.properties || {};
|
|
33
|
+
const allowed = new Set(Object.keys(props));
|
|
34
|
+
if (schema.additionalProperties === false) {
|
|
35
|
+
for (const key of Object.keys(doc)) {
|
|
36
|
+
if (!allowed.has(key)) failures.push(`${filename}: additional property not permitted: ${key}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const [key, def] of Object.entries(props)) {
|
|
40
|
+
if (!(key in doc)) continue;
|
|
41
|
+
const v = doc[key];
|
|
42
|
+
if (def.type === 'string') {
|
|
43
|
+
if (typeof v !== 'string') { failures.push(`${filename}: ${key} is not a string`); continue; }
|
|
44
|
+
if (typeof def.minLength === 'number' && v.length < def.minLength) failures.push(`${filename}: ${key} shorter than minLength ${def.minLength}`);
|
|
45
|
+
if (Array.isArray(def.enum) && !def.enum.includes(v)) failures.push(`${filename}: ${key} value ${JSON.stringify(v)} not in enum ${JSON.stringify(def.enum)}`);
|
|
46
|
+
} else if (def.type === 'integer') {
|
|
47
|
+
if (!Number.isInteger(v)) { failures.push(`${filename}: ${key} is not an integer`); continue; }
|
|
48
|
+
if (typeof def.minimum === 'number' && v < def.minimum) failures.push(`${filename}: ${key} value ${v} below minimum ${def.minimum}`);
|
|
49
|
+
} else if (def.type === 'array') {
|
|
50
|
+
if (!Array.isArray(v)) { failures.push(`${filename}: ${key} is not an array`); continue; }
|
|
51
|
+
if (typeof def.minItems === 'number' && v.length < def.minItems) failures.push(`${filename}: ${key} array shorter than minItems ${def.minItems}`);
|
|
52
|
+
if (def.items && def.items.type === 'string') {
|
|
53
|
+
v.forEach((item, i) => {
|
|
54
|
+
if (typeof item !== 'string') failures.push(`${filename}: ${key}[${i}] is not a string`);
|
|
55
|
+
else if (typeof def.items.minLength === 'number' && item.length < def.items.minLength) failures.push(`${filename}: ${key}[${i}] shorter than minLength ${def.items.minLength}`);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return failures;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default async function runProbe() {
|
|
64
|
+
const schema = await loadSchema();
|
|
65
|
+
const simulateInvalid = process.env.SIMULATE_SCHEMA_INVALID === 'true';
|
|
66
|
+
const results = [];
|
|
67
|
+
const fileFindings = [];
|
|
68
|
+
let scratchPath = null;
|
|
69
|
+
try {
|
|
70
|
+
if (simulateInvalid) {
|
|
71
|
+
await mkdir(MANIFEST_DIR, { recursive: true });
|
|
72
|
+
scratchPath = join(MANIFEST_DIR, '__simulate-schema-invalid.json');
|
|
73
|
+
const invalidDoc = {
|
|
74
|
+
id: 'simulate-schema-invalid',
|
|
75
|
+
expression: '(http.request.uri.path matches "^/api/")',
|
|
76
|
+
period: 60,
|
|
77
|
+
characteristics: ['ip.src'],
|
|
78
|
+
action: 'block',
|
|
79
|
+
duration: 60,
|
|
80
|
+
};
|
|
81
|
+
await writeFile(scratchPath, JSON.stringify(invalidDoc, null, 2) + '\n', 'utf8');
|
|
82
|
+
}
|
|
83
|
+
const entries = (await readdir(MANIFEST_DIR)).filter((f) => f.endsWith('.json')).sort();
|
|
84
|
+
for (const name of entries) {
|
|
85
|
+
const text = await readFile(join(MANIFEST_DIR, name), 'utf8');
|
|
86
|
+
let doc;
|
|
87
|
+
try {
|
|
88
|
+
doc = JSON.parse(text);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
results.push({
|
|
91
|
+
anchorAcId: 'AC-36106-1',
|
|
92
|
+
verdict: 'fail',
|
|
93
|
+
detail: `manifest file ${name} does not parse: ${err.message}`,
|
|
94
|
+
});
|
|
95
|
+
fileFindings.push({ name, valid: false, errors: [err.message] });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const failures = validateDoc(doc, schema, name);
|
|
99
|
+
if (failures.length > 0) {
|
|
100
|
+
results.push({
|
|
101
|
+
anchorAcId: 'AC-36106-1',
|
|
102
|
+
verdict: 'fail',
|
|
103
|
+
detail: failures.join('; '),
|
|
104
|
+
});
|
|
105
|
+
fileFindings.push({ name, valid: false, errors: failures });
|
|
106
|
+
} else {
|
|
107
|
+
fileFindings.push({ name, valid: true });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} finally {
|
|
111
|
+
if (scratchPath) {
|
|
112
|
+
try { await unlink(scratchPath); } catch {}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (results.length === 0) {
|
|
116
|
+
results.push({
|
|
117
|
+
anchorAcId: 'AC-36106-1',
|
|
118
|
+
verdict: 'pass',
|
|
119
|
+
detail: `every manifest file validates against the shipped draft-07 schema (${fileFindings.length} file(s) inspected; required fields ${REQUIRED_FIELDS.join(', ')}; action enum ${ACTION_ENUM.join('/')}).`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
results,
|
|
124
|
+
extra: {
|
|
125
|
+
schemaId: schema.$id,
|
|
126
|
+
manifestFileCount: fileFindings.length,
|
|
127
|
+
manifestFiles: fileFindings,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Shared helpers for edge-cloudflare-rate-limiting probes.
|
|
2
|
+
//
|
|
3
|
+
// Runtime-dependency posture: three probes read the cf-edge fixture
|
|
4
|
+
// manifest directory in-process (no network); one probe fires an
|
|
5
|
+
// undici burst against a scheduled real-account URL when
|
|
6
|
+
// CI_HAS_CLOUDFLARE_ACCOUNT and CF_RATE_LIMIT_URL are set, and
|
|
7
|
+
// records accountBoundSkipped: true otherwise per spec section 3.5
|
|
8
|
+
// and ruling 6. The drift-audit runner realisation lives in the
|
|
9
|
+
// fixture at src/drift-audit-runner.mjs.
|
|
10
|
+
|
|
11
|
+
import { mkdir, writeFile, readFile, readdir, rename, stat } from 'node:fs/promises';
|
|
12
|
+
import { dirname, resolve, join, basename } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
|
|
17
|
+
export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
|
|
18
|
+
export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/cf-edge');
|
|
19
|
+
export const MANIFEST_DIR = resolve(FIXTURE_DIR, 'cloudflare/rate-limits');
|
|
20
|
+
export const SCHEMA_PATH = resolve(HERE, '..', 'schemas', 'rate-limit-rule.schema.json');
|
|
21
|
+
export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/edge-cloudflare-rate-limiting');
|
|
22
|
+
|
|
23
|
+
export const REQUIRED_FIELDS = Object.freeze([
|
|
24
|
+
'id',
|
|
25
|
+
'expression',
|
|
26
|
+
'threshold',
|
|
27
|
+
'period',
|
|
28
|
+
'characteristics',
|
|
29
|
+
'action',
|
|
30
|
+
'duration',
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export const ACTION_ENUM = Object.freeze(['block', 'challenge', 'log', 'managed_challenge']);
|
|
34
|
+
|
|
35
|
+
export function aggregate(results) {
|
|
36
|
+
if (results.some((r) => r.verdict === 'fail')) return 'fail';
|
|
37
|
+
if (results.some((r) => r.verdict === 'warn')) return 'warn';
|
|
38
|
+
return 'pass';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function writeReport({ probeName, engine, results, extra }) {
|
|
42
|
+
await mkdir(REPORT_DIR, { recursive: true });
|
|
43
|
+
const report = {
|
|
44
|
+
slug: 'edge-cloudflare-rate-limiting',
|
|
45
|
+
probeName,
|
|
46
|
+
runAt: new Date().toISOString(),
|
|
47
|
+
engine,
|
|
48
|
+
results,
|
|
49
|
+
aggregateVerdict: aggregate(results),
|
|
50
|
+
...(extra ?? {}),
|
|
51
|
+
};
|
|
52
|
+
const path = resolve(REPORT_DIR, `${probeName}.json`);
|
|
53
|
+
await writeFile(path, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
54
|
+
return { report, path };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function runShim(probeName, engine, mainFn) {
|
|
58
|
+
try {
|
|
59
|
+
const { results, extra } = await mainFn();
|
|
60
|
+
const { report, path } = await writeReport({ probeName, engine, results, extra });
|
|
61
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
62
|
+
process.stdout.write(`report written to ${path}\n`);
|
|
63
|
+
if (report.aggregateVerdict === 'fail') process.exitCode = 1;
|
|
64
|
+
} catch (err) {
|
|
65
|
+
const results = [{
|
|
66
|
+
anchorAcId: 'unknown',
|
|
67
|
+
verdict: 'fail',
|
|
68
|
+
detail: `probe threw: ${err && err.message ? err.message : String(err)}`,
|
|
69
|
+
}];
|
|
70
|
+
const { report, path } = await writeReport({ probeName, engine, results });
|
|
71
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
72
|
+
process.stderr.write(`probe error: ${err && err.stack ? err.stack : String(err)}\n`);
|
|
73
|
+
process.stderr.write(`report written to ${path}\n`);
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function readManifestFiles(dir = MANIFEST_DIR) {
|
|
79
|
+
const missing = process.env.SIMULATE_MANIFEST_MISSING === 'true';
|
|
80
|
+
let entries;
|
|
81
|
+
try {
|
|
82
|
+
entries = (await readdir(dir)).filter((f) => f.endsWith('.json')).sort();
|
|
83
|
+
} catch (err) {
|
|
84
|
+
return { present: false, missing: [], entries: [], error: err.message };
|
|
85
|
+
}
|
|
86
|
+
const hidden = new Set();
|
|
87
|
+
if (missing && entries.length > 0) {
|
|
88
|
+
hidden.add(entries[0]);
|
|
89
|
+
}
|
|
90
|
+
const files = [];
|
|
91
|
+
for (const name of entries) {
|
|
92
|
+
if (hidden.has(name)) continue;
|
|
93
|
+
const p = join(dir, name);
|
|
94
|
+
const text = await readFile(p, 'utf8');
|
|
95
|
+
files.push({ name, path: p, text });
|
|
96
|
+
}
|
|
97
|
+
return { present: entries.length > 0, entries, files, hiddenBySimulate: [...hidden] };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function scanForPlaintextSecrets(text) {
|
|
101
|
+
const hits = [];
|
|
102
|
+
if (/[Bb]earer\s+[A-Za-z0-9._-]{20,}/.test(text)) hits.push('bearer-token-like');
|
|
103
|
+
if (/-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(text)) hits.push('pem-private-key');
|
|
104
|
+
if (/"?CF_API_TOKEN"?\s*:\s*"[^"]{5,}"/.test(text)) hits.push('inline-cf-api-token');
|
|
105
|
+
return hits;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function loadSchema() {
|
|
109
|
+
const raw = await readFile(SCHEMA_PATH, 'utf8');
|
|
110
|
+
return JSON.parse(raw);
|
|
111
|
+
}
|
package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/real-account-burst-and-429.mjs
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Probe: real-account burst-and-429 against a scheduled URL.
|
|
2
|
+
//
|
|
3
|
+
// anchorAcId: AC-36103-1. accountBound: true.
|
|
4
|
+
//
|
|
5
|
+
// When CI_HAS_CLOUDFLARE_ACCOUNT=true AND CF_RATE_LIMIT_URL is set,
|
|
6
|
+
// the probe fires an in-process burst against the scheduled URL and
|
|
7
|
+
// asserts:
|
|
8
|
+
// - the (N+1)th and subsequent requests within the elicited
|
|
9
|
+
// duration return HTTP 429.
|
|
10
|
+
// - the 429 responses carry a Retry-After header consistent with
|
|
11
|
+
// the elicited duration.
|
|
12
|
+
// - the 429 responses carry a Cf-Ray header naming the CF edge.
|
|
13
|
+
//
|
|
14
|
+
// Without either env var the probe records accountBoundSkipped: true
|
|
15
|
+
// and aggregates to pass per spec section 3.5 and ruling 6.
|
|
16
|
+
// N (the elicited threshold) is read from CF_RATE_LIMIT_THRESHOLD
|
|
17
|
+
// (default 60); the burst count is N+3.
|
|
18
|
+
|
|
19
|
+
export const anchorAcId = 'AC-36103-1';
|
|
20
|
+
export const accountBound = true;
|
|
21
|
+
|
|
22
|
+
const BURST_TIMEOUT_MS = 10000;
|
|
23
|
+
|
|
24
|
+
async function fireOne(url) {
|
|
25
|
+
const ctrl = new AbortController();
|
|
26
|
+
const to = setTimeout(() => ctrl.abort(), BURST_TIMEOUT_MS);
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(url, { method: 'GET', redirect: 'manual', signal: ctrl.signal });
|
|
29
|
+
return { status: res.status, retryAfter: res.headers.get('retry-after'), cfRay: res.headers.get('cf-ray') };
|
|
30
|
+
} finally {
|
|
31
|
+
clearTimeout(to);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default async function runProbe() {
|
|
36
|
+
const has = process.env.CI_HAS_CLOUDFLARE_ACCOUNT === 'true';
|
|
37
|
+
const url = process.env.CF_RATE_LIMIT_URL || '';
|
|
38
|
+
if (!has || !url) {
|
|
39
|
+
return {
|
|
40
|
+
results: [{
|
|
41
|
+
anchorAcId: 'AC-36103-1',
|
|
42
|
+
verdict: 'pass',
|
|
43
|
+
accountBoundSkipped: true,
|
|
44
|
+
detail: `accountBoundSkipped: CI_HAS_CLOUDFLARE_ACCOUNT=${has} CF_RATE_LIMIT_URL=${url ? 'set' : 'unset'}; per spec section 3.5 and ruling 6 pass-with-skip.`,
|
|
45
|
+
}],
|
|
46
|
+
extra: { accountBoundSkipped: true },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const threshold = Number.parseInt(process.env.CF_RATE_LIMIT_THRESHOLD || '60', 10);
|
|
50
|
+
const burstCount = threshold + 3;
|
|
51
|
+
const results429 = [];
|
|
52
|
+
const responses = [];
|
|
53
|
+
try {
|
|
54
|
+
for (let i = 0; i < burstCount; i += 1) {
|
|
55
|
+
const r = await fireOne(url);
|
|
56
|
+
responses.push(r);
|
|
57
|
+
if (r.status === 429) results429.push(r);
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
return {
|
|
61
|
+
results: [{
|
|
62
|
+
anchorAcId: 'AC-36103-1',
|
|
63
|
+
verdict: 'fail',
|
|
64
|
+
detail: `real-account burst threw before completion: ${err && err.message ? err.message : String(err)}`,
|
|
65
|
+
}],
|
|
66
|
+
extra: { accountBound: true, responsesFired: responses.length },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const results = [];
|
|
70
|
+
if (results429.length < 2) {
|
|
71
|
+
results.push({
|
|
72
|
+
anchorAcId: 'AC-36103-1',
|
|
73
|
+
verdict: 'fail',
|
|
74
|
+
detail: `burst of ${burstCount} produced ${results429.length} 429 response(s); expected at least the ${burstCount - threshold} requests above the elicited threshold to return 429.`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const missingRetryAfter = results429.filter((r) => !r.retryAfter);
|
|
78
|
+
if (missingRetryAfter.length > 0) {
|
|
79
|
+
results.push({
|
|
80
|
+
anchorAcId: 'AC-36103-1',
|
|
81
|
+
verdict: 'fail',
|
|
82
|
+
detail: `${missingRetryAfter.length} of the 429 response(s) missing a Retry-After header; the Cloudflare WAF rate-limiting rules documented shape names Retry-After as the value the client honours.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const missingCfRay = results429.filter((r) => !r.cfRay);
|
|
86
|
+
if (missingCfRay.length > 0) {
|
|
87
|
+
results.push({
|
|
88
|
+
anchorAcId: 'AC-36103-1',
|
|
89
|
+
verdict: 'fail',
|
|
90
|
+
detail: `${missingCfRay.length} of the 429 response(s) missing a Cf-Ray header; the header identifies the CF edge that served the refusal.`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (results.length === 0) {
|
|
94
|
+
results.push({
|
|
95
|
+
anchorAcId: 'AC-36103-1',
|
|
96
|
+
verdict: 'pass',
|
|
97
|
+
detail: `burst of ${burstCount} produced ${results429.length} 429 response(s), every 429 carries Retry-After and Cf-Ray; over-threshold behaviour confirmed against the scheduled URL.`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
results,
|
|
102
|
+
extra: { accountBound: true, responsesFired: responses.length, count429: results429.length, threshold },
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './event-secrecy.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'event-sink-accumulation', image: 'cf-edge fixture drift-audit runner driven with synthetic manifest and fake fetch (in-process)', healthy: true };
|
|
5
|
+
runShim('event-secrecy', engine, runProbe);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './manifest-schema-validate.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'source-scan', image: 'cf-edge fixture manifest directory validated against draft-07 JSON Schema (in-process)', healthy: true };
|
|
5
|
+
runShim('manifest-schema-validate', engine, runProbe);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './real-account-burst-and-429.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'real-account', image: 'undici burst against scheduled Cloudflare-fronted URL', healthy: true };
|
|
5
|
+
runShim('real-account-burst-and-429', engine, runProbe);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-001",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"title": "The rate-limit rule set is committed to the applying project as a local manifest under cloudflare/rate-limits/, one JSON file per rule",
|
|
5
|
+
"description": "The applying project holds its rate-limit rule set as a set of JSON documents under the elicited rate-limit-rules-dir (default cloudflare/rate-limits/), one file per rule per ADR-3703. Every manifest file declares the seven documented fields the Cloudflare WAF rate-limiting rules contract names per https://developers.cloudflare.com/waf/rate-limiting-rules/: id (a stable operator-facing string), expression (the WAF rules-language expression string), threshold (positive integer), period (seconds), characteristics (non-empty array of stable characteristic strings), action (block or challenge or log or managed_challenge), duration (seconds, the length of the block window). No rule references a secret in plaintext; the zone id is elicited and stored via the applied secretsManagement companion. The manifest is the source of truth an operator applies via the wrangler or dashboard flow named in the guide; no committed script writes the rules to the live zone.",
|
|
6
|
+
"category": "functional",
|
|
7
|
+
"domain": "edge",
|
|
8
|
+
"priority": "must",
|
|
9
|
+
"rationale": "Ratified in the Cloudflare round 6 spec (cloudflare-round-6-spec-2026-09-06.md section 5.6). Ships as v1.0.0 of edge-cloudflare-rate-limiting.",
|
|
10
|
+
"tags": [
|
|
11
|
+
"blueprint:edge-cloudflare-rate-limiting"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"status": "approved",
|
|
15
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-002",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"title": "The operator-facing management surface is a documented wrangler or Cloudflare-dashboard flow that applies the local manifest to the live zone",
|
|
5
|
+
"description": "The blueprint ships no committed script that writes rules to the live Cloudflare zone. The applying project's operator applies the manifest to the elicited zone through one of two documented flows per TAC-3702 and the guide: a wrangler-based flow (the guide names the exact wrangler subcommands the operator runs; commits an audit trail through the wrangler history) or a Cloudflare-dashboard flow (the guide walks the dashboard screens the operator clicks per https://developers.cloudflare.com/waf/rate-limiting-rules/). The elicited rate-limit-management-surface value records the flow the operator chose; the guide's copy-paste walkthrough covers both. The intent is a management surface an operator can hand-run at a known cadence and reproduce from the manifest without inventing a bespoke deploy tool.",
|
|
6
|
+
"category": "operational",
|
|
7
|
+
"domain": "edge",
|
|
8
|
+
"priority": "must",
|
|
9
|
+
"rationale": "Ratified in the Cloudflare round 6 spec (cloudflare-round-6-spec-2026-09-06.md section 5.6). Ships as v1.0.0 of edge-cloudflare-rate-limiting.",
|
|
10
|
+
"tags": [
|
|
11
|
+
"blueprint:edge-cloudflare-rate-limiting"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"status": "approved",
|
|
15
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-003",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"title": "Over-threshold behaviour: the (N+1)th and subsequent requests within the elicited duration return 429 with Retry-After and Cf-Ray, and the origin never sees them",
|
|
5
|
+
"description": "Given a rule that permits N requests per period on a characteristic set, when a client sends the (N+1)th request within that period, Cloudflare's zone-level rate limiter refuses the request at the edge for the elicited duration. The refusal response is HTTP 429 with a Retry-After header naming a value consistent with the elicited duration and a Cf-Ray header identifying the CF edge that served the refusal per the Cloudflare WAF rate-limiting rules documented shape at https://developers.cloudflare.com/waf/rate-limiting-rules/. The origin Worker never sees the refused requests. This is the runtime observable AC-rateLimiting-overThresholdBlocks binds; the runtime verification is the real-account burst probe per REQ-004's account-bound category, and per ruling 6 the local CI records accountBound: skipped without CI_HAS_CLOUDFLARE_ACCOUNT.",
|
|
6
|
+
"category": "functional",
|
|
7
|
+
"domain": "edge",
|
|
8
|
+
"priority": "must",
|
|
9
|
+
"rationale": "Ratified in the Cloudflare round 6 spec (cloudflare-round-6-spec-2026-09-06.md section 5.6). Ships as v1.0.0 of edge-cloudflare-rate-limiting.",
|
|
10
|
+
"tags": [
|
|
11
|
+
"blueprint:edge-cloudflare-rate-limiting"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"status": "approved",
|
|
15
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-004",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"title": "Drift audit: an opt-in scheduled runner reads live zone rules via the Cloudflare API and diffs against the local manifest, reporting mismatches metadata-only",
|
|
5
|
+
"description": "The blueprint ships a scheduled drift-audit runner (TAC-3703) the applying project can wire behind the elicited rate-limit-drift-audit-cadence per ADR-3704. When enabled (daily or hourly), the runner fetches the live rate-limiting rules on the elicited zone via the Cloudflare API, diffs the returned rule set against the local manifest field-by-field, and constructs one drift-audit record per mismatched rule. Each record is written through the applied logger's audit sink with the metadata-only shape {ruleId, clientIpHash, outcome, timestamp} plus the diff fields; a record never carries a full client IP, a request body or a user agent per REQ-005's event-secrecy discipline. The runner's report artefact writes to the standard blueprint-report location under .rcf/reports/blueprints/edge-cloudflare-rate-limiting/. When the elicited cadence is off, the runner is not wired.",
|
|
6
|
+
"category": "operational",
|
|
7
|
+
"domain": "edge",
|
|
8
|
+
"priority": "must",
|
|
9
|
+
"rationale": "Ratified in the Cloudflare round 6 spec (cloudflare-round-6-spec-2026-09-06.md section 5.6). Ships as v1.0.0 of edge-cloudflare-rate-limiting.",
|
|
10
|
+
"tags": [
|
|
11
|
+
"blueprint:edge-cloudflare-rate-limiting"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"status": "approved",
|
|
15
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"reqId": "edge-cloudflare-rate-limiting-REQ-005",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"title": "Composition with security-auth-magic-link: the zone-level rate rule layers over the per-email application rule",
|
|
5
|
+
"description": "When both edge-cloudflare-rate-limiting and security-auth-magic-link are applied on the same project, the composition follows ADR-3702: the zone-level rate rule sits at the CF edge and refuses the (N+1)th request for the elicited duration before it reaches the origin Worker; the per-email application rate limiter that security-auth-magic-link ships continues to run on requests that pass the edge gate, applying per-email per-minute limits at the mint-surface. Zone rule layers OVER the application rule; the two operate on different characteristic sets (IP-per-URL at the zone, email at the application) and never overlap on the same characteristic. The guide names the composition explicitly with a copy-paste example. Applying both blueprints without the ADR-3702 layering understanding would leave two rate rules operating on the same characteristic and shadowing each other; ADR-3702 states the layering explicitly and the applied recorder records both blueprints so the operator sees the two-rule shape at apply time.",
|
|
6
|
+
"category": "functional",
|
|
7
|
+
"domain": "edge",
|
|
8
|
+
"priority": "should",
|
|
9
|
+
"rationale": "Ratified in the Cloudflare round 6 spec (cloudflare-round-6-spec-2026-09-06.md section 5.6). Ships as v1.0.0 of edge-cloudflare-rate-limiting.",
|
|
10
|
+
"tags": [
|
|
11
|
+
"blueprint:edge-cloudflare-rate-limiting"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"status": "approved",
|
|
15
|
+
"createdAt": "2026-09-07T22:00:00.000Z",
|
|
16
|
+
"updatedAt": "2026-09-07T22:00:00.000Z"
|
|
17
|
+
}
|
package/blueprints/edge-cloudflare-rate-limiting/contributions/schemas/rate-limit-rule.schema.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://stravica.ai/rcf-lite/schemas/rate-limit-rule.schema.json",
|
|
4
|
+
"title": "Cloudflare rate-limit rule manifest file",
|
|
5
|
+
"description": "One rule per file under the elicited rate-limit-rules-dir. Fields track the Cloudflare WAF rate-limiting rules documented shape at https://developers.cloudflare.com/waf/rate-limiting-rules/.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"id",
|
|
10
|
+
"expression",
|
|
11
|
+
"threshold",
|
|
12
|
+
"period",
|
|
13
|
+
"characteristics",
|
|
14
|
+
"action",
|
|
15
|
+
"duration"
|
|
16
|
+
],
|
|
17
|
+
"properties": {
|
|
18
|
+
"id": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"minLength": 1,
|
|
21
|
+
"description": "Operator-facing stable rule id (kebab-case; used in drift-audit records as ruleId)."
|
|
22
|
+
},
|
|
23
|
+
"expression": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"description": "Cloudflare WAF rules-language expression string; scopes the rule to a request set."
|
|
27
|
+
},
|
|
28
|
+
"threshold": {
|
|
29
|
+
"type": "integer",
|
|
30
|
+
"minimum": 1,
|
|
31
|
+
"description": "Requests permitted per period on the characteristic set."
|
|
32
|
+
},
|
|
33
|
+
"period": {
|
|
34
|
+
"type": "integer",
|
|
35
|
+
"minimum": 1,
|
|
36
|
+
"description": "Window in seconds the threshold applies over."
|
|
37
|
+
},
|
|
38
|
+
"characteristics": {
|
|
39
|
+
"type": "array",
|
|
40
|
+
"minItems": 1,
|
|
41
|
+
"items": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"minLength": 1
|
|
44
|
+
},
|
|
45
|
+
"description": "Non-empty list of characteristic strings the rule keys on (e.g. cf.colo.id, ip.src, http.host + http.request.uri.path)."
|
|
46
|
+
},
|
|
47
|
+
"action": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"enum": [
|
|
50
|
+
"block",
|
|
51
|
+
"challenge",
|
|
52
|
+
"log",
|
|
53
|
+
"managed_challenge"
|
|
54
|
+
],
|
|
55
|
+
"description": "Cloudflare-documented action verb the rule applies over-threshold."
|
|
56
|
+
},
|
|
57
|
+
"duration": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"minimum": 1,
|
|
60
|
+
"description": "Block window in seconds the (N+1)th and subsequent requests are refused for."
|
|
61
|
+
},
|
|
62
|
+
"description": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"description": "Optional operator-facing description of the rule intent."
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|