ci: add exact-source Gitea backend builds

This commit is contained in:
2026-09-27 10:20:32 -04:00
parent d90a57bb11
commit 6ec84f3e4d
9 changed files with 567 additions and 1 deletions
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Admit one reviewed canonical source or its exact Builds merge wrapper."""
import os
import re
import subprocess
import sys
class Refusal(ValueError):
pass
def git(*args):
return subprocess.check_output(["git", *args], text=True, stderr=subprocess.PIPE).strip()
def commit(value, label):
if not re.fullmatch(r"[0-9a-f]{40}", value or ""):
raise Refusal(f"{label} must be a reviewed full lowercase commit SHA")
return value
def source_for_checkout(require_wrapper):
if not require_wrapper:
return git("rev-parse", "HEAD")
parents = git("show", "-s", "--format=%P", "HEAD").split()
if len(parents) != 2:
raise Refusal("release or main CI requires a two-parent Builds wrapper")
return commit(parents[1], "canonical source parent")
def admit(source, expected_head=None, require_wrapper=False):
source = commit(source, "canonical source")
head = git("rev-parse", "HEAD")
if expected_head is not None and head != commit(expected_head, "expected_sha"):
raise Refusal("checkout HEAD differs from the reviewed dispatch head")
if git("rev-parse", f"{source}^{{commit}}") != source:
raise Refusal("reviewed canonical source is not a commit")
tree = git("rev-parse", f"{source}^{{tree}}")
if git("rev-parse", "HEAD^{tree}") != tree:
raise Refusal("Builds checkout tree differs from reviewed canonical source")
if head != source or require_wrapper:
parents = git("show", "-s", "--format=%P", "HEAD").split()
if len(parents) != 2 or parents[1] != source:
raise Refusal("Builds HEAD is neither canonical source nor its two-parent wrapper")
if git("status", "--porcelain", "--untracked-files=all"):
raise Refusal("Builds checkout contains local changes or untracked files")
return {"source_commit": source, "build_commit": head, "source_tree": tree}
def main():
if os.environ.get("GITHUB_REPOSITORY") != "Builds/smirk-backend-core":
raise Refusal("this workflow is admitted only on Builds/smirk-backend-core")
event = os.environ.get("GITHUB_EVENT_NAME")
expected = os.environ.get("EXPECTED_BUILD_SHA")
if not expected:
raise Refusal("this build requires the exact reviewed event or dispatch head")
if event not in {"push", "pull_request", "workflow_dispatch"}:
raise Refusal("this build event is not admitted")
wrapper = event != "pull_request"
canonical = source_for_checkout(wrapper)
result = admit(canonical, expected, require_wrapper=wrapper)
print(f"Admitted canonical source {result['source_commit']} at Builds {result['build_commit']}")
if __name__ == "__main__":
try:
main()
except Refusal as error:
sys.exit(f"Build source refused: {error}")
except subprocess.CalledProcessError:
sys.exit("Build source refused: Git could not resolve the reviewed source or checkout")
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Own a disposable Unix-socket PostgreSQL cluster. Never use a caller's database.
set -euo pipefail
set +x
if [[ $# != 0 ]]; then
echo 'Fundless CI does not accept a database or test-command override.' >&2
exit 1
fi
if [[ -f .env ]]; then
echo 'Fundless CI refuses a checkout containing .env.' >&2
exit 1
fi
pg_bin=$(pg_config --bindir)
for tool in initdb pg_ctl createdb psql; do
[[ -x "$pg_bin/$tool" ]] || { echo "Fundless CI requires PostgreSQL $tool." >&2; exit 1; }
done
ci_pg_dir=$(mktemp -d /tmp/smirk-ci-pg.XXXXXXXX)
chmod 700 "$ci_pg_dir"
pg_user=$(id -un)
if [[ $(id -u) == 0 ]]; then
pg_user=postgres
id "$pg_user" >/dev/null 2>&1 || { echo 'The isolated CI container requires the postgres service account.' >&2; exit 1; }
chown "$pg_user" "$ci_pg_dir"
fi
pg_exec() {
if [[ $(id -u) == 0 ]]; then
runuser -u "$pg_user" -- "$@"
else
"$@"
fi
}
cleanup() {
pg_exec "$pg_bin/pg_ctl" -D "$ci_pg_dir/data" -m immediate -w stop >/dev/null 2>&1 || true
rm -rf "$ci_pg_dir"
}
trap cleanup EXIT
pg_exec "$pg_bin/initdb" -D "$ci_pg_dir/data" --auth-local=trust --auth-host=reject --no-locale >/dev/null
# No TCP listener and a private socket directory: no password or shared service.
pg_exec "$pg_bin/pg_ctl" -D "$ci_pg_dir/data" -l "$ci_pg_dir/postgres.log" \
-o "-k $ci_pg_dir -c listen_addresses='' -c unix_socket_permissions=0700" -w start >/dev/null
pg_exec "$pg_bin/createdb" -h "$ci_pg_dir" smirk_ci
export TEST_DATABASE_URL="postgresql:///smirk_ci?host=$ci_pg_dir&user=$pg_user"
# A failing or missing DB is an error; tests must not quietly take their no-DB path.
pg_exec "$pg_bin/psql" -h "$ci_pg_dir" -d smirk_ci -Atc 'SELECT 1' | grep -qx 1
cargo test --locked --tests
cargo test --locked --doc
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""Stage a private Linux candidate with exact source and artifact provenance."""
import argparse
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import re
import shutil
import subprocess
import sys
ROOT = Path(__file__).resolve().parent.parent
spec = importlib.util.spec_from_file_location("build_source", ROOT / "tools/check-build-source.py")
source = importlib.util.module_from_spec(spec)
spec.loader.exec_module(source)
def sha256(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def elf_requirements(path):
header = Path(path).read_bytes()[:20]
if len(header) != 20 or header[:6] != b"\x7fELF\x02\x01" or header[18:20] != b"\x3e\x00":
raise source.Refusal("candidate must be a 64-bit little-endian x86_64 ELF binary")
versions = subprocess.check_output(["readelf", "--version-info", str(path)], text=True)
required = sorted(set(re.findall(r"\bGLIBC_([0-9]+(?:\.[0-9]+)+)\b", versions)),
key=lambda value: tuple(map(int, value.split("."))))
if not required:
raise source.Refusal("candidate has no readable GNU libc compatibility evidence")
if tuple(map(int, required[-1].split("."))) > (2, 36):
raise source.Refusal("candidate requires newer GNU libc than the admitted Debian 12 baseline")
return required
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
os.chdir(ROOT)
admitted = source.admit(source.source_for_checkout(True),
os.environ.get("EXPECTED_BUILD_SHA", ""), require_wrapper=True)
binary = ROOT / "target/x86_64-unknown-linux-gnu/release/smirk-backend-core"
required = elf_requirements(binary)
rustc = subprocess.check_output(["rustc", "--version"], text=True).strip()
if not rustc.startswith("rustc 1.98.0 "):
raise source.Refusal("candidate compiler differs from the reviewed Rust 1.98.0 pin")
args.output.mkdir(mode=0o700, parents=False, exist_ok=False)
staged = args.output / "smirk-backend-core"
shutil.copyfile(binary, staged)
staged.chmod(0o755)
manifest = {
"schema_version": 1,
"product": "smirk-backend-core",
"publication": "private_candidate_only",
**admitted,
"canonical_repository": "https://github.com/Such-Software/smirk-backend-core",
"build_repository": "Builds/smirk-backend-core",
"workflow_path": ".gitea/workflows/backend-build.yml",
"workflow_sha256": sha256(ROOT / ".gitea/workflows/backend-build.yml"),
"cargo_lock_sha256": sha256(ROOT / "Cargo.lock"),
"rust_toolchain_sha256": sha256(ROOT / "rust-toolchain.toml"),
"rustc": rustc,
"target": "x86_64-unknown-linux-gnu",
"glibc_versions": required,
"artifact": {"name": staged.name, "sha256": sha256(staged), "size": staged.stat().st_size},
}
(args.output / "manifest.json").write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
print(f"Staged private candidate for {admitted['source_commit']}; publication requires separate admission.")
if __name__ == "__main__":
try:
main()
except source.Refusal as error:
sys.exit(f"Candidate refused: {error}")
except (OSError, subprocess.CalledProcessError):
sys.exit("Candidate refused: required build output, compiler, or ELF evidence is unavailable")
+134
View File
@@ -0,0 +1,134 @@
"""Fundless Git fixtures prove source admission and binary compatibility guards."""
import importlib.util
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
from unittest.mock import patch
TOOLS = Path(__file__).resolve().parents[1]
def load(name, path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
source = load("source", TOOLS / "check-build-source.py")
stage = load("stage", TOOLS / "stage-backend-candidate.py")
class Admission(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix="smirk-git-admission-")
self.previous = Path.cwd()
os.chdir(self.temp.name)
self.git("init", "-q")
self.git("config", "user.name", "Fundless fixture")
self.git("config", "user.email", "fixture@example.invalid")
Path("source.txt").write_text("baseline\n")
self.git("add", ".")
self.git("commit", "-qm", "baseline")
self.base = self.git("rev-parse", "HEAD")
Path("source.txt").write_text("candidate\n")
self.git("commit", "-qam", "candidate")
self.candidate = self.git("rev-parse", "HEAD")
def tearDown(self):
os.chdir(self.previous)
self.temp.cleanup()
def git(self, *args, input=None):
return subprocess.check_output(["git", *args], input=input, text=True,
stderr=subprocess.PIPE).strip()
def wrapper(self, second=None, tree=None):
tree = tree or self.git("rev-parse", self.candidate + "^{tree}")
value = self.git("commit-tree", tree, "-p", self.base, "-p", second or self.candidate,
input="wrapper\n")
self.git("reset", "--hard", value)
return value
def test_canonical_and_tree_identical_wrapper_admitted(self):
self.assertEqual(source.admit(self.candidate)["build_commit"], self.candidate)
wrapper = self.wrapper()
admitted = source.admit(self.candidate, wrapper)
self.assertEqual(admitted["source_commit"], self.candidate)
self.assertEqual(admitted["source_tree"], self.git("rev-parse", "HEAD^{tree}"))
def test_release_requires_wrapper_and_derives_its_source(self):
with self.assertRaises(source.Refusal):
source.source_for_checkout(True)
with self.assertRaises(source.Refusal):
source.admit(self.candidate, self.candidate, require_wrapper=True)
wrapper = self.wrapper()
self.assertEqual(source.source_for_checkout(True), self.candidate)
self.assertEqual(source.admit(self.candidate, wrapper, require_wrapper=True)["build_commit"], wrapper)
def test_moving_dispatch_head_refused(self):
with self.assertRaises(source.Refusal):
source.admit(self.candidate, self.base)
def test_tree_change_refused(self):
self.wrapper(tree=self.git("rev-parse", self.base + "^{tree}"))
with self.assertRaises(source.Refusal):
source.admit(self.candidate)
def test_tree_identity_without_source_parent_refused(self):
tree = self.git("rev-parse", self.candidate + "^{tree}")
unrelated = self.git("commit-tree", tree, "-p", self.base, input="unrelated\n")
self.wrapper(second=unrelated)
with self.assertRaises(source.Refusal):
source.admit(self.candidate)
def test_dirty_surface_and_missing_pin_refused(self):
Path("unknown.txt").write_text("unreviewed\n")
with self.assertRaises(source.Refusal):
source.admit(self.candidate)
with self.assertRaises(source.Refusal):
source.admit("")
def test_dispatch_missing_head_or_wrong_repository_refused(self):
with patch.dict(os.environ, {"GITHUB_REPOSITORY": "Builds/smirk-backend-core",
"GITHUB_EVENT_NAME": "workflow_dispatch"}, clear=True):
with self.assertRaises(source.Refusal):
source.main()
with patch.dict(os.environ, {"GITHUB_REPOSITORY": "unreviewed/repository"}, clear=True):
with self.assertRaises(source.Refusal):
source.main()
class BinaryCompatibility(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix="smirk-elf-fixture-")
self.binary = Path(self.temp.name) / "binary"
self.binary.write_bytes(b"\x7fELF\x02\x01" + bytes(12) + b"\x3e\x00")
def tearDown(self):
self.temp.cleanup()
def test_compatible_versions_recorded_in_numeric_order(self):
with patch.object(subprocess, "check_output", return_value="GLIBC_2.3 GLIBC_2.36 GLIBC_2.9"):
result = stage.elf_requirements(self.binary)
self.assertEqual(result[-1], "2.36")
self.assertIn("2.9", result)
def test_incompatible_or_unknown_libc_refused(self):
for output in ("GLIBC_2.38", "unreadable"):
with self.subTest(output=output), patch.object(subprocess, "check_output", return_value=output):
with self.assertRaises(stage.source.Refusal):
stage.elf_requirements(self.binary)
def test_wrong_binary_format_refused_before_tool_invocation(self):
self.binary.write_bytes(b"not ELF")
with patch.object(subprocess, "check_output") as probe:
with self.assertRaises(stage.source.Refusal):
stage.elf_requirements(self.binary)
probe.assert_not_called()
if __name__ == "__main__":
unittest.main()