Skip to content

Reapply #1209: vulnerability status field + carry-over across re-scans#1236

Closed
ocervell wants to merge 1 commit into
mainfrom
reapply-1209-vuln-status
Closed

Reapply #1209: vulnerability status field + carry-over across re-scans#1236
ocervell wants to merge 1 commit into
mainfrom
reapply-1209-vuln-status

Conversation

@ocervell

@ocervell ocervell commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Restores the changes from #1209, which was merged (0d7bf7d) and then accidentally reverted by #1234 (b556414a).

A merged PR can't be reopened on GitHub, and re-merging feat/vuln-status is a no-op (its commits are already in main's history). The correct restore is to revert the revert — this PR reverts #1234, re-applying #1209's exact changes (vulnerability status field + carry-over across re-scans; 6 files).

Supersedes the accidental revert #1234. Original PR: #1209.

Summary by CodeRabbit

  • New Features

    • Added vulnerability status as a standard field, with support for NEW, ACKNOWLEDGED, and FIXED.
    • Status values are now normalized automatically, so invalid or empty values default to NEW.
  • Bug Fixes

    • Improved duplicate handling so a meaningful existing status can carry forward to newly discovered duplicates.
    • Prevented FIXED statuses from being overwritten by default NEW values.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds status as a first-class field on the Vulnerability dataclass (defaulting to 'NEW', normalized in __post_init__), introduces a _is_unset helper in dedup that treats 'NEW' as empty so prior non-NEW statuses carry forward onto rediscovered duplicates, and registers 'status' in both MongodbAddon and SqliteAddon duplicate_main_copy_fields defaults.

Changes

Vulnerability status field and dedup carry-forward

Layer / File(s) Summary
Vulnerability.status field definition and normalization
secator/definitions.py, secator/output_types/vulnerability.py
Adds STATUS = 'status' constant, declares status: str = field(default='NEW', compare=False) on Vulnerability, adds STATUSES tuple, extends _table_fields, and normalizes status in __post_init__ (coerces empty/unknown to 'NEW', uppercases valid values).
Dedup _is_unset helper and copy-forward logic
secator/hooks/_dedup.py, secator/config.py
Introduces _is_unset(field, value) treating both falsy and status='NEW' as unset; updates compute_duplicate_updates to use _is_unset for copy-forward decisions; adds 'status' to duplicate_main_copy_fields defaults for MongodbAddon and SqliteAddon.
Unit tests
tests/unit/test_dedup.py, tests/unit/test_output_types.py
New TestComputeDuplicateUpdates covers carry-forward of ACKNOWLEDGED, non-overwrite of FIXED, no copy of prior NEW, and non-status truthiness semantics. New TestVulnerabilityStatus covers defaulting, coercion, uppercasing, and equality exclusion.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related PRs

  • freelabz/secator#864: Extends the same duplicate_main_copy_fields mechanism and dedup copy logic that this PR builds on.
  • freelabz/secator#1209: Contains identical code-level changes — Vulnerability.status, _is_unset, and extended copy-field defaults.

Suggested labels

feature:vulnerability-status

🐇 A field called status hops into the fray,
NEW means "unset" — old states lead the way!
ACKNOWLEDGED, FIXED leap over the gate,
while duplicates check if their carrots can wait.
The dedup now knows what it means to be "new"~ 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the restored vulnerability status field and carry-over behavior across re-scans.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch reapply-1209-vuln-status

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ocervell

Copy link
Copy Markdown
Contributor Author

Superseded by #1240, which recreates #1209 cleanly (original commit + title/description) instead of a revert-of-the-revert. Closing this one.

@ocervell ocervell closed this Jun 30, 2026
@ocervell ocervell deleted the reapply-1209-vuln-status branch June 30, 2026 05:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@secator/output_types/vulnerability.py`:
- Around line 73-76: Preserve legacy acknowledgment state in Vulnerability
deserialization: the current status normalization in Vulnerability.__init__ (or
the status handling path) always falls back to NEW when status is missing, which
breaks persisted records that only have is_acknowledged set. Update the
normalization logic so that when status is absent or invalid, it maps
is_acknowledged=True to ACKNOWLEDGED and only defaults to NEW otherwise, while
still uppercasing and validating against STATUSES. Add a regression test for
loading a legacy Vulnerability with is_acknowledged=True and no status, and
verify compute_duplicate_updates() carries ACKNOWLEDGED onto the re-found main.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aad369e1-4b0d-497c-ad5a-9c706f1e0513

📥 Commits

Reviewing files that changed from the base of the PR and between b556414 and d47b23c.

📒 Files selected for processing (6)
  • secator/config.py
  • secator/definitions.py
  • secator/hooks/_dedup.py
  • secator/output_types/vulnerability.py
  • tests/unit/test_dedup.py
  • tests/unit/test_output_types.py

Comment on lines +73 to +76
# Normalize status: coerce empty / None / unknown values to 'NEW', uppercase.
# Allowed values are NEW / ACKNOWLEDGED / FIXED (see STATUSES).
status = (self.status or '').strip().upper()
self.status = status if status in self.STATUSES else 'NEW'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve legacy is_acknowledged state when status is absent.

Line 75-Line 76 always normalizes an unset/invalid status to NEW. That breaks upgrade compatibility for persisted findings created before this field existed: records with is_acknowledged=True but no status now deserialize as NEW, and compute_duplicate_updates() then treats that as unset instead of carrying ACKNOWLEDGED onto the re-found main.

💡 Proposed fix
-		status = (self.status or '').strip().upper()
-		self.status = status if status in self.STATUSES else 'NEW'
+		status = (self.status or '').strip().upper()
+		if status not in self.STATUSES or (status == 'NEW' and self.is_acknowledged):
+			status = 'ACKNOWLEDGED' if self.is_acknowledged else 'NEW'
+		self.status = status

A regression test around a legacy Vulnerability(is_acknowledged=True) load path would lock this down.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Normalize status: coerce empty / None / unknown values to 'NEW', uppercase.
# Allowed values are NEW / ACKNOWLEDGED / FIXED (see STATUSES).
status = (self.status or '').strip().upper()
self.status = status if status in self.STATUSES else 'NEW'
# Normalize status: coerce empty / None / unknown values to 'NEW', uppercase.
# Allowed values are NEW / ACKNOWLEDGED / FIXED (see STATUSES).
status = (self.status or '').strip().upper()
if status not in self.STATUSES or (status == 'NEW' and self.is_acknowledged):
status = 'ACKNOWLEDGED' if self.is_acknowledged else 'NEW'
self.status = status
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@secator/output_types/vulnerability.py` around lines 73 - 76, Preserve legacy
acknowledgment state in Vulnerability deserialization: the current status
normalization in Vulnerability.__init__ (or the status handling path) always
falls back to NEW when status is missing, which breaks persisted records that
only have is_acknowledged set. Update the normalization logic so that when
status is absent or invalid, it maps is_acknowledged=True to ACKNOWLEDGED and
only defaults to NEW otherwise, while still uppercasing and validating against
STATUSES. Add a regression test for loading a legacy Vulnerability with
is_acknowledged=True and no status, and verify compute_duplicate_updates()
carries ACKNOWLEDGED onto the re-found main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant