Files
archy/scripts/tests/test_verified_image_pull.py

65 lines
2.9 KiB
Python

"""Subprocess gate fixtures; no real registry, runtime, cosign or release key."""
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
HELPER = Path(__file__).parents[1] / 'lib/verified-image-pull.sh'
IMAGE = 'registry.invalid/app@sha256:' + 'a' * 64
class VerifiedImagePullTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
self.root = Path(self.tmp.name)
self.key = self.root / 'cosign.pub'
self.key.write_text('subprocess fixture, not a public key')
for name, body in {
'cosign': '#!/bin/sh\nprintf "%s\\n" "$@" > "$FIXTURE_VERIFY_LOG"\nexit "${FIXTURE_VERIFY_EXIT:-0}"\n',
'podman': '#!/bin/sh\nprintf "%s\\n" "$@" > "$FIXTURE_PULL_LOG"\n',
}.items():
path = self.root / name
path.write_text(body)
path.chmod(0o700)
self.env = dict(os.environ, PATH=str(self.root) + ':/usr/bin:/bin',
ARCHIPELAGO_COSIGN_PUBKEY=str(self.key), DOCKER=str(self.root / 'podman'),
FIXTURE_VERIFY_LOG=str(self.root / 'verify'), FIXTURE_PULL_LOG=str(self.root / 'pull'))
def run_gate(self, image=IMAGE):
return subprocess.run(['/bin/bash', '-c', 'source "$1"; verified_image_pull "$2"',
'fixture', str(HELPER), image], env=self.env, capture_output=True, text=True)
def test_digest_verified_then_pulled_with_tls(self):
self.assertEqual(self.run_gate().returncode, 0)
self.assertEqual((self.root / 'pull').read_text().splitlines(), ['pull', '--tls-verify=true', IMAGE])
args = (self.root / 'verify').read_text().splitlines()
self.assertEqual(args, ['verify', '--key', str(self.key), '--insecure-ignore-tlog=true', IMAGE])
def test_missing_key_or_verifier_prevents_runtime(self):
self.key.unlink()
self.assertNotEqual(self.run_gate().returncode, 0)
self.assertFalse((self.root / 'pull').exists())
self.key.write_text('fixture')
(self.root / 'cosign').unlink()
self.env['PATH'] = str(self.root)
self.assertNotEqual(self.run_gate().returncode, 0)
self.assertFalse((self.root / 'pull').exists())
def test_verifier_rejection_prevents_runtime(self):
self.env['FIXTURE_VERIFY_EXIT'] = '1'
self.assertNotEqual(self.run_gate().returncode, 0)
self.assertFalse((self.root / 'pull').exists())
def test_mutable_empty_and_malformed_references_fail_before_verifier(self):
for image in ['', 'registry.invalid/app:latest', 'http://registry.invalid/app@sha256:' + 'a' * 64, IMAGE + ' --flag']:
with self.subTest(image=image):
self.assertNotEqual(self.run_gate(image).returncode, 0)
self.assertFalse((self.root / 'verify').exists())
self.assertFalse((self.root / 'pull').exists())
if __name__ == '__main__':
unittest.main()