@xagents_in/unmask 0.1.3 → 0.1.4

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 (50) hide show
  1. package/README.md +86 -4
  2. package/dist/cli/annotations.mjs +145 -0
  3. package/dist/cli/audit.mjs +223 -0
  4. package/dist/cli/cache.mjs +488 -0
  5. package/dist/cli/compare.mjs +261 -0
  6. package/dist/cli/config.mjs +141 -0
  7. package/dist/cli/discovery.mjs +372 -0
  8. package/dist/cli/doctor.mjs +354 -0
  9. package/dist/cli/exceptions.mjs +170 -0
  10. package/dist/cli/file.mjs +271 -0
  11. package/dist/cli/files.mjs +141 -0
  12. package/dist/cli/history.mjs +232 -0
  13. package/dist/cli/hosted.mjs +251 -43
  14. package/dist/cli/info.mjs +125 -0
  15. package/dist/cli/init.mjs +57 -0
  16. package/dist/cli/install-guard.mjs +896 -0
  17. package/dist/cli/lockfile.mjs +330 -0
  18. package/dist/cli/main.mjs +97 -14
  19. package/dist/cli/preflight.mjs +388 -0
  20. package/dist/cli/sarif.mjs +100 -0
  21. package/dist/cli/shell-integration.mjs +122 -0
  22. package/dist/cli/terminal.mjs +396 -0
  23. package/dist/cli/watch.mjs +233 -0
  24. package/dist/cli/why.mjs +256 -0
  25. package/dist/core/advisories.mjs +101 -24
  26. package/dist/core/advisory-cache.mjs +295 -0
  27. package/dist/core/behavior-signals.mjs +1088 -0
  28. package/dist/core/dependency-graph.mjs +332 -0
  29. package/dist/core/evidence-exports.mjs +469 -0
  30. package/dist/core/guard-config.mjs +463 -0
  31. package/dist/core/guard-policy.mjs +308 -0
  32. package/dist/core/package-details.mjs +42 -6
  33. package/dist/core/report.mjs +7 -0
  34. package/dist/core/sarif.mjs +556 -0
  35. package/dist/core/syntax.mjs +296 -15
  36. package/dist/model/client.mjs +204 -56
  37. package/dist/model/diff-evidence.mjs +177 -0
  38. package/dist/model/summary.mjs +183 -0
  39. package/dist/server/advisory-result.mjs +137 -0
  40. package/dist/server/app.mjs +60 -2
  41. package/dist/server/dependency-screening.mjs +386 -0
  42. package/dist/server/exports.mjs +63 -0
  43. package/dist/server/guard-decision.mjs +37 -0
  44. package/dist/server/main.mjs +25 -7
  45. package/dist/server/queue.mjs +95 -53
  46. package/dist/server/store.mjs +21 -1
  47. package/dist/version.json +1 -1
  48. package/dist/viewer/render.mjs +10 -2
  49. package/dist/viewer/shell.mjs +1 -1
  50. package/package.json +1 -1
@@ -3,6 +3,7 @@ import {
3
3
  boundedVulnerabilityCheck,
4
4
  unavailableVulnerabilityCheck,
5
5
  } from "./enrichment.mjs";
6
+ import { advisoryOnlyResult } from "./advisory-result.mjs";
6
7
 
7
8
  export const DEFAULT_LIMITS = Object.freeze({
8
9
  maxBodyBytes: 4096,
@@ -57,7 +58,22 @@ export function createQueue({
57
58
  })
58
59
  )
59
60
  return;
60
- const { report, vulnerabilityCheck, ...small } = job;
61
+ if (
62
+ job.advisoryResult &&
63
+ store.put({
64
+ ...job,
65
+ advisoryResult: advisoryOnlyResult(
66
+ unavailableVulnerabilityCheck(
67
+ job.nameAtExactVersion,
68
+ clock,
69
+ "storage-byte-cap",
70
+ ),
71
+ { artifactReason: job.reason },
72
+ ),
73
+ })
74
+ )
75
+ return;
76
+ const { report, vulnerabilityCheck, advisoryResult, ...small } = job;
61
77
  store.put({ ...small, status: "incomplete", reason: "report-too-large" });
62
78
  }
63
79
  }
@@ -71,6 +87,38 @@ export function createQueue({
71
87
  delete job.queueTimer;
72
88
  persist(job);
73
89
  }
90
+ async function enrich(job, controller) {
91
+ let abort;
92
+ const interrupted = new Promise((resolve) => {
93
+ abort = () =>
94
+ resolve(
95
+ unavailableVulnerabilityCheck(
96
+ job.nameAtExactVersion,
97
+ clock,
98
+ "aborted",
99
+ ),
100
+ );
101
+ controller.signal.addEventListener("abort", abort, { once: true });
102
+ if (controller.signal.aborted) abort();
103
+ });
104
+ try {
105
+ const value = await Promise.race([
106
+ Promise.resolve().then(() =>
107
+ enrichJob(job.nameAtExactVersion, { signal: controller.signal }),
108
+ ),
109
+ interrupted,
110
+ ]);
111
+ return boundedVulnerabilityCheck(value, job.nameAtExactVersion, clock);
112
+ } catch {
113
+ return unavailableVulnerabilityCheck(
114
+ job.nameAtExactVersion,
115
+ clock,
116
+ "lookup-failed",
117
+ );
118
+ } finally {
119
+ controller.signal.removeEventListener("abort", abort);
120
+ }
121
+ }
74
122
  function begin(job) {
75
123
  active = job;
76
124
  waiting = undefined;
@@ -79,7 +127,7 @@ export function createQueue({
79
127
  job.status = "running";
80
128
  job.startedAt = clock.now();
81
129
  const controller = new AbortController();
82
- let coreReport;
130
+ let coreReport, advisorySnapshot;
83
131
  const timer = clock.setTimeout(() => {
84
132
  job.finishedAt = clock.now();
85
133
  if (coreReport) {
@@ -87,16 +135,33 @@ export function createQueue({
87
135
  persist({
88
136
  ...publicJob(job),
89
137
  report: coreReport,
90
- vulnerabilityCheck: unavailableVulnerabilityCheck(
91
- job.nameAtExactVersion,
92
- clock,
93
- "aborted",
94
- ),
138
+ vulnerabilityCheck:
139
+ advisorySnapshot ??
140
+ unavailableVulnerabilityCheck(
141
+ job.nameAtExactVersion,
142
+ clock,
143
+ "aborted",
144
+ ),
95
145
  });
96
146
  } else {
97
147
  job.status = "incomplete";
98
148
  job.reason = "execution-timeout";
99
- persist(job);
149
+ persist(
150
+ enrichJob
151
+ ? {
152
+ ...publicJob(job),
153
+ advisoryResult: advisoryOnlyResult(
154
+ advisorySnapshot ??
155
+ unavailableVulnerabilityCheck(
156
+ job.nameAtExactVersion,
157
+ clock,
158
+ "aborted",
159
+ ),
160
+ { artifactReason: job.reason },
161
+ ),
162
+ }
163
+ : job,
164
+ );
100
165
  }
101
166
  controller.abort();
102
167
  }, limits.executionMs);
@@ -105,10 +170,14 @@ export function createQueue({
105
170
  clock.clearTimeout(timer);
106
171
  controller.abort();
107
172
  };
108
- Promise.resolve()
109
- .then(() =>
110
- runAnalysis(job.nameAtExactVersion, { signal: controller.signal }),
111
- )
173
+ const analysis = Promise.resolve().then(() =>
174
+ runAnalysis(job.nameAtExactVersion, { signal: controller.signal }),
175
+ );
176
+ // The advisory lookup runs beside acquisition so a hung or failed artifact still keeps it.
177
+ const advisory = enrichJob
178
+ ? enrich(job, controller).then((check) => (advisorySnapshot = check))
179
+ : Promise.resolve(undefined);
180
+ analysis
112
181
  .then(async (report) => {
113
182
  if (job.status !== "running" || closed) return;
114
183
  if (
@@ -119,45 +188,7 @@ export function createQueue({
119
188
  )
120
189
  throw new TypeError("Invalid report");
121
190
  coreReport = report;
122
- let vulnerabilityCheck;
123
- if (enrichJob) {
124
- let abort;
125
- const interrupted = new Promise((resolve) => {
126
- abort = () =>
127
- resolve(
128
- unavailableVulnerabilityCheck(
129
- job.nameAtExactVersion,
130
- clock,
131
- "aborted",
132
- ),
133
- );
134
- controller.signal.addEventListener("abort", abort, { once: true });
135
- if (controller.signal.aborted) abort();
136
- });
137
- try {
138
- const value = await Promise.race([
139
- Promise.resolve().then(() =>
140
- enrichJob(job.nameAtExactVersion, {
141
- signal: controller.signal,
142
- }),
143
- ),
144
- interrupted,
145
- ]);
146
- vulnerabilityCheck = boundedVulnerabilityCheck(
147
- value,
148
- job.nameAtExactVersion,
149
- clock,
150
- );
151
- } catch {
152
- vulnerabilityCheck = unavailableVulnerabilityCheck(
153
- job.nameAtExactVersion,
154
- clock,
155
- "lookup-failed",
156
- );
157
- } finally {
158
- controller.signal.removeEventListener("abort", abort);
159
- }
160
- }
191
+ const vulnerabilityCheck = await advisory;
161
192
  if (job.status !== "running" || closed) return;
162
193
  const status = report.policy.exitCode === 2 ? "incomplete" : "done";
163
194
  const finishedAt = clock.now();
@@ -171,13 +202,24 @@ export function createQueue({
171
202
  job.status = status;
172
203
  job.finishedAt = finishedAt;
173
204
  })
174
- .catch(() => {
205
+ .catch(async () => {
206
+ if (job.status !== "running" || closed) return;
207
+ const vulnerabilityCheck = coreReport ? undefined : await advisory;
175
208
  if (job.status !== "running" || closed) return;
176
209
  job.status = "failed";
177
210
  job.reason = "analysis-failed";
178
211
  job.finishedAt = clock.now();
179
212
  delete job.report;
180
- persist(publicJob(job));
213
+ persist({
214
+ ...publicJob(job),
215
+ ...(vulnerabilityCheck
216
+ ? {
217
+ advisoryResult: advisoryOnlyResult(vulnerabilityCheck, {
218
+ artifactReason: job.reason,
219
+ }),
220
+ }
221
+ : {}),
222
+ });
181
223
  })
182
224
  .finally(() => {
183
225
  clock.clearTimeout(timer);
@@ -8,6 +8,14 @@ const deterministicCaps = new Set([
8
8
  "path-node-cap",
9
9
  "metadata-cap",
10
10
  ]);
11
+ const deterministicAdvisoryCaps = new Set([
12
+ "result-byte-cap",
13
+ "storage-byte-cap",
14
+ "response-limit",
15
+ "page-limit",
16
+ "advisory-limit",
17
+ "record-limit",
18
+ ]);
11
19
  const transientModelStatuses = new Set([
12
20
  "unavailable",
13
21
  "timeout",
@@ -17,7 +25,19 @@ const transientModelStatuses = new Set([
17
25
  ]);
18
26
 
19
27
  function reusable(record) {
20
- if (!record.report || transientModelStatuses.has(record.report.model?.status))
28
+ // A transiently incomplete advisory snapshot stays readable by id but must not answer a resubmission; repeatable caps may.
29
+ if (
30
+ !record.report ||
31
+ transientModelStatuses.has(record.report.model?.status) ||
32
+ (record.vulnerabilityCheck !== undefined &&
33
+ record.vulnerabilityCheck?.complete !== true &&
34
+ !(
35
+ record.vulnerabilityCheck?.reasons?.length > 0 &&
36
+ record.vulnerabilityCheck.reasons.every((reason) =>
37
+ deterministicAdvisoryCaps.has(reason),
38
+ )
39
+ ))
40
+ )
21
41
  return false;
22
42
  if (record.status === "done") return record.report.policy?.exitCode !== 2;
23
43
  return (
package/dist/version.json CHANGED
@@ -1 +1 @@
1
- {"buildSchema":"1","version":"0.1.3","dirty":false,"commit":"541bc4d2e4710b411202882ec2480801994b6cf9","sourceSha256":"429745022e980eb8d09b1c6a6614b8b25f49921bd1883b0b111dfd5c3137ada3","packageSha256":"28210403766aff6ca070f8ca93df42117e93eedb5005b2a1b1fec4ee2f68c0c0","lockfileSha256":"2f632db652163f9f8f55ed649962fc5e4f718daf2edf6b0f0eea5d9501013dac","files":{"cli/batch.mjs":{"sha256":"101f7ecb4c3d5890c42f402e5ca00ab97351c4a4d90e07a1fa4367e3c0807650","size":7296},"cli/hosted.mjs":{"sha256":"dea7b512a2e811102521565e9f218c77aab916fe05e838f55a9aeb7b43cd0852","size":7436},"cli/main.mjs":{"sha256":"c4429dd331b377a1b1ca9b25a04721d51f38c39ee395de2239d0ad2bf7ccb57c","size":6825},"cli/scan.mjs":{"sha256":"9bf33e926ededf1beb1e4af73c861ba5bf33bee74ca0544151112284e0afc1b5","size":3906},"core/acquire.mjs":{"sha256":"aee5ed002292edf1b03385ceec8ebfb03de452dba36bbdced96f888eaafa1d67","size":9549},"core/advisories.mjs":{"sha256":"388088e44422ffeb3b60d930c84cec29fbc89b98d8dfd2879bc6ede50f4e7ea9","size":13004},"core/archive.mjs":{"sha256":"80aa4373c0324458fe322a83af18a4cfd0ffec4b39ebdeffc9084639a8655410","size":16193},"core/compare.mjs":{"sha256":"540614266e06a2875010793d036d256ddfac72f978157cd3d147ffb99015d8e4","size":7579},"core/manifests.mjs":{"sha256":"29c40e01ff1e1dfaed444600d8c78380d23d4bc9be71960251e39ea3594de2f1","size":17891},"core/online.mjs":{"sha256":"368a3f2558e16db0701d2eaf068b48e2661e7e01ab7cf5605cdd22766aeb5cca","size":9741},"core/package-details.mjs":{"sha256":"770551a6ab84e523dbc56ede6131b08eb22b8c21fc9c8b179fe0d1769fb2ec00","size":21538},"core/pipeline.mjs":{"sha256":"9c4ddc5c258a99455a1230c978fd132c135057ad7bb6c7baa201ae530ee136fd","size":11060},"core/policy.mjs":{"sha256":"4281c626c00a6424992f5e1eba26876e2b70f4b968450a8ca52fa42f5a121ba5","size":2954},"core/registry-facts.mjs":{"sha256":"726344597044b0c23fb74aff4fbfe7c60cbbfc4c0bee838abf9257134f9c96db","size":11013},"core/report-exploration.mjs":{"sha256":"1dcc9897d3bbc98ee3107ef8f8279d9eed6ee6d104455eb214a5e5644bd197fb","size":10137},"core/report.mjs":{"sha256":"aa167c94c257a5ff6d830630a37a51a9a9e47f82aa4a0a7b96ead91a5967294b","size":15844},"core/resolve.mjs":{"sha256":"d5575da49ff78e8fea8df1f2fc10a39540adea285eddfa347746e848f9fdf957","size":5202},"core/source.mjs":{"sha256":"798fe74e3fba836b82576cd46e1b91e6f6e0a4e3cf273c533b5e074247c81373","size":3238},"core/syntax.mjs":{"sha256":"2d50f2e73e17aedbcbccd92af280e171de4ef78b55acccd23d6b6ef11e891776","size":10450},"model/client.mjs":{"sha256":"efb68132710cbdff6b86b58cbac006c48e10f9317e852f00b120ef7c3c7ed9c1","size":42865},"model/config.mjs":{"sha256":"127605979a299616be15f4a47e94dcd82928b00ad2af71744ffaa6e359516486","size":3245},"server/app.mjs":{"sha256":"2aa5678bcdd38702707fa05ec7aa749d46f1590993e491ec0adc408a35d2f890","size":10498},"server/enrichment.mjs":{"sha256":"3c5cc57f2c8f019f79418457f366a9422e0a03a8ba86a41b0767aba636bde179","size":3825},"server/main.mjs":{"sha256":"e5bdcd02209c2ccc1ed8c73b85b9988d61aa3e1bcf7c8d119eed782a4bfcd224","size":4587},"server/queue.mjs":{"sha256":"23e30f3ff570771b77a244be9200ad510d2f19811eee566d68b364b7f741a9d7","size":7371},"server/registry-facts.mjs":{"sha256":"58bce5b2a40f25e7561f122ea012594c9eb6789f993ca83dadc07f198afca9e3","size":3315},"server/report-exploration.mjs":{"sha256":"862b8d0ea07b627368aaca3a0f66359cfc638b14c54ab4158f8ef313602c3810","size":2774},"server/runner.mjs":{"sha256":"a6ca5bfbd7b239f7110639d854ca9a263f4cf3aaf06701ea54493b29f8244706","size":9071},"server/store.mjs":{"sha256":"efa2a35c7e9d0344c26e24ba360a457cdf80f4f48975f0186f81844b9fb7a097","size":2706},"server/worker.mjs":{"sha256":"1df839608cd1c691fc2801d89e698daeef3e48d7f4b8843ce1252a21fde9730a","size":1902},"viewer/render.mjs":{"sha256":"c77442c27041a5fe28269b8c80c9d24c72b73a226e8d4491e6d7285a9feb5309","size":19443},"viewer/shell.mjs":{"sha256":"5f800d0a97fe416d02cf9abef766d651b444b4745ad3a998926599469358ca79","size":9408}}}
1
+ {"buildSchema":"1","version":"0.1.4","dirty":false,"commit":"99771a0fe5b9df4d0d98f5e7d7f56cad11e2a005","sourceSha256":"48f4fc48bcce841253639ff72bb90557d9284155d4aa8ed5d0d25c03a5904ea4","packageSha256":"d3b26f02f381b527f441b4bd526d93992b618a05f3e59767449613d871a396c9","lockfileSha256":"d7c23757a0a9662a41414f1a7b026f838b883d313765f05b9a1a151ce62f9000","files":{"cli/annotations.mjs":{"sha256":"9dd89e6bfcb44aa4f24e71dc2c85418093ad19e8824a467c21fe2208aceae260","size":5179},"cli/audit.mjs":{"sha256":"bf3d7d0bb77a5b5baaee36d7c8363f3d29c00eda3bb105da29d5be0dd3c28cfd","size":8047},"cli/batch.mjs":{"sha256":"101f7ecb4c3d5890c42f402e5ca00ab97351c4a4d90e07a1fa4367e3c0807650","size":7296},"cli/cache.mjs":{"sha256":"ce7f608249ac61082f408239187a9e87176d82c3a4f288a933eb6a0f7a29fd3c","size":15783},"cli/compare.mjs":{"sha256":"30870240034847064c7d7fdf6e1de833cc73c7b70ebdc56d2e7fa90c62eefb18","size":9569},"cli/config.mjs":{"sha256":"845767f86dbe1e909fbb02684bdec8588dc7e85e30e1131938ee64865c6e0206","size":4436},"cli/discovery.mjs":{"sha256":"182f3c659cb042025d1bf5ca3c05e39895416706c72e3b1537e7052a2fda71a9","size":11982},"cli/doctor.mjs":{"sha256":"a6f6441cefea069f8f453afea7af48a45ce29c28545e233db30839fefeb15237","size":11007},"cli/exceptions.mjs":{"sha256":"246d70c8675182688f971fb29ede6b5511feb8b6462fe136efee8706382786da","size":6133},"cli/file.mjs":{"sha256":"6cdc85178af71ea11b1a82fb20ca4dd5525f1e1959e6ad97fdf3cea1a9074aad","size":9002},"cli/files.mjs":{"sha256":"16ae0daec2157dda4ee7989db0d0fb98f97fee8873e3ca588e456c42f16390eb","size":5046},"cli/history.mjs":{"sha256":"be2dabf364486b1e484c22354ceb10e30cbb983772d8b555ccc498ab305ec5d2","size":8260},"cli/hosted.mjs":{"sha256":"eb30b1ca566c8164a3b1ae3e21eaf45e41445fa209cd8eef273f844065bec510","size":15100},"cli/info.mjs":{"sha256":"15d359aa45b4a8dd3bddc923c42ef1ed25b9a052a317d9da04628944ab3be929","size":4392},"cli/init.mjs":{"sha256":"09d6eb86046b2832687f6eafd85cf2f1472a4ceb399eece9435a166ea525b6bb","size":1955},"cli/install-guard.mjs":{"sha256":"b5e532e3709d9c9d6c990e116bde9d62464f24c44b43ba5da4a5236076a01003","size":29538},"cli/lockfile.mjs":{"sha256":"9165572bd853dcdb30c7dc1efcde61874784218300b0b9f501a6175795fc4324","size":11452},"cli/main.mjs":{"sha256":"e99f78c25bb5a2abb0f989f076fc3f3fa064e87f5ce6b8ec593179a521015192","size":10436},"cli/preflight.mjs":{"sha256":"801bf1aa12b2b32cccda64f01fc8bbc63e977083130c6657849bd1907c0ee137","size":13308},"cli/sarif.mjs":{"sha256":"7fc60dcef01be06ad79393a8c52dca0af9f24bc2969a410bedf731ab9fbbb4e1","size":3147},"cli/scan.mjs":{"sha256":"9bf33e926ededf1beb1e4af73c861ba5bf33bee74ca0544151112284e0afc1b5","size":3906},"cli/shell-integration.mjs":{"sha256":"76a1714cbd128d559c2c15e051220a4e37c4860fe3b0687e615498c8004a0ed8","size":4287},"cli/terminal.mjs":{"sha256":"730ceb8c2e8d2948afb67b0a79fc804849a5eb52d9ddc6ef7a6db65404119471","size":14324},"cli/watch.mjs":{"sha256":"206fdcd262dc6962fd19adfb2bf8cc1a951ec98219cd7901f60f3ee8fd8aa7fa","size":7184},"cli/why.mjs":{"sha256":"9c287b22ddd0e0ae44d84297d3b5c759c25db116370f8a5878e0f5a2eb621ad8","size":8306},"core/acquire.mjs":{"sha256":"aee5ed002292edf1b03385ceec8ebfb03de452dba36bbdced96f888eaafa1d67","size":9549},"core/advisories.mjs":{"sha256":"d0dbf9d9ed4a79655da9613c7f8cbca80e3f2de54c47b128d1dba3b67a2ac750","size":15537},"core/advisory-cache.mjs":{"sha256":"88808779b455e8d28708ec8afc11bb441a85df2783e224726920f20387eede64","size":8720},"core/archive.mjs":{"sha256":"80aa4373c0324458fe322a83af18a4cfd0ffec4b39ebdeffc9084639a8655410","size":16193},"core/behavior-signals.mjs":{"sha256":"9a119e620c9b5868b33a91da72f22b8462fb74313871ce7d99c43a55cae656dd","size":33504},"core/compare.mjs":{"sha256":"540614266e06a2875010793d036d256ddfac72f978157cd3d147ffb99015d8e4","size":7579},"core/dependency-graph.mjs":{"sha256":"25ab2d6180750ff63717e6e3d1ff5284c1c8a5a2aee4ab373ebd6812e3559225","size":10591},"core/evidence-exports.mjs":{"sha256":"0d8c77b7afdee20ba381c77c94745d76edb7b4e8c1c5e6cd12843558ad9334d7","size":15923},"core/guard-config.mjs":{"sha256":"bb1f1f0df2fe374aacb6b90e3c051a89f7e32c61e8f742307dc7a31b6b3ca7ec","size":14884},"core/guard-policy.mjs":{"sha256":"0c5b356da66f30c2b8f2cb53d3141035f50c4631b4ef032464e455aa7c4e821c","size":10435},"core/manifests.mjs":{"sha256":"29c40e01ff1e1dfaed444600d8c78380d23d4bc9be71960251e39ea3594de2f1","size":17891},"core/online.mjs":{"sha256":"368a3f2558e16db0701d2eaf068b48e2661e7e01ab7cf5605cdd22766aeb5cca","size":9741},"core/package-details.mjs":{"sha256":"eac0b19390caaf0c7cc56b1379fd7d64ecd1b3efd6f2d7414065f4c3a80985aa","size":22611},"core/pipeline.mjs":{"sha256":"9c4ddc5c258a99455a1230c978fd132c135057ad7bb6c7baa201ae530ee136fd","size":11060},"core/policy.mjs":{"sha256":"4281c626c00a6424992f5e1eba26876e2b70f4b968450a8ca52fa42f5a121ba5","size":2954},"core/registry-facts.mjs":{"sha256":"726344597044b0c23fb74aff4fbfe7c60cbbfc4c0bee838abf9257134f9c96db","size":11013},"core/report-exploration.mjs":{"sha256":"1dcc9897d3bbc98ee3107ef8f8279d9eed6ee6d104455eb214a5e5644bd197fb","size":10137},"core/report.mjs":{"sha256":"45a83f45307cabf7067496784ad63f2f913075cf27193b4022ac501794d8fe39","size":16119},"core/resolve.mjs":{"sha256":"d5575da49ff78e8fea8df1f2fc10a39540adea285eddfa347746e848f9fdf957","size":5202},"core/sarif.mjs":{"sha256":"dd3d4ebcc3b3700052983573956372db0876422e0813e1ea9c270aca916ad775","size":18424},"core/source.mjs":{"sha256":"798fe74e3fba836b82576cd46e1b91e6f6e0a4e3cf273c533b5e074247c81373","size":3238},"core/syntax.mjs":{"sha256":"e09d4b62101a006876761410e042369fe4d82633da4cb229172afbfa94ab3c64","size":19841},"model/client.mjs":{"sha256":"af3acdfb0dfaf16f1455e025e779e8380cb416a577dc1b04d6d06fdee5df9494","size":47819},"model/config.mjs":{"sha256":"127605979a299616be15f4a47e94dcd82928b00ad2af71744ffaa6e359516486","size":3245},"model/diff-evidence.mjs":{"sha256":"64c19e53e2e2cb72c4ee0807ed3ed2fb929e75d5359dc16fbfd60454872403c9","size":5763},"model/summary.mjs":{"sha256":"0f950a699e5db898482fe6e220955c8dcda68786976d9a68eba2a7209aa22d62","size":7267},"server/advisory-result.mjs":{"sha256":"e91ef844a3fb319631905cd343f77f0a1c087f63cd38e262dd7257c4a410841a","size":4774},"server/app.mjs":{"sha256":"9915d70330106bd4a713bf002ea9b57e368df0ae35dccca76b15dd8765595bc2","size":12900},"server/dependency-screening.mjs":{"sha256":"18c77b1933f79bb287620342ac7c4995351da6ddb3b457bc8fd5fc374e2647a6","size":12430},"server/enrichment.mjs":{"sha256":"3c5cc57f2c8f019f79418457f366a9422e0a03a8ba86a41b0767aba636bde179","size":3825},"server/exports.mjs":{"sha256":"5b4e9b4206d57ac2970dbf3a29d35cad8e0acfd2995fb23fd9561bf347f5a926","size":1847},"server/guard-decision.mjs":{"sha256":"1c886f7bde97bbccad18f1f2c619579c16ca139c112520d2a29dec08bd64a7e5","size":1097},"server/main.mjs":{"sha256":"1823983aff551478c44e505931c9983a85efd6a74876ef17dd2b1d2bd9267354","size":5342},"server/queue.mjs":{"sha256":"09ae8ff8eda7071ae3ba3004d8cefebd2cd84ceef3320fc9b7cf8a75d8e2b5d4","size":8715},"server/registry-facts.mjs":{"sha256":"58bce5b2a40f25e7561f122ea012594c9eb6789f993ca83dadc07f198afca9e3","size":3315},"server/report-exploration.mjs":{"sha256":"862b8d0ea07b627368aaca3a0f66359cfc638b14c54ab4158f8ef313602c3810","size":2774},"server/runner.mjs":{"sha256":"a6ca5bfbd7b239f7110639d854ca9a263f4cf3aaf06701ea54493b29f8244706","size":9071},"server/store.mjs":{"sha256":"51e5ca409acd67945be232f7fe156c17eea79f4f24860c48a9c9b3e08d97dbfc","size":3309},"server/worker.mjs":{"sha256":"1df839608cd1c691fc2801d89e698daeef3e48d7f4b8843ce1252a21fde9730a","size":1902},"viewer/render.mjs":{"sha256":"cf6e3daa572d4b001257c25e6e68dfd5420e8e6f39edfe2fb73ca7219671e7f3","size":20366},"viewer/shell.mjs":{"sha256":"037ebbeec3e73e962252acb2cea6eef0056cd3c6be7a56a78c082086eabe1d9f","size":9629}}}
@@ -237,7 +237,15 @@ export function renderReport(report) {
237
237
  const modelText =
238
238
  model.status === "disabled"
239
239
  ? "Model is disabled"
240
- : `Model status: ${model.status}`;
240
+ : `Model status: ${model.status}${model.reason ? ` (${model.reason})` : ""}`;
241
+ const assessed =
242
+ model.status === "complete" &&
243
+ typeof model.summary === "string" &&
244
+ model.assessment?.source === "model";
245
+ const scope = assessed ? model.assessment.checkedScope || {} : {};
246
+ const assessment = assessed
247
+ ? `<h3>AI summary</h3><p>${text(model.summary, 600)}</p><dl><dt>Uncertainty</dt><dd>${text(model.assessment.uncertainty, 300)}</dd><dt>Next action</dt><dd>${text(model.assessment.nextAction, 200)}</dd><dt>Checked scope</dt><dd>${text(scope.evidenceSupplied ?? 0)} evidence items supplied, ${text(scope.evidenceOmitted ?? 0)} omitted. Not checked: ${text((scope.notChecked || []).join(", ") || "unspecified")}.</dd></dl><p class="note">The AI summary is advisory and is not a safety signal.</p>`
248
+ : '<p class="note">No AI summary is available for this check. This notice is not model output and is not a safety signal.</p>';
241
249
  const csp = `default-src 'none'; script-src 'sha256-${assetHash(script)}'; style-src 'sha256-${assetHash(css)}'; connect-src 'none'; base-uri 'none'; form-action 'none'`;
242
250
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="${escape(csp)}"><meta name="referrer" content="no-referrer"><meta name="robots" content="noindex"><title>UNMASK · ${text(identity)}</title><style>${css}</style></head><body>
243
251
  <a class="skip" href="#content">Skip to evidence</a><header><strong>UNMASK</strong><p>Published bytes. Source claims. Evidence to review.</p></header>
@@ -250,6 +258,6 @@ export function renderReport(report) {
250
258
  <section><h2>Inert links</h2><p class="note">Artifact links: ${text(report.coverage?.links?.artifact ?? "unknown")}. Source links: ${text(report.coverage?.links?.source ?? "unknown")}.</p>${links.html || '<p class="empty">No inert link entries recorded.</p>'}</section>
251
259
  <section><h2>Source-only paths</h2>${sourceOnly.html ? `<ul>${sourceOnly.body}</ul>${sourceOnly.notice}` : '<p class="empty">No source-only paths recorded. Source availability and completeness still apply.</p>'}</section>
252
260
  <section><h2>Bound evidence</h2><p class="note">Excerpts show original text data. Excerpt display limit: 512 bytes per evidence item. Byte ranges are half-open: start included, end excluded. Open a citation to inspect its digest-bound evidence.</p>${catalog.html || '<p class="empty">No bound evidence recorded.</p>'}</section>
253
- <section class="model"><h2>Model explanations</h2><p>${text(modelText)}</p><p class="note">Hypotheses are separate from deterministic evidence. A valid citation proves its location, not the reasoning.</p>${hypotheses.html}</section>
261
+ <section class="model"><h2>Model explanations</h2><p>${text(modelText)}</p>${assessment}<p class="note">Hypotheses are separate from deterministic evidence. A valid citation proves its location, not the reasoning.</p>${hypotheses.html}</section>
254
262
  </div></main><footer>UNMASK presents evidence for review. It never declares a package safe. HTML display limits do not change the full JSON report.</footer><script>${script}</script></body></html>`;
255
263
  }
@@ -58,7 +58,7 @@ export function renderError({
58
58
  }
59
59
  export function renderCompleted(reportHtml, job) {
60
60
  const time = new Date(job.finishedAt).toISOString();
61
- const navigation = `<nav class="summary" aria-label="Report actions"><a href="/">Check another release</a> | <a href="/r/${escape(job.id)}.json" download="unmask-report.json">Download report JSON</a><p>Cached analysis: <time datetime="${time}">${time}</time>. Eligible results may be reused for up to 30 minutes after completion. Capacity eviction or restart can remove them sooner. Viewing a result does not extend this period. Unavailable model explanations and other retryable failures need a new attempt.</p></nav>`;
61
+ const navigation = `<nav class="summary" aria-label="Report actions"><a href="/">Check another release</a> | <a href="/r/${escape(job.id)}.json" download="unmask-report.json">Download report JSON</a> | <a href="/r/${escape(job.id)}.cdx.json" download="unmask-sbom.cdx.json">Download CycloneDX SBOM</a> | <a href="/r/${escape(job.id)}.evidence.json" download="unmask-evidence-manifest.json">Download evidence manifest</a><p>Cached analysis: <time datetime="${time}">${time}</time>. Eligible results may be reused for up to 30 minutes after completion. Capacity eviction or restart can remove them sooner. Viewing a result does not extend this period. Unavailable model explanations and other retryable failures need a new attempt.</p></nav>`;
62
62
  if (/<\/header\s*>/i.test(reportHtml))
63
63
  return reportHtml.replace(
64
64
  /<\/header\s*>/i,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xagents_in/unmask",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "description": "Evidence-based comparison of npm packages and their source archives",
6
6
  "license": "MIT",