cc/tests/test_materials.py
원본 내용을 읽기 전용으로 표시합니다.
import hashlibimport jsonfrom pathlib import Pathimport pytestfrom startup_app.app import create_appfrom tools.publish_materials import publish@pytest.fixturedef materials_client(tmp_path):files = tmp_path / 'public' / 'files'files.mkdir(parents=True)content = [('example.py', 'code', '<script>alert("x")</script>\nprint("안녕")'),('data.csv', 'csv', '이름,값\n<script>,2\n'), ('map.html', 'map', '<html>map</html>'),('plot.png', 'image', 'image')]entries = []for i, (name, kind, text) in enumerate(content):(files / name).write_text(text, encoding='utf-8')entries.append({'id': str(i) * 20, 'path': name, 'kind': kind, 'size': len(text.encode()), 'sha256': 'example', 'rows': 1, 'columns': 2})(tmp_path / 'outside.txt').write_text('not-public', encoding='utf-8')entries.append({'id': 'f' * 20, 'path': '../../outside.txt', 'kind': 'text', 'size': 10, 'sha256': 'example'})(tmp_path / 'public' / 'manifest.json').write_text(json.dumps({'created': 'today', 'files': entries}), encoding='utf-8')app = create_app()app.config['MATERIALS_DIR'] = tmp_path / 'public'return app.test_client()def test_index_search_and_no_arbitrary_directory(materials_client):assert 'example.py' in materials_client.get('/materials/').textfiltered = materials_client.get('/materials/?q=example').textassert 'example.py' in filtered and 'plot.png' not in filteredassert materials_client.get('/materials/?folder=../../').status_code == 404assert materials_client.get('/materials/download/.env').status_code == 404assert materials_client.get('/materials/download/' + 'f' * 20).status_code == 404def test_source_and_csv_are_escaped(materials_client):source = materials_client.get('/materials/file/' + '0' * 20)assert '<script>' in source.text and '<script>alert' not in source.textdata = materials_client.get('/materials/file/' + '1' * 20)assert '<script>' in data.text and '<script>' not in data.textdef test_download_and_preview_isolation(materials_client):download = materials_client.get('/materials/download/' + '0' * 20)assert download.status_code == 200 and 'attachment' in download.headers['Content-Disposition']frame = materials_client.get('/materials/file/' + '2' * 20)assert 'sandbox="allow-scripts"' in frame.textpreview = materials_client.get('/materials/preview/' + '2' * 20)assert preview.status_code == 200 and 'sandbox allow-scripts;' in preview.headers['Content-Security-Policy']assert 'allow-same-origin' not in preview.headers['Content-Security-Policy']assert materials_client.get('/materials/preview/' + '0' * 20).status_code == 404assert materials_client.get('/materials/image/' + '0' * 20).status_code == 404assert 'frame-src' in frame.headers['Content-Security-Policy']def test_export_excludes_private_folders_and_stops_on_secret(tmp_path):root, output = tmp_path / 'project', tmp_path / 'public'for folder in ('data', 'output', 'cc/startup_app', 'cc/tests', 'cc/tools', 'cc/.venv'):(root / folder).mkdir(parents=True)(root / 'app.py').write_text('print("hello")', encoding='utf-8')(root / 'cc' / '.venv' / 'private.py').write_text('private', encoding='utf-8')(root / '.env').write_text('private', encoding='utf-8')for name in ('requirements.txt', 'requirements-dev.txt'):(root / 'cc' / name).write_text('package', encoding='utf-8')publish(root, output)manifest = json.loads((output / 'manifest.json').read_text(encoding='utf-8'))assert len(manifest['files']) == 3assert all('.env' not in f['path'] and '.venv' not in f['path'] for f in manifest['files'])for entry in manifest['files']:assert hashlib.sha256((output / 'files' / entry['path']).read_bytes()).hexdigest() == entry['sha256'](root / 'app.py').write_text('token = "' + 'sk-' + 'x' * 40 + '"', encoding='utf-8')with pytest.raises(ValueError, match='공개 중단'):publish(root, output)
파일 확인 정보
SHA-256: f815c2432d6cb0b66fdecc1a9d6d7fa17440e643eb3b8612c45af7544f5efc1a