@preventive/triage 1.0.0-alpha.44 → 1.0.0-alpha.46
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/client/linked-findings.js +3 -0
- package/common/bundle-metadata.d.ts +1 -0
- package/common/bundle-metadata.js +1 -1
- package/common/bundle-sources.js +25 -2
- package/common/default-scan-models.ts +1 -1
- package/common/dependency-reviews.d.ts +0 -5
- package/common/dependency-reviews.js +0 -17
- package/common/line-diff.js +5 -4
- package/common/managed/agent-tasks.ts +292 -0
- package/common/managed/github-agents.ts +92 -0
- package/common/managed/github-logins.ts +49 -0
- package/common/managed/roles.ts +7 -0
- package/common/managed/routes.js +88 -7
- package/common/managed/team-app.d.ts +5 -2
- package/common/managed/team-app.js +2 -2
- package/common/server-info.ts +3 -0
- package/common/workspace-app.js +6 -3
- package/out/brotli-fallback.js +3 -3
- package/out/chunk-2XUEZHIP.js +18 -18
- package/out/chunk-2ZDZWLFY.js +1 -0
- package/out/chunk-3PS4KWD2.js +10 -0
- package/out/chunk-4HI2MSAV.js +17 -0
- package/out/chunk-4UFAMJAX.js +1 -0
- package/out/chunk-7C7DWL7I.js +1 -0
- package/out/chunk-7XRR4OFU.js +1 -0
- package/out/chunk-BC2UCLFJ.js +1 -0
- package/out/chunk-BOIXMUU5.js +3 -0
- package/out/chunk-C4Z6ZBXV.js +6 -6
- package/out/chunk-CC4OM6TZ.js +3 -0
- package/out/chunk-G24A42V6.js +2 -0
- package/out/chunk-GDPCLSOS.js +2 -0
- package/out/chunk-GO7FT4OD.js +1 -0
- package/out/chunk-I2MDGSQX.js +3 -0
- package/out/chunk-IYPY47MC.js +1 -0
- package/out/chunk-IZ7POWI3.js +18 -0
- package/out/chunk-JCIIBLKR.js +1 -1
- package/out/chunk-JKGQ3O7O.js +6 -0
- package/out/chunk-LE5ZWLG4.js +235 -0
- package/out/chunk-MSION3G4.js +36 -0
- package/out/chunk-NRPC74AM.js +1 -1
- package/out/chunk-OKRLLE5I.js +17 -0
- package/out/chunk-OOJM4CTU.js +1 -1
- package/out/chunk-PNHBZGDD.js +1 -1
- package/out/chunk-PXK7EU4V.js +1 -0
- package/out/chunk-QB4CBOX2.js +1 -0
- package/out/chunk-R3NZFXVR.js +1 -0
- package/out/chunk-R5O6FAW4.js +1 -1
- package/out/chunk-S6GIXWQW.js +52 -0
- package/out/chunk-SXV2T5C4.js +80 -0
- package/out/chunk-TUII34K2.js +1 -1
- package/out/chunk-V3KWNNMY.js +1 -0
- package/out/chunk-VFWMQ3LG.js +2 -0
- package/out/chunk-VH4XMZIW.js +2 -0
- package/out/chunk-WFYLMF6Z.js +10 -0
- package/out/chunk-WQ74ZBZF.js +7 -0
- package/out/client-managed-import.js +3 -3
- package/out/client-managed.js +31 -35
- package/out/client-sync.js +11 -11
- package/out/compare.js +35 -0
- package/out/dialogs.js +51 -0
- package/out/github-issue-authorized.html +1 -1
- package/out/github-issue-authorized.js +1 -1
- package/out/graph.js +17 -17
- package/out/index.html +30 -34
- package/out/prism.js +14 -14
- package/out/scan.js +2 -0
- package/out/terminal.js +294 -293
- package/out/view.css +1 -1
- package/out/view.js +16 -107
- package/package.json +53 -6
- package/risk/actions/findings.js +161 -0
- package/risk/actions/resolve.js +219 -0
- package/risk/actions/scripts/commands.js +182 -0
- package/risk/actions/scripts/grade.js +113 -0
- package/risk/actions/scripts/packages.js +123 -0
- package/risk/actions/scripts/shell.js +169 -0
- package/risk/actions/uses.js +76 -0
- package/risk/actions/workflow.js +110 -0
- package/risk/files/hosts.js +6 -6
- package/risk/files/readability.js +23 -17
- package/risk/files/runs-code.js +18 -6
- package/risk/files/script.js +7 -3
- package/risk/files/stamps.js +8 -7
- package/risk/index.d.ts +71 -1
- package/risk/index.js +6 -2
- package/risk/npm/assess.js +1 -1
- package/risk/npm/compare.js +34 -10
- package/risk/npm/files.js +413 -2
- package/risk/npm/tarball.js +56 -73
- package/server-e2e/app.ts +5 -4
- package/server-e2e/http.ts +5 -2
- package/server-managed/agent-merges.ts +198 -0
- package/server-managed/app-agents.ts +30 -0
- package/server-managed/avatar-store.ts +1 -0
- package/server-managed/bundle-cache.ts +7 -1
- package/server-managed/combined.ts +3 -2
- package/server-managed/commit-coauthors.ts +83 -0
- package/server-managed/commit-lockfiles.ts +72 -0
- package/server-managed/config.ts +6 -0
- package/server-managed/db-methods.ts +66 -19
- package/server-managed/db-neon.ts +89 -21
- package/server-managed/db-schema.ts +13 -2
- package/server-managed/db.ts +9 -1
- package/server-managed/dependabot-access.ts +60 -0
- package/server-managed/dependabot-alerts.ts +185 -0
- package/server-managed/dependency-review-comments.ts +97 -0
- package/server-managed/dependency-reviews.ts +78 -18
- package/server-managed/github-accounts.ts +33 -0
- package/server-managed/github-actions.ts +71 -0
- package/server-managed/github-app.ts +33 -13
- package/server-managed/github-errors.ts +2 -0
- package/server-managed/github-issue-links.ts +11 -5
- package/server-managed/github-link-oauth.ts +69 -0
- package/server-managed/github-links.ts +204 -0
- package/server-managed/github-oauth.ts +5 -2
- package/server-managed/github-pulls.ts +2 -2
- package/server-managed/github-requests.ts +39 -0
- package/server-managed/github-users.ts +30 -0
- package/server-managed/http-response.ts +10 -2
- package/server-managed/http.ts +1251 -97
- package/server-managed/index.ts +13 -8
- package/server-managed/kept-briefly.ts +37 -0
- package/server-managed/locked-packages.ts +37 -16
- package/server-managed/lockfile-scope.ts +49 -0
- package/server-managed/npm-delta-worker.js +23 -0
- package/server-managed/npm-delta.ts +178 -0
- package/server-managed/npm-insights.ts +20 -11
- package/server-managed/npm-kept.ts +83 -6
- package/server-managed/npm-loads.ts +114 -37
- package/server-managed/npm-packages.ts +110 -64
- package/server-managed/npm-risk.ts +4 -1
- package/server-managed/pretty-print.ts +67 -23
- package/server-managed/pull-comment-reviews.ts +161 -0
- package/server-managed/pull-dependencies.ts +300 -0
- package/server-managed/pull-dependency-reviews.ts +318 -0
- package/server-managed/pull-reviews.ts +205 -0
- package/server-managed/queue.ts +16 -0
- package/server-managed/release-commits.ts +84 -0
- package/server-managed/rename-diff.ts +22 -13
- package/server-managed/report-sources.ts +1 -1
- package/server-managed/report-store.ts +42 -9
- package/server-managed/repository-actions.ts +218 -0
- package/server-managed/repository-agents.ts +220 -0
- package/server-managed/repository-browser.ts +166 -37
- package/server-managed/repository-changes.ts +284 -0
- package/server-managed/repository-code.ts +52 -0
- package/server-managed/repository-dependency-reviews.ts +157 -0
- package/server-managed/repository-history.ts +461 -0
- package/server-managed/repository-issues.ts +181 -0
- package/server-managed/repository-pulse.ts +439 -0
- package/server-managed/repository-risk-audit.ts +13 -0
- package/server-managed/repository-risk-read.ts +170 -0
- package/server-managed/repository-risk.ts +133 -118
- package/server-managed/reviewed-dependencies.ts +149 -0
- package/server-managed/session.ts +27 -9
- package/server-managed/sql.ts +6 -3
- package/server-managed/storage-stores.ts +5 -0
- package/server-managed/storage.ts +4 -2
- package/server-managed/team-app.ts +19 -3
- package/server-managed/team-reports.ts +24 -12
- package/server-managed/upstream-cache.ts +12 -0
- package/server-managed/workspace-shares.ts +4 -1
- package/server.ts +25 -5
- package/out/chunk-2ABLKCOY.js +0 -46
- package/out/chunk-2KBF5TZ7.js +0 -2
- package/out/chunk-35VE6CDH.js +0 -2
- package/out/chunk-3BZ7JERB.js +0 -1
- package/out/chunk-4XCDFGDP.js +0 -10
- package/out/chunk-5LSXOLUS.js +0 -1
- package/out/chunk-5RCM2J63.js +0 -1
- package/out/chunk-7B6HB4D7.js +0 -1
- package/out/chunk-AJ4GTATZ.js +0 -3
- package/out/chunk-CH4UN6WK.js +0 -225
- package/out/chunk-CMQA4DM6.js +0 -1
- package/out/chunk-CVVJAXVY.js +0 -2
- package/out/chunk-DIJJNTRH.js +0 -10
- package/out/chunk-EDKLBQQN.js +0 -17
- package/out/chunk-F47DXCEV.js +0 -33
- package/out/chunk-FK3DZEKL.js +0 -1
- package/out/chunk-G6AJWENO.js +0 -1
- package/out/chunk-GJ4IUCNS.js +0 -1
- package/out/chunk-GNXOKIGP.js +0 -80
- package/out/chunk-GZ4MS3TE.js +0 -13
- package/out/chunk-GZWM7UQM.js +0 -2
- package/out/chunk-IU3CCINR.js +0 -3
- package/out/chunk-K3X5EJBQ.js +0 -2
- package/out/chunk-KEX2ATEW.js +0 -2
- package/out/chunk-KYCNJVB7.js +0 -1
- package/out/chunk-LPCTJYNA.js +0 -7
- package/out/chunk-O4RJY5TP.js +0 -2
- package/out/chunk-OD4LPN3H.js +0 -1
- package/out/chunk-QWDWTBM7.js +0 -1
- package/out/chunk-QYWKC557.js +0 -1
- package/out/chunk-R75XOKUP.js +0 -1
- package/out/chunk-SWTLADW5.js +0 -1
- package/out/chunk-T7OKH4VW.js +0 -1
- package/out/chunk-TZ5KB2Y5.js +0 -10
- package/out/chunk-UNTRGE26.js +0 -2
- package/out/chunk-UTR2LVME.js +0 -2
- package/out/chunk-UYAXVRVL.js +0 -1
- package/out/chunk-V3ME6FI5.js +0 -2
- package/out/chunk-V5O7M2YT.js +0 -1
- package/out/chunk-VIHGO77Y.js +0 -1
- package/out/chunk-W4J3MGLB.js +0 -1
- package/out/chunk-WGG7KQUH.js +0 -1
- package/out/chunk-XYFXXB2G.js +0 -10
- package/out/chunk-ZESLQCTF.js +0 -6
package/common/managed/routes.js
CHANGED
|
@@ -28,6 +28,13 @@ export const MANAGED_PAGES = Object.freeze({
|
|
|
28
28
|
'manage-history': '/manage/history',
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
+
// A team's lists, each at /team/<slug>/<what it lists>; its dependencies'
|
|
32
|
+
// sub-tabs past the first at /team/<slug>/dependencies/<tab>.
|
|
33
|
+
const WORKSPACE_CONTENT_VIEWS = new Set(['workspace-reports', 'workspace-bundles', 'workspace-repositories', 'workspace-dependencies'])
|
|
34
|
+
export const DEPENDENCY_TABS = new Set(['pulls', 'versions', 'branch', 'reviews'])
|
|
35
|
+
// A route's `dependencyTab` field, where it names one.
|
|
36
|
+
const dependencyTabField = route => route.view === 'workspace-dependencies' && route.dependencyTab != null ? { dependencyTab: route.dependencyTab } : {}
|
|
37
|
+
|
|
31
38
|
// Dot-only path components are normalised away by URL parsers, even escaped.
|
|
32
39
|
function findingPath(id) {
|
|
33
40
|
if (!isLinkableFindingId(id) || id === '.' || id === '..') return null
|
|
@@ -38,9 +45,13 @@ export function managedRoutePath(route) {
|
|
|
38
45
|
if (!route) return null
|
|
39
46
|
if (route.view === 'home') return '/'
|
|
40
47
|
if (route.view === 'reviews') return '/my/reviews'
|
|
48
|
+
if (route.view === 'profile') return '/my/profile'
|
|
41
49
|
if (route.view === 'npm') return npmPackagePath(route)
|
|
42
|
-
if (route.view === '
|
|
43
|
-
|
|
50
|
+
if (route.view === 'repository-code') return repositoryCodePath(route)
|
|
51
|
+
if (WORKSPACE_CONTENT_VIEWS.has(route.view)) {
|
|
52
|
+
const tab = dependencyTabField(route).dependencyTab ?? 'pulls'
|
|
53
|
+
if (!/^[A-Za-z0-9_-]+$/u.test(route.teamSlug ?? '') || !DEPENDENCY_TABS.has(tab)) return null
|
|
54
|
+
return `/team/${route.teamSlug}/${route.view.slice(10)}${tab === 'pulls' ? '' : `/${tab}`}`
|
|
44
55
|
}
|
|
45
56
|
if (route.view === 'bundles') {
|
|
46
57
|
if (!/^[A-Za-z0-9_-]+$/u.test(route.bundleSlug ?? '')
|
|
@@ -128,6 +139,66 @@ function parseNpmRoute(path, hash) {
|
|
|
128
139
|
return !match[5] && /^[1-9]\d*$/u.test(match[4]) && Number.isSafeInteger(file) ? { ...route, file, ...codeLines(hash) } : null
|
|
129
140
|
}
|
|
130
141
|
|
|
142
|
+
// The code viewer: a directory of a repository at a commit, on its Code,
|
|
143
|
+
// Search, Treemap, Compare, Commits, Issues, Pull requests, Agents, Pulse
|
|
144
|
+
// or Replay tab, `/repo/<repo id>/<commit>[/<tab>…][?path=<directory>]`,
|
|
145
|
+
// the repository's root where it names no directory. Code, the tab a bare
|
|
146
|
+
// link opens, names its file by number and its lines in the fragment, as a
|
|
147
|
+
// bundle's Code does: `/code/<file>#L4`. Compare names the commit compared
|
|
148
|
+
// with, then its mode past the Overview, as an npm version's does:
|
|
149
|
+
// `/compare/<commit>/code`. Without a commit,
|
|
150
|
+
// `/repo/<repo id>[?path=<directory>]`, it opens on the default
|
|
151
|
+
// branch's head, or on the revision a route held in memory names (`ref`),
|
|
152
|
+
// and its route then names the commit it opened. Links from before it moved
|
|
153
|
+
// name it under `/manage/code/`, and open the same.
|
|
154
|
+
export const REPOSITORY_CODE_TABS = new Set(['code', 'search', 'treemap', 'compare', 'commits', 'issues', 'pulls', 'agents', 'pulse', 'replay'])
|
|
155
|
+
// The tabs reading none of the directory's files, which a directory at a
|
|
156
|
+
// commit shows alone.
|
|
157
|
+
export const REPOSITORY_FILELESS_TABS = new Set(['commits', 'issues', 'pulls', 'agents', 'pulse', 'replay'])
|
|
158
|
+
const COMMIT = /^[a-f\d]{40}$/u
|
|
159
|
+
const MAX_DIRECTORY = 500
|
|
160
|
+
const isRepoId = value => Number.isSafeInteger(value) && value > 0
|
|
161
|
+
|
|
162
|
+
// A directory as the server takes one (server-managed/repo-path.ts), in its
|
|
163
|
+
// canonical form: `''` the root, else names with no empty, `.` or `..` one
|
|
164
|
+
// among them, nor control characters, backslashes or spaces around one.
|
|
165
|
+
export function isRepositoryDirectory(path) {
|
|
166
|
+
return typeof path === 'string' && (path === '' || path.length <= MAX_DIRECTORY && !/[\p{Cc}\\]/u.test(path)
|
|
167
|
+
&& path.split('/').every(part => part !== '' && part !== '.' && part !== '..' && part === part.trim()))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function repositoryCodePath(route) {
|
|
171
|
+
const tab = route.bundleTab ?? 'code'
|
|
172
|
+
const path = route.path ?? ''
|
|
173
|
+
if (!isRepoId(route.repoId) || (route.commit != null && !COMMIT.test(route.commit)) || !isRepositoryDirectory(path) || !REPOSITORY_CODE_TABS.has(tab)
|
|
174
|
+
|| (route.compareCommit != null && !COMMIT.test(route.compareCommit))) return null
|
|
175
|
+
const directory = path ? `?path=${path.split('/').map(encodeURIComponent).join('/')}` : ''
|
|
176
|
+
if (route.commit == null) return `/repo/${route.repoId}${directory}`
|
|
177
|
+
const file = tab === 'code' && isLineNumber(route.file) ? `/code/${route.file}` : tab === 'code' ? '' : `/${tab}`
|
|
178
|
+
const compare = tab === 'compare' && route.compareCommit != null ? `/${route.compareCommit}${compareModeSuffix(route.compareMode)}` : ''
|
|
179
|
+
const lines = tab === 'code' && isLineNumber(route.file) && isLineNumber(route.line)
|
|
180
|
+
? `#L${route.line}${isLineNumber(route.endLine) && route.endLine > route.line ? `-L${route.endLine}` : ''}` : ''
|
|
181
|
+
return `/repo/${route.repoId}/${route.commit}${file}${compare}${directory}${lines}`
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function parseRepositoryCodeRoute(url) {
|
|
185
|
+
const match = /^\/(?:repo|manage\/code)\/([1-9]\d*)(?:\/([a-f\d]{40})(?:\/(code|search|treemap|compare|commits|history|issues|pulls|agents|pulse|replay)(?:\/([^/]+)(?:\/([a-z]+))?)?)?)?$/u
|
|
186
|
+
.exec(url.pathname.replace(/\/$/u, ''))
|
|
187
|
+
if (!match) return undefined
|
|
188
|
+
const repoId = Number(match[1])
|
|
189
|
+
const path = url.searchParams.get('path') ?? ''
|
|
190
|
+
// Commits' tab was History's, `/history`, which links still name.
|
|
191
|
+
const tab = match[3] === 'history' ? 'commits' : match[3] ?? 'code'
|
|
192
|
+
if (!isRepoId(repoId) || !isRepositoryDirectory(path)) return null
|
|
193
|
+
const route = { view: 'repository-code', repoId, commit: match[2] ?? null, path, bundleTab: tab }
|
|
194
|
+
if (match[4] == null) return route
|
|
195
|
+
if (tab === 'compare') {
|
|
196
|
+
return COMMIT.test(match[4]) && (match[5] == null || COMPARE_MODES.has(match[5])) ? { ...route, compareCommit: match[4], ...compareModeField(match[5]) } : null
|
|
197
|
+
}
|
|
198
|
+
const file = Number(match[4])
|
|
199
|
+
return tab === 'code' && match[5] == null && /^[1-9]\d*$/u.test(match[4]) && Number.isSafeInteger(file) ? { ...route, file, ...codeLines(url.hash) } : null
|
|
200
|
+
}
|
|
201
|
+
|
|
131
202
|
function isLineNumber(value) {
|
|
132
203
|
return Number.isSafeInteger(value) && value > 0
|
|
133
204
|
}
|
|
@@ -144,6 +215,12 @@ export function parseManagedRoute(url) {
|
|
|
144
215
|
const path = url.pathname.replace(/\/$/u, '') || '/'
|
|
145
216
|
if (path === '/' || path === '/index.html') return { view: 'home' }
|
|
146
217
|
if (path === '/my/reviews') return { view: 'reviews' }
|
|
218
|
+
// Linking an account lands here, naming why GitHub's answer was refused,
|
|
219
|
+
// which the page shows once: the address it settles on drops it.
|
|
220
|
+
if (path === '/my/profile') {
|
|
221
|
+
const linkError = url.searchParams.get('link-error')
|
|
222
|
+
return { view: 'profile', ...(linkError && /^[a-z-]{1,64}$/u.test(linkError) ? { linkError } : {}) }
|
|
223
|
+
}
|
|
147
224
|
const view = Object.keys(MANAGED_PAGES).find(key => MANAGED_PAGES[key] === path)
|
|
148
225
|
if (view) {
|
|
149
226
|
const createRepoId = Number(url.searchParams.get('createRepo'))
|
|
@@ -169,8 +246,12 @@ export function parseManagedRoute(url) {
|
|
|
169
246
|
}
|
|
170
247
|
const npm = parseNpmRoute(path, url.hash)
|
|
171
248
|
if (npm !== undefined) return npm
|
|
172
|
-
const
|
|
249
|
+
const code = parseRepositoryCodeRoute(url)
|
|
250
|
+
if (code !== undefined) return code
|
|
251
|
+
const contentList = /^\/team\/([A-Za-z0-9_-]+)\/(reports|bundles|repositories|dependencies)$/u.exec(path)
|
|
173
252
|
if (contentList) return { view: `workspace-${contentList[2]}`, teamSlug: contentList[1] }
|
|
253
|
+
const dependencies = /^\/team\/([A-Za-z0-9_-]+)\/dependencies\/([a-z]+)$/u.exec(path)
|
|
254
|
+
if (dependencies) return DEPENDENCY_TABS.has(dependencies[2]) ? { view: 'workspace-dependencies', teamSlug: dependencies[1], dependencyTab: dependencies[2] } : null
|
|
174
255
|
const match = /^\/team\/([^/]+)(?:\/report\/([^/]+))?(?:\/(files)|\/finding\/([^/]+))?$/u.exec(path)
|
|
175
256
|
if (!match) return null
|
|
176
257
|
try {
|
|
@@ -187,9 +268,9 @@ export function parseManagedRoute(url) {
|
|
|
187
268
|
// URL tokens are exact server-assigned slugs. Application state and API calls
|
|
188
269
|
// continue to use UUIDs; never guess IDs from suffixes or accept ID aliases.
|
|
189
270
|
export function resolveManagedRoute(route, teams, adminBundles = []) {
|
|
190
|
-
if (
|
|
271
|
+
if (WORKSPACE_CONTENT_VIEWS.has(route.view)) {
|
|
191
272
|
const matches = teams.filter(team => team.slug === route.teamSlug)
|
|
192
|
-
return matches.length === 1 ? { view: route.view, teamId: matches[0].id } : null
|
|
273
|
+
return matches.length === 1 ? { view: route.view, teamId: matches[0].id, ...dependencyTabField(route) } : null
|
|
193
274
|
}
|
|
194
275
|
if (route.view === 'bundles') {
|
|
195
276
|
const { teamSlug, bundleSlug, compareSlug, compareMode, ...rest } = route
|
|
@@ -220,9 +301,9 @@ export function resolveManagedRoute(route, teams, adminBundles = []) {
|
|
|
220
301
|
}
|
|
221
302
|
|
|
222
303
|
export function managedRouteForIds(route, teams, adminBundles = []) {
|
|
223
|
-
if (
|
|
304
|
+
if (WORKSPACE_CONTENT_VIEWS.has(route.view)) {
|
|
224
305
|
const team = teams.find(entry => entry.id === route.teamId)
|
|
225
|
-
const result = { view: route.view, teamSlug: team?.slug }
|
|
306
|
+
const result = { view: route.view, teamSlug: team?.slug, ...dependencyTabField(route) }
|
|
226
307
|
return team?.slug && resolveManagedRoute(result, teams) ? result : null
|
|
227
308
|
}
|
|
228
309
|
if (route.view === 'bundles') {
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Set for a team that is not App: `findings`, its rows (with `countFindings`),
|
|
2
|
+
// and `appReports`, set by the managed catalog: how many reports open in App mode alone.
|
|
3
|
+
export type TeamAppMetadata = { appMode: true; appFindings: number } | { appMode: false; appReports?: number; findings?: number }
|
|
4
|
+
export function managedTeamAppMetadata(workspace: readonly { filename: string; data: unknown }[] & { links?: readonly (readonly string[])[] },
|
|
5
|
+
options?: { countFindings?: boolean }): TeamAppMetadata
|
|
@@ -8,7 +8,7 @@ import { workspaceAppMetadata } from '../workspace-app.js'
|
|
|
8
8
|
// its `links`. The managed server classifies each team before sending its
|
|
9
9
|
// catalog, so the sidebar opens a team collapsed to its App findings at once.
|
|
10
10
|
// The server backfills finding IDs before building these envelopes.
|
|
11
|
-
export function managedTeamAppMetadata(workspace) {
|
|
11
|
+
export function managedTeamAppMetadata(workspace, options = {}) {
|
|
12
12
|
const duplicates = new Map(), reports = []
|
|
13
13
|
collectDuplicates(workspace.links ?? [], duplicates)
|
|
14
14
|
for (const { filename, data } of workspace) {
|
|
@@ -27,5 +27,5 @@ export function managedTeamAppMetadata(workspace) {
|
|
|
27
27
|
}))
|
|
28
28
|
reports.push({ fileName: filename, groups })
|
|
29
29
|
}
|
|
30
|
-
return workspaceAppMetadata(reports, id => [...duplicates.get(id) ?? []])
|
|
30
|
+
return workspaceAppMetadata(reports, id => [...duplicates.get(id) ?? []], options)
|
|
31
31
|
}
|
package/common/server-info.ts
CHANGED
|
@@ -26,6 +26,9 @@ export interface ManagedSessionInfo {
|
|
|
26
26
|
user: { id: string; login: string; name: string | null; role: string }
|
|
27
27
|
csrfToken: string
|
|
28
28
|
viewer?: { id: string; login: string; name: string | null }
|
|
29
|
+
// Where the user publishes dependency reviews to some team: an npm
|
|
30
|
+
// version's Review tab is theirs (server-managed/dependency-reviews.ts).
|
|
31
|
+
dependencyReview?: true
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
// The `server-info` frame payload (the `type` discriminant is added at the
|
package/common/workspace-app.js
CHANGED
|
@@ -24,11 +24,14 @@ function onlyUnjudgedImports(groups) {
|
|
|
24
24
|
|
|
25
25
|
// Evaluate the entire workspace, independent of triage, filters, or the lens
|
|
26
26
|
// left active by another report. Use the same merge and link rules as the view.
|
|
27
|
-
|
|
27
|
+
// `countFindings` has a workspace that is not App count its rows too, after
|
|
28
|
+
// the same merging, for a caller that shows it collapsed (managed teams).
|
|
29
|
+
export function workspaceAppMetadata(reports, duplicatesOf = () => [], { countFindings = false } = {}) {
|
|
28
30
|
const { groups, conflicts } = mergeReportGroups(reports, { hideRuledOut: true })
|
|
29
|
-
if (conflicts.size > 0) return { appMode: false }
|
|
30
31
|
const linked = mergeLinkedWorkspaceGroups(groups, duplicatesOf, appTabs)
|
|
31
|
-
|
|
32
|
+
const notApp = countFindings ? { appMode: false, findings: linked.length } : { appMode: false }
|
|
33
|
+
if (conflicts.size > 0) return notApp
|
|
34
|
+
if (!onlyUnjudgedImports(linked) && !canLockConfirmed(linked, { tabs: appTabs, kindOf: revalidateKindOf, severityMode: 'corrected' })) return notApp
|
|
32
35
|
return {
|
|
33
36
|
appMode: true,
|
|
34
37
|
appFindings: linked.filter((group) => appTabs(group).some((f) => f.isApp)).length,
|