feat(db): backfill, DB-backed web scans, firewall snapshot view (R001/S001/F001)
- R001: app/db/backfill.py imports git-history blocklist -> ledger, firewall snapshots, and per-source requests.csv (idempotent; ran live migrating 705 historical blocklist entries). - S001: web_scan.latest_scans() now merges SQLite 'scans' records so the dashboard surfaces CLI/restart scans (_db_scans). - F001: /api/firewall/snapshots + 'Snapshot history' panel; added recent_firewall_snapshots() query with entry counts.
This commit is contained in:
1 parent
ba48054293
commit
2fb4032766
4 files changed
+308
-6
No files matched your search
@@ -23,6 +23,11 @@ endblock %} {% block content %}
|
||||
<div class="panel-head"><h2>Firewall rules</h2></div>
|
||||
<div id="firewall-rules"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-head"><h2>Snapshot history (SQLite)</h2></div>
|
||||
<div id="fw-snapshots"></div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script>
|
||||
async function loadState() {
|
||||
@@ -35,6 +40,45 @@ endblock %} {% block content %}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSnapshots() {
|
||||
const box = document.getElementById("fw-snapshots");
|
||||
try {
|
||||
const d = await api("/api/firewall/snapshots?limit=10");
|
||||
const snaps = d.snapshots || [];
|
||||
if (!snaps.length) {
|
||||
box.innerHTML =
|
||||
'<p class="muted">No SQLite snapshots yet — they are recorded on each <code>--update-firewall</code> run.</p>';
|
||||
return;
|
||||
}
|
||||
box.innerHTML = "";
|
||||
const rows = snaps.map((s) =>
|
||||
el(
|
||||
"tr",
|
||||
el("td", { class: "mono", text: `#${s.id}` }),
|
||||
el("td", { text: fmtTime(s.captured_at) }),
|
||||
el("td", { text: s.kind }),
|
||||
el("td", { text: s.trigger }),
|
||||
el("td", { class: "num", text: s.addr_entries }),
|
||||
el("td", { class: "num", text: s.rule_entries }),
|
||||
),
|
||||
);
|
||||
box.append(
|
||||
el(
|
||||
"table",
|
||||
{ class: "table" },
|
||||
el(
|
||||
"thead",
|
||||
el("tr", {}, el("th", { text: "ID" }), el("th", { text: "Captured" }), el("th", { text: "Kind" }), el("th", { text: "Trigger" }), el("th", { text: "Addr" }), el("th", { text: "Rules" })),
|
||||
),
|
||||
el("tbody", {}, ...rows),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
box.innerHTML=
|
||||
'<p class="muted">Snapshot history unavailable (SQLite).</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function renderAddressLists(addr) {
|
||||
const box = document.getElementById("address-lists");
|
||||
box.innerHTML = "";
|
||||
@@ -172,5 +216,6 @@ endblock %} {% block content %}
|
||||
.getElementById("apply-btn")
|
||||
.addEventListener("click", () => sync(false));
|
||||
loadState();
|
||||
loadSnapshots();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user