@assembly-js/app-foundation 0.0.55 → 0.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/bin/scan-client-calls.mjs +14 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,9 @@ A foundation update reads the sections between an app's version and the target:
|
|
|
14
14
|
from every bullet except `[guidance]`, agent work from the check scripts those `[action]`
|
|
15
15
|
bullets ship. Write `[fix]`, `[behavior]` and `[action]` bullets for the app's owner.
|
|
16
16
|
|
|
17
|
+
## 0.0.56
|
|
18
|
+
- [new] The client-call scan now marks each finding as gated only when every page or route that can load its file requires a staff user. Nothing in the app changes.
|
|
19
|
+
|
|
17
20
|
## 0.0.55
|
|
18
21
|
- [new] Add a scan the platform can run on demand to find calls that use a signed-in viewer's access to the platform API from pages and routes clients can open. Nothing in the app changes and no file is added to it.
|
|
19
22
|
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
wrapperName,
|
|
40
40
|
} from './scan-routes.mjs';
|
|
41
41
|
|
|
42
|
-
export const SCANNER_VERSION =
|
|
42
|
+
export const SCANNER_VERSION = 2;
|
|
43
43
|
|
|
44
44
|
export const CLASS_BREAKS = 'BREAKS';
|
|
45
45
|
export const CLASS_CLEAN = 'CLEAN';
|
|
@@ -878,15 +878,20 @@ export function createAnalysis(root) {
|
|
|
878
878
|
return { root, files, ts, read, facts: factsFor, classifyEntries: () => classifyEntries(ts, root, files, read) };
|
|
879
879
|
}
|
|
880
880
|
|
|
881
|
-
// Maps every file
|
|
881
|
+
// Maps every file to the byte-smallest entry that loads it (`entry`) and to every entry that
|
|
882
|
+
// does (`entries`): a file shared with an ungated entry stays exposed however the others are gated.
|
|
882
883
|
function reachFrom(analysis, entries) {
|
|
883
884
|
const reach = new Map();
|
|
884
885
|
for (const entry of entries) {
|
|
886
|
+
const visited = new Set();
|
|
885
887
|
const queue = [entry];
|
|
886
888
|
while (queue.length) {
|
|
887
889
|
const file = queue.pop();
|
|
888
|
-
if (
|
|
889
|
-
|
|
890
|
+
if (visited.has(file)) continue;
|
|
891
|
+
visited.add(file);
|
|
892
|
+
const seen = reach.get(file);
|
|
893
|
+
if (seen) seen.entries.add(entry);
|
|
894
|
+
else reach.set(file, { entry, entries: new Set([entry]) });
|
|
890
895
|
queue.push(...analysis.facts(file).imports);
|
|
891
896
|
}
|
|
892
897
|
}
|
|
@@ -904,14 +909,16 @@ export function projectClientReachable(analysis, allowlist = CLIENT_SAFE_SDK_MET
|
|
|
904
909
|
const reach = reachFrom(analysis, entries);
|
|
905
910
|
const findings = [];
|
|
906
911
|
const unresolved = [];
|
|
907
|
-
|
|
912
|
+
const gatedSet = new Set(gatedEntries);
|
|
913
|
+
for (const [file, { entry, entries: reaching }] of reach) {
|
|
914
|
+
const gated = [...reaching].every((e) => gatedSet.has(e));
|
|
908
915
|
const { calls, defeaters } = analysis.facts(file);
|
|
909
916
|
for (const c of calls) {
|
|
910
917
|
if (c.provenance === PROVENANCE_VIEWER && !allowed.has(c.method)) {
|
|
911
|
-
findings.push({ file, line: c.line, method: c.method, provenance: c.provenance, entry });
|
|
918
|
+
findings.push({ file, line: c.line, method: c.method, provenance: c.provenance, entry, gated });
|
|
912
919
|
}
|
|
913
920
|
}
|
|
914
|
-
for (const d of defeaters) unresolved.push({ file, line: d.line, reason: d.reason, entry });
|
|
921
|
+
for (const d of defeaters) unresolved.push({ file, line: d.line, reason: d.reason, entry, gated });
|
|
915
922
|
}
|
|
916
923
|
sortFindings(findings);
|
|
917
924
|
sortFindings(unresolved);
|