SHA256-Pruefsumme fuer ISO-Builds
Siehe Fund #7 im heutigen Self-Service-Flow-Test (Memory). Migration 0023 (iso_builds.sha256), compute_file_sha256() haest die Datei einmalig direkt nach erfolgreichem Bau (gestreamt, nicht komplett im Speicher - ISOs sind mehrere GB), update_iso_build() nimmt den Wert jetzt entgegen. Ermoeglicht Integritaetspruefung unabhaengig vom Kundenplattform-Download-Proxy-Pfad. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2f6ff909f9
commit
e88e0da0da
33
app.py
33
app.py
@ -2141,7 +2141,7 @@ def recharge_enrollment_session(session_id: str, additional_devices: int, expire
|
||||
|
||||
def iso_build_row_to_dict(row) -> dict:
|
||||
(build_id, organization_id, status, output_filename, error_message,
|
||||
created_at, started_at, finished_at, expires_at) = row
|
||||
created_at, started_at, finished_at, expires_at, sha256) = row
|
||||
return {
|
||||
"id": str(build_id),
|
||||
"organization_id": str(organization_id),
|
||||
@ -2152,6 +2152,7 @@ def iso_build_row_to_dict(row) -> dict:
|
||||
"started_at": started_at.isoformat() if started_at else None,
|
||||
"finished_at": finished_at.isoformat() if finished_at else None,
|
||||
"expires_at": expires_at.isoformat() if expires_at else None,
|
||||
"sha256": sha256,
|
||||
}
|
||||
|
||||
def fetch_iso_build(build_id: str):
|
||||
@ -2160,7 +2161,7 @@ def fetch_iso_build(build_id: str):
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT id, organization_id, status, output_filename, error_message,
|
||||
created_at, started_at, finished_at, expires_at
|
||||
created_at, started_at, finished_at, expires_at, sha256
|
||||
FROM iso_builds
|
||||
WHERE id = %s
|
||||
""",
|
||||
@ -2175,7 +2176,7 @@ def fetch_iso_builds(organization_id: str):
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT id, organization_id, status, output_filename, error_message,
|
||||
created_at, started_at, finished_at, expires_at
|
||||
created_at, started_at, finished_at, expires_at, sha256
|
||||
FROM iso_builds
|
||||
WHERE organization_id = %s
|
||||
ORDER BY created_at DESC
|
||||
@ -2201,6 +2202,7 @@ def update_iso_build(
|
||||
status: str,
|
||||
output_filename: str | None = None,
|
||||
error_message: str | None = None,
|
||||
sha256: str | None = None,
|
||||
mark_started: bool = False,
|
||||
mark_finished: bool = False,
|
||||
):
|
||||
@ -2217,13 +2219,14 @@ def update_iso_build(
|
||||
UPDATE iso_builds
|
||||
SET status = %s,
|
||||
output_filename = COALESCE(%s, output_filename),
|
||||
error_message = %s
|
||||
error_message = %s,
|
||||
sha256 = COALESCE(%s, sha256)
|
||||
{", started_at = CURRENT_TIMESTAMP" if mark_started else ""}
|
||||
{", finished_at = CURRENT_TIMESTAMP" if mark_finished else ""}
|
||||
{f", expires_at = CURRENT_TIMESTAMP + INTERVAL '{ISO_BUILD_EXPIRY_DAYS} days'" if setzt_expiry else ""}
|
||||
WHERE id = %s
|
||||
""",
|
||||
(status, output_filename, error_message, build_id),
|
||||
(status, output_filename, error_message, sha256, build_id),
|
||||
)
|
||||
|
||||
def cleanup_old_iso_builds(organization_id: str, keep_build_id) -> None:
|
||||
@ -2331,6 +2334,20 @@ def compute_iso_volid(organization_name: str) -> str:
|
||||
return f"{sanitized}_{date_suffix}"
|
||||
|
||||
|
||||
def compute_file_sha256(path) -> str:
|
||||
"""
|
||||
Streamt die Datei in 1-MB-Bloecken statt sie komplett in den Speicher zu
|
||||
laden (ISOs sind mehrere GB gross) - laeuft im selben Background-Thread
|
||||
wie der Bau selbst, blockiert also keinen HTTP-Request.
|
||||
"""
|
||||
|
||||
hasher = hashlib.sha256()
|
||||
with open(path, "rb") as f:
|
||||
for block in iter(lambda: f.read(1024 * 1024), b""):
|
||||
hasher.update(block)
|
||||
|
||||
return hasher.hexdigest()
|
||||
|
||||
def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssid: str | None, wifi_psk: str | None) -> None:
|
||||
output_path = ISO_BUILD_OUTPUT_DIR / f"{build_id}.iso"
|
||||
|
||||
@ -2371,7 +2388,11 @@ def run_iso_build(build_id, organization_id: str, activation_code: str, wifi_ssi
|
||||
update_iso_build(build_id, status="failed", error_message=error_tail, mark_finished=True)
|
||||
return
|
||||
|
||||
update_iso_build(build_id, status="completed", output_filename=output_path.name, mark_finished=True)
|
||||
sha256 = compute_file_sha256(output_path)
|
||||
|
||||
update_iso_build(
|
||||
build_id, status="completed", output_filename=output_path.name, sha256=sha256, mark_finished=True
|
||||
)
|
||||
cleanup_old_iso_builds(organization_id, build_id)
|
||||
|
||||
@app.get("/health")
|
||||
|
||||
6
migrations/0023_iso_build_sha256.sql
Normal file
6
migrations/0023_iso_build_sha256.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- SHA256-Pruefsumme fuer heruntergeladene ISOs (28.08.2026-Fund, Self-
|
||||
-- Service-Flow-Test): Download laeuft ueber den Kundenplattform-Proxy zu
|
||||
-- anode, ein Hash zur Integritaetspruefung unabhaengig von diesem Pfad war
|
||||
-- bislang nicht vorhanden. Einmalig direkt nach erfolgreichem Bau berechnet
|
||||
-- (nicht bei jedem Seitenaufruf - mehrere GB Datei).
|
||||
ALTER TABLE iso_builds ADD COLUMN sha256 TEXT;
|
||||
Loading…
x
Reference in New Issue
Block a user