@preventive/triage 1.0.0-alpha.26 → 1.0.0-alpha.28
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-APACHE +202 -0
- package/client/linked-findings.js +1 -1
- package/common/bundle-metadata.js +12 -10
- package/common/code-language.js +17 -2
- package/common/default-scan-models.ts +3 -3
- package/common/finding-id.js +1 -1
- package/common/managed/report-content.ts +1 -1
- package/common/managed/report-filter.ts +1 -1
- package/out/client-managed-import.js +24 -24
- package/out/client-managed.js +93 -68
- package/out/graph.js +11 -11
- package/out/index.html +1 -1
- package/out/prism.js +2 -2
- package/out/stasis.svg +0 -25
- package/out/terminal.js +163 -163
- package/out/view.css +1 -1
- package/out/view.js +223 -190
- package/package.json +29 -29
- package/server-common/storage-crypto.ts +182 -0
- package/server-common/storage-log.ts +5 -1
- package/server-common/vercel-blob.ts +6 -3
- package/server-e2e/static.ts +3 -4
- package/server-managed/avatar-store.ts +1 -40
- package/server-managed/blob-store.ts +3 -52
- package/server-managed/bundle-advisories.ts +53 -0
- package/server-managed/bundle-advisory-inventory.ts +75 -0
- package/server-managed/bundle-build-leases.ts +41 -0
- package/server-managed/bundle-build-worker.js +44 -0
- package/server-managed/bundle-build.ts +141 -0
- package/server-managed/bundle-cache.ts +22 -41
- package/server-managed/bundle-store.ts +3 -7
- package/server-managed/bundle-summary-cache.ts +27 -9
- package/server-managed/bundle.ts +66 -1
- package/server-managed/cache-storage.ts +4 -25
- package/server-managed/cli.js +10 -2
- package/server-managed/config.ts +12 -1
- package/server-managed/content-access.ts +1 -1
- package/server-managed/db-methods.ts +163 -40
- package/server-managed/db-neon.ts +124 -30
- package/server-managed/db-schema.ts +2 -0
- package/server-managed/db.ts +11 -1
- package/server-managed/github-app.ts +10 -15
- package/server-managed/github-errors.ts +21 -0
- package/server-managed/github-issues.ts +1 -1
- package/server-managed/github-metadata.ts +34 -1
- package/server-managed/github-pulls.ts +142 -30
- package/server-managed/http.ts +278 -167
- package/server-managed/index.ts +26 -9
- package/server-managed/management-catalog.ts +45 -0
- package/server-managed/object-storage-disk.ts +144 -0
- package/server-managed/object-storage-vercel.ts +60 -0
- package/server-managed/object-storage.ts +71 -0
- package/server-managed/public-workspace.ts +20 -14
- package/server-managed/report-migration.ts +1 -1
- package/server-managed/report-sources.ts +14 -4
- package/server-managed/repository-browser.ts +8 -1
- package/server-managed/repository-discovery.ts +1 -1
- package/server-managed/revisions.ts +35 -0
- package/server-managed/solidity-entry-points.ts +69 -0
- package/server-managed/sql-postgres.ts +1 -0
- package/server-managed/sql.ts +14 -8
- package/server-managed/storage-command.ts +16 -0
- package/server-managed/storage-db.ts +175 -0
- package/server-managed/storage-encryption.ts +211 -0
- package/server-managed/storage-maintenance.ts +197 -0
- package/server-managed/storage-payload.ts +72 -0
- package/server-managed/storage-stores.ts +81 -0
- package/server-managed/storage.ts +48 -24
- package/server-managed/team-feed.ts +50 -5
- package/server-managed/team-reports.ts +85 -22
- package/server-managed/uploads.ts +2 -2
- package/server-managed/workspace-shares.ts +15 -3
- package/report/index.js +0 -260
- package/report/src/finding-id.js +0 -80
- package/report/src/finding.js +0 -314
- package/report/src/labels.js +0 -35
- package/report/src/md-structure.js +0 -471
- package/report/src/md-text.js +0 -167
- package/report/src/meta.js +0 -76
- package/report/src/parse-codex.js +0 -149
- package/report/src/parse-deepsec.js +0 -199
- package/report/src/parse-deepview-fields.js +0 -375
- package/report/src/parse-deepview-md.js +0 -186
- package/report/src/parse-md-id.js +0 -137
- package/report/src/parse-md.js +0 -323
- package/report/src/parse-piolium-id.js +0 -79
- package/report/src/parse-piolium-rows.js +0 -126
- package/report/src/parse-piolium-tokens.js +0 -185
- package/report/src/parse-piolium.js +0 -399
- package/report/src/security.js +0 -63
- package/report/src/severity.js +0 -18
- package/report/src/utf8.js +0 -21
- package/report/src/write-md-finding.js +0 -273
- package/report/src/write-md.js +0 -291
- package/server-managed/blob-vercel.ts +0 -127
- /package/{LICENSE → LICENSE-MIT} +0 -0
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer'
|
|
2
|
-
import { Readable } from 'node:stream'
|
|
3
|
-
import { type VercelBlobSdk, isNotFound, loadVercelBlobSdk } from '../server-common/vercel-blob.ts'
|
|
4
|
-
import type { AvatarStore } from './avatar-store.ts'
|
|
5
|
-
import type { BlobStore } from './blob-store.ts'
|
|
6
|
-
import { type CacheStorage, validateCacheKey } from './cache-storage.ts'
|
|
7
|
-
import type { BundleCacheStorage } from './bundle-cache.ts'
|
|
8
|
-
import { createBundleStore } from './bundle-store.ts'
|
|
9
|
-
|
|
10
|
-
const ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u
|
|
11
|
-
function validate(id: string): string {
|
|
12
|
-
if (!ID.test(id)) throw new Error('Invalid managed blob id')
|
|
13
|
-
return id
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type ListedBlob = Awaited<ReturnType<VercelBlobSdk['list']>>['blobs'][number]
|
|
17
|
-
|
|
18
|
-
async function deletePrefix(blobs: VercelBlobSdk, token: string, prefix: string, remove: (path: string) => Promise<void>, matches = (_blob: ListedBlob) => true): Promise<void> {
|
|
19
|
-
const cursors = new Set<string>(), paths = new Set<string>()
|
|
20
|
-
let cursor: string | undefined
|
|
21
|
-
// Finish listing before deleting so pagination cannot skip objects as the
|
|
22
|
-
// listed set shrinks. Callers supply a trailing slash to isolate a namespace.
|
|
23
|
-
do {
|
|
24
|
-
const page = await blobs.list({ token, prefix, ...(cursor ? { cursor } : {}) })
|
|
25
|
-
for (const blob of page.blobs) if (blob.pathname.startsWith(prefix) && matches(blob)) paths.add(blob.pathname)
|
|
26
|
-
if (!page.hasMore) break
|
|
27
|
-
if (!page.cursor || cursors.has(page.cursor)) throw new Error('Invalid blob pagination')
|
|
28
|
-
cursor = page.cursor
|
|
29
|
-
cursors.add(cursor)
|
|
30
|
-
} while (cursor)
|
|
31
|
-
for (const path of paths) await remove(path)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function createBlobAvatarStore(avatarBlobs: BlobStore): AvatarStore {
|
|
35
|
-
return {
|
|
36
|
-
put(id, contentType, bytes) {
|
|
37
|
-
const type = contentType.split(';', 1)[0]!.trim()
|
|
38
|
-
if (!/^image\/[a-z0-9.+-]+$/iu.test(type)) throw new Error('Invalid avatar type')
|
|
39
|
-
return avatarBlobs.put(id, Buffer.concat([Buffer.from(`${type}\n`), bytes]))
|
|
40
|
-
},
|
|
41
|
-
async get(id) {
|
|
42
|
-
const bytes = await avatarBlobs.get(id)
|
|
43
|
-
if (!bytes) return null
|
|
44
|
-
const split = bytes.indexOf(10)
|
|
45
|
-
if (split < 0 || split > 100) throw new Error('Invalid cached avatar')
|
|
46
|
-
return { contentType: bytes.subarray(0, split).toString(), bytes: bytes.subarray(split + 1) }
|
|
47
|
-
},
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function openManagedVercelStorage(token: string, sdk?: VercelBlobSdk) {
|
|
52
|
-
const blobs = sdk ?? await loadVercelBlobSdk()
|
|
53
|
-
const options = { token, access: 'private' as const, useCache: false }
|
|
54
|
-
async function put(path: string, bytes: Buffer) {
|
|
55
|
-
await blobs.put(path, bytes, { token, access: 'private', addRandomSuffix: false,
|
|
56
|
-
allowOverwrite: true, contentType: 'application/octet-stream', cacheControlMaxAge: 60 })
|
|
57
|
-
}
|
|
58
|
-
async function open(path: string) {
|
|
59
|
-
try {
|
|
60
|
-
const result = await blobs.get(path, options)
|
|
61
|
-
if (!result) return null
|
|
62
|
-
if (result.statusCode !== 200 || !result.stream) throw new Error('Unexpected blob response')
|
|
63
|
-
// Private SDK GETs may report zero for a nonempty body. Stream without
|
|
64
|
-
// Content-Length in that case so HTTP clients do not truncate the body.
|
|
65
|
-
const size = result.blob.size === 0 ? null : result.blob.size
|
|
66
|
-
return { size, stream: Readable.fromWeb(result.stream as Parameters<typeof Readable.fromWeb>[0]) }
|
|
67
|
-
} catch (err) { if (isNotFound(err, blobs)) return null; throw err }
|
|
68
|
-
}
|
|
69
|
-
async function get(path: string) {
|
|
70
|
-
const result = await open(path)
|
|
71
|
-
if (!result) return null
|
|
72
|
-
const parts: Buffer[] = []
|
|
73
|
-
for await (const chunk of result.stream) parts.push(Buffer.from(chunk))
|
|
74
|
-
return Buffer.concat(parts)
|
|
75
|
-
}
|
|
76
|
-
async function remove(path: string) {
|
|
77
|
-
try { await blobs.del(path, { token }) } catch (err) { if (!isNotFound(err, blobs)) throw err }
|
|
78
|
-
}
|
|
79
|
-
function store(name: string, suffix = ''): BlobStore {
|
|
80
|
-
const path = (id: string) => `.managed/${name}/${validate(id)}${suffix}`
|
|
81
|
-
return {
|
|
82
|
-
async put(id, bytes) { await put(path(id), bytes) },
|
|
83
|
-
async get(id) { return await get(path(id)) },
|
|
84
|
-
open: id => open(path(id)),
|
|
85
|
-
async delete(id) { await remove(path(id)) },
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
const avatarStore = createBlobAvatarStore(store('avatars'))
|
|
89
|
-
const cachePath = (id: string, file: string) => `.managed/cache/bundles/${validate(id)}/${file}`
|
|
90
|
-
const cacheStorage: BundleCacheStorage = {
|
|
91
|
-
async exists(id, file) {
|
|
92
|
-
try { await blobs.head(cachePath(id, file), { token }); return true }
|
|
93
|
-
catch (err) { if (isNotFound(err, blobs)) return false; throw err }
|
|
94
|
-
},
|
|
95
|
-
put: (id, file, bytes) => put(cachePath(id, file), bytes),
|
|
96
|
-
async open(id, file) {
|
|
97
|
-
const result = await open(cachePath(id, file))
|
|
98
|
-
if (!result) throw new Error('Bundle cache unavailable')
|
|
99
|
-
return result
|
|
100
|
-
},
|
|
101
|
-
delete: id => deletePrefix(blobs, token, cachePath(id, ''), remove),
|
|
102
|
-
}
|
|
103
|
-
// Staging uploads are never published. Automatic maintenance and explicit
|
|
104
|
-
// cleanup remove abandoned parts after a full day.
|
|
105
|
-
async function reapUploads(now = Date.now()) {
|
|
106
|
-
let removed = 0
|
|
107
|
-
await deletePrefix(blobs, token, '.managed/uploads/', async path => { await remove(path); removed++ },
|
|
108
|
-
blob => new Date(blob.uploadedAt ?? now).getTime() < now - 86_400_000)
|
|
109
|
-
return removed
|
|
110
|
-
}
|
|
111
|
-
const sourcesPath = (key: string) => `.managed/cache/report-sources/${validateCacheKey(key)}`
|
|
112
|
-
const reportSourcesStorage: CacheStorage = {
|
|
113
|
-
async exists(key) {
|
|
114
|
-
try { await blobs.head(sourcesPath(key), { token }); return true }
|
|
115
|
-
catch (err) { if (isNotFound(err, blobs)) return false; throw err }
|
|
116
|
-
},
|
|
117
|
-
put: (key, bytes) => put(sourcesPath(key), bytes),
|
|
118
|
-
async open(key) {
|
|
119
|
-
const result = await open(sourcesPath(key))
|
|
120
|
-
if (!result) throw new Error('Report sources cache unavailable')
|
|
121
|
-
return result
|
|
122
|
-
},
|
|
123
|
-
delete: prefix => deletePrefix(blobs, token, `${sourcesPath(prefix)}/`, remove),
|
|
124
|
-
}
|
|
125
|
-
const bundleStore = createBundleStore(store('bundles'), store('bundles', '.map.br'))
|
|
126
|
-
return { reportStore: store('reports'), bundleStore, uploadStore: store('uploads'), avatarStore, cacheStorage, reportSourcesStorage, reapUploads }
|
|
127
|
-
}
|
/package/{LICENSE → LICENSE-MIT}
RENAMED
|
File without changes
|