{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "vulnerability-scanner-report",
  "title": "Vulnerability Scanner Report",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/vulnerability-scanner-report/vulnerability-scanner-report.component.ts",
      "content": "// Snyk / Trivy style CVE vulnerability scanner report and dependency security audit:\n// severity breakdown cards, CVSS metrics, package version diffs, advisory inspection\n// drawer, and automated remediation PR actions. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  AlertCircle,\n  AlertTriangle,\n  Check,\n  CheckCircle2,\n  Copy,\n  Download,\n  ExternalLink,\n  FileCode2,\n  GitPullRequest,\n  Info,\n  LucideAngularModule,\n  Package,\n  RefreshCw,\n  Search,\n  ShieldAlert,\n  ShieldCheck,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport {\n  UiSheetCloseComponent,\n  UiSheetComponent,\n  UiSheetContentComponent,\n  UiSheetDescriptionComponent,\n  UiSheetFooterComponent,\n  UiSheetHeaderComponent,\n  UiSheetTitleComponent,\n} from '@/ui/sheet/sheet.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\n\nexport type CveSeverity = 'critical' | 'high' | 'medium' | 'low'\nexport type ExploitStatus = 'poc' | 'none'\n\nexport interface CveItem {\n  id: string\n  title: string\n  cwe: string\n  severity: CveSeverity\n  cvssScore: number\n  cvssVector: string\n  pkgName: string\n  installedVersion: string\n  fixedVersion: string\n  exploitStatus: ExploitStatus\n  exploitLabel: string\n  attackVector: string\n  attackComplexity: string\n  privilegesRequired: string\n  userInteraction: string\n  description: string\n  impact: string\n  remediationDiff: {\n    removed: string\n    added: string\n  }\n  patchCommand: string\n  advisoryUrl: string\n}\n\nconst defaultCveItems: CveItem[] = [\n  {\n    id: 'CVE-2026-38419',\n    title: 'Prototype Pollution via mergeCustomizer in lodash',\n    cwe: 'CWE-1321',\n    severity: 'high',\n    cvssScore: 8.4,\n    cvssVector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N',\n    pkgName: 'lodash',\n    installedVersion: '4.17.20',\n    fixedVersion: '4.17.22+',\n    exploitStatus: 'poc',\n    exploitLabel: 'Proof of Concept available',\n    attackVector: 'Network (Remote)',\n    attackComplexity: 'Low',\n    privilegesRequired: 'None',\n    userInteraction: 'None',\n    description:\n      'A prototype pollution vulnerability in lodash prior to 4.17.22 allows unauthenticated remote attackers to modify Object.prototype properties via crafted JSON payloads, leading to denial of service or potential remote code execution.',\n    impact: 'Critical data integrity failure and property tampering across server runtime objects.',\n    remediationDiff: {\n      removed: '  \"lodash\": \"^4.17.20\",',\n      added: '  \"lodash\": \"^4.17.22\",',\n    },\n    patchCommand: 'npm install lodash@^4.17.22 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-38419',\n  },\n  {\n    id: 'CVE-2026-29401',\n    title: 'Server-Side Request Forgery (SSRF) bypass in axios redirect handler',\n    cwe: 'CWE-918',\n    severity: 'high',\n    cvssScore: 7.8,\n    cvssVector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N',\n    pkgName: 'axios',\n    installedVersion: '1.6.2',\n    fixedVersion: '1.7.9+',\n    exploitStatus: 'poc',\n    exploitLabel: 'Proof of Concept available',\n    attackVector: 'Network (Remote)',\n    attackComplexity: 'Low',\n    privilegesRequired: 'None',\n    userInteraction: 'Required',\n    description:\n      'Axios versions <=1.6.8 improperly preserve sensitive Authorization and Cookie headers during cross-origin HTTP 302/307 redirects, exposing upstream credentials to untrusted third-party endpoints.',\n    impact: 'Authorization bearer token leakage to arbitrary redirect targets.',\n    remediationDiff: {\n      removed: '  \"axios\": \"^1.6.2\",',\n      added: '  \"axios\": \"^1.7.9\",',\n    },\n    patchCommand: 'npm install axios@^1.7.9 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-29401',\n  },\n  {\n    id: 'CVE-2026-10492',\n    title: 'Arbitrary File Overwrite via hardlink traversal in tar',\n    cwe: 'CWE-59',\n    severity: 'medium',\n    cvssScore: 6.5,\n    cvssVector: 'CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H',\n    pkgName: 'tar',\n    installedVersion: '6.1.11',\n    fixedVersion: '6.2.1+',\n    exploitStatus: 'none',\n    exploitLabel: 'No known exploit',\n    attackVector: 'Local Archive Extraction',\n    attackComplexity: 'Low',\n    privilegesRequired: 'None',\n    userInteraction: 'Required',\n    description:\n      'The tar package before 6.2.1 is vulnerable to arbitrary file write outside the extraction destination directory when untrusted tar archives contain hardlinks pointing to symlinked directories.',\n    impact: 'Arbitrary filesystem overwrite upon unpacking unvetted tarball artifacts.',\n    remediationDiff: {\n      removed: '  \"tar\": \"^6.1.11\",',\n      added: '  \"tar\": \"^6.2.1\",',\n    },\n    patchCommand: 'npm install tar@^6.2.1 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-10492',\n  },\n  {\n    id: 'CVE-2026-84920',\n    title: 'Signature verification bypass via algorithm confusion in jsonwebtoken',\n    cwe: 'CWE-347',\n    severity: 'medium',\n    cvssScore: 6.1,\n    cvssVector: 'CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N',\n    pkgName: 'jsonwebtoken',\n    installedVersion: '8.5.1',\n    fixedVersion: '9.0.2+',\n    exploitStatus: 'poc',\n    exploitLabel: 'Proof of Concept available',\n    attackVector: 'Network (Remote)',\n    attackComplexity: 'High',\n    privilegesRequired: 'None',\n    userInteraction: 'None',\n    description:\n      'When jwt.verify() is executed without explicit algorithms whitelisting, attackers can forge unsigned tokens or switch asymmetric RS256 keys to symmetric HMAC evaluation with public certs.',\n    impact: 'Unauthorized identity impersonation and claim forgery.',\n    remediationDiff: {\n      removed: '  \"jsonwebtoken\": \"^8.5.1\",',\n      added: '  \"jsonwebtoken\": \"^9.0.2\",',\n    },\n    patchCommand: 'npm install jsonwebtoken@^9.0.2 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-84920',\n  },\n  {\n    id: 'CVE-2026-18933',\n    title: 'Regular Expression Denial of Service (ReDoS) in micromatch',\n    cwe: 'CWE-1333',\n    severity: 'medium',\n    cvssScore: 5.3,\n    cvssVector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L',\n    pkgName: 'micromatch',\n    installedVersion: '4.0.5',\n    fixedVersion: '4.0.8+',\n    exploitStatus: 'none',\n    exploitLabel: 'No known exploit',\n    attackVector: 'Network (Remote)',\n    attackComplexity: 'Low',\n    privilegesRequired: 'None',\n    userInteraction: 'None',\n    description:\n      'A backtracking exponential regular expression in micromatch path globbing allows attackers sending crafted nested brace expressions to cause catastrophic CPU exhaustion and event loop freeze.',\n    impact: 'Node.js main thread event-loop starvation and service unresponsiveness.',\n    remediationDiff: {\n      removed: '  \"micromatch\": \"^4.0.5\",',\n      added: '  \"micromatch\": \"^4.0.8\",',\n    },\n    patchCommand: 'npm install micromatch@^4.0.8 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-18933',\n  },\n  {\n    id: 'CVE-2026-04192',\n    title: 'Information disclosure in child process error serialization in cross-spawn',\n    cwe: 'CWE-209',\n    severity: 'low',\n    cvssScore: 3.7,\n    cvssVector: 'CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N',\n    pkgName: 'cross-spawn',\n    installedVersion: '7.0.3',\n    fixedVersion: '7.0.6+',\n    exploitStatus: 'none',\n    exploitLabel: 'No known exploit',\n    attackVector: 'Local Environment',\n    attackComplexity: 'High',\n    privilegesRequired: 'Low',\n    userInteraction: 'None',\n    description:\n      'Under verbose debug logging configurations, command environment variables containing auth tokens may be included in uncaught spawn error stacks printed to stdout.',\n    impact: 'Accidental leakage of process environment credentials in CI runner logs.',\n    remediationDiff: {\n      removed: '  \"cross-spawn\": \"^7.0.3\",',\n      added: '  \"cross-spawn\": \"^7.0.6\",',\n    },\n    patchCommand: 'npm install cross-spawn@^7.0.6 --save-exact',\n    advisoryUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-04192',\n  },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-vulnerability-scanner-report, [ui-vulnerability-scanner-report]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiInputComponent,\n    UiProgressComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSheetCloseComponent,\n    UiSheetComponent,\n    UiSheetContentComponent,\n    UiSheetDescriptionComponent,\n    UiSheetFooterComponent,\n    UiSheetHeaderComponent,\n    UiSheetTitleComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n  ],\n  template: `\n    <div data-slot=\"vulnerability-scanner-report\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div\n        class=\"border-border/80 bg-card text-card-foreground flex flex-col gap-4 rounded-xl border p-4 shadow-xs sm:p-5 lg:flex-row lg:items-center lg:justify-between\"\n      >\n        <div class=\"space-y-1.5\">\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <div\n              class=\"bg-muted text-muted-foreground flex size-8 shrink-0 items-center justify-center rounded-lg border\"\n            >\n              <lucide-icon [img]=\"ShieldAlert\" class=\"text-warning size-4.5\" />\n            </div>\n            <div>\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <h1 class=\"text-foreground text-base font-semibold tracking-tight sm:text-lg\">{{ targetRepo() }}</h1>\n                <span ui-badge variant=\"warning\" class=\"gap-1 text-xs font-medium\">\n                  <span class=\"bg-warning size-1.5 rounded-full\"></span>\n                  {{ grade() }} · {{ gradeSummary() }}\n                </span>\n              </div>\n              <div class=\"text-muted-foreground flex flex-wrap items-center gap-2 pt-0.5 text-xs\">\n                <span>{{ currentLastScanned() }}</span>\n                <span class=\"opacity-40\">·</span>\n                <span class=\"font-mono\">{{ targetBranch() }}</span>\n                <span class=\"opacity-40\">·</span>\n                <span class=\"font-mono\">{{ baseImage() }}</span>\n                <span class=\"opacity-40\">·</span>\n                <span>{{ totalDeps().toLocaleString() }} dependencies audited</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div class=\"flex flex-wrap items-center gap-2 self-start sm:gap-2.5 lg:self-center\">\n          <button\n            ui-button\n            aria-label=\"Download attachment\"\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n            (click)=\"exportSbom()\"\n          >\n            @if (exportSuccess()) {\n              <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n            } @else {\n              <lucide-icon [img]=\"Download\" class=\"size-3.5\" />\n            }\n            <span>{{ exportSuccess() ? 'SBOM Exported' : 'Export SBOM (SPDX)' }}</span>\n          </button>\n\n          <button\n            ui-button\n            variant=\"default\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n            [disabled]=\"isScanning()\"\n            (click)=\"triggerRescan()\"\n          >\n            <lucide-icon [img]=\"RefreshCw\" [class]=\"rescanIconClass\" />\n            <span>{{ isScanning() ? 'Scanning Container...' : 'Trigger Re-scan' }}</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Active Scan Progress Track -->\n      @if (isScanning()) {\n        <div class=\"border-primary/20 bg-primary/5 space-y-1.5 rounded-lg border p-3\">\n          <div class=\"flex items-center justify-between gap-x-2 text-xs font-medium\">\n            <span class=\"text-primary flex items-center gap-1.5\">\n              <lucide-icon [img]=\"Search\" class=\"size-3.5\" />\n              Running AST & SBOM vulnerability correlation against NVD & OSV databases...\n            </span>\n            <span class=\"text-muted-foreground font-mono\">{{ scanProgress() }}%</span>\n          </div>\n          <ui-progress [value]=\"scanProgress()\" class=\"h-1.5\" />\n        </div>\n      }\n\n      <!-- 4 CVE Severity Summary Cards -->\n      <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n        <!-- Critical Card -->\n        <div ui-card [class]=\"severityCardClass('critical')\" (click)=\"toggleSeverityFilter('critical')\">\n          <div ui-card-content class=\"p-4\">\n            <div class=\"flex items-start justify-between\">\n              <div class=\"space-y-1\">\n                <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Critical Severity</p>\n                <div class=\"flex items-baseline gap-2\">\n                  <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight\">\n                    {{ summaryCounts().critical }}\n                  </span>\n                  <span class=\"text-success text-xs font-medium\">0 CVEs</span>\n                </div>\n              </div>\n              <div\n                class=\"border-success/20 bg-success/10 text-success flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"ShieldCheck\" class=\"size-4.5\" />\n              </div>\n            </div>\n            <div\n              class=\"border-border/50 text-muted-foreground mt-3 flex items-center justify-between gap-x-2 border-t pt-2 text-xs\"\n            >\n              <span class=\"text-success font-medium\">Zero critical exposures</span>\n              <span class=\"font-mono text-xs\">CVSS 9.0–10.0</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- High Card -->\n        <div ui-card [class]=\"severityCardClass('high')\" (click)=\"toggleSeverityFilter('high')\">\n          <div ui-card-content class=\"p-4\">\n            <div class=\"flex items-start justify-between\">\n              <div class=\"space-y-1\">\n                <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">High Severity</p>\n                <div class=\"flex items-baseline gap-2\">\n                  <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight\">\n                    {{ summaryCounts().high }}\n                  </span>\n                  <span class=\"text-destructive text-xs font-medium\">2 CVEs</span>\n                </div>\n              </div>\n              <div\n                class=\"border-destructive/20 bg-destructive/10 text-destructive flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"AlertTriangle\" class=\"size-4.5\" />\n              </div>\n            </div>\n            <div\n              class=\"border-border/50 text-muted-foreground mt-3 flex items-center justify-between gap-x-2 border-t pt-2 text-xs\"\n            >\n              <span class=\"text-destructive font-medium\">Actionable patches ready</span>\n              <span class=\"font-mono text-xs\">CVSS 7.0–8.9</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- Medium Card -->\n        <div ui-card [class]=\"severityCardClass('medium')\" (click)=\"toggleSeverityFilter('medium')\">\n          <div ui-card-content class=\"p-4\">\n            <div class=\"flex items-start justify-between\">\n              <div class=\"space-y-1\">\n                <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Medium Severity</p>\n                <div class=\"flex items-baseline gap-2\">\n                  <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight\">\n                    {{ summaryCounts().medium }}\n                  </span>\n                  <span class=\"text-warning text-xs font-medium\">5 CVEs</span>\n                </div>\n              </div>\n              <div\n                class=\"border-warning/20 bg-warning/10 text-warning flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"AlertCircle\" class=\"size-4.5\" />\n              </div>\n            </div>\n            <div\n              class=\"border-border/50 text-muted-foreground mt-3 flex items-center justify-between gap-x-2 border-t pt-2 text-xs\"\n            >\n              <span class=\"text-warning font-medium\">3 in direct dependencies</span>\n              <span class=\"font-mono text-xs\">CVSS 4.0–6.9</span>\n            </div>\n          </div>\n        </div>\n\n        <!-- Low Card -->\n        <div ui-card [class]=\"severityCardClass('low')\" (click)=\"toggleSeverityFilter('low')\">\n          <div ui-card-content class=\"p-4\">\n            <div class=\"flex items-start justify-between\">\n              <div class=\"space-y-1\">\n                <p class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">Low Severity</p>\n                <div class=\"flex items-baseline gap-2\">\n                  <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight\">\n                    {{ summaryCounts().low }}\n                  </span>\n                  <span class=\"text-info text-xs font-medium\">12 CVEs</span>\n                </div>\n              </div>\n              <div\n                class=\"border-info/20 bg-info/10 text-info flex size-8 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"Info\" class=\"size-4.5\" />\n              </div>\n            </div>\n            <div\n              class=\"border-border/50 text-muted-foreground mt-3 flex items-center justify-between gap-x-2 border-t pt-2 text-xs\"\n            >\n              <span class=\"text-info font-medium\">Informational & debug</span>\n              <span class=\"font-mono text-xs\">CVSS 0.1–3.9</span>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Filter & Search Toolbar -->\n      <div class=\"flex flex-col gap-2.5 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"flex flex-1 flex-wrap items-center gap-2\">\n          <div class=\"relative w-full sm:w-72\">\n            <lucide-icon\n              [img]=\"Search\"\n              class=\"text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\"\n            />\n            <ui-input\n              [value]=\"searchQuery()\"\n              (valueChange)=\"searchQuery.set($event)\"\n              placeholder=\"Search CVE, package, or CWE...\"\n              class=\"h-8 pl-8 text-xs\"\n            />\n          </div>\n\n          <!-- Severity Filter Select -->\n          <ui-select [value]=\"severityFilter()\" (valueChange)=\"severityFilter.set($event)\">\n            <button ui-select-trigger class=\"h-8 w-36 text-xs capitalize\">\n              <ui-select-value placeholder=\"All Severities\" />\n            </button>\n            <ui-select-content align=\"start\">\n              <ui-select-item value=\"all\">All Severities</ui-select-item>\n              <ui-select-item value=\"critical\">Critical (0)</ui-select-item>\n              <ui-select-item value=\"high\">High (2)</ui-select-item>\n              <ui-select-item value=\"medium\">Medium (5)</ui-select-item>\n              <ui-select-item value=\"low\">Low (12)</ui-select-item>\n            </ui-select-content>\n          </ui-select>\n\n          <!-- Exploitability Filter Select -->\n          <ui-select [value]=\"exploitFilter()\" (valueChange)=\"exploitFilter.set($event)\">\n            <button ui-select-trigger class=\"h-8 w-44 text-xs\">\n              <ui-select-value placeholder=\"All Exploit Status\" />\n            </button>\n            <ui-select-content align=\"start\">\n              <ui-select-item value=\"all\">All Exploit Status</ui-select-item>\n              <ui-select-item value=\"poc\">PoC Available</ui-select-item>\n              <ui-select-item value=\"none\">No Known Exploit</ui-select-item>\n            </ui-select-content>\n          </ui-select>\n\n          @if (severityFilter() !== 'all' || exploitFilter() !== 'all' || searchQuery()) {\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"sm\"\n              class=\"text-muted-foreground hover:text-foreground h-8 px-2 text-xs\"\n              (click)=\"resetFilters()\"\n            >\n              Reset filters\n            </button>\n          }\n        </div>\n\n        <div class=\"text-muted-foreground flex items-center gap-2 text-xs\">\n          <span>\n            Showing <strong class=\"text-foreground font-mono\">{{ filteredItems().length }}</strong> of\n            {{ items().length }} audited vulnerabilities\n          </span>\n        </div>\n      </div>\n\n      <!-- Vulnerability Table Card -->\n      <div ui-card class=\"border-border/80 bg-card text-card-foreground overflow-hidden shadow-xs\">\n        <div class=\"overflow-x-auto\">\n          <table ui-table>\n            <thead ui-table-header>\n              <tr ui-table-row class=\"hover:bg-transparent\">\n                <th ui-table-head class=\"min-w-[220px]\">Vulnerability / CVE</th>\n                <th ui-table-head class=\"min-w-[130px]\">Severity</th>\n                <th ui-table-head class=\"min-w-[160px]\">Affected Package</th>\n                <th ui-table-head class=\"min-w-[170px]\">Remediation Fixed</th>\n                <th ui-table-head class=\"min-w-[180px]\">Exploitability</th>\n                <th ui-table-head class=\"min-w-[180px] text-right\">Actions</th>\n              </tr>\n            </thead>\n            <tbody ui-table-body>\n              @for (item of filteredItems(); track item.id) {\n                <tr\n                  ui-table-row\n                  class=\"hover:bg-muted/40 cursor-pointer transition-colors\"\n                  (click)=\"openAdvisory(item)\"\n                >\n                  <!-- Vulnerability / CVE -->\n                  <td ui-table-cell class=\"py-3 align-top\">\n                    <div class=\"space-y-1\">\n                      <div class=\"flex items-center gap-2\">\n                        <span class=\"text-foreground font-mono text-xs font-semibold hover:underline\">\n                          {{ item.id }}\n                        </span>\n                        <span ui-badge variant=\"outline\" class=\"px-1.5 py-0 font-mono text-xs\">\n                          {{ item.cwe }}\n                        </span>\n                      </div>\n                      <p class=\"text-muted-foreground line-clamp-1 max-w-[220px] text-xs\">{{ item.title }}</p>\n                    </div>\n                  </td>\n\n                  <!-- Severity & CVSS Score -->\n                  <td ui-table-cell class=\"py-3 align-top\">\n                    <div class=\"space-y-1\">\n                      @if (item.severity === 'critical') {\n                        <span ui-badge variant=\"destructive\" class=\"gap-1 font-mono text-xs font-medium\">\n                          <lucide-icon [img]=\"AlertCircle\" class=\"size-3\" />\n                          CVSS {{ item.cvssScore }} Critical\n                        </span>\n                      } @else if (item.severity === 'high') {\n                        <span\n                          ui-badge\n                          class=\"border-destructive/20 bg-destructive/10 text-destructive gap-1 font-mono text-xs font-medium\"\n                        >\n                          <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" />\n                          CVSS {{ item.cvssScore }} High\n                        </span>\n                      } @else if (item.severity === 'medium') {\n                        <span ui-badge variant=\"warning\" class=\"gap-1 font-mono text-xs font-medium\">\n                          <lucide-icon [img]=\"AlertCircle\" class=\"size-3\" />\n                          CVSS {{ item.cvssScore }} Med\n                        </span>\n                      } @else {\n                        <span ui-badge variant=\"info\" class=\"gap-1 font-mono text-xs font-medium\">\n                          <lucide-icon [img]=\"Info\" class=\"size-3\" />\n                          CVSS {{ item.cvssScore }} Low\n                        </span>\n                      }\n                      <p class=\"text-muted-foreground font-mono text-xs\">v3.1 Vector</p>\n                    </div>\n                  </td>\n\n                  <!-- Affected Package & Version -->\n                  <td ui-table-cell class=\"py-3 align-top\">\n                    <div class=\"flex items-center gap-2\">\n                      <lucide-icon [img]=\"Package\" class=\"text-muted-foreground size-3.5 shrink-0\" />\n                      <div class=\"min-w-0\">\n                        <p class=\"text-foreground truncate font-mono text-xs font-medium\">{{ item.pkgName }}</p>\n                        <p class=\"text-muted-foreground font-mono text-xs\">v{{ item.installedVersion }}</p>\n                      </div>\n                    </div>\n                  </td>\n\n                  <!-- Remediation Fixed Version -->\n                  <td ui-table-cell class=\"py-3 align-top\">\n                    <div class=\"space-y-1\">\n                      <div\n                        class=\"border-success/20 bg-success/10 text-success inline-flex items-center gap-1 rounded-md border px-2 py-0.5 font-mono text-xs font-medium\"\n                      >\n                        <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-3\" />\n                        {{ item.fixedVersion }}\n                      </div>\n                      <p class=\"text-muted-foreground text-xs\">Upgrade ready</p>\n                    </div>\n                  </td>\n\n                  <!-- Exploitability Status -->\n                  <td ui-table-cell class=\"py-3 align-top\">\n                    <div class=\"flex items-center gap-1.5\">\n                      <span [class]=\"exploitDotClass(item)\"></span>\n                      <span [class]=\"exploitLabelClass(item)\">\n                        {{ item.exploitLabel }}\n                      </span>\n                    </div>\n                  </td>\n\n                  <!-- Row Action Buttons -->\n                  <td ui-table-cell class=\"py-3 text-right align-top\" (click)=\"$event.stopPropagation()\">\n                    <div class=\"flex items-center justify-end gap-1.5\">\n                      <button\n                        ui-button\n                        variant=\"ghost\"\n                        size=\"sm\"\n                        class=\"text-muted-foreground hover:text-foreground h-7 px-2.5 text-xs\"\n                        (click)=\"openAdvisory(item)\"\n                      >\n                        View Advisory\n                      </button>\n\n                      @if (!fixedPrs()[item.id]) {\n                        <button\n                          ui-button\n                          variant=\"outline\"\n                          size=\"sm\"\n                          class=\"h-7 gap-1 px-2.5 text-xs font-medium shadow-xs\"\n                          (click)=\"handleAutoFix(item.id)\"\n                        >\n                          <lucide-icon [img]=\"GitPullRequest\" class=\"size-3\" />\n                          Auto-Fix PR\n                        </button>\n                      } @else {\n                        <span ui-badge variant=\"success\" class=\"h-7 gap-1 px-2.5 text-xs font-medium\">\n                          <lucide-icon [img]=\"Check\" class=\"size-3\" />\n                          PR #849 Opened\n                        </span>\n                      }\n                    </div>\n                  </td>\n                </tr>\n              }\n\n              @if (filteredItems().length === 0) {\n                <tr ui-table-row>\n                  <td ui-table-cell [attr.colspan]=\"6\" class=\"h-32 text-center\">\n                    <div class=\"flex flex-col items-center justify-center gap-1.5\">\n                      <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-7\" />\n                      <p class=\"text-foreground text-sm font-medium\">No matching vulnerabilities found</p>\n                      <p class=\"text-muted-foreground text-xs\">All packages satisfy the active filter constraints.</p>\n                    </div>\n                  </td>\n                </tr>\n              }\n            </tbody>\n          </table>\n        </div>\n\n        <!-- Table Footer Metadata -->\n        <div\n          class=\"border-border/60 bg-muted/20 text-muted-foreground flex flex-col gap-2 border-t px-4 py-2.5 text-xs sm:flex-row sm:items-center sm:justify-between\"\n        >\n          <div class=\"flex items-center gap-3\">\n            <span class=\"flex items-center gap-1\">\n              <span class=\"bg-success size-2 rounded-full\"></span>\n              NVD Sync Live\n            </span>\n            <span class=\"opacity-40\">·</span>\n            <span>CVSS Score Engine: v3.1 Specification</span>\n          </div>\n          <div class=\"flex items-center gap-2 font-mono\">\n            <span>Target hash: 9a20bf183</span>\n          </div>\n        </div>\n      </div>\n\n      <!-- Detailed CVE Advisory Drawer / Sheet -->\n      <div ui-sheet [open]=\"isDrawerOpen()\" (openChange)=\"onDrawerOpenChange($event)\">\n        <div ui-sheet-content class=\"w-full space-y-6 overflow-y-auto p-6 sm:max-w-xl md:max-w-2xl\">\n          @if (selectedCve(); as sel) {\n            <div ui-sheet-header class=\"space-y-2 p-0 text-left\">\n              <div class=\"flex items-center justify-between gap-3 pr-6\">\n                <div class=\"flex items-center gap-2\">\n                  @if (sel.severity === 'critical') {\n                    <span ui-badge variant=\"destructive\" class=\"font-mono text-xs font-semibold\">\n                      CRITICAL {{ sel.cvssScore }}\n                    </span>\n                  } @else if (sel.severity === 'high') {\n                    <span\n                      ui-badge\n                      class=\"border-destructive/20 bg-destructive/10 text-destructive font-mono text-xs font-semibold\"\n                    >\n                      HIGH {{ sel.cvssScore }}\n                    </span>\n                  } @else if (sel.severity === 'medium') {\n                    <span ui-badge variant=\"warning\" class=\"font-mono text-xs font-semibold\">\n                      MEDIUM {{ sel.cvssScore }}\n                    </span>\n                  } @else {\n                    <span ui-badge variant=\"info\" class=\"font-mono text-xs font-semibold\">LOW {{ sel.cvssScore }}</span>\n                  }\n\n                  <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">\n                    {{ sel.cwe }}\n                  </span>\n                </div>\n\n                <a\n                  [href]=\"sel.advisoryUrl\"\n                  target=\"_blank\"\n                  rel=\"noopener noreferrer\"\n                  class=\"text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs\"\n                >\n                  <span>NVD Source</span>\n                  <lucide-icon [img]=\"ExternalLink\" class=\"size-3\" />\n                </a>\n              </div>\n\n              <h2 ui-sheet-title class=\"text-lg font-bold tracking-tight\">{{ sel.id }}</h2>\n              <p ui-sheet-description class=\"text-foreground/80 text-xs font-medium\">\n                {{ sel.title }}\n              </p>\n            </div>\n\n            <div class=\"space-y-5 text-xs\">\n              <!-- CVSS 3.1 Metrics Grid -->\n              <div class=\"border-border/80 bg-muted/30 space-y-3 rounded-lg border p-3.5\">\n                <div class=\"flex items-center justify-between gap-x-2\">\n                  <span class=\"text-muted-foreground font-medium\">CVSS v3.1 Base Score</span>\n                  <span class=\"text-foreground font-mono text-sm font-bold\">{{ sel.cvssScore }} / 10.0</span>\n                </div>\n                <ui-progress [value]=\"sel.cvssScore * 10\" class=\"h-2\" />\n\n                <div class=\"grid grid-cols-2 gap-2.5 pt-1 text-xs sm:grid-cols-4\">\n                  <div class=\"bg-card border-border/60 rounded-md border p-2\">\n                    <p class=\"text-muted-foreground text-xs\">Attack Vector</p>\n                    <p class=\"text-foreground mt-0.5 truncate font-medium\">{{ sel.attackVector }}</p>\n                  </div>\n                  <div class=\"bg-card border-border/60 rounded-md border p-2\">\n                    <p class=\"text-muted-foreground text-xs\">Complexity</p>\n                    <p class=\"text-foreground mt-0.5 font-medium\">{{ sel.attackComplexity }}</p>\n                  </div>\n                  <div class=\"bg-card border-border/60 rounded-md border p-2\">\n                    <p class=\"text-muted-foreground text-xs\">Privileges</p>\n                    <p class=\"text-foreground mt-0.5 font-medium\">{{ sel.privilegesRequired }}</p>\n                  </div>\n                  <div class=\"bg-card border-border/60 rounded-md border p-2\">\n                    <p class=\"text-muted-foreground text-xs\">Interaction</p>\n                    <p class=\"text-foreground mt-0.5 font-medium\">{{ sel.userInteraction }}</p>\n                  </div>\n                </div>\n\n                <!-- CVSS Vector String -->\n                <div\n                  class=\"border-border/50 text-muted-foreground flex items-center justify-between gap-x-2 border-t pt-2 font-mono text-xs\"\n                >\n                  <span class=\"truncate\">{{ sel.cvssVector }}</span>\n                </div>\n              </div>\n\n              <!-- Description & Technical Impact -->\n              <div class=\"space-y-2\">\n                <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                  Vulnerability Overview\n                </h3>\n                <p class=\"text-foreground text-xs leading-relaxed\">{{ sel.description }}</p>\n              </div>\n\n              <div class=\"space-y-2\">\n                <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">Technical Impact</h3>\n                <div class=\"bg-card border-border/80 text-foreground/90 rounded-md border p-3 text-xs\">\n                  {{ sel.impact }}\n                </div>\n              </div>\n\n              <!-- Package Path & Version Comparison -->\n              <div class=\"space-y-2\">\n                <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">Dependency State</h3>\n                <div class=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2\">\n                  <div class=\"border-destructive/30 bg-destructive/5 rounded-md border p-3\">\n                    <p class=\"text-destructive text-xs font-medium\">Installed Version</p>\n                    <p class=\"text-foreground mt-0.5 font-mono font-bold\">\n                      {{ sel.pkgName }}&#64;{{ sel.installedVersion }}\n                    </p>\n                    <p class=\"text-muted-foreground mt-1 text-xs\">Direct dependency in package.json</p>\n                  </div>\n\n                  <div class=\"border-success/30 bg-success/5 rounded-md border p-3\">\n                    <p class=\"text-success text-xs font-medium\">Remediation Target</p>\n                    <p class=\"text-foreground mt-0.5 font-mono font-bold\">\n                      {{ sel.pkgName }}&#64;{{ sel.fixedVersion }}\n                    </p>\n                    <p class=\"text-muted-foreground mt-1 text-xs\">Non-breaking patch update</p>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Remediation Code Diff -->\n              <div class=\"space-y-2\">\n                <div class=\"flex items-center justify-between gap-x-2\">\n                  <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                    package.json Patch Diff\n                  </h3>\n                  <span class=\"text-muted-foreground font-mono text-xs\">package.json</span>\n                </div>\n                <div class=\"overflow-hidden rounded-md border bg-zinc-950 font-mono text-xs text-zinc-100 shadow-inner\">\n                  <div\n                    class=\"text-muted-foreground flex items-center gap-2 border-b border-zinc-800 bg-zinc-900/90 px-3 py-1.5 text-xs\"\n                  >\n                    <lucide-icon [img]=\"FileCode2\" class=\"size-3.5\" />\n                    <span>dependencies</span>\n                  </div>\n                  <div class=\"space-y-1 p-3 text-xs leading-relaxed select-text\">\n                    <div class=\"bg-destructive/15 text-destructive rounded-xs px-1.5 py-0.5\">\n                      - {{ sel.remediationDiff.removed }}\n                    </div>\n                    <div class=\"bg-success/15 text-success rounded-xs px-1.5 py-0.5\">\n                      + {{ sel.remediationDiff.added }}\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Remediation CLI Command Box -->\n              <div class=\"space-y-2\">\n                <div class=\"flex items-center justify-between gap-x-2\">\n                  <h3 class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                    CLI Remediation Command\n                  </h3>\n                  <button\n                    ui-button\n                    variant=\"ghost\"\n                    size=\"xs\"\n                    class=\"h-6 gap-1 px-2 text-xs\"\n                    (click)=\"copyCommand(sel.id, sel.patchCommand)\"\n                  >\n                    @if (copiedCveId() === sel.id) {\n                      <lucide-icon [img]=\"Check\" class=\"text-success size-3\" />\n                    } @else {\n                      <lucide-icon [img]=\"Copy\" class=\"size-3\" />\n                    }\n                    <span>{{ copiedCveId() === sel.id ? 'Copied' : 'Copy command' }}</span>\n                  </button>\n                </div>\n                <div\n                  class=\"border-border bg-muted/60 flex items-center justify-between gap-x-2 rounded-md border px-3 py-2 font-mono text-xs\"\n                >\n                  <span class=\"text-foreground truncate\">{{ sel.patchCommand }}</span>\n                </div>\n              </div>\n            </div>\n\n            <div ui-sheet-footer class=\"border-border/80 flex flex-row items-center justify-end gap-2 border-t pt-4\">\n              <button ui-button ui-sheet-close variant=\"outline\" size=\"sm\" class=\"text-xs\">Close</button>\n\n              @if (!fixedPrs()[sel.id]) {\n                <button\n                  ui-button\n                  variant=\"default\"\n                  size=\"sm\"\n                  class=\"gap-1.5 text-xs font-medium\"\n                  (click)=\"handleAutoFix(sel.id)\"\n                >\n                  <lucide-icon [img]=\"GitPullRequest\" class=\"size-3.5\" />\n                  Open Auto-Fix Pull Request\n                </button>\n              } @else {\n                <span ui-badge variant=\"success\" class=\"h-8 gap-1.5 px-3 text-xs font-medium\">\n                  <lucide-icon [img]=\"Check\" class=\"size-3.5\" />\n                  PR #849 Created & Assigned\n                </span>\n              }\n            </div>\n          }\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiVulnerabilityScannerReportComponent {\n  protected readonly AlertCircle = AlertCircle\n  protected readonly AlertTriangle = AlertTriangle\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Copy = Copy\n  protected readonly Download = Download\n  protected readonly ExternalLink = ExternalLink\n  protected readonly FileCode2 = FileCode2\n  protected readonly GitPullRequest = GitPullRequest\n  protected readonly Info = Info\n  protected readonly Package = Package\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Search = Search\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly ShieldCheck = ShieldCheck\n\n  @Input('class') className?: string\n  @Input('targetRepo') set targetRepoInput(v: string | undefined) {\n    if (v !== undefined) this.targetRepo.set(v)\n  }\n  @Input('targetBranch') set targetBranchInput(v: string | undefined) {\n    if (v !== undefined) this.targetBranch.set(v)\n  }\n  @Input('baseImage') set baseImageInput(v: string | undefined) {\n    if (v !== undefined) this.baseImage.set(v)\n  }\n  @Input('lastScanned') set lastScannedInput(v: string | undefined) {\n    if (v !== undefined) {\n      this.lastScanned.set(v)\n      this.currentLastScanned.set(v)\n    }\n  }\n  @Input('grade') set gradeInput(v: string | undefined) {\n    if (v !== undefined) this.grade.set(v)\n  }\n  @Input('gradeSummary') set gradeSummaryInput(v: string | undefined) {\n    if (v !== undefined) this.gradeSummary.set(v)\n  }\n  @Input('totalDeps') set totalDepsInput(v: number | undefined) {\n    if (v !== undefined) this.totalDeps.set(v)\n  }\n  @Input('items') set itemsInput(v: CveItem[] | undefined) {\n    if (v !== undefined) this.items.set(v.map((i) => ({ ...i })))\n  }\n\n  readonly targetRepo = signal('uipkge / core-registry:v2.4')\n  readonly targetBranch = signal('main (git:a4f891b)')\n  readonly baseImage = signal('node:22-alpine3.20')\n  readonly lastScanned = signal('Scanned 12m ago via Trivy v0.52')\n  readonly grade = signal('Grade B+')\n  readonly gradeSummary = signal('2 High CVEs')\n  readonly totalDeps = signal(1284)\n  readonly items = signal<CveItem[]>(defaultCveItems.map((i) => ({ ...i })))\n\n  readonly searchQuery = signal('')\n  readonly severityFilter = signal<string>('all')\n  readonly exploitFilter = signal<string>('all')\n  readonly isScanning = signal(false)\n  readonly scanProgress = signal(100)\n  readonly currentLastScanned = signal('Scanned 12m ago via Trivy v0.52')\n  readonly selectedCve = signal<CveItem | null>(null)\n  readonly isDrawerOpen = signal(false)\n  readonly copiedCveId = signal<string | null>(null)\n  readonly fixedPrs = signal<Record<string, boolean>>({})\n  readonly exportSuccess = signal(false)\n  private copyTimer: ReturnType<typeof setTimeout> | undefined\n  private scanTimers: ReturnType<typeof setTimeout>[] = []\n  private scanInterval: ReturnType<typeof setInterval> | undefined\n\n  readonly summaryCounts = computed(() => {\n    const list = this.items()\n    return {\n      critical: list.filter((i) => i.severity === 'critical').length,\n      high: list.filter((i) => i.severity === 'high').length,\n      medium: 5,\n      low: 12,\n      total: list.length,\n    }\n  })\n\n  readonly filteredItems = computed(() => {\n    const query = this.searchQuery().trim().toLowerCase()\n    const sev = this.severityFilter()\n    const exp = this.exploitFilter()\n    return this.items().filter((item) => {\n      const matchesSeverity = sev === 'all' || item.severity === sev\n      const matchesExploit = exp === 'all' || item.exploitStatus === exp\n      const matchesSearch =\n        !query ||\n        item.id.toLowerCase().includes(query) ||\n        item.pkgName.toLowerCase().includes(query) ||\n        item.title.toLowerCase().includes(query) ||\n        item.cwe.toLowerCase().includes(query)\n      return matchesSeverity && matchesExploit && matchesSearch\n    })\n  })\n\n  get rootClass(): string {\n    return cn('w-full space-y-5', this.className)\n  }\n\n  get rescanIconClass(): string {\n    return cn('size-3.5', this.isScanning() && 'animate-spin')\n  }\n\n  severityCardClass(sev: string): string {\n    return cn(\n      'border-border/80 bg-card text-card-foreground hover:border-border cursor-pointer shadow-xs transition-colors',\n      this.severityFilter() === 'critical' && sev === 'critical' && 'border-success/50 ring-success ring-2',\n      this.severityFilter() === 'high' && sev === 'high' && 'border-destructive/50 ring-destructive ring-2',\n      this.severityFilter() === 'medium' && sev === 'medium' && 'border-warning/50 ring-warning ring-2',\n      this.severityFilter() === 'low' && sev === 'low' && 'border-info/50 ring-info ring-2',\n    )\n  }\n\n  exploitDotClass(item: CveItem): string {\n    return cn(\n      'size-2 shrink-0 rounded-full',\n      item.exploitStatus === 'poc' ? 'bg-warning animate-pulse' : 'bg-muted-foreground/50',\n    )\n  }\n\n  exploitLabelClass(item: CveItem): string {\n    return cn('text-xs font-medium', item.exploitStatus === 'poc' ? 'text-warning' : 'text-muted-foreground')\n  }\n\n  toggleSeverityFilter(sev: string): void {\n    this.severityFilter.update((prev) => (prev === sev ? 'all' : sev))\n  }\n\n  resetFilters(): void {\n    this.severityFilter.set('all')\n    this.exploitFilter.set('all')\n    this.searchQuery.set('')\n  }\n\n  triggerRescan(): void {\n    if (this.isScanning()) return\n    this.isScanning.set(true)\n    this.scanProgress.set(15)\n    this.scanInterval = setInterval(() => {\n      this.scanProgress.update((prev) => (prev < 90 ? prev + 25 : prev))\n    }, 150)\n    this.scanTimers.push(\n      setTimeout(() => {\n        if (this.scanInterval) clearInterval(this.scanInterval)\n        this.scanProgress.set(100)\n        this.isScanning.set(false)\n        this.currentLastScanned.set('Scanned just now via Trivy v0.52')\n      }, 800),\n    )\n  }\n\n  openAdvisory(cve: CveItem): void {\n    this.selectedCve.set(cve)\n    this.isDrawerOpen.set(true)\n  }\n\n  onDrawerOpenChange(open: boolean): void {\n    this.isDrawerOpen.set(open)\n    if (!open) this.selectedCve.set(null)\n  }\n\n  handleAutoFix(cveId: string): void {\n    this.fixedPrs.update((prev) => ({ ...prev, [cveId]: true }))\n  }\n\n  copyCommand(cveId: string, command: string): void {\n    if (typeof navigator !== 'undefined' && navigator.clipboard) {\n      void navigator.clipboard.writeText(command)\n      this.copiedCveId.set(cveId)\n      clearTimeout(this.copyTimer)\n      this.copyTimer = setTimeout(() => {\n        if (this.copiedCveId() === cveId) this.copiedCveId.set(null)\n      }, 2000)\n    }\n  }\n\n  exportSbom(): void {\n    const sbomData = {\n      spdxVersion: 'SPDX-2.3',\n      dataLicense: 'CC0-1.0',\n      SPDXID: 'SPDXRef-DOCUMENT',\n      name: 'uipkge-core-registry-sbom',\n      documentNamespace: 'https://uipkge.dev/spdxdocs/core-registry-v2.4',\n      creationInfo: {\n        created: new Date().toISOString(),\n        creators: ['Tool: Trivy-v0.52', 'Organization: UIPKGE Security Squad'],\n      },\n      packages: this.items().map((item) => ({\n        name: item.pkgName,\n        SPDXID: `SPDXRef-Package-${item.pkgName}`,\n        versionInfo: item.installedVersion,\n        downloadLocation: `https://registry.npmjs.org/${item.pkgName}/-/${item.pkgName}-${item.installedVersion}.tgz`,\n        filesAnalyzed: false,\n        securityVulnerabilities: [\n          {\n            id: item.id,\n            severity: item.severity.toUpperCase(),\n            cvssScore: item.cvssScore,\n            remediation: item.fixedVersion,\n          },\n        ],\n      })),\n    }\n    if (typeof document !== 'undefined') {\n      const jsonStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(sbomData, null, 2))\n      const downloadAnchor = document.createElement('a')\n      downloadAnchor.setAttribute('href', jsonStr)\n      downloadAnchor.setAttribute('download', `sbom-spdx-core-registry-${new Date().toISOString().slice(0, 10)}.json`)\n      document.body.appendChild(downloadAnchor)\n      downloadAnchor.click()\n      downloadAnchor.remove()\n      this.exportSuccess.set(true)\n      this.scanTimers.push(\n        setTimeout(() => {\n          this.exportSuccess.set(false)\n        }, 2000),\n      )\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/vulnerability-scanner-report/vulnerability-scanner-report.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/vulnerability-scanner-report/index.ts",
      "content": "export {\n  UiVulnerabilityScannerReportComponent,\n  type CveItem,\n  type CveSeverity,\n  type ExploitStatus,\n} from './vulnerability-scanner-report.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/vulnerability-scanner-report/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/progress.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/sheet.json",
    "https://uipkge.dev/r/angular/table.json"
  ],
  "description": "Snyk and Trivy style CVE vulnerability scanner report and dependency security audit with severity breakdown cards, CVSS metrics, package version diffs, advisory inspection drawer, and automated remediation PR actions.",
  "categories": [
    "security",
    "dashboard",
    "devops"
  ]
}