@endora-commerce/cli 0.100.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/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/bin/endora.d.ts +28 -0
- package/dist/bin/endora.d.ts.map +1 -0
- package/dist/bin/endora.js +926 -0
- package/dist/bin/endora.js.map +1 -0
- package/dist/check/estate.d.ts +189 -0
- package/dist/check/estate.d.ts.map +1 -0
- package/dist/check/estate.js +1037 -0
- package/dist/check/estate.js.map +1 -0
- package/dist/check/hosts.d.ts +25 -0
- package/dist/check/hosts.d.ts.map +1 -0
- package/dist/check/hosts.js +1347 -0
- package/dist/check/hosts.js.map +1 -0
- package/dist/check/index.d.ts +60 -0
- package/dist/check/index.d.ts.map +1 -0
- package/dist/check/index.js +111 -0
- package/dist/check/index.js.map +1 -0
- package/dist/check/layout.d.ts +136 -0
- package/dist/check/layout.d.ts.map +1 -0
- package/dist/check/layout.js +262 -0
- package/dist/check/layout.js.map +1 -0
- package/dist/check/ledger.d.ts +98 -0
- package/dist/check/ledger.d.ts.map +1 -0
- package/dist/check/ledger.js +173 -0
- package/dist/check/ledger.js.map +1 -0
- package/dist/check/peer-owners.d.ts +116 -0
- package/dist/check/peer-owners.d.ts.map +1 -0
- package/dist/check/peer-owners.js +225 -0
- package/dist/check/peer-owners.js.map +1 -0
- package/dist/check/report.d.ts +33 -0
- package/dist/check/report.d.ts.map +1 -0
- package/dist/check/report.js +107 -0
- package/dist/check/report.js.map +1 -0
- package/dist/check/run.d.ts +147 -0
- package/dist/check/run.d.ts.map +1 -0
- package/dist/check/run.js +111 -0
- package/dist/check/run.js.map +1 -0
- package/dist/checks.d.ts +17 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +17 -0
- package/dist/checks.js.map +1 -0
- package/dist/dev/index.d.ts +83 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +298 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/generate/divergence.d.ts +38 -0
- package/dist/generate/divergence.d.ts.map +1 -0
- package/dist/generate/divergence.js +237 -0
- package/dist/generate/divergence.js.map +1 -0
- package/dist/generate/index.d.ts +90 -0
- package/dist/generate/index.d.ts.map +1 -0
- package/dist/generate/index.js +369 -0
- package/dist/generate/index.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/inputs/declaration.d.ts +18 -0
- package/dist/inputs/declaration.d.ts.map +1 -0
- package/dist/inputs/declaration.js +64 -0
- package/dist/inputs/declaration.js.map +1 -0
- package/dist/inputs/env-file.d.ts +73 -0
- package/dist/inputs/env-file.d.ts.map +1 -0
- package/dist/inputs/env-file.js +134 -0
- package/dist/inputs/env-file.js.map +1 -0
- package/dist/inputs/prompt.d.ts +21 -0
- package/dist/inputs/prompt.d.ts.map +1 -0
- package/dist/inputs/prompt.js +59 -0
- package/dist/inputs/prompt.js.map +1 -0
- package/dist/inputs/resolve.d.ts +163 -0
- package/dist/inputs/resolve.d.ts.map +1 -0
- package/dist/inputs/resolve.js +290 -0
- package/dist/inputs/resolve.js.map +1 -0
- package/dist/install/host.d.ts +27 -0
- package/dist/install/host.d.ts.map +1 -0
- package/dist/install/host.js +90 -0
- package/dist/install/host.js.map +1 -0
- package/dist/install/index.d.ts +173 -0
- package/dist/install/index.d.ts.map +1 -0
- package/dist/install/index.js +793 -0
- package/dist/install/index.js.map +1 -0
- package/dist/install/wizard.d.ts +144 -0
- package/dist/install/wizard.d.ts.map +1 -0
- package/dist/install/wizard.js +362 -0
- package/dist/install/wizard.js.map +1 -0
- package/dist/lib/admin-artefacts.d.ts +70 -0
- package/dist/lib/admin-artefacts.d.ts.map +1 -0
- package/dist/lib/admin-artefacts.js +354 -0
- package/dist/lib/admin-artefacts.js.map +1 -0
- package/dist/lib/admin-surfaces.d.ts +298 -0
- package/dist/lib/admin-surfaces.d.ts.map +1 -0
- package/dist/lib/admin-surfaces.js +669 -0
- package/dist/lib/admin-surfaces.js.map +1 -0
- package/dist/lib/delegated-composer.d.ts +85 -0
- package/dist/lib/delegated-composer.d.ts.map +1 -0
- package/dist/lib/delegated-composer.js +241 -0
- package/dist/lib/delegated-composer.js.map +1 -0
- package/dist/lib/divergence-artefacts.d.ts +305 -0
- package/dist/lib/divergence-artefacts.d.ts.map +1 -0
- package/dist/lib/divergence-artefacts.js +828 -0
- package/dist/lib/divergence-artefacts.js.map +1 -0
- package/dist/lib/divergence.d.ts +337 -0
- package/dist/lib/divergence.d.ts.map +1 -0
- package/dist/lib/divergence.js +1005 -0
- package/dist/lib/divergence.js.map +1 -0
- package/dist/lib/docs-artefacts.d.ts +395 -0
- package/dist/lib/docs-artefacts.d.ts.map +1 -0
- package/dist/lib/docs-artefacts.js +781 -0
- package/dist/lib/docs-artefacts.js.map +1 -0
- package/dist/lib/emitted-exports.d.ts +21 -0
- package/dist/lib/emitted-exports.d.ts.map +1 -0
- package/dist/lib/emitted-exports.js +96 -0
- package/dist/lib/emitted-exports.js.map +1 -0
- package/dist/lib/emitted-freshness.d.ts +112 -0
- package/dist/lib/emitted-freshness.d.ts.map +1 -0
- package/dist/lib/emitted-freshness.js +288 -0
- package/dist/lib/emitted-freshness.js.map +1 -0
- package/dist/lib/entity-index-artefact.d.ts +95 -0
- package/dist/lib/entity-index-artefact.d.ts.map +1 -0
- package/dist/lib/entity-index-artefact.js +210 -0
- package/dist/lib/entity-index-artefact.js.map +1 -0
- package/dist/lib/instance-build-inputs.d.ts +108 -0
- package/dist/lib/instance-build-inputs.d.ts.map +1 -0
- package/dist/lib/instance-build-inputs.js +165 -0
- package/dist/lib/instance-build-inputs.js.map +1 -0
- package/dist/lib/module-docs.d.ts +473 -0
- package/dist/lib/module-docs.d.ts.map +1 -0
- package/dist/lib/module-docs.js +711 -0
- package/dist/lib/module-docs.js.map +1 -0
- package/dist/lib/module-package-subpaths.d.ts +56 -0
- package/dist/lib/module-package-subpaths.d.ts.map +1 -0
- package/dist/lib/module-package-subpaths.js +223 -0
- package/dist/lib/module-package-subpaths.js.map +1 -0
- package/dist/lib/module-packages.d.ts +200 -0
- package/dist/lib/module-packages.d.ts.map +1 -0
- package/dist/lib/module-packages.js +580 -0
- package/dist/lib/module-packages.js.map +1 -0
- package/dist/lib/module-population.d.ts +129 -0
- package/dist/lib/module-population.d.ts.map +1 -0
- package/dist/lib/module-population.js +172 -0
- package/dist/lib/module-population.js.map +1 -0
- package/dist/lib/module-roots.d.ts +337 -0
- package/dist/lib/module-roots.d.ts.map +1 -0
- package/dist/lib/module-roots.js +586 -0
- package/dist/lib/module-roots.js.map +1 -0
- package/dist/lib/nested-checkouts.d.ts +33 -0
- package/dist/lib/nested-checkouts.d.ts.map +1 -0
- package/dist/lib/nested-checkouts.js +160 -0
- package/dist/lib/nested-checkouts.js.map +1 -0
- package/dist/lib/platform-root.d.ts +43 -0
- package/dist/lib/platform-root.d.ts.map +1 -0
- package/dist/lib/platform-root.js +134 -0
- package/dist/lib/platform-root.js.map +1 -0
- package/dist/lib/platform-surface.d.ts +235 -0
- package/dist/lib/platform-surface.d.ts.map +1 -0
- package/dist/lib/platform-surface.js +393 -0
- package/dist/lib/platform-surface.js.map +1 -0
- package/dist/lib/port-registrations.d.ts +223 -0
- package/dist/lib/port-registrations.d.ts.map +1 -0
- package/dist/lib/port-registrations.js +532 -0
- package/dist/lib/port-registrations.js.map +1 -0
- package/dist/lib/read-size.d.ts +154 -0
- package/dist/lib/read-size.d.ts.map +1 -0
- package/dist/lib/read-size.js +182 -0
- package/dist/lib/read-size.js.map +1 -0
- package/dist/lib/registration-owners.d.ts +79 -0
- package/dist/lib/registration-owners.d.ts.map +1 -0
- package/dist/lib/registration-owners.js +77 -0
- package/dist/lib/registration-owners.js.map +1 -0
- package/dist/lib/release-index.d.ts +53 -0
- package/dist/lib/release-index.d.ts.map +1 -0
- package/dist/lib/release-index.js +162 -0
- package/dist/lib/release-index.js.map +1 -0
- package/dist/lib/repeating-timers.d.ts +79 -0
- package/dist/lib/repeating-timers.d.ts.map +1 -0
- package/dist/lib/repeating-timers.js +189 -0
- package/dist/lib/repeating-timers.js.map +1 -0
- package/dist/lib/source-text.d.ts +34 -0
- package/dist/lib/source-text.d.ts.map +1 -0
- package/dist/lib/source-text.js +80 -0
- package/dist/lib/source-text.js.map +1 -0
- package/dist/lib/specifiers.d.ts +20 -0
- package/dist/lib/specifiers.d.ts.map +1 -0
- package/dist/lib/specifiers.js +130 -0
- package/dist/lib/specifiers.js.map +1 -0
- package/dist/lib/sql-tables.d.ts +166 -0
- package/dist/lib/sql-tables.d.ts.map +1 -0
- package/dist/lib/sql-tables.js +464 -0
- package/dist/lib/sql-tables.js.map +1 -0
- package/dist/lib/switchable-modules.d.ts +54 -0
- package/dist/lib/switchable-modules.d.ts.map +1 -0
- package/dist/lib/switchable-modules.js +104 -0
- package/dist/lib/switchable-modules.js.map +1 -0
- package/dist/lib/tailwind-sources.d.ts +136 -0
- package/dist/lib/tailwind-sources.d.ts.map +1 -0
- package/dist/lib/tailwind-sources.js +307 -0
- package/dist/lib/tailwind-sources.js.map +1 -0
- package/dist/lib/ui-layer.d.ts +54 -0
- package/dist/lib/ui-layer.d.ts.map +1 -0
- package/dist/lib/ui-layer.js +57 -0
- package/dist/lib/ui-layer.js.map +1 -0
- package/dist/lib/workspace-packages.d.ts +186 -0
- package/dist/lib/workspace-packages.d.ts.map +1 -0
- package/dist/lib/workspace-packages.js +351 -0
- package/dist/lib/workspace-packages.js.map +1 -0
- package/dist/new-instance/deploy.d.ts +211 -0
- package/dist/new-instance/deploy.d.ts.map +1 -0
- package/dist/new-instance/deploy.js +1381 -0
- package/dist/new-instance/deploy.js.map +1 -0
- package/dist/new-instance/docs-toolchain.d.ts +66 -0
- package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
- package/dist/new-instance/docs-toolchain.js +69 -0
- package/dist/new-instance/docs-toolchain.js.map +1 -0
- package/dist/new-instance/host.d.ts +124 -0
- package/dist/new-instance/host.d.ts.map +1 -0
- package/dist/new-instance/host.js +276 -0
- package/dist/new-instance/host.js.map +1 -0
- package/dist/new-instance/index.d.ts +118 -0
- package/dist/new-instance/index.d.ts.map +1 -0
- package/dist/new-instance/index.js +567 -0
- package/dist/new-instance/index.js.map +1 -0
- package/dist/new-instance/modules.d.ts +188 -0
- package/dist/new-instance/modules.d.ts.map +1 -0
- package/dist/new-instance/modules.js +392 -0
- package/dist/new-instance/modules.js.map +1 -0
- package/dist/new-instance/template.d.ts +505 -0
- package/dist/new-instance/template.d.ts.map +1 -0
- package/dist/new-instance/template.js +1886 -0
- package/dist/new-instance/template.js.map +1 -0
- package/dist/new-module/emit.d.ts +67 -0
- package/dist/new-module/emit.d.ts.map +1 -0
- package/dist/new-module/emit.js +1393 -0
- package/dist/new-module/emit.js.map +1 -0
- package/dist/new-module/host.d.ts +67 -0
- package/dist/new-module/host.d.ts.map +1 -0
- package/dist/new-module/host.js +224 -0
- package/dist/new-module/host.js.map +1 -0
- package/dist/new-module/index.d.ts +32 -0
- package/dist/new-module/index.d.ts.map +1 -0
- package/dist/new-module/index.js +193 -0
- package/dist/new-module/index.js.map +1 -0
- package/dist/new-module/spec.d.ts +188 -0
- package/dist/new-module/spec.d.ts.map +1 -0
- package/dist/new-module/spec.js +404 -0
- package/dist/new-module/spec.js.map +1 -0
- package/dist/new-module/text.d.ts +15 -0
- package/dist/new-module/text.d.ts.map +1 -0
- package/dist/new-module/text.js +22 -0
- package/dist/new-module/text.js.map +1 -0
- package/dist/new-storefront/dockerfile.d.ts +20 -0
- package/dist/new-storefront/dockerfile.d.ts.map +1 -0
- package/dist/new-storefront/dockerfile.js +131 -0
- package/dist/new-storefront/dockerfile.js.map +1 -0
- package/dist/new-storefront/gitignore.d.ts +23 -0
- package/dist/new-storefront/gitignore.d.ts.map +1 -0
- package/dist/new-storefront/gitignore.js +39 -0
- package/dist/new-storefront/gitignore.js.map +1 -0
- package/dist/new-storefront/index.d.ts +93 -0
- package/dist/new-storefront/index.d.ts.map +1 -0
- package/dist/new-storefront/index.js +329 -0
- package/dist/new-storefront/index.js.map +1 -0
- package/dist/new-storefront/npmrc.d.ts +98 -0
- package/dist/new-storefront/npmrc.d.ts.map +1 -0
- package/dist/new-storefront/npmrc.js +217 -0
- package/dist/new-storefront/npmrc.js.map +1 -0
- package/dist/new-storefront/reference.d.ts +189 -0
- package/dist/new-storefront/reference.d.ts.map +1 -0
- package/dist/new-storefront/reference.js +430 -0
- package/dist/new-storefront/reference.js.map +1 -0
- package/dist/new-storefront/rewrite.d.ts +171 -0
- package/dist/new-storefront/rewrite.d.ts.map +1 -0
- package/dist/new-storefront/rewrite.js +701 -0
- package/dist/new-storefront/rewrite.js.map +1 -0
- package/dist/release-index.json +284 -0
- package/dist/rules/action-route-permissions.d.ts +141 -0
- package/dist/rules/action-route-permissions.d.ts.map +1 -0
- package/dist/rules/action-route-permissions.js +556 -0
- package/dist/rules/action-route-permissions.js.map +1 -0
- package/dist/rules/bundle-pairing.d.ts +74 -0
- package/dist/rules/bundle-pairing.d.ts.map +1 -0
- package/dist/rules/bundle-pairing.js +281 -0
- package/dist/rules/bundle-pairing.js.map +1 -0
- package/dist/rules/channel-resolution.d.ts +17 -0
- package/dist/rules/channel-resolution.d.ts.map +1 -0
- package/dist/rules/channel-resolution.js +382 -0
- package/dist/rules/channel-resolution.js.map +1 -0
- package/dist/rules/command-coverage.d.ts +210 -0
- package/dist/rules/command-coverage.d.ts.map +1 -0
- package/dist/rules/command-coverage.js +714 -0
- package/dist/rules/command-coverage.js.map +1 -0
- package/dist/rules/container-imports.d.ts +60 -0
- package/dist/rules/container-imports.d.ts.map +1 -0
- package/dist/rules/container-imports.js +158 -0
- package/dist/rules/container-imports.js.map +1 -0
- package/dist/rules/default-language-prose.d.ts +212 -0
- package/dist/rules/default-language-prose.d.ts.map +1 -0
- package/dist/rules/default-language-prose.js +710 -0
- package/dist/rules/default-language-prose.js.map +1 -0
- package/dist/rules/diacritic-folds.d.ts +238 -0
- package/dist/rules/diacritic-folds.d.ts.map +1 -0
- package/dist/rules/diacritic-folds.js +681 -0
- package/dist/rules/diacritic-folds.js.map +1 -0
- package/dist/rules/entity-tenant-classification.d.ts +171 -0
- package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
- package/dist/rules/entity-tenant-classification.js +323 -0
- package/dist/rules/entity-tenant-classification.js.map +1 -0
- package/dist/rules/entry-presence.d.ts +142 -0
- package/dist/rules/entry-presence.d.ts.map +1 -0
- package/dist/rules/entry-presence.js +339 -0
- package/dist/rules/entry-presence.js.map +1 -0
- package/dist/rules/entry-scope.d.ts +91 -0
- package/dist/rules/entry-scope.d.ts.map +1 -0
- package/dist/rules/entry-scope.js +404 -0
- package/dist/rules/entry-scope.js.map +1 -0
- package/dist/rules/env-inputs.d.ts +222 -0
- package/dist/rules/env-inputs.d.ts.map +1 -0
- package/dist/rules/env-inputs.js +951 -0
- package/dist/rules/env-inputs.js.map +1 -0
- package/dist/rules/kernel-boundary.d.ts +37 -0
- package/dist/rules/kernel-boundary.d.ts.map +1 -0
- package/dist/rules/kernel-boundary.js +195 -0
- package/dist/rules/kernel-boundary.js.map +1 -0
- package/dist/rules/nul-bytes.d.ts +233 -0
- package/dist/rules/nul-bytes.d.ts.map +1 -0
- package/dist/rules/nul-bytes.js +332 -0
- package/dist/rules/nul-bytes.js.map +1 -0
- package/dist/rules/platform-surface.d.ts +479 -0
- package/dist/rules/platform-surface.d.ts.map +1 -0
- package/dist/rules/platform-surface.js +749 -0
- package/dist/rules/platform-surface.js.map +1 -0
- package/dist/rules/port-catches.d.ts +225 -0
- package/dist/rules/port-catches.d.ts.map +1 -0
- package/dist/rules/port-catches.js +1374 -0
- package/dist/rules/port-catches.js.map +1 -0
- package/dist/rules/port-shape.d.ts +213 -0
- package/dist/rules/port-shape.d.ts.map +1 -0
- package/dist/rules/port-shape.js +670 -0
- package/dist/rules/port-shape.js.map +1 -0
- package/dist/rules/queue-names.d.ts +108 -0
- package/dist/rules/queue-names.d.ts.map +1 -0
- package/dist/rules/queue-names.js +395 -0
- package/dist/rules/queue-names.js.map +1 -0
- package/dist/rules/singleton-identity.d.ts +205 -0
- package/dist/rules/singleton-identity.d.ts.map +1 -0
- package/dist/rules/singleton-identity.js +830 -0
- package/dist/rules/singleton-identity.js.map +1 -0
- package/dist/rules/subscribe-seam.d.ts +121 -0
- package/dist/rules/subscribe-seam.d.ts.map +1 -0
- package/dist/rules/subscribe-seam.js +594 -0
- package/dist/rules/subscribe-seam.js.map +1 -0
- package/dist/rules/transaction-context.d.ts +40 -0
- package/dist/rules/transaction-context.d.ts.map +1 -0
- package/dist/rules/transaction-context.js +294 -0
- package/dist/rules/transaction-context.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI check — a manifest action's `requiredPermission` is the code enforced on
|
|
3
|
+
* the route behind its own `targetRoute` (issue #232; Principle XVI item 2, "the
|
|
4
|
+
* code gating the target surface, so the palette never advertises a 403").
|
|
5
|
+
*
|
|
6
|
+
* `test/contract/admin_users/permission-inventory.test.ts` already sweeps two
|
|
7
|
+
* directions — every enforced code is grantable, every grantable code is
|
|
8
|
+
* enforced — and **both** of the defects that produced this check passed it,
|
|
9
|
+
* because both codes were real, declared and enforced somewhere:
|
|
10
|
+
*
|
|
11
|
+
* - `settings`' `open-settings` action declared no `requiredPermission` at all
|
|
12
|
+
* while `/api/v1/admin/settings` is `requireAdmin('settings:read')`, so ⌘K
|
|
13
|
+
* offered the screen to every role and every role without the code collected
|
|
14
|
+
* a guaranteed 403;
|
|
15
|
+
* - `inventory`' `open-inventory` declared `catalog:write` while
|
|
16
|
+
* `/api/v1/admin/inventory` is `requireAdmin('orders:read')` — wrong in both
|
|
17
|
+
* directions at once, hiding the screen from operators who can open it and
|
|
18
|
+
* offering it to some who cannot.
|
|
19
|
+
*
|
|
20
|
+
* Neither is visible to a sweep over the *set* of codes. The third direction —
|
|
21
|
+
* the code is the one enforced on **this action's** target — is what this check
|
|
22
|
+
* adds.
|
|
23
|
+
*
|
|
24
|
+
* ## What "agrees" means
|
|
25
|
+
*
|
|
26
|
+
* Permission codes are opaque: `hasPermission(userId, code)` compares strings
|
|
27
|
+
* (plus the `'*'` wildcard), so `catalog:write` does not imply `catalog:read`.
|
|
28
|
+
* The property is therefore **sufficiency**, not equality: *holding the declared
|
|
29
|
+
* code, and nothing else, must be enough to open the target screen.* For
|
|
30
|
+
* `requireAdmin('x')` that collapses to equality; for
|
|
31
|
+
* `requireAdminAny(['customers:read', 'customers:manage'])` — the one any-of
|
|
32
|
+
* gate in the tree — either member is sufficient and either is accepted.
|
|
33
|
+
*
|
|
34
|
+
* Sufficiency leaves one residue, deliberately: an action naming one member of
|
|
35
|
+
* an any-of gate is hidden from an operator holding only the other member. That
|
|
36
|
+
* is under-advertising, not a 403, and the manifest field is a single code, so
|
|
37
|
+
* the palette cannot express the alternative. The sidebar can (MR !736 gave
|
|
38
|
+
* `NavItem.requiredPermission` an any-of array for exactly this route); a
|
|
39
|
+
* manifest action cannot, and widening the contract for one route is not
|
|
40
|
+
* something this check should force.
|
|
41
|
+
*
|
|
42
|
+
* ## Which route is "the" route
|
|
43
|
+
*
|
|
44
|
+
* A `targetRoute` is an admin SPA path (`/inventory`), not an API path
|
|
45
|
+
* (`/api/v1/admin/inventory`), and nothing in the tree declares the link. The
|
|
46
|
+
* check reconstructs it as the **entry route**: the request the browser must be
|
|
47
|
+
* allowed to make for the screen to render at all. Resolution runs in levels,
|
|
48
|
+
* first non-empty level wins, and stops at the first level that answers:
|
|
49
|
+
*
|
|
50
|
+
* 1. **exact** — a registration at `/api/v1/admin` + the target;
|
|
51
|
+
* 2. **subtree** — the shallowest registrations under it, for a screen whose
|
|
52
|
+
* data hangs off sub-resources (`/custom-fields` →
|
|
53
|
+
* `/api/v1/admin/custom-fields/definitions`);
|
|
54
|
+
* 3. **module** — the shallowest registrations the owning module ships at all,
|
|
55
|
+
* for a screen whose SPA placement is not its API path (`/settings/stripe`
|
|
56
|
+
* is placed under Settings; its API is `/api/v1/admin/stripe/config`).
|
|
57
|
+
*
|
|
58
|
+
* An action targeting `/x/new` is a create form, so the parent path is resolved
|
|
59
|
+
* instead and the method class flips from GET to the write verbs: the gate that
|
|
60
|
+
* decides whether that form can be submitted is the POST's, not the list's.
|
|
61
|
+
*
|
|
62
|
+
* Where the shallowest candidates disagree on their gate, or where a selected
|
|
63
|
+
* gate is a `preHandler` the scanner cannot read, the action is reported
|
|
64
|
+
* `unresolvable` rather than compared against a guess. An entry route that gates
|
|
65
|
+
* on **no** code accepts any declaration: holding a code the route does not ask
|
|
66
|
+
* for still opens the screen, so it cannot produce a 403 — it can only
|
|
67
|
+
* under-advertise, and no shipped action does.
|
|
68
|
+
*
|
|
69
|
+
* What the check cannot settle is where the label promises a write and the
|
|
70
|
+
* screen opens on a read: one field cannot say both codes, and
|
|
71
|
+
* `ACTION_PERMISSION_DISAGREEMENTS` holds those three with the question that
|
|
72
|
+
* would retire each.
|
|
73
|
+
*
|
|
74
|
+
* ## The artefact this reads, and when it refuses to judge it
|
|
75
|
+
*
|
|
76
|
+
* The route half is source text, walked. The **manifest** half is imported, and
|
|
77
|
+
* a module that has become a workspace package resolves through its own
|
|
78
|
+
* `exports` map at its build output (D-164) — so an action edited in
|
|
79
|
+
* `packages/modules/<id>/src/manifest.ts` and not rebuilt is not the action
|
|
80
|
+
* this check sees. Measured three consecutive times on
|
|
81
|
+
* `specs/091-module-owned-admin-surfaces/`'s admin drain, most sharply on
|
|
82
|
+
* !1203, where a `requiredPermission` changed from `payu:read` to `payu:write`
|
|
83
|
+
* reported `findings=3 violations=0` and exit 0 before
|
|
84
|
+
* `pnpm --filter @endora-commerce/mod-payu run build`, and `findings=4
|
|
85
|
+
* violations=1` and exit 1 after it. So a run whose manifest artefact is older
|
|
86
|
+
* than the source it was emitted from **exits 2** and names the package: the
|
|
87
|
+
* tree is not in violation, this run could not see it. See
|
|
88
|
+
* `scripts/lib/emitted-freshness.ts`, where the derivation lives, and the
|
|
89
|
+
* `emitted-manifests` token on the `read:` line, which is how a clean run says
|
|
90
|
+
* which artefact it read.
|
|
91
|
+
*
|
|
92
|
+
* Usage: `tsx scripts/check-action-route-permissions.ts [--list]`
|
|
93
|
+
* Exit 0 = every action's declared code is the one its target enforces (or the
|
|
94
|
+
* disagreement is ledgered); exit 1 = at least one is not, or a ledger entry is
|
|
95
|
+
* stale; exit 2 = the scan read no route or no action, or the manifest artefact
|
|
96
|
+
* it read has been outrun by its source — a green would have meant "not
|
|
97
|
+
* looking" (issue #113).
|
|
98
|
+
*
|
|
99
|
+
* ## One analysis, two hosts
|
|
100
|
+
*
|
|
101
|
+
* This file is the analysis (`specs/101-endora-check/contracts/package-scope-layout.md`
|
|
102
|
+
* §6). `backend/scripts/check-action-route-permissions.ts` hosts it over this
|
|
103
|
+
* repository's module walk roots, its overlay root and its emitted manifests,
|
|
104
|
+
* and holds `ACTION_PERMISSION_DISAGREEMENTS` — a ledger of *this* tree's owner
|
|
105
|
+
* decisions, which is why the ledger is an argument rather than a value this
|
|
106
|
+
* file reads.
|
|
107
|
+
*
|
|
108
|
+
* `endora check`'s host lands with Phase 3 and its estate entry says why, with
|
|
109
|
+
* the measurement: half this estate writes a permission code as a module-level
|
|
110
|
+
* constant, the reader that follows one is `admin_roles`' `ConstantResolver`,
|
|
111
|
+
* and no module package can reach it. Without it 27 gates in 11 of the 70
|
|
112
|
+
* module packages read as `unreadable` — findings about correct code, which
|
|
113
|
+
* §5.1 refuses.
|
|
114
|
+
*/
|
|
115
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
116
|
+
import { join } from 'node:path';
|
|
117
|
+
import ts from 'typescript';
|
|
118
|
+
import { moduleIdOf as segmentModuleIdOf, NO_HOST_RESIDENT_MODULES, } from '../lib/module-population.js';
|
|
119
|
+
/** Every admin API path starts here; nothing else is an admin surface. */
|
|
120
|
+
const ADMIN_API_PREFIX = '/api/v1/admin';
|
|
121
|
+
/** The Fastify shorthand methods a route registration can be written as. */
|
|
122
|
+
const ROUTE_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete']);
|
|
123
|
+
/** The verbs a create form submits through — the write half of a surface. */
|
|
124
|
+
const WRITE_METHODS = new Set(['post', 'put', 'patch', 'delete']);
|
|
125
|
+
/** The guard family whose argument is a permission code. */
|
|
126
|
+
const GUARD_NAMES = new Set(['requireAdmin', 'requireAdminAny']);
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Route extraction
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
/** The trailing identifier of a callee: `deps.requireAdmin` → `requireAdmin`. */
|
|
131
|
+
function tailName(node) {
|
|
132
|
+
if (ts.isIdentifier(node))
|
|
133
|
+
return node.text;
|
|
134
|
+
if (ts.isPropertyAccessExpression(node))
|
|
135
|
+
return node.name.text;
|
|
136
|
+
if (ts.isAsExpression(node) ||
|
|
137
|
+
ts.isNonNullExpression(node) ||
|
|
138
|
+
ts.isParenthesizedExpression(node)) {
|
|
139
|
+
return tailName(node.expression);
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
/** The string a node denotes, through casts. Template literals are handled apart. */
|
|
144
|
+
function stringLiteralOf(node) {
|
|
145
|
+
if (ts.isStringLiteralLike(node) && !ts.isTemplateExpression(node))
|
|
146
|
+
return node.text;
|
|
147
|
+
if (ts.isAsExpression(node) ||
|
|
148
|
+
ts.isNonNullExpression(node) ||
|
|
149
|
+
ts.isParenthesizedExpression(node)) {
|
|
150
|
+
return stringLiteralOf(node.expression);
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
/** Every `const x = <initialiser>` in a file, by name — the local scope this reads. */
|
|
155
|
+
function localBindings(sf) {
|
|
156
|
+
const bindings = new Map();
|
|
157
|
+
const visit = (node) => {
|
|
158
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
159
|
+
// First writer wins: a name re-bound in an inner scope is the exception,
|
|
160
|
+
// and taking the outer one keeps the answer stable across files.
|
|
161
|
+
if (!bindings.has(node.name.text))
|
|
162
|
+
bindings.set(node.name.text, node.initializer);
|
|
163
|
+
}
|
|
164
|
+
node.forEachChild(visit);
|
|
165
|
+
};
|
|
166
|
+
sf.forEachChild(visit);
|
|
167
|
+
return bindings;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The path a route registration's first argument denotes.
|
|
171
|
+
*
|
|
172
|
+
* Two spellings appear: a plain literal, and a template whose head is a
|
|
173
|
+
* module-local `const base = '/api/v1/admin/<module>'` (`newsletter`,
|
|
174
|
+
* `transactional_emails`). A span that cannot be resolved yields `null` — the
|
|
175
|
+
* registration is then not attributed to any target, and the run says how many
|
|
176
|
+
* such there were rather than quietly shrinking the population.
|
|
177
|
+
*/
|
|
178
|
+
function routePathOf(node, bindings) {
|
|
179
|
+
const literal = stringLiteralOf(node);
|
|
180
|
+
if (literal !== null)
|
|
181
|
+
return literal;
|
|
182
|
+
if (ts.isTemplateExpression(node)) {
|
|
183
|
+
let out = node.head.text;
|
|
184
|
+
for (const span of node.templateSpans) {
|
|
185
|
+
const name = ts.isIdentifier(span.expression) ? span.expression.text : null;
|
|
186
|
+
const bound = name === null ? undefined : bindings.get(name);
|
|
187
|
+
const value = bound === undefined ? null : stringLiteralOf(bound);
|
|
188
|
+
if (value === null)
|
|
189
|
+
return null;
|
|
190
|
+
out += value + span.literal.text;
|
|
191
|
+
}
|
|
192
|
+
return out;
|
|
193
|
+
}
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
/** The permission codes a guard call requires, as one clause, or `null`. */
|
|
197
|
+
function clauseOfGuardCall(call, file, input) {
|
|
198
|
+
const [argument] = call.arguments;
|
|
199
|
+
if (argument === undefined)
|
|
200
|
+
return []; // `requireAdmin()` — any authenticated admin.
|
|
201
|
+
const absolute = input.absolutePathOf?.(file) ?? file;
|
|
202
|
+
const lookup = input.lookupConstant ?? (() => null);
|
|
203
|
+
const codeOf = (node) => {
|
|
204
|
+
const literal = stringLiteralOf(node);
|
|
205
|
+
if (literal !== null)
|
|
206
|
+
return literal;
|
|
207
|
+
if (ts.isIdentifier(node))
|
|
208
|
+
return lookup(absolute, node.text, null);
|
|
209
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
210
|
+
return lookup(absolute, node.expression.text, node.name.text);
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
};
|
|
214
|
+
if (ts.isArrayLiteralExpression(argument)) {
|
|
215
|
+
const codes = [];
|
|
216
|
+
for (const element of argument.elements) {
|
|
217
|
+
const code = ts.isSpreadElement(element) ? null : codeOf(element);
|
|
218
|
+
if (code === null)
|
|
219
|
+
return null;
|
|
220
|
+
codes.push(code);
|
|
221
|
+
}
|
|
222
|
+
return codes;
|
|
223
|
+
}
|
|
224
|
+
const code = codeOf(argument);
|
|
225
|
+
return code === null ? null : [code];
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* The gate a route's options argument installs.
|
|
229
|
+
*
|
|
230
|
+
* The shapes present in the tree, all of them resolved module-locally:
|
|
231
|
+
* `{ preHandler: requireAdmin('code') }` and its `deps.`/cradle receivers, the
|
|
232
|
+
* same through a `const guard = requireAdmin(CODE)` binding, an options object
|
|
233
|
+
* held in a `const read = { preHandler: … }` and passed bare or spread
|
|
234
|
+
* (`{ ...write, bodyLimit }`), and an array of pre-handlers.
|
|
235
|
+
*/
|
|
236
|
+
function gateOf(node, file, input, bindings, depth = 0) {
|
|
237
|
+
const text = node === undefined ? '' : node.getText().replace(/\s+/g, ' ').slice(0, 120);
|
|
238
|
+
if (node === undefined || depth > 4)
|
|
239
|
+
return { clauses: node === undefined ? [] : null, text };
|
|
240
|
+
// A handler, not an options object: the registration installs no gate.
|
|
241
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
|
|
242
|
+
return { clauses: [], text: '' };
|
|
243
|
+
if (ts.isIdentifier(node)) {
|
|
244
|
+
const bound = bindings.get(node.text);
|
|
245
|
+
return bound === undefined
|
|
246
|
+
? { clauses: null, text }
|
|
247
|
+
: { ...gateOf(bound, file, input, bindings, depth + 1), text };
|
|
248
|
+
}
|
|
249
|
+
if (ts.isObjectLiteralExpression(node)) {
|
|
250
|
+
const clauses = [];
|
|
251
|
+
let unreadable = false;
|
|
252
|
+
let sawGateSlot = false;
|
|
253
|
+
for (const property of node.properties) {
|
|
254
|
+
if (ts.isSpreadAssignment(property)) {
|
|
255
|
+
const spread = gateOf(property.expression, file, input, bindings, depth + 1);
|
|
256
|
+
if (spread.clauses === null)
|
|
257
|
+
unreadable = true;
|
|
258
|
+
else if (spread.clauses.length > 0) {
|
|
259
|
+
sawGateSlot = true;
|
|
260
|
+
clauses.push(...spread.clauses);
|
|
261
|
+
}
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (!ts.isPropertyAssignment(property) || property.name.getText() !== 'preHandler')
|
|
265
|
+
continue;
|
|
266
|
+
sawGateSlot = true;
|
|
267
|
+
const handlers = ts.isArrayLiteralExpression(property.initializer)
|
|
268
|
+
? property.initializer.elements
|
|
269
|
+
: [property.initializer];
|
|
270
|
+
let recognised = false;
|
|
271
|
+
for (const handler of handlers) {
|
|
272
|
+
const clause = clauseOfPreHandler(handler, file, input, bindings, depth + 1);
|
|
273
|
+
if (clause === undefined)
|
|
274
|
+
continue;
|
|
275
|
+
recognised = true;
|
|
276
|
+
if (clause === null)
|
|
277
|
+
unreadable = true;
|
|
278
|
+
else if (clause.length > 0)
|
|
279
|
+
clauses.push(clause);
|
|
280
|
+
}
|
|
281
|
+
if (!recognised)
|
|
282
|
+
unreadable = true;
|
|
283
|
+
}
|
|
284
|
+
if (unreadable)
|
|
285
|
+
return { clauses: null, text };
|
|
286
|
+
return { clauses: sawGateSlot ? clauses : [], text: sawGateSlot ? text : '' };
|
|
287
|
+
}
|
|
288
|
+
return { clauses: null, text };
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* One pre-handler's clause: `null` when it is a guard whose code cannot be read,
|
|
292
|
+
* `undefined` when it is not a permission guard at all (an ETag validator, a
|
|
293
|
+
* rate limiter — those gate nothing this check is about).
|
|
294
|
+
*/
|
|
295
|
+
function clauseOfPreHandler(node, file, input, bindings, depth) {
|
|
296
|
+
if (depth > 6)
|
|
297
|
+
return null;
|
|
298
|
+
// `deps.requireAdmin?.('blog.write') ?? (async () => {})` — the guard is the
|
|
299
|
+
// left operand and the fallback is a no-op the harness never takes. Reading
|
|
300
|
+
// the `??` as unreadable is what hid `blog`'s and `cms`'s gates from a first
|
|
301
|
+
// draft of this check.
|
|
302
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) {
|
|
303
|
+
return clauseOfPreHandler(node.left, file, input, bindings, depth + 1);
|
|
304
|
+
}
|
|
305
|
+
if (ts.isCallExpression(node)) {
|
|
306
|
+
const callee = tailName(node.expression);
|
|
307
|
+
if (callee !== null && GUARD_NAMES.has(callee))
|
|
308
|
+
return clauseOfGuardCall(node, file, input);
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
if (ts.isIdentifier(node)) {
|
|
312
|
+
const bound = bindings.get(node.text);
|
|
313
|
+
return bound === undefined ? undefined : clauseOfPreHandler(bound, file, input, bindings, depth + 1);
|
|
314
|
+
}
|
|
315
|
+
if (ts.isObjectLiteralExpression(node) || ts.isArrayLiteralExpression(node))
|
|
316
|
+
return null;
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
/** Every `/api/v1/admin/**` route registration under `sources`, with its gate. */
|
|
320
|
+
export function findAdminRoutes(input) {
|
|
321
|
+
const routes = [];
|
|
322
|
+
let unreadablePaths = 0;
|
|
323
|
+
for (const [file, text] of input.sources) {
|
|
324
|
+
if (!text.includes(ADMIN_API_PREFIX))
|
|
325
|
+
continue;
|
|
326
|
+
const sf = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
327
|
+
const bindings = localBindings(sf);
|
|
328
|
+
const moduleId = moduleIdOf(file, input.hostResidentModules);
|
|
329
|
+
const visit = (node) => {
|
|
330
|
+
if (ts.isCallExpression(node) &&
|
|
331
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
332
|
+
ROUTE_METHODS.has(node.expression.name.text) &&
|
|
333
|
+
node.arguments.length >= 2) {
|
|
334
|
+
const [pathArgument, optionsArgument] = node.arguments;
|
|
335
|
+
if (pathArgument !== undefined) {
|
|
336
|
+
const looksLikePath = ts.isStringLiteralLike(pathArgument) || ts.isTemplateExpression(pathArgument);
|
|
337
|
+
const path = looksLikePath ? routePathOf(pathArgument, bindings) : null;
|
|
338
|
+
if (looksLikePath && path === null && pathArgument.getText().includes(ADMIN_API_PREFIX)) {
|
|
339
|
+
unreadablePaths += 1;
|
|
340
|
+
}
|
|
341
|
+
if (path !== null && path.startsWith(ADMIN_API_PREFIX)) {
|
|
342
|
+
const gate = gateOf(optionsArgument, file, input, bindings);
|
|
343
|
+
routes.push({
|
|
344
|
+
file,
|
|
345
|
+
line: sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1,
|
|
346
|
+
method: node.expression.name.text,
|
|
347
|
+
path,
|
|
348
|
+
moduleId,
|
|
349
|
+
clauses: gate.clauses,
|
|
350
|
+
gateText: gate.text,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
node.forEachChild(visit);
|
|
356
|
+
};
|
|
357
|
+
sf.forEachChild(visit);
|
|
358
|
+
}
|
|
359
|
+
routes.sort((a, b) => (a.path === b.path ? a.method.localeCompare(b.method) : a.path.localeCompare(b.path)));
|
|
360
|
+
return { routes, unreadablePaths };
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* The module a source key belongs to, or `null` outside every module tree.
|
|
364
|
+
*
|
|
365
|
+
* The two anchored answers are the application's, on keys relative to its own
|
|
366
|
+
* `src/`. The third is `lib/module-population.ts`' segment reader, which is what
|
|
367
|
+
* attributes a module that has become a workspace package — its key is
|
|
368
|
+
* repository-relative and starts with neither `modules` nor `apps` (feature
|
|
369
|
+
* 080, T040a).
|
|
370
|
+
*/
|
|
371
|
+
export function moduleIdOf(file, hostResident = NO_HOST_RESIDENT_MODULES) {
|
|
372
|
+
const segments = file.split('/');
|
|
373
|
+
if (segments[0] === 'modules')
|
|
374
|
+
return segments[1] ?? null;
|
|
375
|
+
// `apps/<deployment>/modules/<id>/…` — an overlay module is an ordinary
|
|
376
|
+
// lifecycle participant and owns its actions the same way (feature 057).
|
|
377
|
+
if (segments[0] === 'apps' && segments[2] === 'modules')
|
|
378
|
+
return segments[3] ?? null;
|
|
379
|
+
return segmentModuleIdOf(file, hostResident);
|
|
380
|
+
}
|
|
381
|
+
const depthOf = (path) => path.split('/').length;
|
|
382
|
+
function shallowest(routes) {
|
|
383
|
+
if (routes.length === 0)
|
|
384
|
+
return routes;
|
|
385
|
+
const min = Math.min(...routes.map((route) => depthOf(route.path)));
|
|
386
|
+
return routes.filter((route) => depthOf(route.path) === min);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The entry route for an action's target, or `null` when no registration
|
|
390
|
+
* corresponds to it at all — which is a defect of its own: a palette entry must
|
|
391
|
+
* point at a real surface.
|
|
392
|
+
*/
|
|
393
|
+
export function resolveTarget(action, routes) {
|
|
394
|
+
const creating = action.targetRoute.endsWith('/new');
|
|
395
|
+
const path = creating ? action.targetRoute.slice(0, -'/new'.length) : action.targetRoute;
|
|
396
|
+
const wanted = (route) => creating ? WRITE_METHODS.has(route.method) : route.method === 'get';
|
|
397
|
+
const base = ADMIN_API_PREFIX + path;
|
|
398
|
+
const exact = routes.filter((route) => route.path === base && wanted(route));
|
|
399
|
+
if (exact.length > 0)
|
|
400
|
+
return { level: 'exact', routes: shallowest(exact) };
|
|
401
|
+
const subtree = routes.filter((route) => route.path.startsWith(`${base}/`) && wanted(route));
|
|
402
|
+
if (subtree.length > 0)
|
|
403
|
+
return { level: 'subtree', routes: shallowest(subtree) };
|
|
404
|
+
const owned = routes.filter((route) => route.moduleId === action.moduleId && wanted(route));
|
|
405
|
+
if (owned.length > 0)
|
|
406
|
+
return { level: 'module', routes: shallowest(closestTo(path, owned)) };
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* The module-level candidates whose path names most of the target's segments.
|
|
411
|
+
*
|
|
412
|
+
* At this level the SPA path and the API path have already been established not
|
|
413
|
+
* to correspond, so "shallowest" alone picks by accident: `/platform/modules`
|
|
414
|
+
* would compare against `/api/v1/admin/api-interceptors` as readily as against
|
|
415
|
+
* `/api/v1/admin/modules`, and the two carry different gates. Ranking by shared
|
|
416
|
+
* segment names first keeps the comparison against the route the screen is
|
|
417
|
+
* actually named after, and leaves the ambiguity report for the case where
|
|
418
|
+
* nothing distinguishes the candidates.
|
|
419
|
+
*/
|
|
420
|
+
function closestTo(target, routes) {
|
|
421
|
+
const wanted = new Set(target.split('/').filter((segment) => segment.length > 0));
|
|
422
|
+
const score = (route) => route.path
|
|
423
|
+
.slice(ADMIN_API_PREFIX.length)
|
|
424
|
+
.split('/')
|
|
425
|
+
.filter((segment) => wanted.has(segment)).length;
|
|
426
|
+
const best = Math.max(...routes.map(score));
|
|
427
|
+
return routes.filter((route) => score(route) === best);
|
|
428
|
+
}
|
|
429
|
+
/** Whether holding `code` alone passes a gate. Membership in every clause. */
|
|
430
|
+
export function isSufficient(code, clauses) {
|
|
431
|
+
return clauses.every((clause) => clause.includes(code));
|
|
432
|
+
}
|
|
433
|
+
/** A gate's clauses as a stable string, so two candidates can be compared. */
|
|
434
|
+
function gateKey(clauses) {
|
|
435
|
+
return clauses === null ? '<unreadable>' : JSON.stringify(clauses.map((c) => [...c].sort()));
|
|
436
|
+
}
|
|
437
|
+
/** `<moduleId>:<actionId>` — the ledger key, and the identity of a finding. */
|
|
438
|
+
export function keyOf(finding) {
|
|
439
|
+
return `${finding.moduleId}:${finding.actionId}`;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* A route's permission clauses, rendered for a message. Exported because the
|
|
443
|
+
* sentence is part of the rule: an author outside this checkout reads the same
|
|
444
|
+
* one this repository's run prints.
|
|
445
|
+
*/
|
|
446
|
+
export function renderClauses(clauses) {
|
|
447
|
+
if (clauses.length === 0)
|
|
448
|
+
return '(no code — any authenticated admin)';
|
|
449
|
+
return clauses.map((clause) => (clause.length === 1 ? clause[0] : `any of [${clause.join(', ')}]`)).join(' and ');
|
|
450
|
+
}
|
|
451
|
+
/** Every action whose declared code is not the one its target enforces. */
|
|
452
|
+
export function findDisagreements(input) {
|
|
453
|
+
const findings = [];
|
|
454
|
+
for (const action of input.actions) {
|
|
455
|
+
const base = {
|
|
456
|
+
moduleId: action.moduleId,
|
|
457
|
+
actionId: action.actionId,
|
|
458
|
+
targetRoute: action.targetRoute,
|
|
459
|
+
declared: action.requiredPermission ?? null,
|
|
460
|
+
};
|
|
461
|
+
const resolved = resolveTarget(action, input.routes);
|
|
462
|
+
if (resolved === null) {
|
|
463
|
+
findings.push({
|
|
464
|
+
...base,
|
|
465
|
+
kind: 'unresolvable',
|
|
466
|
+
enforced: '(no registration)',
|
|
467
|
+
where: `no /api/v1/admin route corresponds to ${action.targetRoute}, and ${action.moduleId} registers none`,
|
|
468
|
+
});
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
const keys = new Set(resolved.routes.map((route) => gateKey(route.clauses)));
|
|
472
|
+
const [first] = resolved.routes;
|
|
473
|
+
if (first === undefined)
|
|
474
|
+
continue;
|
|
475
|
+
if (keys.size > 1) {
|
|
476
|
+
findings.push({
|
|
477
|
+
...base,
|
|
478
|
+
kind: 'unresolvable',
|
|
479
|
+
enforced: '(ambiguous)',
|
|
480
|
+
where: `the ${resolved.level}-level candidates for ${action.targetRoute} disagree: ` +
|
|
481
|
+
resolved.routes
|
|
482
|
+
.map((route) => `${route.method.toUpperCase()} ${route.path} → ${renderClauses(route.clauses ?? [])}`)
|
|
483
|
+
.join('; '),
|
|
484
|
+
});
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
if (first.clauses === null) {
|
|
488
|
+
findings.push({
|
|
489
|
+
...base,
|
|
490
|
+
kind: 'unresolvable',
|
|
491
|
+
enforced: '(unreadable gate)',
|
|
492
|
+
where: `${first.file}:${first.line} — preHandler \`${first.gateText}\` could not be read`,
|
|
493
|
+
});
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
const clauses = first.clauses;
|
|
497
|
+
const where = `${first.method.toUpperCase()} ${first.path} (${first.file}:${first.line}, ${resolved.level})`;
|
|
498
|
+
if (action.requiredPermission === undefined) {
|
|
499
|
+
if (clauses.length === 0)
|
|
500
|
+
continue; // Ungated surface, undeclared action — agreed.
|
|
501
|
+
findings.push({ ...base, kind: 'missing', enforced: renderClauses(clauses), where });
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (!isSufficient(action.requiredPermission, clauses)) {
|
|
505
|
+
findings.push({ ...base, kind: 'mismatched', enforced: renderClauses(clauses), where });
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return findings.sort((a, b) => keyOf(a).localeCompare(keyOf(b)));
|
|
509
|
+
}
|
|
510
|
+
export function checkActionRoutePermissions(input, ledger) {
|
|
511
|
+
const findings = findDisagreements(input);
|
|
512
|
+
const keys = new Set(findings.map(keyOf));
|
|
513
|
+
return {
|
|
514
|
+
findings,
|
|
515
|
+
violations: findings.filter((finding) => ledger[keyOf(finding)] === undefined),
|
|
516
|
+
ledgered: findings.filter((finding) => ledger[keyOf(finding)] !== undefined),
|
|
517
|
+
stale: Object.keys(ledger).filter((key) => !keys.has(key)),
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* The whole analysis, source text in and findings out — the entry a real run
|
|
522
|
+
* takes and the one a red proof has to take with it (issue #130). A fixture
|
|
523
|
+
* handed a ready-made `AdminRoute[]` would prove the comparison and skip the
|
|
524
|
+
* route reading the comparison rests on, which is where every gate shape lives.
|
|
525
|
+
*/
|
|
526
|
+
export function analyse(input, ledger) {
|
|
527
|
+
const scan = findAdminRoutes(input);
|
|
528
|
+
return { ...checkActionRoutePermissions({ actions: input.actions, routes: scan.routes }, ledger), scan };
|
|
529
|
+
}
|
|
530
|
+
// ---------------------------------------------------------------------------
|
|
531
|
+
// CLI
|
|
532
|
+
// ---------------------------------------------------------------------------
|
|
533
|
+
/**
|
|
534
|
+
* Every TypeScript source under `dir`, with the rule's own prunes applied.
|
|
535
|
+
*
|
|
536
|
+
* Exported because the population is part of the rule: two hosts computing
|
|
537
|
+
* "which files this check reads" two ways is the shape that lets one of them go
|
|
538
|
+
* half-blind.
|
|
539
|
+
*/
|
|
540
|
+
export function collectRouteSources(dir, out = []) {
|
|
541
|
+
if (!existsSync(dir))
|
|
542
|
+
return out;
|
|
543
|
+
for (const name of readdirSync(dir)) {
|
|
544
|
+
const full = join(dir, name);
|
|
545
|
+
if (statSync(full).isDirectory()) {
|
|
546
|
+
if (name === 'node_modules' || name === 'dist')
|
|
547
|
+
continue;
|
|
548
|
+
collectRouteSources(full, out);
|
|
549
|
+
}
|
|
550
|
+
else if (name.endsWith('.ts') && !name.endsWith('.test.ts') && !name.endsWith('.d.ts')) {
|
|
551
|
+
out.push(full);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return out;
|
|
555
|
+
}
|
|
556
|
+
//# sourceMappingURL=action-route-permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-route-permissions.js","sourceRoot":"","sources":["../../src/rules/action-route-permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** The log prefix both hosts print under — one grammar, one spelling. */
|
|
2
|
+
export declare const PREFIX = "[bundle-pairing]";
|
|
3
|
+
export type BundlePairingFindingKind = 'missing-language-bundle' | 'empty-bundle' | 'unparseable-bundle' | 'undeclared-bundle-dir';
|
|
4
|
+
/** One registered module, as the generated index and its manifest describe it. */
|
|
5
|
+
export interface ModuleUnderCheck {
|
|
6
|
+
readonly moduleId: string;
|
|
7
|
+
/** The module's own directory — `dirname(manifestPath)`, absolute. */
|
|
8
|
+
readonly directory: string;
|
|
9
|
+
/** `i18n.bundlesDir` from the manifest, or `null` when it declares none. */
|
|
10
|
+
readonly bundlesDir: string | null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The filesystem, injected.
|
|
14
|
+
*
|
|
15
|
+
* Not for the red proofs — those build a fixture module tree on disk and use the
|
|
16
|
+
* real one, because a fixture that hands in a reader proves the classifier and
|
|
17
|
+
* leaves the walk that feeds it unproven. It exists so a caller measuring a tree
|
|
18
|
+
* it does not own can supply its own reader without this file learning about it.
|
|
19
|
+
*/
|
|
20
|
+
export interface BundlePairingFs {
|
|
21
|
+
readonly isDirectory: (path: string) => boolean;
|
|
22
|
+
readonly isFile: (path: string) => boolean;
|
|
23
|
+
readonly readFile: (path: string) => string;
|
|
24
|
+
}
|
|
25
|
+
export declare const nodeBundlePairingFs: BundlePairingFs;
|
|
26
|
+
export interface BundlePairingInput {
|
|
27
|
+
readonly modules: readonly ModuleUnderCheck[];
|
|
28
|
+
/** The platform's shipped languages — `SUPPORTED_LANGUAGES` in a real run. */
|
|
29
|
+
readonly languages: readonly string[];
|
|
30
|
+
readonly fs?: BundlePairingFs;
|
|
31
|
+
}
|
|
32
|
+
export interface BundlePairingFinding {
|
|
33
|
+
readonly kind: BundlePairingFindingKind;
|
|
34
|
+
readonly moduleId: string;
|
|
35
|
+
/** The language it is about, or `null` where the finding is about the module. */
|
|
36
|
+
readonly language: string | null;
|
|
37
|
+
/** The file or directory it names, absolute. */
|
|
38
|
+
readonly path: string;
|
|
39
|
+
/** The sentence the author reads, without the shared remedy. */
|
|
40
|
+
readonly detail: string;
|
|
41
|
+
}
|
|
42
|
+
export interface BundlePairingResult {
|
|
43
|
+
readonly findings: readonly BundlePairingFinding[];
|
|
44
|
+
/** Every bundle file opened — the read line's `files`. */
|
|
45
|
+
readonly filesRead: readonly string[];
|
|
46
|
+
/** Every module classified — the read line's `sites`. */
|
|
47
|
+
readonly classified: readonly string[];
|
|
48
|
+
/** Modules shipping at least one bundle: the ones the predicate binds. */
|
|
49
|
+
readonly shipping: readonly string[];
|
|
50
|
+
/** Modules shipping none: exempt by § 1's conditional, and reported clean. */
|
|
51
|
+
readonly shippingNothing: readonly string[];
|
|
52
|
+
/**
|
|
53
|
+
* How many shipped languages the walk actually probed for — `0` when no module
|
|
54
|
+
* shipped anything at all, which is the vacuous state § 4's fourth condition
|
|
55
|
+
* refuses. It is deliberately *not* "languages a bundle was found in": every
|
|
56
|
+
* module dropping `pl` is a run of findings, not a run that read nothing.
|
|
57
|
+
*/
|
|
58
|
+
readonly languagesProbed: number;
|
|
59
|
+
}
|
|
60
|
+
/** The directory names the manifests themselves declare — never a literal. */
|
|
61
|
+
export declare function declaredBundleDirectories(modules: readonly ModuleUnderCheck[]): readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* The findings, over the modules and languages handed in.
|
|
64
|
+
*
|
|
65
|
+
* Pure but for the injected reader, so a red proof enters where a real run
|
|
66
|
+
* enters: a module tree on disk plus the index's own answer about which modules
|
|
67
|
+
* exist (issue #130). A fixture handing in a per-module classification would
|
|
68
|
+
* prove the reporter and leave the classifier — which is all of the analysis —
|
|
69
|
+
* unproven.
|
|
70
|
+
*/
|
|
71
|
+
export declare function checkBundlePairing(input: BundlePairingInput): BundlePairingResult;
|
|
72
|
+
/** The remedy paragraph, one per finding kind. */
|
|
73
|
+
export declare const REMEDIES: Readonly<Record<BundlePairingFindingKind, string>>;
|
|
74
|
+
//# sourceMappingURL=bundle-pairing.d.ts.map
|