@preventive/triage 1.0.0-alpha.36 → 1.0.0-alpha.38
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 +16 -0
- package/common/bundle-compare-diff.d.ts +3 -0
- package/common/bundle-compare-diff.js +522 -0
- package/common/bundle-compare-inputs.d.ts +2 -0
- package/common/bundle-compare-inputs.js +65 -0
- package/common/bundle-metadata.d.ts +6 -2
- package/common/bundle-metadata.js +63 -20
- package/common/bundle-pkg-of.d.ts +1 -0
- package/common/bundle-pkg-of.js +90 -0
- package/common/bundle-source-links.js +7 -0
- package/common/bundle-sourcemap.d.ts +10 -0
- package/common/bundle-sourcemap.js +100 -0
- package/common/bundle-sources.d.ts +3 -1
- package/common/bundle-sources.js +47 -19
- package/common/code-language.js +16 -2
- package/common/default-scan-models.ts +2 -1
- package/common/dependency-reviews.d.ts +23 -0
- package/common/dependency-reviews.js +81 -0
- package/common/finding-duplicates.js +58 -0
- package/common/finding-filters.js +274 -0
- package/common/github-pr.ts +1 -1
- package/common/gzip.js +59 -0
- package/common/line-diff.d.ts +8 -0
- package/common/line-diff.js +56 -0
- package/common/linked-workspace-groups.js +63 -0
- package/common/managed/npm-packages.d.ts +5 -0
- package/common/managed/npm-packages.js +34 -0
- package/common/managed/permissions.ts +1 -5
- package/common/managed/routes.js +123 -12
- package/common/managed/team-app.d.ts +2 -0
- package/common/managed/team-app.js +31 -0
- package/common/managed/triage.ts +1 -1
- package/common/managed/upload-seal.ts +126 -0
- package/common/pretty-print.d.ts +5 -0
- package/common/pretty-print.js +24 -0
- package/common/revalidation-conflicts.js +48 -0
- package/common/revalidation-input-groups.js +56 -0
- package/common/workspace-app.js +23 -0
- package/common/workspace-groups.js +176 -0
- package/out/brotli-fallback.js +3 -3
- package/out/chunk-2KBF5TZ7.js +2 -0
- package/out/chunk-2XUEZHIP.js +28 -0
- package/out/chunk-35VE6CDH.js +2 -0
- package/out/chunk-3BZ7JERB.js +1 -0
- package/out/chunk-4XCDFGDP.js +10 -0
- package/out/chunk-5FKRIJGF.js +1 -0
- package/out/chunk-6Z5XLSPJ.js +1 -0
- package/out/chunk-ABW5FVSN.js +1 -0
- package/out/chunk-BJKRVROW.js +1 -0
- package/out/chunk-BYUEDJOM.js +7 -0
- package/out/chunk-C4Z6ZBXV.js +10 -0
- package/out/chunk-CMQA4DM6.js +1 -0
- package/out/chunk-CVVJAXVY.js +2 -0
- package/out/chunk-DCQX2J3C.js +223 -0
- package/out/chunk-DIJJNTRH.js +10 -0
- package/out/chunk-F4OMDNEY.js +1 -0
- package/out/chunk-FU4MTW7F.js +1 -0
- package/out/chunk-GJ4IUCNS.js +1 -0
- package/out/chunk-GMFXFEUA.js +2 -0
- package/out/chunk-GNXOKIGP.js +80 -0
- package/out/chunk-GZ4MS3TE.js +13 -0
- package/out/chunk-HIV7SVI7.js +1 -0
- package/out/chunk-IU3CCINR.js +3 -0
- package/out/chunk-JAKWIZWL.js +2 -0
- package/out/chunk-K3X5EJBQ.js +2 -0
- package/out/chunk-KEX2ATEW.js +2 -0
- package/out/chunk-KYCNJVB7.js +1 -0
- package/out/chunk-NRPC74AM.js +1 -0
- package/out/chunk-OJ5DGP5E.js +33 -0
- package/out/chunk-OOJM4CTU.js +1 -0
- package/out/chunk-PNHBZGDD.js +1 -0
- package/out/chunk-R5O6FAW4.js +2 -0
- package/out/chunk-RFZQQXSG.js +17 -0
- package/out/chunk-SD2WJAXN.js +48 -0
- package/out/chunk-TUII34K2.js +1 -0
- package/out/chunk-TZ5KB2Y5.js +10 -0
- package/out/chunk-UNTRGE26.js +2 -0
- package/out/chunk-UYAXVRVL.js +1 -0
- package/out/chunk-V3ME6FI5.js +2 -0
- package/out/chunk-V5O7M2YT.js +1 -0
- package/out/chunk-VIHGO77Y.js +1 -0
- package/out/chunk-W4J3MGLB.js +1 -0
- package/out/chunk-WGG7KQUH.js +1 -0
- package/out/chunk-XYFXXB2G.js +10 -0
- package/out/chunk-YVZH5SHP.js +1 -0
- package/out/chunk-ZPD5R5RP.js +3 -0
- package/out/client-managed-import.js +3 -87
- package/out/client-managed.js +26 -338
- package/out/client-sync.js +8 -14
- package/out/graph.js +17 -30
- package/out/index.html +34 -0
- package/out/prism.js +6 -2
- package/out/terminal.js +241 -257
- package/out/view.css +1 -1
- package/out/view.js +76 -520
- package/package.json +88 -7
- package/risk/files/characters.js +196 -0
- package/risk/files/hosts.js +205 -0
- package/risk/files/readability.js +164 -0
- package/risk/files/runs-code.js +329 -0
- package/risk/files/script.js +112 -0
- package/risk/files/stamps.js +46 -0
- package/risk/index.d.ts +142 -0
- package/risk/index.js +7 -0
- package/risk/npm/assess.js +219 -0
- package/risk/npm/combined.js +65 -0
- package/risk/npm/compare.js +222 -0
- package/risk/npm/dependencies.js +153 -0
- package/risk/npm/diff.js +43 -0
- package/risk/npm/downloads.js +84 -0
- package/risk/npm/files.js +34 -0
- package/risk/npm/held.js +60 -0
- package/risk/npm/install-scripts.js +33 -0
- package/risk/npm/malware.js +36 -0
- package/risk/npm/manifest.js +65 -0
- package/risk/npm/new-dependency.js +30 -0
- package/risk/npm/old-version.js +108 -0
- package/risk/npm/registry.js +282 -0
- package/risk/npm/release.js +85 -0
- package/risk/npm/specs.js +124 -0
- package/risk/npm/tarball.js +113 -0
- package/server-e2e/http.ts +7 -7
- package/server-e2e/npm-proxy.ts +1 -1
- package/server-e2e/objstore/fetch-mint-guard.ts +2 -2
- package/server-e2e/objstore/handlers.ts +1 -1
- package/server-e2e/objstore/tokens.ts +1 -1
- package/server-e2e/sign.ts +1 -1
- package/server-managed/bundle-advisories.ts +68 -11
- package/server-managed/bundle-build-worker.js +1 -1
- package/server-managed/bundle-build.ts +6 -2
- package/server-managed/bundle-cache.ts +37 -4
- package/server-managed/bundle-commits.ts +140 -0
- package/server-managed/bundle-summary-cache.ts +24 -10
- package/server-managed/config.ts +4 -0
- package/server-managed/db-methods.ts +98 -11
- package/server-managed/db-neon.ts +39 -4
- package/server-managed/db-schema.ts +14 -2
- package/server-managed/db-table-names.ts +1 -1
- package/server-managed/db.ts +7 -3
- package/server-managed/dependency-reviews.ts +248 -0
- package/server-managed/github-issue-oauth.ts +5 -6
- package/server-managed/github-metadata.ts +115 -0
- package/server-managed/github-oauth.ts +38 -2
- package/server-managed/http-response.ts +26 -0
- package/server-managed/http.ts +943 -52
- package/server-managed/index.ts +11 -5
- package/server-managed/kept.ts +28 -0
- package/server-managed/locked-packages.ts +85 -0
- package/server-managed/lru.ts +30 -0
- package/server-managed/npm-insights.ts +440 -0
- package/server-managed/npm-kept.ts +65 -0
- package/server-managed/npm-loads.ts +167 -0
- package/server-managed/npm-manifest.ts +115 -0
- package/server-managed/npm-packages.ts +378 -0
- package/server-managed/npm-provenance.ts +123 -0
- package/server-managed/npm-risk.ts +177 -0
- package/server-managed/pretty-print.ts +352 -0
- package/server-managed/public-workspace.ts +78 -7
- package/server-managed/rename-diff-worker.js +26 -0
- package/server-managed/rename-diff.ts +270 -0
- package/server-managed/report-sources.ts +13 -2
- package/server-managed/repository-browser.ts +19 -5
- package/server-managed/repository-risk.ts +413 -0
- package/server-managed/session.ts +16 -2
- package/server-managed/sql.ts +5 -2
- package/server-managed/storage-encryption.ts +5 -3
- package/server-managed/storage-payload.ts +4 -0
- package/server-managed/storage-stores.ts +2 -0
- package/server-managed/storage.ts +6 -3
- package/server-managed/team-app.ts +94 -0
- package/server-managed/team-feed.ts +1 -1
- package/server-managed/team-npm-scopes.ts +77 -0
- package/server-managed/type-only-worker.js +19 -0
- package/server-managed/type-only.ts +103 -0
- package/server-managed/uploads.ts +25 -4
- package/server-managed/upstream-cache.ts +147 -5
- package/server-managed/view-as.ts +58 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { revalidateKindOf } from '@preventive/report'
|
|
2
|
+
import { mergeReportDuplicateFields } from './finding-duplicates.js'
|
|
3
|
+
import { splitRevalidationInputs } from './revalidation-input-groups.js'
|
|
4
|
+
|
|
5
|
+
// Reports retain their original rows. Merge only this derived view, so two
|
|
6
|
+
// application findings that refer to the same source issue keep their own
|
|
7
|
+
// context, verdicts, and tabs. Code mode removes pass findings BEFORE deciding
|
|
8
|
+
// which rows may merge; imports from other analyzers remain App findings.
|
|
9
|
+
export function mergeReportGroups(reports, { showRevalidation = true, upstreamOnly = false, hideRuledOut = false, merges = [] } = {}) {
|
|
10
|
+
const rows = []
|
|
11
|
+
const ruledOutIds = new Set()
|
|
12
|
+
for (let reportIndex = 0; reportIndex < reports.length; reportIndex++) {
|
|
13
|
+
const report = reports[reportIndex]
|
|
14
|
+
for (const original of report.groups) {
|
|
15
|
+
for (const finding of original) {
|
|
16
|
+
if (finding.id && ['refuted', 'unreachable'].includes(revalidateKindOf(finding))) ruledOutIds.add(finding.id)
|
|
17
|
+
}
|
|
18
|
+
// Visibility precedes merging: a hidden answer from another app must
|
|
19
|
+
// neither cause a conflict nor gap-fill the answer the reader will see.
|
|
20
|
+
const kept = upstreamOnly
|
|
21
|
+
? original.filter((f) => f.isUpstream && revalidateKindOf(f) !== 'revalidation').map(withoutRevalidation)
|
|
22
|
+
: showRevalidation
|
|
23
|
+
? hideRuledOut
|
|
24
|
+
? original.filter((f) => !['refuted', 'unreachable'].includes(revalidateKindOf(f)))
|
|
25
|
+
: original
|
|
26
|
+
: original.filter((f) => revalidateKindOf(f) !== 'revalidation').map(withoutRevalidation)
|
|
27
|
+
const group = kept.length === original.length && kept.every((f, i) => f === original[i]) ? original : kept
|
|
28
|
+
if (group.length > 0) rows.push({ group, sourceGroup: original, reportIndex, reportName: report.fileName ?? '', hasApp: group.some((f) => f.isApp) })
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const parent = rows.map((_, i) => i)
|
|
32
|
+
const hasApp = rows.map((r) => r.hasApp)
|
|
33
|
+
const find = (i) => {
|
|
34
|
+
let root = i
|
|
35
|
+
while (parent[root] !== root) root = parent[root]
|
|
36
|
+
while (parent[i] !== root) { const next = parent[i]; parent[i] = root; i = next }
|
|
37
|
+
return root
|
|
38
|
+
}
|
|
39
|
+
const union = (a, b) => {
|
|
40
|
+
a = find(a); b = find(b)
|
|
41
|
+
if (a === b) return
|
|
42
|
+
parent[b] = a
|
|
43
|
+
hasApp[a] ||= hasApp[b]
|
|
44
|
+
}
|
|
45
|
+
const byId = new Map()
|
|
46
|
+
for (let i = 0; i < rows.length; i++) {
|
|
47
|
+
for (const f of rows[i].group) {
|
|
48
|
+
if (!f.id) continue
|
|
49
|
+
if (!byId.has(f.id)) byId.set(f.id, [])
|
|
50
|
+
byId.get(f.id).push({ index: i, app: f.isApp })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// App identities and within-report overlaps establish their components first.
|
|
54
|
+
// Otherwise a source-only row could bridge two App rows through another report.
|
|
55
|
+
for (const occurrences of byId.values()) {
|
|
56
|
+
const ownReports = new Map()
|
|
57
|
+
const app = occurrences.find((entry) => entry.app)
|
|
58
|
+
for (const { index } of occurrences) {
|
|
59
|
+
if (app) union(app.index, index)
|
|
60
|
+
const reportIndex = rows[index].reportIndex
|
|
61
|
+
if (ownReports.has(reportIndex)) union(ownReports.get(reportIndex), index)
|
|
62
|
+
else ownReports.set(reportIndex, index)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const occurrences of byId.values()) {
|
|
66
|
+
let first = null
|
|
67
|
+
for (const { index } of occurrences) {
|
|
68
|
+
if (hasApp[find(index)]) continue
|
|
69
|
+
if (first === null) first = index
|
|
70
|
+
else union(first, index)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Explicit hints are retained for callers supplying already-deduplicated rows.
|
|
74
|
+
// Normal report loading no longer needs them: all original rows are retained.
|
|
75
|
+
for (const merge of merges) {
|
|
76
|
+
let first = null
|
|
77
|
+
for (const id of merge) {
|
|
78
|
+
for (const { index } of byId.get(id) ?? []) {
|
|
79
|
+
if (first === null) first = index
|
|
80
|
+
else union(first, index)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const components = new Map()
|
|
85
|
+
for (let i = 0; i < rows.length; i++) {
|
|
86
|
+
const root = find(i)
|
|
87
|
+
if (!components.has(root)) components.set(root, [])
|
|
88
|
+
components.get(root).push(rows[i])
|
|
89
|
+
}
|
|
90
|
+
const conflicts = new Map(), groups = []
|
|
91
|
+
for (const component of components.values()) {
|
|
92
|
+
const original = component[0].group
|
|
93
|
+
const ids = original.map((f) => f.id).filter(Boolean)
|
|
94
|
+
if (component.length === 1 && new Set(ids).size === ids.length && merges.length === 0) {
|
|
95
|
+
const app = reports.length > 1 && original.find((f) => f.isApp)
|
|
96
|
+
if (app) {
|
|
97
|
+
const group = [...original]
|
|
98
|
+
group.workspaceKey = app.id ?? String(app._id)
|
|
99
|
+
groups.push(...splitOutput(component, group, showRevalidation, upstreamOnly))
|
|
100
|
+
} else groups.push(...splitOutput(component, original, showRevalidation, upstreamOnly))
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
const rowConflicts = new Map()
|
|
104
|
+
const copies = new Map()
|
|
105
|
+
const findings = []
|
|
106
|
+
for (const { group, reportName } of component) {
|
|
107
|
+
for (const f of group) {
|
|
108
|
+
if (f.id && copies.has(f.id)) {
|
|
109
|
+
mergeReportDuplicateFields(copies.get(f.id), f, reportName, rowConflicts)
|
|
110
|
+
} else {
|
|
111
|
+
// Only the derived copy receives gap fills and per-report variants.
|
|
112
|
+
const copy = { ...f, _reportName: f._reportName ?? reportName }
|
|
113
|
+
if (f.id) copies.set(f.id, copy)
|
|
114
|
+
findings.push(copy)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Combined rows carry the author's order; singleton load order does not.
|
|
119
|
+
const canonical = new Set()
|
|
120
|
+
for (const merge of merges) for (const id of merge) if (copies.has(id)) canonical.add(id)
|
|
121
|
+
for (const { group } of component) {
|
|
122
|
+
if (group.length > 1) for (const f of group) if (f.id) canonical.add(f.id)
|
|
123
|
+
}
|
|
124
|
+
const group = [...canonical].map((id) => copies.get(id))
|
|
125
|
+
for (const f of findings) if (!canonical.has(f.id)) group.push(f)
|
|
126
|
+
// Separate App rows can begin with the SAME source id. Give each row its
|
|
127
|
+
// App identity so Lit keys, selection, and popup close targets stay unique.
|
|
128
|
+
if (reports.length > 1) {
|
|
129
|
+
const app = group.find((f) => f.isApp)
|
|
130
|
+
if (app) group.workspaceKey = app.id ?? String(app._id)
|
|
131
|
+
}
|
|
132
|
+
groups.push(...splitOutput(component, group, showRevalidation, upstreamOnly))
|
|
133
|
+
for (const [id, conflict] of rowConflicts) {
|
|
134
|
+
const previous = conflicts.get(id)
|
|
135
|
+
conflicts.set(id, previous
|
|
136
|
+
? { finding: previous.finding, copies: [...previous.copies, ...conflict.copies] }
|
|
137
|
+
: conflict)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
Object.defineProperty(groups, 'ruledOutIds', { value: ruledOutIds, configurable: true })
|
|
141
|
+
return { groups, conflicts }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function splitOutput(component, group, keepAppLayer, upstreamOnly) {
|
|
145
|
+
if (keepAppLayer) return [group]
|
|
146
|
+
if (upstreamOnly) {
|
|
147
|
+
// Upstream projection removes the App and own-source members before this
|
|
148
|
+
// function runs. Reconstruct the complete source component first so an
|
|
149
|
+
// App's inputs outside the upstream lens still determine its partition.
|
|
150
|
+
const complete = component.flatMap((row) => row.sourceGroup)
|
|
151
|
+
const partitions = splitRevalidationInputs(complete)
|
|
152
|
+
if (partitions.length === 1) return [group]
|
|
153
|
+
const projected = []
|
|
154
|
+
const covered = new Set()
|
|
155
|
+
for (const partition of partitions) {
|
|
156
|
+
const ids = new Set(partition.filter((f) => !f.isApp && f.id).map((f) => f.id))
|
|
157
|
+
const visible = group.filter((f) => ids.has(f.id))
|
|
158
|
+
if (visible.length > 0) {
|
|
159
|
+
projected.push(visible)
|
|
160
|
+
for (const finding of visible) covered.add(finding.id)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const groupIds = new Set(group.map((f) => f.id).filter(Boolean))
|
|
164
|
+
return covered.size === groupIds.size ? projected : [group]
|
|
165
|
+
}
|
|
166
|
+
const appFindings = component.flatMap((row) => row.sourceGroup.filter((f) => f.isApp))
|
|
167
|
+
return splitRevalidationInputs(group, appFindings)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function withoutRevalidation(finding) {
|
|
171
|
+
const fields = Object.keys(finding).filter((key) => key.startsWith('revalidate') || key === '_revalidationCopies')
|
|
172
|
+
if (fields.length === 0) return finding
|
|
173
|
+
const copy = { ...finding }
|
|
174
|
+
for (const field of fields) delete copy[field]
|
|
175
|
+
return copy
|
|
176
|
+
}
|