Dependency Track Vulerability Processor
  • Python 55%
  • TypeScript 26.2%
  • Vue 18.4%
  • JavaScript 0.2%
  • Shell 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Philipp A. Baer b0283942f6
All checks were successful
Build and Publish Docker Images / delete-pr-images (push) Has been skipped
Build and Publish Docker Images / test-backend (push) Successful in 54s
Build and Publish Docker Images / test-frontend (push) Successful in 28s
Build and Publish Docker Images / test-agentyzer (push) Successful in 21s
Build and Publish Docker Images / test-e2e (push) Successful in 14s
Build and Publish Docker Images / check-version (push) Has been skipped
Build and Publish Docker Images / create-tag (push) Has been skipped
Build and Publish Docker Images / build-push-images (push) Successful in 2m25s
Build and Publish Docker Images / release (push) Successful in 21s
feat: simplify applying all automatic team assessments (#188)
Improve performance even more and introduce a GIL-free backend.

Reviewed-on: #188
2026-08-04 06:39:12 +00:00
.github/workflows feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
.vscode feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
agentyzer feat: benchmarking generated and manual assessments (#166) 2026-07-13 03:35:17 +00:00
data feat: improve the auto assessment flow (#186) 2026-07-30 13:27:43 +00:00
docs feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
dtvp feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
frontend feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
openapi feat: auto assessment bulk accept (#174) 2026-07-20 04:02:59 +00:00
sbom feat: improve the auto assessment flow (#186) 2026-07-30 13:27:43 +00:00
scripts feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
skills feat: add-attributedon-filter (#160) 2026-06-29 12:49:42 +00:00
test_setup fix: improve performance (#187) 2026-07-30 16:03:52 +00:00
tests feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
.env.dist feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
.env.test feat: make assessments and DT state exportable (#163) 2026-07-02 04:53:41 +00:00
.gitignore feat: integrate code analysis (#139) 2026-05-04 04:22:52 +00:00
AGENTS.md feat: add-attributedon-filter (#160) 2026-06-29 12:49:42 +00:00
cliff.toml fix: use git commits from local workspace phbaer/dtvp#84 2026-03-16 05:15:41 +01:00
compose.gil.yml feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
compose.yml feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
Dockerfile feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
Dockerfile.free-threaded feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
ecosystem.config.js feat: make assessments and DT state exportable (#163) 2026-07-02 04:53:41 +00:00
LICENSE Add MIT license 2026-02-16 16:15:37 +00:00
nginx.conf.template fix: improve performance (#187) 2026-07-30 16:03:52 +00:00
pyproject.toml feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
README.md feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00
renovate.json feat: add changelog generation phbaer/dtvp#84 (#85) 2026-03-16 03:42:05 +00:00
start.sh fix: improve performance (#187) 2026-07-30 16:03:52 +00:00
uv.lock feat: simplify applying all automatic team assessments (#188) 2026-08-04 06:39:12 +00:00

Dependency Track Vulnerability Processor (DTVP)

DTVP is a FastAPI and Vue application for reviewing Dependency-Track findings across every version of a project. It groups findings by vulnerability, exposes version-by-version assessment state, and lets reviewers apply consistent changes without repeating the same work for every release.

This README is the canonical project overview for humans and AI agents. If it conflicts with source, tests, package metadata, lockfiles, or runtime configuration, trust those sources and update this file. Keep AGENTS.md, Copilot instructions, and skills/*/SKILL.md as short entry points back here.

What DTVP Does

  • Groups the same vulnerability across project versions and components.
  • Distinguishes open, assessed, incomplete, inconsistent, and approval-needed lifecycle states.
  • Supports global and team-specific assessments, CVSS rescoring, bulk repair, and audit-backed recovery of lost rescoring metadata.
  • Optionally integrates threat-model rescoring through tmrescore/vscorer.
  • Optionally runs reachability and exploitability analysis through Agentyzer or another compatible code-analysis service.
  • Exports and imports versioned project archives for restore, replacement, and retention workflows.
  • Includes mock Dependency-Track, tmrescore, and code-analysis services for local development and tests.

Quick Start

Requirements: Python 3.14+, Node.js 22+, uv, npm, and pm2. Docker and Docker Compose are needed only for the packaged deployment.

uv sync --dev
cd frontend
npm ci --include=optional
cd ..
pm2 start ecosystem.config.js --update-env
Service URL
Frontend http://localhost:5173
Backend API http://localhost:8000/api/version
Mock Dependency-Track http://localhost:8081
Mock tmrescore http://localhost:8090/ui
Mock code analysis http://localhost:8095

For mock login, open /login, choose Sign in with SSO, then select Login as Reviewer on the mock Dependency-Track page.

Stop the stack with:

pm2 delete mock-dt mock-tmrescore mock-code-analysis dtvp-backend dtvp-frontend

Command Reference

Use uv from the repository root for Python/backend work and npm from frontend/ for frontend work.

Task Command
Install backend dependencies uv sync --dev
Install frontend dependencies cd frontend && npm ci --include=optional
Start the full mock stack pm2 start ecosystem.config.js --update-env
Inspect or tail the stack pm2 list / pm2 logs
Run all Python tests, including Agentyzer uv run pytest
Run Agentyzer tests only cd agentyzer && uv run pytest
Run frontend unit tests cd frontend && npm run test:unit -- --run
Run focused frontend tests cd frontend && npm run test:unit -- ProjectView
Build the frontend cd frontend && npm run build
Run local-stack UI tests cd frontend && npm run test:ui
Benchmark grouped-query concurrency uv run python scripts/benchmark_group_queries.py
Capture README screenshots cd frontend && npm run test:ui:docs
Start the packaged deployment cp .env.dist .env && docker compose up -d
Start the GIL-enabled fallback deployment docker compose -f compose.yml -f compose.gil.yml up -d --build

The CI end-to-end job uses the Playwright container image in .github/workflows/build-publish.yml. When upgrading @playwright/test, update that image tag in the same change.

Repository And Architecture

Repository Map

Path Purpose
dtvp/ FastAPI routes, services, domain logic, runtime wiring, and integrations
agentyzer/ Bundled code-analysis service and assessment pipeline
frontend/ Vue 3, Vite, and Tailwind single-page application
test_setup/ Mock Dependency-Track, tmrescore, and code-analysis services
tests/ Backend pytest suite
data/ Local configuration, cache data, mappings, rules, and archives
dtvp/migrations/ Numbered SQLite migrations for local stores
openapi/ Static OpenAPI specs for optional integrations
docs/ Integration notes, diagrams, screen guide, and generated screenshots
skills/ Project-local AI entry points that route back to this README

The generic project skill is skills/project-entrypoint/SKILL.md; skills/dtvp-project-memory/SKILL.md is the compatibility entry point.

Runtime Shape

Browser
  -> Vue SPA (Vite in development, FastAPI/nginx in production)
  -> FastAPI backend
  -> Dependency-Track API + local cache
  -> optional tmrescore and code-analysis services

Important backend components:

Component Role
dtvp/boot.py Binds early, serves startup status, then loads the real ASGI app
dtvp/main.py and app_wiring.py App lifecycle, middleware, dependency construction, routers, and task stores
dtvp/general_api_routes.py Projects, grouped tasks, task windows, statistics, assessments, and dependency chains
dtvp/grouped_vuln_services.py Concurrent finding, vulnerability, and BOM collection before grouping
dtvp/task_group_query_services.py Backend filtering, sorting, facets, pagination, and task-window queries
dtvp/logic.py Grouping, ownership, assessment parsing, CVSS, statistics, and dependency analysis
dtvp/assessment_* and rescore_rule_services.py Assessment writes, conflict handling, metadata recovery, and CVSS rules
dtvp/assessment_outbox_services.py Transactional assessment overlays, revisions, and pending Dependency-Track synchronization
dtvp/bulk_workflows/ Registry-backed bulk-change plug-ins
dtvp/dt_client.py and dt_cache.py Dependency-Track access, cached data, overlays, and pending writes
dtvp/project_archive_* Project archive export/import and scheduled snapshots
dtvp/tmrescore_* Threat-model integration, inventory, cache, execution, and task state
dtvp/code_analysis_* and analysis_queue_* Analyzer integration, result store, queue, and automatic scans

Important frontend components:

Component Role
frontend/src/main.ts, App.vue, router.ts App shell, routing, authentication, and startup handling
frontend/src/lib/api.ts and types.ts Backend client and shared integration/domain types
frontend/src/pages/ Dashboard, project review, statistics, settings, tmrescore, and code analysis
frontend/src/components/ Vulnerability rows/details, filters, dialogs, queue UI, CVSS, and dependency paths
frontend/src/lib/ Filter/task-window models, composables, caching, updates, and project state

Runtime Behavior

  • Grouped-vulnerability tasks use response_mode=summary for compact list rows. /api/tasks/{task_id}/events streams progress, /api/tasks/{task_id}/groups serves filtered windows and facets, and /api/tasks/{task_id}/groups/{group_id} hydrates full details. Task mutations wake all event-stream clients through one shared event hub instead of one polling loop per client. Serialized status is reused across clients, progress streams carry only the latest 20 log entries, and a 15-second blank heartbeat keeps idle streams open.
  • Partial version results appear while grouping continues. Summary tasks publish at the first version, roughly one-third milestones, and completion instead of rebuilding cumulative snapshots after every tenth of the project. CPU-heavy grouping, indexing, and filtering run outside the async event loop. When the final partial publish already contains every version, it becomes the completed snapshot without repeating grouping and index construction.
  • Grouped-task searches use thread-safe per-task query caches, share identical in-flight queries, and reuse sort orders across filter changes. They run in a dedicated bounded executor so cold searches cannot exhaust the default application thread pool; queued browser searches are discarded when a newer generation supersedes them. Cached result indexes use packed integers and are evicted against both entry-count and approximate byte budgets. Lightweight code-assessment metadata is cached and invalidated when analyzer results change. Derived automatic-assessment facets and team-group context are reused until their metadata or configuration revision changes.
  • Grouped snapshot construction runs in a separate bounded worker pool from foreground filters and vulnerability-detail hydration. This prevents several simultaneous project builds from filling the application thread pool; the default single build worker also avoids wasteful GIL contention. Detail hydration has its own reserved pool, so project builds and cold searches do not consume every slot needed to open a vulnerability.
  • The global analysis indicator polls one compact queue-and-sweep status response: every five seconds while work is active and every 30 seconds while idle, with per-client jitter. Hidden browser tabs pause polling, and detailed queue payloads load only while the queue panel is opened.
  • Project smart search waits 400 ms for continued typing and aborts superseded result-window requests. Deactivated keep-alive project views stop their cache freshness timers. Cache-status filesystem counts are reused for up to five seconds and invalidated when DTVP changes cached content.
  • Queue submission and deduplication use in-memory FIFO and target indexes rather than rescanning and reindexing the complete queue. Detailed queue reads are newest-first and limited to 100 items by default (200 maximum); automatic and manual submissions share a configurable pending-item limit.
  • The frontend viewport-windows list rows, coalesces partial refreshes, and hydrates dependency paths and full assessment details only when needed. Follow-up pages and full-result drains omit facet counts they do not consume; the initial/filter request retains complete task-wide and filtered counts.
  • The local cache under DTVP_DT_CACHE_PATH stores projects, findings, vulnerability details, BOMs, local overlays, and pending writes. Stale cached data remains readable while Dependency-Track is unavailable. Concurrent misses for the same resource share one Dependency-Track request, the complete project list has a short freshness TTL across clients, and API-key requests reuse one application-lifetime HTTP connection pool. The background cache sync also retains its client between refreshes. Each caller still receives an isolated mutable snapshot. Cold finding loads use Dependency-Track's Finding Packaging Format export so assessment state and details arrive in one request instead of issuing one analysis request per finding. Older Dependency-Track versions fall back to the legacy endpoint. Cache JSON is encoded and atomically replaced by one ordered writer thread; async operations await durability without holding the event loop or cache lock. A monotonic cache generation keys grouped snapshots, and summaries created during a cold fill are saved against the generation after that fill. Pending assessment writes and their local overlays live in a transactional SQLite outbox. Newer changes to the same finding replace older pending values, and one application-wide bounded dispatcher retries Dependency-Track synchronization without multiplying write concurrency per client. When a finding disappears before synchronization, a Dependency-Track 404 triggers a live findings-API check. Only a valid response confirming that the exact project/component/vulnerability tuple is absent drops the queued revision and its unsynced overlay; failed checks and findings that still exist keep retrying. Legacy pending_updates.json entries import once on first use. Interactive and bulk assessment requests return after the outbox transaction commits instead of waiting for Dependency-Track. Per-finding local revisions reject stale DTVP edits atomically; optional strict conflict mode additionally performs live Dependency-Track reads before accepting a save. Grouped-task artifacts carry reverse finding indexes, so accepted changes copy and re-summarize only affected groups; their list-query index is rebuilt lazily on the next read instead of delaying the save.
  • Grouped-vulnerability tasks are access-controlled to users who independently requested the exact project/CVE/mode/cache/mapping snapshot; those matching requests share one task and result allocation. Their bulk-workflow operations, uploaded or generated archive tasks, and live tmrescore sessions remain private to the authenticated user who created them. Shared Dependency-Track assessments, the workspace-wide analyzer queue and saved analysis results, and cached project proposal snapshots remain collaborative application data.
  • Live task registries are process-local; the supplied Uvicorn/PM2 launch uses one backend worker. A horizontally scaled deployment needs a shared task and result store before enabling multiple backend workers.
  • Startup status exists at /startup and /api/startup, in the static first paint, and in the Vue initialization view.

Capacity Planning

The current single-process deployment should be planned for roughly 8-12 simultaneously active users on very large projects, or 30-50 active users on medium projects. Mostly idle or dashboard users are substantially cheaper; 100-300 concurrent sessions is a reasonable starting estimate when they are not all retaining large grouped-vulnerability tasks.

These are sizing estimates, not production guarantees. The reproducible benchmark below was run on a 20-CPU, 15 GiB host with 20,000 groups, filtered facet counts enabled, and ten cold searches per simulated user:

Runtime Simultaneous searches Throughput p95 search latency
CPython 3.14.4, GIL enabled 1 19.6 queries/s 78 ms
CPython 3.14.4, GIL enabled 4 21.1 queries/s 355 ms
CPython 3.14.4, GIL enabled 8 22.0 queries/s 523 ms
CPython 3.14.4, free-threaded 1 18.1 queries/s 71 ms
CPython 3.14.4, free-threaded 4 57.2 queries/s 91 ms
CPython 3.14.4, free-threaded 8 67.8 queries/s 155 ms

For this CPU-heavy path, free threading provides real multi-core scaling: at four simultaneous cold searches it delivered about 2.7x the throughput and cut p95 latency by about three quarters. Moving from four to eight free-threaded workers gave only about 19% more throughput while increasing p95 by about 71%. Four query workers therefore remains the balanced default. Identical cached searches remained below 1 ms in every case; new search/filter combinations and their facet counts are the limiting query path.

The same 20,000-group query index retained about 65 MiB of traced Python allocations with the GIL build and 69 MiB with the free-threaded build. Real tasks also retain full vulnerability, component, dependency, and BOM details; budget roughly 150-300 MB or more for each large retained task. Matching project/CVE/mode/cache/mapping requests share one access-controlled task, and completed tasks are retained for 15 minutes by default. Memory remains the likely limit when many users open distinct large projects.

For conservative per-instance planning:

  • large projects with active searching: 8-12 users comfortably; around 20 is likely to show latency or memory pressure;
  • medium projects: 30-50 active users;
  • mostly browsing or dashboard use: 100-300 sessions, assuming few retained large tasks;
  • code-analysis jobs: one runs concurrently by default through DTVP_ANALYSIS_QUEUE_CAPACITY; additional jobs wait in the shared queue.

Before increasing those ranges, use production-shaped load tests. The next scaling steps are validating the free-threaded image with real project mixes, tuning the grouped-task retention/count caps against available RAM, and introducing a shared task/result store before multiple backend processes are enabled. More Uvicorn workers are not safe while live task registries remain process-local.

Reproduce the grouped-query measurements with:

uv run python scripts/benchmark_group_queries.py \
  --groups 1000 5000 10000 20000 \
  --concurrency 1 4 8 16

The benchmark generates deterministic groups, primes only the reusable sort order, and then measures new search/filter contexts separately from identical cached requests. It reports build time, retained Python allocations, throughput, and p50/p95 latency in the dtvp.group-query-benchmark/v1 schema; add --json for machine-readable output and --no-counts to model follow-up pages. Compare the normal project runtime with a clean 3.14t interpreter on the same host (the benchmark itself has no third-party dependencies):

uv run python scripts/benchmark_group_queries.py
uv run --no-project --python 3.14t python scripts/benchmark_group_queries.py

Domain Model

Vulnerabilities And Assessments

A grouped vulnerability joins equivalent IDs and aliases across versions. Its aggregate state follows these rules:

  • Common analysis states are NOT_SET, EXPLOITABLE, IN_TRIAGE, RESOLVED, FALSE_POSITIVE, and NOT_AFFECTED.
  • A non-NOT_SET General assessment takes precedence; otherwise DTVP chooses the worst team state using the priority in dtvp/logic.py.
  • Inconsistency reasons are indexed separately: missing rescoring metadata, differing analysis states, differing structured team blocks, and differing substantive details. Selected reasons use OR semantics; filter categories combine with AND semantics.
  • Assessment details use structured blocks such as [Team: ...], [State: ...], [Assessed By: ...], [Reviewed By: ...], [Rescored Vector: ...], and [Assigned: ...].
  • Structured details retain at most one block per team (case-insensitive). Team assessments are not copied into the General block, and generated General summaries from older sync operations are removed on the next sync.
  • Dependency paths come from CycloneDX BOM dependency graphs. Dependency-Track attribution timestamps are retained as attributed_on.

CVSS rescoring is data-driven through RESCORE_RULES_PATH (default data/rescore_rules.json). The shipped NOT_AFFECTED and FALSE_POSITIVE transitions support CVSS 2.0, 3.0, 3.1, and 4.0 and produce exactly 0.0. Vectors preserve their original CVSS version and base metrics. Cross-version, malformed, or incomplete vectors stay visible for manual review rather than being rewritten speculatively.

A configured transition owns the vector of the state it covers. Whenever a state with a rule is written — by the reviewer, by a code-analysis draft, or by a bulk apply — the rule is layered on top of the proposed vector and the base metrics of the Dependency-Track vector are restored, so an analyzer proposal contributes only its extra metrics. States without a transition keep the analyzer's proposed vector and score unchanged.

Team Mapping And Analyzer Guidance

TEAM_MAPPING_PATH defaults to data/team_mapping.json and is editable in Settings. Keys are deterministic CycloneDX component selectors:

Selector Match
name Ungrouped or name-only component, case-insensitive
group:name Group and name, case-insensitive
purl::pkg:type/namespace/name PURL; version/qualifiers/subpath are ignored unless explicitly supplied
cs::name, cs::group:name Case-sensitive name or group/name
cs,purl::... Case-sensitive PURL
nogroup::name Only components known to have no group
cs,nogroup::name Case-sensitive no-group match
* Fallback team; never creates an automatic scan target

Single-colon keys such as cs:name are ordinary group:name selectors; modifiers require ::. Precedence is PURL, grouped, no-group, plain name, case-sensitive specificity, exact case, then lexical key order. Mapping does not otherwise match BOM refs, Dependency-Track UUIDs, or component versions.

Values are either a primary team string or an array whose first entry is the primary label and remaining entries are historical aliases.

TEAM_GROUPS_PATH defaults to data/team_groups.json and is also editable in Settings. Each group has explicit direct teams and nested groups, so an abstract group can be composed from existing teams and groups while a group such as Core-MUC can also include the existing Core-MUC team:

{
  "Core-MUC": {
    "teams": ["Core-MUC", "3rd Party"],
    "groups": []
  },
  "Product Engineering": {
    "teams": ["Runtime"],
    "groups": ["Core-MUC"]
  }
}

Team references accept configured aliases and are normalized to their primary team. Unknown teams or groups, empty groups, duplicate members, and cycles are rejected when the configuration is saved. Group statistics expand nested membership and count each vulnerability once per group, even when it carries both parent-team and subteam tags.

Analyzer guidance comes from DTVP_AUTO_ANALYSIS_GUIDANCE_PATH (default data/auto_analysis_guidance.json) and uses the same selectors:

{
  "components": {
    "component-name": "extra reviewer context"
  }
}

Values may be strings, arrays, or objects with guidance/prompt. Optional default or * content is prepended. Guidance matches the selected owned scan target, applies without restart, and is context only: it cannot establish dependency presence, version, reachability, or affectedness without evidence. A changed guidance fingerprint makes an automatic result eligible for rescanning.

Workflows

Project Review

The project view searches and filters grouped vulnerabilities by lifecycle, inconsistency reason, analysis state, dependency relationship, component, version, team, assignee, attribution age, tmrescore proposal, CVSS mismatch, code-assessment availability, automatic-analysis outcome, and proposed automatic CVSS severity. Outcome choices (Affected, Probably affected, Not affected, and Uncertain) and rescore choices (Critical through Info, No rescore, and Unscored) use OR semantics within each facet and AND semantics across facets. They are server-side task-window filters, so URL state, counts, pagination, and Bulk Changes all operate on the same candidate set. The Open selection matches the displayed OPEN lifecycle category, and vulnerability-ID searches are combined with all active filters.

The Filters sidebar provides a searchable, alphabetically sorted Team dropdown from the complete task facet list. Selecting a team uses a case-insensitive exact name match; team: smart-search tokens remain available for free-form team searches. The top search result count is the final number of grouped vulnerabilities after every active filter, independent of how many paginated rows are currently loaded. When filters reduce the task, it is shown relative to the unfiltered task total. Every filter-chip count and the Team open/assessed breakdown is calculated from that same final filtered result. Complete task-wide facets remain available as filter choices even when their current filtered count is zero. Overlapping properties such as teams and inconsistency reasons can therefore have counts whose sum exceeds the final result count. When groups are configured, the Results tab renders one Per Group table with indented nested groups, direct team members, and non-grouped teams at the root, so each parent total can be compared with its subgroup and team totals without a duplicate Per Team box. Group totals expand the hierarchy and deduplicate vulnerabilities across member teams. Without group configuration, the existing Per Team table remains as the fallback; it groups configured aliases into their canonical team and shows aliases beneath the primary team. A vulnerability carrying both canonical and alias names is counted only once there.

The detail workspace provides:

Tab Purpose
Overview Advisory, references, affected components, ownership, and dependency context
Assessments Current Dependency-Track assessment blocks
Code Analysis Target selection, queue/history, verdict, evidence, draft, ticket, and artifacts
Review Global assessment editor with CVSS/rescoring, tmrescore, analyzer notes, and reviewer context; team assessment editor
Team Mapping Reviewer-only ownership editor

CVSS and rescoring controls appear in the reviewer-only Global subview of Review so the score and assessment can be evaluated and applied together. Team subviews omit global rescoring controls. Local drafts survive tab changes. Closing or switching a vulnerability prompts the reviewer to apply, discard, or keep editing. Assessment writes refresh the active task window, and route state preserves filters when navigating to statistics or code analysis. Once the transactional local save succeeds, the card reports that it is saved locally while Dependency-Track synchronization continues in the background; retry failures remain visible without blocking another edit. Per-finding local revisions are retained across list updates so subsequent edits keep conflict protection. Each vulnerability card can reload its current assessment directly from Dependency-Track; the refreshed task snapshot updates the card, lifecycle filters, and counts together. Vulnerability headers use compact status icons to show both available and unavailable states for tmrescore/vscorer and code-analysis assessments. In the compact list, the Dependency-Track reload action stays at the bottom-right of the header so it does not overlap the assessed corner marker.

Bulk Changes

The reviewer-only Bulk Changes dialog runs one plug-in workflow at a time:

Workflow Candidates and action
Apply Automatic Assessments Usable, unapplied analyzer assessments; writes one assessment per owning team plus a global assessment with the worst verdict and its CVSS rescore
Sync Incomplete Assessments Groups whose otherwise consistent assessment is missing from some findings
Restore Rescored CVSS Assessed findings with one unambiguous current vector recoverable from audit comments
Repair Rescoring Definitions Findings where a configured state-based CVSS rescore is missing, incomplete, or incorrect; repairs every safely actionable finding

Repair Rescoring Definitions includes cases where a transition such as NOT_AFFECTED should produce a 0.0 score but no rescore was stored. Preview rows show why each finding is a mismatch and place the stored vector and score beside the fixed values that will be written. Findings with a matching transition but a missing or unsupported original CVSS vector remain listed for manual review instead of being silently omitted. Apply Automatic Assessments rows likewise show the current vulnerability CVSS and the automatic rescore that will be written to every eligible finding, together with the teams that receive an assessment and any analyzed component without a team. Its composable selection filters cover every automatic-analysis outcome and every proposed CVSS severity, plus candidates with no rescore or a vector-only unscored proposal. Multiple choices within a facet use OR semantics, while the outcome and rescore facets combine with AND semantics. They filter the visible rows and reset the apply selection to those rows. Their labels, values, and rescore-band classification are shared with the main Filters sidebar. Lightweight saved-result metadata retains the proposed score and vector for this preview; older metadata rows are rebuilt automatically from their stored full results.

Every candidate set is the intersection of all active project-list filters and the selected workflow's applicability rules. The dialog loads plug-in metadata first and prepares only the chosen preview. Preview tokens prevent applying a stale candidate set; prepared previews are reused while the dialog is open. Filtering uses compact task summaries, then carries their canonical lifecycle metadata onto the hydrated full groups used by workflows. This keeps lifecycle- specific workflows such as Sync Incomplete Assessments aligned with the visible filtered list.

The UI starts preview, apply, and document work as background operations and polls their short status endpoint. The operation survives the initiating HTTP request, so reverse-proxy request timeouts do not cancel long bulk changes. Apply operations commit all selected changes to the transactional local outbox and expose item-level progress through the task status. Dependency-Track writes then use the shared bounded background dispatcher with coalescing and retry backoff, so large applies do not hold an HTTP request open or multiply upstream write concurrency. Endpoints are:

  • POST /api/bulk-workflows/summary
  • POST /api/bulk-workflows/{workflow_id}/{preview|apply|document}-task
  • GET /api/bulk-workflows/tasks/{operation_id} returns progress and the final result

The synchronous preview, apply, and optional document endpoints remain available for API compatibility.

Automatic-assessment discovery accepts current, reviewer-started, and source-less legacy records when an assessment can be extracted. Benchmark and explicitly non-final records are excluded. Matching uses vulnerability ID or alias plus project context; it does not rely on stale client IDs.

Rows label assessment coverage as:

  • auto: complete automatic coverage.
  • manual: complete reviewer-started coverage.
  • mixed: both automatic and reviewer-started coverage.
  • partial: one or more grouped components have no code assessment.

The result store maintains dedicated assessment metadata for every saved run. Task windows expose code_assessment_status and calculate filter counts from that server-side property; the browser does not download result payloads or assemble a parallel ID filter. Existing stores backfill metadata once through the numbered SQLite migration path.

For apply, all relevant analyzer runs are combined using the most severe overall verdict: Affected becomes EXPLOITABLE; Probably Affected and Uncertain become IN_TRIAGE; Not Affected becomes NOT_AFFECTED.

Applied details carry one assessment block per owning team plus the global block, matching the vulnerability card's Apply all to <n> teams action. A team's block holds the analyzer evidence for the components it owns and its own worst-wins state and justification; ownership uses the same team mapping and dependency-path resolution as automatic scan targets, with the run's recorded target team as fallback. The global block carries the worst state across all runs, its justification, and the CVSS rescore of that worst run — a milder run never contributes the global vector or score, even when its proposed score is higher. When the global state has a configured rescore transition, that rule produces the written vector and score, so Repair Rescoring Definitions reports nothing right after an apply. Components that no team owns keep their evidence in the global block and are listed in the preview row. Applied details retain every relevant run, the analyzer-generated summary and rationale verbatim, and all decision-relevant advisory conclusions, version notes, research findings, remediation recommendations, audit checks, and CVSS reasons without arbitrary character or item limits. Assessment details use sectioned prose and bullets; raw scan inventories, process prompts, and the analyzer's generated report are not copied into the rationale when their conclusions are already represented semantically. Ticket drafts remain separate from assessment details. Application provenance prevents successfully applied or queued run/finding pairs from being offered again. Previews use only compact metadata; apply and document export hydrate full payloads for the selected groups. Findings are identified by their finding UUID when present, otherwise by project, component, and vulnerability UUIDs.

Project Archives

Reviewer-only archives preserve project versions, SBOMs, findings, vulnerability details, and normalized assessments.

  • Export: POST /api/project-archives/exports
  • Import preview: POST /api/project-archives/imports
  • Apply: POST /api/project-archives/imports/{task_id}/apply with create_missing or update
  • Stored snapshots: GET /api/project-archives/snapshots
  • Schema: dtvp.project-archive/v1

Restore matches project name/version first, then remaps changed UUIDs by component PURL/name/version/BOM ref and vulnerability ID/name/aliases. Audit history and comments are not replayed. ZIPs default to data/project_archives; optional Git-friendly expanded trees default to data/project_archives_git.

Threat-Model Rescoring

Set DTVP_TMRESCORE_URL to enable the project Threat Model workspace. Users can upload a .tm7 model and optional items.csv, analysis configuration, or MITRE countermeasures, then cache proposal snapshots for reviewer dialogs.

The integration supports vscorer's session/inventory contract, normalized step-based progress, chain/prioritization/what-if analysis, MITRE enrichment, offline mode, provider-neutral LLM enrichment, and output download maps. A skeptic_gate_failed response is terminal and requires manual review. DTVP submits inventory runs with vscorer's background-analysis contract and polls the session progress/result endpoints, so long NVD-enriched analyses are not tied to one HTTP response or cancelled by a caller/proxy disconnect. It retains the blocking-call timeout and gateway fallback for older vscorer deployments and reads the persisted result error when a background run fails.

SBOM modes are latest-only or merged multi-version. The merged mode keeps a separate root per version so historical findings remain visible without being misrepresented as current inventory.

Code Analysis

Set DTVP_CODE_ANALYSIS_URL to enable reachability/exploitability analysis. DTVP queues requests containing the vulnerability, selected owned target, CVSS vector, affected product versions, dependency context, reviewer/static guidance, optional tmrescore context, and optional LLM metadata.

Final results pass through a deterministic claim audit that aligns verdict and reasoning, flags unsupported claims or downgrades, and restores original CVSS when a downgrade is rejected. Version presence alone is capped at Probably Affected unless reachability, exploitability, or a positive transitive path is confirmed. Static guidance is never evidence by itself.

Results, Dedupe, And Follow-Ups

Completed results are stored in SQLite at DTVP_CODE_ANALYSIS_RESULTS_PATH. The store retains full payloads separately from lightweight assessment metadata, plus run/job IDs, parent links, model metadata, target context, and application provenance. Numbered migrations live in dtvp/migrations/code_analysis_results; a legacy sibling JSON cache imports on first use.

Automatic scans deduplicate against saved results and the live queue using a fingerprint of the vulnerability, target, versions, components, dependency context, aliases, CVSS, and static guidance. A changed fingerprint is eligible again; DTVP_CODE_ANALYSIS_RESULT_FRESHNESS_DAYS can additionally age out a matching result.

Follow-ups use source=follow-up, retain parent_run_id, and prefer the analyzer's /jobs/{job_id}/follow-up endpoint. Otherwise DTVP sends a normal request with bounded persisted parent context.

The code-analysis dashboard polls every five seconds while work is active and every 15 seconds while idle, pauses in hidden tabs, and applies per-client jitter. DTVP shares a short-lived dashboard snapshot across clients so one polling wave causes one analyzer health/jobs lookup and one recent-result query.

Result APIs:

  • GET /api/code-analysis/results
  • GET /api/code-analysis/results/{run_id}
  • DELETE /api/code-analysis/results/{run_id}
  • POST /api/code-analysis/results/{run_id}/compact
  • POST /api/code-analysis/results/{run_id}/benchmark
  • GET /api/projects/{project}/vulnerabilities/{vuln_id}/analysis-results

Project Workspace And Dashboard

The vulnerability card contains target selection, queue/history, verdict and evidence, an editable assessment draft, benchmark comparison, component results, ticket draft, version coverage, LLM conversation, and pipeline artifacts. The metadata badge and lightweight history for the current vulnerability load automatically; a full result (including its LLM conversation) loads only when its row is opened. Runs can then be removed, applied, benchmarked, or used as parents for follow-ups.

When several components of one vulnerability have their own saved analyzer result, Apply all to <n> teams stages all of them at once. Each team receives the latest result of the components it owns, combined worst-wins when it owns more than one, and the global assessment takes state, justification, CVSS vector, and score from the worst result across all of them. The global block keeps its existing text because the reasoning already lives in the team blocks. Benchmark runs, unfinished runs, and superseded runs of the same component are never candidates, and components without a team mapping are reported instead of silently dropped. The staged drafts land in the Review tab and one Apply writes every team block and the global block in a single assessment update.

An affected result produces a copyable Markdown remediation ticket. Setting DTVP_JIRA_CREATE_URL adds an action that copies the draft and opens Jira's create screen using the browser's existing session; ticket text is never placed in the URL or sent with Jira credentials.

The header Code Analysis page is an operations dashboard for DTVP queue slots, saved results, analyzer health/jobs/agents/progress, configured model and backend, automatic sweep state, logs, cancellation, and abort controls. It is not a second assessment editor.

Benchmarks And Agentyzer

Selecting a saved normal analysis run automatically compares it with an existing assessment. DTVP computes deterministic state, justification, and CVSS anchors, then uses Agentyzer POST /benchmark/compare for semantic reasoning. If the analyzer is unavailable, DTVP returns a labeled deterministic fallback. No benchmark is shown for NOT_SET assessments. Ratings are 1/F (contradiction) through 5/A (strong agreement).

Bundled Agentyzer lives in agentyzer/, runs at http://agentyzer:8000 in Compose, and exposes host port 8095 by default. PM2 uses the mock analyzer on that port. DTVP optionally uses Agentyzer's compact, follow-up, and prompt inspection endpoints; persisted DTVP context remains the fallback.

Agentyzer prompt bundles live under agentyzer/config/prompts/. They enforce structured, conservative assessment contracts and support native tool calls or text FETCH_* fallbacks for allowlisted web/package/source research. Java dependency discovery covers Maven and Gradle build, lock, and version-catalog formats.

Automatic Scanning

Automatic scanning requires both DTVP_AUTO_CODE_ANALYSIS_ENABLED=true and a configured analyzer.

  • Project refresh queues genuinely new groups only when every instance is NOT_SET with no assessment text.
  • A scheduled single-worker sweep starts after one interval and checks cached findings and live projects every DTVP_AUTO_CODE_ANALYSIS_SWEEP_SECONDS.
  • Reviewers can trigger an immediate background sweep from the dashboard.
  • Targets require an explicit team mapping or the first explicitly mapped parent on a dependency path; wildcard ownership is insufficient.
  • Any global, team, or legacy assessment marks a group handled.
  • Stale automatic queue items are cancelled when the group becomes handled or loses its eligible target. Manual requests are not cancelled.

DTVP and Agentyzer default to one running scan. Raise DTVP_ANALYSIS_QUEUE_CAPACITY and AGENTYZER_MAX_CONCURRENT_JOBS together only when the analyzer, model backend, and workspaces support parallel scans.

Development

Split Backend And Frontend

The quick start is preferred for normal work. To run processes separately, start only the mocks:

pm2 start ecosystem.config.js --only mock-dt,mock-tmrescore,mock-code-analysis

Then start the backend:

export DTVP_DT_API_URL=http://127.0.0.1:8081
export DTVP_DT_API_KEY=mock_key
export DTVP_OIDC_AUTHORITY=http://127.0.0.1:8081
export DTVP_OIDC_CLIENT_ID=mock_id
export DTVP_OIDC_CLIENT_SECRET=mock_secret
export DTVP_OIDC_REDIRECT_URI=http://localhost:5173/auth/callback
export DTVP_FRONTEND_URL=http://localhost:5173
export DTVP_TMRESCORE_URL=http://127.0.0.1:8090
export DTVP_CODE_ANALYSIS_URL=http://127.0.0.1:8095
uv run uvicorn dtvp.boot:app --reload --host 127.0.0.1 --port 8000

Use DTVP_DEV_DISABLE_AUTH=true to make /auth/me resolve to local devuser, which maps to REVIEWER in data/user_roles.json. Start the frontend with cd frontend && npm run dev.

Testing Notes

Commands are in the command reference. README screenshots come from frontend/e2e/capture-readme-screenshots.manual.ts. Real-stack manual flows use npm run test:ui:real-stack with the relevant Playwright grep.

To exercise apply conflicts, edit the same finding in two sessions or change it through mock Dependency-Track before submitting. The expected dialog is shown in docs/screenshots/conflict-resolution.png.

Docker Deployment

cp .env.dist .env
docker compose up -d

Set at least the Dependency-Track API key and public URL. For a non-default gateway:

DTVP_HTTP_PORT=8083
DTVP_FRONTEND_URL=http://host.example:8083/dtvp

Deployment rules:

  • ./data mounts at /app/data; mappings, roles, rules, caches, proposals, and archives survive container restarts.
  • Compose starts Agentyzer and persists cloned repositories in the agentyzer-repos volume. Populate or override the sanitized agentyzer/config/repos.yaml before enabling automatic scans; never commit repository credentials.
  • Internal services use Compose names and container ports. DTVP reaches Dependency-Track at http://dtrack-apiserver:8080 and Agentyzer at http://agentyzer:8000 unless overridden.
  • If proxies are configured, list exact internal hostnames/IPs in NO_PROXY; do not rely only on CIDR entries.
  • DTVP OIDC is independent of Dependency-Track browser sessions. Backend calls use DTVP_DT_API_KEY and never forward browser credentials.
  • API 401 responses move the SPA to sign-in and preserve the current route for the OIDC return. Reviewer authorization failures remain 403 errors and do not incorrectly log the user out.
  • Completed grouped-vulnerability tasks are retained by idle time. Visible project tabs renew their lightweight task lease and rebuild an expired task automatically after a suspended browser resumes, so details and bulk actions do not require a full-page reload.
  • Background Dependency-Track refresh tracks a timestamped, bounded set of recently viewed projects. Older projects remain on disk and load on demand; they no longer receive three upstream refresh calls every minute forever.
  • Process-local cache objects and named project searches use LRU limits, and completed grouped tasks have a separate retained-count cap. These bounds keep long-running and multi-user instances from growing without limit.
  • nginx proxies DTVP_CONTEXT_PATH to DTVP and defaults it to /dtvp. DTVP_HTTP_PORT changes the host gateway port. Direct-container deployments must publish port 8000 and include the context path in the URL.
  • The Compose nginx gateway keeps upstream HTTP/1.1 connections open, compresses JSON/static text responses, and disables buffering for grouped task event streams. Uvicorn keeps those upstream connections for 30 seconds and uses a 2048-connection accept backlog.
  • dtvp.boot:app serves startup status while the real app initializes. Startup logs time cache and integration initialization.
  • /api/performance-status reports grouped-query/build saturation, retained task counts, process-local cache pressure, and the active Python/GIL state. API responses include a Server-Timing: app;dur=... header for browser and proxy latency analysis.
  • Reviewers see the Python/GIL state in the application footer and can inspect live worker capacity, retained grouped tasks, and cache pressure on the Settings Runtime tab.
  • The frontend image renders index.html from its immutable template on every start, so frontend URL and context-path changes are restart-safe.

Python Runtime Images

The default Compose and published DTVP image use the Python 3.14 free-threaded build. Start it normally:

docker compose up -d --build

Dockerfile.free-threaded asks uv for the explicit 3.14t interpreter. It loads DTVP's native dependencies and verifies the runtime during the image build. Compose also sets DTVP_REQUIRE_FREE_THREADED=true, so the application refuses to start if it receives a normal interpreter or a native extension re-enables the GIL. Confirm the live state under python in /api/performance-status; free_threading_active must be true and gil_enabled must be false.

See the official CPython free-threading guide and uv Python variant documentation for the interpreter guarantees and 3.14t selector.

Free threading lets DTVP's dedicated CPU worker pools execute Python code on multiple cores. It does not make Dependency-Track/network I/O faster, and the free-threaded interpreter has some single-thread overhead. The pipeline retains GIL-enabled rollback tags with a -gil suffix, and local deployments can use:

docker compose -f compose.yml -f compose.gil.yml up -d --build

Published primary tags (latest, release versions, dev, and PR tags) use free threading and also receive explicit -freethreaded aliases. The fallback build receives corresponding -gil tags.

Archive imports require read, BOM upload, and vulnerability-analysis update permissions in Dependency-Track. Scheduled snapshots and expanded Git trees are controlled by the archive variables below. The optional dtvp-archive-git-push Compose job pushes an expanded tree; schedule it with cron, systemd, or CI when required.

Configuration Reference

Set values in .env for Compose or in the shell for local uv runs. unset means the integration or override is disabled.

Dependency-Track, Cache, And Rules

Variable Purpose Default
DTVP_DT_API_URL Dependency-Track API base URL http://localhost:8081; Compose: http://dtrack-apiserver:8080
DTVP_DT_API_KEY Dependency-Track API key change_me
DTVP_DT_API_KEY_FILE API-key file used when the direct value is unset unset
DEPENDENCY_TRACK_URL / DEPENDENCY_TRACK_API_KEY Deployment aliases unset
DTVP_DT_CACHE_PATH Dependency-Track cache and pending update queue data/dt_cache
DTVP_DT_CACHE_REFRESH_SECONDS Background refresh interval 60
DTVP_DT_PROJECT_LIST_TTL_SECONDS Freshness window for serving the complete cached project list without an upstream request 30
DTVP_DT_ACTIVE_PROJECT_TTL_SECONDS Idle window for periodic per-project background refresh 900
DTVP_DT_ACTIVE_PROJECT_LIMIT Most-recent projects eligible for periodic refresh 8
DTVP_DT_MEMORY_CACHE_MAX_ENTRIES Process-local LRU file-object cache entries; disk files remain persistent 256
DTVP_DT_PROJECT_QUERY_CACHE_MAX_ENTRIES Process-local named-project query LRU entries 128
DTVP_ASSESSMENT_OUTBOX_PATH Transactional assessment overlay and synchronization outbox <DTVP_DT_CACHE_PATH>/assessment_outbox.sqlite
DTVP_ASSESSMENT_SYNC_CONCURRENCY Global concurrent background assessment writes to Dependency-Track 4
DTVP_ASSESSMENT_STRICT_DT_CONFLICTS Perform live Dependency-Track conflict reads before accepting assessment saves false
DTVP_VERSION_FETCH_CONCURRENCY Parallel version fetch limit 4
DTVP_ASSESSMENT_IO_CONCURRENCY Concurrent Dependency-Track assessment reads or writes per operation 4
DTVP_ASSESSMENT_WRITE_MAX_ATTEMPTS Attempts for transient assessment-write timeouts, rate limits, and HTTP 5xx responses 3
DTVP_GROUPED_VULN_TASK_TTL_SECONDS Completed/failed grouped-task idle retention 900
DTVP_GROUPED_VULN_TASK_MAX_RETAINED Maximum completed/failed grouped tasks retained in process 24
DTVP_GROUPED_VULN_SUMMARY_INDEX_PATH Persisted summary-index SQLite path sibling of cache path
DTVP_GROUPED_VULN_SUMMARY_INDEX_MAX_ENTRIES Maximum persisted summary indexes 64
DTVP_GROUP_QUERY_WORKERS Dedicated grouped-search worker threads 4
DTVP_GROUP_QUERY_MAX_PENDING Maximum grouped searches queued behind active workers 8
DTVP_GROUP_QUERY_CACHE_ENTRIES Maximum cached filter combinations per grouped task 32
DTVP_GROUP_QUERY_CACHE_BYTES Approximate per-task filtered-index and facet-cache budget 8388608
DTVP_GROUP_BUILD_WORKERS Dedicated CPU workers for grouped snapshot/index construction 1
DTVP_GROUP_BUILD_MAX_PENDING Group-build jobs admitted behind active build workers before async backpressure 2
DTVP_GROUP_DETAIL_WORKERS Reserved workers for full vulnerability detail hydration 2
DTVP_GROUP_DETAIL_MAX_PENDING Detail hydration jobs admitted before async backpressure 8
TEAM_MAPPING_PATH Component ownership mapping data/team_mapping.json
TEAM_GROUPS_PATH Nested team-group definitions data/team_groups.json
USER_ROLES_PATH User-to-role mapping data/user_roles.json
RESCORE_RULES_PATH CVSS transition rules data/rescore_rules.json

Authentication, Runtime, And Frontend

Variable Purpose Default
DTVP_OIDC_AUTHORITY OIDC authority URL unset
DTVP_OIDC_CLIENT_ID OIDC client ID unset
DTVP_OIDC_CLIENT_SECRET OIDC client secret unset
DTVP_OIDC_REDIRECT_URI OIDC callback derived from frontend URL/context path
DTVP_SESSION_SECRET_KEY Session signing key change_me
DTVP_DEV_DISABLE_AUTH Resolve local requests as devuser false
DTVP_FRONTEND_URL Public frontend base URL http://localhost:8000
DTVP_CONTEXT_PATH Application mount path app /; Compose /dtvp
DTVP_HTTP_PORT Compose nginx host port 80
DTVP_UVICORN_KEEP_ALIVE_SECONDS Backend upstream keep-alive timeout 30
DTVP_REQUIRE_FREE_THREADED Fail startup unless CPython supports free threading and its GIL is actually disabled local Python: false; Compose: true
DTVP_BOOT_APP Real ASGI app loaded by the boot wrapper dtvp.main:app
DTVP_CORS_ORIGINS Additional comma-separated CORS origins unset
DTVP_API_URL Frontend API base override; Vite alias VITE_DTVP_API_URL empty
DTVP_DEFAULT_PROJECT_FILTER Dashboard default project filter empty
DTVP_ATTRIBUTION_AGE_FILTER_DAYS Attribution-age presets 7d,14d,28d
DTVP_BUILD_COMMIT Build metadata shown in the UI unknown

Project Archives

Variable Purpose Default
DTVP_PROJECT_ARCHIVE_PATH ZIPs, import previews, and snapshots data/project_archives
DTVP_PROJECT_ARCHIVE_EXPANDED_ENABLED Write stable Git-friendly trees false
DTVP_PROJECT_ARCHIVE_EXPANDED_PATH Expanded tree directory data/project_archives_git
DTVP_PROJECT_ARCHIVE_SNAPSHOT_ENABLED Enable scheduled snapshots false
DTVP_PROJECT_ARCHIVE_INTERVAL_SECONDS Snapshot interval; minimum 60 86400
DTVP_PROJECT_ARCHIVE_RETENTION_COUNT Recent ZIPs retained per project 30
DTVP_PROJECT_ARCHIVE_INCLUDE Comma-separated scheduled project names empty
DTVP_ARCHIVE_GIT_REMOTE Optional archive Git remote empty
DTVP_ARCHIVE_GIT_BRANCH Archive Git branch main
DTVP_ARCHIVE_GIT_AUTHOR_NAME Commit author name DTVP Archive Bot
DTVP_ARCHIVE_GIT_AUTHOR_EMAIL Commit author email dtvp-archive@example.invalid
DTVP_ARCHIVE_GIT_SSH_KEY_FILE SSH key inside Git helper /ssh/dtvp_archive_deploy_key
DTVP_ARCHIVE_GIT_KNOWN_HOSTS_FILE Known-hosts file inside Git helper /ssh/known_hosts

Threat Model And Code Analysis

Variable Purpose Default
DTVP_TMRESCORE_URL tmrescore/vscorer base URL unset
DTVP_TMRESCORE_TIMEOUT_SECONDS HTTP timeout before polling fallback 180
DTVP_TMRESCORE_CACHE_PATH Cached proposal snapshots data/tmrescore_proposals.json
DTVP_TMRESCORE_TASK_TTL_SECONDS Completed/failed task retention 3600
DTVP_CODE_ANALYSIS_URL Analyzer base URL unset; Compose: http://agentyzer:8000
DTVP_CODE_ANALYSIS_TIMEOUT_SECONDS Analyzer HTTP timeout 300
DTVP_CODE_ANALYSIS_STATUS_TIMEOUT_SECONDS Dashboard health/jobs timeout 5
DTVP_CODE_ANALYSIS_DASHBOARD_CACHE_SECONDS Shared dashboard status snapshot lifetime 3
DTVP_CODE_ANALYSIS_MODEL Analyzer model hint unset
DTVP_CODE_ANALYSIS_LLM_BACKEND LLM backend hint unset
DTVP_CODE_ANALYSIS_LLM_PROVIDER LLM provider hint unset
DTVP_JIRA_CREATE_URL Jira create-screen URL unset
DTVP_ANALYSIS_QUEUE_CAPACITY Concurrent DTVP queue items 1
DTVP_ANALYSIS_QUEUE_MAX_PENDING Maximum pending DTVP queue items before new submissions receive HTTP 429 1000
DTVP_ANALYSIS_QUEUE_TTL_SECONDS Completed/failed queue retention 3600
DTVP_CODE_ANALYSIS_RESULTS_PATH Result/application SQLite store data/code_analysis_results.sqlite
DTVP_CODE_ANALYSIS_RESULTS_MAX_RECORDS Maximum stored results 2000
DTVP_CODE_ANALYSIS_RESULTS_RETENTION_DAYS Maximum result age; 0 disables 0
DTVP_CODE_ANALYSIS_RESULTS_STORE_GUIDANCE Persist reviewer/follow-up guidance true
DTVP_CODE_ANALYSIS_RESULT_FRESHNESS_DAYS Maximum dedupe age; 0 uses fingerprints only 0
DTVP_AUTO_CODE_ANALYSIS_ENABLED Enable automatic scans false
DTVP_AUTO_CODE_ANALYSIS_SWEEP_SECONDS Automatic sweep interval 900
DTVP_AUTO_ANALYSIS_GUIDANCE_PATH Static component guidance data/auto_analysis_guidance.json

Agentyzer

Variable Purpose Default
AGENTYZER_PORT Compose host port 8095
AGENTYZER_LOG_LEVEL Service log level INFO
AGENTYZER_MAX_CONCURRENT_JOBS Concurrent assessment pipelines 1
AGENTYZER_LLM_BACKEND ollama or openwebui ollama
AGENTYZER_OLLAMA_HOST / AGENTYZER_OLLAMA_MODEL Ollama endpoint and model http://host.docker.internal:11434 / mistral
AGENTYZER_OPENWEBUI_HOST / AGENTYZER_OPENWEBUI_MODEL OpenWebUI endpoint and model http://host.docker.internal:3000 / mistral
AGENTYZER_OPENWEBUI_API_KEY Optional OpenWebUI bearer token unset
AGENTYZER_OPENWEBUI_TOOL_CALLS Native tool calls: auto or off auto
AGENTYZER_OPENWEBUI_CONTEXT_WINDOW Optional context limit 0
AGENTYZER_OPENWEBUI_CONTEXT_SAFETY_MARGIN Reserved token margin 256
AGENTYZER_OPENWEBUI_CONTEXT_RETRIES Oversized-context retries 2
AGENTYZER_OPENWEBUI_MIN_COMPLETION_TOKENS Completion budget preserved during compaction 256

SBOM, Documentation, And License

The DTVP image contains CycloneDX frontend/backend SBOMs. The app exposes the combined document at /api/sbom and /api/sbom/html; CI publishes a separate Agentyzer SBOM. Production dependencies come from frontend/package*.json, pyproject.toml, and uv.lock; test/development dependencies are excluded.

Documentation entry points:

This project is licensed under the MIT License. See LICENSE.