mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-29 18:16:43 +00:00
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>
58 lines
2.6 KiB
Python
58 lines
2.6 KiB
Python
"""Validation for the experimental native-device/dynamic-library NVIDIA profile.
|
|
|
|
Driver files are runtime evidence, not persistent desired-state dependencies.
|
|
This module does not enable transactions before the common installer supports
|
|
the same profile.
|
|
"""
|
|
from pathlib import Path
|
|
import hashlib
|
|
|
|
import oci_nvidia_runtime as nv
|
|
from oci_ui import translate
|
|
|
|
|
|
def gpu_identity(inventory):
|
|
identities = []
|
|
for row in inventory['gpus']:
|
|
fields = [part.strip() for part in row.split(',')]
|
|
if len(fields) != 3 or not all(fields):
|
|
raise ValueError(translate('Incomplete NVIDIA identity'))
|
|
identities.append(tuple(fields[:2]))
|
|
if not identities or len(set(identities)) != len(identities):
|
|
raise ValueError(translate('Empty or duplicated NVIDIA identity'))
|
|
return sorted(identities)
|
|
|
|
|
|
def validate(config, previous, current, hook, expected_hook_sha256,
|
|
capabilities='compute,utility,video'):
|
|
if gpu_identity(previous) != gpu_identity(current):
|
|
raise ValueError(translate('The selected GPU changed'))
|
|
if nv.mount_lines(config):
|
|
raise ValueError(translate('The dynamic profile does not support static driver mounts'))
|
|
hook = Path(hook)
|
|
info = hook.stat()
|
|
if (hook.is_symlink() or not hook.is_file() or info.st_uid != 0
|
|
or info.st_mode & 0o022 or not info.st_mode & 0o111
|
|
or hashlib.sha256(hook.read_bytes()).hexdigest() != expected_hook_sha256):
|
|
raise ValueError(translate('Untrusted or modified NVIDIA hook'))
|
|
allowed = {'lxc.hook.mount': str(hook),
|
|
'lxc.environment': {'NVIDIA_VISIBLE_DEVICES=all',
|
|
f'NVIDIA_DRIVER_CAPABILITIES={capabilities}'}}
|
|
found_hook, environments = [], []
|
|
for line in config.decode().splitlines():
|
|
if not line.startswith('lxc.') or ': ' not in line:
|
|
continue
|
|
key, value = line.split(': ', 1)
|
|
if key == 'lxc.hook.mount':
|
|
found_hook.append(value)
|
|
elif key == 'lxc.environment':
|
|
environments.append(value)
|
|
elif key.startswith(('lxc.hook.', 'lxc.cgroup', 'lxc.apparmor')):
|
|
raise ValueError(translate('Security directive outside the dynamic profile'))
|
|
if found_hook != [allowed['lxc.hook.mount']] or (
|
|
len(environments) != 2 or set(environments) != allowed['lxc.environment']):
|
|
raise ValueError(translate('The NVIDIA hook or environment differs from the declared one'))
|
|
nv.check_devices(config, current)
|
|
return {'gpu_identity': gpu_identity(current), 'hook_sha256': expected_hook_sha256,
|
|
'driver_capabilities': capabilities, 'inventory': current}
|