diff --git a/src/polyswarm/formatters/text.py b/src/polyswarm/formatters/text.py index 3dfcfd69..2f506352 100644 --- a/src/polyswarm/formatters/text.py +++ b/src/polyswarm/formatters/text.py @@ -120,13 +120,27 @@ def artifact_instance(self, instance, write=True, timeout=False): # below the dependency floor, so the pin already guarantees them. This is # belt-and-braces for an unsupported configuration, NOT the version-probing # the floor replaced -- don't add siblings for a version the floor permits. - # The bounty state (KNOWN_GOOD) is the only reliable signal that this artifact is + # The reported state (KNOWN_GOOD) is the only reliable signal that this artifact is # a known-good binary whose bytes are withheld — it alone decides. known_good_sources - # (the flagging feeds) is emitted for any instance whose sha256 matches a known-good - # record, including a fully scanned one carrying real detections, so it only shapes - # the message; reading it as the signal would render a scanned artifact "not scanned". - is_known_good = getattr(instance, 'state', None) == 'KNOWN_GOOD' + # (the flagging feeds) only shapes the message. + # + # The server gates the `known_good` field on the SAME predicate it reports + # KNOWN_GOOD from, so the feeds can never arrive without the state. The converse + # does not hold — the state can arrive with no feeds, when the catalogue entry + # stopped resolving between the gate and the render — which is why the attribution + # below is guarded on `known_good_sources` rather than assuming it is populated. + # Read once and compare twice — a second `getattr` for the same attribute would be + # the sibling the note above warns against. + reported_state = getattr(instance, 'state', None) + is_known_good = reported_state == 'KNOWN_GOOD' known_good_sources = (getattr(instance, 'known_good_sources', None) or []) if is_known_good else [] + # NOT_STORED is a different fact from "never scanned" and from "not found": the + # platform knows this hash and deliberately never kept its bytes, because it was + # declined as a known-good binary at submission and is no longer currently + # known-good. Resubmitting the file scans it. Without its own branch it fell + # through to "Assertion window closed" — these records carry window_closed=True — + # which reads as a finished scan that produced nothing. + is_not_stored = reported_state == 'NOT_STORED' if is_known_good and not instance.failed: # A known-good binary can still carry results: an instance scanned before the @@ -198,6 +212,13 @@ def artifact_instance(self, instance, write=True, timeout=False): output.append(self._red(f'Failure Reason: {instance.failed_reason}')) elif is_known_good: output.append(self._green('Status: Known good')) + elif is_not_stored: + # Ahead of window_closed deliberately: these records carry window_closed=True, + # so the ordinary branch would claim a finished scan for an artifact that has + # never been scanned and holds no bytes to scan. + output.append(self._white( + 'Status: Not stored. Its bytes were declined as a known-good binary when ' + 'submitted; resubmit the file to scan it.')) elif instance.window_closed: output.append(self._white('Status: Assertion window closed')) elif instance.community == 'stream': diff --git a/tests/known_good_field_test.py b/tests/known_good_field_test.py index 24b52485..70557a01 100644 --- a/tests/known_good_field_test.py +++ b/tests/known_good_field_test.py @@ -238,3 +238,32 @@ def test_scanned_instance_with_feeds_reports_its_detections(self): # The real scan results are reported, never overwritten by a "not scanned" claim. assert 'Detections: 1/2 engines reported malicious' in text assert 'it is not scanned' not in text + + +class TestNotStoredRendering: + """NOT_STORED — the platform knows the hash and deliberately never kept its bytes. + + Distinct from KNOWN_GOOD (bytes withheld, but the hash IS currently known-good) and + from a plain miss. These records are the ones a submission declined at ingest, whose + hash later stopped being currently known-good (specs/05 case 2b). + """ + + def test_not_stored_names_its_cause_instead_of_claiming_a_finished_scan(self): + # These records carry window_closed=True, so before NOT_STORED had its own + # branch they fell through to "Assertion window closed" — which reads as a finished + # scan that found nothing, for an artifact that was never scanned and holds no bytes + # to scan. That is what sent the reporter looking for a retention bug. + text = _render(_instance(state='NOT_STORED')) + assert 'Status: Not stored.' in text + assert 'declined as a known-good binary when submitted' in text + assert 'resubmit the file to scan it' in text + assert 'Status: Assertion window closed' not in text + + def test_not_stored_is_not_reported_as_known_good(self): + # The hash is no longer CURRENTLY known-good — that is the whole reason the state is + # NOT_STORED rather than KNOWN_GOOD — so neither the known-good status nor a feed + # attribution may appear, even when the server sent a feed list. + text = _render(_instance(state='NOT_STORED', known_good=FEEDS)) + assert 'Status: Known good' not in text + assert 'flagged by' not in text + assert 'Status: Not stored.' in text