mirror of
https://github.com/0xMarcio/cve.git
synced 2026-10-27 16:51:03 +00:00
186 lines
9.3 KiB
Python
186 lines
9.3 KiB
Python
"""The front-page lists read the same before and after the feed arrives.
|
|
|
|
build_pages pre-renders Just landed; logic.js renders both lists from
|
|
trending_poc.json, run in node the way tests/test_search.js runs it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import html
|
|
import json
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "scripts"))
|
|
|
|
import build_pages
|
|
|
|
KERNELCTF = "https://github.com/google/security-research/tree/master/pocs/linux/kernelctf/CVE-2024-26642_"
|
|
SHARED = "https://github.com/owner/CVE-2026-21589"
|
|
# Published order. Sorting either list by stars or by date would change it.
|
|
LANDED = [
|
|
{"cve": "CVE-2024-26642", "url": KERNELCTF + "mitigation", "name": "CVE-2024-26642_mitigation", "stars": 5000,
|
|
"desc": "nf_tables", "released": "2026-10-06T23:30:00-02:00", "basis": "commit", "kev": False,
|
|
"page": "/CVE-2024-26642", "landed": True, "source": "github.com", "artifact": True},
|
|
{"cve": "CVE-2026-21589", "url": SHARED, "name": "CVE-2026-21589", "stars": 5,
|
|
"desc": "Atlassian's <b>file read</b>", "released": "2026-10-06T15:51:43Z", "basis": "commit", "kev": True,
|
|
"page": "/CVE-2026-21589", "landed": True, "source": "github.com", "artifact": False},
|
|
{"cve": "CVE-2021-44228", "url": "https://www.exploit-db.com/exploits/50592", "name": "50592", "stars": 4682,
|
|
"desc": "log4j", "released": "2026-10-05", "basis": "source", "kev": True,
|
|
"page": "/CVE-2021-44228", "landed": True, "source": "www.exploit-db.com", "artifact": True},
|
|
]
|
|
TRENDING = [
|
|
{"cve": "CVE-2026-21589", "url": SHARED, "name": "CVE-2026-21589", "stars": 5, "desc": "Atlassian",
|
|
"pushed": "2026-10-06T15:51:43Z", "released": "2026-10-06T15:51:43Z", "basis": "commit", "score": 0.4,
|
|
"trending": True, "kev": True, "page": "/CVE-2026-21589"},
|
|
{"cve": "CVE-2026-24061", "url": "https://github.com/owner/CVE-2026-24061", "name": "CVE-2026-24061",
|
|
"stars": 1250, "desc": "telnetd", "pushed": "2026-10-03T16:24:22Z", "released": "2026-03-08T11:25:39Z",
|
|
"basis": "commit", "score": 0.3, "trending": True, "kev": False, "page": "/CVE-2026-24061"},
|
|
{"cve": "CVE-2026-99999", "url": "https://github.com/owner/unpublished", "name": "unpublished", "stars": 40,
|
|
"desc": "", "pushed": None, "released": None, "basis": "unknown", "score": 0.2, "trending": True,
|
|
"kev": False, "page": None},
|
|
]
|
|
FEED = {"generated": "2026-10-07T09:00:00+00:00", "total_cves": 5, "with_pocs": 4,
|
|
"items": TRENDING, "landed": LANDED, "ranking": "stars_weighted_by_artifact_release_age"}
|
|
INDEXED = [{"cve": cve} for cve in ("CVE-2024-26642", "CVE-2026-21589", "CVE-2021-44228", "CVE-2026-24061")]
|
|
|
|
HARNESS = r"""
|
|
const fs = require('node:fs');
|
|
const vm = require('node:vm');
|
|
const { MessageChannel } = require('node:worker_threads');
|
|
const input = JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
const elements = new Map();
|
|
const buttons = ['LANDED', 'TRENDING'].map(mode => ({
|
|
dataset: { mode }, disabled: mode !== 'LANDED', pressed: null,
|
|
setAttribute(name, value) { if (name === 'aria-pressed') this.pressed = value; }
|
|
}));
|
|
const document = {
|
|
addEventListener() {},
|
|
querySelectorAll: selector => selector === '.trend-controls .switch button' ? buttons : [],
|
|
querySelector(selector) {
|
|
if (!elements.has(selector)) elements.set(selector, {
|
|
value: '', innerHTML: '', textContent: '', addEventListener() {}, setAttribute() {}, querySelectorAll: () => []
|
|
});
|
|
return elements.get(selector);
|
|
}
|
|
};
|
|
const context = vm.createContext({
|
|
console: { warn() {} }, document, performance, MessageChannel, URLSearchParams, URL,
|
|
location: { pathname: '/', search: '' },
|
|
window: { matchMedia: () => ({ matches: false }) },
|
|
setTimeout() {}, clearTimeout() {},
|
|
fetch: url => url === '/trending_poc.json'
|
|
? Promise.resolve({ ok: true, json: async () => input.feed })
|
|
: new Promise(() => {})
|
|
});
|
|
vm.runInContext(fs.readFileSync(input.script, 'utf8'), context);
|
|
const view = () => ({
|
|
rows: elements.get('[data-trend-rows]').innerHTML,
|
|
date: elements.get('[data-trend-date]').textContent,
|
|
pressed: buttons.map(button => button.pressed),
|
|
disabled: buttons.map(button => button.disabled)
|
|
});
|
|
setImmediate(() => {
|
|
const views = { initial: view() };
|
|
for (const mode of ['TRENDING', 'RECENT', 'LANDED']) {
|
|
vm.runInContext(`state.mode = ${JSON.stringify(mode)}; renderTrending();`, context);
|
|
views[mode] = view();
|
|
}
|
|
vm.runInContext('yieldPort.port1.close(); yieldPort.port2.close();', context);
|
|
process.stdout.write(JSON.stringify(views));
|
|
});
|
|
"""
|
|
|
|
|
|
def browser(feed: dict) -> dict:
|
|
"""What logic.js shows once the feed arrives, then for each switch value."""
|
|
node = shutil.which("node")
|
|
if node is None:
|
|
raise unittest.SkipTest("node renders the browser lists")
|
|
payload = {"script": str(ROOT / "docs" / "logic.js"), "feed": feed}
|
|
done = subprocess.run([node, "-e", HARNESS], input=json.dumps(payload), capture_output=True,
|
|
text=True, timeout=60)
|
|
if done.returncode:
|
|
raise AssertionError(done.stderr)
|
|
return json.loads(done.stdout)
|
|
|
|
|
|
def as_browser(markup: str) -> str:
|
|
"""html.escape writes an apostrophe as ' where logic.js writes '."""
|
|
return markup.replace("'", "'")
|
|
|
|
|
|
def cells(markup: str) -> list[dict]:
|
|
rows = []
|
|
for row in re.findall(r'<div class="trend-row">(.*?)</div>', markup):
|
|
stars = re.search(r'<span class="trend-stars[^"]*"[^>]*>(.*?)</span><span class="trend-age">', row).group(1)
|
|
href, name = re.search(r'<a class="trend-name" href="([^"]*)"[^>]*>([^<]*)</a>', row).groups()
|
|
rows.append({"href": html.unescape(href), "name": html.unescape(name),
|
|
"stars": re.sub(r"<[^>]+>", "", stars), "kev": 'class="trend-kev"' in row,
|
|
"date": re.search(r'<span class="trend-age">([^<]*)</span>', row).group(1)})
|
|
return rows
|
|
|
|
|
|
class HomepageListTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls) -> None:
|
|
cls.views = browser(FEED)
|
|
|
|
def test_browser_and_prerendered_homepage_render_the_same_rows(self) -> None:
|
|
landed, trending = build_pages.trend_rows(LANDED, True), build_pages.trend_rows(TRENDING, False)
|
|
for mode in ("initial", "LANDED", "RECENT"):
|
|
with self.subTest(mode=mode):
|
|
self.assertEqual(self.views[mode]["rows"], as_browser(landed))
|
|
self.assertEqual(self.views["TRENDING"]["rows"], as_browser(trending))
|
|
page = build_pages.homepage(INDEXED, {}, FEED)
|
|
self.assertIn(landed, page)
|
|
self.assertNotIn("telnetd", page)
|
|
|
|
def test_each_list_keeps_its_published_order_and_may_share_a_poc(self) -> None:
|
|
landed, trending = cells(self.views["LANDED"]["rows"]), cells(self.views["TRENDING"]["rows"])
|
|
self.assertEqual([row["href"] for row in landed], [item["url"] for item in LANDED])
|
|
self.assertEqual([row["href"] for row in trending], [item["url"] for item in TRENDING])
|
|
self.assertIn(SHARED, [row["href"] for row in landed])
|
|
self.assertIn(SHARED, [row["href"] for row in trending])
|
|
|
|
def test_dates_are_utc_days_and_unknown_dates_are_explicit(self) -> None:
|
|
landed, trending = cells(self.views["LANDED"]["rows"]), cells(self.views["TRENDING"]["rows"])
|
|
self.assertEqual([row["date"] for row in landed], ["2026-10-07", "2026-10-06", "2026-10-05"])
|
|
self.assertEqual([row["date"] for row in trending], ["2026-10-06", "2026-10-03", "N/A"])
|
|
self.assertEqual([self.views[mode]["date"] for mode in ("initial", "TRENDING", "RECENT")],
|
|
["RELEASED", "UPDATED", "RELEASED"])
|
|
self.assertNotIn(" ago", self.views["LANDED"]["rows"] + self.views["TRENDING"]["rows"])
|
|
|
|
def test_artifacts_show_host_repository_stars_and_keep_their_variant_or_host(self) -> None:
|
|
landed = cells(self.views["LANDED"]["rows"])
|
|
self.assertEqual([(row["name"], row["stars"], row["kev"]) for row in landed], [
|
|
("CVE-2024-26642_mitigation", "5.0k ★", False), ("CVE-2026-21589", "5 ★", True),
|
|
("exploit-db.com/50592", "N/A", True)])
|
|
self.assertIn('title="Repository stars: google/security-research"', self.views["LANDED"]["rows"])
|
|
self.assertEqual(cells(self.views["TRENDING"]["rows"])[1]["stars"], "1.3k ★")
|
|
self.assertIn("Atlassian's <b>file read</b>", self.views["LANDED"]["rows"])
|
|
|
|
def test_switch_starts_on_just_landed_and_trending_waits_for_the_feed(self) -> None:
|
|
page = build_pages.homepage(INDEXED, {}, FEED)
|
|
landed = re.search(r'<button [^>]*data-mode="LANDED"[^>]*>', page).group(0)
|
|
trending = re.search(r'<button [^>]*data-mode="TRENDING"[^>]*>', page).group(0)
|
|
self.assertIn('aria-pressed="true"', landed)
|
|
self.assertIn(" disabled", trending)
|
|
self.assertEqual(self.views["initial"]["disabled"], [False, False])
|
|
self.assertEqual([self.views[mode]["pressed"] for mode in ("initial", "TRENDING", "RECENT")],
|
|
[["true", "false"], ["false", "true"], ["true", "false"]])
|
|
|
|
def test_an_empty_list_shows_the_empty_state_in_both(self) -> None:
|
|
empty = build_pages.trend_rows([], True)
|
|
self.assertIn("No recent PoCs.", empty)
|
|
self.assertEqual(browser({**FEED, "landed": []})["initial"]["rows"], empty)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|