Skip to content

Commit

Permalink
Add script to check newly added packages against buildinfo files
Browse files Browse the repository at this point in the history
buildinfo files contain package checksums in a machine-readable
format, so script checking newly added packages against those.

This will be added to CI for securedrop-apt-test and securedrop-apt-prod.

The main iffy part of this is how it compares against "origin/main",
but I think for PRs it'll mostly do the right thing. We only check new
packages because old ones don't have buildinfo published. Maybe once
we no longer have any legacy cases left, we just check everything in
the repository.

Likely there are more checks that could be added, but this is a start.

Refs <freedomofpress/securedrop#6356>.
  • Loading branch information
legoktm committed Mar 10, 2023
1 parent 99d1d95 commit 0158726
Showing 1 changed file with 89 additions and 0 deletions.
89 changes: 89 additions & 0 deletions scripts/check-buildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Check newly added packages against their buildinfo files
Example:
./check-buildinfo package.deb package.buildinfo
"""
import argparse
import hashlib
import subprocess
import sys
from pathlib import Path
from typing import List

from debian.deb822 import BuildInfo


def lookup_buildinfos(buildinfos: Path) -> dict:
"""Extract checksums out of every buildinfo file we can find"""
data = {}
for path in buildinfos.glob("**/*.buildinfo"):
info = BuildInfo(path.read_text())
for details in info['Checksums-Sha256']:
if details['name'].endswith('.deb'):
data[details['name']] = details['sha256']
return data


def check_package(package: Path, buildinfos: dict) -> bool:
"""Verify the package's checksum matches buildinfo"""
try:
expected = buildinfos[str(package.name)]
except IndexError:
print(f"ERROR: Unable to find buildinfo containing {package.name}")
return False
actual = hashlib.sha256(package.read_bytes()).hexdigest()
if actual == expected:
print(f"OK: got expected checksum {actual} for {package.name}")
return True
else:
print(f"ERROR: package is {actual}, buildinfo has {expected} for {package.name}")
return False


def added_files(against="origin/main") -> List[Path]:
"""Get list of added files compared to main"""
added = []
output = subprocess.check_output([
"git", "log",
# Only list added files
"--diff-filter=A",
# Set our terminal width to be huge so it doesn't truncate
"--stat=999999",
# Output nothing else
"--pretty=",
f"{against}..HEAD"
], text=True)
for line in output.splitlines():
if "|" not in line:
continue
path = Path(line.split("|", 1)[0].strip())
if path.exists():
# Wasn't deleted in an intermediate commit
added.append(path)
added.sort(key=lambda x: x.name)
return added


def main():
parser = argparse.ArgumentParser(
description="Check packages against their buildinfo files"
)
parser.add_argument("buildinfos", type=Path, help="Folder with buildinfo files")
args = parser.parse_args()
buildinfos = lookup_buildinfos(args.buildinfos)
status = 0
added = added_files()
if not added:
print("No new packages detected.")
sys.exit(0)
for package in added:
if not check_package(package, buildinfos):
status = 1
sys.exit(status)


if __name__ == '__main__':
main()

0 comments on commit 0158726

Please sign in to comment.