Add signed runtime distribution pipeline
Dependency Audit / dependency-audit (push) Successful in 1m39s
Deployment Installer / deployment-installer (push) Successful in 5s
Security Audit / security-audit (push) Successful in 10m3s

This commit is contained in:
2026-08-03 00:54:06 +02:00
parent 29acb55b7c
commit 43380eb068
24 changed files with 3371 additions and 54 deletions
+207
View File
@@ -0,0 +1,207 @@
from __future__ import annotations
import base64
from datetime import UTC, datetime, timedelta
import hashlib
from pathlib import Path
import sys
import tempfile
import unittest
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
META_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(META_ROOT / "tools" / "deployment"))
from govoplan_deploy.bundle import bundle_paths # noqa: E402
from govoplan_deploy.cli import main # noqa: E402
from govoplan_deploy.distribution import ( # noqa: E402
canonical_json,
canonical_signed_payload,
)
from govoplan_deploy.model import load_spec # noqa: E402
from govoplan_deploy.planning import static_checks # noqa: E402
class DeploymentReleaseAdoptionTests(unittest.TestCase):
def test_adopts_verified_manifest_and_makes_release_checks_pass(self) -> None:
with tempfile.TemporaryDirectory(prefix="govoplan-release-adopt-") as value:
root = Path(value)
self.assertEqual(
0,
main(
[
"init",
"--directory",
str(root),
"--non-interactive",
"--module-set",
"core",
]
),
)
manifest, keyring = self._signed_distribution()
manifest_path = root / "source-manifest.json"
keyring_path = root / "source-keyring.json"
encoded_manifest = canonical_json(manifest)
manifest_path.write_bytes(encoded_manifest)
keyring_path.write_bytes(canonical_json(keyring))
result = main(
[
"verify-release",
"--directory",
str(root),
"--manifest",
str(manifest_path),
"--manifest-sha256",
hashlib.sha256(encoded_manifest).hexdigest(),
"--trusted-keyring",
str(keyring_path),
"--adopt",
]
)
self.assertEqual(0, result)
paths = bundle_paths(root)
spec = load_spec(paths.spec)
self.assertEqual("1.2.3", spec.release.version)
self.assertEqual("release-1", spec.release.manifest_signature_key_id)
self.assertTrue(spec.release.api_image.endswith("a" * 64))
release_checks = {
item.id: item for item in static_checks(spec, paths)
if item.id.startswith("release.") or item.id == "modules.image_composition"
}
self.assertEqual("ok", release_checks["release.manifest"].level)
self.assertEqual(
"ok", release_checks["release.signature_verification"].level
)
self.assertEqual("ok", release_checks["modules.image_composition"].level)
def test_rejects_manifest_whose_independent_digest_does_not_match(self) -> None:
with tempfile.TemporaryDirectory(prefix="govoplan-release-adopt-") as value:
root = Path(value)
main(
[
"init",
"--directory",
str(root),
"--non-interactive",
"--module-set",
"core",
]
)
manifest, keyring = self._signed_distribution()
manifest_path = root / "source-manifest.json"
keyring_path = root / "source-keyring.json"
manifest_path.write_bytes(canonical_json(manifest))
keyring_path.write_bytes(canonical_json(keyring))
self.assertEqual(
1,
main(
[
"verify-release",
"--directory",
str(root),
"--manifest",
str(manifest_path),
"--manifest-sha256",
"0" * 64,
"--trusted-keyring",
str(keyring_path),
]
),
)
@staticmethod
def _signed_distribution() -> tuple[dict[str, object], dict[str, object]]:
now = datetime.now(UTC)
private = Ed25519PrivateKey.generate()
public = private.public_key().public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo,
).decode("ascii")
artifact = {
"url": "https://downloads.example.test/artifact.json",
"sha256": "f" * 64,
}
payload: dict[str, object] = {
"schema_version": "1",
"channel": "stable",
"sequence": 1,
"version": "1.2.3",
"issued_at": (now - timedelta(minutes=1)).isoformat(),
"expires_at": (now + timedelta(days=30)).isoformat(),
"revoked": False,
"deployer": {
"url": "https://downloads.example.test/govoplan-deploy.pyz",
"sha256": "e" * 64,
},
"images": {
"api": {
"index": "registry.example/govoplan/api@sha256:" + "a" * 64,
"platforms": {
"linux/amd64": "registry.example/govoplan/api@sha256:" + "1" * 64,
"linux/arm64": "registry.example/govoplan/api@sha256:" + "2" * 64,
},
"sbom": dict(artifact),
"provenance": dict(artifact),
},
"web": {
"index": "registry.example/govoplan/web@sha256:" + "b" * 64,
"platforms": {
"linux/amd64": "registry.example/govoplan/web@sha256:" + "3" * 64,
"linux/arm64": "registry.example/govoplan/web@sha256:" + "4" * 64,
},
"sbom": dict(artifact),
"provenance": dict(artifact),
},
},
"dependencies": {
"postgres": "docker.io/library/postgres@sha256:" + "5" * 64,
"redis": "docker.io/library/redis@sha256:" + "6" * 64,
"load_balancer": "docker.io/library/haproxy@sha256:" + "7" * 64,
},
"composition": {
"sha256": "c" * 64,
"module_ids": [],
"packages": [
{
"name": "govoplan-core",
"version": "1.2.3",
"wheel_sha256": "8" * 64,
}
],
},
}
payload["signatures"] = [
{
"key_id": "release-1",
"algorithm": "ed25519",
"value": base64.b64encode(
private.sign(canonical_signed_payload(payload))
).decode("ascii"),
}
]
keyring = {
"schema_version": "1",
"purpose": "govoplan-runtime-distribution",
"keys": [
{
"key_id": "release-1",
"algorithm": "ed25519",
"status": "active",
"public_key_pem": public,
"not_before": (now - timedelta(days=1)).isoformat(),
"expires_at": (now + timedelta(days=365)).isoformat(),
}
],
}
return payload, keyring
if __name__ == "__main__":
unittest.main()