@proappstore/compliance 0.2.16 → 0.2.18
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/README.md +0 -1
- package/dist/checks/mcp-unscoped.d.ts +15 -0
- package/dist/checks/mcp-unscoped.d.ts.map +1 -0
- package/dist/checks/mcp-unscoped.js +43 -0
- package/dist/checks/mcp-unscoped.js.map +1 -0
- package/dist/clause-map.js +2 -2
- package/dist/clause-map.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/unscoped-policy.d.ts +102 -0
- package/dist/lib/unscoped-policy.d.ts.map +1 -0
- package/dist/lib/unscoped-policy.js +283 -0
- package/dist/lib/unscoped-policy.js.map +1 -0
- package/package.json +1 -1
- package/dist/checks/store-link.d.ts +0 -13
- package/dist/checks/store-link.d.ts.map +0 -1
- package/dist/checks/store-link.js +0 -30
- package/dist/checks/store-link.js.map +0 -1
package/README.md
CHANGED
|
@@ -60,7 +60,6 @@ There is also a separate live-URL audit (`auditLive`, exported from
|
|
|
60
60
|
| `PWA offline correctness` | Service worker / offline behaviour is correct | **fail** / warn |
|
|
61
61
|
| `PWA manifest` | Static `web/public/manifest.json` (or inline VitePWA manifest) declares name / short_name / start_url / display | **fail** |
|
|
62
62
|
| `PWA maskable icon` | Manifest declares at least one `purpose: "maskable"` icon | **fail** |
|
|
63
|
-
| `Store link` | Some source file links back to `proappstore.online` | warn |
|
|
64
63
|
| `Dark mode support` | Respects the system colour-scheme preference | warn |
|
|
65
64
|
| `Bundle size` | Largest JS in `web/dist/assets/` is ≤ 300 KB gzipped | **fail** if too big; warn if not built yet |
|
|
66
65
|
| `CLAUDE.md slim` | Per-repo `CLAUDE.md` stays slim (no drift-prone platform-wide content) | warn |
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FileSource } from '../lib/file-source.js';
|
|
2
|
+
import type { CheckResult } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* #426 (PAS-DATA-012): every action in `mcp.json` that any signed-in user can run
|
|
5
|
+
* without `:__user_id` (`auth.caller_unscoped`, no role, callable by "user") must
|
|
6
|
+
* have a reviewed `approved_unscoped` entry and must not return personal data.
|
|
7
|
+
*
|
|
8
|
+
* The platform's registration gate applies the same policy (lib/unscoped-policy.ts)
|
|
9
|
+
* with the app's registered actions in hand, grandfathering unchanged ones. This
|
|
10
|
+
* check has no registry, so it warns on every gap the gate might accept today and
|
|
11
|
+
* fails only on what no approval fixes: a malformed approval list, or an approved
|
|
12
|
+
* action that returns personal data or `*`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkMcpUnscoped(source: FileSource): Promise<CheckResult>;
|
|
15
|
+
//# sourceMappingURL=mcp-unscoped.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-unscoped.d.ts","sourceRoot":"","sources":["../../src/checks/mcp-unscoped.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAwB/E"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { evaluateUnscoped, isOpenUnscoped, validateApprovals } from '../lib/unscoped-policy.js';
|
|
2
|
+
const NAME = 'Unscoped actions approved';
|
|
3
|
+
/**
|
|
4
|
+
* #426 (PAS-DATA-012): every action in `mcp.json` that any signed-in user can run
|
|
5
|
+
* without `:__user_id` (`auth.caller_unscoped`, no role, callable by "user") must
|
|
6
|
+
* have a reviewed `approved_unscoped` entry and must not return personal data.
|
|
7
|
+
*
|
|
8
|
+
* The platform's registration gate applies the same policy (lib/unscoped-policy.ts)
|
|
9
|
+
* with the app's registered actions in hand, grandfathering unchanged ones. This
|
|
10
|
+
* check has no registry, so it warns on every gap the gate might accept today and
|
|
11
|
+
* fails only on what no approval fixes: a malformed approval list, or an approved
|
|
12
|
+
* action that returns personal data or `*`.
|
|
13
|
+
*/
|
|
14
|
+
export async function checkMcpUnscoped(source) {
|
|
15
|
+
const raw = await source.read('mcp.json');
|
|
16
|
+
if (raw === null)
|
|
17
|
+
return { name: NAME, status: 'pass', detail: 'no mcp.json' };
|
|
18
|
+
let manifest;
|
|
19
|
+
try {
|
|
20
|
+
manifest = JSON.parse(raw);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { name: NAME, status: 'pass', detail: 'mcp.json is not valid JSON; registration reports it' };
|
|
24
|
+
}
|
|
25
|
+
const tools = (Array.isArray(manifest.tools) ? manifest.tools : [])
|
|
26
|
+
.filter((t) => !!t && typeof t === 'object' && typeof t.name === 'string');
|
|
27
|
+
const approvals = validateApprovals(manifest.approved_unscoped);
|
|
28
|
+
if ('error' in approvals) {
|
|
29
|
+
return { name: NAME, status: 'fail', detail: approvals.error, suggestions: ['Each approved_unscoped entry is { "action", "reviewer", "date": "YYYY-MM-DD", "reason" }.'] };
|
|
30
|
+
}
|
|
31
|
+
const open = tools.filter(isOpenUnscoped).length;
|
|
32
|
+
const verdict = evaluateUnscoped({ tools, approvals: approvals.approvals, previous: null });
|
|
33
|
+
const suggestions = [
|
|
34
|
+
'Scope the statement to the caller with :__user_id, gate it with auth.app_roles, or narrow callers to ["worker"].',
|
|
35
|
+
'A reviewed, shared read with no personal data: add { "action", "reviewer", "date", "reason" } to approved_unscoped.',
|
|
36
|
+
];
|
|
37
|
+
if (verdict.errors.length)
|
|
38
|
+
return { name: NAME, status: 'fail', detail: verdict.errors.join('; '), suggestions };
|
|
39
|
+
if (verdict.warnings.length)
|
|
40
|
+
return { name: NAME, status: 'warn', detail: verdict.warnings.join('; '), suggestions };
|
|
41
|
+
return { name: NAME, status: 'pass', detail: open ? `${open} unscoped action(s), all approved, none returning personal data` : 'no action is open to every user unscoped' };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=mcp-unscoped.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-unscoped.js","sourceRoot":"","sources":["../../src/checks/mcp-unscoped.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,iBAAiB,EAA2B,MAAM,2BAA2B,CAAC;AAGzH,MAAM,IAAI,GAAG,2BAA2B,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,MAAkB;IACvD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAC/E,IAAI,QAA0D,CAAC;IAC/D,IAAI,CAAC;QACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,qDAAqD,EAAE,CAAC;IACvG,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;SAChE,MAAM,CAAC,CAAC,CAAC,EAA2B,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IAC9H,MAAM,SAAS,GAAG,iBAAiB,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAChE,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,2FAA2F,CAAC,EAAE,CAAC;IAC7K,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5F,MAAM,WAAW,GAAG;QAClB,kHAAkH;QAClH,qHAAqH;KACtH,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACjH,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC;IACrH,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,iEAAiE,CAAC,CAAC,CAAC,0CAA0C,EAAE,CAAC;AAC9K,CAAC"}
|
package/dist/clause-map.js
CHANGED
|
@@ -43,14 +43,14 @@ export const CHECKS = [
|
|
|
43
43
|
limits: 'The four required fields; the rest of the manifest is reviewed manually.' },
|
|
44
44
|
{ id: 'pwa-maskable-icon', name: 'PWA maskable icon', clauses: ['PAS-UI-020'], automation: 'full', evidenceClass: 'configuration', scope: 'all',
|
|
45
45
|
limits: 'Declaration only; the icon\'s safe zone is not rendered.' },
|
|
46
|
-
{ id: 'store-link', name: 'Store link', clauses: ['PAS-UI-001', 'PAS-STACK-022'], automation: 'full', evidenceClass: 'source', scope: 'all',
|
|
47
|
-
limits: 'That the domain appears somewhere under web/src; not that it is visible.' },
|
|
48
46
|
{ id: 'dark-mode', name: 'Dark mode support', clauses: ['PAS-UI-002'], automation: 'partial', evidenceClass: 'source', scope: 'apps',
|
|
49
47
|
limits: 'Warn-only signal detection; the storage-key split (fas:theme vs stores-theme) and dark-scheme contrast are manual.' },
|
|
50
48
|
{ id: 'bundle-size', name: 'Bundle size', clauses: ['PAS-UI-021', 'PAS-STACK-024'], automation: 'partial', evidenceClass: 'process', scope: 'all',
|
|
51
49
|
limits: 'Warns when web/dist is unbuilt; measures the largest JS chunk only.' },
|
|
52
50
|
{ id: 'claude-md-slim', name: 'CLAUDE.md is slim (no platform boilerplate)', clauses: ['PAS-STACK-001'], automation: 'partial', evidenceClass: 'documentation', scope: 'all',
|
|
53
51
|
limits: 'Documentation hygiene of the scaffold\'s agent guide; warn-only and not a security signal.' },
|
|
52
|
+
{ id: 'mcp-unscoped', name: 'Unscoped actions approved', clauses: ['PAS-DATA-012'], automation: 'partial', evidenceClass: 'configuration', scope: 'all',
|
|
53
|
+
limits: 'Reads mcp.json only: personal data is judged by output column names, and approval proves a review was recorded, not that it was sound. Without the registry it cannot tell a grandfathered action from a new one, so it warns where registration may refuse.' },
|
|
54
54
|
// Live-URL audit (auditLive) — a post-publish subset run against the deployed app.
|
|
55
55
|
{ id: 'reachable', name: 'Reachable', clauses: ['PAS-OPS-010'], automation: 'partial', evidenceClass: 'runtime', scope: 'all', live: true,
|
|
56
56
|
limits: 'HTTP 200 from the live URL; not that the app works (that is the post-deploy smoke).' },
|
package/dist/clause-map.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clause-map.js","sourceRoot":"","sources":["../src/clause-map.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"clause-map.js","sourceRoot":"","sources":["../src/clause-map.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { checkHtmlMeta } from './checks/html-meta.js';
|
|
|
8
8
|
import { checkLicenseMit } from './checks/license-mit.js';
|
|
9
9
|
import { checkManifest } from './checks/manifest.js';
|
|
10
10
|
import { checkMaskableIcon } from './checks/pwa-maskable-icon.js';
|
|
11
|
+
import { checkMcpUnscoped } from './checks/mcp-unscoped.js';
|
|
11
12
|
import { checkNoBrandOverrides } from './checks/no-brand-overrides.js';
|
|
12
13
|
import { checkNoEnvProduction } from './checks/no-env-production.js';
|
|
13
14
|
import { checkNoPlaceholders } from './checks/no-placeholders.js';
|
|
@@ -15,7 +16,6 @@ import { checkNoScroll } from './checks/no-scroll.js';
|
|
|
15
16
|
import { checkNoTracking } from './checks/no-tracking.js';
|
|
16
17
|
import { checkPwaMeta } from './checks/pwa-meta.js';
|
|
17
18
|
import { checkPwaOffline } from './checks/pwa-offline.js';
|
|
18
|
-
import { checkStoreLink } from './checks/store-link.js';
|
|
19
19
|
import { checkUnsafeVh } from './checks/unsafe-vh.js';
|
|
20
20
|
import { checkViewportSupport } from './checks/viewport-support.js';
|
|
21
21
|
import { fsFileSource, mapFileSource } from './lib/file-source.js';
|
|
@@ -23,12 +23,14 @@ import { isGameProject } from './lib/project-type.js';
|
|
|
23
23
|
import { CHECKS, annotate, annotateByName, getCheckMeta, getCheckMetaForName, citationsFor, clauseUrl, complianceMap, STANDARD_BASE_URL } from './clause-map.js';
|
|
24
24
|
import type { CheckResult } from './types.js';
|
|
25
25
|
export type { FileSource } from './lib/file-source.js';
|
|
26
|
+
export { actionPersonalData, describeExposure, evaluateUnscoped, isOpenUnscoped, MAX_UNSCOPED_APPROVALS, PERSONAL_DATA_COLUMN_PARTS, personalDataExposure, validateApprovals, } from './lib/unscoped-policy.js';
|
|
27
|
+
export type { PersonalDataExposure, UnscopedApproval, UnscopedEvaluation, UnscopedPolicyTool } from './lib/unscoped-policy.js';
|
|
26
28
|
export type { LiveAuditInput, LiveAuditReport } from './live/index.js';
|
|
27
29
|
export { auditLive, checkBrandFontsLive, checkBundleSizeLive, checkManifestLive, checkNoTrackingLive, checkUnsafeVhLive, } from './live/index.js';
|
|
28
30
|
export type { CheckAutomation, CheckResult, CheckStatus, EvidenceClass, StandardCitation } from './types.js';
|
|
29
31
|
export type { CheckMeta } from './clause-map.js';
|
|
30
32
|
export { CHECKS, annotate, annotateByName, getCheckMeta, getCheckMetaForName, citationsFor, clauseUrl, complianceMap, STANDARD_BASE_URL };
|
|
31
|
-
export { checkAccessibilityStatic, checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoBrandOverrides, checkNoEnvProduction, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPwaMeta, checkPwaOffline,
|
|
33
|
+
export { checkAccessibilityStatic, checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkMcpUnscoped, checkNoBrandOverrides, checkNoEnvProduction, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPwaMeta, checkPwaOffline, checkUnsafeVh, checkViewportSupport, fsFileSource, isGameProject, mapFileSource, };
|
|
32
34
|
/**
|
|
33
35
|
* Runs every compliance check against the source. Two front doors:
|
|
34
36
|
* - `runChecks(repoDir)` — CLI / CI; reads from disk.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { checkHtmlMeta } from './checks/html-meta.js';
|
|
|
8
8
|
import { checkLicenseMit } from './checks/license-mit.js';
|
|
9
9
|
import { checkManifest } from './checks/manifest.js';
|
|
10
10
|
import { checkMaskableIcon } from './checks/pwa-maskable-icon.js';
|
|
11
|
+
import { checkMcpUnscoped } from './checks/mcp-unscoped.js';
|
|
11
12
|
import { checkNoBrandOverrides } from './checks/no-brand-overrides.js';
|
|
12
13
|
import { checkNoEnvProduction } from './checks/no-env-production.js';
|
|
13
14
|
import { checkNoPlaceholders } from './checks/no-placeholders.js';
|
|
@@ -15,18 +16,19 @@ import { checkNoScroll } from './checks/no-scroll.js';
|
|
|
15
16
|
import { checkNoTracking } from './checks/no-tracking.js';
|
|
16
17
|
import { checkPwaMeta } from './checks/pwa-meta.js';
|
|
17
18
|
import { checkPwaOffline } from './checks/pwa-offline.js';
|
|
18
|
-
import { checkStoreLink } from './checks/store-link.js';
|
|
19
19
|
import { checkUnsafeVh } from './checks/unsafe-vh.js';
|
|
20
20
|
import { checkViewportSupport } from './checks/viewport-support.js';
|
|
21
21
|
import { fsFileSource, mapFileSource } from './lib/file-source.js';
|
|
22
22
|
import { isGameProject } from './lib/project-type.js';
|
|
23
23
|
import { CHECKS, annotate, annotateByName, getCheckMeta, getCheckMetaForName, citationsFor, clauseUrl, complianceMap, STANDARD_BASE_URL } from './clause-map.js';
|
|
24
|
+
// #426: the caller_unscoped policy, shared with the platform's registration gate.
|
|
25
|
+
export { actionPersonalData, describeExposure, evaluateUnscoped, isOpenUnscoped, MAX_UNSCOPED_APPROVALS, PERSONAL_DATA_COLUMN_PARTS, personalDataExposure, validateApprovals, } from './lib/unscoped-policy.js';
|
|
24
26
|
// Live-URL audit (used by the compliance audit Worker; runs in
|
|
25
27
|
// browser/Workers env, no filesystem). Separate export path so callers
|
|
26
28
|
// don't accidentally pull node:fs in via the file-walking checks.
|
|
27
29
|
export { auditLive, checkBrandFontsLive, checkBundleSizeLive, checkManifestLive, checkNoTrackingLive, checkUnsafeVhLive, } from './live/index.js';
|
|
28
30
|
export { CHECKS, annotate, annotateByName, getCheckMeta, getCheckMetaForName, citationsFor, clauseUrl, complianceMap, STANDARD_BASE_URL };
|
|
29
|
-
export { checkAccessibilityStatic, checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkNoBrandOverrides, checkNoEnvProduction, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPwaMeta, checkPwaOffline,
|
|
31
|
+
export { checkAccessibilityStatic, checkBrandFonts, checkBrandTokens, checkBundleSize, checkClaudeMdSlim, checkDarkMode, checkHtmlMeta, checkLicenseMit, checkManifest, checkMaskableIcon, checkMcpUnscoped, checkNoBrandOverrides, checkNoEnvProduction, checkNoPlaceholders, checkNoScroll, checkNoTracking, checkPwaMeta, checkPwaOffline, checkUnsafeVh, checkViewportSupport, fsFileSource, isGameProject, mapFileSource, };
|
|
30
32
|
/**
|
|
31
33
|
* Runs every compliance check against the source. Two front doors:
|
|
32
34
|
* - `runChecks(repoDir)` — CLI / CI; reads from disk.
|
|
@@ -64,10 +66,10 @@ const RUNNERS = [
|
|
|
64
66
|
{ id: 'pwa-offline', run: checkPwaOffline },
|
|
65
67
|
{ id: 'pwa-manifest', run: checkManifest },
|
|
66
68
|
{ id: 'pwa-maskable-icon', run: checkMaskableIcon },
|
|
67
|
-
{ id: 'store-link', run: checkStoreLink },
|
|
68
69
|
{ id: 'dark-mode', run: checkDarkMode },
|
|
69
70
|
{ id: 'bundle-size', run: checkBundleSize },
|
|
70
71
|
{ id: 'claude-md-slim', run: checkClaudeMdSlim },
|
|
72
|
+
{ id: 'mcp-unscoped', run: checkMcpUnscoped },
|
|
71
73
|
];
|
|
72
74
|
/** Ids of the source-side checks, in output order. */
|
|
73
75
|
export const SOURCE_CHECK_IDS = RUNNERS.map((r) => r.id);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deny-by-default for unscoped actions (platform#426), shared by the platform's
|
|
3
|
+
* registration gate (backend `routes/tools.ts`) and the `mcp-unscoped` compliance
|
|
4
|
+
* check, so `pas check`, an app's CI and the deploy apply one rule.
|
|
5
|
+
*
|
|
6
|
+
* An action's statements must be scoped to the caller with `:__user_id` unless it
|
|
7
|
+
* declares `auth.caller_unscoped`. That exemption is the risk this module bounds:
|
|
8
|
+
* an unscoped statement that ANY signed-in user can run reads or writes every
|
|
9
|
+
* tenant's rows (doordrop#85: `get_user` returned every user's email and phone).
|
|
10
|
+
*
|
|
11
|
+
* - An action is **open-unscoped** when a signed-in user can run it and nothing
|
|
12
|
+
* narrows who: it requires auth, is not scheduled, lists "user" in its callers
|
|
13
|
+
* (the default), carries no app or platform role gate, and declares
|
|
14
|
+
* `caller_unscoped`. Worker-only, hook-only, scheduled, role-gated and public
|
|
15
|
+
* actions are not: a user cannot reach them, or a role already decides who can.
|
|
16
|
+
* - An open-unscoped action needs an explicit, reviewed entry in the manifest's
|
|
17
|
+
* top-level `approved_unscoped` list: `{ action, reviewer, date, reason }`.
|
|
18
|
+
* A `caller_unscoped.reason` alone no longer opens an action to every user.
|
|
19
|
+
* - An open-unscoped action may never return personal data: no output column
|
|
20
|
+
* named like an email, phone, address or location, and no `*` / `t.*`, which
|
|
21
|
+
* could return one. Approval does not lift this.
|
|
22
|
+
*/
|
|
23
|
+
export interface UnscopedPolicyTool {
|
|
24
|
+
name: string;
|
|
25
|
+
operation?: string;
|
|
26
|
+
sql?: string;
|
|
27
|
+
statements?: string[];
|
|
28
|
+
requires_auth?: boolean;
|
|
29
|
+
schedule?: unknown;
|
|
30
|
+
callers?: string[];
|
|
31
|
+
auth?: {
|
|
32
|
+
caller_unscoped?: {
|
|
33
|
+
reason?: unknown;
|
|
34
|
+
};
|
|
35
|
+
app_roles?: string[];
|
|
36
|
+
platform_roles?: string[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface UnscopedApproval {
|
|
40
|
+
action: string;
|
|
41
|
+
reviewer: string;
|
|
42
|
+
/** ISO date of the review, YYYY-MM-DD. */
|
|
43
|
+
date: string;
|
|
44
|
+
reason: string;
|
|
45
|
+
}
|
|
46
|
+
export declare const MAX_UNSCOPED_APPROVALS = 200;
|
|
47
|
+
/**
|
|
48
|
+
* Parts of a column name that mark personal data. A name matches when one of its
|
|
49
|
+
* underscore-separated parts is listed (`contact_email`, `phone_number`,
|
|
50
|
+
* `home_address`, `date_of_birth`); a key or count of one (`location_id`,
|
|
51
|
+
* `email_count`) does not.
|
|
52
|
+
*/
|
|
53
|
+
export declare const PERSONAL_DATA_COLUMN_PARTS: readonly string[];
|
|
54
|
+
/** The statements an action runs, as the platform executes them. */
|
|
55
|
+
export declare function policyStatements(tool: UnscopedPolicyTool): string[];
|
|
56
|
+
/** Does the action declare an unscoped exemption (with a reason, as registration requires)? */
|
|
57
|
+
export declare function declaresUnscoped(tool: UnscopedPolicyTool): boolean;
|
|
58
|
+
/** Open-unscoped: any signed-in user can run its unscoped statements. */
|
|
59
|
+
export declare function isOpenUnscoped(tool: UnscopedPolicyTool): boolean;
|
|
60
|
+
export interface PersonalDataExposure {
|
|
61
|
+
/** `*` or `t.*` in an output list: the columns cannot be checked, so it counts as exposing. */
|
|
62
|
+
star: boolean;
|
|
63
|
+
/** Personal-data column names found in output lists (names or aliases). */
|
|
64
|
+
columns: string[];
|
|
65
|
+
}
|
|
66
|
+
/** What a statement could return that names a person. */
|
|
67
|
+
export declare function personalDataExposure(sql: string): PersonalDataExposure;
|
|
68
|
+
/** The exposure across all of an action's statements, or null when none. */
|
|
69
|
+
export declare function actionPersonalData(tool: UnscopedPolicyTool): PersonalDataExposure | null;
|
|
70
|
+
export declare function describeExposure(e: PersonalDataExposure): string;
|
|
71
|
+
/** Validate a manifest's `approved_unscoped` list. Absent is an empty list. */
|
|
72
|
+
export declare function validateApprovals(raw: unknown): {
|
|
73
|
+
error: string;
|
|
74
|
+
} | {
|
|
75
|
+
approvals: Map<string, UnscopedApproval>;
|
|
76
|
+
};
|
|
77
|
+
export interface UnscopedEvaluation {
|
|
78
|
+
/** Refusals: the registration (or check) must not pass. */
|
|
79
|
+
errors: string[];
|
|
80
|
+
warnings: string[];
|
|
81
|
+
/** Open-unscoped actions accepted only because they were already registered unchanged. */
|
|
82
|
+
grandfathered: string[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Apply the policy to an app's action set.
|
|
86
|
+
*
|
|
87
|
+
* `previous` is the set currently registered, by name. An open-unscoped action
|
|
88
|
+
* that was already registered open-unscoped with the same statements is
|
|
89
|
+
* grandfathered: accepted with a warning while it lacks approval, and with a
|
|
90
|
+
* [SECURITY] warning (not a refusal) if it returns personal data. Anything new or
|
|
91
|
+
* changed must be approved and must not return personal data.
|
|
92
|
+
*
|
|
93
|
+
* `previous: null` means the registry is unknown (an app's CI): every gap is
|
|
94
|
+
* reported as a warning, except what approval cannot fix — an approved action
|
|
95
|
+
* that returns personal data — which is an error.
|
|
96
|
+
*/
|
|
97
|
+
export declare function evaluateUnscoped(opts: {
|
|
98
|
+
tools: UnscopedPolicyTool[];
|
|
99
|
+
approvals: Map<string, UnscopedApproval>;
|
|
100
|
+
previous: Map<string, UnscopedPolicyTool> | null;
|
|
101
|
+
}): UnscopedEvaluation;
|
|
102
|
+
//# sourceMappingURL=unscoped-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unscoped-policy.d.ts","sourceRoot":"","sources":["../../src/lib/unscoped-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACpG;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,EAAE,SAAS,MAAM,EAGvD,CAAC;AAGF,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAInE;AAED,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAElE;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAOhE;AA8ED,MAAM,WAAW,oBAAoB;IACnC,+FAA+F;IAC/F,IAAI,EAAE,OAAO,CAAC;IACd,2EAA2E;IAC3E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAUtE;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,oBAAoB,GAAG,IAAI,CASxF;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAGhE;AAQD,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAAE,CAkBhH;AAED,MAAM,WAAW,kBAAkB;IACjC,2DAA2D;IAC3D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0FAA0F;IAC1F,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAOD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,IAAI,CAAC;CAClD,GAAG,kBAAkB,CAwCrB"}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deny-by-default for unscoped actions (platform#426), shared by the platform's
|
|
3
|
+
* registration gate (backend `routes/tools.ts`) and the `mcp-unscoped` compliance
|
|
4
|
+
* check, so `pas check`, an app's CI and the deploy apply one rule.
|
|
5
|
+
*
|
|
6
|
+
* An action's statements must be scoped to the caller with `:__user_id` unless it
|
|
7
|
+
* declares `auth.caller_unscoped`. That exemption is the risk this module bounds:
|
|
8
|
+
* an unscoped statement that ANY signed-in user can run reads or writes every
|
|
9
|
+
* tenant's rows (doordrop#85: `get_user` returned every user's email and phone).
|
|
10
|
+
*
|
|
11
|
+
* - An action is **open-unscoped** when a signed-in user can run it and nothing
|
|
12
|
+
* narrows who: it requires auth, is not scheduled, lists "user" in its callers
|
|
13
|
+
* (the default), carries no app or platform role gate, and declares
|
|
14
|
+
* `caller_unscoped`. Worker-only, hook-only, scheduled, role-gated and public
|
|
15
|
+
* actions are not: a user cannot reach them, or a role already decides who can.
|
|
16
|
+
* - An open-unscoped action needs an explicit, reviewed entry in the manifest's
|
|
17
|
+
* top-level `approved_unscoped` list: `{ action, reviewer, date, reason }`.
|
|
18
|
+
* A `caller_unscoped.reason` alone no longer opens an action to every user.
|
|
19
|
+
* - An open-unscoped action may never return personal data: no output column
|
|
20
|
+
* named like an email, phone, address or location, and no `*` / `t.*`, which
|
|
21
|
+
* could return one. Approval does not lift this.
|
|
22
|
+
*/
|
|
23
|
+
export const MAX_UNSCOPED_APPROVALS = 200;
|
|
24
|
+
/**
|
|
25
|
+
* Parts of a column name that mark personal data. A name matches when one of its
|
|
26
|
+
* underscore-separated parts is listed (`contact_email`, `phone_number`,
|
|
27
|
+
* `home_address`, `date_of_birth`); a key or count of one (`location_id`,
|
|
28
|
+
* `email_count`) does not.
|
|
29
|
+
*/
|
|
30
|
+
export const PERSONAL_DATA_COLUMN_PARTS = [
|
|
31
|
+
'email', 'phone', 'mobile', 'address', 'street', 'postcode', 'location',
|
|
32
|
+
'lat', 'lng', 'latitude', 'longitude', 'dob', 'birth', 'birthdate', 'birthday',
|
|
33
|
+
];
|
|
34
|
+
const NOT_PERSONAL_SUFFIXES = ['_id', '_ids', '_count', '_verified', '_at'];
|
|
35
|
+
/** The statements an action runs, as the platform executes them. */
|
|
36
|
+
export function policyStatements(tool) {
|
|
37
|
+
if (tool.operation === 'batch')
|
|
38
|
+
return tool.statements ?? [];
|
|
39
|
+
if (tool.operation === 'verify')
|
|
40
|
+
return [tool.sql ?? '', ...(tool.statements ?? [])];
|
|
41
|
+
return [tool.sql ?? ''];
|
|
42
|
+
}
|
|
43
|
+
/** Does the action declare an unscoped exemption (with a reason, as registration requires)? */
|
|
44
|
+
export function declaresUnscoped(tool) {
|
|
45
|
+
return tool.auth?.caller_unscoped !== undefined;
|
|
46
|
+
}
|
|
47
|
+
/** Open-unscoped: any signed-in user can run its unscoped statements. */
|
|
48
|
+
export function isOpenUnscoped(tool) {
|
|
49
|
+
return declaresUnscoped(tool)
|
|
50
|
+
&& tool.requires_auth !== false
|
|
51
|
+
&& tool.schedule === undefined
|
|
52
|
+
&& (tool.callers ?? ['user']).includes('user')
|
|
53
|
+
&& !tool.auth?.app_roles?.length
|
|
54
|
+
&& !tool.auth?.platform_roles?.length;
|
|
55
|
+
}
|
|
56
|
+
/** SQL with comments removed and string-literal contents blanked, lower-cased. */
|
|
57
|
+
function normalise(sql) {
|
|
58
|
+
return sql
|
|
59
|
+
.replace(/--[^\n]*/g, ' ')
|
|
60
|
+
.replace(/\/\*[\s\S]*?\*\//g, ' ')
|
|
61
|
+
.replace(/'(?:[^']|'')*'/g, "''")
|
|
62
|
+
.replace(/:[a-z_][a-z0-9_]*/gi, ' ')
|
|
63
|
+
.toLowerCase();
|
|
64
|
+
}
|
|
65
|
+
/** Text at paren depth 0 relative to `text`'s start (nested parentheses blanked). */
|
|
66
|
+
function topLevel(text) {
|
|
67
|
+
let depth = 0;
|
|
68
|
+
let out = '';
|
|
69
|
+
for (const ch of text) {
|
|
70
|
+
if (ch === '(') {
|
|
71
|
+
depth += 1;
|
|
72
|
+
out += ' ';
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (ch === ')') {
|
|
76
|
+
depth = Math.max(0, depth - 1);
|
|
77
|
+
out += ' ';
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
out += depth === 0 ? ch : ' ';
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/** `text` with every parenthesised sub-select removed; each is its own output list. */
|
|
85
|
+
function withoutSubqueries(text) {
|
|
86
|
+
let out = '';
|
|
87
|
+
let i = 0;
|
|
88
|
+
while (i < text.length) {
|
|
89
|
+
if (text[i] === '(' && /^\(\s*select\b/.test(text.slice(i))) {
|
|
90
|
+
let depth = 0;
|
|
91
|
+
for (; i < text.length; i++) {
|
|
92
|
+
if (text[i] === '(')
|
|
93
|
+
depth += 1;
|
|
94
|
+
else if (text[i] === ')' && --depth === 0) {
|
|
95
|
+
i += 1;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
out += ' ';
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
out += text[i];
|
|
103
|
+
i += 1;
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
const LIST_END = /^(from|union|intersect|except|where|group|order|limit|window|having)\b/;
|
|
108
|
+
/**
|
|
109
|
+
* The output lists of a statement: each SELECT's list (up to its own FROM, at its
|
|
110
|
+
* own depth) and a RETURNING list. Sub-selects are lists too, since what they
|
|
111
|
+
* return can surface in the outer result.
|
|
112
|
+
*/
|
|
113
|
+
function outputLists(sql) {
|
|
114
|
+
const s = normalise(sql);
|
|
115
|
+
const lists = [];
|
|
116
|
+
const select = /\bselect\b/g;
|
|
117
|
+
let m;
|
|
118
|
+
while ((m = select.exec(s)) !== null) {
|
|
119
|
+
let depth = 0;
|
|
120
|
+
let end = s.length;
|
|
121
|
+
for (let i = m.index + 6; i < s.length; i++) {
|
|
122
|
+
const ch = s[i];
|
|
123
|
+
if (ch === '(')
|
|
124
|
+
depth += 1;
|
|
125
|
+
else if (ch === ')') {
|
|
126
|
+
if (depth === 0) {
|
|
127
|
+
end = i;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
depth -= 1;
|
|
131
|
+
}
|
|
132
|
+
else if (ch === ';' && depth === 0) {
|
|
133
|
+
end = i;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
else if (depth === 0 && /\W/.test(s[i - 1] ?? ' ') && LIST_END.test(s.slice(i))) {
|
|
137
|
+
end = i;
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
lists.push(withoutSubqueries(s.slice(m.index + 6, end)));
|
|
142
|
+
}
|
|
143
|
+
const returning = /\breturning\b([\s\S]*?)(;|$)/g;
|
|
144
|
+
while ((m = returning.exec(s)) !== null)
|
|
145
|
+
lists.push(m[1] ?? '');
|
|
146
|
+
return lists;
|
|
147
|
+
}
|
|
148
|
+
function personalColumn(identifier) {
|
|
149
|
+
if (NOT_PERSONAL_SUFFIXES.some((suffix) => identifier.endsWith(suffix)))
|
|
150
|
+
return false;
|
|
151
|
+
return identifier.split('_').some((part) => PERSONAL_DATA_COLUMN_PARTS.includes(part));
|
|
152
|
+
}
|
|
153
|
+
/** What a statement could return that names a person. */
|
|
154
|
+
export function personalDataExposure(sql) {
|
|
155
|
+
let star = false;
|
|
156
|
+
const columns = new Set();
|
|
157
|
+
for (const list of outputLists(sql)) {
|
|
158
|
+
const top = topLevel(list);
|
|
159
|
+
// A whole item `*` or `t.*` (after an optional DISTINCT/ALL); `a * 2` is arithmetic.
|
|
160
|
+
if (top.split(',').some((item) => /^\s*(?:(?:distinct|all)\s+)?(?:[a-z_][a-z0-9_]*\s*\.\s*)?\*\s*$/.test(item)))
|
|
161
|
+
star = true;
|
|
162
|
+
for (const id of list.match(/[a-z_][a-z0-9_]*/g) ?? [])
|
|
163
|
+
if (personalColumn(id))
|
|
164
|
+
columns.add(id);
|
|
165
|
+
}
|
|
166
|
+
return { star, columns: [...columns].sort() };
|
|
167
|
+
}
|
|
168
|
+
/** The exposure across all of an action's statements, or null when none. */
|
|
169
|
+
export function actionPersonalData(tool) {
|
|
170
|
+
let star = false;
|
|
171
|
+
const columns = new Set();
|
|
172
|
+
for (const sql of policyStatements(tool)) {
|
|
173
|
+
const e = personalDataExposure(sql);
|
|
174
|
+
star ||= e.star;
|
|
175
|
+
for (const c of e.columns)
|
|
176
|
+
columns.add(c);
|
|
177
|
+
}
|
|
178
|
+
return star || columns.size ? { star, columns: [...columns].sort() } : null;
|
|
179
|
+
}
|
|
180
|
+
export function describeExposure(e) {
|
|
181
|
+
const parts = [e.columns.length ? `personal-data column(s) ${e.columns.join(', ')}` : '', e.star ? '`*` (any column, so possibly personal data)' : ''].filter(Boolean);
|
|
182
|
+
return parts.join(' and ');
|
|
183
|
+
}
|
|
184
|
+
function isIsoDate(value) {
|
|
185
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
186
|
+
return false;
|
|
187
|
+
const d = new Date(`${value}T00:00:00Z`);
|
|
188
|
+
return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === value;
|
|
189
|
+
}
|
|
190
|
+
/** Validate a manifest's `approved_unscoped` list. Absent is an empty list. */
|
|
191
|
+
export function validateApprovals(raw) {
|
|
192
|
+
const approvals = new Map();
|
|
193
|
+
if (raw === undefined || raw === null)
|
|
194
|
+
return { approvals };
|
|
195
|
+
if (!Array.isArray(raw))
|
|
196
|
+
return { error: 'approved_unscoped must be an array of { action, reviewer, date, reason }' };
|
|
197
|
+
if (raw.length > MAX_UNSCOPED_APPROVALS)
|
|
198
|
+
return { error: `approved_unscoped: at most ${MAX_UNSCOPED_APPROVALS} entries` };
|
|
199
|
+
for (const [i, entry] of raw.entries()) {
|
|
200
|
+
const at = `approved_unscoped[${i}]`;
|
|
201
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
202
|
+
return { error: `${at} must be an object` };
|
|
203
|
+
const e = entry;
|
|
204
|
+
for (const field of ['action', 'reviewer', 'date', 'reason']) {
|
|
205
|
+
if (typeof e[field] !== 'string' || !e[field].trim())
|
|
206
|
+
return { error: `${at}.${field} must be a non-empty string` };
|
|
207
|
+
}
|
|
208
|
+
if (!isIsoDate(e.date.trim()))
|
|
209
|
+
return { error: `${at}.date must be an ISO date, YYYY-MM-DD` };
|
|
210
|
+
const action = e.action.trim();
|
|
211
|
+
if (approvals.has(action))
|
|
212
|
+
return { error: `${at}: action "${action}" is approved twice` };
|
|
213
|
+
approvals.set(action, { action, reviewer: e.reviewer.trim(), date: e.date.trim(), reason: e.reason.trim() });
|
|
214
|
+
}
|
|
215
|
+
return { approvals };
|
|
216
|
+
}
|
|
217
|
+
/** Same statements as before: an unchanged action keeps its registration. */
|
|
218
|
+
function sameStatements(a, b) {
|
|
219
|
+
return JSON.stringify(policyStatements(a).map((x) => x.trim())) === JSON.stringify(policyStatements(b).map((x) => x.trim()));
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Apply the policy to an app's action set.
|
|
223
|
+
*
|
|
224
|
+
* `previous` is the set currently registered, by name. An open-unscoped action
|
|
225
|
+
* that was already registered open-unscoped with the same statements is
|
|
226
|
+
* grandfathered: accepted with a warning while it lacks approval, and with a
|
|
227
|
+
* [SECURITY] warning (not a refusal) if it returns personal data. Anything new or
|
|
228
|
+
* changed must be approved and must not return personal data.
|
|
229
|
+
*
|
|
230
|
+
* `previous: null` means the registry is unknown (an app's CI): every gap is
|
|
231
|
+
* reported as a warning, except what approval cannot fix — an approved action
|
|
232
|
+
* that returns personal data — which is an error.
|
|
233
|
+
*/
|
|
234
|
+
export function evaluateUnscoped(opts) {
|
|
235
|
+
const { tools, approvals, previous } = opts;
|
|
236
|
+
const errors = [];
|
|
237
|
+
const warnings = [];
|
|
238
|
+
const grandfathered = [];
|
|
239
|
+
const unapprovedKept = [];
|
|
240
|
+
const open = new Set();
|
|
241
|
+
for (const tool of tools) {
|
|
242
|
+
if (!isOpenUnscoped(tool))
|
|
243
|
+
continue;
|
|
244
|
+
open.add(tool.name);
|
|
245
|
+
const approved = approvals.has(tool.name);
|
|
246
|
+
const pii = actionPersonalData(tool);
|
|
247
|
+
const before = previous?.get(tool.name);
|
|
248
|
+
const kept = previous !== null && before !== undefined && isOpenUnscoped(before) && sameStatements(before, tool);
|
|
249
|
+
const where = `tool "${tool.name}"`;
|
|
250
|
+
if (kept) {
|
|
251
|
+
grandfathered.push(tool.name);
|
|
252
|
+
if (pii)
|
|
253
|
+
warnings.push(`[SECURITY] ${where} is caller_unscoped and returns ${describeExposure(pii)} to any signed-in user. Scope it to :__user_id, gate it with auth.app_roles, or drop those columns; a changed version will be refused (PAS-DATA-012)`);
|
|
254
|
+
if (!approved)
|
|
255
|
+
unapprovedKept.push(tool.name);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (pii) {
|
|
259
|
+
const msg = `${where} is caller_unscoped and returns ${describeExposure(pii)}: any signed-in user would read every user's. An unscoped action may not return personal data, approved or not. Scope it to :__user_id, gate it with auth.app_roles, or select only non-personal columns (PAS-DATA-012)`;
|
|
260
|
+
if (previous === null && !approved)
|
|
261
|
+
warnings.push(`[SECURITY] ${msg}`);
|
|
262
|
+
else
|
|
263
|
+
errors.push(msg);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (!approved) {
|
|
267
|
+
const msg = `${where} is caller_unscoped and open to every signed-in user, and has no approved_unscoped entry. Scope it to :__user_id, restrict it with auth.app_roles or callers, or add { "action": "${tool.name}", "reviewer", "date", "reason" } to approved_unscoped after review (PAS-DATA-012)`;
|
|
268
|
+
if (previous === null)
|
|
269
|
+
warnings.push(msg);
|
|
270
|
+
else
|
|
271
|
+
errors.push(msg);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
for (const name of approvals.keys()) {
|
|
275
|
+
if (!open.has(name))
|
|
276
|
+
warnings.push(`approved_unscoped: "${name}" is not an open caller_unscoped action; remove the stale approval`);
|
|
277
|
+
}
|
|
278
|
+
if (unapprovedKept.length) {
|
|
279
|
+
warnings.push(`${unapprovedKept.length} action(s) are caller_unscoped and require approval before next registration change: ${unapprovedKept.join(', ')}`);
|
|
280
|
+
}
|
|
281
|
+
return { errors, warnings, grandfathered };
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=unscoped-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unscoped-policy.js","sourceRoot":"","sources":["../../src/lib/unscoped-policy.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { FileSource } from '../lib/file-source.js';
|
|
2
|
-
import type { CheckResult } from '../types.js';
|
|
3
|
-
/**
|
|
4
|
-
* Apps on ProAppStore should link back to proappstore.online — it's
|
|
5
|
-
* how visitors discover the rest of the catalog from inside any
|
|
6
|
-
* single app. The check passes if any source file under `web/src/`
|
|
7
|
-
* references the domain. The link can be in JSX
|
|
8
|
-
* (`<a href="https://proappstore.online">`), a string constant, or
|
|
9
|
-
* a footer comment — we don't enforce a specific component, just
|
|
10
|
-
* that the link exists somewhere visible.
|
|
11
|
-
*/
|
|
12
|
-
export declare function checkStoreLink(source: FileSource): Promise<CheckResult>;
|
|
13
|
-
//# sourceMappingURL=store-link.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store-link.d.ts","sourceRoot":"","sources":["../../src/checks/store-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAmB7E"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Apps on ProAppStore should link back to proappstore.online — it's
|
|
3
|
-
* how visitors discover the rest of the catalog from inside any
|
|
4
|
-
* single app. The check passes if any source file under `web/src/`
|
|
5
|
-
* references the domain. The link can be in JSX
|
|
6
|
-
* (`<a href="https://proappstore.online">`), a string constant, or
|
|
7
|
-
* a footer comment — we don't enforce a specific component, just
|
|
8
|
-
* that the link exists somewhere visible.
|
|
9
|
-
*/
|
|
10
|
-
export async function checkStoreLink(source) {
|
|
11
|
-
const domain = 'proappstore.online';
|
|
12
|
-
for await (const path of source.list()) {
|
|
13
|
-
if (!path.startsWith('web/src/'))
|
|
14
|
-
continue;
|
|
15
|
-
const content = await source.read(path);
|
|
16
|
-
if (content?.includes(domain)) {
|
|
17
|
-
return { name: 'Store link', status: 'pass', detail: `${domain} referenced in ${path}` };
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
name: 'Store link',
|
|
22
|
-
status: 'warn',
|
|
23
|
-
detail: `no link to ${domain} found in web/src/`,
|
|
24
|
-
suggestions: [
|
|
25
|
-
`Add a small "Built for ${domain}" link in the footer or about screen.`,
|
|
26
|
-
'It helps visitors find the rest of the catalog — and it counts for storefront ranking.',
|
|
27
|
-
],
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=store-link.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"store-link.js","sourceRoot":"","sources":["../../src/checks/store-link.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAkB;IACrD,MAAM,MAAM,GAAG,oBAAoB,CAAC;IAEpC,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QAC3C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,kBAAkB,IAAI,EAAE,EAAE,CAAC;QAC3F,CAAC;IACH,CAAC;IACD,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,cAAc,MAAM,oBAAoB;QAChD,WAAW,EAAE;YACX,0BAA0B,MAAM,uCAAuC;YACvE,wFAAwF;SACzF;KACF,CAAC;AACJ,CAAC"}
|