95 lines
4.6 KiB
Python
95 lines
4.6 KiB
Python
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tomllib
|
|
from types import SimpleNamespace
|
|
|
|
from viano_bug_analysis import deployment
|
|
from viano_bug_analysis.api.config import APIConfig, Project, Client
|
|
from viano_bug_analysis.api.sessions import Sessions
|
|
from viano_bug_analysis.worker.config import WorkerConfig
|
|
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def installer():
|
|
spec=importlib.util.spec_from_file_location('linux_install',ROOT/'deploy/install.py')
|
|
module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def test_install_plan_and_templates():
|
|
result=subprocess.run([sys.executable,str(ROOT/'deploy/install.py'),'--dry-run'],capture_output=True,text=True,check=True)
|
|
assert json.loads(result.stdout)['services_started'] is False
|
|
files=installer().templates()
|
|
for name,text in files.items():
|
|
if name.endswith('.toml'):tomllib.loads(text)
|
|
project=tomllib.loads(files['project.toml'])
|
|
assert project['database']['password_env']=='VIANO_DB_PASSWORD'
|
|
assert 'password_file' not in project['database']
|
|
assert project['source']['commit']=='0'*40
|
|
assert tomllib.loads(files['api.toml'])['auth']['users_database'].startswith('/etc/')
|
|
|
|
|
|
def test_api_ready_and_missing_machine_credentials(tmp_path,monkeypatch):
|
|
config=APIConfig(tmp_path,(Project('p','wow','vcore'),),())
|
|
monkeypatch.setattr(deployment.APIConfig,'load',lambda path:config)
|
|
assert deployment.check('api','unused')['status']=='NOT_READY'
|
|
Sessions(config).users.manage('create_user','alice','example password')
|
|
assert deployment.check('api','unused')['status']=='READY'
|
|
config=APIConfig(tmp_path,config.projects,(Client('m','VBA_TEST_MISSING',('p',)),))
|
|
monkeypatch.delenv('VBA_TEST_MISSING',raising=False)
|
|
assert deployment.check('api','unused')['code']=='DEPLOY_MACHINE_CREDENTIALS'
|
|
|
|
|
|
def test_worker_checks_only_read_dependencies(tmp_path,monkeypatch):
|
|
config=APIConfig(tmp_path,(Project('p','wow','vcore'),),())
|
|
monkeypatch.setattr(deployment.WorkerConfig,'load',lambda path:SimpleNamespace(intake=config,min_free_bytes=1))
|
|
calls=[]
|
|
research=SimpleNamespace(source=SimpleNamespace(inventory=lambda:calls.append('git')),
|
|
database=SimpleNamespace(tables=['creature'],query=lambda query:calls.append(query)))
|
|
def loader(project):return object(),{'project_research':research},'hash'
|
|
result=deployment.check('worker','unused',loader=loader)
|
|
assert result['status']=='READY' and result['model_requests']==0 and not result['cloud_api_tested']
|
|
assert calls==['git',{'kind':'database.schema','table':'creature'}]
|
|
calls.clear()
|
|
assert deployment.check('worker','unused',offline=True,loader=loader)['status']=='CONFIG_READY'
|
|
assert calls==[]
|
|
def failing(project):raise RuntimeError('secret-value')
|
|
assert 'secret-value' not in json.dumps(deployment.check('worker','unused',loader=failing))
|
|
|
|
|
|
def test_units_keep_secrets_separate_and_code_readonly():
|
|
for role in ('api','worker'):
|
|
unit=(ROOT/'deploy'/f'viano-bug-analysis-{role}.service').read_text()
|
|
assert f'EnvironmentFile=/etc/viano-bug-analysis/{role}.env' in unit
|
|
assert f'deployment check --role {role}' in unit
|
|
assert 'ProtectSystem=strict' in unit
|
|
assert 'ReadWritePaths=/var/lib/viano-bug-analysis' in unit
|
|
assert 'Restart=always' in unit and '--once' not in unit
|
|
|
|
|
|
def test_installed_config_references_resolve(tmp_path):
|
|
for name,text in installer().templates().items():
|
|
(tmp_path/name).write_text(text,encoding='utf-8')
|
|
config=WorkerConfig.load(tmp_path/'worker.toml')
|
|
assert config.intake.projects[0].planning_mode=='joint'
|
|
assert all(path.is_file() for path in config.intake.projects[0].settings.values())
|
|
|
|
|
|
def test_https_proxy_preserves_secure_login_cookie(tmp_path):
|
|
from starlette.testclient import TestClient
|
|
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
|
from viano_bug_analysis.api.app import create_app
|
|
config=APIConfig(tmp_path,(Project('p','wow','vcore'),),())
|
|
app=create_app(config)
|
|
app.state.sessions.users.manage('create_user','alice','example password')
|
|
proxied=ProxyHeadersMiddleware(app,trusted_hosts=['127.0.0.1'])
|
|
with TestClient(proxied,client=('127.0.0.1',1234)) as client:
|
|
result=client.post('/v1/auth/login',headers={'X-Forwarded-Proto':'https','Origin':'https://testserver'},
|
|
json={'username':'alice','password':'example password'})
|
|
assert result.status_code==200
|
|
assert 'secure' in result.headers['set-cookie'].lower()
|