rcf-lite 0.27.0 → 0.28.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 +23 -0
- package/README.md +10 -0
- package/bin/rcf.js +2 -0
- package/blueprints/application-account-settings/CHANGELOG.md +35 -6
- package/blueprints/application-account-settings/README.md +1 -1
- package/blueprints/application-account-settings/blueprint.json +4 -2
- package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
- package/blueprints/application-account-settings/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-account-settings/contributions/probes/profile-form-autocomplete.mjs +67 -0
- package/blueprints/application-account-settings/contributions/probes/run-profile-form-autocomplete.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-sessions-adapter-uniform.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-sessions-surface-shape.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-shell-tablist-per-capability.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/run-theme-radiogroup.mjs +5 -0
- package/blueprints/application-account-settings/contributions/probes/sessions-adapter-uniform.mjs +130 -0
- package/blueprints/application-account-settings/contributions/probes/sessions-surface-shape.mjs +70 -0
- package/blueprints/application-account-settings/contributions/probes/shell-tablist-per-capability.mjs +60 -0
- package/blueprints/application-account-settings/contributions/probes/theme-radiogroup.mjs +126 -0
- package/blueprints/application-admin-console/CHANGELOG.md +32 -6
- package/blueprints/application-admin-console/README.md +1 -1
- package/blueprints/application-admin-console/blueprint.json +4 -2
- package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +1 -1
- package/blueprints/application-admin-console/contributions/probes/audit-log-surface.mjs +79 -0
- package/blueprints/application-admin-console/contributions/probes/org-switcher-surface.mjs +83 -0
- package/blueprints/application-admin-console/contributions/probes/permission-matrix-grid.mjs +67 -0
- package/blueprints/application-admin-console/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-admin-console/contributions/probes/run-audit-log-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-sign-in-access-gated-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs +5 -0
- package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs +117 -0
- package/blueprints/application-admin-console/contributions/probes/users-directory-surface.mjs +145 -0
- package/blueprints/application-api-rest/CHANGELOG.md +16 -8
- package/blueprints/application-api-rest/README.md +3 -3
- package/blueprints/application-api-rest/blueprint.json +3 -2
- package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +1 -1
- package/blueprints/application-api-rest/contributions/probes/cursor-pagination-round-trip.mjs +154 -0
- package/blueprints/application-api-rest/contributions/probes/health-probes-distinct.mjs +124 -0
- package/blueprints/application-api-rest/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-api-rest/contributions/probes/problem-details-on-error.mjs +77 -0
- package/blueprints/application-api-rest/contributions/probes/request-id-echoed.mjs +76 -0
- package/blueprints/application-api-rest/contributions/probes/run-cursor-pagination-round-trip.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-health-probes-distinct.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-problem-details-on-error.mjs +5 -0
- package/blueprints/application-api-rest/contributions/probes/run-request-id-echoed.mjs +5 -0
- package/blueprints/application-api-rest/docs/topics.md +1 -1
- package/blueprints/application-charts/CHANGELOG.md +35 -9
- package/blueprints/application-charts/README.md +6 -6
- package/blueprints/application-charts/blueprint.json +5 -3
- package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +1 -1
- package/blueprints/application-charts/contributions/probes/keyboard-traversal.mjs +151 -0
- package/blueprints/application-charts/contributions/probes/non-colour-distinction.mjs +67 -0
- package/blueprints/application-charts/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-charts/contributions/probes/run-keyboard-traversal.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/run-non-colour-distinction.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/run-text-alternative-table.mjs +5 -0
- package/blueprints/application-charts/contributions/probes/text-alternative-table.mjs +139 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +1 -1
- package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +1 -1
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +5 -5
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +1 -1
- package/blueprints/application-charts/guide/application-charts.md +1 -1
- package/blueprints/application-dashboard/CHANGELOG.md +20 -10
- package/blueprints/application-dashboard/README.md +6 -6
- package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
- package/blueprints/application-dashboard/blueprint.json +3 -2
- package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +1 -1
- package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +1 -1
- package/blueprints/application-dashboard/contributions/probes/export-handle-formats.mjs +75 -0
- package/blueprints/application-dashboard/contributions/probes/four-tile-states.mjs +75 -0
- package/blueprints/application-dashboard/contributions/probes/primary-kpi-top-left.mjs +58 -0
- package/blueprints/application-dashboard/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-dashboard/contributions/probes/run-export-handle-formats.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-four-tile-states.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-primary-kpi-top-left.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/run-shell-five-regions.mjs +4 -0
- package/blueprints/application-dashboard/contributions/probes/shell-five-regions.mjs +93 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +1 -1
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +1 -1
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +1 -1
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +2 -2
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +5 -5
- package/blueprints/application-dashboard/docs/topics.md +2 -2
- package/blueprints/application-dashboard/guide/application-dashboard.md +2 -2
- package/blueprints/application-datatable/CHANGELOG.md +19 -9
- package/blueprints/application-datatable/README.md +2 -2
- package/blueprints/application-datatable/blueprint.json +3 -2
- package/blueprints/application-datatable/contributions/probes/apg-table-shape.mjs +57 -0
- package/blueprints/application-datatable/contributions/probes/four-states-regions.mjs +80 -0
- package/blueprints/application-datatable/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-datatable/contributions/probes/run-apg-table-shape.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-four-states-regions.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-search-adapter-round-trip.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/run-sort-adapter-round-trip.mjs +4 -0
- package/blueprints/application-datatable/contributions/probes/search-adapter-round-trip.mjs +58 -0
- package/blueprints/application-datatable/contributions/probes/sort-adapter-round-trip.mjs +60 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +1 -1
- package/blueprints/application-datatable/docs/topics.md +1 -1
- package/blueprints/application-empty-error-states/CHANGELOG.md +33 -3
- package/blueprints/application-empty-error-states/blueprint.json +4 -2
- package/blueprints/application-empty-error-states/contributions/probes/empty-list-and-no-search.mjs +66 -0
- package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs +65 -0
- package/blueprints/application-empty-error-states/contributions/probes/forbidden-and-server-error.mjs +167 -0
- package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs +61 -0
- package/blueprints/application-empty-error-states/contributions/probes/permission-denied-and-offline.mjs +155 -0
- package/blueprints/application-empty-error-states/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-empty-list-and-no-search.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-forbidden-and-server-error.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-not-found-and-recovery.mjs +5 -0
- package/blueprints/application-empty-error-states/contributions/probes/run-permission-denied-and-offline.mjs +5 -0
- package/blueprints/application-error-handling/CHANGELOG.md +45 -6
- package/blueprints/application-error-handling/blueprint.json +3 -2
- package/blueprints/application-error-handling/contributions/probes/category-vocabulary.mjs +90 -0
- package/blueprints/application-error-handling/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-error-handling/contributions/probes/record-shape-adr-1701.mjs +78 -0
- package/blueprints/application-error-handling/contributions/probes/run-category-vocabulary.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/run-record-shape-adr-1701.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/run-two-boundaries-registered.mjs +5 -0
- package/blueprints/application-error-handling/contributions/probes/two-boundaries-registered.mjs +343 -0
- package/blueprints/application-file-upload/CHANGELOG.md +28 -6
- package/blueprints/application-file-upload/README.md +1 -1
- package/blueprints/application-file-upload/blueprint.json +3 -2
- package/blueprints/application-file-upload/contributions/probes/assertive-completion-slot.mjs +78 -0
- package/blueprints/application-file-upload/contributions/probes/chunked-transport-endpoints.mjs +173 -0
- package/blueprints/application-file-upload/contributions/probes/per-file-progressbar.mjs +124 -0
- package/blueprints/application-file-upload/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-file-upload/contributions/probes/run-assertive-completion-slot.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-chunked-transport-endpoints.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-per-file-progressbar.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/run-upload-surface-shape.mjs +4 -0
- package/blueprints/application-file-upload/contributions/probes/upload-surface-shape.mjs +55 -0
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +1 -1
- package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +1 -1
- package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +1 -1
- package/blueprints/application-forms-wizard/CHANGELOG.md +20 -6
- package/blueprints/application-forms-wizard/README.md +2 -2
- package/blueprints/application-forms-wizard/blueprint.json +3 -2
- package/blueprints/application-forms-wizard/contributions/probes/draft-persistence-round-trip.mjs +110 -0
- package/blueprints/application-forms-wizard/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-draft-persistence-round-trip.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-step-page-shape.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/run-task-list-surface.mjs +4 -0
- package/blueprints/application-forms-wizard/contributions/probes/step-page-shape.mjs +61 -0
- package/blueprints/application-forms-wizard/contributions/probes/task-list-surface.mjs +109 -0
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +1 -1
- package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +1 -1
- package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +1 -1
- package/blueprints/application-notifications-in-app/CHANGELOG.md +38 -5
- package/blueprints/application-notifications-in-app/README.md +4 -4
- package/blueprints/application-notifications-in-app/blueprint.json +4 -2
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/probes/centre-acknowledge-round-trip.mjs +210 -0
- package/blueprints/application-notifications-in-app/contributions/probes/live-region-preseeding.mjs +93 -0
- package/blueprints/application-notifications-in-app/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-centre-acknowledge-round-trip.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-live-region-preseeding.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/run-toast-contract.mjs +5 -0
- package/blueprints/application-notifications-in-app/contributions/probes/toast-contract.mjs +92 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +3 -3
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +1 -1
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +1 -1
- package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +3 -3
- package/blueprints/application-onboarding-tour/CHANGELOG.md +31 -5
- package/blueprints/application-onboarding-tour/README.md +1 -1
- package/blueprints/application-onboarding-tour/blueprint.json +5 -3
- package/blueprints/application-onboarding-tour/contributions/probes/checklist-anchor-open.mjs +81 -0
- package/blueprints/application-onboarding-tour/contributions/probes/completion-persistence.mjs +159 -0
- package/blueprints/application-onboarding-tour/contributions/probes/first-run-detection.mjs +67 -0
- package/blueprints/application-onboarding-tour/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-checklist-anchor-open.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-completion-persistence.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-first-run-detection.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/run-stepper-role-dialog.mjs +5 -0
- package/blueprints/application-onboarding-tour/contributions/probes/stepper-role-dialog.mjs +45 -0
- package/blueprints/application-spa/CHANGELOG.md +20 -11
- package/blueprints/application-spa/README.md +9 -10
- package/blueprints/application-spa/blueprint.json +3 -2
- package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +1 -1
- package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +1 -1
- package/blueprints/application-spa/contributions/probes/designed-empty-state.mjs +72 -0
- package/blueprints/application-spa/contributions/probes/probe-utils.mjs +177 -0
- package/blueprints/application-spa/contributions/probes/route-inventory-published.mjs +185 -0
- package/blueprints/application-spa/contributions/probes/run-designed-empty-state.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/run-route-inventory-published.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/run-shell-nav-present.mjs +5 -0
- package/blueprints/application-spa/contributions/probes/shell-nav-present.mjs +69 -0
- package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +1 -1
- package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +2 -2
- package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +3 -3
- package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +2 -2
- package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +2 -2
- package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +1 -1
- package/blueprints/application-spa/docs/topics.md +1 -1
- package/blueprints/delivery-ci-workflows/CHANGELOG.md +31 -11
- package/blueprints/delivery-ci-workflows/README.md +3 -3
- package/blueprints/delivery-ci-workflows/blueprint.json +3 -2
- package/blueprints/delivery-ci-workflows/contributions/adrs/adr-702-delivery-ci-workflows-strict-coverage-gate.json +2 -2
- package/blueprints/delivery-ci-workflows/contributions/probes/node-gate-entrypoint.mjs +76 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/probe-utils.mjs +56 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/real-account-github-actions-run-record.mjs +139 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-node-gate-entrypoint.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-real-account-github-actions-run-record.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/run-workflow-template-shape.mjs +3 -0
- package/blueprints/delivery-ci-workflows/contributions/probes/workflow-template-shape.mjs +94 -0
- package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +1 -1
- package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
- package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +4 -4
- package/blueprints/deploy-cloudflare-workers/README.md +3 -3
- package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +2 -2
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
- package/blueprints/deploy-hetzner-server/CHANGELOG.md +98 -7
- package/blueprints/deploy-hetzner-server/blueprint.json +7 -6
- package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +46 -21
- package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +344 -83
- package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +211 -42
- package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +140 -22
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +111 -30
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +158 -30
- package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +154 -32
- package/blueprints/edge-cloudflare-access/CHANGELOG.md +6 -5
- package/blueprints/edge-cloudflare-access/blueprint.json +1 -1
- package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
- package/blueprints/edge-cloudflare-access/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +4 -7
- package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +4 -6
- package/blueprints/edge-cloudflare-tunnel/README.md +1 -2
- package/blueprints/edge-cloudflare-tunnel/docs/topics.md +1 -1
- package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +2 -3
- package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
- package/blueprints/email-smtp-resend/CHANGELOG.md +24 -8
- package/blueprints/email-smtp-resend/README.md +2 -2
- package/blueprints/email-smtp-resend/blueprint.json +3 -2
- package/blueprints/email-smtp-resend/contributions/probes/probe-utils.mjs +50 -0
- package/blueprints/email-smtp-resend/contributions/probes/real-account-resend-send.mjs +50 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-real-account-resend-send.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-smtp-round-trip.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/run-unverified-sender-refusal.mjs +3 -0
- package/blueprints/email-smtp-resend/contributions/probes/smtp-round-trip.mjs +43 -0
- package/blueprints/email-smtp-resend/contributions/probes/unverified-sender-refusal.mjs +99 -0
- package/blueprints/email-smtp-resend/docs/topics.md +2 -3
- package/blueprints/jobs-background/CHANGELOG.md +66 -5
- package/blueprints/jobs-background/README.md +2 -2
- package/blueprints/jobs-background/blueprint.json +3 -2
- package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +38 -10
- package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +28 -6
- package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +16 -2
- package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +102 -21
- package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +10 -2
- package/blueprints/jobs-background/contributions/probes/retry-and-fail-real-account.mjs +355 -0
- package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +33 -2
- package/blueprints/jobs-background/contributions/probes/run-retry-and-fail-real-account.mjs +12 -0
- package/blueprints/jobs-background/docs/topics.md +1 -1
- package/blueprints/jobs-background/guide/jobs-background.md +1 -1
- package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +25 -19
- package/blueprints/messaging-queue-cloudflare/README.md +12 -12
- package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +2 -2
- package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +1 -1
- package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +180 -12
- package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +1 -1
- package/blueprints/messaging-queue-cloudflare/docs/topics.md +2 -2
- package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +2 -2
- package/blueprints/object-storage-s3/CHANGELOG.md +75 -4
- package/blueprints/object-storage-s3/blueprint.json +3 -2
- package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +73 -12
- package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +55 -7
- package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +102 -18
- package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +105 -36
- package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +104 -55
- package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +129 -7
- package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +80 -18
- package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +291 -37
- package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +5 -5
- package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +8 -5
- package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +8 -2
- package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +6 -3
- package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +10 -2
- package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +1 -1
- package/blueprints/object-storage-s3/docs/topics.md +1 -1
- package/blueprints/object-storage-s3/guide/object-storage-s3.md +1 -1
- package/blueprints/observability-essentials/CHANGELOG.md +23 -7
- package/blueprints/observability-essentials/README.md +2 -2
- package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +1 -1
- package/blueprints/observability-essentials/blueprint.json +3 -2
- package/blueprints/observability-essentials/contributions/probes/liveness-probe.mjs +84 -0
- package/blueprints/observability-essentials/contributions/probes/metrics-endpoint.mjs +96 -0
- package/blueprints/observability-essentials/contributions/probes/probe-utils.mjs +52 -0
- package/blueprints/observability-essentials/contributions/probes/readiness-probe.mjs +171 -0
- package/blueprints/observability-essentials/contributions/probes/run-liveness-probe.mjs +3 -0
- package/blueprints/observability-essentials/contributions/probes/run-metrics-endpoint.mjs +3 -0
- package/blueprints/observability-essentials/contributions/probes/run-readiness-probe.mjs +3 -0
- package/blueprints/observability-essentials/docs/topics.md +2 -3
- package/blueprints/observability-logging/CHANGELOG.md +29 -4
- package/blueprints/observability-logging/README.md +2 -2
- package/blueprints/observability-logging/blueprint.json +3 -2
- package/blueprints/observability-logging/contributions/probes/correlation-id-flow.mjs +173 -0
- package/blueprints/observability-logging/contributions/probes/line-shape-and-fields.mjs +82 -0
- package/blueprints/observability-logging/contributions/probes/probe-utils.mjs +47 -0
- package/blueprints/observability-logging/contributions/probes/redaction-boundary.mjs +130 -0
- package/blueprints/observability-logging/contributions/probes/run-correlation-id-flow.mjs +3 -0
- package/blueprints/observability-logging/contributions/probes/run-line-shape-and-fields.mjs +3 -0
- package/blueprints/observability-logging/contributions/probes/run-redaction-boundary.mjs +3 -0
- package/blueprints/observability-probe-endpoints/CHANGELOG.md +23 -8
- package/blueprints/observability-probe-endpoints/README.md +3 -3
- package/blueprints/observability-probe-endpoints/blueprint.json +3 -2
- package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs +80 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/partial-profile-refusal.mjs +101 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/probe-utils.mjs +49 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/profile-boot-materialisation.mjs +69 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-kubernetes-startup-enabled.mjs +3 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-partial-profile-refusal.mjs +3 -0
- package/blueprints/observability-probe-endpoints/contributions/probes/run-profile-boot-materialisation.mjs +3 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
- package/blueprints/persistence-data-d1/CHANGELOG.md +16 -3
- package/blueprints/persistence-data-d1/README.md +2 -2
- package/blueprints/persistence-data-d1/blueprint.json +3 -2
- package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +1 -1
- package/blueprints/persistence-data-d1/contributions/probes/facade-round-trip.mjs +140 -0
- package/blueprints/persistence-data-d1/contributions/probes/migrations-forward-only.mjs +66 -0
- package/blueprints/persistence-data-d1/contributions/probes/probe-utils.mjs +51 -0
- package/blueprints/persistence-data-d1/contributions/probes/real-account-d1-round-trip.mjs +133 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-facade-round-trip.mjs +3 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-migrations-forward-only.mjs +3 -0
- package/blueprints/persistence-data-d1/contributions/probes/run-real-account-d1-round-trip.mjs +3 -0
- package/blueprints/persistence-data-d1/docs/topics.md +2 -3
- package/blueprints/persistence-data-postgres/CHANGELOG.md +84 -4
- package/blueprints/persistence-data-postgres/README.md +2 -2
- package/blueprints/persistence-data-postgres/blueprint.json +3 -2
- package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
- package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +87 -12
- package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +245 -19
- package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +109 -26
- package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +151 -38
- package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +24 -6
- package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +261 -48
- package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +76 -20
- package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +1 -1
- package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
- package/blueprints/persistence-data-sqlite/CHANGELOG.md +16 -2
- package/blueprints/persistence-data-sqlite/README.md +2 -2
- package/blueprints/persistence-data-sqlite/blueprint.json +3 -2
- package/blueprints/persistence-data-sqlite/contributions/probes/boot-open-migrate.mjs +90 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/facade-round-trip.mjs +82 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/probe-utils.mjs +83 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-boot-open-migrate.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-facade-round-trip.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/run-wal-checkpoint.mjs +5 -0
- package/blueprints/persistence-data-sqlite/contributions/probes/wal-checkpoint.mjs +137 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
- package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +5 -5
- package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
- package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +1 -1
- package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +6 -10
- package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +1 -1
- package/blueprints/platform-cloudflare-kv/CHANGELOG.md +16 -12
- package/blueprints/platform-cloudflare-kv/README.md +2 -4
- package/blueprints/platform-cloudflare-kv/blueprint.json +2 -2
- package/blueprints/platform-cloudflare-kv/docs/topics.md +1 -1
- package/blueprints/platform-docker-compose-host/CHANGELOG.md +92 -5
- package/blueprints/platform-docker-compose-host/blueprint.json +2 -2
- package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +116 -29
- package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +181 -109
- package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +146 -26
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +238 -24
- package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +207 -21
- package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +246 -42
- package/blueprints/platform-docker-compose-host/docs/topics.md +1 -1
- package/blueprints/security-auth-clerk/CHANGELOG.md +18 -6
- package/blueprints/security-auth-clerk/README.md +3 -3
- package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
- package/blueprints/security-auth-clerk/blueprint.json +3 -2
- package/blueprints/security-auth-clerk/contributions/probes/hosted-identity-ui-config.mjs +61 -0
- package/blueprints/security-auth-clerk/contributions/probes/probe-utils.mjs +188 -0
- package/blueprints/security-auth-clerk/contributions/probes/real-account-principal-directory-round-trip.mjs +216 -0
- package/blueprints/security-auth-clerk/contributions/probes/real-account-session-inventory.mjs +260 -0
- package/blueprints/security-auth-clerk/contributions/probes/role-model-adapter.mjs +53 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-hosted-identity-ui-config.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-real-account-principal-directory-round-trip.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-real-account-session-inventory.mjs +4 -0
- package/blueprints/security-auth-clerk/contributions/probes/run-role-model-adapter.mjs +4 -0
- package/blueprints/security-auth-clerk/docs/topics.md +2 -3
- package/blueprints/security-auth-keycloak/CHANGELOG.md +18 -7
- package/blueprints/security-auth-keycloak/README.md +2 -2
- package/blueprints/security-auth-keycloak/blueprint.json +3 -2
- package/blueprints/security-auth-keycloak/contributions/probes/discovery-shape.mjs +68 -0
- package/blueprints/security-auth-keycloak/contributions/probes/introspection-shape.mjs +88 -0
- package/blueprints/security-auth-keycloak/contributions/probes/jwt-verifier-shape.mjs +86 -0
- package/blueprints/security-auth-keycloak/contributions/probes/probe-utils.mjs +180 -0
- package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs +91 -0
- package/blueprints/security-auth-keycloak/contributions/probes/role-adapter-shape.mjs +69 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-discovery-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-introspection-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-jwt-verifier-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs +4 -0
- package/blueprints/security-auth-keycloak/contributions/probes/run-role-adapter-shape.mjs +4 -0
- package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
- package/blueprints/security-auth-magic-link/CHANGELOG.md +15 -4
- package/blueprints/security-auth-magic-link/README.md +2 -2
- package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +1 -1
- package/blueprints/security-auth-magic-link/blueprint.json +3 -2
- package/blueprints/security-auth-magic-link/contributions/probes/probe-utils.mjs +174 -0
- package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs +139 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-real-account-magic-link-send.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-token-entropy-shape.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/run-token-issue-verify.mjs +4 -0
- package/blueprints/security-auth-magic-link/contributions/probes/token-entropy-shape.mjs +60 -0
- package/blueprints/security-auth-magic-link/contributions/probes/token-issue-verify.mjs +90 -0
- package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
- package/blueprints/security-auth-oauth2/CHANGELOG.md +16 -5
- package/blueprints/security-auth-oauth2/README.md +2 -2
- package/blueprints/security-auth-oauth2/blueprint.json +3 -2
- package/blueprints/security-auth-oauth2/contributions/probes/authorisation-code-flow-shape.mjs +259 -0
- package/blueprints/security-auth-oauth2/contributions/probes/pkce-challenge-shape.mjs +58 -0
- package/blueprints/security-auth-oauth2/contributions/probes/probe-utils.mjs +190 -0
- package/blueprints/security-auth-oauth2/contributions/probes/provider-adapter-shape.mjs +64 -0
- package/blueprints/security-auth-oauth2/contributions/probes/real-account-authorisation-code-flow.mjs +93 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-authorisation-code-flow-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-pkce-challenge-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-provider-adapter-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-real-account-authorisation-code-flow.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/run-session-bridge-shape.mjs +4 -0
- package/blueprints/security-auth-oauth2/contributions/probes/session-bridge-shape.mjs +78 -0
- package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
- package/blueprints/security-secrets-management/CHANGELOG.md +15 -4
- package/blueprints/security-secrets-management/README.md +2 -2
- package/blueprints/security-secrets-management/blueprint.json +3 -2
- package/blueprints/security-secrets-management/contributions/probes/add-recipient-rotation.mjs +107 -0
- package/blueprints/security-secrets-management/contributions/probes/encrypt-decrypt-round-trip.mjs +122 -0
- package/blueprints/security-secrets-management/contributions/probes/key-rotation.mjs +93 -0
- package/blueprints/security-secrets-management/contributions/probes/mismatched-key-refusal.mjs +74 -0
- package/blueprints/security-secrets-management/contributions/probes/probe-utils.mjs +214 -0
- package/blueprints/security-secrets-management/contributions/probes/run-add-recipient-rotation.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-encrypt-decrypt-round-trip.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-key-rotation.mjs +4 -0
- package/blueprints/security-secrets-management/contributions/probes/run-mismatched-key-refusal.mjs +4 -0
- package/blueprints/security-secrets-management/docs/topics.md +2 -3
- package/fixtures/canary-manifest.json +9 -9
- package/guidance/harness-template.md +25 -0
- package/guidance/managed/agent-instructions-block.hash +1 -1
- package/guidance/managed/agent-instructions-block.md +25 -0
- package/package.json +2 -2
- package/rcf/adrs/adr-4101-feedback-store-gitignored.json +20 -0
- package/rcf/adrs/adr-4102-fingerprint-and-labels.json +25 -0
- package/rcf/adrs/adr-4103-redaction-rule-based.json +20 -0
- package/rcf/adrs/adr-4104-destination-on-library.json +25 -0
- package/rcf/adrs/adr-4105-gh-ambient-auth.json +20 -0
- package/rcf/adrs/adr-4106-bundled-entries-terminal.json +20 -0
- package/rcf/adrs/adr-4107-stop-is-ask-event.json +30 -0
- package/rcf/adrs/adr-4108-hooks-in-committed-config.json +25 -0
- package/rcf/adrs/adr-4109-referee-validate-adr-crosslinks.json +25 -0
- package/rcf/adrs/adr-4110-referee-coverage-strict-by-default.json +25 -0
- package/rcf/adrs/adr-4111-referee-finalise-refusals.json +20 -0
- package/rcf/adrs/adr-4112-referee-finalise-verified-invariant.json +30 -0
- package/rcf/code-nodes/cn-600.json +45 -0
- package/rcf/code-nodes/cn-601.json +18 -0
- package/rcf/code-nodes/cn-602.json +15 -0
- package/rcf/code-nodes/cn-603.json +12 -0
- package/rcf/code-nodes/cn-604.json +14 -0
- package/rcf/code-nodes/cn-605.json +17 -0
- package/rcf/code-nodes/cn-606.json +12 -0
- package/rcf/code-nodes/cn-607.json +12 -0
- package/rcf/code-nodes/cn-608.json +14 -0
- package/rcf/code-nodes/cn-609.json +17 -0
- package/rcf/code-nodes/cn-620.json +18 -0
- package/rcf/code-nodes/cn-621.json +14 -0
- package/rcf/code-nodes/cn-622.json +15 -0
- package/rcf/code-nodes/cn-623.json +16 -0
- package/rcf/code-nodes/cn-624.json +14 -0
- package/rcf/code-nodes/cn-625.json +15 -0
- package/rcf/code-nodes/cn-626.json +13 -0
- package/rcf/code-nodes/cn-627.json +13 -0
- package/rcf/code-nodes/cn-628.json +14 -0
- package/rcf/code-nodes/cn-629.json +12 -0
- package/rcf/code-nodes/cn-630.json +12 -0
- package/rcf/code-nodes/cn-631.json +13 -0
- package/rcf/code-nodes/cn-632.json +13 -0
- package/rcf/fbs/fbs-180.json +45 -0
- package/rcf/fbs/fbs-181.json +45 -0
- package/rcf/fbs/fbs-182.json +42 -0
- package/rcf/fbs/fbs-183.json +50 -0
- package/rcf/fbs/fbs-184.json +49 -0
- package/rcf/fbs/fbs-185.json +34 -0
- package/rcf/fbs/fbs-186.json +16 -0
- package/rcf/fbs/fbs-187.json +17 -0
- package/rcf/fbs/fbs-188.json +17 -0
- package/rcf/fbs/fbs-189.json +17 -0
- package/rcf/requirements/req-155.json +13 -0
- package/rcf/requirements/req-156.json +13 -0
- package/rcf/requirements/req-157.json +13 -0
- package/rcf/requirements/req-158.json +13 -0
- package/rcf/requirements/req-159.json +13 -0
- package/rcf/requirements/req-160.json +13 -0
- package/rcf/requirements/req-161.json +13 -0
- package/rcf/requirements/req-162.json +13 -0
- package/rcf/requirements/req-163.json +13 -0
- package/rcf/requirements/req-164.json +13 -0
- package/rcf/requirements/req-165.json +13 -0
- package/rcf/tacs/tac-4101-feedback-cli.json +77 -0
- package/rcf/tacs/tac-4102-feedback-store.json +50 -0
- package/rcf/tacs/tac-4103-feedback-redact.json +39 -0
- package/rcf/tacs/tac-4104-feedback-fingerprint.json +33 -0
- package/rcf/tacs/tac-4105-feedback-render.json +45 -0
- package/rcf/tacs/tac-4106-feedback-destination.json +39 -0
- package/rcf/tacs/tac-4107-feedback-gh.json +43 -0
- package/rcf/tacs/tac-4108-feedback-hook.json +46 -0
- package/rcf/tacs/tac-4109-referee-validate-adr-crosslinks.json +20 -0
- package/rcf/tacs/tac-4110-referee-coverage-mode-selector.json +21 -0
- package/rcf/tacs/tac-4111-referee-finalise-per-ac-refusals.json +21 -0
- package/rcf/tacs/tac-4112-referee-finalise-verified-invariant.json +22 -0
- package/rcf/test-suites/ts-140.json +9 -9
- package/rcf/test-suites/ts-150.json +9 -9
- package/rcf/test-suites/ts-185.json +54 -0
- package/rcf/test-suites/ts-186.json +58 -0
- package/rcf/test-suites/ts-187.json +44 -0
- package/rcf/test-suites/ts-188.json +166 -0
- package/rcf/test-suites/ts-189.json +38 -0
- package/rcf/test-suites/ts-190.json +30 -0
- package/rcf/test-suites/ts-191.json +51 -0
- package/rcf/test-suites/ts-192.json +37 -0
- package/rcf/test-suites/ts-193.json +60 -0
- package/rcf/test-suites/ts-194.json +67 -0
- package/rcf/test-suites/ts-195.json +52 -0
- package/rcf/test-suites/ts-196.json +58 -0
- package/rcf/test-suites/ts-197.json +66 -0
- package/rcf/test-suites/ts-198.json +87 -0
- package/rcf/test-suites/ts-199.json +51 -0
- package/rcf/test-suites/ts-200.json +30 -0
- package/rcf/test-suites/ts-201.json +38 -0
- package/rcf/test-suites/ts-202.json +38 -0
- package/rcf/test-suites/ts-203.json +38 -0
- package/rcf/user-stories/us-15501.json +60 -0
- package/rcf/user-stories/us-15502.json +33 -0
- package/rcf/user-stories/us-15503.json +33 -0
- package/rcf/user-stories/us-15601.json +51 -0
- package/rcf/user-stories/us-15701.json +42 -0
- package/rcf/user-stories/us-15801.json +42 -0
- package/rcf/user-stories/us-15802.json +33 -0
- package/rcf/user-stories/us-15901.json +33 -0
- package/rcf/user-stories/us-15902.json +51 -0
- package/rcf/user-stories/us-16001.json +51 -0
- package/rcf/user-stories/us-16101.json +42 -0
- package/rcf/user-stories/us-16102.json +33 -0
- package/rcf/user-stories/us-16103.json +42 -0
- package/rcf/user-stories/us-16104.json +42 -0
- package/rcf/user-stories/us-16201.json +33 -0
- package/rcf/user-stories/us-16301.json +36 -0
- package/rcf/user-stories/us-16401.json +45 -0
- package/rcf/user-stories/us-16501.json +45 -0
- package/rcf/user-stories/us-16502.json +45 -0
- package/releases/releases.yaml +11 -1
- package/src/blueprint/library-loader.js +48 -0
- package/src/blueprint/library-registry.js +13 -0
- package/src/browser-verify/pack-runner.js +7 -12
- package/src/build/mark.js +1 -1
- package/src/cli/blueprint-library.js +149 -0
- package/src/cli/coverage.js +49 -24
- package/src/cli/doctor.js +195 -7
- package/src/cli/feedback.js +2204 -0
- package/src/cli/finalise.js +158 -1
- package/src/cli/help.js +6 -0
- package/src/cli/init.js +63 -0
- package/src/cli/update.js +21 -1
- package/src/core/store/walker.js +33 -0
- package/src/core/store/writer.js +23 -0
- package/src/feedback/destination.js +361 -0
- package/src/feedback/fingerprint.js +132 -0
- package/src/feedback/gh.js +376 -0
- package/src/feedback/hook.js +183 -0
- package/src/feedback/labels.js +87 -0
- package/src/feedback/redact-allowlist.json +14 -0
- package/src/feedback/redact.js +1108 -0
- package/src/feedback/render.js +267 -0
- package/src/feedback/store.js +604 -0
- package/src/finalise/index.js +4 -0
- package/src/finalise/ingest.js +61 -0
- package/src/finalise/ship-without-eval.js +19 -7
- package/src/mcp/tools.js +8 -2
- package/src/setup/feedback-hooks.js +397 -0
- package/src/setup/managed-gitignore.js +3 -0
- package/src/view/html-page.js +5 -5
- package/src/view/style.css +2 -2
package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// Real-account Keycloak realm round-trip for security-auth-
|
|
2
|
+
// keycloak. This estate does not expose a live Keycloak realm to
|
|
3
|
+
// the probe pack. When the gate variable CI_HAS_KEYCLOAK_ACCOUNT is
|
|
4
|
+
// unset the probe honest-skips per rule 7d naming that variable;
|
|
5
|
+
// when every gate and second-tier variable is set the credential-
|
|
6
|
+
// present branch returns a FAIL row with a NOT IMPLEMENTED detail
|
|
7
|
+
// (no live round-trip has been authored) rather than silently
|
|
8
|
+
// passing. The live branch is intended to discover the realm's
|
|
9
|
+
// OIDC document, obtain an admin token via client credentials,
|
|
10
|
+
// create a scratch user, read it back, and delete it, capturing
|
|
11
|
+
// the Keycloak-assigned user id and every response's HTTP status
|
|
12
|
+
// for evidence. It will be authored when an estate-owned realm is
|
|
13
|
+
// wired to CI. The slug reads AMBER on criterion e until that
|
|
14
|
+
// happens.
|
|
15
|
+
//
|
|
16
|
+
// capability: principalDirectory + sessionInventory (composite).
|
|
17
|
+
// Anchor: AC-11112-2 (live cloud-hosted-realm smoke
|
|
18
|
+
// completes a full authorisation-code + PKCE round-trip and
|
|
19
|
+
// issues a project session whose Principal carries the
|
|
20
|
+
// deployment's realm slug).
|
|
21
|
+
// accountBound: true.
|
|
22
|
+
|
|
23
|
+
import { DECLARED_ENV, accountBoundSkippedResult } from './probe-utils.mjs';
|
|
24
|
+
|
|
25
|
+
export const anchorAcId = 'security-auth-keycloak-AC-11112-2';
|
|
26
|
+
export const capability = 'principalDirectory';
|
|
27
|
+
export const accountBound = true;
|
|
28
|
+
|
|
29
|
+
const SECOND_TIER_VARS = ['KEYCLOAK_BASE_URL', 'KEYCLOAK_REALM', 'KEYCLOAK_ADMIN_CLIENT_ID', 'KEYCLOAK_ADMIN_CLIENT_SECRET'];
|
|
30
|
+
|
|
31
|
+
function gateResult(varName, value) {
|
|
32
|
+
if (value === undefined || value === '') return { kind: 'unset', reason: varName };
|
|
33
|
+
if (value !== 'true') return { kind: 'set-not-true', reason: `${varName}_SET_NOT_TRUE`, observedValue: value };
|
|
34
|
+
return { kind: 'true' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default async function runProbe() {
|
|
38
|
+
const gate = gateResult('CI_HAS_KEYCLOAK_ACCOUNT', process.env.CI_HAS_KEYCLOAK_ACCOUNT);
|
|
39
|
+
if (gate.kind === 'unset') {
|
|
40
|
+
return {
|
|
41
|
+
results: [accountBoundSkippedResult(anchorAcId, capability, 'CI_HAS_KEYCLOAK_ACCOUNT')],
|
|
42
|
+
extra: {
|
|
43
|
+
accountBoundSkipped: true,
|
|
44
|
+
reason: 'CI_HAS_KEYCLOAK_ACCOUNT',
|
|
45
|
+
envDeclared: [...DECLARED_ENV],
|
|
46
|
+
note: 'No live Keycloak client is available in this estate; no live realm is exposed to shelf probes. Local RFC 7662 introspection shape, RS256 verifier shape and role-adapter shape are proven by the local probes in this pack.',
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (gate.kind === 'set-not-true') {
|
|
51
|
+
return {
|
|
52
|
+
results: [{
|
|
53
|
+
anchorAcId, capability, verdict: 'fail',
|
|
54
|
+
detail: `AC-11112-2: CI_HAS_KEYCLOAK_ACCOUNT is set to "${gate.observedValue}" (not the string "true"). Gate refuses this shape; set the variable to the exact string "true" to run the live branch.`,
|
|
55
|
+
evidence: { gate: 'CI_HAS_KEYCLOAK_ACCOUNT', observedValue: gate.observedValue, expected: 'true' },
|
|
56
|
+
}],
|
|
57
|
+
extra: { gateMisconfigured: true, gate: 'CI_HAS_KEYCLOAK_ACCOUNT', envDeclared: [...DECLARED_ENV] },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// One result row per unset second-tier variable per rule 4.
|
|
62
|
+
const unsetRows = [];
|
|
63
|
+
for (const v of SECOND_TIER_VARS) {
|
|
64
|
+
if (!process.env[v]) {
|
|
65
|
+
unsetRows.push({
|
|
66
|
+
anchorAcId, capability, verdict: 'pass', accountBoundSkipped: true, reason: v,
|
|
67
|
+
detail: `accountBoundSkipped: ${v} unset. AC-11112-2 requires a live realm; set ${v} to run the live branch.`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (unsetRows.length > 0) {
|
|
72
|
+
return {
|
|
73
|
+
results: unsetRows,
|
|
74
|
+
extra: { accountBoundSkipped: true, unsetVars: unsetRows.map((r) => r.reason), envDeclared: [...DECLARED_ENV] },
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// All credentials present but the live branch is not implemented
|
|
79
|
+
// in this estate. FAIL explicitly (never a misleading pass).
|
|
80
|
+
return {
|
|
81
|
+
results: [{
|
|
82
|
+
anchorAcId, capability, verdict: 'fail',
|
|
83
|
+
detail: 'AC-11112-2 live branch is NOT IMPLEMENTED. Every gate variable is set, but the estate has no wired live Keycloak realm and no round-trip code has been authored. Supplying credentials does not silently pass; the branch must be implemented before this result flips to pass. Local shape evidence is proven by the local probes in this pack; the live branch remains AMBER until an estate-owned realm is wired.',
|
|
84
|
+
}],
|
|
85
|
+
extra: {
|
|
86
|
+
envDeclared: [...DECLARED_ENV],
|
|
87
|
+
liveBranchImplemented: false,
|
|
88
|
+
note: 'implement admin-client credentials round-trip against KEYCLOAK_BASE_URL/KEYCLOAK_REALM/KEYCLOAK_ADMIN_CLIENT_ID/KEYCLOAK_ADMIN_CLIENT_SECRET here when the estate exposes a realm',
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Keycloak role-adapter shape probe. Conformance-only. Every row
|
|
2
|
+
// records anchorAcId=null with a limitation naming the shipped AC
|
|
3
|
+
// whose verified-session behaviour the raw-claim fixture-adapter
|
|
4
|
+
// observation does not exercise. The integration harness follow-up
|
|
5
|
+
// is the surface where the AC-level properties become observable.
|
|
6
|
+
//
|
|
7
|
+
// capability: roleModel. engine: fixture. accountBound: false.
|
|
8
|
+
|
|
9
|
+
import { pathToFileURL } from 'node:url';
|
|
10
|
+
import { resolve, dirname } from 'node:path';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { deClaim } from './probe-utils.mjs';
|
|
13
|
+
|
|
14
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-keycloak', 'src');
|
|
16
|
+
|
|
17
|
+
export const anchorAcId = null;
|
|
18
|
+
export const capability = 'roleModel';
|
|
19
|
+
export const accountBound = false;
|
|
20
|
+
|
|
21
|
+
const LIM_CLIENT = 'security-auth-keycloak-AC-11107-1: probe receives a raw claim object, not a verified access token; the AC requires the client-roles path from a verified session, needs the integration harness (the auth integration harness follow-up).';
|
|
22
|
+
const LIM_ABSENT = 'security-auth-keycloak-AC-11107-2: probe receives an empty raw claim object; the AC requires absent-claim behaviour on a verified session, needs the integration harness (the auth integration harness follow-up).';
|
|
23
|
+
const LIM_MALFORMED = 'security-auth-keycloak-AC-11107-3: probe receives a raw claim object; the AC requires the malformed-claim refusal path on a verified session, needs the integration harness (the auth integration harness follow-up).';
|
|
24
|
+
const LIM_REQ006 = 'security-auth-keycloak-AC-11107-3: probe observes an unknown-role refusal at the fixture adapter; the AC states a verified token whose expected claim path is present but not an array of strings is refused with KEYCLOAK_ROLES_MALFORMED, which requires observing the deployed adapter through the integration harness follow-up.';
|
|
25
|
+
|
|
26
|
+
export default async function runProbe() {
|
|
27
|
+
const { mapKeycloakRoles, knownRoles } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'role-adapter.mjs')).href);
|
|
28
|
+
const results = [];
|
|
29
|
+
|
|
30
|
+
const clientOnly = mapKeycloakRoles({
|
|
31
|
+
resource_access: { 'app-x': { roles: ['editor', 'admin'] } },
|
|
32
|
+
}, { clientId: 'app-x', roleClaimShape: 'client-roles' });
|
|
33
|
+
results.push(deClaim({
|
|
34
|
+
capability,
|
|
35
|
+
verdict: clientOnly.ok && JSON.stringify(clientOnly.roles) === JSON.stringify(['editor', 'admin']) && clientOnly.source && clientOnly.source.client === 2 && (clientOnly.source.realm ?? 0) === 0 ? 'pass' : 'fail',
|
|
36
|
+
detail: `client-roles claim path lifts resource_access.<clientId>.roles: ok=${clientOnly.ok} roles=${JSON.stringify(clientOnly.roles)} source=${JSON.stringify(clientOnly.source)}`,
|
|
37
|
+
evidence: { adapterReturn: clientOnly, knownRoles },
|
|
38
|
+
}, { ac: 'security-auth-keycloak-AC-11107-1', limitation: LIM_CLIENT }));
|
|
39
|
+
|
|
40
|
+
const absentPath = mapKeycloakRoles({}, { clientId: 'app-x', roleClaimShape: 'client-roles' });
|
|
41
|
+
results.push(deClaim({
|
|
42
|
+
capability,
|
|
43
|
+
verdict: absentPath.ok && Array.isArray(absentPath.roles) && absentPath.roles.length === 0 ? 'pass' : 'fail',
|
|
44
|
+
detail: `absent-claim yields empty roles: ok=${absentPath.ok} roles=${JSON.stringify(absentPath.roles)}`,
|
|
45
|
+
evidence: { adapterReturn: absentPath },
|
|
46
|
+
}, { ac: 'security-auth-keycloak-AC-11107-2', limitation: LIM_ABSENT }));
|
|
47
|
+
|
|
48
|
+
const nonArray = mapKeycloakRoles({
|
|
49
|
+
resource_access: { 'app-x': { roles: 'admin' } },
|
|
50
|
+
}, { clientId: 'app-x', roleClaimShape: 'client-roles' });
|
|
51
|
+
results.push(deClaim({
|
|
52
|
+
capability,
|
|
53
|
+
verdict: !nonArray.ok && /KEYCLOAK_ROLES_MALFORMED|must be an array/i.test(nonArray.error) ? 'pass' : 'fail',
|
|
54
|
+
detail: `non-array claim refused: ok=${nonArray.ok} error=${JSON.stringify(nonArray.error)}`,
|
|
55
|
+
evidence: { adapterReturn: nonArray },
|
|
56
|
+
}, { ac: 'security-auth-keycloak-AC-11107-3', limitation: LIM_MALFORMED }));
|
|
57
|
+
|
|
58
|
+
const unknown = mapKeycloakRoles({
|
|
59
|
+
resource_access: { 'app-x': { roles: ['viewer', 'root-emperor'] } },
|
|
60
|
+
}, { clientId: 'app-x', roleClaimShape: 'client-roles' });
|
|
61
|
+
results.push(deClaim({
|
|
62
|
+
capability,
|
|
63
|
+
verdict: !unknown.ok && /root-emperor/.test(unknown.error) ? 'pass' : 'fail',
|
|
64
|
+
detail: `unknown-role refusal (fixture adapter): ok=${unknown.ok} error=${JSON.stringify(unknown.error)}`,
|
|
65
|
+
evidence: { adapterReturn: unknown },
|
|
66
|
+
}, { ac: 'security-auth-keycloak-AC-11107-3', limitation: LIM_REQ006 }));
|
|
67
|
+
|
|
68
|
+
return { results, extra: {} };
|
|
69
|
+
}
|
package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import runProbe from './real-account-realm-round-trip.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
const engine = { kind: 'keycloak' /* live-realm branch is honest-skip; slug AMBER */, image: 'estate-owned Keycloak realm (or skipped)', healthy: true };
|
|
4
|
+
runShim('real-account-realm-round-trip', engine, runProbe);
|
|
@@ -70,8 +70,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
70
70
|
| platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
|
|
71
71
|
| edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
|
|
72
72
|
|
|
73
|
-
US 11101-11113 sit at the LOW end of the 11101-11899 band on purpose. A project-side story that mechanically derives from a security-auth-keycloak REQ id into the number `11113` would collide against security-auth-keycloak-US-11113 in this package; the band leaves headroom at the HIGH end (US 11181-11899) so a project's own stories anchored to security-auth-keycloak REQs can allocate without conflict.
|
|
74
|
-
|
|
73
|
+
US 11101-11113 sit at the LOW end of the 11101-11899 band on purpose. A project-side story that mechanically derives from a security-auth-keycloak REQ id into the number `11113` would collide against security-auth-keycloak-US-11113 in this package; the band leaves headroom at the HIGH end (US 11181-11899) so a project's own stories anchored to security-auth-keycloak REQs can allocate without conflict.
|
|
75
74
|
The ADR/TAC suffix block 1201-1299 is the third block in the four-digit suffix space; `security-auth-clerk` opened the door at 1001-1099 and `security-auth-oauth2` took 1101-1199. Every shipped blueprint continues to load, validate, and audit against this shape without a schema change: rcf-schemas 0.5.0 `adrId` and `tacId` patterns are `^ADR-\d{3,}(-[a-z0-9]+...)?$` (three-digit minimum, unbounded above); four-digit and higher suffixes validate verbatim. The registry table above records the growth for a downstream author reaching for the next block.
|
|
76
75
|
|
|
77
76
|
## Provider-aware install-design shape (plain language, no named second issuer)
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
# security-auth-magic-link CHANGELOG
|
|
2
2
|
|
|
3
|
-
## 1.2.
|
|
3
|
+
## 1.2.7 - 2026-09-11
|
|
4
|
+
|
|
5
|
+
- Criterion-e probe pack refinement: every conformance-only result row now records `anchorAcId: null` alongside a `limitation` that opens with a shipped AC id from the blueprint's user stories (token-entropy rows and the fixture manager rows move from `REQ-002` to `AC-3102-1` / `AC-3102-2` / `AC-3102-3`; the live `real-account-magic-link-send` row remains under `AC-3110-1` as its limitation citation). Detail strings on de-claimed rows describe only what was observed at the surface the probe drove (Resend adapter return for the live probe; fixture manager return for the local probes) and no longer describe `AC-3110-1` as exercised end to end. Probe source header on `real-account-magic-link-send` matches the de-claim comment (no "exercises AC-3110-1 end-to-end" wording). `token-issue-verify` header comment matches its implementation (every row de-claims, including AC-3102-3). The magic-link fixture README now records the entropy sample count as 1,000 tokens (matching the probe implementation and the run record). The anatomy helper enforces conformance-only rows to satisfy `anchorAcId === null`, requires limitations to open with an `AC-<n>-<n>` id that resolves to a shipped acceptance criterion on the blueprint's user stories (REQ-prefixed anchors are refused and fabricated ids are rejected), and does not count pre-delete presence as an absence observation on the inventory-diff shape.
|
|
6
|
+
|
|
7
|
+
## 1.2.6 - 2026-09-11
|
|
8
|
+
|
|
9
|
+
- Every conformance-only anchor on the criterion-e probe pack is de-claimed to `conformanceOnly` with a limitation naming the shipped AC that is observable only in the integration harness follow-up. The Resend adapter now returns `error: null` on success so the four declared keys (ok, providerStatus, providerMessageId, error) are always present, and the probe now requires all four (the previous check allowed missing `error`). Live evidence on `real-account-magic-link-send` (Resend HTTP send through the adapter) is preserved; anchor drops to null and the limitation says why.
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
## 1.2.5 - 2026-09-11
|
|
12
|
+
|
|
13
|
+
- Added a criterion-e probe pack (`contributions/probes/`) covering the principalDirectory capability across three probes: `token-issue-verify` (single-use, TTL-bounded, email-bound token with constant-time compare; local, deterministic clock), `token-entropy-shape` (1,000-token uniqueness + base64url shape sweep), and `real-account-magic-link-send` (LIVE; drives Resend's HTTP API sending to sandbox recipient `delivered@resend.dev` from sandbox sender `onboarding@resend.dev` and records the Resend-assigned email id, HTTP status and `cf-ray` request id on the adapter return; verifies the issued token locally for end-to-end shape). Fixture at `packages/rcf-lite/test/fixtures/security-auth-magic-link/` declares every env var; anatomy test pins pack shape, fixture manifest and the account-bound skip contract.
|
|
14
|
+
- Iteration on the probe pack routed the outgoing send through a fixture `email-delivery-adapter` whose default binding is Resend, so live evidence carries the provider-assigned message id and the HTTP request id on the adapter's returned shape rather than a direct-vendor call. `aggregate([])` and null-result normalisation now report `detail: 'no checks ran'` exactly. Slug reads AMBER on criterion e.
|
|
15
|
+
|
|
16
|
+
## 1.2.4
|
|
6
17
|
|
|
7
18
|
## 1.2.3
|
|
8
19
|
|
|
@@ -12,9 +23,9 @@
|
|
|
12
23
|
|
|
13
24
|
- Register: neutral wording in shipped prose (no capability change).
|
|
14
25
|
|
|
15
|
-
## 1.2.1 (
|
|
26
|
+
## 1.2.1 (2026-09-09)
|
|
16
27
|
|
|
17
|
-
- Adds `deliveredBy` on every `must` requirement and `disposition: fixed` on every existing acceptance criterion; adds `ownerRef` on ACs that restate the `isRegistered` interface on `TAC-505`. Extends `REQ-003` with the session-lifetime contract (sliding idle window, absolute lifetime, server-side revocation as the only truthful invalidation). Names the `principalDirectory` capability on `REQ-011`, which already carries its runtime clause through the principal-registry contract.
|
|
28
|
+
- Adds `deliveredBy` on every `must` requirement and `disposition: fixed` on every existing acceptance criterion; adds `ownerRef` on ACs that restate the `isRegistered` interface on `TAC-505`. Extends `REQ-003` with the session-lifetime contract (sliding idle window, absolute lifetime, server-side revocation as the only truthful invalidation). Names the `principalDirectory` capability on `REQ-011`, which already carries its runtime clause through the principal-registry contract. No new contributions.
|
|
18
29
|
|
|
19
30
|
## 1.2.0 (visual round, spec 2026-09-06 section 5.4.2, doc-only)
|
|
20
31
|
|
|
@@ -30,9 +30,9 @@ The doc set is contributions (copied into the project tree by `rcf define bluepr
|
|
|
30
30
|
|
|
31
31
|
## What it contributes, and what it deliberately does not
|
|
32
32
|
|
|
33
|
-
Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (
|
|
33
|
+
Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (shipped policy 5) and no code.
|
|
34
34
|
|
|
35
|
-
No FBS contributions, as a matter of principle (
|
|
35
|
+
No FBS contributions, as a matter of principle (policy): FBSs are the work of the implementing agent, not the blueprint; project constraints have to be applied at the time of creation. The blueprint contributes the WHAT (the sign-in flow, the token lifecycle, the session lifecycle, the two pluggable interfaces); the implementing agent derives the HOW-tasks (FBS) in the host project, where the ACs contributed here get picked up by the project's own build sequencing.
|
|
36
36
|
|
|
37
37
|
Deliberately not contributed: authorisation (roles, permissions, tenancy) is a project concern that layers above the session record's principal id, not inside this blueprint; multi-factor authentication is a project concern that layers on top of a resolved session; federated identity (OIDC, SAML) is a future auth-oidc blueprint (see guide 'when it does not fit'); email transport is a project concern behind the pluggable adapter contract; principal registry shape is a project concern behind the pluggable lookup contract.
|
|
38
38
|
|
package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md
CHANGED
|
@@ -32,4 +32,4 @@ The project supplies one field:
|
|
|
32
32
|
|
|
33
33
|
## Why it exists
|
|
34
34
|
|
|
35
|
-
The rcf-lite tier this blueprint targets includes solo-operator projects (
|
|
35
|
+
The rcf-lite tier this blueprint targets includes solo-operator projects (personal dashboards, single-tenant admin surfaces, small internal tools). The single-address registry is the smallest useful implementation and demonstrates the boolean-only shape of the contract; projects that scale past one operator write their own allow-list-file or database-lookup implementation, keeping the same interface.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "security-auth-magic-link",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.7",
|
|
4
4
|
"category": "security",
|
|
5
5
|
"capabilities": [
|
|
6
6
|
"principalDirectory"
|
|
@@ -168,5 +168,6 @@
|
|
|
168
168
|
"kind": "adr",
|
|
169
169
|
"path": "adrs/adr-505-security-auth-magic-link-rate-limiting.json"
|
|
170
170
|
}
|
|
171
|
-
]
|
|
171
|
+
],
|
|
172
|
+
"updatedAt": "2026-09-11T15:37:12.000Z"
|
|
172
173
|
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// Shared helpers for security-auth-magic-link probes.
|
|
2
|
+
//
|
|
3
|
+
// Runtime-dependency posture:
|
|
4
|
+
// - Local probes drive token-issue / token-verify shape on the
|
|
5
|
+
// fixture-owned magic-link manager against a deterministic clock;
|
|
6
|
+
// no network call.
|
|
7
|
+
// - real-account-magic-link-send drives Resend's HTTP API
|
|
8
|
+
// (https://api.resend.com/emails, docs
|
|
9
|
+
// https://resend.com/docs/api-reference/emails/send-email
|
|
10
|
+
// verifiedOn 2026-09-11) with the vendor's documented sandbox
|
|
11
|
+
// sender `onboarding@resend.dev` and sandbox recipient
|
|
12
|
+
// `delivered@resend.dev` (per
|
|
13
|
+
// https://resend.com/docs/dashboard/emails/send-test-emails
|
|
14
|
+
// verifiedOn 2026-09-11), which routes the message to the
|
|
15
|
+
// Resend sandbox rather than a real inbox. The probe records the
|
|
16
|
+
// Resend-assigned email id and the HTTP status as positive
|
|
17
|
+
// evidence per rule 7d. Without CI_HAS_RESEND_ACCOUNT the probe
|
|
18
|
+
// honest-skips naming the missing var.
|
|
19
|
+
|
|
20
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
21
|
+
import { dirname, resolve } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
|
|
26
|
+
export const SLUG = 'security-auth-magic-link';
|
|
27
|
+
export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/security-auth-magic-link');
|
|
28
|
+
export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/security-auth-magic-link');
|
|
29
|
+
|
|
30
|
+
export const DECLARED_ENV = Object.freeze([
|
|
31
|
+
'CI_HAS_RESEND_ACCOUNT',
|
|
32
|
+
'RESEND_API_KEY',
|
|
33
|
+
'RESEND_API_BASE_URL',
|
|
34
|
+
'RESEND_SANDBOX_FROM',
|
|
35
|
+
'RESEND_SANDBOX_TO',
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
export const RESEND_SANDBOX_FROM_DEFAULT = 'onboarding@resend.dev';
|
|
39
|
+
export const RESEND_SANDBOX_TO_DEFAULT = 'delivered@resend.dev';
|
|
40
|
+
export const RESEND_API_BASE_URL_DEFAULT = 'https://api.resend.com';
|
|
41
|
+
|
|
42
|
+
// First-8-words-of-anchor helper. Each result row's `detail` starts
|
|
43
|
+
// with the first eight words of the anchored AC's or REQ's
|
|
44
|
+
// description text. Anchor lookup walks contributions/user-stories/
|
|
45
|
+
// and contributions/requirements/ under the blueprint root and
|
|
46
|
+
// caches the map on first call. Null / unknown / missing anchors
|
|
47
|
+
// yield an empty prefix.
|
|
48
|
+
import { readFileSync as _rf } from 'node:fs';
|
|
49
|
+
import { readdirSync as _rd } from 'node:fs';
|
|
50
|
+
let _anchorMap = null;
|
|
51
|
+
function _loadAnchorMap() {
|
|
52
|
+
const map = new Map();
|
|
53
|
+
const dirs = [
|
|
54
|
+
{ dir: resolve(PROJECT_ROOT, 'blueprints', SLUG, 'contributions', 'user-stories'), kind: 'ac' },
|
|
55
|
+
{ dir: resolve(PROJECT_ROOT, 'blueprints', SLUG, 'contributions', 'requirements'), kind: 'req' },
|
|
56
|
+
];
|
|
57
|
+
for (const { dir, kind } of dirs) {
|
|
58
|
+
let entries;
|
|
59
|
+
try { entries = _rd(dir); } catch { continue; }
|
|
60
|
+
for (const name of entries) {
|
|
61
|
+
if (!name.endsWith('.json')) continue;
|
|
62
|
+
let j;
|
|
63
|
+
try { j = JSON.parse(_rf(resolve(dir, name), 'utf8')); } catch { continue; }
|
|
64
|
+
if (kind === 'ac') {
|
|
65
|
+
const usId = j.usId;
|
|
66
|
+
for (const ac of (j.acceptanceCriteria || [])) {
|
|
67
|
+
// AC id in the shipped JSON is like "AC-9101-1"; the
|
|
68
|
+
// anchor form used by probes is "<slug>-AC-9101-1".
|
|
69
|
+
const key = `${SLUG}-${ac.id}`;
|
|
70
|
+
map.set(key, ac.description || '');
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
const key = j.reqId; // already "<slug>-REQ-###"
|
|
74
|
+
if (key) map.set(key, j.description || j.title || '');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return map;
|
|
79
|
+
}
|
|
80
|
+
export function first8Words(anchor) {
|
|
81
|
+
if (!anchor) return '';
|
|
82
|
+
if (!_anchorMap) _anchorMap = _loadAnchorMap();
|
|
83
|
+
const txt = _anchorMap.get(anchor) || '';
|
|
84
|
+
if (!txt) return '';
|
|
85
|
+
const words = txt.split(/\s+/).filter(Boolean).slice(0, 8).join(' ');
|
|
86
|
+
return words;
|
|
87
|
+
}
|
|
88
|
+
export function withAnchorPrefix(row) {
|
|
89
|
+
const prefix = first8Words(row.anchorAcId);
|
|
90
|
+
if (!prefix) return row;
|
|
91
|
+
const already = typeof row.detail === 'string' && row.detail.startsWith(prefix);
|
|
92
|
+
if (already) return row;
|
|
93
|
+
const oldDetail = row.detail || '';
|
|
94
|
+
return { ...row, detail: `${prefix} :: ${oldDetail}` };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function aggregate(results) {
|
|
98
|
+
if (!Array.isArray(results) || results.length === 0) return 'fail';
|
|
99
|
+
if (results.some((r) => r.verdict === 'fail')) return 'fail';
|
|
100
|
+
if (results.some((r) => r.verdict === 'warn')) return 'warn';
|
|
101
|
+
return 'pass';
|
|
102
|
+
}
|
|
103
|
+
export function isSkipped(results) {
|
|
104
|
+
return results.length > 0 && results.every((r) => r.accountBoundSkipped === true);
|
|
105
|
+
}
|
|
106
|
+
export async function writeReport({ probeName, engine, results, extra }) {
|
|
107
|
+
await mkdir(REPORT_DIR, { recursive: true });
|
|
108
|
+
// Prefix every row's detail with the first eight words of its
|
|
109
|
+
// anchored AC or REQ description; unanchored rows are left alone.
|
|
110
|
+
const prefixedResults = (results || []).map(withAnchorPrefix);
|
|
111
|
+
const raw = aggregate(prefixedResults);
|
|
112
|
+
const aggregateVerdict = isSkipped(prefixedResults) ? 'pass' : raw;
|
|
113
|
+
const report = { slug: 'security-auth-magic-link', probeName, runAt: new Date().toISOString(), engine, results: prefixedResults, aggregateVerdict, ...(extra ?? {}) };
|
|
114
|
+
const path = resolve(REPORT_DIR, `${probeName}.json`);
|
|
115
|
+
await writeFile(path, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
116
|
+
return { report, path };
|
|
117
|
+
}
|
|
118
|
+
export async function runShim(probeName, engine, mainFn) {
|
|
119
|
+
try {
|
|
120
|
+
const outcome = await mainFn();
|
|
121
|
+
if (!outcome || !Array.isArray(outcome.results) || outcome.results.length === 0) {
|
|
122
|
+
const results = [{
|
|
123
|
+
anchorAcId: 'unknown',
|
|
124
|
+
verdict: 'fail',
|
|
125
|
+
detail: 'no checks ran',
|
|
126
|
+
}];
|
|
127
|
+
const { report, path } = await writeReport({ probeName, engine, results });
|
|
128
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
129
|
+
process.stderr.write(`no-checks-ran fail written to ${path}\n`);
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const { results, extra } = outcome;
|
|
134
|
+
const { report, path } = await writeReport({ probeName, engine, results, extra });
|
|
135
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
136
|
+
process.stdout.write(`report written to ${path}\n`);
|
|
137
|
+
if (report.aggregateVerdict === 'fail') process.exitCode = 1;
|
|
138
|
+
} catch (err) {
|
|
139
|
+
const results = [{ anchorAcId: 'unknown', verdict: 'fail', detail: `probe threw: ${err && err.message ? err.message : String(err)}` }];
|
|
140
|
+
const { report, path } = await writeReport({ probeName, engine, results });
|
|
141
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
142
|
+
process.stderr.write(`probe error: ${err && err.stack ? err.stack : String(err)}\n`);
|
|
143
|
+
process.stderr.write(`report written to ${path}\n`);
|
|
144
|
+
process.exitCode = 1;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// De-claim helper. When the shipped AC does not observe what the probe observes, the row keeps its
|
|
148
|
+
// verdict, evidence and engine as they are, but the anchor drops to null and the
|
|
149
|
+
// row carries conformanceOnly:true plus a limitation string naming the AC that
|
|
150
|
+
// this probe does NOT observe and why. The integration-harness follow-up (the auth integration harness follow-up)
|
|
151
|
+
// is the surface where those AC-level properties become observable.
|
|
152
|
+
export function deClaim(row, { ac, limitation }) {
|
|
153
|
+
const acId = ac || 'unknown-AC';
|
|
154
|
+
const limText = (limitation || '').trim();
|
|
155
|
+
const finalLim = /^(security-[a-z0-9-]+-)?(AC|REQ)-/.test(limText) ? limText : (limText ? `${acId}: ${limText}` : `${acId}: not observable at this probe surface; needs the integration harness (the auth integration harness follow-up)`);
|
|
156
|
+
const out = { ...row };
|
|
157
|
+
out.anchorAcId = null;
|
|
158
|
+
if ('anchorReqId' in out) delete out.anchorReqId;
|
|
159
|
+
out.conformanceOnly = true;
|
|
160
|
+
out.limitation = finalLim;
|
|
161
|
+
const tag = ` :: conformance-only (${finalLim})`;
|
|
162
|
+
if (typeof out.detail === 'string' && !out.detail.includes('conformance-only')) {
|
|
163
|
+
out.detail = out.detail + tag;
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function accountBoundSkippedResult(anchorAcId, capability, reason) {
|
|
169
|
+
return {
|
|
170
|
+
anchorAcId, capability, verdict: 'pass',
|
|
171
|
+
accountBoundSkipped: true, reason,
|
|
172
|
+
detail: `accountBoundSkipped: ${reason} unset; probe did not execute against the live Resend API. Set the missing var and re-run.`,
|
|
173
|
+
};
|
|
174
|
+
}
|
package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Real-account magic-link send smoke. Conformance-only. The probe
|
|
2
|
+
// issues a real magic-link token via the fixture manager, hands the
|
|
3
|
+
// resulting message to the fixture's `email-delivery-adapter` whose
|
|
4
|
+
// default binding is Resend, and verifies the issued token locally.
|
|
5
|
+
// The probe observes what the adapter returned and what the fixture
|
|
6
|
+
// manager did; it does not observe the shipped ACs on the project's
|
|
7
|
+
// routes and managers, and the row records that limit alongside the
|
|
8
|
+
// raw adapter evidence it did capture.
|
|
9
|
+
//
|
|
10
|
+
// Positive evidence per rule 7d that is preserved on the row: the
|
|
11
|
+
// Resend-assigned `providerMessageId` returned by the adapter
|
|
12
|
+
// (created-resource id), the adapter's `providerStatus` HTTP code,
|
|
13
|
+
// and the `requestId` header the adapter captures. All three are
|
|
14
|
+
// read off the adapter's return, not off a direct vendor call.
|
|
15
|
+
//
|
|
16
|
+
// capability: principalDirectory.
|
|
17
|
+
// engine: resend (live) or skip:CI_HAS_RESEND_ACCOUNT.
|
|
18
|
+
// accountBound: true.
|
|
19
|
+
|
|
20
|
+
import { pathToFileURL } from 'node:url';
|
|
21
|
+
import { resolve, dirname } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import {
|
|
24
|
+
DECLARED_ENV, accountBoundSkippedResult,
|
|
25
|
+
RESEND_SANDBOX_FROM_DEFAULT, RESEND_SANDBOX_TO_DEFAULT, RESEND_API_BASE_URL_DEFAULT,
|
|
26
|
+
} from './probe-utils.mjs';
|
|
27
|
+
|
|
28
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-magic-link', 'src');
|
|
30
|
+
|
|
31
|
+
export const anchorAcId = null;
|
|
32
|
+
export const capability = 'principalDirectory';
|
|
33
|
+
export const accountBound = true;
|
|
34
|
+
// AC-3110-1 binds the routes-and-managers side of the
|
|
35
|
+
// email-delivery-adapter contract: only the declared send method,
|
|
36
|
+
// only the declared arguments, only the declared fields consumed.
|
|
37
|
+
// This probe drives the adapter directly from a probe process, so
|
|
38
|
+
// it cannot observe the routes-and-managers property; the row
|
|
39
|
+
// records that limit next to the adapter-return evidence it did
|
|
40
|
+
// capture.
|
|
41
|
+
const DECLAIM_LIMITATION = 'security-auth-magic-link-AC-3110-1: probe drives the email-delivery-adapter directly from a probe process; the AC states the project routes and managers invoke only the declared adapter method with only the declared arguments and consume only the declared fields, which requires observing the deployed runtime through the integration harness follow-up.';
|
|
42
|
+
|
|
43
|
+
function gateResult(varName, value) {
|
|
44
|
+
if (value === undefined || value === '') return { kind: 'unset', reason: varName };
|
|
45
|
+
if (value !== 'true') return { kind: 'set-not-true', reason: `${varName}_SET_NOT_TRUE`, observedValue: value };
|
|
46
|
+
return { kind: 'true' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default async function runProbe() {
|
|
50
|
+
const gate = gateResult('CI_HAS_RESEND_ACCOUNT', process.env.CI_HAS_RESEND_ACCOUNT);
|
|
51
|
+
if (gate.kind === 'unset') {
|
|
52
|
+
return {
|
|
53
|
+
results: [accountBoundSkippedResult(null, capability, 'CI_HAS_RESEND_ACCOUNT')],
|
|
54
|
+
extra: { accountBoundSkipped: true, reason: 'CI_HAS_RESEND_ACCOUNT', envDeclared: [...DECLARED_ENV] },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (gate.kind === 'set-not-true') {
|
|
58
|
+
return {
|
|
59
|
+
results: [{
|
|
60
|
+
anchorAcId: null, capability, verdict: 'fail',
|
|
61
|
+
conformanceOnly: true, limitation: DECLAIM_LIMITATION,
|
|
62
|
+
detail: `conformance-only gate: CI_HAS_RESEND_ACCOUNT is set to "${gate.observedValue}" (not the string "true"). Gate refuses this shape; set the variable to the exact string "true" to run the live branch.`,
|
|
63
|
+
evidence: { gate: 'CI_HAS_RESEND_ACCOUNT', observedValue: gate.observedValue, expected: 'true' },
|
|
64
|
+
}],
|
|
65
|
+
extra: { gateMisconfigured: true, gate: 'CI_HAS_RESEND_ACCOUNT', envDeclared: [...DECLARED_ENV] },
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (!process.env.RESEND_API_KEY) {
|
|
69
|
+
return {
|
|
70
|
+
results: [accountBoundSkippedResult(null, capability, 'RESEND_API_KEY')],
|
|
71
|
+
extra: { accountBoundSkipped: true, reason: 'RESEND_API_KEY', envDeclared: [...DECLARED_ENV] },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const baseUrl = process.env.RESEND_API_BASE_URL || RESEND_API_BASE_URL_DEFAULT;
|
|
76
|
+
const from = process.env.RESEND_SANDBOX_FROM || RESEND_SANDBOX_FROM_DEFAULT;
|
|
77
|
+
const to = process.env.RESEND_SANDBOX_TO || RESEND_SANDBOX_TO_DEFAULT;
|
|
78
|
+
|
|
79
|
+
const evidence = { envDeclared: [...DECLARED_ENV], baseUrl, from, to };
|
|
80
|
+
const resultRow = { anchorAcId: null, conformanceOnly: true, limitation: DECLAIM_LIMITATION, capability, verdict: 'fail', detail: '', evidence: {} };
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const { createMagicLinkManager } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'magic-link-manager.mjs')).href);
|
|
84
|
+
const { createResendAdapter } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'email-delivery-adapter.mjs')).href);
|
|
85
|
+
|
|
86
|
+
const mgr = createMagicLinkManager({ ttlSeconds: 900 });
|
|
87
|
+
const issued = await mgr.issue({ emailAddress: to });
|
|
88
|
+
const magicLink = `https://app.example.com/auth/magic?token=${encodeURIComponent(issued.token)}`;
|
|
89
|
+
|
|
90
|
+
const adapter = createResendAdapter({ apiKey: process.env.RESEND_API_KEY, baseUrl, from });
|
|
91
|
+
const outcome = await adapter.send({
|
|
92
|
+
to,
|
|
93
|
+
subject: 'Sign-in link',
|
|
94
|
+
textBody: `Sign in to your account by opening this magic link: ${magicLink}\n\nIf you did not request this, ignore this email.`,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const verified = await mgr.verify({ token: issued.token, emailAddress: to });
|
|
98
|
+
|
|
99
|
+
const declaredKeys = ['ok', 'providerStatus', 'providerMessageId', 'error'];
|
|
100
|
+
const outcomeKeys = Object.keys(outcome).sort();
|
|
101
|
+
const extraKeys = outcomeKeys.filter((k) => !declaredKeys.includes(k));
|
|
102
|
+
const missingKeys = declaredKeys.filter((k) => !(k in outcome));
|
|
103
|
+
const shapeOk = extraKeys.every((k) => k === 'requestId') && missingKeys.length === 0;
|
|
104
|
+
const adapterOk = outcome && outcome.ok === true && typeof outcome.providerMessageId === 'string' && outcome.providerMessageId.length > 0 && typeof outcome.providerStatus === 'number';
|
|
105
|
+
const verifyOk = verified.ok;
|
|
106
|
+
|
|
107
|
+
if (adapterOk && shapeOk && verifyOk) {
|
|
108
|
+
resultRow.verdict = 'pass';
|
|
109
|
+
resultRow.detail =
|
|
110
|
+
`Resend adapter return observed at the probe boundary: ` +
|
|
111
|
+
`outcome.ok=true providerMessageId=${outcome.providerMessageId} providerStatus=${outcome.providerStatus} ` +
|
|
112
|
+
`(requestId=${outcome.requestId || 'n/a'}); fixture magic-link manager verify consumed the token single-use and returned ok=true.`;
|
|
113
|
+
resultRow.evidence = {
|
|
114
|
+
providerMessageId: outcome.providerMessageId,
|
|
115
|
+
providerStatus: outcome.providerStatus,
|
|
116
|
+
requestId: outcome.requestId || null,
|
|
117
|
+
adapterKind: adapter.kind,
|
|
118
|
+
outcomeKeys,
|
|
119
|
+
outcomeShapeOk: shapeOk,
|
|
120
|
+
from, to,
|
|
121
|
+
localVerifyOk: true,
|
|
122
|
+
localTokenLen: issued.token.length,
|
|
123
|
+
};
|
|
124
|
+
Object.assign(evidence, {
|
|
125
|
+
providerMessageId: outcome.providerMessageId,
|
|
126
|
+
providerStatus: outcome.providerStatus,
|
|
127
|
+
requestId: outcome.requestId || null,
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
resultRow.detail = `adapter return did not match the declared shape: outcome.ok=${outcome && outcome.ok} shapeOk=${shapeOk} extraKeys=${JSON.stringify(extraKeys)} providerMessageId=${outcome && outcome.providerMessageId} providerStatus=${outcome && outcome.providerStatus} error=${outcome && outcome.error} verifyOk=${verifyOk}`;
|
|
131
|
+
resultRow.evidence = { outcome, outcomeKeys, shapeOk, verifyOk };
|
|
132
|
+
}
|
|
133
|
+
} catch (err) {
|
|
134
|
+
resultRow.detail = `probe threw: ${err && err.message ? err.message : String(err)}`;
|
|
135
|
+
resultRow.evidence = { threw: err && err.message ? err.message : String(err) };
|
|
136
|
+
evidence.threw = err && err.message ? err.message : String(err);
|
|
137
|
+
}
|
|
138
|
+
return { results: [resultRow], extra: evidence };
|
|
139
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import runProbe from './real-account-magic-link-send.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
const engine = { kind: 'resend', image: 'live Resend HTTP API (sandbox sender + sandbox recipient) (or skipped)', healthy: true };
|
|
4
|
+
runShim('real-account-magic-link-send', engine, runProbe);
|