feat(release): install and supervise the bounded HTTPS entry
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
"""Closed public NGINX runtime inventory, independent from TLS and service state."""
|
||||
|
||||
import re
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
from .policy import DeliveryError, digest, fields, integer, read_json, sha256
|
||||
|
||||
VERSION = "1.30.5"
|
||||
MAX_BYTES = 64 * 1024**2
|
||||
|
||||
|
||||
def validate(value: dict) -> dict:
|
||||
fields(
|
||||
value,
|
||||
{
|
||||
"schema_version",
|
||||
"format",
|
||||
"version",
|
||||
"architecture",
|
||||
"package_sha256",
|
||||
"files",
|
||||
"directories",
|
||||
"payload_bytes",
|
||||
},
|
||||
"proxy runtime",
|
||||
)
|
||||
if (
|
||||
type(value["schema_version"]) is not int
|
||||
or value["schema_version"] != 1
|
||||
or value["format"] != "kf.nginx.runtime.v1"
|
||||
or value["version"] != VERSION
|
||||
or value["architecture"] != "x86_64"
|
||||
or value["directories"] != ["bin", "lib"]
|
||||
or not isinstance(value["files"], list)
|
||||
or not 1 <= len(value["files"]) <= 32
|
||||
):
|
||||
raise DeliveryError("unsupported proxy runtime profile")
|
||||
sha256(value["package_sha256"])
|
||||
names = set()
|
||||
total = 0
|
||||
for entry in value["files"]:
|
||||
fields(entry, {"path", "bytes", "sha256", "mode"}, "proxy runtime file")
|
||||
name = entry["path"]
|
||||
if not isinstance(name, str) or (
|
||||
name != "bin/nginx" and not re.fullmatch(r"lib/[A-Za-z0-9_.+-]+\.so(?:\.[0-9]+)*", name)
|
||||
):
|
||||
raise DeliveryError("non-runtime or private proxy member")
|
||||
if name in names or entry["mode"] != ("0555" if name == "bin/nginx" else "0444"):
|
||||
raise DeliveryError("duplicate proxy member or unsafe mode")
|
||||
names.add(name)
|
||||
total += integer(entry["bytes"], 1, 32 * 1024**2, "proxy file bytes")
|
||||
sha256(entry["sha256"])
|
||||
if (
|
||||
not {"bin/nginx", "lib/libc.so.6", "lib/ld-linux-x86-64.so.2"} <= names
|
||||
or total > MAX_BYTES
|
||||
or type(value["payload_bytes"]) is not int
|
||||
or value["payload_bytes"] != total
|
||||
):
|
||||
raise DeliveryError("incomplete or unbounded proxy runtime")
|
||||
return value
|
||||
|
||||
|
||||
def verify(root: Path, expected: str) -> dict:
|
||||
if root.is_symlink() or not root.is_dir():
|
||||
raise DeliveryError("ordinary proxy runtime directory required")
|
||||
catalog = root / "manifest.json"
|
||||
if catalog.is_symlink() or digest(catalog) != sha256(expected):
|
||||
raise DeliveryError("proxy runtime out-of-band fingerprint differs")
|
||||
value = validate(read_json(catalog, 16384))
|
||||
if {p.name for p in root.iterdir()} != {"manifest.json", "bin", "lib"}:
|
||||
raise DeliveryError("unexpected proxy runtime tree member")
|
||||
for directory in (root / "bin", root / "lib"):
|
||||
if (
|
||||
directory.is_symlink()
|
||||
or not directory.is_dir()
|
||||
or stat.S_IMODE(directory.stat().st_mode) != 0o555
|
||||
):
|
||||
raise DeliveryError("readonly ordinary proxy runtime directories required")
|
||||
names = set()
|
||||
for directory in (root / "bin", root / "lib"):
|
||||
for p in directory.iterdir():
|
||||
names.add(p.relative_to(root).as_posix())
|
||||
if names != {entry["path"] for entry in value["files"]}:
|
||||
raise DeliveryError("proxy runtime inventory differs")
|
||||
for entry in value["files"]:
|
||||
p = root / entry["path"]
|
||||
info = p.lstat()
|
||||
if (
|
||||
not stat.S_ISREG(info.st_mode)
|
||||
or info.st_nlink != 1
|
||||
or info.st_size != entry["bytes"]
|
||||
or stat.S_IMODE(info.st_mode) != int(entry["mode"], 8)
|
||||
or digest(p) != entry["sha256"]
|
||||
):
|
||||
raise DeliveryError("proxy runtime bytes or permission differ")
|
||||
return value
|
||||
|
||||
|
||||
def copy_to_payload(root: Path, expected: str, destination: Path) -> None:
|
||||
from .build import copy
|
||||
|
||||
value = verify(root, expected)
|
||||
if destination.exists() or destination.is_symlink():
|
||||
raise DeliveryError("proxy runtime payload must be new")
|
||||
destination.mkdir()
|
||||
for directory in value["directories"]:
|
||||
(destination / directory).mkdir()
|
||||
for entry in value["files"]:
|
||||
copy(root / entry["path"], destination / entry["path"])
|
||||
copy(root / "manifest.json", destination / "manifest.json")
|
||||
Reference in New Issue
Block a user