"""Reject unsafe release coordinates and keep secrets out of public release files.""" from dataclasses import replace from pathlib import Path import tempfile import unittest from dotenv import dotenv_values from deploy.gray_config import GrayConfig, write_release class GrayConfigTests(unittest.TestCase): def settings(self): return { 'PUBLIC_ORIGIN': 'https://chat.example.com', 'HOST_PORT': '29013', 'GRAY_DEPLOY_DIR': '/data/services/gray-logistics-chat', 'GRAY_PROXY_CONF_DIR': '/etc/nginx/conf.d', 'GRAY_TLS_CERT_FILE': '/etc/ssl/example/fullchain.pem', 'GRAY_TLS_KEY_FILE': '/etc/ssl/example/privkey.pem', 'SOURCE_COMMIT': 'a' * 40, 'BUILD_NUMBER': '7', 'CHAT_IMAGE': 'baiyue-logistics-chat-gray:' + 'a' * 12 + '-b7', 'CHAT_IMAGE_ID': 'sha256:' + 'b' * 64, 'CERTBOT_IMAGE_ID': 'sha256:' + 'c' * 64, } def test_unsafe_origins_paths_and_mismatched_images_are_rejected(self): cases = ( ('PUBLIC_ORIGIN', 'http://chat.example.com'), ('PUBLIC_ORIGIN', 'https://user:password@chat.example.com'), ('PUBLIC_ORIGIN', 'https://chat.example.com/admin'), ('GRAY_DEPLOY_DIR', '/data/services/../gray-logistics-chat'), ('GRAY_DEPLOY_DIR', '/data/shared-services'), ('GRAY_PROXY_CONF_DIR', '/etc/nginx; echo unsafe'), ('HOST_PORT', '443'), ('CHAT_IMAGE', 'another-service:latest'), ('SOURCE_COMMIT', 'main'), ('CHAT_IMAGE_ID', 'unverified-image'), ) for key, value in cases: with self.subTest(setting=key, value=value): settings = self.settings() settings[key] = value with self.assertRaises(ValueError): GrayConfig.from_environment(settings) def test_data_paths_remain_stable_across_releases_and_credentials_stay_separate(self): config = GrayConfig.from_environment(self.settings()) updated = replace(config, release=config.root + '/releases/next-build') for release in (config, updated): self.assertIn('CHAT_DATA_DIR=' + config.root + '/data\n', release.release_environment()) self.assertIn('CHAT_LOG_DIR=' + config.root + '/logs\n', release.release_environment()) with tempfile.TemporaryDirectory() as directory: path = Path(directory) / 'release' key = "fixture-${literal}-don't-expand" write_release(path, config, key) self.assertEqual(dotenv_values(path / 'runtime.env', interpolate=False)['DEEPSEEK_API_KEY'], key) for name in ('release.env', 'site.conf', 'compose.yml', 'activate.sh'): self.assertNotIn(key, (path / name).read_text(encoding='utf-8')) self.assertIn('auth_basic_user_file', (path / 'site.conf').read_text(encoding='utf-8')) def test_invalid_model_credential_does_not_create_a_release_directory(self): config = GrayConfig.from_environment(self.settings()) with tempfile.TemporaryDirectory() as directory: path = Path(directory) / 'release' with self.assertRaises(ValueError): write_release(path, config, 'fixture-key\nANOTHER_SETTING=bad') self.assertFalse(path.exists()) if __name__ == '__main__': unittest.main()