Workflow column: FP# only, urgency-based colors

- Backend: only extract FP# workflows; SYS# auto-generated tickets
  are no longer stored or shown (not actionable for triage purposes).
  Findings with no FP# ticket show blank in the workflow column.
- Frontend: recolor workflow badges by action urgency —
  Expired/Rejected = red (act now), Reworked/Actionable = amber
  (resubmit), Requested = blue (waiting on approval).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-11 15:36:02 -06:00
parent 2d1acca990
commit bc9e223ab7
2 changed files with 25 additions and 27 deletions

View File

@@ -130,33 +130,31 @@ function extractFinding(f) {
// CVE list: vulnerabilities.vulnInfoList[].cve
const cves = (f.vulnerabilities?.vulnInfoList || []).map(v => v.cve).filter(Boolean);
// Workflow: flatten all distribution buckets, prioritise FP# over SYS#
// Workflow: only capture FP# (False Positive) tickets — SYS# are auto-generated
// system workflows and not actionable for our purposes.
const wfDist = f.workflowDistribution || {};
const allWfEntries = [
...(wfDist.actionableWorkflows || []),
...(wfDist.requestedWorkflows || []),
...(wfDist.approvedWorkflows || []),
...(wfDist.reworkedWorkflows || []),
...(wfDist.rejectedWorkflows || []),
...(wfDist.expiredWorkflows || []),
...(wfDist.latestSystemWorkflows || []),
];
// FP# (False Positive tickets) take priority over SYS# (system workflows)
const fpEntry = allWfEntries.find(w => (w.generatedId || '').startsWith('FP#'));
const sysEntry = allWfEntries.find(w => (w.generatedId || '').startsWith('SYS#'));
const wfEntry = fpEntry || sysEntry || allWfEntries[0] || null;
const fpBuckets = [
...(wfDist.actionableWorkflows || []),
...(wfDist.requestedWorkflows || []),
...(wfDist.reworkedWorkflows || []),
...(wfDist.rejectedWorkflows || []),
...(wfDist.expiredWorkflows || []),
...(wfDist.approvedWorkflows || []),
].filter(w => (w.generatedId || '').startsWith('FP#'));
// If the distribution didn't surface an FP#, also check workflowGeneratedNames directly.
// (Some FP# tickets only appear in the names list without full state info.)
// Priority: actionable > requested > reworked > rejected > expired > approved
const fpEntry = fpBuckets[0] || null;
// Fallback: if no FP# in distribution, check workflowGeneratedNames directly
const generatedNames = f.workflowGeneratedNames || [];
const fpFromNames = !fpEntry
? generatedNames.find(n => n.startsWith('FP#')) || null
: null;
const workflow = wfEntry ? {
id: wfEntry.generatedId || '',
state: wfEntry.state || '',
type: wfEntry.type || wfEntry.acronym || '',
const workflow = fpEntry ? {
id: fpEntry.generatedId || '',
state: fpEntry.state || '',
type: 'FP',
} : fpFromNames ? {
id: fpFromNames,
state: '',