#!/usr/bin/env python3 """Cross-shell safeguards for real Compose volume names and existing bind paths.""" import json import os from pathlib import Path import shutil import subprocess import tempfile source = Path(__file__).resolve().parent.parent with tempfile.TemporaryDirectory(prefix='easyai-storage-check-') as temporary: root = Path(temporary) (root / 'upload').mkdir() (root / 'compose.yml').write_text('''name: fixture-project services: mongo: container_name: fixture-mongo image: mongo:7 volumes: [database:/data/db] easyai-server: container_name: fixture-server image: alpine:3 volumes: [./upload:/app/upload] volumes: database: name: existing-database ''') configuration = subprocess.check_output(['docker','compose','config','--format','json'], cwd=root, text=True) (root / 'config.json').write_text(configuration) binaries = root / 'bin' binaries.mkdir() docker = binaries / 'docker' docker.write_text('''#!/usr/bin/env python3 import json,os,sys from pathlib import Path args=sys.argv[1:] if args[:2]==['compose','config']: print(Path('config.json').read_text());sys.exit(0) if args[:1]==['info']:sys.exit(0) if args[:2]==['container','inspect']: project='another-project' if os.environ['STORAGE_CASE']=='wrong-project' else 'fixture-project' mount={'Type':'volume','Name':'old-database' if os.environ['STORAGE_CASE']=='changed-volume' else 'existing-database','Destination':'/data/db'} if args[-1]=='fixture-server':mount={'Type':'bind','Source':str(Path('upload').resolve()),'Destination':'/app/upload'} print(json.dumps([{'Config':{'Labels':{'com.docker.compose.project':project}},'Mounts':[mount]}]));sys.exit(0) sys.exit(1) ''') docker.chmod(0o755) script = root / 'check.ps1' script.write_text('param($Runtime)\n$ErrorActionPreference="Stop"\n. $Runtime\n$selection = @($env:STORAGE_SELECTED -split " " | Where-Object { $_ })\nTest-DeploymentStorage -ComposeCommand @("docker","compose") -Services $selection\n') for case, selected, success in [('same-storage','',True),('wrong-project','',False),('changed-volume','',False),('changed-volume','easyai-server',True),('missing-bind','',False)]: if case == 'missing-bind': (root / 'upload').rmdir() env = {**os.environ, 'PATH':str(binaries)+os.pathsep+os.environ['PATH'], 'STORAGE_CASE':case, 'STORAGE_SELECTED':selected} commands = [(['python3',str(source/'scripts/check-deployment-storage.py'),'--services',*selected.split()], configuration), (['pwsh','-NoProfile','-NonInteractive','-File',str(script),str(source/'scripts/DeploymentRuntime.ps1')], None)] for command, stdin in commands: result = subprocess.run(command, input=stdin, cwd=root, env=env, capture_output=True, text=True, timeout=90) assert (result.returncode == 0) == success, (case, selected, result.stdout, result.stderr) print(case + '/' + (selected or 'all') + ': passed in Python/Bash and PowerShell')