Skip to content

Commit db6cf91

Browse files
authored
feat(frontend): scope Fix available tag to active ecosystem filter (#3784)
Accurately displays the `Fix Available` tag in the [vulnerability list](https://osv.dev/list) page when filtering by a specific ecosystem. Fixes #2491
1 parent 5c85789 commit db6cf91

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

gcp/website/frontend_emulator.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,43 @@ def setUp():
8080
package=osv.Package(ecosystem='Ecosystem3', name='proj3'))
8181
],
8282
).put()
83+
84+
osv.Bug(
85+
id='MULTI-ECO-FIX-DEMO',
86+
db_id='MULTI-ECO-FIX-DEMO',
87+
status=1,
88+
source='test',
89+
public=True,
90+
import_last_modified=datetime.datetime(2025, 3, 1, tzinfo=datetime.UTC),
91+
timestamp=datetime.datetime(2025, 3, 1, tzinfo=datetime.UTC),
92+
summary='Demo vuln with fix only in PyPI ecosystem',
93+
affected_packages=[
94+
osv.AffectedPackage(
95+
package=osv.Package(ecosystem='PyPI', name='demo-lib'),
96+
ranges=[
97+
osv.AffectedRange2(
98+
type='SEMVER',
99+
events=[
100+
osv.AffectedEvent(type='introduced', value='0'),
101+
osv.AffectedEvent(type='fixed', value='1.2.0'),
102+
],
103+
)
104+
],
105+
),
106+
osv.AffectedPackage(
107+
package=osv.Package(ecosystem='npm', name='demo-lib'),
108+
ranges=[
109+
osv.AffectedRange2(
110+
type='SEMVER',
111+
events=[
112+
osv.AffectedEvent(type='introduced', value='0'),
113+
],
114+
)
115+
],
116+
),
117+
],
118+
).put()
119+
83120
osv.Bug(
84121
id='CVE-3',
85122
db_id='CVE-3',

gcp/website/frontend_handlers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,14 @@ def osv_query(search_string, page, affected_only, ecosystem):
616616
# yapf: enable
617617
result_items = [bug_to_response(bug, detailed=False) for bug in bugs]
618618

619+
# Filter isFixed flag to apply only for selected ecosystem.
620+
if ecosystem:
621+
eco_variants = osv.ecosystems.add_matching_ecosystems({ecosystem})
622+
eco_variants.add(osv.ecosystems.normalize(ecosystem))
623+
624+
for item, bug_obj in zip(result_items, bugs):
625+
item['isFixed'] = _is_fixed_in_ecosystem(bug_obj, eco_variants)
626+
619627
results = {
620628
'total': total_future.get_result(),
621629
'items': result_items,
@@ -624,6 +632,26 @@ def osv_query(search_string, page, affected_only, ecosystem):
624632
return results
625633

626634

635+
def _is_fixed_in_ecosystem(bug: osv.Bug, eco_variants: set[str]) -> bool:
636+
"""Determine if a bug has a fix within the specified ecosystem variants.
637+
638+
Args:
639+
bug: The Bug entity.
640+
eco_variants: Set of ecosystem names (including variants) to match.
641+
642+
Returns:
643+
True if any affected package in the ecosystem has a fixed/limit event.
644+
"""
645+
for affected_pkg in getattr(bug, 'affected_packages', []):
646+
pkg = affected_pkg.package
647+
if not pkg or pkg.ecosystem not in eco_variants:
648+
continue
649+
for r in affected_pkg.ranges or []:
650+
if any(evt.type in ('fixed', 'limit') for evt in (r.events or [])):
651+
return True
652+
return False
653+
654+
627655
def get_vuln_count_for_ecosystem(ecosystem: str) -> int:
628656
ecosystem_counts = osv_get_ecosystem_counts_cached()
629657
if not ecosystem:

0 commit comments

Comments
 (0)