← Files VeraARCHIVED FILE

vendor/modules/courseware/website_view.py

2.97 KB · Oct 2, 2026 · 00:29 UTC

↓ Download file

"""Copy the exact validated local teaching site, including its local assets."""

from __future__ import annotations

import hashlib
import json
from pathlib import Path, PurePosixPath


def website_files(lesson: Path, execution: dict) -> dict[Path, tuple[str, str]]:
    """Bind authored outputs and passive assets to the complete native inventory."""
    records = [
        lesson / item["path"]
        for item in execution["native_records"]
        if Path(item["path"]).name == "site_validation.json"
    ]
    if len(records) != 1:
        raise ValueError("Website results need one native site validation record")
    validation = json.loads(records[0].read_text(encoding="utf-8"))
    inventory = validation.get("inventory", [])
    digest = hashlib.sha256(
        json.dumps(
            inventory, ensure_ascii=False, sort_keys=True, separators=(",", ":")
        ).encode("utf-8")
    ).hexdigest()
    if (
        validation.get("status") != "ready"
        or validation.get("site_digest") != digest
        or not inventory
    ):
        raise ValueError("Website results need a current successful site inventory")
    site = records[0].parent / "work/site"
    outputs = {lesson / item["path"]: item["sha256"] for item in execution["outputs"]}
    allowed = {
        ".html",
        ".css",
        ".png",
        ".jpg",
        ".jpeg",
        ".webp",
        ".woff",
        ".woff2",
        ".ttf",
        ".txt",
    }
    result = {}
    for item in inventory:
        relative = PurePosixPath(item["path"])
        if (
            relative.is_absolute()
            or ".." in relative.parts
            or "\\" in item["path"]
            or relative.as_posix() != item["path"]
            or relative.suffix.lower() not in allowed
        ):
            raise ValueError("Website inventory contains an unsupported local path")
        source = site / relative
        # Reused styles/fonts/images are dependencies, never completion evidence.
        # Their exact bytes remain bound by the attested native inventory.
        output_required = relative.suffix.lower() == ".html"
        if (
            source in result
            or (output_required and outputs.get(source) != item["sha256"])
            or (source in outputs and outputs[source] != item["sha256"])
            or not source.is_file()
            or any(p.is_symlink() for p in (source, *source.parents))
            or source.stat().st_size != item["bytes"]
            or hashlib.sha256(source.read_bytes()).hexdigest() != item["sha256"]
        ):
            raise ValueError(
                "Website results must include every exact validated site file"
            )
        result[source] = ("website/" + relative.as_posix(), item["sha256"])
    if site / "index.html" not in result:
        raise ValueError("Website results need the validated index page")
    if any(p.is_relative_to(site) and p not in result for p in outputs):
        raise ValueError("Website outputs contain an unvalidated site file")
    return result

SHA-256: f230f86272201bae7bc34f1868d8cb6013b47ce9ccc8b876acdfb0bc257637d5