mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-03 12:06:38 +00:00
feat(oci): run official container images as native LXC containers
Adds the OCI manager: an engine that turns a Docker Compose file into an LXC definition, a catalog of 365 applications drawn from LinuxServer.io and other container image sources, and a per-instance registry recording what each container was built from. Reachable from the main menu. Catalog text is translated like every other string in the project: the taglines go through translate() and land in lang/*.json, so the entries read in all eight languages instead of only English. Translation cache builder: - a failed translation leaves the key absent rather than writing English, which previously made the string count as translated forever - a result identical to a 3+ word source is rejected, catching a provider that silently returns the text it was given - strings that are nothing but glossary terms keep their source spelling instead of being discarded as failures - no backoff between attempts when the provider is deterministic - application names are protected so "HAOS One" survives translation - argos joins the provider list, and the workflow reads the OCI sources Audit & Report: - findings that moved in the wrong direction between runs are reported alongside the ones that improved - an accepted risk can carry a review date and is flagged when it falls due - backup checks explain in plain language what they looked at and what to do next Monitor: - disks can be excluded from periodic reads, and an idle disk says so instead of showing a stale temperature - per-disk identity survives a controller or enclosure change - scheduled Borg backups resolve their SSH key from the repository entry - PVE upgrades log the package list and the resulting dpkg changes The web build no longer copies scripts/ into public/: the documentation links to GitHub, so nothing read that folder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -691,6 +691,37 @@ def run_assessment(profile: str = "full",
|
||||
return run_id
|
||||
|
||||
|
||||
def _scope(finding: dict) -> int:
|
||||
"""How many objects a finding covers. A check that named three guests
|
||||
and now names nine describes a larger problem, even at the same
|
||||
gravity."""
|
||||
return len(finding.get("affected") or [])
|
||||
|
||||
|
||||
def _movement(previous: dict, current: dict) -> int:
|
||||
"""Whether a finding present in both runs got worse (1), better (-1) or
|
||||
held (0). Gravity decides; scope only breaks a tie, because a finding
|
||||
takes the gravity of its gravest object and dropping from critical to
|
||||
warning is progress however many objects it now names."""
|
||||
before = audit_store.CLASS_ORDER.get(previous["classification"])
|
||||
after = audit_store.CLASS_ORDER.get(current["classification"])
|
||||
if before is not None and after is not None and before != after:
|
||||
return 1 if after < before else -1
|
||||
before_scope, after_scope = _scope(previous), _scope(current)
|
||||
if after_scope != before_scope:
|
||||
return 1 if after_scope > before_scope else -1
|
||||
return 0
|
||||
|
||||
|
||||
def _against(current: dict, previous: dict) -> dict:
|
||||
"""A finding carrying where it came from, so the reader is told what
|
||||
moved instead of only what it is now."""
|
||||
return {**current,
|
||||
"previous_classification": previous["classification"],
|
||||
"previous_affected": _scope(previous),
|
||||
"affected_count": _scope(current)}
|
||||
|
||||
|
||||
def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
|
||||
"""Classify how findings moved between two runs.
|
||||
|
||||
@@ -700,6 +731,12 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
|
||||
that merges them would tell its reader the problem went away when the
|
||||
decision was to live with it.
|
||||
|
||||
A finding that was already failing and still fails is never new. It
|
||||
either got worse, got better without being resolved, or held: reporting
|
||||
a warning that became critical as new hides that it was already there,
|
||||
and reporting a critical that dropped to a warning as new tells the
|
||||
reader their work created a problem.
|
||||
|
||||
``unchanged`` is kept so a report can state that the rest of the
|
||||
surface held steady rather than leaving it unaccounted for.
|
||||
"""
|
||||
@@ -708,6 +745,7 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
|
||||
other = {f["check_id"]: f for f in audit_store.get_findings(other_run)}
|
||||
|
||||
new, resolved, accepted, unchanged, unverified = [], [], [], [], []
|
||||
worse, better = [], []
|
||||
for check_id, current in other.items():
|
||||
previous = base.get(check_id)
|
||||
was = previous["classification"] in problems if previous else False
|
||||
@@ -718,8 +756,16 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
|
||||
unverified.append(current)
|
||||
elif now and current.get("decision") == audit_store.DECISION_ACCEPTED:
|
||||
accepted.append(current)
|
||||
elif now and (not was or previous["classification"] != current["classification"]):
|
||||
elif now and not was:
|
||||
new.append(current)
|
||||
elif now and was:
|
||||
moved = _movement(previous, current)
|
||||
if moved > 0:
|
||||
worse.append(_against(current, previous))
|
||||
elif moved < 0:
|
||||
better.append(_against(current, previous))
|
||||
else:
|
||||
unchanged.append(current)
|
||||
elif was and not now:
|
||||
if current.get("decision") == audit_store.DECISION_ACCEPTED:
|
||||
accepted.append(current)
|
||||
@@ -738,6 +784,8 @@ def compare_runs(base_run: str, other_run: str) -> dict[str, list[dict]]:
|
||||
|
||||
return {
|
||||
"new": new,
|
||||
"worse": worse,
|
||||
"better": better,
|
||||
"resolved": resolved,
|
||||
"accepted": accepted,
|
||||
"unchanged": unchanged,
|
||||
|
||||
Reference in New Issue
Block a user