@lockhawk/core 0.2.10 → 0.2.12-alpha.0

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  The scanning engine behind [**lockhawk**](https://github.com/lockhawk/lockhawk): lockfile parsing,
4
4
  dependency graph building, [OSV.dev](https://osv.dev) matching, CVSS v3 and v4 scoring, and report
5
- generation (table, JSON, SARIF, JUnit, HTML).
5
+ generation (table, JSON, SARIF, JUnit, HTML, Markdown).
6
6
 
7
7
  > **Most people want the CLI, not this package.** To scan a project, use
8
8
  > [`lockhawk`](https://www.npmjs.com/package/lockhawk) and run `npx lockhawk scan`. Install
package/dist/index.d.ts CHANGED
@@ -560,4 +560,7 @@ declare function toHtml(result: ScanResult, shell?: string): string;
560
560
  /** Render a scan result as JUnit XML (one failed test per finding). */
561
561
  declare function toJunit(result: ScanResult): string;
562
562
 
563
- export { AutoSource, type CvssResult, DATA_MARKER, type DatabaseInfo, type DepNode, type DepScope, type DependencyGraph, type DetectedLockfile, type Finding, type FindingsOptions, LockfileError, OfflineDbMissingError, type OfflineMeta, OfflineSource, type OnlineClientOptions, OnlineSource, type OsvAffected, OsvClient, OsvDatabase, type OsvEvent, type OsvRange, type OsvReference, type OsvSeverity, type OsvVulnerability, type PackageManager, type PackageRef, type PkgKey, type RawGraph, type RawNode, type ResolvedSource, type RootManifest, SEVERITY_RANK, SHARD_BUCKETS, type SarifLog, type ScanOptions, type ScanResult, type ScanStats, type ScanSummary, type Severity, type SeverityInfo, type SourceMode, type SourceOptions, TOOL, type UnscannablePackage, type UpdateResult, type VulnMatch, type VulnSource, buildDependencyGraph, buildFindings, canonicalId, createSource, dedupeVulnerabilities, detectLockfile, isVersionAffected, levelFromLabel, levelFromScore, loadAdvisoriesForPackages, loadDependencyGraph, nearestFix, offlineDbDir, offlineMetaPath, parseLockfile, pkgKey, readOfflineMeta, readRootManifest, resolveCacheDir, resolveSeverity, rootLabel, scan, scoreFromVector, severityAtLeast, shardBucket, shortestPath, shouldFail, toHtml, toJson, toJunit, toSarif, toSarifString, uniqueScannablePackages, updateOfflineDatabase, vulnerabilityAffects };
563
+ /** Render a scan result as GitHub-Flavored Markdown for inline CI summaries. */
564
+ declare function toMarkdown(result: ScanResult): string;
565
+
566
+ export { AutoSource, type CvssResult, DATA_MARKER, type DatabaseInfo, type DepNode, type DepScope, type DependencyGraph, type DetectedLockfile, type Finding, type FindingsOptions, LockfileError, OfflineDbMissingError, type OfflineMeta, OfflineSource, type OnlineClientOptions, OnlineSource, type OsvAffected, OsvClient, OsvDatabase, type OsvEvent, type OsvRange, type OsvReference, type OsvSeverity, type OsvVulnerability, type PackageManager, type PackageRef, type PkgKey, type RawGraph, type RawNode, type ResolvedSource, type RootManifest, SEVERITY_RANK, SHARD_BUCKETS, type SarifLog, type ScanOptions, type ScanResult, type ScanStats, type ScanSummary, type Severity, type SeverityInfo, type SourceMode, type SourceOptions, TOOL, type UnscannablePackage, type UpdateResult, type VulnMatch, type VulnSource, buildDependencyGraph, buildFindings, canonicalId, createSource, dedupeVulnerabilities, detectLockfile, isVersionAffected, levelFromLabel, levelFromScore, loadAdvisoriesForPackages, loadDependencyGraph, nearestFix, offlineDbDir, offlineMetaPath, parseLockfile, pkgKey, readOfflineMeta, readRootManifest, resolveCacheDir, resolveSeverity, rootLabel, scan, scoreFromVector, severityAtLeast, shardBucket, shortestPath, shouldFail, toHtml, toJson, toJunit, toMarkdown, toSarif, toSarifString, uniqueScannablePackages, updateOfflineDatabase, vulnerabilityAffects };
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
- var N={none:0,unknown:1,low:2,medium:3,high:4,critical:5};function qe(e,n){return N[e]>=N[n]}function w(e,n){return`${e}@${n}`}import{statSync as gt}from"fs";import{resolve as mt}from"path";import{existsSync as Fe,readFileSync as Gn,statSync as Bn}from"fs";import{join as Te}from"path";var zn=[{filename:"pnpm-lock.yaml",manager:"pnpm"},{filename:"yarn.lock",manager:"yarn"},{filename:"package-lock.json",manager:"npm"},{filename:"npm-shrinkwrap.json",manager:"npm"}];function F(e){for(let{filename:n,manager:t}of zn){let s=Te(e,n);if(Fe(s)&&Bn(s).isFile())return{manager:t,path:s,filename:n}}}function M(e){let n=Te(e,"package.json"),t={};if(Fe(n))try{t=JSON.parse(Gn(n,"utf8"))}catch{t={}}let s=r=>r&&typeof r=="object"?r:{};return{name:typeof t.name=="string"?t.name:"project",version:typeof t.version=="string"?t.version:void 0,dependencies:s(t.dependencies),devDependencies:s(t.devDependencies),optionalDependencies:s(t.optionalDependencies),peerDependencies:s(t.peerDependencies)}}function fe(e,n){let t=new Set,s=[];for(let r of e)t.has(r)||(t.add(r),s.push(r));for(let r=0;r<s.length;r++){let a=n[s[r]];if(a)for(let i of a.dependencies)t.has(i)||(t.add(i),s.push(i))}return t}function ue(e){let n=fe(e.directProd,e.nodes),t=fe(e.directOptional,e.nodes),s=fe(e.directDev,e.nodes),r=new Set([...e.directProd,...e.directOptional,...e.directDev]),a={};for(let[i,o]of Object.entries(e.nodes)){let d;n.has(i)?d="prod":t.has(i)?d="optional":s.has(i)?d="dev":d="prod",a[i]={key:i,name:o.name,version:o.version,scope:d,direct:r.has(i),dependencies:Yn(o.dependencies),...o.unscannable?{unscannable:o.unscannable}:{}}}return{manager:e.manager,lockfilePath:e.lockfilePath,lockfileVersion:e.lockfileVersion,root:e.root,nodes:a,directKeys:[...r].filter(i=>a[i]!==void 0)}}function Yn(e){return e.length>1?[...new Set(e)]:e}import{readFileSync as Wn}from"fs";import{dirname as Jn}from"path";function Ue(e){let n=JSON.parse(Wn(e,"utf8"));return n.packages?Zn(n,e):Qn(n,e)}function Xn(e){let n="node_modules/",t=e.lastIndexOf(n);return t===-1?e:e.slice(t+n.length)}function Zn(e,n){let t=e.packages??{},s=t[""]??{},r={name:s.name??e.name??"project",version:s.version??e.version},a=Object.create(null),i=[],o=Object.create(null);for(let[l,u]of Object.entries(t)){if(l===""||u.link)continue;let g=u.name??Xn(l),y=u.version;if(!y)continue;let p=w(g,y);if(o[l]=p,!a[p]){let k={key:p,name:g,version:y,dependencies:[]};l.includes("node_modules")||(k.unscannable={reason:"local workspace package"},i.push({name:g,version:y,reason:"local workspace package"})),a[p]=k}}let d=(l,u)=>{let g=l;for(;;){let y=`${g?`${g}/`:""}node_modules/${u}`,p=t[y];if(p)return p.link&&typeof p.resolved=="string"?p.resolved:y;if(!g)return;let k=g.lastIndexOf("/node_modules/");g=k===-1?"":g.slice(0,k)}},c=new Set,f=new Set,m=new Set;for(let[l,u]of Object.entries(t)){if(u.link)continue;let g=l===""?void 0:o[l],y=l===""||!l.includes("node_modules"),p=(k,R)=>{for(let S of k){let O=d(l,S);if(!O)continue;let P=o[O];P&&(g&&g!==P&&a[g].dependencies.push(P),R&&R.add(P))}};p(Object.keys(u.dependencies??{}),y?c:void 0),p(Object.keys(u.optionalDependencies??{}),y?m:void 0),y&&p(Object.keys(u.devDependencies??{}),f)}return{manager:"npm",lockfilePath:n,lockfileVersion:e.lockfileVersion,root:r,nodes:a,directProd:[...c],directDev:[...f],directOptional:[...m],unscannable:i}}var Ke=500;function Qn(e,n){let t=M(Jn(n)),s={name:e.name??t.name,version:e.version??t.version},r=Object.create(null),a=u=>{let g=new Map;for(let[y,p]of Object.entries(u??{}))p?.version&&g.set(y,p.version);return g},i=(u,g)=>{for(let y=g.length-1;y>=0;y--){let p=g[y].get(u);if(p)return p}},o=(u,g)=>{if(g.length>Ke)throw new Error(`dependency nesting exceeds ${Ke} levels (malformed or malicious lockfile)`);let y=a(u),p=[...g,y];for(let[k,R]of Object.entries(u??{})){let S=R?.version;if(!S)continue;let O=w(k,S);r[O]||(r[O]={key:O,name:k,version:S,dependencies:[]});let P=[...p,a(R.dependencies)];for(let C of Object.keys(R.requires??{})){let D=i(C,P);if(D){let $=w(C,D);$!==O&&r[O].dependencies.push($)}}R.dependencies&&o(R.dependencies,p)}};o(e.dependencies,[]);let d=a(e.dependencies),c=[],f=[],m=[],l=(u,g)=>{for(let y of u){let p=d.get(y);p&&g.push(w(y,p))}};return l(Object.keys(t.dependencies),c),l(Object.keys(t.optionalDependencies),m),l(Object.keys(t.devDependencies),f),{manager:"npm",lockfilePath:n,lockfileVersion:e.lockfileVersion,root:s,nodes:r,directProd:c,directDev:f,directOptional:m,unscannable:[]}}import{readFileSync as et}from"fs";import{dirname as nt}from"path";import{createRequire as tt}from"module";import rt from"js-yaml";var st=tt(import.meta.url),ot=st("@yarnpkg/lockfile");function Ge(e){let n=et(e,"utf8"),t=M(nt(e)),s=n.includes("__metadata"),{descriptorToVersion:r,entryByVersion:a,lockfileVersion:i}=s?at(n):it(n);return ct(e,t,r,a,i,s)}function Be(e){let n=e.lastIndexOf("@");if(!(n<=0))return{name:e.slice(0,n),range:e.slice(n+1)}}function it(e){let n=ot.parse(e),t=new Map,s=new Map;for(let[r,a]of Object.entries(n.object))if(a.version)for(let i of r.split(/,\s*/)){let o=Be(i);o&&t.set(`${o.name}@${o.range}`,a.version),o&&s.set(w(o.name,a.version),a)}return{descriptorToVersion:t,entryByVersion:s,lockfileVersion:1}}function at(e){let n=rt.load(e)??{},t=new Map,s=new Map,r="berry";for(let[a,i]of Object.entries(n)){if(a==="__metadata"){let o=i.version;o!==void 0&&(r=o);continue}if(i.version)for(let o of a.split(/,\s*/)){let d=Be(o);d&&(t.set(`${d.name}@${d.range}`,i.version),s.set(w(d.name,i.version),i))}}return{descriptorToVersion:t,entryByVersion:s,lockfileVersion:r}}function ct(e,n,t,s,r,a){let i=(c,f)=>{let m=a?[`${c}@${f}`,`${c}@npm:${f}`]:[`${c}@${f}`];for(let l of m){let u=t.get(l);if(u)return u}},o=Object.create(null);for(let[c,f]of s){let m=c.lastIndexOf("@"),l=c.slice(0,m),u=c.slice(m+1);o[c]||(o[c]={key:c,name:l,version:u,dependencies:[]});let g=y=>{for(let[p,k]of Object.entries(y??{})){let R=i(p,k);if(!R)continue;let S=w(p,R);S!==c&&o[c].dependencies.push(S)}};g(f.dependencies),g(f.optionalDependencies)}let d=c=>{let f=[];for(let[m,l]of Object.entries(c)){let u=i(m,l);u&&f.push(w(m,u))}return f};return{manager:"yarn",lockfilePath:e,lockfileVersion:r,root:{name:n.name,version:n.version},nodes:o,directProd:d(n.dependencies),directDev:d(n.devDependencies),directOptional:d(n.optionalDependencies),unscannable:[]}}import{readFileSync as dt}from"fs";import{dirname as ft}from"path";import ut from"js-yaml";function Ye(e){let n=ut.load(dt(e,"utf8"))??{},t=M(ft(e)),s=lt(n.lockfileVersion),r=Object.create(null);for(let m of Object.keys(n.packages??{})){let l=ze(m,s);if(!l)continue;let u=w(l.name,l.version);r[u]||(r[u]={key:u,name:l.name,version:l.version,dependencies:[]})}let a=s>=9?n.snapshots??{}:n.packages??{};for(let[m,l]of Object.entries(a)){let u=ze(m,s);if(!u)continue;let g=w(u.name,u.version);r[g]||(r[g]={key:g,name:u.name,version:u.version,dependencies:[]});let y=p=>{for(let[k,R]of Object.entries(p??{})){let S=w(k,Y(R,s));S!==g&&r[S]&&r[g].dependencies.push(S)}};y(l.dependencies),y(l.optionalDependencies)}let i=n.importers??{".":{dependencies:n.dependencies,devDependencies:n.devDependencies,optionalDependencies:n.optionalDependencies}},o=new Set,d=new Set,c=new Set,f=(m,l)=>{for(let[u,g]of Object.entries(m??{})){let y=pt(g,s);if(!y)continue;let p=w(u,y);r[p]&&l.add(p)}};for(let m of Object.values(i))f(m.dependencies,o),f(m.optionalDependencies,c),f(m.devDependencies,d);return{manager:"pnpm",lockfilePath:e,lockfileVersion:n.lockfileVersion,root:{name:t.name,version:t.version},nodes:r,directProd:[...o],directDev:[...d],directOptional:[...c],unscannable:[]}}function lt(e){let n=parseFloat(String(e??"9"));return Number.isNaN(n)?9:Math.floor(n)}function ze(e,n){let t=e.startsWith("/")?e.slice(1):e;if(n<6){let i=t.lastIndexOf("/");if(i<=0)return;let o=t.slice(0,i),d=Y(t.slice(i+1),n);return d?{name:o,version:d}:void 0}let s=t.lastIndexOf("@");if(s<=0)return;let r=t.slice(0,s),a=Y(t.slice(s+1),n);return a?{name:r,version:a}:void 0}function Y(e,n){let t=e;if(n<6){let r=t.indexOf("_");r!==-1&&(t=t.slice(0,r))}let s=t.indexOf("(");return s!==-1&&(t=t.slice(0,s)),t}function pt(e,n){let t;if(typeof e=="string"?t=e:e&&typeof e=="object"&&typeof e.version=="string"&&(t=e.version),!!t&&!(t.startsWith("link:")||t.startsWith("file:")||t.startsWith("workspace:")))return Y(t,n)}var E=class extends Error{constructor(n){super(n),this.name="LockfileError"}};function yt(){let e=Number(process.env.LOCKHAWK_MAX_LOCKFILE_BYTES);return Number.isFinite(e)&&e>0?e:64*1024*1024}function We(e){let n=0;try{n=gt(e.path).size}catch{}let t=yt();if(n>t)throw new E(`${e.filename} is ${n} bytes, exceeding the ${t}-byte safety limit. Set LOCKHAWK_MAX_LOCKFILE_BYTES to raise it.`);try{switch(e.manager){case"npm":return Ue(e.path);case"yarn":return Ge(e.path);case"pnpm":return Ye(e.path)}}catch(s){throw new E(`Failed to parse ${e.filename}: ${s instanceof Error?s.message:String(s)}`)}}function le(e){let n=F(mt(e));if(!n)throw new E(`No lockfile found in ${e}. Expected one of: package-lock.json, yarn.lock, pnpm-lock.yaml.`);return ue(We(n))}function pe(e){return e.root.version?`${e.root.name}@${e.root.version}`:e.root.name}function ge(e,n){if(!e.nodes[n])return null;let t="\0root",s=new Map,r=new Set([t]),a=[t];for(let i=0;i<a.length;i++){let o=a[i],d=o===t?e.directKeys:e.nodes[o]?.dependencies??[];for(let c of d)if(!r.has(c)){if(r.add(c),s.set(c,o),c===n)return vt(e,s,n,t);a.push(c)}}return[pe(e),n]}function vt(e,n,t,s){let r=[],a=t;for(;a!==void 0&&a!==s;)r.unshift(a),a=n.get(a);return r.unshift(pe(e)),r}import I from"semver";function Je(e,n){if(n.versions?.includes(e))return!0;let t=I.parse(e,{loose:!0});if(!t)return!1;for(let s of n.ranges??[])if(s.type!=="GIT"&&ht(t,s.events))return!0;return!1}function ht(e,n){let t=[];for(let r of n)r.introduced!==void 0?t.push({kind:"introduced",version:r.introduced==="0"?null:me(r.introduced)}):r.fixed!==void 0?t.push({kind:"fixed",version:me(r.fixed)}):r.last_affected!==void 0&&t.push({kind:"last_affected",version:me(r.last_affected)});t.sort((r,a)=>r.version===null?a.version===null?0:-1:a.version===null?1:r.version.compare(a.version));let s=!1;for(let r of t){if(r.version===null){s=!0;continue}let a=e.compare(r.version);switch(r.kind){case"introduced":a>=0&&(s=!0);break;case"fixed":a>=0&&(s=!1);break;case"last_affected":a>0&&(s=!1);break}}return s}function me(e){return I.parse(e,{loose:!0})??I.coerce(e)}function W(e,n,t){if(t.withdrawn)return{affected:!1,fixedVersions:[]};let s=!1,r=new Set;for(let a of t.affected??[]){let i=a.package?.ecosystem;if(!(i&&i!=="npm")&&!(a.package?.name&&a.package.name!==e)&&Je(n,a)){s=!0;for(let o of a.ranges??[])for(let d of o.events)d.fixed&&r.add(d.fixed)}}return{affected:s,fixedVersions:[...r]}}function ye(e,n){let t=I.parse(e,{loose:!0});return n.map(r=>I.parse(r,{loose:!0})??I.coerce(r)).filter(r=>r!==null).filter(r=>t?r.compare(t)>0:!0).sort((r,a)=>r.compare(a))[0]?.version}function Xe(e){return[e.id,...e.aliases??[]]}function Ze(e){let n=[...e];return n.find(t=>t.startsWith("CVE-"))??n.find(t=>t.startsWith("GHSA-"))??n[0]}function ve(e){if(e.length<=1)return e;let n=new Map,t=a=>{let i=a;for(;n.get(i)!==void 0&&n.get(i)!==i;)i=n.get(i);return n.set(a,i),i},s=(a,i)=>{n.set(t(a),t(i))};for(let a of e){let i=Xe(a);n.has(i[0])||n.set(i[0],i[0]);for(let o of i.slice(1))n.has(o)||n.set(o,o),s(i[0],o)}let r=new Map;for(let a of e){let i=t(a.id),o=r.get(i);o?o.push(a):r.set(i,[a])}return[...r.values()].map(bt)}function bt(e){if(e.length===1)return e[0];let n=new Set,t=new Map,s=[],r=[],a,i,o;for(let c of e){for(let f of Xe(c))n.add(f);for(let f of c.references??[])t.set(f.url,f);for(let f of c.severity??[])s.push(f);for(let f of c.affected??[])r.push(f);a??=c.summary,i??=c.details,o??=c.database_specific}let d=Ze(n);return{id:d,aliases:[...n].filter(c=>c!==d),summary:a,details:i,references:[...t.values()],severity:s,affected:r,database_specific:o}}import kn from"semver";var J={1e5:9.8,100001:9.5,100010:9.4,100011:8.7,100020:9.1,100021:8.1,100100:9.4,100101:8.9,100110:8.6,100111:7.4,100120:7.7,100121:6.4,100200:8.7,100201:7.5,100210:7.4,100211:6.3,100220:6.3,100221:4.9,101e3:9.4,101001:8.9,101010:8.8,101011:7.7,101020:7.6,101021:6.7,101100:8.6,101101:7.6,101110:7.4,101111:5.8,101120:5.9,101121:5,101200:7.2,101201:5.7,101210:5.7,101211:5.2,101220:5.2,101221:2.5,102001:8.3,102011:7,102021:5.4,102101:6.5,102111:5.8,102121:2.6,102201:5.3,102211:2.1,102221:1.3,11e4:9.5,110001:9,110010:8.8,110011:7.6,110020:7.6,110021:7,110100:9,110101:7.7,110110:7.5,110111:6.2,110120:6.1,110121:5.3,110200:7.7,110201:6.6,110210:6.8,110211:5.9,110220:5.2,110221:3,111e3:8.9,111001:7.8,111010:7.6,111011:6.7,111020:6.2,111021:5.8,111100:7.4,111101:5.9,111110:5.7,111111:5.7,111120:4.7,111121:2.3,111200:6.1,111201:5.2,111210:5.7,111211:2.9,111220:2.4,111221:1.6,112001:7.1,112011:5.9,112021:3,112101:5.8,112111:2.6,112121:1.5,112201:2.3,112211:1.3,112221:.6,2e5:9.3,200001:8.7,200010:8.6,200011:7.2,200020:7.5,200021:5.8,200100:8.6,200101:7.4,200110:7.4,200111:6.1,200120:5.6,200121:3.4,200200:7,200201:5.4,200210:5.2,200211:4,200220:4,200221:2.2,201e3:8.5,201001:7.5,201010:7.4,201011:5.5,201020:6.2,201021:5.1,201100:7.2,201101:5.7,201110:5.5,201111:4.1,201120:4.6,201121:1.9,201200:5.3,201201:3.6,201210:3.4,201211:1.9,201220:1.9,201221:.8,202001:6.4,202011:5.1,202021:2,202101:4.7,202111:2.1,202121:1.1,202201:2.4,202211:.9,202221:.4,21e4:8.8,210001:7.5,210010:7.3,210011:5.3,210020:6,210021:5,210100:7.3,210101:5.5,210110:5.9,210111:4,210120:4.1,210121:2,210200:5.4,210201:4.3,210210:4.5,210211:2.2,210220:2,210221:1.1,211e3:7.5,211001:5.5,211010:5.8,211011:4.5,211020:4,211021:2.1,211100:6.1,211101:5.1,211110:4.8,211111:1.8,211120:2,211121:.9,211200:4.6,211201:1.8,211210:1.7,211211:.7,211220:.8,211221:.2,212001:5.3,212011:2.4,212021:1.4,212101:2.4,212111:1.2,212121:.5,212201:1,212211:.3,212221:.1,"000000":10,"000001":9.9,"000010":9.8,"000011":9.5,"000020":9.5,"000021":9.2,"000100":10,"000101":9.6,"000110":9.3,"000111":8.7,"000120":9.1,"000121":8.1,"000200":9.3,"000201":9,"000210":8.9,"000211":8,"000220":8.1,"000221":6.8,"001000":9.8,"001001":9.5,"001010":9.5,"001011":9.2,"001020":9,"001021":8.4,"001100":9.3,"001101":9.2,"001110":8.9,"001111":8.1,"001120":8.1,"001121":6.5,"001200":8.8,"001201":8,"001210":7.8,"001211":7,"001220":6.9,"001221":4.8,"002001":9.2,"002011":8.2,"002021":7.2,"002101":7.9,"002111":6.9,"002121":5,"002201":6.9,"002211":5.5,"002221":2.7,"010000":9.9,"010001":9.7,"010010":9.5,"010011":9.2,"010020":9.2,"010021":8.5,"010100":9.5,"010101":9.1,"010110":9,"010111":8.3,"010120":8.4,"010121":7.1,"010200":9.2,"010201":8.1,"010210":8.2,"010211":7.1,"010220":7.2,"010221":5.3,"011000":9.5,"011001":9.3,"011010":9.2,"011011":8.5,"011020":8.5,"011021":7.3,"011100":9.2,"011101":8.2,"011110":8,"011111":7.2,"011120":7,"011121":5.9,"011200":8.4,"011201":7,"011210":7.1,"011211":5.2,"011220":5,"011221":3,"012001":8.6,"012011":7.5,"012021":5.2,"012101":7.1,"012111":5.2,"012121":2.9,"012201":6.3,"012211":2.9,"012221":1.7},he={eq1:{0:["AV:N/PR:N/UI:N/"],1:["AV:A/PR:N/UI:N/","AV:N/PR:L/UI:N/","AV:N/PR:N/UI:P/"],2:["AV:P/PR:N/UI:N/","AV:A/PR:L/UI:P/"]},eq2:{0:["AC:L/AT:N/"],1:["AC:H/AT:N/","AC:L/AT:P/"]},eq3:{0:{0:["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"],1:["VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/","VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/"]},1:{0:["VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/","VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/"],1:["VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/","VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/","VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/","VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/","VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"]},2:{1:["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"]}},eq4:{0:["SC:H/SI:S/SA:S/"],1:["SC:H/SI:H/SA:H/"],2:["SC:L/SI:L/SA:L/"]},eq5:{0:["E:A/"],1:["E:P/"],2:["E:U/"]}},Qe={eq1:{0:1,1:4,2:5},eq2:{0:1,1:2},eq3eq6:{0:{0:7,1:6},1:{0:8,1:8},2:{1:10}},eq4:{0:6,1:5,2:4},eq5:{0:1,1:1,2:1}};var mn=["AV","AC","AT","PR","UI","VC","VI","VA","SC","SI","SA"],en={N:0,A:.1,L:.2,P:.3},nn={N:0,L:.1,H:.2},tn={N:0,P:.1,A:.2},rn={L:0,H:.1},sn={N:0,P:.1},on={H:0,L:.1,N:.2},an={H:0,L:.1,N:.2},cn={H:0,L:.1,N:.2},dn={H:.1,L:.2,N:.3},fn={S:0,H:.1,L:.2,N:.3},un={S:0,H:.1,L:.2,N:.3},ln={H:0,M:.1,L:.2},pn={H:0,M:.1,L:.2},gn={H:0,M:.1,L:.2};function yn(e){let n=kt(e);if(!n)return null;let t=Rt(n);return J[t]===void 0?null:St(n,t)}function kt(e){let n=e.split("/");if(n[0]!=="CVSS:4.0")return null;let t={};for(let s of n.slice(1)){let[r,a]=s.split(":");r&&a&&(t[r]=a)}for(let s of mn)if(!(s in t))return null;for(let s of["E","CR","IR","AR"])s in t||(t[s]="X");return t}function v(e,n){let t=e[n];if(n==="E"&&t==="X")return"A";if((n==="CR"||n==="IR"||n==="AR")&&t==="X")return"H";let s=e[`M${n}`];return s!==void 0&&s!=="X"?s:t??""}function Rt(e){let n=v(e,"AV"),t=v(e,"PR"),s=v(e,"UI"),r="2";n==="N"&&t==="N"&&s==="N"?r="0":(n==="N"||t==="N"||s==="N")&&n!=="P"&&(r="1");let a=v(e,"AC")==="L"&&v(e,"AT")==="N"?"0":"1",i=v(e,"VC"),o=v(e,"VI"),d=v(e,"VA"),c="2";i==="H"&&o==="H"?c="0":(i==="H"||o==="H"||d==="H")&&(c="1");let f=v(e,"MSI"),m=v(e,"MSA"),l="2";f==="S"||m==="S"?l="0":(v(e,"SC")==="H"||v(e,"SI")==="H"||v(e,"SA")==="H")&&(l="1");let u=v(e,"E"),g=u==="A"?"0":u==="P"?"1":"2",y=v(e,"CR"),p=v(e,"IR"),k=v(e,"AR");return`${r}${a}${c}${l}${g}${y==="H"&&i==="H"||p==="H"&&o==="H"||k==="H"&&d==="H"?"0":"1"}`}function h(e,n){return e[n]??0}function X(e,n){return he[`eq${n}`][e[n-1]]??[]}function V(e,n){let t=n.indexOf(e)+e.length+1,s=n.slice(t),r=s.indexOf("/");return r>0?s.substring(0,r):s}function St(e,n){if(mn.slice(5).every(b=>v(e,b)==="N"))return 0;let t=J[n],s=Number(n[0]),r=Number(n[2]),a=Number(n[5]),i=b=>J[b.join("")]??NaN,o=n.split("").map(Number),d=i([o[0]+1,o[1],o[2],o[3],o[4],o[5]]),c=i([o[0],o[1]+1,o[2],o[3],o[4],o[5]]),f;if(r===1&&a===1)f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);else if(r===0&&a===1)f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);else if(r===1&&a===0)f=i([o[0],o[1],o[2],o[3],o[4],o[5]+1]);else if(r===0&&a===0){let b=i([o[0],o[1],o[2],o[3],o[4],o[5]+1]),q=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);f=b>q?b:q}else f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]+1]);let m=i([o[0],o[1],o[2],o[3]+1,o[4],o[5]]),l=i([o[0],o[1],o[2],o[3],o[4]+1,o[5]]),u=X(n,1),g=X(n,2),y=he.eq3[n[2]][n[5]],p=X(n,4),k=X(n,5),R=[];for(let b of u)for(let q of g)for(let de of y)for(let Kn of p)for(let Un of k)R.push(b+q+de+Kn+Un);let S=0,O=0,P=0,C=0,D=0,$=0,ne=0,te=0,re=0,se=0,oe=0,ie=0,ae=0,ce=0;for(let b of R)if(S=h(en,v(e,"AV"))-h(en,V("AV",b)),O=h(nn,v(e,"PR"))-h(nn,V("PR",b)),P=h(tn,v(e,"UI"))-h(tn,V("UI",b)),C=h(rn,v(e,"AC"))-h(rn,V("AC",b)),D=h(sn,v(e,"AT"))-h(sn,V("AT",b)),$=h(on,v(e,"VC"))-h(on,V("VC",b)),ne=h(an,v(e,"VI"))-h(an,V("VI",b)),te=h(cn,v(e,"VA"))-h(cn,V("VA",b)),re=h(dn,v(e,"SC"))-h(dn,V("SC",b)),se=h(fn,v(e,"SI"))-h(fn,V("SI",b)),oe=h(un,v(e,"SA"))-h(un,V("SA",b)),ie=h(ln,v(e,"CR"))-h(ln,V("CR",b)),ae=h(pn,v(e,"IR"))-h(pn,V("IR",b)),ce=h(gn,v(e,"AR"))-h(gn,V("AR",b)),![S,O,P,C,D,$,ne,te,re,se,oe,ie,ae,ce].some(de=>de<0))break;let $n=S+O+P,En=C+D,In=$+ne+te+ie+ae+ce,Hn=re+se+oe,B=.1,De=t-d,$e=t-c,Ee=t-f,Ie=t-m,Ln=t-l,z=Qe,jn=z.eq1[String(s)]*B,_n=z.eq2[n[1]]*B,qn=z.eq3eq6[String(r)][String(a)]*B,Fn=z.eq4[n[3]]*B,A=0,He=0,Le=0,je=0,_e=0;Number.isNaN(De)||(A++,He=De*($n/jn)),Number.isNaN($e)||(A++,Le=$e*(En/_n)),Number.isNaN(Ee)||(A++,je=Ee*(In/qn)),Number.isNaN(Ie)||(A++,_e=Ie*(Hn/Fn)),Number.isNaN(Ln)||A++;let Tn=A===0?0:(He+Le+je+_e)/A;return t-=Tn,t<0&&(t=0),t>10&&(t=10),Math.round(t*10)/10}var xt={N:.85,A:.62,L:.55,P:.2},wt={L:.77,H:.44},Vt={N:.85,R:.62},Ot={N:.85,L:.62,H:.27},Pt={N:.85,L:.68,H:.5},be={H:.56,L:.22,N:0};function ke(e){return e<=0?"none":e<4?"low":e<7?"medium":e<9?"high":"critical"}function hn(e){switch(e.trim().toUpperCase()){case"CRITICAL":return"critical";case"HIGH":return"high";case"MODERATE":case"MEDIUM":return"medium";case"LOW":return"low";case"NONE":return"none";default:return"unknown"}}function vn(e){let n=Math.round(e*1e5);return n%1e4===0?n/1e5:(Math.floor(n/1e4)+1)/10}function bn(e){let n=e.split("/"),t=n[0]??"";if(t==="CVSS:4.0"){let p=yn(e);return p===null?null:{score:p,level:ke(p),version:t}}if(!/^CVSS:3\.[01]$/.test(t))return null;let s={};for(let p of n.slice(1)){let[k,R]=p.split(":");k&&R&&(s[k]=R)}let r=xt[s.AV??""],a=wt[s.AC??""],i=Vt[s.UI??""],o=s.S==="C",d=(o?Pt:Ot)[s.PR??""],c=be[s.C??""],f=be[s.I??""],m=be[s.A??""];if([r,a,i,d,c,f,m].some(p=>p===void 0))return null;let l=1-(1-c)*(1-f)*(1-m),u=o?7.52*(l-.029)-3.25*Math.pow(l-.02,15):6.42*l,g=8.22*r*a*d*i,y;return u<=0?y=0:o?y=vn(Math.min(1.08*(u+g),10)):y=vn(Math.min(u+g,10)),{score:y,level:ke(y),version:t}}function Re(e){let n=[];for(let r of e.severity??[])r.score&&n.push(r.score);for(let r of e.affected??[])for(let a of r.severity??[])a.score&&n.push(a.score);let t=null;for(let r of n){let a=bn(r);a&&(!t||a.score>t.score)&&(t=a)}if(t)return{level:t.level,score:t.score,vector:At(t,n),cvssVersion:t.version,source:"cvss"};let s=Nt(e);return s?{level:hn(s),source:"database"}:{level:"unknown",source:"unknown"}}function At(e,n){return n.find(t=>t.startsWith(e.version))}function Nt(e){let n=s=>{let r=s?.severity;return typeof r=="string"?r:void 0},t=n(e.database_specific);if(t)return t;for(let s of e.affected??[]){let r=n(s.database_specific);if(r)return r}}function Se(e,n,t={}){let s=[];for(let r of Object.values(e.nodes)){if(r.unscannable||t.prodOnly&&r.scope==="dev")continue;let a=n(r.name);if(a.length===0)continue;let i=new Map,o=a.filter(c=>{let f=W(r.name,r.version,c);return i.set(c,f),f.affected});if(o.length===0)continue;let d=ge(e,r.key);for(let c of ve(o)){if(Mt(c,t.ignore))continue;let{fixedVersions:f}=i.get(c)??W(r.name,r.version,c),m=Ct(f),l=ye(r.version,f);s.push({id:c.id,aliases:c.aliases??[],packageName:r.name,version:r.version,scope:r.scope,direct:r.direct,severity:Re(c),summary:c.summary??c.id,details:c.details,references:(c.references??[]).map(u=>u.url),fixedVersions:m,recommendation:$t(r.name,r.direct,l,e.manager),dependencyPaths:d?[d]:[],source:"osv"})}}return s}function Mt(e,n){return!n||n.size===0?!1:n.has(e.id)?!0:(e.aliases??[]).some(t=>n.has(t))}function Ct(e){return[...new Set(e)].sort((n,t)=>{let s=kn.parse(n,{loose:!0}),r=kn.parse(t,{loose:!0});return s&&r?s.compare(r):n.localeCompare(t)})}var Dt={npm:"npm install",yarn:"yarn add",pnpm:"pnpm add"};function $t(e,n,t,s){return t?n?`Upgrade to ${e}@${t} or later (e.g. \`${Dt[s]} ${e}@${t}\`).`:`Update the dependency that pulls in ${e} so it resolves to ${e}@${t} or later. If it cannot, force the resolution via an override.`:n?"No fixed version is available yet. Watch the advisory, or evaluate an alternative package.":"No fixed version is available yet. Pressure the parent dependency to update, or override the version."}var xe=class{byName=new Map;ids=new Set;add(n){if(n.withdrawn||this.ids.has(n.id))return;this.ids.add(n.id);let t=new Set;for(let s of n.affected??[]){let r=s.package?.ecosystem;r&&r!=="npm"||s.package?.name&&t.add(s.package.name)}for(let s of t){let r=this.byName.get(s);r?r.push(n):this.byName.set(s,[n])}}addAll(n){for(let t of n)this.add(t)}vulnerabilitiesFor(n){return this.byName.get(n)??[]}get size(){return this.ids.size}};import{resolve as cr}from"path";import{join as we}from"path";import Et from"env-paths";function Ve(e){return e||(process.env.LOCKHAWK_CACHE?process.env.LOCKHAWK_CACHE:Et("lockhawk",{suffix:""}).cache)}function T(e){return we(e,"osv-db","npm")}var Rn=4096;function Z(e){let n=2166136261;for(let t=0;t<e.length;t++)n^=e.charCodeAt(t),n=Math.imul(n,16777619);return(n>>>0)%Rn}function K(e){return we(T(e),"meta.json")}function Oe(e,n){return we(e,"query-cache",`${encodeURIComponent(n)}.json`)}import{mkdir as It,readFile as Ht,writeFile as Lt}from"fs/promises";import{dirname as jt}from"path";import _t from"p-limit";import qt,{AbortError as Ft}from"p-retry";var Pe="https://api.osv.dev/v1",Sn=1e3,U=class{constructor(n){this.opts=n;this.limit=_t(n.concurrency??16)}opts;limit;async fetchAdvisories(n){let t=[...new Set(n.map(o=>o.name))],s=await this.queryBatch(t),r=new Set;for(let o of s.values())for(let d of o)r.add(d);let a=await this.hydrate([...r]),i=new Map;for(let[o,d]of s){let c=[];for(let f of d){let m=a.get(f);m&&c.push(m)}c.length&&i.set(o,c)}return i}async queryBatch(n){let t=new Map;for(let s=0;s<n.length;s+=Sn){let r=n.slice(s,s+Sn),a={queries:r.map(o=>({package:{name:o,ecosystem:"npm"}}))},i=await this.request(`${Pe}/querybatch`,a);for(let o=0;o<r.length;o++){let d=r[o],c=i.results[o];if(!c)continue;let f=t.get(d)??new Set;for(let l of c.vulns??[])f.add(l.id);let m=c.next_page_token;for(;m;){let l=await this.request(`${Pe}/query`,{package:{name:d,ecosystem:"npm"},page_token:m});for(let u of l.vulns??[])f.add(u.id);m=l.next_page_token}f.size&&t.set(d,f)}}return t}async hydrate(n){let t=new Map;return await Promise.all(n.map(s=>this.limit(async()=>{let r=await this.getVulnerability(s);r&&t.set(s,r)}))),t}async getVulnerability(n){let t=await this.readCache(n);if(t)return t;let s=await this.request(`${Pe}/vulns/${encodeURIComponent(n)}`);return await this.writeCache(n,s),s}async request(n,t){let s=this.opts.retries??3;return qt(async()=>{let r=await fetch(n,{method:t?"POST":"GET",headers:t?{"content-type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(this.opts.timeoutMs??15e3)});if(r.ok)return await r.json();throw r.status===429||r.status>=500?new Error(`OSV ${r.status} for ${n}`):new Ft(`OSV ${r.status} for ${n}`)},{retries:s})}async readCache(n){if(!this.opts.noCache)try{let t=JSON.parse(await Ht(Oe(this.opts.cacheDir,n),"utf8")),s=(this.opts.cacheTtlHours??24)*36e5;return Date.now()-t.fetchedAt>s?void 0:t.vuln}catch{return}}async writeCache(n,t){if(!this.opts.noCache)try{let s=Oe(this.opts.cacheDir,n);await It(jt(s),{recursive:!0}),await Lt(s,JSON.stringify({fetchedAt:Date.now(),vuln:t}))}catch{}}};import{createWriteStream as Tt}from"fs";import{mkdir as xn,mkdtemp as Kt,readFile as wn,rm as Vn,writeFile as Ae}from"fs/promises";import{tmpdir as Ut}from"os";import{join as Q}from"path";import{Readable as Gt}from"stream";import{pipeline as Bt}from"stream/promises";import{gunzipSync as zt,gzipSync as Yt}from"zlib";import Wt from"p-limit";import Jt from"yauzl";var Xt="https://storage.googleapis.com/osv-vulnerabilities/npm/all.zip",Zt=32,Qt=8*1024*1024,H=class extends Error{constructor(){super("No offline OSV database found. Run `lockhawk db update` first."),this.name="OfflineDbMissingError"}},er=/^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/,nr=/^(?:W\/)?"[\x21\x23-\x7e]*"$/;function tr(e){return e&&er.test(e)?e:void 0}function rr(e){return e&&nr.test(e)?e:void 0}async function L(e){try{return JSON.parse(await wn(K(e),"utf8"))}catch{return}}async function sr(e){let{cacheDir:n,nowIso:t,force:s,onProgress:r}=e,a=T(n);await xn(a,{recursive:!0});let i=s?void 0:await L(n),o={},d=rr(i?.etag),c=tr(i?.lastModified);d&&(o["If-None-Match"]=d),c&&(o["If-Modified-Since"]=c),r?.("Fetching npm advisory database from OSV.dev\u2026");let f=await fetch(Xt,{headers:o});if(f.status===304&&i){let p={...i,lastUpdated:t};return await Ae(K(n),JSON.stringify(p,null,2)),{status:"unchanged",meta:p}}if(!f.ok||!f.body)throw new Error(`OSV database download failed: HTTP ${f.status}`);let m=await Kt(Q(Ut(),"lockhawk-osv-")),l=Q(m,"all.zip"),u;try{await Bt(Gt.fromWeb(f.body),Tt(l)),r?.("Extracting advisories\u2026"),u=await ar(l)}finally{await Vn(m,{recursive:!0,force:!0})}r?.("Building package index\u2026");let g=or(u);await ir(n,g);let y={ecosystem:"npm",source:"osv.dev",lastUpdated:t,recordCount:u.length,packageCount:g.size,etag:f.headers.get("etag")??void 0,lastModified:f.headers.get("last-modified")??void 0};return await Ae(K(n),JSON.stringify(y,null,2)),{status:"updated",meta:y}}function On(e){return Q(T(e),"by-name")}function Pn(e,n){return Q(On(e),`${n}.json.gz`)}async function Ne(e,n){if(!await L(e))throw new H;let t=new Map;for(let a of new Set(n)){let i=Z(a),o=t.get(i);o?o.push(a):t.set(i,[a])}let s=new Map,r=Wt(Zt);return await Promise.all([...t.entries()].map(([a,i])=>r(async()=>{try{let o=JSON.parse(zt(await wn(Pn(e,a))).toString("utf8"));for(let d of i){let c=o[d];c?.length&&s.set(d,c)}}catch{}}))),s}function or(e){let n=new Map;for(let t of e){if(t.withdrawn)continue;let s=new Set;for(let r of t.affected??[]){let a=r.package?.ecosystem;a&&a!=="npm"||r.package?.name&&s.add(r.package.name)}for(let r of s){let a=n.get(r);a?a.push(t):n.set(r,[t])}}return n}async function ir(e,n){let t=On(e);await Vn(t,{recursive:!0,force:!0}),await xn(t,{recursive:!0});let s=new Map;for(let[i,o]of n){let d=Z(i),c=s.get(d)??{};c[i]=o,s.set(d,c)}let r=[...s.entries()],a=256;for(let i=0;i<r.length;i+=a)await Promise.all(r.slice(i,i+a).map(([o,d])=>Ae(Pn(e,o),Yt(Buffer.from(JSON.stringify(d))))))}function ar(e){return new Promise((n,t)=>{let s=[];Jt.open(e,{lazyEntries:!0},(r,a)=>{if(r||!a)return t(r??new Error("Failed to open OSV zip"));a.on("entry",i=>{if(!i.fileName.endsWith(".json")||i.uncompressedSize>Qt)return a.readEntry();a.openReadStream(i,(o,d)=>{if(o||!d)return a.readEntry();let c=[];d.on("data",f=>c.push(f)),d.on("error",()=>a.readEntry()),d.on("end",()=>{try{s.push(JSON.parse(Buffer.concat(c).toString("utf8")))}catch{}a.readEntry()})})}),a.on("end",()=>n(s)),a.on("error",t),a.readEntry()})})}var An=36e5,j=class{constructor(n){this.opts=n}opts;async prepare(n){let t=await L(this.opts.cacheDir);if(!t)throw new H;let s=await Ne(this.opts.cacheDir,n.map(o=>o.name)),r=(Date.now()-Date.parse(t.lastUpdated))/An,a=r>(this.opts.staleAfterHours??24),i=a?[`Offline database is ${Math.round(r)}h old. Run \`lockhawk db update\` for current results.`]:[];return{candidatesFor:o=>s.get(o)??[],database:{source:"offline",recordCount:t.recordCount,lastUpdated:t.lastUpdated,ageHours:Math.round(r*10)/10,stale:a,warnings:i}}}},G=class{constructor(n){this.opts=n}opts;async prepare(n){let t=new U({cacheDir:this.opts.cacheDir,concurrency:this.opts.concurrency,noCache:this.opts.noCache,cacheTtlHours:this.opts.cacheTtlHours});try{let s=await t.fetchAdvisories(n);return{candidatesFor:r=>s.get(r)??[],database:{source:"online",stale:!1,warnings:[]}}}catch(s){if(this.opts.strictNetwork)throw s;let r=s instanceof Error?s.message:String(s);return{candidatesFor:()=>[],database:{source:"online",stale:!0,warnings:[`OSV.dev was unreachable (${r}). Scan completed without online data \u2014 results may be incomplete.`]}}}}},ee=class{constructor(n){this.opts=n}opts;async prepare(n){let t=await L(this.opts.cacheDir),s=this.opts.staleAfterHours??24;if(t&&(Date.now()-Date.parse(t.lastUpdated))/An<=s)return new j(this.opts).prepare(n);try{return await new G({...this.opts,strictNetwork:!0}).prepare(n)}catch(r){if(t){let i=await new j(this.opts).prepare(n);return i.database.warnings.push("Used the stale offline database because OSV.dev was unreachable."),i}if(this.opts.strictNetwork)throw r;let a=r instanceof Error?r.message:String(r);return{candidatesFor:()=>[],database:{source:"online",stale:!0,warnings:[`No offline database and OSV.dev was unreachable (${a}). Run \`lockhawk db update\`.`]}}}}};function Me(e,n){switch(e){case"offline":return new j(n);case"online":return new G(n);default:return new ee(n)}}var Nn={name:"lockhawk",version:"0.1.0"};async function dr(e={},n){let t=Date.now(),s=cr(e.path??"."),r=le(s),a=F(s),i=Mn(r,e.prodOnly),o=Ve(e.cacheDir),d=n??Me(e.mode??"auto",{cacheDir:o,concurrency:e.concurrency,noCache:e.noCache,cacheTtlHours:e.cacheTtlHours,strictNetwork:e.strictNetwork});e.onProgress?.("Checking dependencies against OSV.dev\u2026");let c=await d.prepare(i),f=Se(r,c.candidatesFor,{prodOnly:e.prodOnly,ignore:e.ignore&&e.ignore.length?new Set(e.ignore):void 0});e.severityThreshold&&e.severityThreshold!=="none"&&(f=f.filter(l=>qe(l.severity.level,e.severityThreshold))),f.sort(lr);let m=fr(r);return{schemaVersion:1,tool:{...Nn},scannedAt:new Date(t).toISOString(),target:{path:s,manager:r.manager,lockfile:a?.filename??"",root:r.root},database:c.database,summary:ur(f),stats:{totalPackages:Object.keys(r.nodes).length,uniquePackages:i.length,directDependencies:r.directKeys.length,unscannable:m.length,durationMs:Date.now()-t},findings:f,unscannable:m}}function Mn(e,n){let t=new Set,s=[];for(let r of Object.values(e.nodes))r.unscannable||n&&r.scope==="dev"||t.has(r.key)||(t.add(r.key),s.push({name:r.name,version:r.version}));return s}function fr(e){let n=[];for(let t of Object.values(e.nodes))t.unscannable&&n.push({name:t.name,version:t.version,reason:t.unscannable.reason});return n}function ur(e){let n={total:e.length,critical:0,high:0,medium:0,low:0,unknown:0,none:0,vulnerablePackages:0,fixable:0},t=new Set;for(let s of e)n[s.severity.level]+=1,t.add(`${s.packageName}@${s.version}`),s.fixedVersions.length>0&&(n.fixable+=1);return n.vulnerablePackages=t.size,n}function lr(e,n){let t=N[n.severity.level]-N[e.severity.level];return t!==0?t:e.packageName.localeCompare(n.packageName)}function pr(e,n){return["critical","high","medium","low","unknown"].some(s=>N[s]>=N[n]&&e[s]>0)}function gr(e){return JSON.stringify(e,null,2)}var mr="https://github.com/lockhawk/lockhawk";function yr(e){return e.find(n=>{try{let t=new URL(n);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}})}function vr(e){if(typeof e.severity.score=="number")return e.severity.score;switch(e.severity.level){case"critical":return 9.5;case"high":return 7.5;case"medium":return 5;case"low":return 2;default:return 0}}function hr(e){return e==="critical"||e==="high"?"error":e==="medium"?"warning":"note"}function Cn(e){let n=e.target.lockfile||"package-lock.json",t=new Map,s=[];for(let r of e.findings){t.has(r.id)||t.set(r.id,{id:r.id,name:`${r.packageName} ${r.id}`,shortDescription:{text:r.summary},fullDescription:r.details?{text:r.details}:void 0,helpUri:yr(r.references),properties:{"security-severity":String(vr(r)),tags:["security","dependency",r.severity.level]}});let a=r.dependencyPaths[0]?.join(" \u203A ")??r.packageName,i=r.fixedVersions[0]?` Fixed in ${r.fixedVersions[0]}.`:"";s.push({ruleId:r.id,level:hr(r.severity.level),message:{text:`${r.severity.level.toUpperCase()}: ${r.packageName}@${r.version} \u2014 ${r.summary}.${i} Path: ${a}.`},locations:[{physicalLocation:{artifactLocation:{uri:n},region:{startLine:1}}}],partialFingerprints:{lockhawkFinding:`${r.packageName}@${r.version}@${r.id}`},properties:{package:r.packageName,version:r.version,scope:r.scope,fixedVersions:r.fixedVersions}})}return{$schema:"https://json.schemastore.org/sarif-2.1.0.json",version:"2.1.0",runs:[{tool:{driver:{name:e.tool.name,version:e.tool.version,informationUri:mr,rules:[...t.values()]}},results:s,properties:{scannedAt:e.scannedAt,databaseSource:e.database.source,databaseAgeHours:e.database.ageHours,databaseStale:e.database.stale}}]}}function br(e){return JSON.stringify(Cn(e),null,2)}var Ce="<!--LOCKHAWK_DATA-->";function kr(e){return`<script>window.__SCAN_RESULT__ = ${JSON.stringify(e).replace(/</g,"\\u003c").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")};</script>`}function Rr(e,n){let t=kr(e);return n?n.includes(Ce)?n.replace(Ce,()=>t):n.replace("</head>",()=>`${t}</head>`):xr(e,t)}var Dn={critical:"#b4232c",high:"#d9822b",medium:"#c9a227",low:"#3a7bd5",unknown:"#7a7a7a",none:"#3a9e54"};function x(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function Sr(e){try{let n=new URL(e);return n.protocol==="http:"||n.protocol==="https:"?e:void 0}catch{return}}function xr(e,n){let{summary:t}=e,s=["critical","high","medium","low","unknown"].map(i=>`
2
- <div class="card" style="border-top:4px solid ${Dn[i]}">
1
+ var A={none:0,unknown:1,low:2,medium:3,high:4,critical:5};function Ke(e,n){return A[e]>=A[n]}function x(e,n){return`${e}@${n}`}import{statSync as ht}from"fs";import{resolve as bt}from"path";import{existsSync as Ue,readFileSync as Wn,statSync as Jn}from"fs";import{join as Ge}from"path";var Xn=[{filename:"pnpm-lock.yaml",manager:"pnpm"},{filename:"yarn.lock",manager:"yarn"},{filename:"package-lock.json",manager:"npm"},{filename:"npm-shrinkwrap.json",manager:"npm"}];function F(e){for(let{filename:n,manager:t}of Xn){let s=Ge(e,n);if(Ue(s)&&Jn(s).isFile())return{manager:t,path:s,filename:n}}}function M(e){let n=Ge(e,"package.json"),t={};if(Ue(n))try{t=JSON.parse(Wn(n,"utf8"))}catch{t={}}let s=r=>r&&typeof r=="object"?r:{};return{name:typeof t.name=="string"?t.name:"project",version:typeof t.version=="string"?t.version:void 0,dependencies:s(t.dependencies),devDependencies:s(t.devDependencies),optionalDependencies:s(t.optionalDependencies),peerDependencies:s(t.peerDependencies)}}function le(e,n){let t=new Set,s=[];for(let r of e)t.has(r)||(t.add(r),s.push(r));for(let r=0;r<s.length;r++){let a=n[s[r]];if(a)for(let i of a.dependencies)t.has(i)||(t.add(i),s.push(i))}return t}function pe(e){let n=le(e.directProd,e.nodes),t=le(e.directOptional,e.nodes),s=le(e.directDev,e.nodes),r=new Set([...e.directProd,...e.directOptional,...e.directDev]),a={};for(let[i,o]of Object.entries(e.nodes)){let d;n.has(i)?d="prod":t.has(i)?d="optional":s.has(i)?d="dev":d="prod",a[i]={key:i,name:o.name,version:o.version,scope:d,direct:r.has(i),dependencies:Zn(o.dependencies),...o.unscannable?{unscannable:o.unscannable}:{}}}return{manager:e.manager,lockfilePath:e.lockfilePath,lockfileVersion:e.lockfileVersion,root:e.root,nodes:a,directKeys:[...r].filter(i=>a[i]!==void 0)}}function Zn(e){return e.length>1?[...new Set(e)]:e}import{readFileSync as Qn}from"fs";import{dirname as et}from"path";function ze(e){let n=JSON.parse(Qn(e,"utf8"));return n.packages?tt(n,e):rt(n,e)}function nt(e){let n="node_modules/",t=e.lastIndexOf(n);return t===-1?e:e.slice(t+n.length)}function tt(e,n){let t=e.packages??{},s=t[""]??{},r={name:s.name??e.name??"project",version:s.version??e.version},a=Object.create(null),i=[],o=Object.create(null);for(let[u,l]of Object.entries(t)){if(u===""||l.link)continue;let m=l.name??nt(u),y=l.version;if(!y)continue;let p=x(m,y);if(o[u]=p,!a[p]){let k={key:p,name:m,version:y,dependencies:[]};u.includes("node_modules")||(k.unscannable={reason:"local workspace package"},i.push({name:m,version:y,reason:"local workspace package"})),a[p]=k}}let d=(u,l)=>{let m=u;for(;;){let y=`${m?`${m}/`:""}node_modules/${l}`,p=t[y];if(p)return p.link&&typeof p.resolved=="string"?p.resolved:y;if(!m)return;let k=m.lastIndexOf("/node_modules/");m=k===-1?"":m.slice(0,k)}},c=new Set,f=new Set,g=new Set;for(let[u,l]of Object.entries(t)){if(l.link)continue;let m=u===""?void 0:o[u],y=u===""||!u.includes("node_modules"),p=(k,S)=>{for(let R of k){let O=d(u,R);if(!O)continue;let P=o[O];P&&(m&&m!==P&&a[m].dependencies.push(P),S&&S.add(P))}};p(Object.keys(l.dependencies??{}),y?c:void 0),p(Object.keys(l.optionalDependencies??{}),y?g:void 0),y&&p(Object.keys(l.devDependencies??{}),f)}return{manager:"npm",lockfilePath:n,lockfileVersion:e.lockfileVersion,root:r,nodes:a,directProd:[...c],directDev:[...f],directOptional:[...g],unscannable:i}}var Be=500;function rt(e,n){let t=M(et(n)),s={name:e.name??t.name,version:e.version??t.version},r=Object.create(null),a=l=>{let m=new Map;for(let[y,p]of Object.entries(l??{}))p?.version&&m.set(y,p.version);return m},i=(l,m)=>{for(let y=m.length-1;y>=0;y--){let p=m[y].get(l);if(p)return p}},o=(l,m)=>{if(m.length>Be)throw new Error(`dependency nesting exceeds ${Be} levels (malformed or malicious lockfile)`);let y=a(l),p=[...m,y];for(let[k,S]of Object.entries(l??{})){let R=S?.version;if(!R)continue;let O=x(k,R);r[O]||(r[O]={key:O,name:k,version:R,dependencies:[]});let P=[...p,a(S.dependencies)];for(let N of Object.keys(S.requires??{})){let C=i(N,P);if(C){let D=x(N,C);D!==O&&r[O].dependencies.push(D)}}S.dependencies&&o(S.dependencies,p)}};o(e.dependencies,[]);let d=a(e.dependencies),c=[],f=[],g=[],u=(l,m)=>{for(let y of l){let p=d.get(y);p&&m.push(x(y,p))}};return u(Object.keys(t.dependencies),c),u(Object.keys(t.optionalDependencies),g),u(Object.keys(t.devDependencies),f),{manager:"npm",lockfilePath:n,lockfileVersion:e.lockfileVersion,root:s,nodes:r,directProd:c,directDev:f,directOptional:g,unscannable:[]}}import{readFileSync as st}from"fs";import{dirname as ot}from"path";import{createRequire as it}from"module";import at from"js-yaml";var ct=it(import.meta.url),dt=ct("@yarnpkg/lockfile");function Ye(e){let n=st(e,"utf8"),t=M(ot(e)),s=n.includes("__metadata"),{descriptorToVersion:r,entryByVersion:a,lockfileVersion:i}=s?ut(n):ft(n);return lt(e,t,r,a,i,s)}function We(e){let n=e.lastIndexOf("@");if(!(n<=0))return{name:e.slice(0,n),range:e.slice(n+1)}}function ft(e){let n=dt.parse(e),t=new Map,s=new Map;for(let[r,a]of Object.entries(n.object))if(a.version)for(let i of r.split(/,\s*/)){let o=We(i);o&&t.set(`${o.name}@${o.range}`,a.version),o&&s.set(x(o.name,a.version),a)}return{descriptorToVersion:t,entryByVersion:s,lockfileVersion:1}}function ut(e){let n=at.load(e)??{},t=new Map,s=new Map,r="berry";for(let[a,i]of Object.entries(n)){if(a==="__metadata"){let o=i.version;o!==void 0&&(r=o);continue}if(i.version)for(let o of a.split(/,\s*/)){let d=We(o);d&&(t.set(`${d.name}@${d.range}`,i.version),s.set(x(d.name,i.version),i))}}return{descriptorToVersion:t,entryByVersion:s,lockfileVersion:r}}function lt(e,n,t,s,r,a){let i=(c,f)=>{let g=a?[`${c}@${f}`,`${c}@npm:${f}`]:[`${c}@${f}`];for(let u of g){let l=t.get(u);if(l)return l}},o=Object.create(null);for(let[c,f]of s){let g=c.lastIndexOf("@"),u=c.slice(0,g),l=c.slice(g+1);o[c]||(o[c]={key:c,name:u,version:l,dependencies:[]});let m=y=>{for(let[p,k]of Object.entries(y??{})){let S=i(p,k);if(!S)continue;let R=x(p,S);R!==c&&o[c].dependencies.push(R)}};m(f.dependencies),m(f.optionalDependencies)}let d=c=>{let f=[];for(let[g,u]of Object.entries(c)){let l=i(g,u);l&&f.push(x(g,l))}return f};return{manager:"yarn",lockfilePath:e,lockfileVersion:r,root:{name:n.name,version:n.version},nodes:o,directProd:d(n.dependencies),directDev:d(n.devDependencies),directOptional:d(n.optionalDependencies),unscannable:[]}}import{readFileSync as pt}from"fs";import{dirname as gt}from"path";import mt from"js-yaml";function Xe(e){let n=mt.load(pt(e,"utf8"))??{},t=M(gt(e)),s=yt(n.lockfileVersion),r=Object.create(null);for(let g of Object.keys(n.packages??{})){let u=Je(g,s);if(!u)continue;let l=x(u.name,u.version);r[l]||(r[l]={key:l,name:u.name,version:u.version,dependencies:[]})}let a=s>=9?n.snapshots??{}:n.packages??{};for(let[g,u]of Object.entries(a)){let l=Je(g,s);if(!l)continue;let m=x(l.name,l.version);r[m]||(r[m]={key:m,name:l.name,version:l.version,dependencies:[]});let y=p=>{for(let[k,S]of Object.entries(p??{})){let R=x(k,J(S,s));R!==m&&r[R]&&r[m].dependencies.push(R)}};y(u.dependencies),y(u.optionalDependencies)}let i=n.importers??{".":{dependencies:n.dependencies,devDependencies:n.devDependencies,optionalDependencies:n.optionalDependencies}},o=new Set,d=new Set,c=new Set,f=(g,u)=>{for(let[l,m]of Object.entries(g??{})){let y=vt(m,s);if(!y)continue;let p=x(l,y);r[p]&&u.add(p)}};for(let g of Object.values(i))f(g.dependencies,o),f(g.optionalDependencies,c),f(g.devDependencies,d);return{manager:"pnpm",lockfilePath:e,lockfileVersion:n.lockfileVersion,root:{name:t.name,version:t.version},nodes:r,directProd:[...o],directDev:[...d],directOptional:[...c],unscannable:[]}}function yt(e){let n=parseFloat(String(e??"9"));return Number.isNaN(n)?9:Math.floor(n)}function Je(e,n){let t=e.startsWith("/")?e.slice(1):e;if(n<6){let i=t.lastIndexOf("/");if(i<=0)return;let o=t.slice(0,i),d=J(t.slice(i+1),n);return d?{name:o,version:d}:void 0}let s=t.lastIndexOf("@");if(s<=0)return;let r=t.slice(0,s),a=J(t.slice(s+1),n);return a?{name:r,version:a}:void 0}function J(e,n){let t=e;if(n<6){let r=t.indexOf("_");r!==-1&&(t=t.slice(0,r))}let s=t.indexOf("(");return s!==-1&&(t=t.slice(0,s)),t}function vt(e,n){let t;if(typeof e=="string"?t=e:e&&typeof e=="object"&&typeof e.version=="string"&&(t=e.version),!!t&&!(t.startsWith("link:")||t.startsWith("file:")||t.startsWith("workspace:")))return J(t,n)}var E=class extends Error{constructor(n){super(n),this.name="LockfileError"}};function kt(){let e=Number(process.env.LOCKHAWK_MAX_LOCKFILE_BYTES);return Number.isFinite(e)&&e>0?e:64*1024*1024}function Ze(e){let n=0;try{n=ht(e.path).size}catch{}let t=kt();if(n>t)throw new E(`${e.filename} is ${n} bytes, exceeding the ${t}-byte safety limit. Set LOCKHAWK_MAX_LOCKFILE_BYTES to raise it.`);try{switch(e.manager){case"npm":return ze(e.path);case"yarn":return Ye(e.path);case"pnpm":return Xe(e.path)}}catch(s){throw new E(`Failed to parse ${e.filename}: ${s instanceof Error?s.message:String(s)}`)}}function ge(e){let n=F(bt(e));if(!n)throw new E(`No lockfile found in ${e}. Expected one of: package-lock.json, yarn.lock, pnpm-lock.yaml.`);return pe(Ze(n))}function me(e){return e.root.version?`${e.root.name}@${e.root.version}`:e.root.name}function ye(e,n){if(!e.nodes[n])return null;let t="\0root",s=new Map,r=new Set([t]),a=[t];for(let i=0;i<a.length;i++){let o=a[i],d=o===t?e.directKeys:e.nodes[o]?.dependencies??[];for(let c of d)if(!r.has(c)){if(r.add(c),s.set(c,o),c===n)return St(e,s,n,t);a.push(c)}}return[me(e),n]}function St(e,n,t,s){let r=[],a=t;for(;a!==void 0&&a!==s;)r.unshift(a),a=n.get(a);return r.unshift(me(e)),r}import I from"semver";function Qe(e,n){if(n.versions?.includes(e))return!0;let t=I.parse(e,{loose:!0});if(!t)return!1;for(let s of n.ranges??[])if(s.type!=="GIT"&&Rt(t,s.events))return!0;return!1}function Rt(e,n){let t=[];for(let r of n)r.introduced!==void 0?t.push({kind:"introduced",version:r.introduced==="0"?null:ve(r.introduced)}):r.fixed!==void 0?t.push({kind:"fixed",version:ve(r.fixed)}):r.last_affected!==void 0&&t.push({kind:"last_affected",version:ve(r.last_affected)});t.sort((r,a)=>r.version===null?a.version===null?0:-1:a.version===null?1:r.version.compare(a.version));let s=!1;for(let r of t){if(r.version===null){s=!0;continue}let a=e.compare(r.version);switch(r.kind){case"introduced":a>=0&&(s=!0);break;case"fixed":a>=0&&(s=!1);break;case"last_affected":a>0&&(s=!1);break}}return s}function ve(e){return I.parse(e,{loose:!0})??I.coerce(e)}function X(e,n,t){if(t.withdrawn)return{affected:!1,fixedVersions:[]};let s=!1,r=new Set;for(let a of t.affected??[]){let i=a.package?.ecosystem;if(!(i&&i!=="npm")&&!(a.package?.name&&a.package.name!==e)&&Qe(n,a)){s=!0;for(let o of a.ranges??[])for(let d of o.events)d.fixed&&r.add(d.fixed)}}return{affected:s,fixedVersions:[...r]}}function he(e,n){let t=I.parse(e,{loose:!0});return n.map(r=>I.parse(r,{loose:!0})??I.coerce(r)).filter(r=>r!==null).filter(r=>t?r.compare(t)>0:!0).sort((r,a)=>r.compare(a))[0]?.version}function en(e){return[e.id,...e.aliases??[]]}function nn(e){let n=[...e];return n.find(t=>t.startsWith("CVE-"))??n.find(t=>t.startsWith("GHSA-"))??n[0]}function be(e){if(e.length<=1)return e;let n=new Map,t=a=>{let i=a;for(;n.get(i)!==void 0&&n.get(i)!==i;)i=n.get(i);return n.set(a,i),i},s=(a,i)=>{n.set(t(a),t(i))};for(let a of e){let i=en(a);n.has(i[0])||n.set(i[0],i[0]);for(let o of i.slice(1))n.has(o)||n.set(o,o),s(i[0],o)}let r=new Map;for(let a of e){let i=t(a.id),o=r.get(i);o?o.push(a):r.set(i,[a])}return[...r.values()].map(wt)}function wt(e){if(e.length===1)return e[0];let n=new Set,t=new Map,s=[],r=[],a,i,o;for(let c of e){for(let f of en(c))n.add(f);for(let f of c.references??[])t.set(f.url,f);for(let f of c.severity??[])s.push(f);for(let f of c.affected??[])r.push(f);a??=c.summary,i??=c.details,o??=c.database_specific}let d=nn(n);return{id:d,aliases:[...n].filter(c=>c!==d),summary:a,details:i,references:[...t.values()],severity:s,affected:r,database_specific:o}}import wn from"semver";var Z={1e5:9.8,100001:9.5,100010:9.4,100011:8.7,100020:9.1,100021:8.1,100100:9.4,100101:8.9,100110:8.6,100111:7.4,100120:7.7,100121:6.4,100200:8.7,100201:7.5,100210:7.4,100211:6.3,100220:6.3,100221:4.9,101e3:9.4,101001:8.9,101010:8.8,101011:7.7,101020:7.6,101021:6.7,101100:8.6,101101:7.6,101110:7.4,101111:5.8,101120:5.9,101121:5,101200:7.2,101201:5.7,101210:5.7,101211:5.2,101220:5.2,101221:2.5,102001:8.3,102011:7,102021:5.4,102101:6.5,102111:5.8,102121:2.6,102201:5.3,102211:2.1,102221:1.3,11e4:9.5,110001:9,110010:8.8,110011:7.6,110020:7.6,110021:7,110100:9,110101:7.7,110110:7.5,110111:6.2,110120:6.1,110121:5.3,110200:7.7,110201:6.6,110210:6.8,110211:5.9,110220:5.2,110221:3,111e3:8.9,111001:7.8,111010:7.6,111011:6.7,111020:6.2,111021:5.8,111100:7.4,111101:5.9,111110:5.7,111111:5.7,111120:4.7,111121:2.3,111200:6.1,111201:5.2,111210:5.7,111211:2.9,111220:2.4,111221:1.6,112001:7.1,112011:5.9,112021:3,112101:5.8,112111:2.6,112121:1.5,112201:2.3,112211:1.3,112221:.6,2e5:9.3,200001:8.7,200010:8.6,200011:7.2,200020:7.5,200021:5.8,200100:8.6,200101:7.4,200110:7.4,200111:6.1,200120:5.6,200121:3.4,200200:7,200201:5.4,200210:5.2,200211:4,200220:4,200221:2.2,201e3:8.5,201001:7.5,201010:7.4,201011:5.5,201020:6.2,201021:5.1,201100:7.2,201101:5.7,201110:5.5,201111:4.1,201120:4.6,201121:1.9,201200:5.3,201201:3.6,201210:3.4,201211:1.9,201220:1.9,201221:.8,202001:6.4,202011:5.1,202021:2,202101:4.7,202111:2.1,202121:1.1,202201:2.4,202211:.9,202221:.4,21e4:8.8,210001:7.5,210010:7.3,210011:5.3,210020:6,210021:5,210100:7.3,210101:5.5,210110:5.9,210111:4,210120:4.1,210121:2,210200:5.4,210201:4.3,210210:4.5,210211:2.2,210220:2,210221:1.1,211e3:7.5,211001:5.5,211010:5.8,211011:4.5,211020:4,211021:2.1,211100:6.1,211101:5.1,211110:4.8,211111:1.8,211120:2,211121:.9,211200:4.6,211201:1.8,211210:1.7,211211:.7,211220:.8,211221:.2,212001:5.3,212011:2.4,212021:1.4,212101:2.4,212111:1.2,212121:.5,212201:1,212211:.3,212221:.1,"000000":10,"000001":9.9,"000010":9.8,"000011":9.5,"000020":9.5,"000021":9.2,"000100":10,"000101":9.6,"000110":9.3,"000111":8.7,"000120":9.1,"000121":8.1,"000200":9.3,"000201":9,"000210":8.9,"000211":8,"000220":8.1,"000221":6.8,"001000":9.8,"001001":9.5,"001010":9.5,"001011":9.2,"001020":9,"001021":8.4,"001100":9.3,"001101":9.2,"001110":8.9,"001111":8.1,"001120":8.1,"001121":6.5,"001200":8.8,"001201":8,"001210":7.8,"001211":7,"001220":6.9,"001221":4.8,"002001":9.2,"002011":8.2,"002021":7.2,"002101":7.9,"002111":6.9,"002121":5,"002201":6.9,"002211":5.5,"002221":2.7,"010000":9.9,"010001":9.7,"010010":9.5,"010011":9.2,"010020":9.2,"010021":8.5,"010100":9.5,"010101":9.1,"010110":9,"010111":8.3,"010120":8.4,"010121":7.1,"010200":9.2,"010201":8.1,"010210":8.2,"010211":7.1,"010220":7.2,"010221":5.3,"011000":9.5,"011001":9.3,"011010":9.2,"011011":8.5,"011020":8.5,"011021":7.3,"011100":9.2,"011101":8.2,"011110":8,"011111":7.2,"011120":7,"011121":5.9,"011200":8.4,"011201":7,"011210":7.1,"011211":5.2,"011220":5,"011221":3,"012001":8.6,"012011":7.5,"012021":5.2,"012101":7.1,"012111":5.2,"012121":2.9,"012201":6.3,"012211":2.9,"012221":1.7},ke={eq1:{0:["AV:N/PR:N/UI:N/"],1:["AV:A/PR:N/UI:N/","AV:N/PR:L/UI:N/","AV:N/PR:N/UI:P/"],2:["AV:P/PR:N/UI:N/","AV:A/PR:L/UI:P/"]},eq2:{0:["AC:L/AT:N/"],1:["AC:H/AT:N/","AC:L/AT:P/"]},eq3:{0:{0:["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"],1:["VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/","VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/"]},1:{0:["VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/","VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/"],1:["VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/","VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/","VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/","VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/","VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"]},2:{1:["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"]}},eq4:{0:["SC:H/SI:S/SA:S/"],1:["SC:H/SI:H/SA:H/"],2:["SC:L/SI:L/SA:L/"]},eq5:{0:["E:A/"],1:["E:P/"],2:["E:U/"]}},tn={eq1:{0:1,1:4,2:5},eq2:{0:1,1:2},eq3eq6:{0:{0:7,1:6},1:{0:8,1:8},2:{1:10}},eq4:{0:6,1:5,2:4},eq5:{0:1,1:1,2:1}};var hn=["AV","AC","AT","PR","UI","VC","VI","VA","SC","SI","SA"],rn={N:0,A:.1,L:.2,P:.3},sn={N:0,L:.1,H:.2},on={N:0,P:.1,A:.2},an={L:0,H:.1},cn={N:0,P:.1},dn={H:0,L:.1,N:.2},fn={H:0,L:.1,N:.2},un={H:0,L:.1,N:.2},ln={H:.1,L:.2,N:.3},pn={S:0,H:.1,L:.2,N:.3},gn={S:0,H:.1,L:.2,N:.3},mn={H:0,M:.1,L:.2},yn={H:0,M:.1,L:.2},vn={H:0,M:.1,L:.2};function bn(e){let n=xt(e);if(!n)return null;let t=Vt(n);return Z[t]===void 0?null:Ot(n,t)}function xt(e){let n=e.split("/");if(n[0]!=="CVSS:4.0")return null;let t={};for(let s of n.slice(1)){let[r,a]=s.split(":");r&&a&&(t[r]=a)}for(let s of hn)if(!(s in t))return null;for(let s of["E","CR","IR","AR"])s in t||(t[s]="X");return t}function v(e,n){let t=e[n];if(n==="E"&&t==="X")return"A";if((n==="CR"||n==="IR"||n==="AR")&&t==="X")return"H";let s=e[`M${n}`];return s!==void 0&&s!=="X"?s:t??""}function Vt(e){let n=v(e,"AV"),t=v(e,"PR"),s=v(e,"UI"),r="2";n==="N"&&t==="N"&&s==="N"?r="0":(n==="N"||t==="N"||s==="N")&&n!=="P"&&(r="1");let a=v(e,"AC")==="L"&&v(e,"AT")==="N"?"0":"1",i=v(e,"VC"),o=v(e,"VI"),d=v(e,"VA"),c="2";i==="H"&&o==="H"?c="0":(i==="H"||o==="H"||d==="H")&&(c="1");let f=v(e,"MSI"),g=v(e,"MSA"),u="2";f==="S"||g==="S"?u="0":(v(e,"SC")==="H"||v(e,"SI")==="H"||v(e,"SA")==="H")&&(u="1");let l=v(e,"E"),m=l==="A"?"0":l==="P"?"1":"2",y=v(e,"CR"),p=v(e,"IR"),k=v(e,"AR");return`${r}${a}${c}${u}${m}${y==="H"&&i==="H"||p==="H"&&o==="H"||k==="H"&&d==="H"?"0":"1"}`}function h(e,n){return e[n]??0}function Q(e,n){return ke[`eq${n}`][e[n-1]]??[]}function V(e,n){let t=n.indexOf(e)+e.length+1,s=n.slice(t),r=s.indexOf("/");return r>0?s.substring(0,r):s}function Ot(e,n){if(hn.slice(5).every(b=>v(e,b)==="N"))return 0;let t=Z[n],s=Number(n[0]),r=Number(n[2]),a=Number(n[5]),i=b=>Z[b.join("")]??NaN,o=n.split("").map(Number),d=i([o[0]+1,o[1],o[2],o[3],o[4],o[5]]),c=i([o[0],o[1]+1,o[2],o[3],o[4],o[5]]),f;if(r===1&&a===1)f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);else if(r===0&&a===1)f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);else if(r===1&&a===0)f=i([o[0],o[1],o[2],o[3],o[4],o[5]+1]);else if(r===0&&a===0){let b=i([o[0],o[1],o[2],o[3],o[4],o[5]+1]),q=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]]);f=b>q?b:q}else f=i([o[0],o[1],o[2]+1,o[3],o[4],o[5]+1]);let g=i([o[0],o[1],o[2],o[3]+1,o[4],o[5]]),u=i([o[0],o[1],o[2],o[3],o[4]+1,o[5]]),l=Q(n,1),m=Q(n,2),y=ke.eq3[n[2]][n[5]],p=Q(n,4),k=Q(n,5),S=[];for(let b of l)for(let q of m)for(let ue of y)for(let zn of p)for(let Yn of k)S.push(b+q+ue+zn+Yn);let R=0,O=0,P=0,N=0,C=0,D=0,re=0,se=0,oe=0,ie=0,ae=0,ce=0,de=0,fe=0;for(let b of S)if(R=h(rn,v(e,"AV"))-h(rn,V("AV",b)),O=h(sn,v(e,"PR"))-h(sn,V("PR",b)),P=h(on,v(e,"UI"))-h(on,V("UI",b)),N=h(an,v(e,"AC"))-h(an,V("AC",b)),C=h(cn,v(e,"AT"))-h(cn,V("AT",b)),D=h(dn,v(e,"VC"))-h(dn,V("VC",b)),re=h(fn,v(e,"VI"))-h(fn,V("VI",b)),se=h(un,v(e,"VA"))-h(un,V("VA",b)),oe=h(ln,v(e,"SC"))-h(ln,V("SC",b)),ie=h(pn,v(e,"SI"))-h(pn,V("SI",b)),ae=h(gn,v(e,"SA"))-h(gn,V("SA",b)),ce=h(mn,v(e,"CR"))-h(mn,V("CR",b)),de=h(yn,v(e,"IR"))-h(yn,V("IR",b)),fe=h(vn,v(e,"AR"))-h(vn,V("AR",b)),![R,O,P,N,C,D,re,se,oe,ie,ae,ce,de,fe].some(ue=>ue<0))break;let _n=R+O+P,jn=N+C,Ln=D+re+se+ce+de+fe,qn=oe+ie+ae,Y=.1,Ie=t-d,He=t-c,_e=t-f,je=t-g,Fn=t-u,W=tn,Tn=W.eq1[String(s)]*Y,Kn=W.eq2[n[1]]*Y,Un=W.eq3eq6[String(r)][String(a)]*Y,Gn=W.eq4[n[3]]*Y,$=0,Le=0,qe=0,Fe=0,Te=0;Number.isNaN(Ie)||($++,Le=Ie*(_n/Tn)),Number.isNaN(He)||($++,qe=He*(jn/Kn)),Number.isNaN(_e)||($++,Fe=_e*(Ln/Un)),Number.isNaN(je)||($++,Te=je*(qn/Gn)),Number.isNaN(Fn)||$++;let Bn=$===0?0:(Le+qe+Fe+Te)/$;return t-=Bn,t<0&&(t=0),t>10&&(t=10),Math.round(t*10)/10}var Pt={N:.85,A:.62,L:.55,P:.2},$t={L:.77,H:.44},At={N:.85,R:.62},Mt={N:.85,L:.62,H:.27},Nt={N:.85,L:.68,H:.5},Se={H:.56,L:.22,N:0};function Re(e){return e<=0?"none":e<4?"low":e<7?"medium":e<9?"high":"critical"}function Sn(e){switch(e.trim().toUpperCase()){case"CRITICAL":return"critical";case"HIGH":return"high";case"MODERATE":case"MEDIUM":return"medium";case"LOW":return"low";case"NONE":return"none";default:return"unknown"}}function kn(e){let n=Math.round(e*1e5);return n%1e4===0?n/1e5:(Math.floor(n/1e4)+1)/10}function Rn(e){let n=e.split("/"),t=n[0]??"";if(t==="CVSS:4.0"){let p=bn(e);return p===null?null:{score:p,level:Re(p),version:t}}if(!/^CVSS:3\.[01]$/.test(t))return null;let s={};for(let p of n.slice(1)){let[k,S]=p.split(":");k&&S&&(s[k]=S)}let r=Pt[s.AV??""],a=$t[s.AC??""],i=At[s.UI??""],o=s.S==="C",d=(o?Nt:Mt)[s.PR??""],c=Se[s.C??""],f=Se[s.I??""],g=Se[s.A??""];if([r,a,i,d,c,f,g].some(p=>p===void 0))return null;let u=1-(1-c)*(1-f)*(1-g),l=o?7.52*(u-.029)-3.25*Math.pow(u-.02,15):6.42*u,m=8.22*r*a*d*i,y;return l<=0?y=0:o?y=kn(Math.min(1.08*(l+m),10)):y=kn(Math.min(l+m,10)),{score:y,level:Re(y),version:t}}function we(e){let n=[];for(let r of e.severity??[])r.score&&n.push(r.score);for(let r of e.affected??[])for(let a of r.severity??[])a.score&&n.push(a.score);let t=null;for(let r of n){let a=Rn(r);a&&(!t||a.score>t.score)&&(t=a)}if(t)return{level:t.level,score:t.score,vector:Ct(t,n),cvssVersion:t.version,source:"cvss"};let s=Dt(e);return s?{level:Sn(s),source:"database"}:{level:"unknown",source:"unknown"}}function Ct(e,n){return n.find(t=>t.startsWith(e.version))}function Dt(e){let n=s=>{let r=s?.severity;return typeof r=="string"?r:void 0},t=n(e.database_specific);if(t)return t;for(let s of e.affected??[]){let r=n(s.database_specific);if(r)return r}}function xe(e,n,t={}){let s=[];for(let r of Object.values(e.nodes)){if(r.unscannable||t.prodOnly&&r.scope==="dev")continue;let a=n(r.name);if(a.length===0)continue;let i=new Map,o=a.filter(c=>{let f=X(r.name,r.version,c);return i.set(c,f),f.affected});if(o.length===0)continue;let d=ye(e,r.key);for(let c of be(o)){if(Et(c,t.ignore))continue;let{fixedVersions:f}=i.get(c)??X(r.name,r.version,c),g=It(f),u=he(r.version,f);s.push({id:c.id,aliases:c.aliases??[],packageName:r.name,version:r.version,scope:r.scope,direct:r.direct,severity:we(c),summary:c.summary??c.id,details:c.details,references:(c.references??[]).map(l=>l.url),fixedVersions:g,recommendation:_t(r.name,r.direct,u,e.manager),dependencyPaths:d?[d]:[],source:"osv"})}}return s}function Et(e,n){return!n||n.size===0?!1:n.has(e.id)?!0:(e.aliases??[]).some(t=>n.has(t))}function It(e){return[...new Set(e)].sort((n,t)=>{let s=wn.parse(n,{loose:!0}),r=wn.parse(t,{loose:!0});return s&&r?s.compare(r):n.localeCompare(t)})}var Ht={npm:"npm install",yarn:"yarn add",pnpm:"pnpm add"};function _t(e,n,t,s){return t?n?`Upgrade to ${e}@${t} or later (e.g. \`${Ht[s]} ${e}@${t}\`).`:`Update the dependency that pulls in ${e} so it resolves to ${e}@${t} or later. If it cannot, force the resolution via an override.`:n?"No fixed version is available yet. Watch the advisory, or evaluate an alternative package.":"No fixed version is available yet. Pressure the parent dependency to update, or override the version."}var Ve=class{byName=new Map;ids=new Set;add(n){if(n.withdrawn||this.ids.has(n.id))return;this.ids.add(n.id);let t=new Set;for(let s of n.affected??[]){let r=s.package?.ecosystem;r&&r!=="npm"||s.package?.name&&t.add(s.package.name)}for(let s of t){let r=this.byName.get(s);r?r.push(n):this.byName.set(s,[n])}}addAll(n){for(let t of n)this.add(t)}vulnerabilitiesFor(n){return this.byName.get(n)??[]}get size(){return this.ids.size}};import{resolve as lr}from"path";import{join as Oe}from"path";import jt from"env-paths";function Pe(e){return e||(process.env.LOCKHAWK_CACHE?process.env.LOCKHAWK_CACHE:jt("lockhawk",{suffix:""}).cache)}function T(e){return Oe(e,"osv-db","npm")}var xn=4096;function ee(e){let n=2166136261;for(let t=0;t<e.length;t++)n^=e.charCodeAt(t),n=Math.imul(n,16777619);return(n>>>0)%xn}function K(e){return Oe(T(e),"meta.json")}function $e(e,n){return Oe(e,"query-cache",`${encodeURIComponent(n)}.json`)}import{mkdir as Lt,readFile as qt,writeFile as Ft}from"fs/promises";import{dirname as Tt}from"path";import Kt from"p-limit";import Ut,{AbortError as Gt}from"p-retry";var Ae="https://api.osv.dev/v1",Vn=1e3,U=class{constructor(n){this.opts=n;this.limit=Kt(n.concurrency??16)}opts;limit;async fetchAdvisories(n){let t=[...new Set(n.map(o=>o.name))],s=await this.queryBatch(t),r=new Set;for(let o of s.values())for(let d of o)r.add(d);let a=await this.hydrate([...r]),i=new Map;for(let[o,d]of s){let c=[];for(let f of d){let g=a.get(f);g&&c.push(g)}c.length&&i.set(o,c)}return i}async queryBatch(n){let t=new Map;for(let s=0;s<n.length;s+=Vn){let r=n.slice(s,s+Vn),a={queries:r.map(o=>({package:{name:o,ecosystem:"npm"}}))},i=await this.request(`${Ae}/querybatch`,a);for(let o=0;o<r.length;o++){let d=r[o],c=i.results[o];if(!c)continue;let f=t.get(d)??new Set;for(let u of c.vulns??[])f.add(u.id);let g=c.next_page_token;for(;g;){let u=await this.request(`${Ae}/query`,{package:{name:d,ecosystem:"npm"},page_token:g});for(let l of u.vulns??[])f.add(l.id);g=u.next_page_token}f.size&&t.set(d,f)}}return t}async hydrate(n){let t=new Map;return await Promise.all(n.map(s=>this.limit(async()=>{let r=await this.getVulnerability(s);r&&t.set(s,r)}))),t}async getVulnerability(n){let t=await this.readCache(n);if(t)return t;let s=await this.request(`${Ae}/vulns/${encodeURIComponent(n)}`);return await this.writeCache(n,s),s}async request(n,t){let s=this.opts.retries??3;return Ut(async()=>{let r=await fetch(n,{method:t?"POST":"GET",headers:t?{"content-type":"application/json"}:void 0,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(this.opts.timeoutMs??15e3)});if(r.ok)return await r.json();throw r.status===429||r.status>=500?new Error(`OSV ${r.status} for ${n}`):new Gt(`OSV ${r.status} for ${n}`)},{retries:s})}async readCache(n){if(!this.opts.noCache)try{let t=JSON.parse(await qt($e(this.opts.cacheDir,n),"utf8")),s=(this.opts.cacheTtlHours??24)*36e5;return Date.now()-t.fetchedAt>s?void 0:t.vuln}catch{return}}async writeCache(n,t){if(!this.opts.noCache)try{let s=$e(this.opts.cacheDir,n);await Lt(Tt(s),{recursive:!0}),await Ft(s,JSON.stringify({fetchedAt:Date.now(),vuln:t}))}catch{}}};import{createWriteStream as Bt}from"fs";import{mkdir as On,mkdtemp as zt,readFile as Pn,rm as $n,writeFile as Me}from"fs/promises";import{tmpdir as Yt}from"os";import{join as ne}from"path";import{Readable as Wt}from"stream";import{pipeline as Jt}from"stream/promises";import{gunzipSync as Xt,gzipSync as Zt}from"zlib";import Qt from"p-limit";import er from"yauzl";var nr="https://storage.googleapis.com/osv-vulnerabilities/npm/all.zip",tr=32,rr=8*1024*1024,H=class extends Error{constructor(){super("No offline OSV database found. Run `lockhawk db update` first."),this.name="OfflineDbMissingError"}},sr=/^[A-Za-z]{3}, \d{2} [A-Za-z]{3} \d{4} \d{2}:\d{2}:\d{2} GMT$/,or=/^(?:W\/)?"[\x21\x23-\x7e]*"$/;function ir(e){return e&&sr.test(e)?e:void 0}function ar(e){return e&&or.test(e)?e:void 0}async function _(e){try{return JSON.parse(await Pn(K(e),"utf8"))}catch{return}}async function cr(e){let{cacheDir:n,nowIso:t,force:s,onProgress:r}=e,a=T(n);await On(a,{recursive:!0});let i=s?void 0:await _(n),o={},d=ar(i?.etag),c=ir(i?.lastModified);d&&(o["If-None-Match"]=d),c&&(o["If-Modified-Since"]=c),r?.("Fetching npm advisory database from OSV.dev\u2026");let f=await fetch(nr,{headers:o});if(f.status===304&&i){let p={...i,lastUpdated:t};return await Me(K(n),JSON.stringify(p,null,2)),{status:"unchanged",meta:p}}if(!f.ok||!f.body)throw new Error(`OSV database download failed: HTTP ${f.status}`);let g=await zt(ne(Yt(),"lockhawk-osv-")),u=ne(g,"all.zip"),l;try{await Jt(Wt.fromWeb(f.body),Bt(u)),r?.("Extracting advisories\u2026"),l=await ur(u)}finally{await $n(g,{recursive:!0,force:!0})}r?.("Building package index\u2026");let m=dr(l);await fr(n,m);let y={ecosystem:"npm",source:"osv.dev",lastUpdated:t,recordCount:l.length,packageCount:m.size,etag:f.headers.get("etag")??void 0,lastModified:f.headers.get("last-modified")??void 0};return await Me(K(n),JSON.stringify(y,null,2)),{status:"updated",meta:y}}function An(e){return ne(T(e),"by-name")}function Mn(e,n){return ne(An(e),`${n}.json.gz`)}async function Ne(e,n){if(!await _(e))throw new H;let t=new Map;for(let a of new Set(n)){let i=ee(a),o=t.get(i);o?o.push(a):t.set(i,[a])}let s=new Map,r=Qt(tr);return await Promise.all([...t.entries()].map(([a,i])=>r(async()=>{try{let o=JSON.parse(Xt(await Pn(Mn(e,a))).toString("utf8"));for(let d of i){let c=o[d];c?.length&&s.set(d,c)}}catch{}}))),s}function dr(e){let n=new Map;for(let t of e){if(t.withdrawn)continue;let s=new Set;for(let r of t.affected??[]){let a=r.package?.ecosystem;a&&a!=="npm"||r.package?.name&&s.add(r.package.name)}for(let r of s){let a=n.get(r);a?a.push(t):n.set(r,[t])}}return n}async function fr(e,n){let t=An(e);await $n(t,{recursive:!0,force:!0}),await On(t,{recursive:!0});let s=new Map;for(let[i,o]of n){let d=ee(i),c=s.get(d)??{};c[i]=o,s.set(d,c)}let r=[...s.entries()],a=256;for(let i=0;i<r.length;i+=a)await Promise.all(r.slice(i,i+a).map(([o,d])=>Me(Mn(e,o),Zt(Buffer.from(JSON.stringify(d))))))}function ur(e){return new Promise((n,t)=>{let s=[];er.open(e,{lazyEntries:!0},(r,a)=>{if(r||!a)return t(r??new Error("Failed to open OSV zip"));a.on("entry",i=>{if(!i.fileName.endsWith(".json")||i.uncompressedSize>rr)return a.readEntry();a.openReadStream(i,(o,d)=>{if(o||!d)return a.readEntry();let c=[];d.on("data",f=>c.push(f)),d.on("error",()=>a.readEntry()),d.on("end",()=>{try{s.push(JSON.parse(Buffer.concat(c).toString("utf8")))}catch{}a.readEntry()})})}),a.on("end",()=>n(s)),a.on("error",t),a.readEntry()})})}var Nn=36e5,j=class{constructor(n){this.opts=n}opts;async prepare(n){let t=await _(this.opts.cacheDir);if(!t)throw new H;let s=await Ne(this.opts.cacheDir,n.map(o=>o.name)),r=(Date.now()-Date.parse(t.lastUpdated))/Nn,a=r>(this.opts.staleAfterHours??24),i=a?[`Offline database is ${Math.round(r)}h old. Run \`lockhawk db update\` for current results.`]:[];return{candidatesFor:o=>s.get(o)??[],database:{source:"offline",recordCount:t.recordCount,lastUpdated:t.lastUpdated,ageHours:Math.round(r*10)/10,stale:a,warnings:i}}}},G=class{constructor(n){this.opts=n}opts;async prepare(n){let t=new U({cacheDir:this.opts.cacheDir,concurrency:this.opts.concurrency,noCache:this.opts.noCache,cacheTtlHours:this.opts.cacheTtlHours});try{let s=await t.fetchAdvisories(n);return{candidatesFor:r=>s.get(r)??[],database:{source:"online",stale:!1,warnings:[]}}}catch(s){if(this.opts.strictNetwork)throw s;let r=s instanceof Error?s.message:String(s);return{candidatesFor:()=>[],database:{source:"online",stale:!0,warnings:[`OSV.dev was unreachable (${r}). Scan completed without online data \u2014 results may be incomplete.`]}}}}},te=class{constructor(n){this.opts=n}opts;async prepare(n){let t=await _(this.opts.cacheDir),s=this.opts.staleAfterHours??24;if(t&&(Date.now()-Date.parse(t.lastUpdated))/Nn<=s)return new j(this.opts).prepare(n);try{return await new G({...this.opts,strictNetwork:!0}).prepare(n)}catch(r){if(t){let i=await new j(this.opts).prepare(n);return i.database.warnings.push("Used the stale offline database because OSV.dev was unreachable."),i}if(this.opts.strictNetwork)throw r;let a=r instanceof Error?r.message:String(r);return{candidatesFor:()=>[],database:{source:"online",stale:!0,warnings:[`No offline database and OSV.dev was unreachable (${a}). Run \`lockhawk db update\`.`]}}}}};function Ce(e,n){switch(e){case"offline":return new j(n);case"online":return new G(n);default:return new te(n)}}var Cn={name:"lockhawk",version:"0.1.0"};async function pr(e={},n){let t=Date.now(),s=lr(e.path??"."),r=ge(s),a=F(s),i=Dn(r,e.prodOnly),o=Pe(e.cacheDir),d=n??Ce(e.mode??"auto",{cacheDir:o,concurrency:e.concurrency,noCache:e.noCache,cacheTtlHours:e.cacheTtlHours,strictNetwork:e.strictNetwork});e.onProgress?.("Checking dependencies against OSV.dev\u2026");let c=await d.prepare(i),f=xe(r,c.candidatesFor,{prodOnly:e.prodOnly,ignore:e.ignore&&e.ignore.length?new Set(e.ignore):void 0});e.severityThreshold&&e.severityThreshold!=="none"&&(f=f.filter(u=>Ke(u.severity.level,e.severityThreshold))),f.sort(yr);let g=gr(r);return{schemaVersion:1,tool:{...Cn},scannedAt:new Date(t).toISOString(),target:{path:s,manager:r.manager,lockfile:a?.filename??"",root:r.root},database:c.database,summary:mr(f),stats:{totalPackages:Object.keys(r.nodes).length,uniquePackages:i.length,directDependencies:r.directKeys.length,unscannable:g.length,durationMs:Date.now()-t},findings:f,unscannable:g}}function Dn(e,n){let t=new Set,s=[];for(let r of Object.values(e.nodes))r.unscannable||n&&r.scope==="dev"||t.has(r.key)||(t.add(r.key),s.push({name:r.name,version:r.version}));return s}function gr(e){let n=[];for(let t of Object.values(e.nodes))t.unscannable&&n.push({name:t.name,version:t.version,reason:t.unscannable.reason});return n}function mr(e){let n={total:e.length,critical:0,high:0,medium:0,low:0,unknown:0,none:0,vulnerablePackages:0,fixable:0},t=new Set;for(let s of e)n[s.severity.level]+=1,t.add(`${s.packageName}@${s.version}`),s.fixedVersions.length>0&&(n.fixable+=1);return n.vulnerablePackages=t.size,n}function yr(e,n){let t=A[n.severity.level]-A[e.severity.level];return t!==0?t:e.packageName.localeCompare(n.packageName)}function vr(e,n){return["critical","high","medium","low","unknown"].some(s=>A[s]>=A[n]&&e[s]>0)}function hr(e){return JSON.stringify(e,null,2)}var br="https://github.com/lockhawk/lockhawk";function kr(e){return e.find(n=>{try{let t=new URL(n);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}})}function Sr(e){if(typeof e.severity.score=="number")return e.severity.score;switch(e.severity.level){case"critical":return 9.5;case"high":return 7.5;case"medium":return 5;case"low":return 2;default:return 0}}function Rr(e){return e==="critical"||e==="high"?"error":e==="medium"?"warning":"note"}function En(e){let n=e.target.lockfile||"package-lock.json",t=new Map,s=[];for(let r of e.findings){t.has(r.id)||t.set(r.id,{id:r.id,name:`${r.packageName} ${r.id}`,shortDescription:{text:r.summary},fullDescription:r.details?{text:r.details}:void 0,helpUri:kr(r.references),properties:{"security-severity":String(Sr(r)),tags:["security","dependency",r.severity.level]}});let a=r.dependencyPaths[0]?.join(" \u203A ")??r.packageName,i=r.fixedVersions[0]?` Fixed in ${r.fixedVersions[0]}.`:"";s.push({ruleId:r.id,level:Rr(r.severity.level),message:{text:`${r.severity.level.toUpperCase()}: ${r.packageName}@${r.version} \u2014 ${r.summary}.${i} Path: ${a}.`},locations:[{physicalLocation:{artifactLocation:{uri:n},region:{startLine:1}}}],partialFingerprints:{lockhawkFinding:`${r.packageName}@${r.version}@${r.id}`},properties:{package:r.packageName,version:r.version,scope:r.scope,fixedVersions:r.fixedVersions}})}return{$schema:"https://json.schemastore.org/sarif-2.1.0.json",version:"2.1.0",runs:[{tool:{driver:{name:e.tool.name,version:e.tool.version,informationUri:br,rules:[...t.values()]}},results:s,properties:{scannedAt:e.scannedAt,databaseSource:e.database.source,databaseAgeHours:e.database.ageHours,databaseStale:e.database.stale}}]}}function wr(e){return JSON.stringify(En(e),null,2)}var De="<!--LOCKHAWK_DATA-->";function xr(e){return`<script>window.__SCAN_RESULT__ = ${JSON.stringify(e).replace(/</g,"\\u003c").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")};</script>`}function Vr(e,n){let t=xr(e);return n?n.includes(De)?n.replace(De,()=>t):n.replace("</head>",()=>`${t}</head>`):Pr(e,t)}var In={critical:"#b4232c",high:"#d9822b",medium:"#c9a227",low:"#3a7bd5",unknown:"#7a7a7a",none:"#3a9e54"};function w(e){return e.replace(/[&<>"]/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[n])}function Or(e){try{let n=new URL(e);return n.protocol==="http:"||n.protocol==="https:"?e:void 0}catch{return}}function Pr(e,n){let{summary:t}=e,s=["critical","high","medium","low","unknown"].map(i=>`
2
+ <div class="card" style="border-top:4px solid ${In[i]}">
3
3
  <div class="count">${t[i]}</div><div class="label">${i}</div>
4
- </div>`).join(""),r=e.findings.map(i=>{let o=i.dependencyPaths[0]?.join(" \u203A ")??i.packageName,d=i.references.slice(0,3).map(c=>Sr(c)).filter(c=>c!==void 0).map(c=>`<a href="${x(c)}" target="_blank" rel="noopener">link</a>`).join(" ");return`
4
+ </div>`).join(""),r=e.findings.map(i=>{let o=i.dependencyPaths[0]?.join(" \u203A ")??i.packageName,d=i.references.slice(0,3).map(c=>Or(c)).filter(c=>c!==void 0).map(c=>`<a href="${w(c)}" target="_blank" rel="noopener">link</a>`).join(" ");return`
5
5
  <tr>
6
- <td><span class="pill" style="background:${Dn[i.severity.level]}">${i.severity.level}${i.severity.score?` ${i.severity.score}`:""}</span></td>
7
- <td><code>${x(i.packageName)}@${x(i.version)}</code><div class="scope">${i.scope}${i.direct?" \xB7 direct":""}</div></td>
8
- <td><a href="https://osv.dev/${x(i.id)}" target="_blank" rel="noopener">${x(i.id)}</a></td>
9
- <td>${x(i.summary)}<div class="path">${x(o)}</div></td>
10
- <td>${i.fixedVersions[0]?x(i.fixedVersions[0]):"\u2014"}</td>
6
+ <td><span class="pill" style="background:${In[i.severity.level]}">${i.severity.level}${i.severity.score?` ${i.severity.score}`:""}</span></td>
7
+ <td><code>${w(i.packageName)}@${w(i.version)}</code><div class="scope">${i.scope}${i.direct?" \xB7 direct":""}</div></td>
8
+ <td><a href="https://osv.dev/${w(i.id)}" target="_blank" rel="noopener">${w(i.id)}</a></td>
9
+ <td>${w(i.summary)}<div class="path">${w(o)}</div></td>
10
+ <td>${i.fixedVersions[0]?w(i.fixedVersions[0]):"\u2014"}</td>
11
11
  <td>${d}</td>
12
- </tr>`}).join(""),a=e.database.warnings.map(i=>`<div class="warn">\u26A0 ${x(i)}</div>`).join("");return`<!doctype html>
12
+ </tr>`}).join(""),a=e.database.warnings.map(i=>`<div class="warn">\u26A0 ${w(i)}</div>`).join("");return`<!doctype html>
13
13
  <html lang="en">
14
14
  <head>
15
15
  <meta charset="utf-8">
16
16
  <meta name="viewport" content="width=device-width, initial-scale=1">
17
- <title>lockhawk report \u2014 ${x(e.target.root.name)}</title>
17
+ <title>lockhawk report \u2014 ${w(e.target.root.name)}</title>
18
18
  ${n}
19
19
  <style>
20
20
  :root { color-scheme: light dark; }
@@ -43,7 +43,7 @@ ${n}
43
43
  <body>
44
44
  <header>
45
45
  <h1>lockhawk report</h1>
46
- <div class="meta">${x(e.target.root.name)}${e.target.root.version?`@${x(e.target.root.version)}`:""} \xB7 ${x(e.target.manager)} \xB7 ${e.stats.totalPackages} packages \xB7 scanned ${x(e.scannedAt)}</div>
46
+ <div class="meta">${w(e.target.root.name)}${e.target.root.version?`@${w(e.target.root.version)}`:""} \xB7 ${w(e.target.manager)} \xB7 ${e.stats.totalPackages} packages \xB7 scanned ${w(e.scannedAt)}</div>
47
47
  </header>
48
48
  <main>
49
49
  <div class="cards">${s}</div>
@@ -53,12 +53,16 @@ ${n}
53
53
  <tbody>${r}</tbody>
54
54
  </table>`}
55
55
  </main>
56
- <footer>Generated by lockhawk v${x(e.tool.version)} \xB7 data from OSV.dev \xB7 database: ${x(e.database.source)}</footer>
56
+ <footer>Generated by lockhawk v${w(e.tool.version)} \xB7 data from OSV.dev \xB7 database: ${w(e.database.source)}</footer>
57
57
  </body>
58
- </html>`}function _(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"})[n])}function wr(e){return[`Package: ${e.packageName}@${e.version} (${e.scope}${e.direct?", direct":", transitive"})`,`Severity: ${e.severity.level}${e.severity.score!==void 0?`, CVSS ${e.severity.score}`:""}${e.severity.vector?` (${e.severity.vector})`:""}`,e.fixedVersions.length?`Fixed in: ${e.fixedVersions.join(", ")}`:"Fix: none available yet",e.dependencyPaths[0]?`Dependency path: ${e.dependencyPaths[0].join(" > ")}`:"",e.recommendation?`Recommendation: ${e.recommendation}`:"",e.references.length?`References:
58
+ </html>`}function L(e){return e.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"})[n])}function $r(e){return[`Package: ${e.packageName}@${e.version} (${e.scope}${e.direct?", direct":", transitive"})`,`Severity: ${e.severity.level}${e.severity.score!==void 0?`, CVSS ${e.severity.score}`:""}${e.severity.vector?` (${e.severity.vector})`:""}`,e.fixedVersions.length?`Fixed in: ${e.fixedVersions.join(", ")}`:"Fix: none available yet",e.dependencyPaths[0]?`Dependency path: ${e.dependencyPaths[0].join(" > ")}`:"",e.recommendation?`Recommendation: ${e.recommendation}`:"",e.references.length?`References:
59
59
  ${e.references.join(`
60
60
  `)}`:""].filter(Boolean).join(`
61
- `)}function Vr(e){let{findings:n}=e,t=n.length,s=n.length===0?1:n.length,r=((e.stats.durationMs??0)/1e3).toFixed(3),a=`${e.target.root.name} npm dependency vulnerabilities`,i=n.length===0?[' <testcase name="No known vulnerabilities" classname="lockhawk" time="0" />']:n.map(o=>{let d=`${o.packageName}@${o.version}: ${o.id} (${o.severity.level})`,c=`${o.severity.level.toUpperCase()}${o.severity.score!==void 0?` ${o.severity.score}`:""} ${o.id}: ${o.summary}`;return[` <testcase name="${_(d)}" classname="lockhawk.${_(o.severity.level)}" time="0">`,` <failure message="${_(c)}" type="${_(o.severity.level)}">${_(wr(o))}</failure>`," </testcase>"].join(`
62
- `)});return['<?xml version="1.0" encoding="UTF-8"?>',`<testsuites name="lockhawk" tests="${s}" failures="${t}" errors="0" time="${r}">`,` <testsuite name="${_(a)}" tests="${s}" failures="${t}" errors="0" time="${r}">`,...i," </testsuite>","</testsuites>",""].join(`
63
- `)}export{ee as AutoSource,Ce as DATA_MARKER,E as LockfileError,H as OfflineDbMissingError,j as OfflineSource,G as OnlineSource,U as OsvClient,xe as OsvDatabase,N as SEVERITY_RANK,Rn as SHARD_BUCKETS,Nn as TOOL,ue as buildDependencyGraph,Se as buildFindings,Ze as canonicalId,Me as createSource,ve as dedupeVulnerabilities,F as detectLockfile,Je as isVersionAffected,hn as levelFromLabel,ke as levelFromScore,Ne as loadAdvisoriesForPackages,le as loadDependencyGraph,ye as nearestFix,T as offlineDbDir,K as offlineMetaPath,We as parseLockfile,w as pkgKey,L as readOfflineMeta,M as readRootManifest,Ve as resolveCacheDir,Re as resolveSeverity,pe as rootLabel,dr as scan,bn as scoreFromVector,qe as severityAtLeast,Z as shardBucket,ge as shortestPath,pr as shouldFail,Rr as toHtml,gr as toJson,Vr as toJunit,Cn as toSarif,br as toSarifString,Mn as uniqueScannablePackages,sr as updateOfflineDatabase,W as vulnerabilityAffects};
61
+ `)}function Ar(e){let{findings:n}=e,t=n.length,s=n.length===0?1:n.length,r=((e.stats.durationMs??0)/1e3).toFixed(3),a=`${e.target.root.name} npm dependency vulnerabilities`,i=n.length===0?[' <testcase name="No known vulnerabilities" classname="lockhawk" time="0" />']:n.map(o=>{let d=`${o.packageName}@${o.version}: ${o.id} (${o.severity.level})`,c=`${o.severity.level.toUpperCase()}${o.severity.score!==void 0?` ${o.severity.score}`:""} ${o.id}: ${o.summary}`;return[` <testcase name="${L(d)}" classname="lockhawk.${L(o.severity.level)}" time="0">`,` <failure message="${L(c)}" type="${L(o.severity.level)}">${L($r(o))}</failure>`," </testcase>"].join(`
62
+ `)});return['<?xml version="1.0" encoding="UTF-8"?>',`<testsuites name="lockhawk" tests="${s}" failures="${t}" errors="0" time="${r}">`,` <testsuite name="${L(a)}" tests="${s}" failures="${t}" errors="0" time="${r}">`,...i," </testsuite>","</testsuites>",""].join(`
63
+ `)}var B={critical:"\u{1F534}",high:"\u{1F7E0}",medium:"\u{1F7E1}",low:"\u26AA",unknown:"\u26AB",none:"\u{1F7E2}"},Ee=100,Mr=100;function z(e){return e.replace(/\r?\n/g," ").replace(/\\/g,"\\\\").replace(/\|/g,"\\|").replace(/`/g,"\\`").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function Nr(e,n){return e.length>n?`${e.slice(0,n-1)}\u2026`:e}function Hn(e){return`_lockhawk ${e.tool.version} \xB7 data: OSV.dev (${e.database.source}) \xB7 scanned ${e.scannedAt}_`}function Cr(e){let{summary:n,findings:t}=e,s=[],r=n.total===1?"vulnerability":"vulnerabilities";if(s.push(`## \u{1F6E1}\uFE0F lockhawk \u2014 ${n.total} ${r}`,""),t.length===0)return s.push("\u2713 No known vulnerabilities found.","",Hn(e)),`${s.join(`
64
+ `)}
65
+ `;s.push(`${B.critical} ${n.critical} critical \xB7 ${B.high} ${n.high} high \xB7 ${B.medium} ${n.medium} medium \xB7 ${B.low} ${n.low} low \xB7 ${n.vulnerablePackages} packages \xB7 ${n.fixable} fixable`,"");let a=e.database.warnings;if(e.database.stale||a.length){for(let i of a)s.push(`> \u26A0\uFE0F ${z(i)}`);e.database.stale&&a.length===0&&s.push("> \u26A0\uFE0F The offline advisory database is stale."),s.push("")}s.push("| Severity | Package | Advisory | Fixed in | Summary |","|---|---|---|---|---|");for(let i of t.slice(0,Ee)){let o=i.severity.score!==void 0?` ${i.severity.score}`:"",d=`${B[i.severity.level]} ${i.severity.level}${o}`,c=`\`${z(`${i.packageName}@${i.version}`)}\`${i.direct?" (direct)":""}`,f=`[${z(i.id)}](https://osv.dev/${encodeURIComponent(i.id)})`,g=i.fixedVersions[0]?z(i.fixedVersions[0]):"none",u=z(Nr(i.summary,Mr));s.push(`| ${d} | ${c} | ${f} | ${g} | ${u} |`)}return t.length>Ee&&s.push("",`_\u2026and ${t.length-Ee} more \u2014 see the downloadable report._`),s.push("",Hn(e)),`${s.join(`
66
+ `)}
67
+ `}export{te as AutoSource,De as DATA_MARKER,E as LockfileError,H as OfflineDbMissingError,j as OfflineSource,G as OnlineSource,U as OsvClient,Ve as OsvDatabase,A as SEVERITY_RANK,xn as SHARD_BUCKETS,Cn as TOOL,pe as buildDependencyGraph,xe as buildFindings,nn as canonicalId,Ce as createSource,be as dedupeVulnerabilities,F as detectLockfile,Qe as isVersionAffected,Sn as levelFromLabel,Re as levelFromScore,Ne as loadAdvisoriesForPackages,ge as loadDependencyGraph,he as nearestFix,T as offlineDbDir,K as offlineMetaPath,Ze as parseLockfile,x as pkgKey,_ as readOfflineMeta,M as readRootManifest,Pe as resolveCacheDir,we as resolveSeverity,me as rootLabel,pr as scan,Rn as scoreFromVector,Ke as severityAtLeast,ee as shardBucket,ye as shortestPath,vr as shouldFail,Vr as toHtml,hr as toJson,Ar as toJunit,Cr as toMarkdown,En as toSarif,wr as toSarifString,Dn as uniqueScannablePackages,cr as updateOfflineDatabase,X as vulnerabilityAffects};
64
68
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lockhawk/core",
3
- "version": "0.2.10",
3
+ "version": "0.2.12-alpha.0",
4
4
  "description": "Scanning engine for lockhawk: lockfile parsing, OSV.dev vulnerability matching, CVSS v3/v4 scoring, and SARIF/JUnit/HTML reports",
5
5
  "license": "MIT",
6
6
  "type": "module",