rcf-lite 0.27.0 → 0.28.1
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 +39 -0
- package/README.md +19 -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 +46 -0
- package/rcf/code-nodes/cn-601.json +18 -0
- package/rcf/code-nodes/cn-602.json +16 -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 +18 -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 +46 -0
- package/rcf/fbs/fbs-182.json +43 -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 +40 -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 +40 -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 +174 -0
- package/rcf/test-suites/ts-189.json +60 -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 +60 -0
- package/rcf/user-stories/us-15701.json +42 -0
- package/rcf/user-stories/us-15801.json +51 -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 +21 -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 +2213 -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 +455 -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 +1148 -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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// application-admin-console probe: org switcher surface across the
|
|
2
|
+
// two shipped ACs for the org-switcher story - the tenancy-applied
|
|
3
|
+
// render contract (AC-21104-1) and the tenancy-absent suppression
|
|
4
|
+
// contract (AC-21104-2). Each row detail opens on the first eight
|
|
5
|
+
// words of the shipped AC it anchors (rule 10).
|
|
6
|
+
//
|
|
7
|
+
// AC-21104-1 requires: with tenancy applied, the shell renders
|
|
8
|
+
// [data-role="org-switcher"] on the console header; when tenancy is
|
|
9
|
+
// not applied, neither the control nor the org-scoped invite path is
|
|
10
|
+
// rendered nor reachable.
|
|
11
|
+
//
|
|
12
|
+
// AC-21104-2 requires: when tenancy is NOT applied, the orgs route is
|
|
13
|
+
// suppressed (not linked in the shell navigation and returning 404 or
|
|
14
|
+
// the shared forbidden state on direct URL); the org switcher control
|
|
15
|
+
// is absent from the DOM on every route.
|
|
16
|
+
|
|
17
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
18
|
+
|
|
19
|
+
export const anchorAcId = 'application-admin-console-AC-21104-1';
|
|
20
|
+
export const accountBound = false;
|
|
21
|
+
|
|
22
|
+
export default async function runProbe() {
|
|
23
|
+
const results = [];
|
|
24
|
+
const withTenancy = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory,tenancy' } });
|
|
25
|
+
try {
|
|
26
|
+
// Row 1: AC-21104-1 tenancy-applied render.
|
|
27
|
+
const r = await fixtureFetch(withTenancy.url, '/admin/orgs');
|
|
28
|
+
const switcherCount = (r.body.match(/data-role="org-switcher"/g) || []).length;
|
|
29
|
+
const orgsLinkInNav = /<nav[^>]*data-role="primary-nav"[^]*?<a[^>]*href="\/admin\/orgs">Orgs<\/a>[^]*?<\/nav>/.test(r.body);
|
|
30
|
+
const pass = r.status === 200 && !!r.requestId && switcherCount >= 1 && orgsLinkInNav;
|
|
31
|
+
results.push({
|
|
32
|
+
anchorAcId: null,
|
|
33
|
+
conformanceOnly: true,
|
|
34
|
+
limitation: 'application-admin-console-AC-21104-1: the users invite-path organization selector for scoping the invite (the AC clause beyond the general header selector) is not present in this fixture and not observed by this Node HTTP probe; the general header org-selector walk is a partial observation of AC-21104-1',
|
|
35
|
+
verdict: pass ? 'warn' : 'fail',
|
|
36
|
+
detail: pass
|
|
37
|
+
? `Given an applied blueprint declaring tenancy, the shell rendered [data-role="org-switcher"] count=${switcherCount} on the console header and the Orgs link is present in the primary navigation; GET /admin/orgs returned 200; x-fixture-request-id=${r.requestId}`
|
|
38
|
+
: `Given an applied blueprint declaring tenancy, the shell tenancy-on gap: status=${r.status} rid=${r.requestId} switcher=${switcherCount} orgsNavLink=${orgsLinkInNav}`,
|
|
39
|
+
evidence: {
|
|
40
|
+
requestId: r.requestId,
|
|
41
|
+
responseStatus: r.status,
|
|
42
|
+
bodyExcerpt: excerpt((r.body.match(/data-role="org-switcher"[^]{0,140}/) || [''])[0]),
|
|
43
|
+
derived: { switcherCount, orgsLinkInNav, capsIncludesTenancy: true },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
} finally {
|
|
47
|
+
await withTenancy.kill();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const noTenancy = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory' } });
|
|
51
|
+
try {
|
|
52
|
+
// Row 2: AC-21104-2 tenancy-absent suppression.
|
|
53
|
+
// The AC mandates 404 or forbidden on direct URL AND no orgs link
|
|
54
|
+
// in nav AND no switcher control on any route.
|
|
55
|
+
const directOrgs = await fixtureFetch(noTenancy.url, '/admin/orgs');
|
|
56
|
+
const home = await fixtureFetch(noTenancy.url, '/admin');
|
|
57
|
+
const statusIsRefused = directOrgs.status === 404 || directOrgs.status === 403;
|
|
58
|
+
const orgsLinkInNav = /href="\/admin\/orgs">Orgs</.test(home.body);
|
|
59
|
+
const switcherOnHome = /data-role="org-switcher"/.test(home.body);
|
|
60
|
+
const switcherOnOrgs = /data-role="org-switcher"/.test(directOrgs.body);
|
|
61
|
+
const suppressionPass = !!directOrgs.requestId && !!home.requestId
|
|
62
|
+
&& statusIsRefused
|
|
63
|
+
&& !orgsLinkInNav
|
|
64
|
+
&& !switcherOnHome
|
|
65
|
+
&& !switcherOnOrgs;
|
|
66
|
+
results.push({
|
|
67
|
+
anchorAcId: 'application-admin-console-AC-21104-2',
|
|
68
|
+
verdict: suppressionPass ? 'pass' : 'fail',
|
|
69
|
+
detail: suppressionPass
|
|
70
|
+
? `When tenancy is NOT applied, the orgs route was suppressed: GET /admin/orgs returned ${directOrgs.status} (404 or 403 as the AC requires); no /admin/orgs link in the shell nav; no [data-role="org-switcher"] on /admin or on the refused /admin/orgs response; x-fixture-request-id=${directOrgs.requestId}`
|
|
71
|
+
: `When tenancy is NOT applied, the orgs route suppression gap: orgs status=${directOrgs.status} orgsRid=${directOrgs.requestId} homeRid=${home.requestId} statusRefused=${statusIsRefused} orgsNavLink=${orgsLinkInNav} switcherOnHome=${switcherOnHome} switcherOnOrgs=${switcherOnOrgs}`,
|
|
72
|
+
evidence: {
|
|
73
|
+
requestId: directOrgs.requestId,
|
|
74
|
+
responseStatus: directOrgs.status,
|
|
75
|
+
bodyExcerpt: excerpt(directOrgs.body),
|
|
76
|
+
derived: { statusIsRefused, orgsLinkInNav, switcherOnHome, switcherOnOrgs, capsIncludesTenancy: false },
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
} finally {
|
|
80
|
+
await noTenancy.kill();
|
|
81
|
+
}
|
|
82
|
+
return { results };
|
|
83
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// application-admin-console probe: permission matrix ARIA APG grid
|
|
2
|
+
// (AC-21103-1). Row detail opens on the first eight words of the
|
|
3
|
+
// shipped AC it anchors (rule 10).
|
|
4
|
+
//
|
|
5
|
+
// AC-21103-1 requires: given the roles surface AND an applied auth
|
|
6
|
+
// blueprint declaring roleModel, the permission matrix renders as an
|
|
7
|
+
// ARIA APG grid: role="grid" on the outer element, role="row" on
|
|
8
|
+
// every rank (including the header rank), role="columnheader" on
|
|
9
|
+
// every permission column header, role="rowheader" on the leftmost
|
|
10
|
+
// cell of each role rank, role="gridcell" on every inner cell, and
|
|
11
|
+
// each cell carries an aria-label announcing the exact permission
|
|
12
|
+
// string plus the allowed/denied state on focus.
|
|
13
|
+
|
|
14
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
15
|
+
|
|
16
|
+
export const anchorAcId = 'application-admin-console-AC-21103-1';
|
|
17
|
+
export const accountBound = false;
|
|
18
|
+
|
|
19
|
+
export default async function runProbe() {
|
|
20
|
+
const fixture = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory,roleModel' } });
|
|
21
|
+
const results = [];
|
|
22
|
+
try {
|
|
23
|
+
const r = await fixtureFetch(fixture.url, '/admin/roles');
|
|
24
|
+
const gridPresent = /role="grid"/.test(r.body);
|
|
25
|
+
const columnCount = (r.body.match(/role="columnheader" data-permission="/g) || []).length;
|
|
26
|
+
const roleRankRows = [...r.body.matchAll(/data-role-rank="([^"]+)"/g)].map((m) => m[1]);
|
|
27
|
+
const rowCount = roleRankRows.length;
|
|
28
|
+
const gridcellCount = (r.body.match(/role="gridcell" data-cell-state="/g) || []).length;
|
|
29
|
+
const rowHeaderCount = (r.body.match(/role="rowheader"/g) || []).length;
|
|
30
|
+
|
|
31
|
+
// Every gridcell must carry an aria-label of the form
|
|
32
|
+
// "<role> (allowed|denied): <permission>". Collect ALL labels
|
|
33
|
+
// (no slicing) so length equality with gridcellCount protects the
|
|
34
|
+
// check against a vacuous every() on an empty array.
|
|
35
|
+
const cellLabels = [...r.body.matchAll(/role="gridcell"[^>]*aria-label="([^"]+)"/g)].map((m) => m[1]);
|
|
36
|
+
const labelShape = /^[A-Za-z]+ (allowed|denied): [A-Za-z ]+$/;
|
|
37
|
+
const everyLabelHonoursContract = cellLabels.length > 0
|
|
38
|
+
&& cellLabels.length === gridcellCount
|
|
39
|
+
&& cellLabels.every((l) => labelShape.test(l));
|
|
40
|
+
|
|
41
|
+
const derivedPass = r.status === 200 && !!r.requestId
|
|
42
|
+
&& gridPresent
|
|
43
|
+
&& columnCount > 0
|
|
44
|
+
&& rowCount > 0
|
|
45
|
+
&& gridcellCount === rowCount * columnCount
|
|
46
|
+
&& rowHeaderCount >= rowCount
|
|
47
|
+
&& everyLabelHonoursContract;
|
|
48
|
+
results.push({
|
|
49
|
+
anchorAcId: null,
|
|
50
|
+
conformanceOnly: true,
|
|
51
|
+
limitation: 'application-admin-console-AC-21103-1: permission-derivation checking against role-permission tables (each cell label corresponding to the actual role permission and state, row-role x column-permission mapping) is not observed by this Node HTTP probe against a fixed fixture; the label-shape walk over gridcell aria-labels is a partial observation of AC-21103-1',
|
|
52
|
+
verdict: derivedPass ? 'warn' : 'fail',
|
|
53
|
+
detail: derivedPass
|
|
54
|
+
? `Given the roles surface AND an applied auth blueprint declaring roleModel: GET /admin/roles returned 200 with role="grid" present, ${rowCount} role ranks, ${columnCount} permission columnheaders, ${gridcellCount} gridcells (=rows*columns), ${rowHeaderCount} rowheader cells, and all ${cellLabels.length} gridcell aria-labels honour the "<role> allowed/denied: <permission>" contract; x-fixture-request-id=${r.requestId}`
|
|
55
|
+
: `Given the roles surface AND an applied auth blueprint declaring roleModel gap: status=${r.status} rid=${r.requestId} grid=${gridPresent} rows=${rowCount} cols=${columnCount} cells=${gridcellCount} rowHeaders=${rowHeaderCount} labelCount=${cellLabels.length} labelsHonourContract=${everyLabelHonoursContract}`,
|
|
56
|
+
evidence: {
|
|
57
|
+
requestId: r.requestId,
|
|
58
|
+
responseStatus: r.status,
|
|
59
|
+
bodyExcerpt: excerpt((r.body.match(/role="gridcell"[^>]{0,180}/) || [''])[0]),
|
|
60
|
+
derived: { rowCount, columnCount, gridcellCount, rowHeaderCount, expectedCells: rowCount * columnCount, labelCount: cellLabels.length, sampledLabels: cellLabels.slice(0, 3) },
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
} finally {
|
|
64
|
+
await fixture.kill();
|
|
65
|
+
}
|
|
66
|
+
return { results };
|
|
67
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// Shared helpers for application-admin-console contributions/probes/.
|
|
2
|
+
//
|
|
3
|
+
// The real engine for every probe in this pack is the fixture HTTP
|
|
4
|
+
// server at packages/rcf-lite/test/fixtures/probe-pack-application-admin-console/server.js
|
|
5
|
+
// booted on a scratch port from the family range 47600-47609.
|
|
6
|
+
// The fixture echoes a per-request x-fixture-request-id header on
|
|
7
|
+
// every response; probes record that id and a response body excerpt
|
|
8
|
+
// as positive evidence per rule 7d.
|
|
9
|
+
//
|
|
10
|
+
// No account credentials or network calls: every probe is
|
|
11
|
+
// local-fixture-driven, so no probe carries an account-bound branch
|
|
12
|
+
// or a CI_HAS_* gate. Declared env vars are the fixture's own
|
|
13
|
+
// PORT and (where the fixture reads them) the CAPS/state switches
|
|
14
|
+
// the probes drive via query string.
|
|
15
|
+
|
|
16
|
+
import { spawn } from 'node:child_process';
|
|
17
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
18
|
+
import { createServer } from 'node:net';
|
|
19
|
+
import { dirname, resolve } from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
|
|
24
|
+
export const SLUG = 'application-admin-console';
|
|
25
|
+
export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
|
|
26
|
+
export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/probe-pack-application-admin-console');
|
|
27
|
+
export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/application-admin-console');
|
|
28
|
+
export const PORT_RANGE_START = 47600;
|
|
29
|
+
export const PORT_RANGE_END = 47609;
|
|
30
|
+
export const DECLARED_ENV = Object.freeze(['PORT', 'ADMIN_CONSOLE_CAPS', 'ADMIN_CONSOLE_BREAK', 'ADMIN_CONSOLE_PRINCIPAL_EMAIL', 'PROBE_BREAK']);
|
|
31
|
+
export const REQUEST_ID_HEADER = 'x-fixture-request-id';
|
|
32
|
+
|
|
33
|
+
// Pick a free port from the fixture family range. Falls back to
|
|
34
|
+
// asking the OS for an ephemeral port only if the whole range is
|
|
35
|
+
// held by other workers (never expected on a single-machine run).
|
|
36
|
+
export async function pickPort() {
|
|
37
|
+
for (let port = PORT_RANGE_START; port <= PORT_RANGE_END; port += 1) {
|
|
38
|
+
if (await canBind(port)) return port;
|
|
39
|
+
}
|
|
40
|
+
return await bindEphemeral();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function canBind(port) {
|
|
44
|
+
return new Promise((res) => {
|
|
45
|
+
const s = createServer();
|
|
46
|
+
s.once('error', () => res(false));
|
|
47
|
+
s.listen(port, '127.0.0.1', () => {
|
|
48
|
+
const bound = s.address();
|
|
49
|
+
s.close(() => res(!!bound));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function bindEphemeral() {
|
|
55
|
+
return new Promise((res) => {
|
|
56
|
+
const s = createServer();
|
|
57
|
+
s.listen(0, '127.0.0.1', () => {
|
|
58
|
+
const port = s.address().port;
|
|
59
|
+
s.close(() => res(port));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Spawns the fixture server as a child on `port` with the given
|
|
65
|
+
// env overlay; resolves once the fixture has printed LISTENING and
|
|
66
|
+
// returns { child, url, kill } (kill is synchronous best-effort).
|
|
67
|
+
export async function startFixture({ port, env = {} } = {}) {
|
|
68
|
+
const boundPort = port ?? await pickPort();
|
|
69
|
+
const child = spawn(process.execPath, ['server.js'], {
|
|
70
|
+
cwd: FIXTURE_DIR,
|
|
71
|
+
env: { ...process.env, PORT: String(boundPort), ...env },
|
|
72
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
73
|
+
});
|
|
74
|
+
await new Promise((res, rej) => {
|
|
75
|
+
const timer = setTimeout(() => rej(new Error(`fixture did not print LISTENING within 4s on port ${boundPort}`)), 4000);
|
|
76
|
+
let stderrBuf = '';
|
|
77
|
+
child.stderr.on('data', (chunk) => { stderrBuf += String(chunk); });
|
|
78
|
+
child.on('exit', (code) => rej(new Error(`fixture exited early (code=${code}) stderr=${stderrBuf.slice(0, 400)}`)));
|
|
79
|
+
child.stdout.on('data', (chunk) => {
|
|
80
|
+
if (String(chunk).includes(`LISTENING ${boundPort}`)) { clearTimeout(timer); res(); }
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
const url = new URL(`http://127.0.0.1:${boundPort}`);
|
|
84
|
+
return {
|
|
85
|
+
child,
|
|
86
|
+
url,
|
|
87
|
+
port: boundPort,
|
|
88
|
+
// Await child exit and propagate any error. A teardown failure
|
|
89
|
+
// must fail the verdict (the teardown-propagation rule);
|
|
90
|
+
// no swallowed errors here.
|
|
91
|
+
kill: () => new Promise((res, rej) => {
|
|
92
|
+
let settled = false;
|
|
93
|
+
const done = (err) => { if (settled) return; settled = true; err ? rej(err) : res(); };
|
|
94
|
+
child.once('exit', () => done());
|
|
95
|
+
child.once('error', (err) => done(err));
|
|
96
|
+
try { child.kill('SIGTERM'); } catch (err) { return done(err); }
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
if (settled) return;
|
|
99
|
+
try { child.kill('SIGKILL'); } catch (err) { return done(err); }
|
|
100
|
+
}, 4000);
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Issue an HTTP request against the fixture and return
|
|
106
|
+
// { status, headers, body, requestId }.
|
|
107
|
+
export async function fixtureFetch(url, pathAndQuery, init = {}) {
|
|
108
|
+
const target = new URL(pathAndQuery, url);
|
|
109
|
+
const res = await fetch(target, init);
|
|
110
|
+
const body = await res.text();
|
|
111
|
+
const requestId = res.headers.get(REQUEST_ID_HEADER);
|
|
112
|
+
return { status: res.status, headers: Object.fromEntries(res.headers.entries()), body, requestId };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function excerpt(body, maxLen = 240) {
|
|
116
|
+
if (typeof body !== 'string') return '';
|
|
117
|
+
return body.length <= maxLen ? body : body.slice(0, maxLen) + '…';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function aggregate(results) {
|
|
121
|
+
// Positive-evidence rule: no-checks-ran is a fail.
|
|
122
|
+
if (!Array.isArray(results) || results.length === 0) return 'fail';
|
|
123
|
+
if (results.some((r) => r.verdict === 'fail')) return 'fail';
|
|
124
|
+
// Any warn row lifts the aggregate to warn, including honest
|
|
125
|
+
// notObservableHere de-claims. A probe whose rows are all warn
|
|
126
|
+
// aggregates to warn, not pass; the shelf reads amber and the tally
|
|
127
|
+
// accepts a warn aggregate as problems=0 when no fail row is present.
|
|
128
|
+
if (results.some((r) => r && r.verdict === 'warn')) return 'warn';
|
|
129
|
+
return 'pass';
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function writeReport({ probeName, engine, results, extra }) {
|
|
133
|
+
await mkdir(REPORT_DIR, { recursive: true });
|
|
134
|
+
const report = {
|
|
135
|
+
slug: SLUG,
|
|
136
|
+
probeName,
|
|
137
|
+
runAt: new Date().toISOString(),
|
|
138
|
+
engine,
|
|
139
|
+
results,
|
|
140
|
+
aggregateVerdict: aggregate(results),
|
|
141
|
+
...(extra ?? {}),
|
|
142
|
+
};
|
|
143
|
+
const filepath = resolve(REPORT_DIR, `${probeName}.json`);
|
|
144
|
+
await writeFile(filepath, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
145
|
+
return { report, path: filepath };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function runShim(probeName, engine, mainFn) {
|
|
149
|
+
try {
|
|
150
|
+
const outcome = (await mainFn()) ?? { results: [] };
|
|
151
|
+
const { results, extra } = outcome;
|
|
152
|
+
const { report, path: filepath } = await writeReport({ probeName, engine, results, extra });
|
|
153
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
154
|
+
process.stdout.write(`report written to ${filepath}\n`);
|
|
155
|
+
if (report.aggregateVerdict === 'fail') process.exitCode = 1;
|
|
156
|
+
} catch (err) {
|
|
157
|
+
// Positive-evidence rule (exception fallback): exception rows have no
|
|
158
|
+
// observed AC; anchor null (never a fabricated id like
|
|
159
|
+
// "unknown"), carry an evidence object with the error excerpt.
|
|
160
|
+
const message = err && err.message ? err.message : String(err);
|
|
161
|
+
const stack = err && err.stack ? err.stack : String(err);
|
|
162
|
+
const results = [{
|
|
163
|
+
anchorAcId: null,
|
|
164
|
+
verdict: 'fail',
|
|
165
|
+
detail: `probe threw: ${message}`,
|
|
166
|
+
evidence: {
|
|
167
|
+
errorMessage: message,
|
|
168
|
+
errorExcerpt: excerpt(stack, 480),
|
|
169
|
+
},
|
|
170
|
+
}];
|
|
171
|
+
const { report, path: filepath } = await writeReport({ probeName, engine, results });
|
|
172
|
+
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
173
|
+
process.stderr.write(`probe error: ${stack}\n`);
|
|
174
|
+
process.stderr.write(`report written to ${filepath}\n`);
|
|
175
|
+
process.exitCode = 1;
|
|
176
|
+
}
|
|
177
|
+
}
|
package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './org-switcher-surface.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-admin-console/server.js', healthy: true };
|
|
5
|
+
runShim('org-switcher-surface', engine, runProbe);
|
package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './permission-matrix-grid.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-admin-console/server.js', healthy: true };
|
|
5
|
+
runShim('permission-matrix-grid', engine, runProbe);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './sign-in-access-gated-surface.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-admin-console/server.js', healthy: true };
|
|
5
|
+
runShim('sign-in-access-gated-surface', engine, runProbe);
|
package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import runProbe from './users-directory-surface.mjs';
|
|
2
|
+
import { runShim } from './probe-utils.mjs';
|
|
3
|
+
|
|
4
|
+
const engine = { kind: 'fixture', image: 'test/fixtures/probe-pack-application-admin-console/server.js', healthy: true };
|
|
5
|
+
runShim('users-directory-surface', engine, runProbe);
|
package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// application-admin-console probe: sign-in surface across the three
|
|
2
|
+
// shipped ACs for the sign-in stories - the Access-gated render with
|
|
3
|
+
// request.auth present (AC-21815-1), the 403 refusal when
|
|
4
|
+
// request.auth is missing (AC-21815-2) and the local-login fallback
|
|
5
|
+
// when zeroTrustGate is not applied (AC-21816-1). Each row detail
|
|
6
|
+
// opens on the first eight words of the AC it anchors (rule 10).
|
|
7
|
+
//
|
|
8
|
+
// AC-21815-1 requires: with zeroTrustGate applied, GET /admin/sign-in
|
|
9
|
+
// renders [data-surface=access-gated], no [data-surface=local-login]
|
|
10
|
+
// region is present, and [data-role=principal-read] carries the
|
|
11
|
+
// principal email read from request.auth.
|
|
12
|
+
//
|
|
13
|
+
// AC-21815-2 requires: with zeroTrustGate applied but request.auth
|
|
14
|
+
// absent, the route refuses with HTTP 403, the DOM carries the
|
|
15
|
+
// access-denied surface, no principal-read element is rendered and
|
|
16
|
+
// no protected data is served.
|
|
17
|
+
//
|
|
18
|
+
// AC-21816-1 requires: without zeroTrustGate applied, GET /admin/sign-in
|
|
19
|
+
// renders [data-surface=local-login] and no [data-surface=access-gated]
|
|
20
|
+
// region; the local login form ships with data-role=local-login-form
|
|
21
|
+
// and data-action=local-sign-in controls.
|
|
22
|
+
|
|
23
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
24
|
+
|
|
25
|
+
export const anchorAcId = 'application-admin-console-AC-21815-1';
|
|
26
|
+
export const accountBound = false;
|
|
27
|
+
|
|
28
|
+
export default async function runProbe() {
|
|
29
|
+
const results = [];
|
|
30
|
+
const principalEmail = 'probe-signin@example.test';
|
|
31
|
+
|
|
32
|
+
const gated = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory,zeroTrustGate' } });
|
|
33
|
+
try {
|
|
34
|
+
// Row 1: AC-21815-1 with an Authorization header populating request.auth.
|
|
35
|
+
const withAuth = await fixtureFetch(gated.url, '/admin/sign-in', {
|
|
36
|
+
headers: { authorization: `Bearer ${principalEmail}` },
|
|
37
|
+
});
|
|
38
|
+
const accessGatedPresent = /data-surface="access-gated"/.test(withAuth.body);
|
|
39
|
+
const localLoginPresent = /data-surface="local-login"/.test(withAuth.body);
|
|
40
|
+
const principalReadPresent = /data-role="principal-read"/.test(withAuth.body);
|
|
41
|
+
const principalEmailPresent = withAuth.body.includes(principalEmail);
|
|
42
|
+
const gatedPass = withAuth.status === 200 && !!withAuth.requestId
|
|
43
|
+
&& accessGatedPresent && !localLoginPresent
|
|
44
|
+
&& principalReadPresent && principalEmailPresent;
|
|
45
|
+
results.push({
|
|
46
|
+
anchorAcId: 'application-admin-console-AC-21815-1',
|
|
47
|
+
verdict: gatedPass ? 'pass' : 'fail',
|
|
48
|
+
detail: gatedPass
|
|
49
|
+
? `When application-admin-console v1.1.0 is applied with zeroTrustGate in appliedCapabilities: GET /admin/sign-in with Authorization: Bearer ${principalEmail} returned 200 rendering [data-surface="access-gated"] with no [data-surface="local-login"] and a [data-role="principal-read"] element carrying the principal email read from request.auth; x-fixture-request-id=${withAuth.requestId}`
|
|
50
|
+
: `When application-admin-console v1.1.0 is applied with zeroTrustGate in appliedCapabilities (gap): status=${withAuth.status} rid=${withAuth.requestId} gated=${accessGatedPresent} localLogin=${localLoginPresent} principalRead=${principalReadPresent} emailPresent=${principalEmailPresent}`,
|
|
51
|
+
evidence: {
|
|
52
|
+
requestId: withAuth.requestId,
|
|
53
|
+
responseStatus: withAuth.status,
|
|
54
|
+
bodyExcerpt: excerpt((withAuth.body.match(/data-surface="access-gated"[^]{0,240}/) || [''])[0]),
|
|
55
|
+
derived: { accessGatedPresent, localLoginPresent, principalReadPresent, principalEmailPresent },
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Row 2: AC-21815-2 refusal-when-request.auth-absent path,
|
|
60
|
+
// observed at the fixture itself. The fixture now returns HTTP
|
|
61
|
+
// 403 with a [data-surface="access-denied"] region and no
|
|
62
|
+
// [data-role="principal-read"] element when zeroTrustGate is
|
|
63
|
+
// applied and the Authorization header is missing.
|
|
64
|
+
const noAuth = await fixtureFetch(gated.url, '/admin/sign-in');
|
|
65
|
+
const deniedPresent = /data-surface="access-denied"/.test(noAuth.body);
|
|
66
|
+
const noPrincipalRead = !/data-role="principal-read"/.test(noAuth.body);
|
|
67
|
+
const noGatedSurface = !/data-surface="access-gated"/.test(noAuth.body);
|
|
68
|
+
const refusalPass = noAuth.status === 403 && !!noAuth.requestId
|
|
69
|
+
&& deniedPresent && noPrincipalRead && noGatedSurface;
|
|
70
|
+
results.push({
|
|
71
|
+
anchorAcId: null,
|
|
72
|
+
conformanceOnly: true,
|
|
73
|
+
limitation: 'application-admin-console-AC-21815-2: refusal-log capability field checking against a shipped log adapter (the AC clause requiring the refusal event to be recorded with the required capability fields) is not observed by this Node HTTP probe; the HTTP-403 + access-denied surface walk when zeroTrustGate is applied and Authorization is missing is a partial observation of AC-21815-2',
|
|
74
|
+
verdict: refusalPass ? 'warn' : 'fail',
|
|
75
|
+
detail: refusalPass
|
|
76
|
+
? `When zeroTrustGate is applied but the incoming request lacks request.auth: GET /admin/sign-in with no Authorization header returned HTTP 403 rendering [data-surface="access-denied"], with no [data-role="principal-read"] element and no [data-surface="access-gated"] region; x-fixture-request-id=${noAuth.requestId}`
|
|
77
|
+
: `When zeroTrustGate is applied but the incoming request lacks request.auth (gap): status=${noAuth.status} rid=${noAuth.requestId} deniedPresent=${deniedPresent} noPrincipalRead=${noPrincipalRead} noGatedSurface=${noGatedSurface}`,
|
|
78
|
+
evidence: {
|
|
79
|
+
requestId: noAuth.requestId,
|
|
80
|
+
responseStatus: noAuth.status,
|
|
81
|
+
bodyExcerpt: excerpt((noAuth.body.match(/data-surface="access-denied"[^]{0,240}/) || [''])[0]),
|
|
82
|
+
derived: { deniedPresent, noPrincipalRead, noGatedSurface },
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
} finally {
|
|
86
|
+
await gated.kill();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const local = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory' } });
|
|
90
|
+
try {
|
|
91
|
+
// Row 3: AC-21816-1 fallback branch (zeroTrustGate not applied).
|
|
92
|
+
const r = await fixtureFetch(local.url, '/admin/sign-in');
|
|
93
|
+
const accessGatedPresent = /data-surface="access-gated"/.test(r.body);
|
|
94
|
+
const localLoginPresent = /data-surface="local-login"/.test(r.body);
|
|
95
|
+
const localFormPresent = /data-role="local-login-form"/.test(r.body);
|
|
96
|
+
const localSignInControl = /data-action="local-sign-in"/.test(r.body);
|
|
97
|
+
const pass = r.status === 200 && !!r.requestId
|
|
98
|
+
&& !accessGatedPresent && localLoginPresent
|
|
99
|
+
&& localFormPresent && localSignInControl;
|
|
100
|
+
results.push({
|
|
101
|
+
anchorAcId: 'application-admin-console-AC-21816-1',
|
|
102
|
+
verdict: pass ? 'pass' : 'fail',
|
|
103
|
+
detail: pass
|
|
104
|
+
? `When application-admin-console v1.1.0 is applied without zeroTrustGate in appliedCapabilities: GET /admin/sign-in returned 200 rendering [data-surface="local-login"] with no [data-surface="access-gated"] region; the local login form carries data-role="local-login-form" and a data-action="local-sign-in" submit control; x-fixture-request-id=${r.requestId}`
|
|
105
|
+
: `When application-admin-console v1.1.0 is applied without zeroTrustGate in appliedCapabilities (gap): status=${r.status} rid=${r.requestId} gated=${accessGatedPresent} localLogin=${localLoginPresent} form=${localFormPresent} signInControl=${localSignInControl}`,
|
|
106
|
+
evidence: {
|
|
107
|
+
requestId: r.requestId,
|
|
108
|
+
responseStatus: r.status,
|
|
109
|
+
bodyExcerpt: excerpt((r.body.match(/data-surface="local-login"[^]{0,240}/) || [''])[0]),
|
|
110
|
+
derived: { accessGatedPresent, localLoginPresent, localFormPresent, localSignInControl },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
} finally {
|
|
114
|
+
await local.kill();
|
|
115
|
+
}
|
|
116
|
+
return { results };
|
|
117
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// application-admin-console probe: users directory surface.
|
|
2
|
+
//
|
|
3
|
+
// De-claim first, observe second. This probe splits observation
|
|
4
|
+
// across the two shipped ACs for the users-directory story: the
|
|
5
|
+
// directory listing contract (AC-21102-1) and the per-row
|
|
6
|
+
// invite/deactivate action controls (AC-21102-2). Each row detail
|
|
7
|
+
// opens on the first eight words of the shipped AC it anchors (rule 10).
|
|
8
|
+
//
|
|
9
|
+
// AC-21102-1 requires: with principalDirectory applied AND admin
|
|
10
|
+
// scope, the users table lists every principal by data-user-id with
|
|
11
|
+
// a role column (only when roleModel is applied), a last-active
|
|
12
|
+
// timestamp and a status column; a principal without admin scope
|
|
13
|
+
// hitting /admin renders an access-denied state with a request-access
|
|
14
|
+
// control routing to POST /api/request-access.
|
|
15
|
+
//
|
|
16
|
+
// AC-21102-2 requires: each row exposes an invite control for a
|
|
17
|
+
// principal without an active session (data-action="invite") and a
|
|
18
|
+
// deactivate control for an active principal (data-action="deactivate");
|
|
19
|
+
// the controls are keyboard-reachable buttons.
|
|
20
|
+
|
|
21
|
+
import { fixtureFetch, startFixture, excerpt } from './probe-utils.mjs';
|
|
22
|
+
|
|
23
|
+
export const anchorAcId = 'application-admin-console-AC-21102-1';
|
|
24
|
+
export const accountBound = false;
|
|
25
|
+
|
|
26
|
+
export default async function runProbe() {
|
|
27
|
+
const withRole = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory,roleModel' } });
|
|
28
|
+
const results = [];
|
|
29
|
+
try {
|
|
30
|
+
const r = await fixtureFetch(withRole.url, '/admin/users');
|
|
31
|
+
const rowIds = [...r.body.matchAll(/data-user-id="([^"]+)"/g)].map((m) => m[1]);
|
|
32
|
+
const distinctRowIds = [...new Set(rowIds)];
|
|
33
|
+
const roleColumnPresent = /<th data-column="role">/.test(r.body);
|
|
34
|
+
const roleCellCount = (r.body.match(/<td data-column="role">/g) || []).length;
|
|
35
|
+
const statusColumnPresent = /<th data-column="status">/.test(r.body);
|
|
36
|
+
const lastActiveColumnPresent = /<th data-column="lastActive">/.test(r.body);
|
|
37
|
+
const inviteBtnCount = (r.body.match(/data-action="invite" data-user-id="/g) || []).length;
|
|
38
|
+
const deactivateBtnCount = (r.body.match(/data-action="deactivate" data-user-id="/g) || []).length;
|
|
39
|
+
|
|
40
|
+
// Row 1: AC-21102-1 directory-listing contract with roleModel applied.
|
|
41
|
+
const listingPass = r.status === 200 && !!r.requestId
|
|
42
|
+
&& distinctRowIds.length > 0
|
|
43
|
+
&& roleColumnPresent
|
|
44
|
+
&& roleCellCount === distinctRowIds.length
|
|
45
|
+
&& statusColumnPresent
|
|
46
|
+
&& lastActiveColumnPresent;
|
|
47
|
+
results.push({
|
|
48
|
+
anchorAcId: null,
|
|
49
|
+
conformanceOnly: true,
|
|
50
|
+
limitation: 'application-admin-console-AC-21102-1: inventory-completeness reconciliation against the applied provider adapter (every principal in the provider inventory rendered with populated role, last-active and status values) is not observed by this Node HTTP probe against a fixed fixture; the directory-shell walk is a partial observation of AC-21102-1',
|
|
51
|
+
verdict: listingPass ? 'warn' : 'fail',
|
|
52
|
+
detail: listingPass
|
|
53
|
+
? `Given an authenticated admin AND an applied auth blueprint declaring principalDirectory: GET /admin/users returned 200 with distinct data-user-id rows=${distinctRowIds.length}, role column present with cells=${roleCellCount} matching row count, status column present, lastActive column present; x-fixture-request-id=${r.requestId}`
|
|
54
|
+
: `Given an authenticated admin AND an applied auth blueprint listing gap: status=${r.status} rid=${r.requestId} rows=${distinctRowIds.length} roleColumn=${roleColumnPresent} roleCells=${roleCellCount} statusColumn=${statusColumnPresent} lastActiveColumn=${lastActiveColumnPresent}`,
|
|
55
|
+
evidence: {
|
|
56
|
+
requestId: r.requestId,
|
|
57
|
+
responseStatus: r.status,
|
|
58
|
+
bodyExcerpt: excerpt((r.body.match(/<tr data-user-id="[^"]+">[^]{0,180}/) || [''])[0]),
|
|
59
|
+
derived: { rowCount: distinctRowIds.length, roleColumnPresent, roleCellCount, statusColumnPresent, lastActiveColumnPresent },
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Row 2: AC-21102-2 per-row invite/deactivate action controls.
|
|
64
|
+
// Every row must carry exactly one action (invite if pending, deactivate if active).
|
|
65
|
+
const perRowAction = distinctRowIds.every((id) => {
|
|
66
|
+
const inviteHere = new RegExp(`data-action="invite" data-user-id="${id}"`).test(r.body);
|
|
67
|
+
const deactivateHere = new RegExp(`data-action="deactivate" data-user-id="${id}"`).test(r.body);
|
|
68
|
+
return (inviteHere && !deactivateHere) || (!inviteHere && deactivateHere);
|
|
69
|
+
});
|
|
70
|
+
const actionButtonsAreButtons = /(<button[^>]*data-action="invite"|<button[^>]*data-action="deactivate")/.test(r.body);
|
|
71
|
+
const actionPass = r.status === 200 && !!r.requestId
|
|
72
|
+
&& distinctRowIds.length > 0
|
|
73
|
+
&& (inviteBtnCount + deactivateBtnCount) === distinctRowIds.length
|
|
74
|
+
&& perRowAction
|
|
75
|
+
&& actionButtonsAreButtons;
|
|
76
|
+
results.push({
|
|
77
|
+
anchorAcId: null,
|
|
78
|
+
conformanceOnly: true,
|
|
79
|
+
limitation: 'application-admin-console-AC-21102-2: state-to-action correlation (deactivate offered on active sessions, invite offered on pending) against varied per-principal states is not observed by this Node HTTP probe against a fixed fixture; the per-row action-control walk is a partial observation of AC-21102-2',
|
|
80
|
+
verdict: actionPass ? 'warn' : 'fail',
|
|
81
|
+
detail: actionPass
|
|
82
|
+
? `Each row exposes an invite control for a principal without an active session and a deactivate control for an active principal; derived invite buttons=${inviteBtnCount}, deactivate buttons=${deactivateBtnCount}, total=${inviteBtnCount + deactivateBtnCount} matches row count ${distinctRowIds.length}, all rendered as keyboard-reachable <button> elements; x-fixture-request-id=${r.requestId}`
|
|
83
|
+
: `Each row exposes an invite control for a action gap: status=${r.status} rid=${r.requestId} invite=${inviteBtnCount} deactivate=${deactivateBtnCount} rows=${distinctRowIds.length} perRowAction=${perRowAction} buttonElements=${actionButtonsAreButtons}`,
|
|
84
|
+
evidence: {
|
|
85
|
+
requestId: r.requestId,
|
|
86
|
+
responseStatus: r.status,
|
|
87
|
+
bodyExcerpt: excerpt((r.body.match(/<button[^>]*data-action="(?:invite|deactivate)"[^>]{0,180}/) || [''])[0]),
|
|
88
|
+
derived: { inviteBtnCount, deactivateBtnCount, rowCount: distinctRowIds.length, perRowAction, actionButtonsAreButtons },
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
} finally {
|
|
92
|
+
await withRole.kill();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const noRole = await startFixture({ env: { ADMIN_CONSOLE_CAPS: 'principalDirectory' } });
|
|
96
|
+
try {
|
|
97
|
+
// Row 3: AC-21102-1 role-column-suppression when roleModel is absent.
|
|
98
|
+
const r = await fixtureFetch(noRole.url, '/admin/users');
|
|
99
|
+
const rowIds = [...r.body.matchAll(/data-user-id="([^"]+)"/g)].map((m) => m[1]);
|
|
100
|
+
const distinctRowIds = [...new Set(rowIds)];
|
|
101
|
+
const roleColumnPresent = /<th data-column="role">/.test(r.body);
|
|
102
|
+
const suppressionPass = r.status === 200 && !!r.requestId
|
|
103
|
+
&& distinctRowIds.length > 0
|
|
104
|
+
&& !roleColumnPresent;
|
|
105
|
+
results.push({
|
|
106
|
+
anchorAcId: null,
|
|
107
|
+
conformanceOnly: true,
|
|
108
|
+
limitation: 'application-admin-console-AC-21102-1: the full directory-listing contract (every provider principal enumerated with populated status and last-active) is not observed by this Node HTTP probe against a fixed fixture; the role-column suppression walk (when roleModel is not applied) is a partial observation of AC-21102-1',
|
|
109
|
+
verdict: suppressionPass ? 'warn' : 'fail',
|
|
110
|
+
detail: suppressionPass
|
|
111
|
+
? `Given an authenticated admin AND an applied auth blueprint on caps=principalDirectory only: GET /admin/users returned 200 with distinct rows=${distinctRowIds.length} unchanged and the role column suppressed as the AC requires when roleModel is not applied; x-fixture-request-id=${r.requestId}`
|
|
112
|
+
: `Given an authenticated admin AND an applied auth blueprint suppression gap: status=${r.status} rid=${r.requestId} rows=${distinctRowIds.length} roleColumn=${roleColumnPresent}`,
|
|
113
|
+
evidence: {
|
|
114
|
+
requestId: r.requestId,
|
|
115
|
+
responseStatus: r.status,
|
|
116
|
+
bodyExcerpt: excerpt((r.body.match(/<thead>[^]{0,200}/) || [''])[0]),
|
|
117
|
+
derived: { rowCount: distinctRowIds.length, roleColumnPresent },
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// Row 4: AC-21102-1 access-denied surface with request-access control.
|
|
122
|
+
const denied = await fixtureFetch(noRole.url, '/admin/users?asAdmin=false');
|
|
123
|
+
const hasDeniedRegion = /data-surface="denied"/.test(denied.body);
|
|
124
|
+
const hasRequestAccess = /data-action="request-access"/.test(denied.body);
|
|
125
|
+
const deniedPass = denied.status === 200 && !!denied.requestId && hasDeniedRegion && hasRequestAccess;
|
|
126
|
+
results.push({
|
|
127
|
+
anchorAcId: null,
|
|
128
|
+
conformanceOnly: true,
|
|
129
|
+
limitation: 'application-admin-console-AC-21102-1: request-access control activation and outcome against a routed API are browser-driven and not observed by this Node HTTP probe; the denied-surface walk on the not-authorised branch is a partial observation of AC-21102-1',
|
|
130
|
+
verdict: deniedPass ? 'warn' : 'fail',
|
|
131
|
+
detail: deniedPass
|
|
132
|
+
? `Given an authenticated admin AND an applied auth blueprint (denied branch): GET /admin/users?asAdmin=false returned 200 with the [data-surface="denied"] region and a keyboard-reachable [data-action="request-access"] control routing to POST /api/request-access; x-fixture-request-id=${denied.requestId}`
|
|
133
|
+
: `Given an authenticated admin AND an applied auth blueprint denied-branch gap: status=${denied.status} rid=${denied.requestId} deniedRegion=${hasDeniedRegion} requestAccess=${hasRequestAccess}`,
|
|
134
|
+
evidence: {
|
|
135
|
+
requestId: denied.requestId,
|
|
136
|
+
responseStatus: denied.status,
|
|
137
|
+
bodyExcerpt: excerpt((denied.body.match(/data-surface="denied"[^]{0,220}/) || [''])[0]),
|
|
138
|
+
derived: { hasDeniedRegion, hasRequestAccess },
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
} finally {
|
|
142
|
+
await noRole.kill();
|
|
143
|
+
}
|
|
144
|
+
return { results };
|
|
145
|
+
}
|