@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.
Files changed (96) hide show
  1. package/LICENSE-APACHE +202 -0
  2. package/client/linked-findings.js +1 -1
  3. package/common/bundle-metadata.js +12 -10
  4. package/common/code-language.js +17 -2
  5. package/common/default-scan-models.ts +3 -3
  6. package/common/finding-id.js +1 -1
  7. package/common/managed/report-content.ts +1 -1
  8. package/common/managed/report-filter.ts +1 -1
  9. package/out/client-managed-import.js +24 -24
  10. package/out/client-managed.js +93 -68
  11. package/out/graph.js +11 -11
  12. package/out/index.html +1 -1
  13. package/out/prism.js +2 -2
  14. package/out/stasis.svg +0 -25
  15. package/out/terminal.js +163 -163
  16. package/out/view.css +1 -1
  17. package/out/view.js +223 -190
  18. package/package.json +29 -29
  19. package/server-common/storage-crypto.ts +182 -0
  20. package/server-common/storage-log.ts +5 -1
  21. package/server-common/vercel-blob.ts +6 -3
  22. package/server-e2e/static.ts +3 -4
  23. package/server-managed/avatar-store.ts +1 -40
  24. package/server-managed/blob-store.ts +3 -52
  25. package/server-managed/bundle-advisories.ts +53 -0
  26. package/server-managed/bundle-advisory-inventory.ts +75 -0
  27. package/server-managed/bundle-build-leases.ts +41 -0
  28. package/server-managed/bundle-build-worker.js +44 -0
  29. package/server-managed/bundle-build.ts +141 -0
  30. package/server-managed/bundle-cache.ts +22 -41
  31. package/server-managed/bundle-store.ts +3 -7
  32. package/server-managed/bundle-summary-cache.ts +27 -9
  33. package/server-managed/bundle.ts +66 -1
  34. package/server-managed/cache-storage.ts +4 -25
  35. package/server-managed/cli.js +10 -2
  36. package/server-managed/config.ts +12 -1
  37. package/server-managed/content-access.ts +1 -1
  38. package/server-managed/db-methods.ts +163 -40
  39. package/server-managed/db-neon.ts +124 -30
  40. package/server-managed/db-schema.ts +2 -0
  41. package/server-managed/db.ts +11 -1
  42. package/server-managed/github-app.ts +10 -15
  43. package/server-managed/github-errors.ts +21 -0
  44. package/server-managed/github-issues.ts +1 -1
  45. package/server-managed/github-metadata.ts +34 -1
  46. package/server-managed/github-pulls.ts +142 -30
  47. package/server-managed/http.ts +278 -167
  48. package/server-managed/index.ts +26 -9
  49. package/server-managed/management-catalog.ts +45 -0
  50. package/server-managed/object-storage-disk.ts +144 -0
  51. package/server-managed/object-storage-vercel.ts +60 -0
  52. package/server-managed/object-storage.ts +71 -0
  53. package/server-managed/public-workspace.ts +20 -14
  54. package/server-managed/report-migration.ts +1 -1
  55. package/server-managed/report-sources.ts +14 -4
  56. package/server-managed/repository-browser.ts +8 -1
  57. package/server-managed/repository-discovery.ts +1 -1
  58. package/server-managed/revisions.ts +35 -0
  59. package/server-managed/solidity-entry-points.ts +69 -0
  60. package/server-managed/sql-postgres.ts +1 -0
  61. package/server-managed/sql.ts +14 -8
  62. package/server-managed/storage-command.ts +16 -0
  63. package/server-managed/storage-db.ts +175 -0
  64. package/server-managed/storage-encryption.ts +211 -0
  65. package/server-managed/storage-maintenance.ts +197 -0
  66. package/server-managed/storage-payload.ts +72 -0
  67. package/server-managed/storage-stores.ts +81 -0
  68. package/server-managed/storage.ts +48 -24
  69. package/server-managed/team-feed.ts +50 -5
  70. package/server-managed/team-reports.ts +85 -22
  71. package/server-managed/uploads.ts +2 -2
  72. package/server-managed/workspace-shares.ts +15 -3
  73. package/report/index.js +0 -260
  74. package/report/src/finding-id.js +0 -80
  75. package/report/src/finding.js +0 -314
  76. package/report/src/labels.js +0 -35
  77. package/report/src/md-structure.js +0 -471
  78. package/report/src/md-text.js +0 -167
  79. package/report/src/meta.js +0 -76
  80. package/report/src/parse-codex.js +0 -149
  81. package/report/src/parse-deepsec.js +0 -199
  82. package/report/src/parse-deepview-fields.js +0 -375
  83. package/report/src/parse-deepview-md.js +0 -186
  84. package/report/src/parse-md-id.js +0 -137
  85. package/report/src/parse-md.js +0 -323
  86. package/report/src/parse-piolium-id.js +0 -79
  87. package/report/src/parse-piolium-rows.js +0 -126
  88. package/report/src/parse-piolium-tokens.js +0 -185
  89. package/report/src/parse-piolium.js +0 -399
  90. package/report/src/security.js +0 -63
  91. package/report/src/severity.js +0 -18
  92. package/report/src/utf8.js +0 -21
  93. package/report/src/write-md-finding.js +0 -273
  94. package/report/src/write-md.js +0 -291
  95. package/server-managed/blob-vercel.ts +0 -127
  96. /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
- }
File without changes