Plan skip restoration leaves false-positive findings with stale reopened metadata

Aperta
#855 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
25/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
python
Ambito
backend

Direzione di ricerca

Start with the reproduction steps, which use only in-memory state: call upsert_issues in desloppify/engine/_state/merge_issues.py, then reconcile_plan_after_scan in desloppify/engine/_plan/scan_issue_reconcile.py, and compare the row's note, reopen_count, and resolution fields. The maintainers have not decided which side owns the fix, so confirm the contract with them before editing. Done means a regression test asserts the agreed terminal fields for a plan-skipped false positive.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Problem

A finding with a durable plan skip --false-positive disposition can be returned by the next scan, briefly reopened by scan merge, and then restored to false_positive during post-scan plan reconciliation. The terminal state can retain the scan's Reopened (×N) note, a higher reopen_count, and null resolved_at/resolution_attestation even though the final status is false_positive and the plan still contains the accepted skip evidence.

This makes the terminal state ambiguous: it looks both accepted and unresolved, and the reopen counter reports churn that was immediately superseded by the durable plan disposition.

Minimal in-memory reproduction

No project files or persisted state are required:

  1. Create one synthetic test_coverage work item with status false_positive, a prior resolved_at, and a resolution_attestation.
  2. Add a matching plan entry under plan["skipped"] with kind false_positive, note accepted, and attestation reviewed.
  3. Pass the same finding through engine._state.merge_issues.upsert_issues.
  4. Pass the plan and state through engine._plan.scan_issue_reconcile.reconcile_plan_after_scan.

Observed after upsert_issues:

status = open
reopen_count = 1
note = "Reopened (×1) — reappeared in scan (was false_positive)"
resolved_at = null
resolution_attestation = null

Observed after reconcile_plan_after_scan:

status = false_positive
reopen_count = 1
note = "Reopened (×1) — reappeared in scan (was false_positive)"
resolved_at = null
resolution_attestation = null
plan["skipped"][id]["kind"] = "false_positive"
plan["skipped"][id]["note"] = "accepted"
plan["skipped"][id]["attestation"] = "reviewed"

Code path

  • desloppify/engine/_state/merge_issues.py::upsert_issues increments reopen_count, clears resolution metadata, and writes the Reopened note when a previously resolved finding is present in current detector output.
  • desloppify/engine/_plan/scan_issue_reconcile.py::_sync_skipped_issue_statuses restores an open skipped finding to the skip-kind status by assigning status only.
  • desloppify/app/commands/scan/workflow.py persists state after scan merge and again after post-scan reporting, so the restored terminal status can be persisted.

Expected behavior / question

Please clarify the supported contract for a durable plan skip:

  • If the plan skip is the canonical disposition, should scan merge avoid treating the accepted finding as a user-resolution reopen, or should reconciliation restore coherent state metadata from the plan skip?
  • If the reopen event is intentionally retained as history, should it be represented separately so a final false_positive row does not carry an unresolved-looking note and null resolution metadata?

A regression test should assert the chosen terminal contract for status, reopen count, note, resolved_at, resolution_attestation, and plan skip evidence.

Related work

  • PR836 preserves deliberate skip dispositions across scans and cleans stale queue/cluster references. This report concerns the state-row metadata left after status restoration.
  • PR798 persists reconciled scan scores and history. This report concerns per-finding terminal metadata, not score persistence.
  • Issue807 tracks conflicting scan scores in one invocation and is related to the pre/post-reconciliation visibility problem.
Lingua principale
Python
Stelle
4.1k
Fork
313
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di peteromallet/desloppify

Tutte le issue di peteromallet/desloppify

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.