@conterra/vuln-scan 1.0.11 → 1.0.13
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 +53 -6
- package/dist/add-project-to-vex.js +2 -2
- package/dist/add-project.js +15 -15
- package/dist/add-statement.js +19 -19
- package/dist/auto-vex-creator.js +4 -4
- package/dist/jira-reporter.js +7 -7
- package/dist/remove-project.js +16 -16
- package/dist/schema/auto-vex-config.schema.json +26 -0
- package/dist/vuln-scan.js +12 -12
- package/package.json +8 -8
package/dist/add-statement.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
`,n=await sr(t,r);await(0,N.writeFile)(t,n,{encoding:"utf-8"})}async function or(t){try{return await(0,N.access)(t,N.constants.F_OK),!0}catch{return!1}}async function sr(t,e){let r=await lr();if(!r)return e;let n=await r.resolveConfig(t);return n?await r.format(e,{...n,filepath:t}):e}var ar;function lr(){return ar??=import("prettier").catch(()=>{})}var oe=["UNKNOWN","LOW","MEDIUM","HIGH","CRITICAL"];var Be=class t{constructor(e){this.workingDir=e}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(e,r){let n=e.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:r,onNewVulnerabilities:e.onNewVulnerabilities??(e.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:e.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:e.reportNoLongerDetectedVulnerabilities??!0,consoleReport:e.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:e.createSubDirsForProject??!0,mavenRepo:e.mavenRepo??t.DEFAULT_MAVEN_REPO,vexUrls:e.vexUrls??[],vexDir:this.resolvePath(e.vexDir)??(0,G.resolve)(this.workingDir,t.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(e.outDir)??(0,G.resolve)(this.workingDir,t.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(e.cacheDir)??(0,G.resolve)(this.workingDir,t.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(e.scanners,r),projects:this.normalizeProjects(e.projects??[],n)}}normalizeScanners(e,r){return(e??t.DEFAULT_SCANNERS).map(i=>{if(typeof i!="string")throw new Error(`Invalid scanner name '${String(i)}' in configuration file '${r}'`);let o=i.split("@");if(o.length>2)throw new Error(`Invalid scanner name '${i}' in configuration file '${r}'`);return{name:o[0],version:o[1]??""}})}normalizeProjects(e,r){return e.map(n=>{let i=n;if(!i.name)throw new Error("Project name is missing on entry: "+JSON.stringify(i));if(!i.version)throw new Error("Project version is missing on entry: "+JSON.stringify(i));if(!i.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(i));let o={...i,purlAliases:i.purlAliases??[],enabled:i.enabled??!0,silent:i.silent??!1,minimumSeverity:i.minimumSeverity??"UNKNOWN"};return o.sbomFile?{...o,sbomFile:this.resolvePath(o.sbomFile)??o.sbomFile}:{...o,detectNoLongerUsedVulnerabilities:r?o.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(e){if(e)return G.default.isAbsolute(e)?e:(0,G.resolve)(this.workingDir,e)}},he=class{constructor(e){this.workingDir=e;this.normalizer=new Be(e)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let e=(0,G.resolve)(this.workingDir,"vuln-scan-conf.json"),r=await me(e);if(!r)throw new Error(`Missing project configuration file '${e}'`);return this.normalizer.normalize(r,e)}async loadJiraConfig(e){let r=await(0,_e.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.issues&&n.issue&&(n.issues=n.issue),!n.jiraUrl||typeof n.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(n.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(n.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[i,o]of n.issues.entries())o&&typeof o=="object"&&this.validateAutoCloseSeverity(o.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${i}].autoCloseBelowSeverity'`);return n}validateAutoCloseSeverity(e,r){if(e!==void 0&&!oe.includes(e))throw new Error(`${r} value '${String(e)}'. Must be one of: ${oe.join(", ")}`)}async loadAutoVexConfig(e){let r=await(0,_e.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.impactStatement||typeof n.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(n.maxSeverity!==void 0&&!oe.includes(n.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(n.maxSeverity)}'. Must be one of: ${oe.join(", ")}`);return n}};var Qt=require("path");var ot=require("crypto");function st(t){let{cveName:e,purls:r,status:n,impactStatement:i,actionStatement:o,statusNotes:a,justification:s,timestamp:p=new Date().toISOString()}=t,u={vulnerability:{name:e},timestamp:p,products:r.map(h=>({"@id":h})),status:n};return i&&(u.impact_statement=i),o&&(u.action_statement=o),a&&(u.status_notes=a),s&&(u.justification=s),u}var cr="https://openvex.dev/ns/v0.2.0";function at(t,e="conterra"){let n=`https://openvex.dev/docs/public/vex-${(0,ot.randomUUID)()}`,i=t.timestamp??new Date().toISOString();return{"@context":cr,"@id":n,author:e,timestamp:i,last_updated:i,version:1,statements:[t]}}function lt(t,e){let r=e.timestamp??new Date().toISOString();return{...t,last_updated:r,version:t.version+1,statements:[...t.statements,e]}}var ge=require("fs/promises"),Se=require("path");function ct(t){let e=t.vulnerability.name;return new Set([e,...t.vulnerability.aliases??[]])}var se=class{constructor(e){this.location=e}location;_content=void 0;_exists=!1;get exists(){return this._exists}get content(){return this._content}set content(e){this._content=e,this._exists=e!==void 0}async read(){let e=await me(this.location);this._content=e??void 0,this._exists=this._content!==void 0}async write(){if(this._content===void 0)throw new Error(`Cannot write VexFile: content is undefined (${this.location})`);await(0,ge.mkdir)((0,Se.dirname)((0,Se.resolve)(this.location)),{recursive:!0}),await it(this.location,this._content)}async delete(){await(0,ge.unlink)(this.location),this._exists=!1}upsert(e,r){return this._content===void 0?(this._content=at(e,r),this._exists=!0,{created:!0}):(this._content=lt(this._content,e),{created:!1})}addProductId(e,r){this.assertContentLoaded("addProductId");let n=!1;for(let i of this._content.statements){if(!i.products||i.products.some(a=>a["@id"]===r))continue;let o=i.products.findIndex(a=>a["@id"]===e);o!==-1&&(i.products.splice(o+1,0,{"@id":r}),n=!0)}return n}removeProductId(e,r){this.assertContentLoaded("removeProductId");let n=this._content.statements,i=[],o=!1;for(let a of n){if(r&&!ct(a).has(r)||!a.products)continue;let s=a.products.findIndex(p=>p["@id"]===e);s!==-1&&(a.products.splice(s,1),o=!0,a.products.length===0&&i.push(a))}if(!o)return"unchanged";for(let a of i)n.splice(n.indexOf(a),1);return n.length===0?"emptied":"changed"}hasStatementForProduct(e){return this.assertContentLoaded("hasStatementForProduct"),this._content.statements.some(r=>r.products?.some(n=>n["@id"]===e)??!1)}assertContentLoaded(e){if(this._content===void 0)throw new Error(`VexFile.${e}(): content is not loaded. Call read() first (${this.location})`)}};var j=(t,e=[])=>t.name==="up"||e.includes("vim")&&t.name==="k"||e.includes("emacs")&&t.ctrl&&t.name==="p",z=(t,e=[])=>t.name==="down"||e.includes("vim")&&t.name==="j"||e.includes("emacs")&&t.ctrl&&t.name==="n",Fe=t=>t.name==="space",ae=t=>t.name==="backspace",le=t=>t.name==="tab",ce=t=>"1234567890".includes(t.name),V=t=>t.name==="enter"||t.name==="return";var we=class extends Error{name="AbortPromptError";message="Prompt was aborted";constructor(e){super(),this.cause=e?.cause}},xe=class extends Error{name="CancelPromptError";message="Prompt was canceled"},ue=class extends Error{name="ExitPromptError"},be=class extends Error{name="HookError"},q=class extends Error{name="ValidationError"};var pt=require("node:async_hooks");var ye=require("node:async_hooks");var ut=new ye.AsyncLocalStorage;function ur(t){return{rl:t,hooks:[],hooksCleanup:[],hooksEffect:[],index:0,handleChange(){}}}function dt(t,e){let r=ur(t);return ut.run(r,()=>{function n(i){r.handleChange=()=>{r.index=0,i()},r.handleChange()}return e(n)})}function Y(){let t=ut.getStore();if(!t)throw new be("[Inquirer] Hook functions can only be called from within a prompt");return t}function Ue(){return Y().rl}function Ne(t){let e=(...r)=>{let n=Y(),i=!1,o=n.handleChange;n.handleChange=()=>{i=!0};let a=t(...r);return i&&o(),n.handleChange=o,a};return ye.AsyncResource.bind(e)}function re(t){let e=Y(),{index:r}=e,n={get(){return e.hooks[r]},set(o){e.hooks[r]=o},initialized:r in e.hooks},i=t(n);return e.index++,i}function ft(){Y().handleChange()}var Q={queue(t){let e=Y(),{index:r}=e;e.hooksEffect.push(()=>{e.hooksCleanup[r]?.();let n=t(Ue());if(n!=null&&typeof n!="function")throw new q("useEffect return value must be a cleanup function or nothing.");e.hooksCleanup[r]=n})},run(){let t=Y();Ne(()=>{t.hooksEffect.forEach(e=>{e()}),t.hooksEffect.length=0})()},clearAll(){let t=Y();t.hooksCleanup.forEach(e=>{e?.()}),t.hooksEffect.length=0,t.hooksCleanup.length=0}};function dr(t){return typeof t=="function"}function v(t){return re(e=>{let r=pt.AsyncResource.bind(function(o){e.get()!==o&&(e.set(o),ft())});if(e.initialized)return[e.get(),r];let n=dr(t)?t():t;return e.set(n),[n,r]})}function $(t,e){re(r=>{let n=r.get();(!Array.isArray(n)||e.some((o,a)=>!Object.is(o,n[a])))&&Q.queue(t),r.set(e)})}var F=require("node:util");var B=X(require("node:process"),1);function fr(){return B.default.platform.startsWith("win")?!!B.default.env.CI||!!B.default.env.WT_SESSION||!!B.default.env.TERMINUS_SUBLIME||B.default.env.ConEmuTask==="{cmd::Cmder}"||B.default.env.TERM_PROGRAM==="Terminus-Sublime"||B.default.env.TERM_PROGRAM==="vscode"||B.default.env.TERM==="xterm-256color"||B.default.env.TERM==="alacritty"||B.default.env.TERMINAL_EMULATOR==="JetBrains-JediTerm":B.default.env.TERM!=="linux"}var mt={circleQuestionMark:"(?)",questionMarkPrefix:"(?)",square:"\u2588",squareDarkShade:"\u2593",squareMediumShade:"\u2592",squareLightShade:"\u2591",squareTop:"\u2580",squareBottom:"\u2584",squareLeft:"\u258C",squareRight:"\u2590",squareCenter:"\u25A0",bullet:"\u25CF",dot:"\u2024",ellipsis:"\u2026",pointerSmall:"\u203A",triangleUp:"\u25B2",triangleUpSmall:"\u25B4",triangleDown:"\u25BC",triangleDownSmall:"\u25BE",triangleLeftSmall:"\u25C2",triangleRightSmall:"\u25B8",home:"\u2302",heart:"\u2665",musicNote:"\u266A",musicNoteBeamed:"\u266B",arrowUp:"\u2191",arrowDown:"\u2193",arrowLeft:"\u2190",arrowRight:"\u2192",arrowLeftRight:"\u2194",arrowUpDown:"\u2195",almostEqual:"\u2248",notEqual:"\u2260",lessOrEqual:"\u2264",greaterOrEqual:"\u2265",identical:"\u2261",infinity:"\u221E",subscriptZero:"\u2080",subscriptOne:"\u2081",subscriptTwo:"\u2082",subscriptThree:"\u2083",subscriptFour:"\u2084",subscriptFive:"\u2085",subscriptSix:"\u2086",subscriptSeven:"\u2087",subscriptEight:"\u2088",subscriptNine:"\u2089",oneHalf:"\xBD",oneThird:"\u2153",oneQuarter:"\xBC",oneFifth:"\u2155",oneSixth:"\u2159",oneEighth:"\u215B",twoThirds:"\u2154",twoFifths:"\u2156",threeQuarters:"\xBE",threeFifths:"\u2157",threeEighths:"\u215C",fourFifths:"\u2158",fiveSixths:"\u215A",fiveEighths:"\u215D",sevenEighths:"\u215E",line:"\u2500",lineBold:"\u2501",lineDouble:"\u2550",lineDashed0:"\u2504",lineDashed1:"\u2505",lineDashed2:"\u2508",lineDashed3:"\u2509",lineDashed4:"\u254C",lineDashed5:"\u254D",lineDashed6:"\u2574",lineDashed7:"\u2576",lineDashed8:"\u2578",lineDashed9:"\u257A",lineDashed10:"\u257C",lineDashed11:"\u257E",lineDashed12:"\u2212",lineDashed13:"\u2013",lineDashed14:"\u2010",lineDashed15:"\u2043",lineVertical:"\u2502",lineVerticalBold:"\u2503",lineVerticalDouble:"\u2551",lineVerticalDashed0:"\u2506",lineVerticalDashed1:"\u2507",lineVerticalDashed2:"\u250A",lineVerticalDashed3:"\u250B",lineVerticalDashed4:"\u254E",lineVerticalDashed5:"\u254F",lineVerticalDashed6:"\u2575",lineVerticalDashed7:"\u2577",lineVerticalDashed8:"\u2579",lineVerticalDashed9:"\u257B",lineVerticalDashed10:"\u257D",lineVerticalDashed11:"\u257F",lineDownLeft:"\u2510",lineDownLeftArc:"\u256E",lineDownBoldLeftBold:"\u2513",lineDownBoldLeft:"\u2512",lineDownLeftBold:"\u2511",lineDownDoubleLeftDouble:"\u2557",lineDownDoubleLeft:"\u2556",lineDownLeftDouble:"\u2555",lineDownRight:"\u250C",lineDownRightArc:"\u256D",lineDownBoldRightBold:"\u250F",lineDownBoldRight:"\u250E",lineDownRightBold:"\u250D",lineDownDoubleRightDouble:"\u2554",lineDownDoubleRight:"\u2553",lineDownRightDouble:"\u2552",lineUpLeft:"\u2518",lineUpLeftArc:"\u256F",lineUpBoldLeftBold:"\u251B",lineUpBoldLeft:"\u251A",lineUpLeftBold:"\u2519",lineUpDoubleLeftDouble:"\u255D",lineUpDoubleLeft:"\u255C",lineUpLeftDouble:"\u255B",lineUpRight:"\u2514",lineUpRightArc:"\u2570",lineUpBoldRightBold:"\u2517",lineUpBoldRight:"\u2516",lineUpRightBold:"\u2515",lineUpDoubleRightDouble:"\u255A",lineUpDoubleRight:"\u2559",lineUpRightDouble:"\u2558",lineUpDownLeft:"\u2524",lineUpBoldDownBoldLeftBold:"\u252B",lineUpBoldDownBoldLeft:"\u2528",lineUpDownLeftBold:"\u2525",lineUpBoldDownLeftBold:"\u2529",lineUpDownBoldLeftBold:"\u252A",lineUpDownBoldLeft:"\u2527",lineUpBoldDownLeft:"\u2526",lineUpDoubleDownDoubleLeftDouble:"\u2563",lineUpDoubleDownDoubleLeft:"\u2562",lineUpDownLeftDouble:"\u2561",lineUpDownRight:"\u251C",lineUpBoldDownBoldRightBold:"\u2523",lineUpBoldDownBoldRight:"\u2520",lineUpDownRightBold:"\u251D",lineUpBoldDownRightBold:"\u2521",lineUpDownBoldRightBold:"\u2522",lineUpDownBoldRight:"\u251F",lineUpBoldDownRight:"\u251E",lineUpDoubleDownDoubleRightDouble:"\u2560",lineUpDoubleDownDoubleRight:"\u255F",lineUpDownRightDouble:"\u255E",lineDownLeftRight:"\u252C",lineDownBoldLeftBoldRightBold:"\u2533",lineDownLeftBoldRightBold:"\u252F",lineDownBoldLeftRight:"\u2530",lineDownBoldLeftBoldRight:"\u2531",lineDownBoldLeftRightBold:"\u2532",lineDownLeftRightBold:"\u252E",lineDownLeftBoldRight:"\u252D",lineDownDoubleLeftDoubleRightDouble:"\u2566",lineDownDoubleLeftRight:"\u2565",lineDownLeftDoubleRightDouble:"\u2564",lineUpLeftRight:"\u2534",lineUpBoldLeftBoldRightBold:"\u253B",lineUpLeftBoldRightBold:"\u2537",lineUpBoldLeftRight:"\u2538",lineUpBoldLeftBoldRight:"\u2539",lineUpBoldLeftRightBold:"\u253A",lineUpLeftRightBold:"\u2536",lineUpLeftBoldRight:"\u2535",lineUpDoubleLeftDoubleRightDouble:"\u2569",lineUpDoubleLeftRight:"\u2568",lineUpLeftDoubleRightDouble:"\u2567",lineUpDownLeftRight:"\u253C",lineUpBoldDownBoldLeftBoldRightBold:"\u254B",lineUpDownBoldLeftBoldRightBold:"\u2548",lineUpBoldDownLeftBoldRightBold:"\u2547",lineUpBoldDownBoldLeftRightBold:"\u254A",lineUpBoldDownBoldLeftBoldRight:"\u2549",lineUpBoldDownLeftRight:"\u2540",lineUpDownBoldLeftRight:"\u2541",lineUpDownLeftBoldRight:"\u253D",lineUpDownLeftRightBold:"\u253E",lineUpBoldDownBoldLeftRight:"\u2542",lineUpDownLeftBoldRightBold:"\u253F",lineUpBoldDownLeftBoldRight:"\u2543",lineUpBoldDownLeftRightBold:"\u2544",lineUpDownBoldLeftBoldRight:"\u2545",lineUpDownBoldLeftRightBold:"\u2546",lineUpDoubleDownDoubleLeftDoubleRightDouble:"\u256C",lineUpDoubleDownDoubleLeftRight:"\u256B",lineUpDownLeftDoubleRightDouble:"\u256A",lineCross:"\u2573",lineBackslash:"\u2572",lineSlash:"\u2571"},ht={tick:"\u2714",info:"\u2139",warning:"\u26A0",cross:"\u2718",squareSmall:"\u25FB",squareSmallFilled:"\u25FC",circle:"\u25EF",circleFilled:"\u25C9",circleDotted:"\u25CC",circleDouble:"\u25CE",circleCircle:"\u24DE",circleCross:"\u24E7",circlePipe:"\u24BE",radioOn:"\u25C9",radioOff:"\u25EF",checkboxOn:"\u2612",checkboxOff:"\u2610",checkboxCircleOn:"\u24E7",checkboxCircleOff:"\u24BE",pointer:"\u276F",triangleUpOutline:"\u25B3",triangleLeft:"\u25C0",triangleRight:"\u25B6",lozenge:"\u25C6",lozengeOutline:"\u25C7",hamburger:"\u2630",smiley:"\u32E1",mustache:"\u0DF4",star:"\u2605",play:"\u25B6",nodejs:"\u2B22",oneSeventh:"\u2150",oneNinth:"\u2151",oneTenth:"\u2152"},pr={tick:"\u221A",info:"i",warning:"\u203C",cross:"\xD7",squareSmall:"\u25A1",squareSmallFilled:"\u25A0",circle:"( )",circleFilled:"(*)",circleDotted:"( )",circleDouble:"( )",circleCircle:"(\u25CB)",circleCross:"(\xD7)",circlePipe:"(\u2502)",radioOn:"(*)",radioOff:"( )",checkboxOn:"[\xD7]",checkboxOff:"[ ]",checkboxCircleOn:"(\xD7)",checkboxCircleOff:"( )",pointer:">",triangleUpOutline:"\u2206",triangleLeft:"\u25C4",triangleRight:"\u25BA",lozenge:"\u2666",lozengeOutline:"\u25CA",hamburger:"\u2261",smiley:"\u263A",mustache:"\u250C\u2500\u2510",star:"\u2736",play:"\u25BA",nodejs:"\u2666",oneSeventh:"1/7",oneNinth:"1/9",oneTenth:"1/10"},mr={...mt,...ht},hr={...mt,...pr},gr=fr(),Sr=gr?mr:hr,O=Sr,gn=Object.entries(ht);var gt={prefix:{idle:(0,F.styleText)("blue","?"),done:(0,F.styleText)("green",O.tick)},spinner:{interval:80,frames:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"].map(t=>(0,F.styleText)("yellow",t))},style:{answer:t=>(0,F.styleText)("cyan",t),message:t=>(0,F.styleText)("bold",t),error:t=>(0,F.styleText)("red",`> ${t}`),defaultAnswer:t=>(0,F.styleText)("dim",`(${t})`),help:t=>(0,F.styleText)("dim",t),highlight:t=>(0,F.styleText)("cyan",t),key:t=>(0,F.styleText)("cyan",(0,F.styleText)("bold",`<${t}>`))}};function St(t){if(typeof t!="object"||t===null)return!1;let e=t;for(;Object.getPrototypeOf(e)!==null;)e=Object.getPrototypeOf(e);return Object.getPrototypeOf(t)===e}function wt(...t){let e={};for(let r of t)for(let[n,i]of Object.entries(r)){let o=e[n];e[n]=St(o)&&St(i)?wt(o,i):i}return e}function A(...t){let e=[gt,...t.filter(r=>r!=null)];return wt(...e)}function M({status:t="idle",theme:e}){let[r,n]=v(!1),[i,o]=v(0),{prefix:a,spinner:s}=A(e);return $(()=>{if(t==="loading"){let u,h=-1,l=setTimeout(()=>{n(!0),u=setInterval(()=>{h=h+1,o(h%s.frames.length)},s.interval)},300);return()=>{clearTimeout(l),clearInterval(u)}}else n(!1)},[t]),r?s.frames[i]:typeof a=="string"?a:a[t==="loading"?"idle":t]??a.idle}function Z(t,e){return re(r=>{let n=r.get();if(!n||n.dependencies.length!==e.length||n.dependencies.some((i,o)=>i!==e[o])){let i=t();return r.set({value:i,dependencies:e}),i}return n.value})}function ee(t){return v({current:t})[0]}function W(t){let e=ee(t);e.current=t,$(r=>{let n=!1,i=Ne((o,a)=>{n||e.current(a,r)});return r.input.on("keypress",i),()=>{n=!0,r.input.removeListener("keypress",i)}},[])}var Ot=X(bt(),1);var yt=(()=>{let t=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;return e=>{let r=0;for(t.lastIndex=0;t.test(e);)r+=1;return e.length-r}})(),Et=t=>t===12288||t>=65281&&t<=65376||t>=65504&&t<=65510,Dt=t=>t===8987||t===9001||t>=12272&&t<=12287||t>=12289&&t<=12350||t>=12441&&t<=12543||t>=12549&&t<=12591||t>=12593&&t<=12686||t>=12688&&t<=12771||t>=12783&&t<=12830||t>=12832&&t<=12871||t>=12880&&t<=19903||t>=65040&&t<=65049||t>=65072&&t<=65106||t>=65108&&t<=65126||t>=65128&&t<=65131||t>=127488&&t<=127490||t>=127504&&t<=127547||t>=127552&&t<=127560||t>=131072&&t<=196605||t>=196608&&t<=262141;var br=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,yr=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,vt=/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu,Er=/\t{1,1000}/y,Lt=new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*","yu"),Dr=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,vr=new RegExp("\\p{M}+","gu"),Lr={limit:1/0,ellipsis:""},Pt=(t,e={},r={})=>{let n=e.limit??1/0,i=e.ellipsis??"",o=e?.ellipsisWidth??(i?Pt(i,Lr,r).width:0),a=0,s=r.controlWidth??0,p=r.tabWidth??8,u=r.emojiWidth??2,h=2,l=r.regularWidth??1,d=r.wideWidth??h,g=[[Dr,l],[br,a],[yr,s],[Er,p],[Lt,u],[vt,d]],f=0,m=0,S=t.length,b=0,w=!1,E=S,L=Math.max(0,n-o),R=0,P=0,T=0,C=0;e:for(;;){if(P>R||m>=S&&m>f){let c=t.slice(R,P)||t.slice(f,m);b=0;for(let x of c.replaceAll(vr,"")){let y=x.codePointAt(0)||0;if(Et(y)?C=h:Dt(y)?C=d:C=l,T+C>L&&(E=Math.min(E,Math.max(R,f)+b)),T+C>n){w=!0;break e}b+=x.length,T+=C}R=P=0}if(m>=S)break e;for(let c=0,x=g.length;c<x;c++){let[y,D]=g[c];if(y.lastIndex=m,y.test(t)){if(b=y===vt?yt(t.slice(m,y.lastIndex)):y===Lt?1:y.lastIndex-m,C=b*D,T+C>L&&(E=Math.min(E,m+Math.floor((L-T)/D))),T+C>n){w=!0;break e}T+=C,R=f,P=m,m=f=y.lastIndex;continue e}}m+=1}return{width:w?L:T,index:w?E:S,truncated:w,ellipsed:w&&n>=o}},It=Pt;var Pr={limit:1/0,ellipsis:"",ellipsisWidth:0},Ir=(t,e={})=>It(t,Pr,e).width,K=Ir;var Ee="\x1B",Bt="\x9B",Rr=39,Ae="\x07",Ft="[",Tr="]",Ut="m",ke=`${Tr}8;;`,Rt=new RegExp(`(?:\\${Ft}(?<code>\\d+)m|\\${ke}(?<uri>.*)${Ae})`,"y"),Tt=t=>{if(t>=30&&t<=37||t>=90&&t<=97)return 39;if(t>=40&&t<=47||t>=100&&t<=107)return 49;if(t===1||t===2)return 22;if(t===3)return 23;if(t===4)return 24;if(t===7)return 27;if(t===8)return 28;if(t===9)return 29;if(t===0)return 0},Ct=t=>`${Ee}${Ft}${t}${Ut}`,_t=t=>`${Ee}${ke}${t}${Ae}`,Oe=(t,e,r)=>{let n=e[Symbol.iterator](),i=!1,o=!1,a=t.at(-1),s=a===void 0?0:K(a),p=n.next(),u=n.next(),h=0;for(;!p.done;){let l=p.value,d=K(l);s+d<=r?t[t.length-1]+=l:(t.push(l),s=0),(l===Ee||l===Bt)&&(i=!0,o=e.startsWith(ke,h+1)),i?o?l===Ae&&(i=!1,o=!1):l===Ut&&(i=!1):(s+=d,s===r&&!u.done&&(t.push(""),s=0)),p=u,u=n.next(),h+=l.length}a=t.at(-1),!s&&a!==void 0&&a.length&&t.length>1&&(t[t.length-2]+=t.pop())},Cr=t=>{let e=t.split(" "),r=e.length;for(;r&&!K(e[r-1]);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},_r=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let n="",i,o,a=t.split(" "),s=[""],p=0;for(let l=0;l<a.length;l++){let d=a[l];if(r.trim!==!1){let f=s.at(-1)??"",m=f.trimStart();f.length!==m.length&&(s[s.length-1]=m,p=K(m))}l!==0&&(p>=e&&(r.wordWrap===!1||r.trim===!1)&&(s.push(""),p=0),(p||r.trim===!1)&&(s[s.length-1]+=" ",p++));let g=K(d);if(r.hard&&g>e){let f=e-p,m=1+Math.floor((g-f-1)/e);Math.floor((g-1)/e)<m&&s.push(""),Oe(s,d,e),p=K(s.at(-1)??"");continue}if(p+g>e&&p&&g){if(r.wordWrap===!1&&p<e){Oe(s,d,e),p=K(s.at(-1)??"");continue}s.push(""),p=0}if(p+g>e&&r.wordWrap===!1){Oe(s,d,e),p=K(s.at(-1)??"");continue}s[s.length-1]+=d,p+=g}r.trim!==!1&&(s=s.map(l=>Cr(l)));let u=s.join(`
|
|
4
|
-
`),h=!1;for(let l=0;l<
|
|
5
|
-
`){o&&(n+=
|
|
6
|
-
`&&(i&&
|
|
7
|
-
`)}function
|
|
8
|
-
`).flatMap(r=>
|
|
2
|
+
"use strict";var rr=Object.create;var it=Object.defineProperty;var nr=Object.getOwnPropertyDescriptor;var ir=Object.getOwnPropertyNames;var or=Object.getPrototypeOf,sr=Object.prototype.hasOwnProperty;var ot=(t,e)=>()=>{try{return e||t((e={exports:{}}).exports,e),e.exports}catch(r){throw e=0,r}};var ar=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ir(e))!sr.call(t,i)&&i!==r&&it(t,i,{get:()=>e[i],enumerable:!(n=nr(e,i))||n.enumerable});return t};var z=(t,e,r)=>(r=t!=null?rr(or(t)):{},ar(e||!t||!t.__esModule?it(r,"default",{value:t,enumerable:!0}):r,t));var Et=ot((zn,vt)=>{"use strict";vt.exports=Rr;function Pr(t){let e={defaultWidth:0,output:process.stdout,tty:require("tty")};return t?(Object.keys(e).forEach(function(r){t[r]||(t[r]=e[r])}),t):e}function Rr(t){let e=Pr(t);if(e.output.getWindowSize)return e.output.getWindowSize()[0]||e.defaultWidth;if(e.tty.getWindowSize)return e.tty.getWindowSize()[1]||e.defaultWidth;if(e.output.columns)return e.output.columns;if(process.env.CLI_WIDTH){let r=parseInt(process.env.CLI_WIDTH,10);if(!isNaN(r)&&r!==0)return r}return e.defaultWidth}});var $t=ot((ui,Vt)=>{var Kr=require("stream"),$e=class extends Kr{#r=null;constructor(e={}){super(e),this.writable=this.readable=!0,this.muted=!1,this.on("pipe",this._onpipe),this.replace=e.replace,this._prompt=e.prompt||null,this._hadControl=!1}#t(e,r){return this._dest?this._dest[e]:this._src?this._src[e]:r}#e(e,...r){typeof this._dest?.[e]=="function"&&this._dest[e](...r),typeof this._src?.[e]=="function"&&this._src[e](...r)}get isTTY(){return this.#r!==null?this.#r:this.#t("isTTY",!1)}set isTTY(e){this.#r=e}get rows(){return this.#t("rows")}get columns(){return this.#t("columns")}mute(){this.muted=!0}unmute(){this.muted=!1}_onpipe(e){this._src=e}pipe(e,r){return this._dest=e,super.pipe(e,r)}pause(){if(this._src)return this._src.pause()}resume(){if(this._src)return this._src.resume()}write(e){if(this.muted){if(!this.replace)return!0;if(e.match(/^\u001b/))return e.indexOf(this._prompt)===0&&(e=e.slice(this._prompt.length),e=e.replace(/./g,this.replace),e=this._prompt+e),this._hadControl=!0,this.emit("data",e);this._prompt&&this._hadControl&&e.indexOf(this._prompt)===0&&(this._hadControl=!1,this.emit("data",this._prompt),e=e.slice(this._prompt.length)),e=e.toString().replace(/./g,this.replace)}this.emit("data",e)}end(e){this.muted&&(e&&this.replace?e=e.toString().replace(/./g,this.replace):e=null),e&&this.emit("data",e),this.emit("end")}destroy(...e){return this.#e("destroy",...e)}destroySoon(...e){return this.#e("destroySoon",...e)}close(...e){return this.#e("close",...e)}};Vt.exports=$e});var q=z(require("path")),Be=require("fs/promises");var N=require("fs/promises");async function me(t){try{return await lr(t)?JSON.parse(await(0,N.readFile)(t,{encoding:"utf-8"})):void 0}catch(e){throw new Error(`Error reading JSON file ${t}: ${e}`,{cause:e})}}async function st(t,e){let r=JSON.stringify(e,null,4)+`
|
|
3
|
+
`,n=await cr(t,r);await(0,N.writeFile)(t,n,{encoding:"utf-8"})}async function lr(t){try{return await(0,N.access)(t,N.constants.F_OK),!0}catch{return!1}}async function cr(t,e){let r=await fr();if(!r)return e;let n=await r.resolveConfig(t);return n?await r.format(e,{...n,filepath:t}):e}var ur;function fr(){return ur??=import("prettier").catch(()=>{})}var k=["UNKNOWN","LOW","MEDIUM","HIGH","CRITICAL"];var Fe=class t{constructor(e){this.workingDir=e}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(e,r){let n=e.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:r,onNewVulnerabilities:e.onNewVulnerabilities??(e.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:e.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:e.reportNoLongerDetectedVulnerabilities??!0,consoleReport:e.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:e.createSubDirsForProject??!0,mavenRepo:e.mavenRepo??t.DEFAULT_MAVEN_REPO,vexUrls:e.vexUrls??[],vexDir:this.resolvePath(e.vexDir)??(0,q.resolve)(this.workingDir,t.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(e.outDir)??(0,q.resolve)(this.workingDir,t.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(e.cacheDir)??(0,q.resolve)(this.workingDir,t.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(e.scanners,r),projects:this.normalizeProjects(e.projects??[],n)}}normalizeScanners(e,r){return(e??t.DEFAULT_SCANNERS).map(i=>{if(typeof i!="string")throw new Error(`Invalid scanner name '${String(i)}' in configuration file '${r}'`);let o=i.split("@");if(o.length>2)throw new Error(`Invalid scanner name '${i}' in configuration file '${r}'`);return{name:o[0],version:o[1]??""}})}normalizeProjects(e,r){return e.map(n=>{let i=n;if(!i.name)throw new Error("Project name is missing on entry: "+JSON.stringify(i));if(!i.version)throw new Error("Project version is missing on entry: "+JSON.stringify(i));if(!i.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(i));let o={...i,purlAliases:i.purlAliases??[],enabled:i.enabled??!0,silent:i.silent??!1,minimumSeverity:i.minimumSeverity??"UNKNOWN"};return o.sbomFile?{...o,sbomFile:this.resolvePath(o.sbomFile)??o.sbomFile}:{...o,detectNoLongerUsedVulnerabilities:r?o.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(e){if(e)return q.default.isAbsolute(e)?e:(0,q.resolve)(this.workingDir,e)}},he=class{constructor(e){this.workingDir=e;this.normalizer=new Fe(e)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let e=(0,q.resolve)(this.workingDir,"vuln-scan-conf.json"),r=await me(e);if(!r)throw new Error(`Missing project configuration file '${e}'`);return this.normalizer.normalize(r,e)}async loadJiraConfig(e){let r=await(0,Be.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.issues&&n.issue&&(n.issues=n.issue),!n.jiraUrl||typeof n.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(n.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(n.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[i,o]of n.issues.entries())o&&typeof o=="object"&&this.validateAutoCloseSeverity(o.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${i}].autoCloseBelowSeverity'`);return n}validateAutoCloseSeverity(e,r){if(e!==void 0&&!k.includes(e))throw new Error(`${r} value '${String(e)}'. Must be one of: ${k.join(", ")}`)}async loadAutoVexConfig(e){let r=await(0,Be.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.impactStatement||typeof n.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(n.maxSeverity!==void 0&&!k.includes(n.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(n.maxSeverity)}'. Must be one of: ${k.join(", ")}`);if(n.projectOverrides!==void 0){if(!Array.isArray(n.projectOverrides))throw new Error("auto-vex-conf.json: 'projectOverrides' must be an array");for(let[i,o]of n.projectOverrides.entries()){if(!o||typeof o!="object")throw new Error(`auto-vex-conf.json: 'projectOverrides[${i}]' must be an object`);let s=o;if(!Array.isArray(s.projects)||s.projects.length===0||!s.projects.every(a=>typeof a=="string"&&a.length>0))throw new Error(`auto-vex-conf.json: 'projectOverrides[${i}].projects' must be a non-empty array of non-empty strings`);if(!k.includes(s.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'projectOverrides[${i}].maxSeverity' value '${String(s.maxSeverity)}'. Must be one of: ${k.join(", ")}`)}}return n}};var tr=require("path");var at=require("crypto");var Ue="auto_vex_max_severity=";function dr(t){return`${Ue}${t}`}function ge(t){let e=t.status_notes;if(!e||!e.startsWith(Ue))return;let r=e.slice(Ue.length).trim();return k.includes(r)?r:void 0}function lt(t){let{cveName:e,purls:r,status:n,impactStatement:i,actionStatement:o,statusNotes:s,justification:a,timestamp:p=new Date().toISOString(),autoVexMaxSeverity:d}=t,h={vulnerability:{name:e},timestamp:p,products:r.map(l=>({"@id":l})),status:n};return i&&(h.impact_statement=i),o&&(h.action_statement=o),d?h.status_notes=dr(d):s&&(h.status_notes=s),a&&(h.justification=a),h}var pr="https://openvex.dev/ns/v0.2.0";function ct(t,e="conterra"){let n=`https://openvex.dev/docs/public/vex-${(0,at.randomUUID)()}`,i=t.timestamp??new Date().toISOString();return{"@context":pr,"@id":n,author:e,timestamp:i,last_updated:i,version:1,statements:[t]}}function ut(t,e){let r=e.timestamp??new Date().toISOString();return{...t,last_updated:r,version:t.version+1,statements:[...t.statements,e]}}var Se=require("fs/promises"),we=require("path");function ft(t){let e=t.vulnerability.name;return new Set([e,...t.vulnerability.aliases??[]])}var se=class{constructor(e){this.location=e}location;_content=void 0;_exists=!1;get exists(){return this._exists}get content(){return this._content}set content(e){this._content=e,this._exists=e!==void 0}async read(){let e=await me(this.location);this._content=e??void 0,this._exists=this._content!==void 0}async write(){if(this._content===void 0)throw new Error(`Cannot write VexFile: content is undefined (${this.location})`);await(0,Se.mkdir)((0,we.dirname)((0,we.resolve)(this.location)),{recursive:!0}),await st(this.location,this._content)}async delete(){await(0,Se.unlink)(this.location),this._exists=!1}upsert(e,r){if(this._content===void 0)return this._content=ct(e,r),this._exists=!0,{created:!0,changed:!0};let n=ge(e);if(n!==void 0){let i=this._content.statements.findIndex(o=>o.vulnerability.name===e.vulnerability.name&&o.status===e.status&&ge(o)===n);if(i!==-1){let o=this._content.statements[i];return mr(o,e)?{created:!1,changed:!1}:(o.products=e.products,o.impact_statement=e.impact_statement,o.action_statement=e.action_statement,o.justification=e.justification,o.status_notes=e.status_notes,o.timestamp=e.timestamp,this._content.version+=1,this._content.last_updated=e.timestamp??new Date().toISOString(),{created:!1,changed:!0})}}return this._content=ut(this._content,e),{created:!1,changed:!0}}addProductId(e,r){this.assertContentLoaded("addProductId");let n=!1;for(let i of this._content.statements){if(!i.products||i.products.some(s=>s["@id"]===r))continue;let o=i.products.findIndex(s=>s["@id"]===e);o!==-1&&(i.products.splice(o+1,0,{"@id":r}),n=!0)}return n}removeProductId(e,r){this.assertContentLoaded("removeProductId");let n=this._content.statements,i=[],o=!1;for(let s of n){if(r&&!ft(s).has(r)||!s.products)continue;let a=s.products.findIndex(p=>p["@id"]===e);a!==-1&&(s.products.splice(a,1),o=!0,s.products.length===0&&i.push(s))}if(!o)return"unchanged";for(let s of i)n.splice(n.indexOf(s),1);return n.length===0?"emptied":"changed"}hasStatementForProduct(e){return this.assertContentLoaded("hasStatementForProduct"),this._content.statements.some(r=>r.products?.some(n=>n["@id"]===e)??!1)}assertContentLoaded(e){if(this._content===void 0)throw new Error(`VexFile.${e}(): content is not loaded. Call read() first (${this.location})`)}};function mr(t,e){return t.impact_statement!==e.impact_statement||t.action_statement!==e.action_statement||t.justification!==e.justification||t.status_notes!==e.status_notes?!1:hr(t.products,e.products)}function hr(t,e){let r=o=>Array.from(new Set((o??[]).map(s=>s["@id"]).filter(s=>typeof s=="string"))).sort(),n=r(t),i=r(e);return n.length!==i.length?!1:n.every((o,s)=>o===i[s])}var gr=["emacs","vim"],Sr=new Set(gr);function wr(t){return Sr.has(t)}function dt(){let t=process.env.INQUIRER_KEYBINDINGS;return t?Array.from(new Set(t.toLowerCase().split(/[\s,]+/).filter(wr))):[]}var V=(t,e=[])=>t.name==="up"||e.includes("vim")&&t.name==="k"||e.includes("emacs")&&t.ctrl&&t.name==="p",Y=(t,e=[])=>t.name==="down"||e.includes("vim")&&t.name==="j"||e.includes("emacs")&&t.ctrl&&t.name==="n",Ne=t=>t.name==="space",ae=t=>t.name==="backspace",le=t=>t.name==="tab",ce=t=>"1234567890".includes(t.name),$=t=>t.name==="enter"||t.name==="return";var xe=class extends Error{name="AbortPromptError";message="Prompt was aborted";constructor(e){super(),this.cause=e?.cause}},be=class extends Error{name="CancelPromptError";message="Prompt was canceled"},ue=class extends Error{name="ExitPromptError"},ye=class extends Error{name="HookError"},J=class extends Error{name="ValidationError"};var gt=require("node:async_hooks");var ve=require("node:async_hooks");var pt=new ve.AsyncLocalStorage;function xr(t){return{rl:t,hooks:[],hooksCleanup:[],hooksEffect:[],index:0,handleChange(){}}}function mt(t,e){let r=xr(t);return pt.run(r,()=>{function n(i){r.handleChange=()=>{r.index=0,i()},r.handleChange()}return e(n)})}function Q(){let t=pt.getStore();if(!t)throw new ye("[Inquirer] Hook functions can only be called from within a prompt");return t}function Oe(){return Q().rl}function je(t){let e=(...r)=>{let n=Q(),i=!1,o=n.handleChange;n.handleChange=()=>{i=!0};let s=t(...r);return i&&o(),n.handleChange=o,s};return ve.AsyncResource.bind(e)}function ne(t){let e=Q(),{index:r}=e,n={get(){return e.hooks[r]},set(o){e.hooks[r]=o},initialized:r in e.hooks},i=t(n);return e.index++,i}function ht(){Q().handleChange()}var Z={queue(t){let e=Q(),{index:r}=e;e.hooksEffect.push(()=>{e.hooksCleanup[r]?.();let n=t(Oe());if(n!=null&&typeof n!="function")throw new J("useEffect return value must be a cleanup function or nothing.");e.hooksCleanup[r]=n})},run(){let t=Q();je(()=>{t.hooksEffect.forEach(e=>{e()}),t.hooksEffect.length=0})()},clearAll(){let t=Q();t.hooksCleanup.forEach(e=>{e?.()}),t.hooksEffect.length=0,t.hooksCleanup.length=0}};function br(t){return typeof t=="function"}function D(t){return ne(e=>{let r=gt.AsyncResource.bind(function(o){e.get()!==o&&(e.set(o),ht())});if(e.initialized)return[e.get(),r];let n=br(t)?t():t;return e.set(n),[n,r]})}function M(t,e){ne(r=>{let n=r.get();(!Array.isArray(n)||e.some((o,s)=>!Object.is(o,n[s])))&&Z.queue(t),r.set(e)})}var F=require("node:util");var B=z(require("node:process"),1);function yr(){return B.default.platform.startsWith("win")?!!B.default.env.CI||!!B.default.env.WT_SESSION||!!B.default.env.TERMINUS_SUBLIME||B.default.env.ConEmuTask==="{cmd::Cmder}"||B.default.env.TERM_PROGRAM==="Terminus-Sublime"||B.default.env.TERM_PROGRAM==="vscode"||B.default.env.TERM==="xterm-256color"||B.default.env.TERM==="alacritty"||B.default.env.TERMINAL_EMULATOR==="JetBrains-JediTerm":B.default.env.TERM!=="linux"}var St={circleQuestionMark:"(?)",questionMarkPrefix:"(?)",square:"\u2588",squareDarkShade:"\u2593",squareMediumShade:"\u2592",squareLightShade:"\u2591",squareTop:"\u2580",squareBottom:"\u2584",squareLeft:"\u258C",squareRight:"\u2590",squareCenter:"\u25A0",bullet:"\u25CF",dot:"\u2024",ellipsis:"\u2026",pointerSmall:"\u203A",triangleUp:"\u25B2",triangleUpSmall:"\u25B4",triangleDown:"\u25BC",triangleDownSmall:"\u25BE",triangleLeftSmall:"\u25C2",triangleRightSmall:"\u25B8",home:"\u2302",heart:"\u2665",musicNote:"\u266A",musicNoteBeamed:"\u266B",arrowUp:"\u2191",arrowDown:"\u2193",arrowLeft:"\u2190",arrowRight:"\u2192",arrowLeftRight:"\u2194",arrowUpDown:"\u2195",almostEqual:"\u2248",notEqual:"\u2260",lessOrEqual:"\u2264",greaterOrEqual:"\u2265",identical:"\u2261",infinity:"\u221E",subscriptZero:"\u2080",subscriptOne:"\u2081",subscriptTwo:"\u2082",subscriptThree:"\u2083",subscriptFour:"\u2084",subscriptFive:"\u2085",subscriptSix:"\u2086",subscriptSeven:"\u2087",subscriptEight:"\u2088",subscriptNine:"\u2089",oneHalf:"\xBD",oneThird:"\u2153",oneQuarter:"\xBC",oneFifth:"\u2155",oneSixth:"\u2159",oneEighth:"\u215B",twoThirds:"\u2154",twoFifths:"\u2156",threeQuarters:"\xBE",threeFifths:"\u2157",threeEighths:"\u215C",fourFifths:"\u2158",fiveSixths:"\u215A",fiveEighths:"\u215D",sevenEighths:"\u215E",line:"\u2500",lineBold:"\u2501",lineDouble:"\u2550",lineDashed0:"\u2504",lineDashed1:"\u2505",lineDashed2:"\u2508",lineDashed3:"\u2509",lineDashed4:"\u254C",lineDashed5:"\u254D",lineDashed6:"\u2574",lineDashed7:"\u2576",lineDashed8:"\u2578",lineDashed9:"\u257A",lineDashed10:"\u257C",lineDashed11:"\u257E",lineDashed12:"\u2212",lineDashed13:"\u2013",lineDashed14:"\u2010",lineDashed15:"\u2043",lineVertical:"\u2502",lineVerticalBold:"\u2503",lineVerticalDouble:"\u2551",lineVerticalDashed0:"\u2506",lineVerticalDashed1:"\u2507",lineVerticalDashed2:"\u250A",lineVerticalDashed3:"\u250B",lineVerticalDashed4:"\u254E",lineVerticalDashed5:"\u254F",lineVerticalDashed6:"\u2575",lineVerticalDashed7:"\u2577",lineVerticalDashed8:"\u2579",lineVerticalDashed9:"\u257B",lineVerticalDashed10:"\u257D",lineVerticalDashed11:"\u257F",lineDownLeft:"\u2510",lineDownLeftArc:"\u256E",lineDownBoldLeftBold:"\u2513",lineDownBoldLeft:"\u2512",lineDownLeftBold:"\u2511",lineDownDoubleLeftDouble:"\u2557",lineDownDoubleLeft:"\u2556",lineDownLeftDouble:"\u2555",lineDownRight:"\u250C",lineDownRightArc:"\u256D",lineDownBoldRightBold:"\u250F",lineDownBoldRight:"\u250E",lineDownRightBold:"\u250D",lineDownDoubleRightDouble:"\u2554",lineDownDoubleRight:"\u2553",lineDownRightDouble:"\u2552",lineUpLeft:"\u2518",lineUpLeftArc:"\u256F",lineUpBoldLeftBold:"\u251B",lineUpBoldLeft:"\u251A",lineUpLeftBold:"\u2519",lineUpDoubleLeftDouble:"\u255D",lineUpDoubleLeft:"\u255C",lineUpLeftDouble:"\u255B",lineUpRight:"\u2514",lineUpRightArc:"\u2570",lineUpBoldRightBold:"\u2517",lineUpBoldRight:"\u2516",lineUpRightBold:"\u2515",lineUpDoubleRightDouble:"\u255A",lineUpDoubleRight:"\u2559",lineUpRightDouble:"\u2558",lineUpDownLeft:"\u2524",lineUpBoldDownBoldLeftBold:"\u252B",lineUpBoldDownBoldLeft:"\u2528",lineUpDownLeftBold:"\u2525",lineUpBoldDownLeftBold:"\u2529",lineUpDownBoldLeftBold:"\u252A",lineUpDownBoldLeft:"\u2527",lineUpBoldDownLeft:"\u2526",lineUpDoubleDownDoubleLeftDouble:"\u2563",lineUpDoubleDownDoubleLeft:"\u2562",lineUpDownLeftDouble:"\u2561",lineUpDownRight:"\u251C",lineUpBoldDownBoldRightBold:"\u2523",lineUpBoldDownBoldRight:"\u2520",lineUpDownRightBold:"\u251D",lineUpBoldDownRightBold:"\u2521",lineUpDownBoldRightBold:"\u2522",lineUpDownBoldRight:"\u251F",lineUpBoldDownRight:"\u251E",lineUpDoubleDownDoubleRightDouble:"\u2560",lineUpDoubleDownDoubleRight:"\u255F",lineUpDownRightDouble:"\u255E",lineDownLeftRight:"\u252C",lineDownBoldLeftBoldRightBold:"\u2533",lineDownLeftBoldRightBold:"\u252F",lineDownBoldLeftRight:"\u2530",lineDownBoldLeftBoldRight:"\u2531",lineDownBoldLeftRightBold:"\u2532",lineDownLeftRightBold:"\u252E",lineDownLeftBoldRight:"\u252D",lineDownDoubleLeftDoubleRightDouble:"\u2566",lineDownDoubleLeftRight:"\u2565",lineDownLeftDoubleRightDouble:"\u2564",lineUpLeftRight:"\u2534",lineUpBoldLeftBoldRightBold:"\u253B",lineUpLeftBoldRightBold:"\u2537",lineUpBoldLeftRight:"\u2538",lineUpBoldLeftBoldRight:"\u2539",lineUpBoldLeftRightBold:"\u253A",lineUpLeftRightBold:"\u2536",lineUpLeftBoldRight:"\u2535",lineUpDoubleLeftDoubleRightDouble:"\u2569",lineUpDoubleLeftRight:"\u2568",lineUpLeftDoubleRightDouble:"\u2567",lineUpDownLeftRight:"\u253C",lineUpBoldDownBoldLeftBoldRightBold:"\u254B",lineUpDownBoldLeftBoldRightBold:"\u2548",lineUpBoldDownLeftBoldRightBold:"\u2547",lineUpBoldDownBoldLeftRightBold:"\u254A",lineUpBoldDownBoldLeftBoldRight:"\u2549",lineUpBoldDownLeftRight:"\u2540",lineUpDownBoldLeftRight:"\u2541",lineUpDownLeftBoldRight:"\u253D",lineUpDownLeftRightBold:"\u253E",lineUpBoldDownBoldLeftRight:"\u2542",lineUpDownLeftBoldRightBold:"\u253F",lineUpBoldDownLeftBoldRight:"\u2543",lineUpBoldDownLeftRightBold:"\u2544",lineUpDownBoldLeftBoldRight:"\u2545",lineUpDownBoldLeftRightBold:"\u2546",lineUpDoubleDownDoubleLeftDoubleRightDouble:"\u256C",lineUpDoubleDownDoubleLeftRight:"\u256B",lineUpDownLeftDoubleRightDouble:"\u256A",lineCross:"\u2573",lineBackslash:"\u2572",lineSlash:"\u2571"},wt={tick:"\u2714",info:"\u2139",warning:"\u26A0",cross:"\u2718",squareSmall:"\u25FB",squareSmallFilled:"\u25FC",circle:"\u25EF",circleFilled:"\u25C9",circleDotted:"\u25CC",circleDouble:"\u25CE",circleCircle:"\u24DE",circleCross:"\u24E7",circlePipe:"\u24BE",radioOn:"\u25C9",radioOff:"\u25EF",checkboxOn:"\u2612",checkboxOff:"\u2610",checkboxCircleOn:"\u24E7",checkboxCircleOff:"\u24BE",pointer:"\u276F",triangleUpOutline:"\u25B3",triangleLeft:"\u25C0",triangleRight:"\u25B6",lozenge:"\u25C6",lozengeOutline:"\u25C7",hamburger:"\u2630",smiley:"\u32E1",mustache:"\u0DF4",star:"\u2605",play:"\u25B6",nodejs:"\u2B22",oneSeventh:"\u2150",oneNinth:"\u2151",oneTenth:"\u2152"},vr={tick:"\u221A",info:"i",warning:"\u203C",cross:"\xD7",squareSmall:"\u25A1",squareSmallFilled:"\u25A0",circle:"( )",circleFilled:"(*)",circleDotted:"( )",circleDouble:"( )",circleCircle:"(\u25CB)",circleCross:"(\xD7)",circlePipe:"(\u2502)",radioOn:"(*)",radioOff:"( )",checkboxOn:"[\xD7]",checkboxOff:"[ ]",checkboxCircleOn:"(\xD7)",checkboxCircleOff:"( )",pointer:">",triangleUpOutline:"\u2206",triangleLeft:"\u25C4",triangleRight:"\u25BA",lozenge:"\u2666",lozengeOutline:"\u25CA",hamburger:"\u2261",smiley:"\u263A",mustache:"\u250C\u2500\u2510",star:"\u2736",play:"\u25BA",nodejs:"\u2666",oneSeventh:"1/7",oneNinth:"1/9",oneTenth:"1/10"},Er={...St,...wt},Dr={...St,...vr},Lr=yr(),Ir=Lr?Er:Dr,O=Ir,Cn=Object.entries(wt);var _r={prefix:{idle:(0,F.styleText)("blue","?"),done:(0,F.styleText)("green",O.tick)},spinner:{interval:80,frames:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"].map(t=>(0,F.styleText)("yellow",t))},keybindings:[],style:{answer:t=>(0,F.styleText)("cyan",t),message:t=>(0,F.styleText)("bold",t),error:t=>(0,F.styleText)("red",`> ${t}`),defaultAnswer:t=>(0,F.styleText)("dim",`(${t})`),help:t=>(0,F.styleText)("dim",t),highlight:t=>(0,F.styleText)("cyan",t),key:t=>(0,F.styleText)("cyan",(0,F.styleText)("bold",`<${t}>`))}};function xt(){return{..._r,keybindings:dt()}}function bt(t){if(typeof t!="object"||t===null)return!1;let e=t;for(;Object.getPrototypeOf(e)!==null;)e=Object.getPrototypeOf(e);return Object.getPrototypeOf(t)===e}function yt(...t){let e={};for(let r of t)for(let[n,i]of Object.entries(r)){let o=e[n];e[n]=bt(o)&&bt(i)?yt(o,i):i}return e}function j(...t){let e=[xt(),...t.filter(r=>r!=null)];return yt(...e)}function W({status:t="idle",theme:e}){let[r,n]=D(!1),[i,o]=D(0),{prefix:s,spinner:a}=j(e);return M(()=>{if(t==="loading"){let d,h=-1,l=setTimeout(()=>{n(!0),d=setInterval(()=>{h=h+1,o(h%a.frames.length)},a.interval)},300);return()=>{clearTimeout(l),clearInterval(d)}}else n(!1)},[t]),r?a.frames[i]:typeof s=="string"?s:s[t==="loading"?"idle":t]??s.idle}function ee(t,e){return ne(r=>{let n=r.get();if(!n||n.dependencies.length!==e.length||n.dependencies.some((i,o)=>i!==e[o])){let i=t();return r.set({value:i,dependencies:e}),i}return n.value})}function te(t){return D({current:t})[0]}function K(t){let e=te(t);e.current=t,M(r=>{let n=!1,i=je((o,s)=>{n||e.current(s,r)});return r.input.on("keypress",i),()=>{n=!0,r.input.removeListener("keypress",i)}},[])}var kt=z(Et(),1);var Dt=(()=>{let t=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;return e=>{let r=0;for(t.lastIndex=0;t.test(e);)r+=1;return e.length-r}})(),Lt=t=>t===12288||t>=65281&&t<=65376||t>=65504&&t<=65510,It=t=>t===8987||t===9001||t>=12272&&t<=12287||t>=12289&&t<=12350||t>=12441&&t<=12543||t>=12549&&t<=12591||t>=12593&&t<=12686||t>=12688&&t<=12771||t>=12783&&t<=12830||t>=12832&&t<=12871||t>=12880&&t<=19903||t>=65040&&t<=65049||t>=65072&&t<=65106||t>=65108&&t<=65126||t>=65128&&t<=65131||t>=127488&&t<=127490||t>=127504&&t<=127547||t>=127552&&t<=127560||t>=131072&&t<=196605||t>=196608&&t<=262141;var Tr=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,Cr=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,_t=/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu,Br=/\t{1,1000}/y,Pt=new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*","yu"),Fr=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,Ur=new RegExp("\\p{M}+","gu"),Nr={limit:1/0,ellipsis:""},Rt=(t,e={},r={})=>{let n=e.limit??1/0,i=e.ellipsis??"",o=e?.ellipsisWidth??(i?Rt(i,Nr,r).width:0),s=0,a=r.controlWidth??0,p=r.tabWidth??8,d=r.emojiWidth??2,h=2,l=r.regularWidth??1,u=r.wideWidth??h,g=[[Fr,l],[Tr,s],[Cr,a],[Br,p],[Pt,d],[_t,u]],f=0,m=0,S=t.length,b=0,w=!1,v=S,L=Math.max(0,n-o),P=0,I=0,R=0,T=0;e:for(;;){if(I>P||m>=S&&m>f){let c=t.slice(P,I)||t.slice(f,m);b=0;for(let x of c.replaceAll(Ur,"")){let y=x.codePointAt(0)||0;if(Lt(y)?T=h:It(y)?T=u:T=l,R+T>L&&(v=Math.min(v,Math.max(P,f)+b)),R+T>n){w=!0;break e}b+=x.length,R+=T}P=I=0}if(m>=S)break e;for(let c=0,x=g.length;c<x;c++){let[y,E]=g[c];if(y.lastIndex=m,y.test(t)){if(b=y===_t?Dt(t.slice(m,y.lastIndex)):y===Pt?1:y.lastIndex-m,T=b*E,R+T>L&&(v=Math.min(v,m+Math.floor((L-R)/E))),R+T>n){w=!0;break e}R+=T,P=f,I=m,m=f=y.lastIndex;continue e}}m+=1}return{width:w?L:R,index:w?v:S,truncated:w,ellipsed:w&&n>=o}},Tt=Rt;var Or={limit:1/0,ellipsis:"",ellipsisWidth:0},jr=(t,e={})=>Tt(t,Or,e).width,H=jr;var Ee="\x1B",Nt="\x9B",Ar=39,ke="\x07",Ot="[",kr="]",jt="m",Ve=`${kr}8;;`,Ct=new RegExp(`(?:\\${Ot}(?<code>\\d+)m|\\${Ve}(?<uri>.*)${ke})`,"y"),Bt=t=>{if(t>=30&&t<=37||t>=90&&t<=97)return 39;if(t>=40&&t<=47||t>=100&&t<=107)return 49;if(t===1||t===2)return 22;if(t===3)return 23;if(t===4)return 24;if(t===7)return 27;if(t===8)return 28;if(t===9)return 29;if(t===0)return 0},Ft=t=>`${Ee}${Ot}${t}${jt}`,Ut=t=>`${Ee}${Ve}${t}${ke}`,Ae=(t,e,r)=>{let n=e[Symbol.iterator](),i=!1,o=!1,s=t.at(-1),a=s===void 0?0:H(s),p=n.next(),d=n.next(),h=0;for(;!p.done;){let l=p.value,u=H(l);a+u<=r?t[t.length-1]+=l:(t.push(l),a=0),(l===Ee||l===Nt)&&(i=!0,o=e.startsWith(Ve,h+1)),i?o?l===ke&&(i=!1,o=!1):l===jt&&(i=!1):(a+=u,a===r&&!d.done&&(t.push(""),a=0)),p=d,d=n.next(),h+=l.length}s=t.at(-1),!a&&s!==void 0&&s.length&&t.length>1&&(t[t.length-2]+=t.pop())},Vr=t=>{let e=t.split(" "),r=e.length;for(;r&&!H(e[r-1]);)r--;return r===e.length?t:e.slice(0,r).join(" ")+e.slice(r).join("")},$r=(t,e,r={})=>{if(r.trim!==!1&&t.trim()==="")return"";let n="",i,o,s=t.split(" "),a=[""],p=0;for(let l=0;l<s.length;l++){let u=s[l];if(r.trim!==!1){let f=a.at(-1)??"",m=f.trimStart();f.length!==m.length&&(a[a.length-1]=m,p=H(m))}l!==0&&(p>=e&&(r.wordWrap===!1||r.trim===!1)&&(a.push(""),p=0),(p||r.trim===!1)&&(a[a.length-1]+=" ",p++));let g=H(u);if(r.hard&&g>e){let f=e-p,m=1+Math.floor((g-f-1)/e);Math.floor((g-1)/e)<m&&a.push(""),Ae(a,u,e),p=H(a.at(-1)??"");continue}if(p+g>e&&p&&g){if(r.wordWrap===!1&&p<e){Ae(a,u,e),p=H(a.at(-1)??"");continue}a.push(""),p=0}if(p+g>e&&r.wordWrap===!1){Ae(a,u,e),p=H(a.at(-1)??"");continue}a[a.length-1]+=u,p+=g}r.trim!==!1&&(a=a.map(l=>Vr(l)));let d=a.join(`
|
|
4
|
+
`),h=!1;for(let l=0;l<d.length;l++){let u=d[l];if(n+=u,h)h=!1;else if(h=u>="\uD800"&&u<="\uDBFF",h)continue;if(u===Ee||u===Nt){Ct.lastIndex=l+1;let f=Ct.exec(d)?.groups;if(f?.code!==void 0){let m=Number.parseFloat(f.code);i=m===Ar?void 0:m}else f?.uri!==void 0&&(o=f.uri.length===0?void 0:f.uri)}if(d[l+1]===`
|
|
5
|
+
`){o&&(n+=Ut(""));let g=i?Bt(i):void 0;i&&g&&(n+=Ft(g))}else u===`
|
|
6
|
+
`&&(i&&Bt(i)&&(n+=Ft(i)),o&&(n+=Ut(o)))}return n},Mr=/\r?\n/;function At(t,e,r){return String(t).normalize().split(Mr).map(n=>$r(n,e,r)).join(`
|
|
7
|
+
`)}function fe(t,e){return t.split(`
|
|
8
|
+
`).flatMap(r=>At(r,e,{trim:!1,wordWrap:!1}).split(`
|
|
9
9
|
`).map(n=>n.trimEnd())).join(`
|
|
10
|
-
`)}function De(){return(0,
|
|
11
|
-
`)),p=
|
|
12
|
-
`)}var
|
|
13
|
-
`).length,
|
|
14
|
-
`).pop()??"",pe=class{height=0;extraLinesUnderPrompt=0;cursorPos;rl;constructor(e){this.rl=e,this.cursorPos=e.getCursorPos()}write(e){this.rl.output.unmute(),this.rl.output.write(e),this.rl.output.mute()}render(e,r=""){let n=
|
|
15
|
-
`);let
|
|
16
|
-
`+r:""),
|
|
17
|
-
`,r
|
|
18
|
-
at ${c}`)}let[T
|
|
19
|
-
`).trimEnd()}${
|
|
20
|
-
`).trimEnd()}${
|
|
10
|
+
`)}function De(){return(0,kt.default)({defaultWidth:80,output:Oe().output})}function Wr({active:t,renderedItems:e,pageSize:r,loop:n}){let i=te({lastPointer:t,lastActive:void 0}),{lastPointer:o,lastActive:s}=i.current,a=Math.floor(r/2),p=e.reduce((l,u)=>l+u.length,0),d=e.slice(0,t).reduce((l,u)=>l+u.length,0),h=d;if(p>r)if(n)h=o,s!=null&&s<t&&t-s<r&&(h=Math.min(a,Math.abs(t-s)===1?Math.min(o+(e[s]?.length??0),Math.max(d,o)):o+t-s));else{let l=e.slice(t).reduce((u,g)=>u+g.length,0);h=l<r-a?r-l:Math.min(d,a)}return i.current.lastPointer=h,i.current.lastActive=t,h}function de({items:t,active:e,renderItem:r,pageSize:n,loop:i=!0}){let o=De(),s=b=>(b%t.length+t.length)%t.length,a=t.map((b,w)=>b==null?[]:fe(r({item:b,index:w,isActive:w===e}),o).split(`
|
|
11
|
+
`)),p=a.reduce((b,w)=>b+w.length,0),d=b=>a[b]??[],h=Wr({active:e,renderedItems:a,pageSize:n,loop:i}),l=d(e).slice(0,n),u=h+l.length<=n?h:n-l.length,g=Array.from({length:n});g.splice(u,l.length,...l);let f=new Set([e]),m=u+l.length,S=s(e+1);for(;m<n&&!f.has(S)&&(i&&p>n?S!==e:S>e);){let w=d(S).slice(0,n-m);g.splice(m,w.length,...w),f.add(S),m+=w.length,S=s(S+1)}for(m=u-1,S=s(e-1);m>=0&&!f.has(S)&&(i&&p>n?S!==e:S<e);){let b=d(S),w=b.slice(Math.max(0,b.length-m-1));g.splice(m-w.length+1,w.length,...w),f.add(S),m-=w.length,S=s(S-1)}return g.filter(b=>typeof b=="string").join(`
|
|
12
|
+
`)}var qt=z(require("node:readline"),1),Jt=require("node:async_hooks"),Xt=z($t(),1);var re=[];re.push("SIGHUP","SIGINT","SIGTERM");process.platform!=="win32"&&re.push("SIGALRM","SIGABRT","SIGVTALRM","SIGXCPU","SIGXFSZ","SIGUSR2","SIGTRAP","SIGSYS","SIGQUIT","SIGIOT");process.platform==="linux"&&re.push("SIGIO","SIGPOLL","SIGPWR","SIGSTKFLT");var Le=t=>!!t&&typeof t=="object"&&typeof t.removeListener=="function"&&typeof t.emit=="function"&&typeof t.reallyExit=="function"&&typeof t.listeners=="function"&&typeof t.kill=="function"&&typeof t.pid=="number"&&typeof t.on=="function",Me=Symbol.for("signal-exit emitter"),We=globalThis,Hr=Object.defineProperty.bind(Object),Ke=class{emitted={afterExit:!1,exit:!1};listeners={afterExit:[],exit:[]};count=0;id=Math.random();constructor(){if(We[Me])return We[Me];Hr(We,Me,{value:this,writable:!1,enumerable:!1,configurable:!1})}on(e,r){this.listeners[e].push(r)}removeListener(e,r){let n=this.listeners[e],i=n.indexOf(r);i!==-1&&(i===0&&n.length===1?n.length=0:n.splice(i,1))}emit(e,r,n){if(this.emitted[e])return!1;this.emitted[e]=!0;let i=!1;for(let o of this.listeners[e])i=o(r,n)===!0||i;return e==="exit"&&(i=this.emit("afterExit",r,n)||i),i}},Ie=class{},Gr=t=>({onExit(e,r){return t.onExit(e,r)},load(){return t.load()},unload(){return t.unload()}}),He=class extends Ie{onExit(){return()=>{}}load(){}unload(){}},Ge=class extends Ie{#r=qe.platform==="win32"?"SIGINT":"SIGHUP";#t=new Ke;#e;#o;#s;#i={};#n=!1;constructor(e){super(),this.#e=e,this.#i={};for(let r of re)this.#i[r]=()=>{let n=this.#e.listeners(r),{count:i}=this.#t,o=e;if(typeof o.__signal_exit_emitter__=="object"&&typeof o.__signal_exit_emitter__.count=="number"&&(i+=o.__signal_exit_emitter__.count),n.length===i){this.unload();let s=this.#t.emit("exit",null,r),a=r==="SIGHUP"?this.#r:r;s||e.kill(e.pid,a)}};this.#s=e.reallyExit,this.#o=e.emit}onExit(e,r){if(!Le(this.#e))return()=>{};this.#n===!1&&this.load();let n=r?.alwaysLast?"afterExit":"exit";return this.#t.on(n,e),()=>{this.#t.removeListener(n,e),this.#t.listeners.exit.length===0&&this.#t.listeners.afterExit.length===0&&this.unload()}}load(){if(!this.#n){this.#n=!0,this.#t.count+=1;for(let e of re)try{let r=this.#i[e];r&&this.#e.on(e,r)}catch{}this.#e.emit=(e,...r)=>this.#l(e,...r),this.#e.reallyExit=e=>this.#a(e)}}unload(){this.#n&&(this.#n=!1,re.forEach(e=>{let r=this.#i[e];if(!r)throw new Error("Listener not defined for signal: "+e);try{this.#e.removeListener(e,r)}catch{}}),this.#e.emit=this.#o,this.#e.reallyExit=this.#s,this.#t.count-=1)}#a(e){return Le(this.#e)?(this.#e.exitCode=e||0,this.#t.emit("exit",this.#e.exitCode,null),this.#s.call(this.#e,this.#e.exitCode)):0}#l(e,...r){let n=this.#o;if(e==="exit"&&Le(this.#e)){typeof r[0]=="number"&&(this.#e.exitCode=r[0]);let i=n.call(this.#e,e,...r);return this.#t.emit("exit",this.#e.exitCode,null),i}else return n.call(this.#e,e,...r)}},qe=globalThis.process,{onExit:Mt,load:pi,unload:mi}=Gr(Le(qe)?new Ge(qe):new He);var Gt=require("node:util");var _e="\x1B[?25l",Kt="\x1B[?25h",Je=(t=1)=>t>0?`\x1B[${t}A`:"",Xe=(t=1)=>t>0?`\x1B[${t}B`:"",ze=(t,e)=>typeof e=="number"&&!Number.isNaN(e)?`\x1B[${e+1};${t+1}H`:`\x1B[${t+1}G`,Wt="\x1B[2K",Ye=t=>t>0?(Wt+Je(1)).repeat(t-1)+Wt+"\x1B[G":"";var Ht=t=>t.split(`
|
|
13
|
+
`).length,Jr=t=>t.split(`
|
|
14
|
+
`).pop()??"",pe=class{height=0;extraLinesUnderPrompt=0;cursorPos;rl;constructor(e){this.rl=e,this.cursorPos=e.getCursorPos()}write(e){this.rl.output.unmute(),this.rl.output.write(e),this.rl.output.mute()}render(e,r=""){let n=Jr(e),i=(0,Gt.stripVTControlCharacters)(n),o=i;this.rl.line.length>0&&(o=o.slice(0,-this.rl.line.length)),this.rl.setPrompt(o),this.cursorPos=this.rl.getCursorPos();let s=De();e=fe(e,s),r=fe(r,s),i.length%s===0&&(e+=`
|
|
15
|
+
`);let a=e+(r?`
|
|
16
|
+
`+r:""),d=Math.floor(i.length/s)-this.cursorPos.rows+(r?Ht(r):0);d>0&&(a+=Je(d)),a+=ze(this.cursorPos.cols),this.write(Xe(this.extraLinesUnderPrompt)+Ye(this.height)+a),this.extraLinesUnderPrompt=d,this.height=Ht(a)}checkCursorPos(){let e=this.rl.getCursorPos();e.cols!==this.cursorPos.cols&&(this.write(ze(e.cols)),this.cursorPos=e)}done({clearContent:e}){this.rl.setPrompt("");let r=Xe(this.extraLinesUnderPrompt);r+=e?Ye(this.height):`
|
|
17
|
+
`,r+="\x1B[G",r+=Kt,this.write(r),this.rl.close()}};var Pe=class extends Promise{static withResolver(){let e,r;return{promise:new Promise((i,o)=>{e=i,r=o}),resolve:e,reject:r}}};var zt=z(require("node:path"),1),Xr=globalThis.setImmediate;function zr(){let t=Error.prepareStackTrace,e=[];try{Error.prepareStackTrace=(r,n)=>{let i=n.slice(1);return e=i,i},new Error().stack}catch{return e}return Error.prepareStackTrace=t,e}function G(t){let e=zr();return(n,i={})=>{let{input:o=process.stdin,signal:s}=i,a=new Set,p=new Xt.default;p.pipe(i.output??process.stdout);let d=qt.createInterface({terminal:!0,input:o,output:p});p.mute();let h=new pe(d),{promise:l,resolve:u,reject:g}=Pe.withResolver(),f=()=>g(new be);if(s){let S=()=>g(new xe({cause:s.reason}));if(s.aborted)return S(),Object.assign(l,{cancel:f});s.addEventListener("abort",S),a.add(()=>s.removeEventListener("abort",S))}a.add(Mt((S,b)=>{g(new ue(`User force closed the prompt with ${S} ${b}`))}));let m=()=>g(new ue("User force closed the prompt with SIGINT"));return d.on("SIGINT",m),a.add(()=>d.removeListener("SIGINT",m)),mt(d,S=>{let b=Jt.AsyncResource.bind(()=>Z.clearAll());d.on("close",b),a.add(()=>d.removeListener("close",b));let w=()=>{let v=()=>h.checkCursorPos();d.input.on("keypress",v),a.add(()=>d.input.removeListener("keypress",v));let L=null;S(()=>{let P=!1;try{let I=t(n,c=>{P?u(c):L={value:c}});if(I===void 0){let c=e[1]?.getFileName();throw c&&!c.startsWith("file://")&&(c=zt.default.resolve(c)),new Error(`Prompt functions must return a string.
|
|
18
|
+
at ${c}`)}let[R,T]=typeof I=="string"?[I]:I;h.render(R,T),Z.run()}catch(I){g(I)}if(P=!0,L!==null){let{value:I}=L;L=null,u(I)}})};return"readableFlowing"in o?Xr(w):w(),Object.assign(l.then(v=>(Z.clearAll(),v),v=>{throw Z.clearAll(),v}).finally(()=>{a.forEach(v=>v()),h.done({clearContent:!!i.clearPromptOnDone}),p.end()}).then(()=>l),{cancel:f})})}}var Yt=require("node:util");var _=class{separator=(0,Yt.styleText)("dim",Array.from({length:15}).join(O.line));type="separator";constructor(e){e&&(this.separator=e)}static isSeparator(e){return!!(e&&typeof e=="object"&&"type"in e&&e.type==="separator")}};var X=require("node:util");var Yr={icon:{checked:(0,X.styleText)("green",O.circleFilled),unchecked:O.circle,cursor:O.pointer,disabledChecked:(0,X.styleText)("green",O.circleDouble),disabledUnchecked:"-"},style:{disabled:t=>(0,X.styleText)("dim",t),renderSelectedChoices:t=>t.map(e=>e.short).join(", "),description:t=>(0,X.styleText)("cyan",t),keysHelpTip:t=>t.map(([e,r])=>`${(0,X.styleText)("bold",e)} ${(0,X.styleText)("dim",r)}`).join((0,X.styleText)("dim"," \u2022 "))},i18n:{disabledError:"This option is disabled and cannot be toggled."}};function Re(t){return!_.isSeparator(t)&&!t.disabled}function Qe(t){return!_.isSeparator(t)}function Qt(t){return!_.isSeparator(t)&&t.checked}function Ze(t){return Re(t)?{...t,checked:!t.checked}:t}function Qr(t){return function(e){return Re(e)?{...e,checked:t}:e}}function Zr(t){return t.map(e=>{if(_.isSeparator(e))return e;if(typeof e!="object"||e===null||!("value"in e)){let i=String(e);return{value:e,name:i,short:i,checkedName:i,disabled:!1,checked:!1}}let r=e.name??String(e.value),n={value:e.value,name:r,short:e.short??r,checkedName:e.checkedName??r,disabled:e.disabled??!1,checked:e.checked??!1};return e.description&&(n.description=e.description),n})}var et=G((t,e)=>{let{pageSize:r=7,loop:n=!0,required:i,validate:o=()=>!0}=t,s={all:"a",invert:"i",...t.shortcuts},a=j(Yr,t.theme),{keybindings:p}=a,[d,h]=D("idle"),l=W({status:d,theme:a}),[u,g]=D(Zr(t.choices)),f=ee(()=>{let c=u.findIndex(Qe),x=u.findLastIndex(Qe);if(c===-1)throw new J("[checkbox prompt] No selectable choices. All choices are disabled.");return{first:c,last:x}},[u]),[m,S]=D(f.first),[b,w]=D();K(async c=>{if($(c)){let x=u.filter(Qt),y=await o([...x]);i&&!x.length?w("At least one choice must be selected"):y===!0?(h("done"),e(x.map(E=>E.value))):w(y||"You must select a valid value")}else if(V(c,p)||Y(c,p)){if(b&&w(void 0),n||V(c,p)&&m!==f.first||Y(c,p)&&m!==f.last){let x=V(c,p)?-1:1,y=m;do y=(y+x+u.length)%u.length;while(!Qe(u[y]));S(y)}}else if(Ne(c)){let x=u[m];x&&!_.isSeparator(x)&&(x.disabled?w(a.i18n.disabledError):(w(void 0),g(u.map((y,E)=>E===m?Ze(y):y))))}else if(c.name===s.all){let x=u.some(y=>Re(y)&&!y.checked);g(u.map(Qr(x)))}else if(c.name===s.invert)g(u.map(Ze));else if(ce(c)){let x=Number(c.name)-1,y=-1,E=u.findIndex(A=>_.isSeparator(A)?!1:(y++,y===x)),C=u[E];C&&Re(C)&&(S(E),g(u.map((A,U)=>U===E?Ze(A):A)))}});let v=a.style.message(t.message,d),L,P=de({items:u,active:m,renderItem({item:c,isActive:x}){if(_.isSeparator(c))return` ${c.separator}`;let y=x?a.icon.cursor:" ";if(c.disabled){let U=typeof c.disabled=="string"?c.disabled:"(disabled)",Ce=c.checked?a.icon.disabledChecked:a.icon.disabledUnchecked;return a.style.disabled(`${y}${Ce} ${c.name} ${U}`)}x&&(L=c.description);let E=c.checked?a.icon.checked:a.icon.unchecked,C=c.checked?c.checkedName:c.name;return(x?a.style.highlight:U=>U)(`${y}${E} ${C}`)},pageSize:r,loop:n});if(d==="done"){let c=u.filter(Qt),x=a.style.answer(a.style.renderSelectedChoices(c,u));return[l,v,x].filter(Boolean).join(" ")}let I=[["\u2191\u2193","navigate"],["space","select"]];s.all&&I.push([s.all,"all"]),s.invert&&I.push([s.invert,"invert"]),I.push(["\u23CE","submit"]);let R=a.style.keysHelpTip(I);return`${[[l,v].filter(Boolean).join(" "),P," ",L?a.style.description(L):"",b?a.style.error(b):"",R].filter(Boolean).join(`
|
|
19
|
+
`).trimEnd()}${_e}`});function Zt(t,e){let r=e!==!1;return/^(y|yes)/i.test(t)?r=!0:/^(n|no)/i.test(t)&&(r=!1),r}function er(t){return t?"Yes":"No"}var tt=G((t,e)=>{let{transformer:r=er}=t,[n,i]=D("idle"),[o,s]=D(""),a=j(t.theme),p=W({status:n,theme:a});K((u,g)=>{if(n==="idle")if($(u)){let f=Zt(o,t.default);s(r(f)),i("done"),e(f)}else if(le(u)){let f=er(!Zt(o,t.default));g.clearLine(0),g.write(f),s(f)}else s(g.line)});let d=o,h="";n==="done"?d=a.style.answer(o):h=` ${a.style.defaultAnswer(t.default===!1?"y/N":"Y/n")}`;let l=a.style.message(t.message,n);return`${p} ${l}${h} ${d}`});var en={validationFailureMode:"keep"},ie=G((t,e)=>{let{prefill:r="tab"}=t,n=j(en,t.theme),[i,o]=D("idle"),[s,a]=D(String(t.default??"")),[p,d]=D(),[h,l]=D(""),u=W({status:i,theme:n});async function g(w){let{required:v,pattern:L,patternError:P="Invalid input"}=t;return v&&!w?"You must provide a value":L&&!L.test(w)?P:typeof t.validate=="function"?await t.validate(w)||"You must provide a valid value":!0}K(async(w,v)=>{if(i==="idle")if($(w)){let L=h||s;o("loading");let P=await g(L);P===!0?(l(L),o("done"),e(L)):(n.validationFailureMode==="clear"?l(""):v.write(h),d(P),o("idle"))}else ae(w)&&!h?a(""):le(w)&&!h?(a(""),v.clearLine(0),v.write(s),l(s)):(l(v.line),d(void 0))}),M(w=>{r==="editable"&&s&&(w.write(s),l(s))},[]);let f=n.style.message(t.message,i),m=h;typeof t.transformer=="function"?m=t.transformer(h,{isFinal:i==="done"}):i==="done"&&(m=n.style.answer(h));let S;s&&i!=="done"&&!h&&(S=n.style.defaultAnswer(s));let b="";return p&&(b=n.style.error(p)),[[u,f,S,m].filter(w=>w!==void 0).join(" "),b]});var oe=require("node:util");var tn={icon:{cursor:O.pointer},style:{disabled:t=>(0,oe.styleText)("dim",t),description:t=>(0,oe.styleText)("cyan",t),keysHelpTip:t=>t.map(([e,r])=>`${(0,oe.styleText)("bold",e)} ${(0,oe.styleText)("dim",r)}`).join((0,oe.styleText)("dim"," \u2022 "))},i18n:{disabledError:"This option is disabled and cannot be selected."},indexMode:"hidden"};function rt(t){return!_.isSeparator(t)&&!t.disabled}function nt(t){return!_.isSeparator(t)}function rn(t){return t.map(e=>{if(_.isSeparator(e))return e;if(typeof e!="object"||e===null||!("value"in e)){let i=String(e);return{value:e,name:i,short:i,disabled:!1}}let r=e.name??String(e.value),n={value:e.value,name:r,short:e.short??r,disabled:e.disabled??!1};return e.description&&(n.description=e.description),n})}var Te=G((t,e)=>{let{loop:r=!0,pageSize:n=7}=t,i=j(tn,t.theme),{keybindings:o}=i,[s,a]=D("idle"),p=W({status:s,theme:i}),d=te(),h=!o.includes("vim"),l=ee(()=>rn(t.choices),[t.choices]),u=ee(()=>{let c=l.findIndex(nt),x=l.findLastIndex(nt);if(c===-1)throw new J("[select prompt] No selectable choices. All choices are disabled.");return{first:c,last:x}},[l]),g=ee(()=>"default"in t?l.findIndex(c=>rt(c)&&c.value===t.default):-1,[t.default,l]),[f,m]=D(g===-1?u.first:g),S=l[f];if(S==null||_.isSeparator(S))throw new Error("Active index does not point to a choice");let[b,w]=D();K((c,x)=>{if(clearTimeout(d.current),b&&w(void 0),$(c))S.disabled?w(i.i18n.disabledError):(a("done"),e(S.value));else if(V(c,o)||Y(c,o)){if(x.clearLine(0),r||V(c,o)&&f!==u.first||Y(c,o)&&f!==u.last){let y=V(c,o)?-1:1,E=f;do E=(E+y+l.length)%l.length;while(!nt(l[E]));m(E)}}else if(ce(c)&&!Number.isNaN(Number(x.line))){let y=Number(x.line)-1,E=-1,C=l.findIndex(U=>_.isSeparator(U)?!1:(E++,E===y)),A=l[C];A!=null&&rt(A)&&m(C),d.current=setTimeout(()=>{x.clearLine(0)},700)}else if(ae(c))x.clearLine(0);else if(h){let y=x.line.toLowerCase(),E=l.findIndex(C=>_.isSeparator(C)||!rt(C)?!1:C.name.toLowerCase().startsWith(y));E!==-1&&m(E),d.current=setTimeout(()=>{x.clearLine(0)},700)}}),M(()=>()=>{clearTimeout(d.current)},[]);let v=i.style.message(t.message,s),L=i.style.keysHelpTip([["\u2191\u2193","navigate"],["\u23CE","select"]]),P=0,I=de({items:l,active:f,renderItem({item:c,isActive:x,index:y}){if(_.isSeparator(c))return P++,` ${c.separator}`;let E=x?i.icon.cursor:" ",C=i.indexMode==="number"?`${y+1-P}. `:"";if(c.disabled){let U=typeof c.disabled=="string"?c.disabled:"(disabled)",Ce=x?i.icon.cursor:"-";return i.style.disabled(`${Ce} ${C}${c.name} ${U}`)}return(x?i.style.highlight:U=>U)(`${E} ${C}${c.name}`)},pageSize:n,loop:r});if(s==="done")return[p,v,i.style.answer(S.short)].filter(Boolean).join(" ");let{description:R}=S;return`${[[p,v].filter(Boolean).join(" "),I," ",R?i.style.description(R):"",b?i.style.error(b):"",L].filter(Boolean).join(`
|
|
20
|
+
`).trimEnd()}${_e}`});(async()=>{let e=!process.argv.slice(2).includes("--no-project-filter");try{let r=await new he(process.cwd()).loadProjectConfig();console.info("## Add New VEX Statement ##");let n=await ie({message:"CVE name (e.g. CVE-2023-52070)",required:!0}),i=r.projects.filter(f=>!e||f.enabled&&!f.silent).map(f=>({name:`${f.name}@${f.version}`,value:f.purl}));i.sort((f,m)=>f.name.localeCompare(m.name));let o=await et({message:"Projects to add",choices:i,required:!0,pageSize:15}),s=(0,tr.resolve)(r.vexDir,`${n}.json`),a=["under_investigation","affected","fixed","not_affected"],p=await Te({message:"Status?",choices:a.map(f=>({name:f,value:f})),default:a[a.length-1]}),d={};switch(p){case"affected":{let f=await ie({message:"Action statement?",required:!0});d.actionStatement=f;break}case"not_affected":{let m=await Te({message:"Justification?",choices:["none","component_not_present","vulnerable_code_not_present","vulnerable_code_not_in_execute_path","vulnerable_code_cannot_be_controlled_by_adversary","inline_mitigations_already_exist"].map(b=>({name:b,value:b}))});m!=="none"&&(d.justification=m);let S=await ie({message:"Impact statement?",required:m==="none"});S&&(d.impactStatement=S);break}case"fixed":{let f=await ie({message:"Status note?"});f&&(d.statusNotes=f);break}}let h=new Date().toISOString(),l=lt({cveName:n,purls:Array.from(o),status:p,timestamp:h,...d});await tt({message:`Following statement will be added to ${s}:
|
|
21
21
|
${JSON.stringify(l,null,2)}
|
|
22
22
|
|
|
23
|
-
Do you want to proceed?`})||(console.log("Aborted."),process.exit(0));let g=new se(
|
|
23
|
+
Do you want to proceed?`})||(console.log("Aborted."),process.exit(0));let g=new se(s);await g.read(),g.upsert(l),await g.write()}catch(r){console.error(`Error: ${r}`),process.exitCode=1}})();
|
package/dist/auto-vex-creator.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
`,r=await nt(n,e);await(0,u.writeFile)(n,r,{encoding:"utf-8"})}async function rt(n){try{return await(0,u.access)(n,u.constants.F_OK),!0}catch{return!1}}async function nt(n,t){let e=await ot();if(!e)return t;let r=await e.resolveConfig(n);return r?await e.format(t,{...r,filepath:n}):t}var it;function ot(){return it??=import("prettier").catch(()=>{})}var R={UNKNOWN:0,LOW:1,MEDIUM:2,HIGH:3,CRITICAL:4},v=["UNKNOWN","LOW","MEDIUM","HIGH","CRITICAL"];function U(n,t){return R[n]<R[t]}var O=class n{constructor(t){this.workingDir=t}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(t,e){let r=t.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:e,onNewVulnerabilities:t.onNewVulnerabilities??(t.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:t.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:t.reportNoLongerDetectedVulnerabilities??!0,consoleReport:t.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:t.createSubDirsForProject??!0,mavenRepo:t.mavenRepo??n.DEFAULT_MAVEN_REPO,vexUrls:t.vexUrls??[],vexDir:this.resolvePath(t.vexDir)??(0,m.resolve)(this.workingDir,n.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(t.outDir)??(0,m.resolve)(this.workingDir,n.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(t.cacheDir)??(0,m.resolve)(this.workingDir,n.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(t.scanners,e),projects:this.normalizeProjects(t.projects??[],r)}}normalizeScanners(t,e){return(t??n.DEFAULT_SCANNERS).map(i=>{if(typeof i!="string")throw new Error(`Invalid scanner name '${String(i)}' in configuration file '${e}'`);let o=i.split("@");if(o.length>2)throw new Error(`Invalid scanner name '${i}' in configuration file '${e}'`);return{name:o[0],version:o[1]??""}})}normalizeProjects(t,e){return t.map(r=>{let i=r;if(!i.name)throw new Error("Project name is missing on entry: "+JSON.stringify(i));if(!i.version)throw new Error("Project version is missing on entry: "+JSON.stringify(i));if(!i.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(i));let o={...i,purlAliases:i.purlAliases??[],enabled:i.enabled??!0,silent:i.silent??!1,minimumSeverity:i.minimumSeverity??"UNKNOWN"};return o.sbomFile?{...o,sbomFile:this.resolvePath(o.sbomFile)??o.sbomFile}:{...o,detectNoLongerUsedVulnerabilities:e?o.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(t){if(t)return m.default.isAbsolute(t)?t:(0,m.resolve)(this.workingDir,t)}},f=class{constructor(t){this.workingDir=t;this.normalizer=new O(t)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let t=(0,m.resolve)(this.workingDir,"vuln-scan-conf.json"),e=await x(t);if(!e)throw new Error(`Missing project configuration file '${t}'`);return this.normalizer.normalize(e,t)}async loadJiraConfig(t){let e=await(0,N.readFile)(t,"utf8"),r=JSON.parse(e);if(!r.issues&&r.issue&&(r.issues=r.issue),!r.jiraUrl||typeof r.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(r.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(r.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[i,o]of r.issues.entries())o&&typeof o=="object"&&this.validateAutoCloseSeverity(o.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${i}].autoCloseBelowSeverity'`);return r}validateAutoCloseSeverity(t,e){if(t!==void 0&&!v.includes(t))throw new Error(`${e} value '${String(t)}'. Must be one of: ${v.join(", ")}`)}async loadAutoVexConfig(t){let e=await(0,N.readFile)(t,"utf8"),r=JSON.parse(e);if(!r.impactStatement||typeof r.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(r.maxSeverity!==void 0&&!v.includes(r.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(r.maxSeverity)}'. Must be one of: ${v.join(", ")}`);return r}};var k=require("fs/promises"),j=require("path");var _=require("crypto");function M(n){let{cveName:t,purls:e,status:r,impactStatement:i,actionStatement:o,statusNotes:s,justification:l,timestamp:c=new Date().toISOString()}=n,d={vulnerability:{name:t},timestamp:c,products:e.map(y=>({"@id":y})),status:r};return i&&(d.impact_statement=i),o&&(d.action_statement=o),s&&(d.status_notes=s),l&&(d.justification=l),d}var st="https://openvex.dev/ns/v0.2.0";function H(n,t="conterra"){let r=`https://openvex.dev/docs/public/vex-${(0,_.randomUUID)()}`,i=n.timestamp??new Date().toISOString();return{"@context":st,"@id":r,author:t,timestamp:i,last_updated:i,version:1,statements:[n]}}function X(n,t){let e=t.timestamp??new Date().toISOString();return{...n,last_updated:e,version:n.version+1,statements:[...n.statements,t]}}var P=require("fs/promises"),V=require("path");function B(n){let t=n.vulnerability.name;return new Set([t,...n.vulnerability.aliases??[]])}var S=class{constructor(t){this.location=t}location;_content=void 0;_exists=!1;get exists(){return this._exists}get content(){return this._content}set content(t){this._content=t,this._exists=t!==void 0}async read(){let t=await x(this.location);this._content=t??void 0,this._exists=this._content!==void 0}async write(){if(this._content===void 0)throw new Error(`Cannot write VexFile: content is undefined (${this.location})`);await(0,P.mkdir)((0,V.dirname)((0,V.resolve)(this.location)),{recursive:!0}),await L(this.location,this._content)}async delete(){await(0,P.unlink)(this.location),this._exists=!1}upsert(t,e){return this._content===void 0?(this._content=H(t,e),this._exists=!0,{created:!0}):(this._content=X(this._content,t),{created:!1})}addProductId(t,e){this.assertContentLoaded("addProductId");let r=!1;for(let i of this._content.statements){if(!i.products||i.products.some(s=>s["@id"]===e))continue;let o=i.products.findIndex(s=>s["@id"]===t);o!==-1&&(i.products.splice(o+1,0,{"@id":e}),r=!0)}return r}removeProductId(t,e){this.assertContentLoaded("removeProductId");let r=this._content.statements,i=[],o=!1;for(let s of r){if(e&&!B(s).has(e)||!s.products)continue;let l=s.products.findIndex(c=>c["@id"]===t);l!==-1&&(s.products.splice(l,1),o=!0,s.products.length===0&&i.push(s))}if(!o)return"unchanged";for(let s of i)r.splice(r.indexOf(s),1);return r.length===0?"emptied":"changed"}hasStatementForProduct(t){return this.assertContentLoaded("hasStatementForProduct"),this._content.statements.some(e=>e.products?.some(r=>r["@id"]===t)??!1)}assertContentLoaded(t){if(this._content===void 0)throw new Error(`VexFile.${t}(): content is not loaded. Call read() first (${this.location})`)}};var at="HIGH";async function W(n){let{scanSummaryPath:t,autoVexConfigPath:e,vexDir:r,dryRun:i=!1}=n,o=new f(process.cwd()),[s,l,c]=await Promise.all([ct(t),o.loadProjectConfig(),o.loadAutoVexConfig(e)]),d=new Map(l.projects.map(a=>[`${a.name}@${a.version}`,a.purl])),y=c.maxSeverity??at,J=c.subDir??"auto",z=(0,j.resolve)(r,J),p={created:[],updated:[],errors:[]};for(let[a,b]of Object.entries(s.vulnerabilities))try{if(!U(b.severity,y)){console.log(`[skip] ${a}: severity ${b.severity} is not below ${y}`);continue}let g=(0,j.resolve)(z,`${a}.json`),h=s.vulnerabilityToProject[a]??[];if(h.length===0){console.warn(`[warn] ${a}: no affected projects found in summary, skipping`);continue}let w=[];for(let A of h){let F=d.get(A);F===void 0?console.warn(`[warn] ${a}: project "${A}" not found in vuln-scan-conf.json, skipping product`):w.push(F)}if(w.length===0){console.warn(`[warn] ${a}: no resolvable project PURLs, skipping`);continue}if(i){console.log(`[dry-run] Would write auto VEX for ${a} (severity: ${b.severity}) \u2192 ${g}`),console.log(` Affected projects: ${w.join(", ")}`),p.created.push(a);continue}let G=new Date().toISOString(),K=M({cveName:a,purls:w,status:"not_affected",impactStatement:c.impactStatement,timestamp:G}),E=new S(g);await E.read();let{created:I}=E.upsert(K,c.author);await E.write(),console.log(`${I?"[created]":"[updated]"} Auto VEX for ${a} -> ${g}`),I?p.created.push(a):p.updated.push(a)}catch(g){let h=`Failed to process ${a}: ${String(g)}`;console.error(`[error] ${h}`),p.errors.push(h)}return p}async function ct(n){let t=await(0,k.readFile)(n,"utf8");return JSON.parse(t)}var C=class{specs;commandName;helpLines;constructor(t,e,r=[]){this.commandName=t,this.specs=e,this.helpLines=r}parse(t){let e=t.slice(2),r=new Map(this.specs.map(o=>[o.flag,o.defaultValue])),i=!1;for(let o=0;o<e.length;o++){let s=e[o];if(s==="--dry-run"){i=!0;continue}(s==="--help"||s==="-h")&&(this.printHelp(),process.exit(0));let l=this.specs.find(c=>c.flag===s||c.alias===s);l&&e[o+1]?r.set(l.flag,e[++o]):(console.error(`Unknown argument: ${s}`),this.printHelp(),process.exit(1))}return{values:r,dryRun:i}}printHelp(){let t=this.specs.map(e=>` ${(e.alias?`${e.alias}, ${e.flag} <path>`:` ${e.flag} <path>`).padEnd(38)}${e.description}
|
|
4
|
-
${"".padEnd(42)}(default: ${
|
|
5
|
-
`))}};var
|
|
2
|
+
"use strict";var Ae=Object.create;var pe=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var ke=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,Ie=Object.prototype.hasOwnProperty;var Ne=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ke(e))!Ie.call(t,o)&&o!==r&&pe(t,o,{get:()=>e[o],enumerable:!(n=Ce(e,o))||n.enumerable});return t};var me=(t,e,r)=>(r=t!=null?Ae(Oe(t)):{},Ne(e||!t||!t.__esModule?pe(r,"default",{value:t,enumerable:!0}):r,t));var ue=require("path");var C=me(require("path")),ne=require("fs/promises");var w=require("fs/promises");async function W(t){try{return await Te(t)?JSON.parse(await(0,w.readFile)(t,{encoding:"utf-8"})):void 0}catch(e){throw new Error(`Error reading JSON file ${t}: ${e}`,{cause:e})}}async function ge(t,e){let r=JSON.stringify(e,null,4)+`
|
|
3
|
+
`,n=await _e(t,r);await(0,w.writeFile)(t,n,{encoding:"utf-8"})}async function Te(t){try{return await(0,w.access)(t,w.constants.F_OK),!0}catch{return!1}}async function _e(t,e){let r=await Fe();if(!r)return e;let n=await r.resolveConfig(t);return n?await r.format(e,{...n,filepath:t}):e}var De;function Fe(){return De??=import("prettier").catch(()=>{})}var H={UNKNOWN:0,LOW:1,MEDIUM:2,HIGH:3,CRITICAL:4},$=["UNKNOWN","LOW","MEDIUM","HIGH","CRITICAL"];function U(t,e){return H[t]-H[e]}function J(t,e){return H[t]<H[e]}var ie=class t{constructor(e){this.workingDir=e}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(e,r){let n=e.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:r,onNewVulnerabilities:e.onNewVulnerabilities??(e.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:e.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:e.reportNoLongerDetectedVulnerabilities??!0,consoleReport:e.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:e.createSubDirsForProject??!0,mavenRepo:e.mavenRepo??t.DEFAULT_MAVEN_REPO,vexUrls:e.vexUrls??[],vexDir:this.resolvePath(e.vexDir)??(0,C.resolve)(this.workingDir,t.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(e.outDir)??(0,C.resolve)(this.workingDir,t.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(e.cacheDir)??(0,C.resolve)(this.workingDir,t.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(e.scanners,r),projects:this.normalizeProjects(e.projects??[],n)}}normalizeScanners(e,r){return(e??t.DEFAULT_SCANNERS).map(o=>{if(typeof o!="string")throw new Error(`Invalid scanner name '${String(o)}' in configuration file '${r}'`);let i=o.split("@");if(i.length>2)throw new Error(`Invalid scanner name '${o}' in configuration file '${r}'`);return{name:i[0],version:i[1]??""}})}normalizeProjects(e,r){return e.map(n=>{let o=n;if(!o.name)throw new Error("Project name is missing on entry: "+JSON.stringify(o));if(!o.version)throw new Error("Project version is missing on entry: "+JSON.stringify(o));if(!o.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(o));let i={...o,purlAliases:o.purlAliases??[],enabled:o.enabled??!0,silent:o.silent??!1,minimumSeverity:o.minimumSeverity??"UNKNOWN"};return i.sbomFile?{...i,sbomFile:this.resolvePath(i.sbomFile)??i.sbomFile}:{...i,detectNoLongerUsedVulnerabilities:r?i.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(e){if(e)return C.default.isAbsolute(e)?e:(0,C.resolve)(this.workingDir,e)}},T=class{constructor(e){this.workingDir=e;this.normalizer=new ie(e)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let e=(0,C.resolve)(this.workingDir,"vuln-scan-conf.json"),r=await W(e);if(!r)throw new Error(`Missing project configuration file '${e}'`);return this.normalizer.normalize(r,e)}async loadJiraConfig(e){let r=await(0,ne.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.issues&&n.issue&&(n.issues=n.issue),!n.jiraUrl||typeof n.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(n.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(n.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[o,i]of n.issues.entries())i&&typeof i=="object"&&this.validateAutoCloseSeverity(i.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${o}].autoCloseBelowSeverity'`);return n}validateAutoCloseSeverity(e,r){if(e!==void 0&&!$.includes(e))throw new Error(`${r} value '${String(e)}'. Must be one of: ${$.join(", ")}`)}async loadAutoVexConfig(e){let r=await(0,ne.readFile)(e,"utf8"),n=JSON.parse(r);if(!n.impactStatement||typeof n.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(n.maxSeverity!==void 0&&!$.includes(n.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(n.maxSeverity)}'. Must be one of: ${$.join(", ")}`);if(n.projectOverrides!==void 0){if(!Array.isArray(n.projectOverrides))throw new Error("auto-vex-conf.json: 'projectOverrides' must be an array");for(let[o,i]of n.projectOverrides.entries()){if(!i||typeof i!="object")throw new Error(`auto-vex-conf.json: 'projectOverrides[${o}]' must be an object`);let s=i;if(!Array.isArray(s.projects)||s.projects.length===0||!s.projects.every(u=>typeof u=="string"&&u.length>0))throw new Error(`auto-vex-conf.json: 'projectOverrides[${o}].projects' must be a non-empty array of non-empty strings`);if(!$.includes(s.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'projectOverrides[${o}].maxSeverity' value '${String(s.maxSeverity)}'. Must be one of: ${$.join(", ")}`)}}return n}};var $e=require("fs/promises"),B=require("path");var ve=require("crypto");var oe="auto_vex_max_severity=";function se(t){return`${oe}${t}`}function O(t){let e=t.status_notes;if(!e||!e.startsWith(oe))return;let r=e.slice(oe.length).trim();return $.includes(r)?r:void 0}function he(t){let{cveName:e,purls:r,status:n,impactStatement:o,actionStatement:i,statusNotes:s,justification:u,timestamp:f=new Date().toISOString(),autoVexMaxSeverity:a}=t,g={vulnerability:{name:e},timestamp:f,products:r.map(y=>({"@id":y})),status:n};return o&&(g.impact_statement=o),i&&(g.action_statement=i),a?g.status_notes=se(a):s&&(g.status_notes=s),u&&(g.justification=u),g}var Re="https://openvex.dev/ns/v0.2.0";function ye(t,e="conterra"){let n=`https://openvex.dev/docs/public/vex-${(0,ve.randomUUID)()}`,o=t.timestamp??new Date().toISOString();return{"@context":Re,"@id":n,author:e,timestamp:o,last_updated:o,version:1,statements:[t]}}function Se(t,e){let r=e.timestamp??new Date().toISOString();return{...t,last_updated:r,version:t.version+1,statements:[...t.statements,e]}}var K=require("fs/promises"),G=require("path");var we=require("fs/promises"),ae=require("path");async function z(t,e){for(let r of await(0,we.readdir)(t,{withFileTypes:!0}))r.name.endsWith(".json")?await e(new _((0,ae.resolve)(r.parentPath,r.name))):r.isDirectory()&&await z((0,ae.resolve)(r.parentPath,r.name),e)}function xe(t){let e=t.vulnerability.name;return new Set([e,...t.vulnerability.aliases??[]])}var _=class{constructor(e){this.location=e}location;_content=void 0;_exists=!1;get exists(){return this._exists}get content(){return this._content}set content(e){this._content=e,this._exists=e!==void 0}async read(){let e=await W(this.location);this._content=e??void 0,this._exists=this._content!==void 0}async write(){if(this._content===void 0)throw new Error(`Cannot write VexFile: content is undefined (${this.location})`);await(0,K.mkdir)((0,G.dirname)((0,G.resolve)(this.location)),{recursive:!0}),await ge(this.location,this._content)}async delete(){await(0,K.unlink)(this.location),this._exists=!1}upsert(e,r){if(this._content===void 0)return this._content=ye(e,r),this._exists=!0,{created:!0,changed:!0};let n=O(e);if(n!==void 0){let o=this._content.statements.findIndex(i=>i.vulnerability.name===e.vulnerability.name&&i.status===e.status&&O(i)===n);if(o!==-1){let i=this._content.statements[o];return Me(i,e)?{created:!1,changed:!1}:(i.products=e.products,i.impact_statement=e.impact_statement,i.action_statement=e.action_statement,i.justification=e.justification,i.status_notes=e.status_notes,i.timestamp=e.timestamp,this._content.version+=1,this._content.last_updated=e.timestamp??new Date().toISOString(),{created:!1,changed:!0})}}return this._content=Se(this._content,e),{created:!1,changed:!0}}addProductId(e,r){this.assertContentLoaded("addProductId");let n=!1;for(let o of this._content.statements){if(!o.products||o.products.some(s=>s["@id"]===r))continue;let i=o.products.findIndex(s=>s["@id"]===e);i!==-1&&(o.products.splice(i+1,0,{"@id":r}),n=!0)}return n}removeProductId(e,r){this.assertContentLoaded("removeProductId");let n=this._content.statements,o=[],i=!1;for(let s of n){if(r&&!xe(s).has(r)||!s.products)continue;let u=s.products.findIndex(f=>f["@id"]===e);u!==-1&&(s.products.splice(u,1),i=!0,s.products.length===0&&o.push(s))}if(!i)return"unchanged";for(let s of o)n.splice(n.indexOf(s),1);return n.length===0?"emptied":"changed"}hasStatementForProduct(e){return this.assertContentLoaded("hasStatementForProduct"),this._content.statements.some(r=>r.products?.some(n=>n["@id"]===e)??!1)}assertContentLoaded(e){if(this._content===void 0)throw new Error(`VexFile.${e}(): content is not loaded. Call read() first (${this.location})`)}};function Me(t,e){return t.impact_statement!==e.impact_statement||t.action_statement!==e.action_statement||t.justification!==e.justification||t.status_notes!==e.status_notes?!1:Le(t.products,e.products)}function Le(t,e){let r=i=>Array.from(new Set((i??[]).map(s=>s["@id"]).filter(s=>typeof s=="string"))).sort(),n=r(t),o=r(e);return n.length!==o.length?!1:n.every((i,s)=>i===o[s])}function Ue(t){return t.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}function Be(t,e){let r=e.split("*").map(Ue).join(".*");return new RegExp(`^${r}$`).test(t)}function be(t,e){return e.some(r=>Be(t,r))}var Xe="HIGH";function Pe(t){if(t.kind==="default")return"default";let e=t.override,r=e.projects.join(", "),n=e.comment?`, comment: "${e.comment}"`:"";return`override [${r}]${n}`}var Ee=10,We=" ".repeat(Ee);function He(t){return`[${t}]`.padEnd(Ee," ")}function E(t,e,r=[]){let n=`${He(t)}${e}`,o=t==="warn"||t==="error"?console.error:console.log;o(n);for(let i of r)o(`${We}${i}`)}var d={info(t,e=[]){E("info",t,e)},create(t,e=[]){E("create",t,e)},update(t,e=[]){E("update",t,e)},revoke(t,e=[]){E("revoke",t,e)},skip(t,e=[]){E("skip",t,e)},dryRun(t,e=[]){E("dry-run",t,e)},backfill(t,e=[]){E("backfill",t,e)},warn(t,e=[]){E("warn",t,e)},error(t,e=[]){E("error",t,e)},banner(t){let e="\u2500".repeat(Math.max(0,62-t.length-4));console.log(""),console.log(`\u2500\u2500 ${t} ${e}`)}};function I(t){let e=(0,B.relative)(process.cwd(),t);return e===""?".":e.startsWith("..")?t:e.split(/[\\/]/).join("/")}async function je(t){let{scanSummaryPath:e,autoVexConfigPath:r,vexDir:n,dryRun:o=!1,writeMissingMarker:i=!1}=t,s=new T(process.cwd()),[u,f,a]=await Promise.all([Je(e),s.loadProjectConfig(),s.loadAutoVexConfig(r)]),g=new Map(f.projects.map(c=>[`${c.name}@${c.version}`,c.purl])),y=a.maxSeverity??Xe,D=a.subDir??"auto",j=(0,B.resolve)(n,D),F=a.projectOverrides??[],V=c=>{let v={severity:y,source:{kind:"default"}};for(let m of F)be(c,m.projects)&&U(m.maxSeverity,v.severity)<0&&(v={severity:m.maxSeverity,source:{kind:"override",override:m}});return v},x=c=>V(c).severity,l={created:[],updated:[],invalidated:[],markersWritten:[],errors:[],warnings:[],skipped:{atOrAboveThreshold:[],noEligibleProject:[],partial:[]},revokedProducts:0,filesRemoved:0},R=(c,v=[])=>{d.warn(c,v),l.warnings.push(c)};if(i)return d.banner("Marker backfill"),await Ye(j,y,o,l,R),l;d.banner("Invalidation pass"),await ze(j,u,g,y,x,o,l),d.info(`${l.revokedProducts} product(s) revoked across ${l.invalidated.length} CVE(s)`+(l.filesRemoved>0?`, ${l.filesRemoved} file(s) removed`:"")),d.banner("Statement creation");for(let[c,v]of Object.entries(u.vulnerabilities))try{let m=(0,B.resolve)(j,`${c}.json`),b=u.vulnerabilityToProject[c]??[];if(b.length===0){d.skip(`${c}: no affected projects found in summary`),l.skipped.noEligibleProject.push(c);continue}let A=new Map,N=[],h=[],M=!1;for(let p of b){let S=g.get(p);if(S===void 0){R(`${c}: project "${p}" not found in vuln-scan-conf.json, skipping product`),M=!0;continue}let P=V(p);if(!J(v.severity,P.severity)){h.push({projectId:p,effective:P});continue}N.push({projectId:p,purl:S,effective:P});let k=A.get(P.severity);k===void 0?A.set(P.severity,[S]):k.includes(S)||k.push(S)}if(A.size===0){h.length>0?(d.skip(`${c}: severity ${v.severity} meets or exceeds threshold for every eligible project`,h.map(p=>`${p.projectId} -> ${p.effective.severity} (${Pe(p.effective.source)})`)),l.skipped.atOrAboveThreshold.push(c)):M?(d.skip(`${c}: no resolvable project PURLs (see [warn] above)`),l.skipped.noEligibleProject.push(c)):(d.skip(`${c}: no eligible projects`),l.skipped.noEligibleProject.push(c));continue}h.length>0&&l.skipped.partial.push(c);let le=Array.from(A.entries()).sort(([p],[S])=>U(p,S)),q=le.map(([p,S])=>{let P=new Set(N.filter(L=>L.effective.severity===p).map(L=>L.effective.source.kind)),k=P.size===1?P.has("default")?" (default)":" (override)":" (mixed)";return`\u2022 max severity ${p}${k}: ${S.join(", ")}`}),Q=h.map(p=>`excluded: ${p.projectId} -> ${p.effective.severity} (${Pe(p.effective.source)})`);if(o){let p=h.length>0?` (partial: ${h.length} project(s) excluded)`:"";d.dryRun(`${c}${p} -> ${I(m)}`,[`severity=${v.severity}`,...q,...Q]),l.created.push(c);continue}let Z=new _(m);await Z.read();let X=!1,ee=!1,de=!1,Ve=new Date().toISOString();for(let[p,S]of le){let P=he({cveName:c,purls:S,status:"not_affected",impactStatement:a.impactStatement,timestamp:Ve,autoVexMaxSeverity:p}),{created:k,changed:L}=Z.upsert(P,a.author);L&&(de=!0,k?X=!0:ee=!0)}let fe=h.length>0?` (partial: ${h.length} project(s) excluded)`:"";if(!de){d.skip(`${c}${fe} -> ${I(m)}: unchanged`,[`severity=${v.severity}`,...q,...Q]);continue}await Z.write();let te=`${c}${fe} -> ${I(m)}`,re=[`severity=${v.severity}`,...q,...Q];X&&ee?(d.create(te,re),d.update(`${c}: also updated existing statement(s)`)):X?d.create(te,re):d.update(te,re),X?l.created.push(c):ee&&l.updated.push(c)}catch(m){let b=`Failed to process ${c}: ${String(m)}`;d.error(b),l.errors.push(b)}return l}async function Je(t){let e=await(0,$e.readFile)(t,"utf8");return JSON.parse(e)}async function ze(t,e,r,n,o,i,s){let u=Ge(e,r),f=Ke(r,o);try{await z(t,async a=>{if(await a.read(),!a.content)return;let y=a.content.statements.slice(),D=new Set,j=!1,F=!1;for(let V of y){if(F)break;let x=O(V)??n,l=V.vulnerability.name,R=u.get(l);if(!R)continue;let c=[];for(let v of V.products??[]){let m=v["@id"];if(!m)continue;let b=R.get(m);if(b===void 0)continue;let A=f.get(m),N=A!==void 0&&U(A,x)<0?A:x;if(!J(b,N)){c.push(m);let h=N===x?`severity ${b} meets or exceeds recorded threshold ${x}`:`severity ${b} meets or exceeds effective threshold ${N} (override stricter than recorded ${x})`,M=i?`would revoke ${l} on ${m}`:`revoked ${l} on ${m}`;i?d.dryRun(M,[h]):d.revoke(M,[h]),s.revokedProducts++}}if(c.length!==0){if(D.add(l),i){j=!0;continue}for(let v of c){let m=a.removeProductId(v,l);m==="emptied"?(F=!0,j=!0):m==="changed"&&(j=!0)}}}if(D.size>0){let V=new Set(s.invalidated);for(let x of D)V.has(x)||s.invalidated.push(x)}i||!j||(F?(await a.delete(),s.filesRemoved++,d.revoke(`removed empty auto VEX file ${I(a.location)}`)):await a.write())})}catch(a){if(a.code!=="ENOENT"){let g=`Auto-VEX invalidation pass failed: ${String(a)}`;d.error(g),s.errors.push(g)}}}function Ke(t,e){let r=new Map;for(let[n,o]of t){let i=e(n),s=r.get(o);(s===void 0||U(i,s)<0)&&r.set(o,i)}return r}function Ge(t,e){let r=new Map;for(let[n,o]of Object.entries(t.vulnerabilities)){let i=t.vulnerabilityToProject[n]??[],s=new Map;for(let u of i){let f=e.get(u);f&&s.set(f,o.severity)}s.size>0&&r.set(n,s)}return r}async function Ye(t,e,r,n,o){let i=se(e);try{await z(t,async s=>{if(await s.read(),!s.content)return;let u=!1,f=0,a=0;for(let y of s.content.statements)if(O(y)===void 0){if(y.status_notes){a++;continue}r||(y.status_notes=i),f++,u=!0}if(a>0&&o(`${I(s.location)}: skipped ${a} statement(s) that already have manual status notes`),!u)return;n.markersWritten.push(s.location);let g=r?`would stamp ${f} statement(s) in ${I(s.location)} with ${i}`:`${I(s.location)}: stamped ${f} statement(s) with ${i}`;r?d.dryRun(g):d.backfill(g),!r&&(s.content.version+=1,s.content.last_updated=new Date().toISOString(),await s.write())})}catch(s){if(s.code!=="ENOENT"){let u=`Auto-VEX marker backfill failed: ${String(s)}`;d.error(u),n.errors.push(u)}}}var ce={flag:"--dry-run",description:"Print what would happen without making changes"},Y=class{specs;booleanSpecs;commandName;helpLines;constructor(e,r,n=[],o=[]){this.commandName=e,this.specs=r;let i=o.some(s=>s.flag===ce.flag);this.booleanSpecs=i?o:[...o,ce],this.helpLines=n}parse(e){let r=e.slice(2),n=new Map(this.specs.map(i=>[i.flag,i.defaultValue])),o=new Map(this.booleanSpecs.map(i=>[i.flag,!1]));for(let i=0;i<r.length;i++){let s=r[i];(s==="--help"||s==="-h")&&(this.printHelp(),process.exit(0));let u=this.booleanSpecs.find(a=>a.flag===s||a.alias===s);if(u){o.set(u.flag,!0);continue}let f=this.specs.find(a=>a.flag===s||a.alias===s);f&&r[i+1]?n.set(f.flag,r[++i]):(console.error(`Unknown argument: ${s}`),this.printHelp(),process.exit(1))}return{values:n,dryRun:o.get(ce.flag)===!0,booleans:o}}printHelp(){let e=this.specs.map(n=>` ${(n.alias?`${n.alias}, ${n.flag} <path>`:` ${n.flag} <path>`).padEnd(38)}${n.description}
|
|
4
|
+
${"".padEnd(42)}(default: ${n.defaultValue})`),r=this.booleanSpecs.map(n=>` ${(n.alias?`${n.alias}, ${n.flag}`:` ${n.flag}`).padEnd(38)}${n.description}`);console.log([`Usage: ${this.commandName} [options]`,"","Options:",...e,...r," -h, --help"+" ".repeat(32)+"Show this help message",...this.helpLines].join(`
|
|
5
|
+
`))}};var qe=new Y("ct-vuln-auto-vex",[{flag:"--auto-vex-config",alias:"-c",description:"Path to auto-vex-conf.json configuration file",defaultValue:(0,ue.join)(process.cwd(),"auto-vex-conf.json")},{flag:"--summary",alias:"-s",description:"Path to scan-summary.json produced by ct-vuln-scan",defaultValue:(0,ue.join)(process.cwd(),"output","scan-summary.json")}],["","Configuration (auto-vex-conf.json):"," impactStatement Required. Text written as impact_statement in each VEX statement."," maxSeverity Optional. Exclusive severity threshold. CVEs with a severity"," strictly below this level receive an auto-generated statement."," Values: UNKNOWN | LOW | MEDIUM | HIGH | CRITICAL (default: HIGH)"," author Optional. Author field in the OpenVEX document (default: conterra)"," subDir Optional. Sub-directory of vexDir for auto files (default: auto)"],[{flag:"--write-missing-marker",description:"Backfill auto_vex_max_severity into auto VEX statements that lack it, then exit"}]);(async()=>{let{values:t,dryRun:e,booleans:r}=qe.parse(process.argv),n=t.get("--auto-vex-config"),o=t.get("--summary"),i=r.get("--write-missing-marker")===!0,s=process.cwd(),u=i?" [write-missing-marker]":e?" [dry-run]":"";console.log(`Auto VEX Creator${u}`),console.log(` auto-vex-config: ${n}`),console.log(` summary: ${o}`);try{let f=await new T(s).loadProjectConfig();console.log(` vex-dir: ${f.vexDir}`);let a=await je({scanSummaryPath:o,autoVexConfigPath:n,vexDir:f.vexDir,dryRun:e,writeMissingMarker:i});if(console.log(""),console.log(`=== Auto VEX Creator Summary${u} ===`),i)console.log(` Files stamped : ${a.markersWritten.length}`);else{let g=a.skipped.atOrAboveThreshold.length+a.skipped.noEligibleProject.length;console.log(` Created : ${a.created.length}`),console.log(` Updated : ${a.updated.length}`),console.log(` Invalidated : ${a.invalidated.length} CVE (${a.revokedProducts} product(s), ${a.filesRemoved} file(s) removed)`),console.log(` Skipped (CVEs) : ${g}`),console.log(` at or above threshold : ${a.skipped.atOrAboveThreshold.length}`),console.log(` no eligible project : ${a.skipped.noEligibleProject.length}`),console.log(` partial (some projects excluded): ${a.skipped.partial.length}`)}console.log(` Warnings : ${a.warnings.length}`),console.log(` Errors : ${a.errors.length}`),e&&(console.log(""),console.log("No files were written (dry-run). Re-run without --dry-run to apply.")),a.errors.length>0&&(process.exitCode=1)}catch(f){console.error(`Fatal error: ${String(f)}`),process.exit(1)}})();
|
package/dist/jira-reporter.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var
|
|
3
|
-
`,n+=i)}return r.delete(o.purl),n}function
|
|
4
|
-
`),
|
|
5
|
-
`)}function
|
|
2
|
+
"use strict";var Se=Object.create;var K=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var $e=Object.getOwnPropertyNames;var je=Object.getPrototypeOf,be=Object.prototype.hasOwnProperty;var Pe=(o,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of $e(e))!be.call(o,n)&&n!==r&&K(o,n,{get:()=>e[n],enumerable:!(t=Ce(e,n))||t.enumerable});return o};var xe=(o,e,r)=>(r=o!=null?Se(je(o)):{},Pe(e||!o||!o.__esModule?K(r,"default",{value:o,enumerable:!0}):r,o));var z=require("path"),me=require("fs/promises"),ye=require("zx");var fe=require("fs/promises");var X={UNKNOWN:0,LOW:1,MEDIUM:2,HIGH:3,CRITICAL:4},y=["UNKNOWN","LOW","MEDIUM","HIGH","CRITICAL"];function J(o,e){return X[o]<X[e]}function $(...o){return{type:"doc",version:1,content:o}}function S(o,e){return{type:"heading",attrs:{level:o},content:[{type:"text",text:e}]}}function R(o,e="text"){return{type:"codeBlock",attrs:{language:e},content:[{type:"text",text:o}]}}function q(o){return{type:"bulletList",content:o.map(e=>({type:"listItem",content:[{type:"paragraph",content:[{type:"text",text:e}]}]}))}}function Y(o){return{type:"bulletList",content:o.map(e=>({type:"listItem",content:[{type:"paragraph",content:[{type:"text",text:e,marks:[{type:"link",attrs:{href:e}}]}]}]}))}}function I(o,...e){return{type:"expand",attrs:{title:o},content:e}}function f(o){return{type:"paragraph",content:[{type:"text",text:o,marks:[{type:"em"}]}]}}var h=require("fs/promises");async function Z(o){try{return await Re(o)?JSON.parse(await(0,h.readFile)(o,{encoding:"utf-8"})):void 0}catch(e){throw new Error(`Error reading JSON file ${o}: ${e}`,{cause:e})}}async function Re(o){try{return await(0,h.access)(o,h.constants.F_OK),!0}catch{return!1}}function Q(o,e){return`Basic ${Buffer.from(`${o}:${e}`).toString("base64")}`}var T=class{authHeader;baseUrl;constructor(e,r,t){this.baseUrl=e.replace(/\/$/,""),this.authHeader=Q(r,t)}get headers(){return{Authorization:this.authHeader,"Content-Type":"application/json",Accept:"application/json"}}async safeJson(e,r){let t=await e.text();try{return JSON.parse(t)}catch{let n=t.slice(0,500).replace(/\s+/g," ").trim();throw new Error(`${r}: expected JSON but got (HTTP ${e.status}): ${n}`)}}async findExistingIssue(e,r){let t=e.replace(/"/g,'\\"'),n=r.replace(/"/g,'\\"'),s=`project = "${t}" AND summary ~ "\\"${n}\\""`,c=`${this.baseUrl}/rest/api/3/search/jql?jql=${encodeURIComponent(s)}&maxResults=1&fields=summary,labels,status`,i=await fetch(c,{method:"GET",headers:this.headers});if(!i.ok){let l=await i.text();throw new Error(`Jira search failed (${i.status}): ${l}`)}let d=(await this.safeJson(i,"Jira search")).issues[0];return d?{key:d.key,summary:d.fields?.summary??"",labels:d.fields?.labels??[],statusCategory:d.fields?.status?.statusCategory?.key??"new"}:null}async createIssue(e){let r={project:{key:e.projectKey},issuetype:{name:e.issueType},summary:e.summary,description:e.description};e.labels&&e.labels.length>0&&(r.labels=e.labels),e.sprintId!=null&&(r.customfield_10020=e.sprintId);let t={fields:r},n=await fetch(`${this.baseUrl}/rest/api/3/issue`,{method:"POST",headers:this.headers,body:JSON.stringify(t)});if(!n.ok){let c=await n.text();throw new Error(`Jira create issue failed (${n.status}): ${c}`)}return(await this.safeJson(n,"Jira create issue")).key}async addLabels(e,r){if(r.length===0)return;let t={update:{labels:r.map(s=>({add:s}))}},n=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}`,{method:"PUT",headers:this.headers,body:JSON.stringify(t)});if(!n.ok){let s=await n.text();throw new Error(`Jira add labels failed (${n.status}): ${s}`)}}async updateIssueSummary(e,r){let t={fields:{summary:r}},n=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}`,{method:"PUT",headers:this.headers,body:JSON.stringify(t)});if(!n.ok){let s=await n.text();throw new Error(`Jira update summary failed (${n.status}): ${s}`)}}async setSprint(e,r){let t={fields:{customfield_10020:r}},n=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}`,{method:"PUT",headers:this.headers,body:JSON.stringify(t)});if(!n.ok){let s=await n.text();throw new Error(`Jira set sprint failed (${n.status}): ${s}`)}}async addComment(e,r){let t=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}/comment`,{method:"POST",headers:this.headers,body:JSON.stringify({body:r})});if(!t.ok){let n=await t.text();throw new Error(`Jira add comment failed (${t.status}): ${n}`)}}async getTransitions(e){let r=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}/transitions`,{method:"GET",headers:this.headers});if(!r.ok){let n=await r.text();throw new Error(`Jira get transitions failed (${r.status}): ${n}`)}return(await this.safeJson(r,"Jira transitions lookup")).transitions.map(n=>({id:n.id,name:n.name,toStatusName:n.to?.name??"",toStatusCategory:n.to?.statusCategory?.key??""}))}async transitionIssue(e,r){let t=await fetch(`${this.baseUrl}/rest/api/3/issue/${e}/transitions`,{method:"POST",headers:this.headers,body:JSON.stringify({transition:{id:r}})});if(!t.ok){let n=await t.text();throw new Error(`Jira transition issue failed (${t.status}): ${n}`)}}async attachMarkdown(e,r,t){let n=`${this.baseUrl}/rest/api/3/issue/${e}/attachments`,s=new FormData;s.append("file",new Blob([t],{type:"text/markdown"}),r);let c=await fetch(n,{method:"POST",headers:{Authorization:this.authHeader,"X-Atlassian-Token":"no-check"},body:s});if(!c.ok){let i=await c.text();throw new Error(`Jira attach file failed (${c.status}): ${i}`)}}async getActiveSprintId(e){let r=`${this.baseUrl}/rest/agile/1.0/board/${e}/sprint?state=active&maxResults=1`,t=await fetch(r,{method:"GET",headers:this.headers});if(!t.ok){let s=await t.text();throw new Error(`Jira agile sprint lookup failed (${t.status}): ${s}`)}return(await this.safeJson(t,"Jira sprint lookup")).values[0]?.id??null}};function Ie(o){return o.replace(/[.+?^${}()|[\]\\]/g,"\\$&")}function Te(o,e){let r=e.split("*").map(Ie).join(".*");return new RegExp(`^${r}$`).test(o)}function B(o,e){return e.some(r=>Te(o,r))}function ee(o,e=""){return te(o,e,new Set,new Set)}function te(o,e="",r,t){let n=`${e}- ${o.purl}`;if(r.has(o.purl))return n+=" (cycle detected)",n;if(t.has(o.purl))return n+=" (deduplicated)",n;t.add(o.purl),r.add(o.purl);let s=r.size===1;for(let c of o.usedBy){let i=te(c,e+(s?" ":" "),r,t);i!==""&&(n+=`
|
|
3
|
+
`,n+=i)}return r.delete(o.purl),n}function re(o){let e=o.split(/\r?\n/),r=[],t=0;for(;t<e.length;){let n=e[t],s=n.match(/^```(\w*)$/);if(s){let a=s[1]??"text",d=[];for(t++;t<e.length&&!e[t].startsWith("```");)d.push(e[t]),t++;t++,r.push(R(d.join(`
|
|
4
|
+
`),a));continue}let c=n.match(/^(#{1,3})\s+(.+)$/);if(c){let a=Math.min(c[1].length,3);r.push({type:"heading",attrs:{level:a},content:[{type:"text",text:c[2].trim()}]}),t++;continue}if(/^[-*]\s/.test(n)){let a=[];for(;t<e.length&&/^[-*]\s/.test(e[t]);){let d=e[t].replace(/^[-*]\s+/,"");a.push({type:"listItem",content:[{type:"paragraph",content:O(d)}]}),t++}r.push({type:"bulletList",content:a});continue}if(/^\d+\.\s/.test(n)){let a=[];for(;t<e.length&&/^\d+\.\s/.test(e[t]);){let d=e[t].replace(/^\d+\.\s+/,"");a.push({type:"listItem",content:[{type:"paragraph",content:O(d)}]}),t++}r.push({type:"orderedList",content:a});continue}if(n.trim()===""){t++;continue}let i=[];for(;t<e.length&&e[t].trim()!==""&&!/^(#{1,3}\s|[-*]\s|\d+\.\s|```)/.test(e[t]);)i.push(e[t]),t++;if(i.length>0){let a=[];for(let d=0;d<i.length;d++)a.push(...O(i[d])),d<i.length-1&&a.push({type:"hardBreak"});r.push({type:"paragraph",content:a})}}return r}function O(o){let e=[],r=/(\*\*(.+?)\*\*|\*(.+?)\*|`(.+?)`|_(.+?)_)/g,t=0,n;for(;(n=r.exec(o))!==null;)n.index>t&&e.push({type:"text",text:o.slice(t,n.index)}),n[2]!==void 0?e.push({type:"text",text:n[2],marks:[{type:"strong"}]}):n[3]!==void 0?e.push({type:"text",text:n[3],marks:[{type:"em"}]}):n[4]!==void 0?e.push({type:"text",text:n[4],marks:[{type:"code"}]}):n[5]!==void 0&&e.push({type:"text",text:n[5],marks:[{type:"em"}]}),t=n.index+n[0].length;return t<o.length&&e.push({type:"text",text:o.slice(t)}),e.length>0?e:[{type:"text",text:o}]}var Ne=2e4;function U(o){let e=o.title?`: ${o.title}`:"";return`[${o.severity}] ${o.id}${e}`}function ne(o){let e=o.match(/^\[([A-Z]+)\]\s+(\S+?)(?::\s*(.*))?$/);if(!e)return;let[,r,t,n]=e;if(!(!r||!t)&&y.includes(r))return{severity:r,vulnId:t,title:n??""}}function oe(o,e,r=new Map){let t=[];if(t.push(S(1,"Informationen zur Schwachstelle")),t.push(f("Diese Informationen wurden automatisch generiert.")),o.refs&&o.refs.length>0&&t.push(Y(o.refs)),o.description){let n=re(o.description);t.push(I("Beschreibung",...n))}return t.push(S(2,"Betroffene Artefakte")),o.components&&o.components.length>0?t.push(q(o.components)):t.push(f("Keine Komponenten bekannt.")),t.push(S(2,"Gemeldet f\xFCr")),ie(t,e,r),t.push(S(1,"Einwertung")),t.push(f("Einwertung des CVE in Bezug auf die gemeldeten Projekte/Produkte. Dies kann eine Bewertung der Schwere, der Auswirkungen und der Wahrscheinlichkeit eines Angriffs umfassen.")),t.push(S(1,"Betroffen sind")),t.push(f("Abschlie\xDFende Darstellung, welche Projekte/Produkte tats\xE4chlich betroffen oder nicht betroffen sind.")),t.push(S(1,"Ma\xDFnahmen")),t.push(f("\xDCbersicht der zu ergreifenden Ma\xDFnahmen, um den CVE zu beheben oder zu mitigieren. Dies kann Patches, Updates oder Konfigurations\xE4nderungen umfassen.")),$(...t)}function se(o,e=new Map){let r=[];return r.push(f("Diese Projekte sind ebenfalls von dieser Schwachstelle betroffen und wurden automatisch erg\xE4nzt.")),r.push(S(2,"Zus\xE4tzlich gemeldet f\xFCr")),ie(r,o,e),$(...r)}function ie(o,e,r){let t=0;for(let n of e.slice().sort()){o.push({type:"paragraph",content:[{type:"text",text:n,marks:[{type:"strong"}]}]});let s=r.get(n);if(s&&s.length>0){let c=ce(s);c&&(t+=c.length,t>Ne?o.push(I("Verwendungsbaum",f("Gesamtgr\xF6\xDFe der Verwendungsb\xE4ume \xFCberschreitet Limit. Siehe Issue-Attachments f\xFCr vollst\xE4ndige B\xE4ume."))):o.push(I("Verwendungsbaum",R(c))))}}}function ae(o,e){if(e.size===0)return"";let r=[`# Verwendungsb\xE4ume f\xFCr ${o}`,""];for(let[t,n]of[...e.entries()].sort(([s],[c])=>s.localeCompare(c))){r.push(`## ${t}`,"");let s=ce(n);s&&r.push("```",s,"```"),r.push("")}return r.join(`
|
|
5
|
+
`)}function ce(o){return!o||o.length===0?"":o.map(e=>ee(e,"")).join(`
|
|
6
6
|
|
|
7
|
-
`)}var L="proj:";function U(o){let e=o.replace(/@/g,"_v").replace(/\s+/g,"_");return`${L}${e}`}function Se(o){if(!o.startsWith(L))return null;let e=o.slice(L.length),r=e.lastIndexOf("_v");return r<0?e:e.slice(0,r)+"@"+e.slice(r+2)}function re(o){let e=new Set;if(!o)return e;for(let r of o){let t=Se(r);t!==null&&e.add(t)}return e}var T=class{constructor(e,r,t){this.config=e;this.client=new N(e.jiraUrl,r,t)}config;client;activeSprintCache=new Map;async report(e,r){let t={created:[],updated:[],skipped:[],errors:[]};for(let[n,s]of Object.entries(e.vulnerabilities)){let a=e.vulnerabilityToProject[n]??[];for(let i of this.config.issues){let l=a.filter(c=>E(c,i.reportProjects));if(l.length!==0)try{let c=await this.client.findExistingIssue(i.jiraProject,n);c?await this.handleExistingIssue(e,s,c,i,l,r,t):await this.handleNewIssue(e,n,s,i,l,r,t)}catch(c){let d=`Failed to process ${n} for project ${i.jiraProject}: ${String(c)}`;console.error(`[error] ${d}`),t.errors.push(d)}}}return t}async handleNewIssue(e,r,t,n,s,a,i){let l=K(t),c=this.resolveAutoCloseThreshold(n),d=c!=null&&R(t.severity,c);if(a){console.log(`[dry-run] Would create issue in ${n.jiraProject}: "${l}"`),console.log(` Matching projects: ${s.join(", ")}`),d&&console.log(`[dry-run] Would auto-close ${n.jiraProject}::${r} (severity=${t.severity} below ${c})`),i.created.push(`${n.jiraProject}::${r}`);return}let{activeSprintId:g,allLabels:y}=await this.resolveBoardRouting(n,s),w=this.collectProjectComponentTrees(e,s,t.components),k=Q(t,s,w),C=[...y,...s.map(U)],h=await this.client.createIssue({projectKey:n.jiraProject,issueType:n.issueType,summary:l,description:k,labels:C.length>0?C:void 0,sprintId:g});if(w.size>0){let $=ee(r,w);if($){let x=`${r}-dependency-trees.md`;await this.client.attachMarkdown(h,x,$),console.log(`[attached] ${x} to ${h}`)}}console.log(`[created] ${h} in ${n.jiraProject}: "${l}"`),i.created.push(h),d&&await this.autoCloseIssue(h,t.severity,c)}async handleExistingIssue(e,r,t,n,s,a,i){let l=re(t.labels),c=s.filter(S=>!l.has(S));if(c.length===0){console.log(`[skip] ${t.key} already covers all matching projects`),i.skipped.push(t.key);return}let d=t.statusCategory==="done",g=this.resolveAutoCloseThreshold(n),y=g!=null&&R(r.severity,g),w=d&&!y;if(a){let S=w?" and re-open + re-add to active sprint":d?" (kept closed: sub-threshold)":"";console.log(`[dry-run] Would update ${t.key}: add project tag(s) ${c.join(", ")}`+S),i.updated.push(t.key);return}let{activeSprintId:k,allLabels:C}=await this.resolveBoardRouting(n,s),h=this.collectProjectComponentTrees(e,c,r.components),$=[...C,...c.map(U)],x=new Set(t.labels),M=$.filter(S=>!x.has(S));M.length>0&&await this.client.addLabels(t.key,M);let ae=Y(c,h);await this.client.addComment(t.key,ae),console.log(`[updated] ${t.key}: added project(s) ${c.join(", ")}`),d&&y?console.log(`[kept-closed] ${t.key} (severity ${r.severity} below auto-close threshold ${g})`):d&&await this.reopenAndReassignSprint(t.key,k),i.updated.push(t.key)}async reopenAndReassignSprint(e,r){let t;try{t=await this.client.getTransitions(e)}catch(s){console.warn(`[warn] Could not list transitions for ${e}: ${String(s)}`);return}let n=t.find(s=>s.toStatusCategory==="new");if(!n){console.warn(`[warn] ${e} is closed but no transition leading to a non-done status is available; leaving status unchanged`);return}try{await this.client.transitionIssue(e,n.id),console.log(`[reopened] ${e} via transition "${n.name}"`)}catch(s){console.warn(`[warn] Could not transition ${e} to a non-done status: ${String(s)}`);return}if(r!=null)try{await this.client.setSprint(e,r),console.log(`[sprint] ${e} added to active sprint ${r}`)}catch(s){console.warn(`[warn] Could not set sprint for ${e}: ${String(s)}`)}}resolveAutoCloseThreshold(e){return e.autoCloseBelowSeverity??this.config.autoCloseBelowSeverity}async autoCloseIssue(e,r,t){let n;try{n=await this.client.getTransitions(e)}catch(i){console.warn(`[warn] Could not list transitions for ${e} (auto-close): ${String(i)}`);return}let s=n.filter(i=>i.toStatusCategory==="done"),a=s.find(i=>i.toStatusName.toLowerCase()==="closed")??s.find(i=>{let l=i.name.toLowerCase();return l==="close"||l==="closed"})??s[0];if(!a){console.warn(`[warn] ${e} has no transition leading to a done status; cannot auto-close`);return}try{await this.client.transitionIssue(e,a.id),console.log(`[auto-closed] ${e} (severity=${r}, threshold=${t}) via transition "${a.name}"`)}catch(i){console.warn(`[warn] Could not transition ${e} to a done status: ${String(i)}`);return}try{let i=v(p(`Automatisch geschlossen: Schwere ${r} liegt unterhalb der konfigurierten Auto-Close-Schwelle ${t}.`));await this.client.addComment(e,i)}catch(i){console.warn(`[warn] Could not post auto-close comment on ${e}: ${String(i)}`)}}async resolveBoardRouting(e,r){let t,n=[],s=!1;for(let i of e.addToBoard??[]){let l=i.matchProjects??["*"];if(r.some(d=>E(d,l)))if(i.sprintBoardId!=null){if(!s){s=!0;let d=i.sprintBoardId;if(!this.activeSprintCache.has(d)){let g=await this.client.getActiveSprintId(d).catch(y=>(console.warn(`[warn] Could not resolve active sprint for boardId ${d}: ${String(y)}`),null));this.activeSprintCache.set(d,g)}t=this.activeSprintCache.get(d)??void 0,i.issueLabels&&n.push(...i.issueLabels)}}else i.issueLabels&&n.push(...i.issueLabels)}let a=[...e.issueLabels??[],...n];return{activeSprintId:t,allLabels:a}}collectProjectComponentTrees(e,r,t){let n=new Map;if(!e.projectsToComponents)return n;for(let s of r){let a=e.projectsToComponents[s]??{},i=[];for(let l of t){let c=a[l];c&&i.push(c)}i.length>0&&n.set(s,i)}return n}};var m=me(require("path")),B=require("fs/promises");var D=class o{constructor(e){this.workingDir=e}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(e,r){let t=e.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:r,onNewVulnerabilities:e.onNewVulnerabilities??(e.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:e.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:e.reportNoLongerDetectedVulnerabilities??!0,consoleReport:e.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:e.createSubDirsForProject??!0,mavenRepo:e.mavenRepo??o.DEFAULT_MAVEN_REPO,vexUrls:e.vexUrls??[],vexDir:this.resolvePath(e.vexDir)??(0,m.resolve)(this.workingDir,o.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(e.outDir)??(0,m.resolve)(this.workingDir,o.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(e.cacheDir)??(0,m.resolve)(this.workingDir,o.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(e.scanners,r),projects:this.normalizeProjects(e.projects??[],t)}}normalizeScanners(e,r){return(e??o.DEFAULT_SCANNERS).map(n=>{if(typeof n!="string")throw new Error(`Invalid scanner name '${String(n)}' in configuration file '${r}'`);let s=n.split("@");if(s.length>2)throw new Error(`Invalid scanner name '${n}' in configuration file '${r}'`);return{name:s[0],version:s[1]??""}})}normalizeProjects(e,r){return e.map(t=>{let n=t;if(!n.name)throw new Error("Project name is missing on entry: "+JSON.stringify(n));if(!n.version)throw new Error("Project version is missing on entry: "+JSON.stringify(n));if(!n.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(n));let s={...n,purlAliases:n.purlAliases??[],enabled:n.enabled??!0,silent:n.silent??!1,minimumSeverity:n.minimumSeverity??"UNKNOWN"};return s.sbomFile?{...s,sbomFile:this.resolvePath(s.sbomFile)??s.sbomFile}:{...s,detectNoLongerUsedVulnerabilities:r?s.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(e){if(e)return m.default.isAbsolute(e)?e:(0,m.resolve)(this.workingDir,e)}},I=class{constructor(e){this.workingDir=e;this.normalizer=new D(e)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let e=(0,m.resolve)(this.workingDir,"vuln-scan-conf.json"),r=await H(e);if(!r)throw new Error(`Missing project configuration file '${e}'`);return this.normalizer.normalize(r,e)}async loadJiraConfig(e){let r=await(0,B.readFile)(e,"utf8"),t=JSON.parse(r);if(!t.issues&&t.issue&&(t.issues=t.issue),!t.jiraUrl||typeof t.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(t.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(t.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[n,s]of t.issues.entries())s&&typeof s=="object"&&this.validateAutoCloseSeverity(s.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${n}].autoCloseBelowSeverity'`);return t}validateAutoCloseSeverity(e,r){if(e!==void 0&&!b.includes(e))throw new Error(`${r} value '${String(e)}'. Must be one of: ${b.join(", ")}`)}async loadAutoVexConfig(e){let r=await(0,B.readFile)(e,"utf8"),t=JSON.parse(r);if(!t.impactStatement||typeof t.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(t.maxSeverity!==void 0&&!b.includes(t.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(t.maxSeverity)}'. Must be one of: ${b.join(", ")}`);return t}};async function oe(o){let{scanSummaryPath:e,jiraConfigPath:r,jiraUser:t,jiraApiToken:n,dryRun:s=!1}=o,a=new I(process.cwd()),[i,l]=await Promise.all([be(e),a.loadJiraConfig(r)]);return new T(l,t,n).report(i,s)}async function be(o){let e=await(0,ne.readFile)(o,"utf8");return JSON.parse(e)}var A=class{specs;commandName;helpLines;constructor(e,r,t=[]){this.commandName=e,this.specs=r,this.helpLines=t}parse(e){let r=e.slice(2),t=new Map(this.specs.map(s=>[s.flag,s.defaultValue])),n=!1;for(let s=0;s<r.length;s++){let a=r[s];if(a==="--dry-run"){n=!0;continue}(a==="--help"||a==="-h")&&(this.printHelp(),process.exit(0));let i=this.specs.find(l=>l.flag===a||l.alias===a);i&&r[s+1]?t.set(i.flag,r[++s]):(console.error(`Unknown argument: ${a}`),this.printHelp(),process.exit(1))}return{values:t,dryRun:n}}printHelp(){let e=this.specs.map(r=>` ${(r.alias?`${r.alias}, ${r.flag} <path>`:` ${r.flag} <path>`).padEnd(38)}${r.description}
|
|
8
|
-
${"".padEnd(42)}(default: ${
|
|
9
|
-
`))}};
|
|
7
|
+
`)}var D="proj:";function M(o){let e=o.replace(/@/g,"_v").replace(/\s+/g,"_");return`${D}${e}`}function Ae(o){if(!o.startsWith(D))return null;let e=o.slice(D.length),r=e.lastIndexOf("_v");return r<0?e:e.slice(0,r)+"@"+e.slice(r+2)}function de(o){let e=new Set;if(!o)return e;for(let r of o){let t=Ae(r);t!==null&&e.add(t)}return e}function Ee(o){let e=o.severityChange,r=o.newProjects;return e&&r&&r.length>0?`Issue wieder ge\xF6ffnet, da sich der Schweregrad von ${e.from} auf ${e.to} ge\xE4ndert hat und zus\xE4tzlich neue betroffene Projekte gefunden wurden: ${r.join(", ")}.`:e?`Issue wieder ge\xF6ffnet: Schweregrad hat sich von ${e.from} auf ${e.to} ge\xE4ndert. Eine ggf. bestehende automatische VEX-Ausnahme ist nicht mehr g\xFCltig und sollte erneut bewertet werden.`:r&&r.length>0?`Issue wieder ge\xF6ffnet, da die Schwachstelle nun zus\xE4tzlich folgende Projekte betrifft: ${r.join(", ")}. Bitte erneut bewerten, ob die urspr\xFCngliche L\xF6sung/Mitigation weiterhin ausreicht.`:"Issue wieder ge\xF6ffnet."}function ke(o){let e=[];return o.severityChange&&e.push(`severity ${o.severityChange.from}->${o.severityChange.to}`),o.newProjects&&o.newProjects.length>0&&e.push(`new projects: ${o.newProjects.join(", ")}`),e.join(" + ")||"unspecified"}var le=10,pe=" ".repeat(le);function F(o){return`[${o}]`.padEnd(le," ")}function ue(o){return o==="warn"?console.warn:o==="error"?console.error:console.log}function Le(o,e,r=[]){let t=ue(o);t(`${F(o)}${e}`);for(let n of r)t(`${pe}${n}`)}function Je(o){let e="\u2500".repeat(Math.max(0,62-o.length-4));console.log(""),console.log(`\u2500\u2500 ${o} ${e}`)}var V=class{vulnId;jiraProject;severity;issueKey;kind="skip";header="";details=[];constructor(e,r,t){this.vulnId=e,this.jiraProject=r,this.severity=t}setOutcome(e,r){this.kind=e,this.header=this.composeHeader(r)}detail(e,r){this.details.push(`${e.padEnd(9," ")}: ${r}`)}note(e){this.details.push(e)}warn(e,r){console.warn(`${F("warn")}${e}`),this.detail("warn",e),r.warnings.push(e)}flush(){let e=ue(this.kind);e(`${F(this.kind)}${this.header}`);for(let r of this.details)e(`${pe}${r}`)}composeHeader(e){let r=this.issueKey??"<new>",t=e?` ${e}`:"",n=r.padEnd(12," ");return`${this.vulnId} -> ${n} in ${this.jiraProject}, severity=${this.severity}${t}`}},N=class{constructor(e,r,t){this.config=e;this.client=new T(e.jiraUrl,r,t)}config;client;activeSprintCache=new Map;async report(e,r){let t={created:[],updated:[],skipped:[],errors:[],warnings:[],noMatchingRule:[],reopened:[],autoClosed:[],keptClosed:[]};Je("Issue processing");for(let[n,s]of Object.entries(e.vulnerabilities)){let c=e.vulnerabilityToProject[n]??[],i=!1;for(let a of this.config.issues){let d=c.filter(u=>B(u,a.reportProjects));if(d.length===0)continue;i=!0;let l=new V(n,a.jiraProject,s.severity);try{let u=await this.client.findExistingIssue(a.jiraProject,n);u?(l.issueKey=u.key,await this.handleExistingIssue(e,s,u,a,d,r,t,l)):await this.handleNewIssue(e,n,s,a,d,r,t,l)}catch(u){let p=`Failed to process ${n} for project ${a.jiraProject}: ${String(u)}`;t.errors.push(p),l.setOutcome("error"),l.note(`error : ${String(u)}`)}l.flush()}i||(t.noMatchingRule.push(n),Le("skip",`${n} (no matching jira-project rule, severity=${s.severity})`))}return t}async handleNewIssue(e,r,t,n,s,c,i,a){let d=U(t),l=this.resolveAutoCloseThreshold(n),u=l!=null&&J(t.severity,l);if(c){a.setOutcome("dry-run"),a.detail("would",`create issue with title "${d}"`),a.detail("projects",s.join(", "));let v=`${n.jiraProject}::${r}`;u&&(a.detail("would",`auto-close (severity ${t.severity} below threshold ${l})`),i.autoClosed.push(v)),i.created.push(v);return}let{activeSprintId:p,allLabels:w}=await this.resolveBoardRouting(n,s,a,i),g=this.collectProjectComponentTrees(e,s,t.components),j=oe(t,s,g),b=[...w,...s.map(M)],m=await this.client.createIssue({projectKey:n.jiraProject,issueType:n.issueType,summary:d,description:j,labels:b.length>0?b:void 0,sprintId:p});if(a.issueKey=m,a.setOutcome("create"),a.detail("title",d),a.detail("projects",s.join(", ")),i.created.push(m),g.size>0){let v=ae(r,g);if(v){let x=`${r}-dependency-trees.md`;await this.client.attachMarkdown(m,x,v),a.detail("attach",x)}}u&&await this.autoCloseIssue(m,t.severity,l,a,i)}async handleExistingIssue(e,r,t,n,s,c,i,a){let d=de(t.labels),l=s.filter(P=>!d.has(P)),p=ne(t.summary)?.severity,w=p!==void 0&&p!==r.severity;if(l.length===0&&!w){a.setOutcome("skip"),a.detail("reason",`already covers all matching projects (${s.join(", ")})`),i.skipped.push(t.key);return}let g=t.statusCategory==="done",j=this.resolveAutoCloseThreshold(n),b=j!=null&&J(r.severity,j),m=g&&!b,v=m?{severityChange:w?{from:p,to:r.severity}:void 0,newProjects:l.length>0?l:void 0}:void 0;if(c){a.setOutcome("dry-run"),w&&a.detail("would",`retitle severity ${p} -> ${r.severity}`),l.length>0&&a.detail("would",`add project tag(s) ${l.join(", ")}`),m?(a.note("would re-open + re-add to active sprint"),a.detail("would",`post reopen-reason comment (${ke(v)})`),i.reopened.push(t.key)):g&&(a.note(`would keep closed (severity ${r.severity} below auto-close threshold ${j})`),i.keptClosed.push(t.key)),i.updated.push(t.key);return}let{activeSprintId:x,allLabels:we}=await this.resolveBoardRouting(n,s,a,i);if(w){let P=U(r);try{await this.client.updateIssueSummary(t.key,P),a.detail("retitle",`${p} -> ${r.severity}`)}catch(k){a.warn(`Could not update summary of ${t.key}: ${String(k)}`,i)}m||await this.postSeverityChangeComment(t.key,p,r.severity,a,i)}if(l.length>0){let P=this.collectProjectComponentTrees(e,l,r.components),k=[...we,...l.map(M)],ve=new Set(t.labels),G=k.filter(L=>!ve.has(L));if(G.length>0&&await this.client.addLabels(t.key,G),!m){let L=se(l,P);await this.client.addComment(t.key,L)}a.setOutcome("update"),a.detail("projects",`added ${l.join(", ")}`)}else a.setOutcome("update"),a.detail("reason","severity changed (no new projects)");g&&b?(a.note(`kept closed: severity ${r.severity} below auto-close threshold ${j}`),i.keptClosed.push(t.key)):g&&await this.reopenAndReassignSprint(t.key,x,v,a,i),i.updated.push(t.key)}async postSeverityChangeComment(e,r,t,n,s){try{let c=$(f(`Schweregrad ge\xE4ndert von ${r} auf ${t}. Falls eine automatisch erstellte VEX-Ausnahme bestand, ist sie nicht mehr g\xFCltig.`));await this.client.addComment(e,c)}catch(c){n.warn(`Could not post severity-change comment on ${e}: ${String(c)}`,s)}}async reopenAndReassignSprint(e,r,t,n,s){let c;try{c=await this.client.getTransitions(e)}catch(a){n.warn(`Could not list transitions for ${e}: ${String(a)}`,s);return}let i=c.find(a=>a.toStatusCategory==="new");if(!i){n.warn(`${e} is closed but no transition leading to a non-done status is available; leaving status unchanged`,s);return}try{await this.client.transitionIssue(e,i.id),n.detail("reopen",`via "${i.name}"`),s.reopened.push(e)}catch(a){n.warn(`Could not transition ${e} to a non-done status: ${String(a)}`,s);return}if(await this.postReopenReasonComment(e,t,n,s),r!=null)try{await this.client.setSprint(e,r),n.detail("sprint",`added to active sprint ${r}`)}catch(a){n.warn(`Could not set sprint for ${e}: ${String(a)}`,s)}}async postReopenReasonComment(e,r,t,n){try{let s=Ee(r),c=$(f(s));await this.client.addComment(e,c),t.detail("comment","reopen-reason posted")}catch(s){t.warn(`Could not post reopen-reason comment on ${e}: ${String(s)}`,n)}}resolveAutoCloseThreshold(e){return e.autoCloseBelowSeverity??this.config.autoCloseBelowSeverity}async autoCloseIssue(e,r,t,n,s){let c;try{c=await this.client.getTransitions(e)}catch(d){n.warn(`Could not list transitions for ${e} (auto-close): ${String(d)}`,s);return}let i=c.filter(d=>d.toStatusCategory==="done"),a=i.find(d=>d.toStatusName.toLowerCase()==="closed")??i.find(d=>{let l=d.name.toLowerCase();return l==="close"||l==="closed"})??i[0];if(!a){n.warn(`${e} has no transition leading to a done status; cannot auto-close`,s);return}try{await this.client.transitionIssue(e,a.id),n.detail("close",`auto-closed (severity ${r} below ${t}) via "${a.name}"`),s.autoClosed.push(e)}catch(d){n.warn(`Could not transition ${e} to a done status: ${String(d)}`,s);return}try{let d=$(f(`Automatisch geschlossen: Schwere ${r} liegt unterhalb der konfigurierten Auto-Close-Schwelle ${t}.`));await this.client.addComment(e,d)}catch(d){n.warn(`Could not post auto-close comment on ${e}: ${String(d)}`,s)}}async resolveBoardRouting(e,r,t,n){let s,c=[],i=!1;for(let d of e.addToBoard??[]){let l=d.matchProjects??["*"];if(r.some(p=>B(p,l)))if(d.sprintBoardId!=null){if(!i){i=!0;let p=d.sprintBoardId;if(!this.activeSprintCache.has(p)){let w=await this.client.getActiveSprintId(p).catch(g=>(t.warn(`Could not resolve active sprint for boardId ${p}: ${String(g)}`,n),null));this.activeSprintCache.set(p,w)}s=this.activeSprintCache.get(p)??void 0,d.issueLabels&&c.push(...d.issueLabels)}}else d.issueLabels&&c.push(...d.issueLabels)}let a=[...e.issueLabels??[],...c];return{activeSprintId:s,allLabels:a}}collectProjectComponentTrees(e,r,t){let n=new Map;if(!e.projectsToComponents)return n;for(let s of r){let c=e.projectsToComponents[s]??{},i=[];for(let a of t){let d=c[a];d&&i.push(d)}i.length>0&&n.set(s,i)}return n}};var C=xe(require("path")),_=require("fs/promises");var H=class o{constructor(e){this.workingDir=e}workingDir;static DEFAULT_MAVEN_REPO="https://repository.conterra.de/repository/maven-mirror-ct";static DEFAULT_VEX_SUBDIR="input/vex";static DEFAULT_OUT_SUBDIR="output";static DEFAULT_CACHE_SUBDIR="cache";static DEFAULT_SCANNERS=["grype","trivy","ossindex"];normalize(e,r){let t=e.findNoLongerDetectedVulnerabilitiesOnlyForSnapshots??!1;return{projectConfigFileLocation:r,onNewVulnerabilities:e.onNewVulnerabilities??(e.failOnNewVulnerabilities?"fail":"warn"),onNoLongerDetectedVulnerabilities:e.onNoLongerDetectedVulnerabilities??"ignore",reportNoLongerDetectedVulnerabilities:e.reportNoLongerDetectedVulnerabilities??!0,consoleReport:e.consoleReport??"BY_PROJECT_DETAILED",createSubDirsForProject:e.createSubDirsForProject??!0,mavenRepo:e.mavenRepo??o.DEFAULT_MAVEN_REPO,vexUrls:e.vexUrls??[],vexDir:this.resolvePath(e.vexDir)??(0,C.resolve)(this.workingDir,o.DEFAULT_VEX_SUBDIR),outDir:this.resolvePath(e.outDir)??(0,C.resolve)(this.workingDir,o.DEFAULT_OUT_SUBDIR),cacheDir:this.resolvePath(e.cacheDir)??(0,C.resolve)(this.workingDir,o.DEFAULT_CACHE_SUBDIR),scanners:this.normalizeScanners(e.scanners,r),projects:this.normalizeProjects(e.projects??[],t)}}normalizeScanners(e,r){return(e??o.DEFAULT_SCANNERS).map(n=>{if(typeof n!="string")throw new Error(`Invalid scanner name '${String(n)}' in configuration file '${r}'`);let s=n.split("@");if(s.length>2)throw new Error(`Invalid scanner name '${n}' in configuration file '${r}'`);return{name:s[0],version:s[1]??""}})}normalizeProjects(e,r){return e.map(t=>{let n=t;if(!n.name)throw new Error("Project name is missing on entry: "+JSON.stringify(n));if(!n.version)throw new Error("Project version is missing on entry: "+JSON.stringify(n));if(!n.purl)throw new Error("Project purl is missing on entry: "+JSON.stringify(n));let s={...n,purlAliases:n.purlAliases??[],enabled:n.enabled??!0,silent:n.silent??!1,minimumSeverity:n.minimumSeverity??"UNKNOWN"};return s.sbomFile?{...s,sbomFile:this.resolvePath(s.sbomFile)??s.sbomFile}:{...s,detectNoLongerUsedVulnerabilities:r?s.purl.endsWith("-SNAPSHOT"):!0}})}resolvePath(e){if(e)return C.default.isAbsolute(e)?e:(0,C.resolve)(this.workingDir,e)}},A=class{constructor(e){this.workingDir=e;this.normalizer=new H(e)}workingDir;normalizer;projectConfigCache;async loadProjectConfig(){return this.projectConfigCache??=this.doLoadProjectConfig(),this.projectConfigCache}async doLoadProjectConfig(){let e=(0,C.resolve)(this.workingDir,"vuln-scan-conf.json"),r=await Z(e);if(!r)throw new Error(`Missing project configuration file '${e}'`);return this.normalizer.normalize(r,e)}async loadJiraConfig(e){let r=await(0,_.readFile)(e,"utf8"),t=JSON.parse(r);if(!t.issues&&t.issue&&(t.issues=t.issue),!t.jiraUrl||typeof t.jiraUrl!="string")throw new Error("jira-conf.json: missing or invalid 'jiraUrl' field");if(!Array.isArray(t.issues))throw new Error("jira-conf.json: missing or invalid 'issues' array");this.validateAutoCloseSeverity(t.autoCloseBelowSeverity,"jira-conf.json: invalid 'autoCloseBelowSeverity'");for(let[n,s]of t.issues.entries())s&&typeof s=="object"&&this.validateAutoCloseSeverity(s.autoCloseBelowSeverity,`jira-conf.json: invalid 'issues[${n}].autoCloseBelowSeverity'`);return t}validateAutoCloseSeverity(e,r){if(e!==void 0&&!y.includes(e))throw new Error(`${r} value '${String(e)}'. Must be one of: ${y.join(", ")}`)}async loadAutoVexConfig(e){let r=await(0,_.readFile)(e,"utf8"),t=JSON.parse(r);if(!t.impactStatement||typeof t.impactStatement!="string")throw new Error("auto-vex-conf.json: missing or invalid 'impactStatement' field (must be a non-empty string)");if(t.maxSeverity!==void 0&&!y.includes(t.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'maxSeverity' value '${String(t.maxSeverity)}'. Must be one of: ${y.join(", ")}`);if(t.projectOverrides!==void 0){if(!Array.isArray(t.projectOverrides))throw new Error("auto-vex-conf.json: 'projectOverrides' must be an array");for(let[n,s]of t.projectOverrides.entries()){if(!s||typeof s!="object")throw new Error(`auto-vex-conf.json: 'projectOverrides[${n}]' must be an object`);let c=s;if(!Array.isArray(c.projects)||c.projects.length===0||!c.projects.every(i=>typeof i=="string"&&i.length>0))throw new Error(`auto-vex-conf.json: 'projectOverrides[${n}].projects' must be a non-empty array of non-empty strings`);if(!y.includes(c.maxSeverity))throw new Error(`auto-vex-conf.json: invalid 'projectOverrides[${n}].maxSeverity' value '${String(c.maxSeverity)}'. Must be one of: ${y.join(", ")}`)}}return t}};async function ge(o){let{scanSummaryPath:e,jiraConfigPath:r,jiraUser:t,jiraApiToken:n,dryRun:s=!1}=o,c=new A(process.cwd()),[i,a]=await Promise.all([Be(e),c.loadJiraConfig(r)]);return new N(a,t,n).report(i,s)}async function Be(o){let e=await(0,fe.readFile)(o,"utf8");return JSON.parse(e)}var W={flag:"--dry-run",description:"Print what would happen without making changes"},E=class{specs;booleanSpecs;commandName;helpLines;constructor(e,r,t=[],n=[]){this.commandName=e,this.specs=r;let s=n.some(c=>c.flag===W.flag);this.booleanSpecs=s?n:[...n,W],this.helpLines=t}parse(e){let r=e.slice(2),t=new Map(this.specs.map(s=>[s.flag,s.defaultValue])),n=new Map(this.booleanSpecs.map(s=>[s.flag,!1]));for(let s=0;s<r.length;s++){let c=r[s];(c==="--help"||c==="-h")&&(this.printHelp(),process.exit(0));let i=this.booleanSpecs.find(d=>d.flag===c||d.alias===c);if(i){n.set(i.flag,!0);continue}let a=this.specs.find(d=>d.flag===c||d.alias===c);a&&r[s+1]?t.set(a.flag,r[++s]):(console.error(`Unknown argument: ${c}`),this.printHelp(),process.exit(1))}return{values:t,dryRun:n.get(W.flag)===!0,booleans:n}}printHelp(){let e=this.specs.map(t=>` ${(t.alias?`${t.alias}, ${t.flag} <path>`:` ${t.flag} <path>`).padEnd(38)}${t.description}
|
|
8
|
+
${"".padEnd(42)}(default: ${t.defaultValue})`),r=this.booleanSpecs.map(t=>` ${(t.alias?`${t.alias}, ${t.flag}`:` ${t.flag}`).padEnd(38)}${t.description}`);console.log([`Usage: ${this.commandName} [options]`,"","Options:",...e,...r," -h, --help"+" ".repeat(32)+"Show this help message",...this.helpLines].join(`
|
|
9
|
+
`))}};ye.dotenv.config();var he=process.env,Oe=new E("ct-vuln-jira-report",[{flag:"--jira-config",alias:"-c",description:"Path to jira-conf.json configuration file",defaultValue:(0,z.join)(process.cwd(),"jira-conf.json")},{flag:"--summary",alias:"-s",description:"Path to scan-summary.json produced by ct-vuln-scan",defaultValue:(0,z.join)(process.cwd(),"output","scan-summary.json")}],["","Required environment variables:"," JIRA_USER Jira account e-mail address"," JIRA_API_TOKEN Jira API token (see https://id.atlassian.com/manage-profile/security/api-tokens)"]);(async()=>{let{values:o,dryRun:e}=Oe.parse(process.argv),r=o.get("--jira-config"),t=o.get("--summary"),n=he.JIRA_USER,s=he.JIRA_API_TOKEN;(!n||!s)&&(console.error("Error: JIRA_USER and JIRA_API_TOKEN environment variables must be set."),process.exit(1));let c=e?" [dry-run]":"";console.log(`Jira reporter${c}`),console.log(` config: ${r}`),console.log(` summary: ${t}`);try{let i=await(0,me.readFile)(r,"utf8"),a=JSON.parse(i);a.jiraUrl&&console.log(` jira-url: ${a.jiraUrl}`)}catch{}try{let i=await ge({scanSummaryPath:t,jiraConfigPath:r,jiraUser:n,jiraApiToken:s,dryRun:e}),a=Math.max(0,i.updated.length-i.reopened.length-i.keptClosed.length);console.log(""),console.log(`=== Jira Report Summary${c} ===`),console.log(` Created : ${i.created.length}`),console.log(` Updated : ${i.updated.length} (re-opened: ${i.reopened.length}, kept-closed: ${i.keptClosed.length}, retitled or new-projects: ${a})`);let d=i.skipped.length+i.noMatchingRule.length;console.log(` Skipped (CVEs) : ${d}`),console.log(` up-to-date : ${i.skipped.length}`),console.log(` no matching rule : ${i.noMatchingRule.length}`),console.log(` Auto-closed : ${i.autoClosed.length}`),console.log(` Warnings : ${i.warnings.length}`),console.log(` Errors : ${i.errors.length}`),e&&(console.log(""),console.log("No issues were created or modified (dry-run). Re-run without --dry-run to apply.")),i.errors.length>0&&(process.exitCode=1)}catch(i){console.error(`Fatal error: ${String(i)}`),process.exit(1)}})();
|