105 lines
5.9 KiB
Python
105 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Pure manifest preparation tests, not installed-manager acceptance."""
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from fixture_manifests import manifests
|
|
|
|
ROOT = Path(__file__).resolve().parent
|
|
|
|
|
|
class FixtureManifests(unittest.TestCase):
|
|
def args(self):
|
|
return ['a'*64,'b'*64,'c'*64,'d'*64,'/var/lib/archipelago/fixture-podsteadr-test']
|
|
|
|
def render(self):
|
|
return manifests(*self.args())
|
|
|
|
def test_requires_exact_images_and_explicit_public_service_key(self):
|
|
for index, invalid in ((0,'app:latest'),(1,'abc123'),(2,''),(3,''),(3,'npub1invalid'),(3,'d'*64+'\nOTHER=value')):
|
|
args = self.args(); args[index] = invalid
|
|
with self.subTest(index=index, invalid=invalid), self.assertRaises(ValueError):
|
|
manifests(*args)
|
|
|
|
def test_live_paths_and_traversal_refused(self):
|
|
for value in ('/var/lib/archipelago/podsteadr','/var/lib/archipelago/fixture-podsteadr-test/../live','relative','/tmp/other'):
|
|
args = self.args(); args[4] = value
|
|
with self.subTest(value=value), self.assertRaises(ValueError): manifests(*args)
|
|
|
|
def test_all_three_pin_images_nonroot_data_and_loopback_ports(self):
|
|
rendered = self.render()
|
|
self.assertEqual(set(rendered),{'podsteadr','podsteadr-mediamtx','podsteadr-blossom'})
|
|
for document in rendered.values():
|
|
app = document['app']
|
|
self.assertEqual(app['container']['pull_policy'],'never')
|
|
self.assertTrue(app['container']['image'].startswith('sha256:'))
|
|
self.assertEqual(app['container']['data_uid'],'1000:1000')
|
|
self.assertNotIn('user',app['container'], 'No unsupported runtime-user field')
|
|
self.assertEqual(app['security']['capabilities'],[])
|
|
self.assertTrue(app['security']['readonly_root'])
|
|
self.assertTrue(app['security']['no_new_privileges'])
|
|
self.assertNotIn('hooks',app)
|
|
self.assertNotIn('secret_env',app['container'])
|
|
self.assertNotIn('generated_secrets',app['container'])
|
|
self.assertTrue(all(port['bind']=='127.0.0.1' for port in app['ports']))
|
|
self.assertTrue(all(not file['overwrite'] for file in app.get('files',[])))
|
|
|
|
def test_native_admin_and_distinct_service_key_bindings(self):
|
|
docs = self.render()
|
|
app = docs['podsteadr']['app']; blossom = docs['podsteadr-blossom']['app']
|
|
self.assertEqual(app['container']['derived_env'],[{'key':'PODSTEADR_ADMIN_PUBKEYS','template':'{{NODE_IDENTITY_PUBKEYS}}'}])
|
|
self.assertEqual(blossom['container']['derived_env'],[{'key':'ARCHY_BLOSSOM_PUBKEYS','template':'{{NODE_IDENTITY_PUBKEYS}},'+'d'*64}])
|
|
self.assertNotIn('server-nostr-key',json.dumps(docs))
|
|
self.assertIn('NOSTR_RELAYS=',app['environment'])
|
|
self.assertIn('CASHU_MINT_URL_DEFAULT=http://127.0.0.1:9996',app['environment'])
|
|
|
|
def test_matching_paths_recording_permissions_and_no_root_copy_hook(self):
|
|
docs = self.render()
|
|
volumes = {key:{v['target']:v for v in doc['app']['volumes']} for key,doc in docs.items()}
|
|
self.assertEqual(volumes['podsteadr']['/recordings']['options'],['ro'])
|
|
self.assertEqual(volumes['podsteadr-mediamtx']['/recordings']['options'],['rw'])
|
|
self.assertEqual(volumes['podsteadr']['/recordings']['source'],volumes['podsteadr-mediamtx']['/recordings']['source'])
|
|
blossom = volumes['podsteadr-blossom']
|
|
self.assertEqual(blossom['/config/config.json']['options'],['ro'])
|
|
self.assertEqual(blossom['/bridge']['options'],['ro'])
|
|
self.assertNotIn('/app/data',blossom)
|
|
config = docs['podsteadr-mediamtx']['app']['files'][0]['content']
|
|
self.assertIn('authHTTPAddress: http://podsteadr-app:8095/api/mediamtx/auth',config)
|
|
self.assertIn('recordPath: /recordings/',config)
|
|
self.assertNotIn('runOn',config)
|
|
|
|
def test_canonical_parser_samples_match_generator_exactly(self):
|
|
for app_id, expected in self.render().items():
|
|
actual = json.loads((ROOT/'manifest-samples'/app_id/'manifest.yml').read_text())
|
|
self.assertEqual(actual, expected)
|
|
|
|
def test_large_upload_is_explicit_and_does_not_change_other_services(self):
|
|
baseline = self.render()
|
|
large = manifests(*self.args(), large_upload_candidate=True)
|
|
self.assertEqual(baseline['podsteadr-blossom']['app']['environment'], [])
|
|
self.assertEqual(large['podsteadr-blossom']['app']['environment'], ['ARCHY_BLOSSOM_MAX_UPLOAD_BYTES=2147483648'])
|
|
self.assertEqual(large['podsteadr-blossom']['app']['version'], '6.4.1-fixture.large1')
|
|
for service in ('podsteadr', 'podsteadr-mediamtx'):
|
|
self.assertEqual(large[service], baseline[service])
|
|
self.assertEqual(large['podsteadr-blossom']['app']['container'], baseline['podsteadr-blossom']['app']['container'])
|
|
|
|
def test_cli_refuses_existing_output_and_leaves_it_untouched(self):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
args = self.args()
|
|
command = [sys.executable,str(ROOT/'fixture_manifests.py')]
|
|
for name,value in zip(('app-image','mtx-image','blossom-image','server-pubkey','data-root'),args): command += ['--'+name,value]
|
|
command += ['--output',directory]
|
|
first = subprocess.run(command,capture_output=True,text=True)
|
|
self.assertEqual(first.returncode,0,first.stderr)
|
|
before = {str(p.relative_to(directory)):p.read_bytes() for p in Path(directory).rglob('manifest.yml')}
|
|
self.assertEqual(len(before),3)
|
|
second = subprocess.run(command,capture_output=True,text=True)
|
|
self.assertNotEqual(second.returncode,0)
|
|
self.assertEqual(before,{str(p.relative_to(directory)):p.read_bytes() for p in Path(directory).rglob('manifest.yml')})
|
|
|
|
|
|
if __name__ == '__main__': unittest.main()
|