65 lines
2.9 KiB
Python
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()
|