94 lines
2.7 KiB
Python
94 lines
2.7 KiB
Python
"""The security scanner must fail closed when its dependency audit cannot run."""
|
|
|
|
import json
|
|
import subprocess
|
|
import urllib.error
|
|
|
|
from app.supporting_scripts import security_scan
|
|
|
|
|
|
def _result(returncode, stdout='', stderr=''):
|
|
return subprocess.CompletedProcess([], returncode, stdout=stdout, stderr=stderr)
|
|
|
|
|
|
def test_debug_mode_fails_the_environment_check(monkeypatch):
|
|
monkeypatch.setenv('SECRET_KEY', 'x' * 32)
|
|
monkeypatch.setenv('DATABASE_URL', 'sqlite:///:memory:')
|
|
monkeypatch.setenv('FLASK_DEBUG', 'true')
|
|
|
|
assert security_scan.check_environment() is False
|
|
|
|
|
|
def test_a_missing_database_url_fails_the_environment_check(monkeypatch):
|
|
monkeypatch.setenv('SECRET_KEY', 'x' * 32)
|
|
monkeypatch.delenv('DATABASE_URL', raising=False)
|
|
monkeypatch.setenv('FLASK_DEBUG', 'false')
|
|
|
|
assert security_scan.check_environment() is False
|
|
|
|
|
|
def test_an_unreachable_http_target_cannot_report_success(monkeypatch):
|
|
def unreachable(*args, **kwargs):
|
|
raise urllib.error.URLError('connection refused')
|
|
|
|
monkeypatch.setattr(security_scan.urllib.request, 'urlopen', unreachable)
|
|
|
|
assert security_scan.check_https_headers('https://example.test') is False
|
|
|
|
|
|
def test_a_clean_dependency_audit_passes(monkeypatch):
|
|
command = []
|
|
|
|
def clean_audit(args, **kwargs):
|
|
command.extend(args)
|
|
return _result(0)
|
|
|
|
monkeypatch.setattr(
|
|
security_scan.subprocess,
|
|
'run',
|
|
clean_audit,
|
|
)
|
|
|
|
assert security_scan.check_dependencies() is True
|
|
requirement_flag = command.index('--requirement')
|
|
assert command[requirement_flag + 1] == str(security_scan.REQUIREMENTS_FILE)
|
|
|
|
|
|
def test_reported_vulnerabilities_fail_the_scan(monkeypatch):
|
|
report = {
|
|
'dependencies': [
|
|
{
|
|
'name': 'example',
|
|
'version': '1.0',
|
|
'vulns': [{'id': 'PYSEC-TEST'}],
|
|
}
|
|
]
|
|
}
|
|
monkeypatch.setattr(
|
|
security_scan.subprocess,
|
|
'run',
|
|
lambda *args, **kwargs: _result(1, stdout=json.dumps(report)),
|
|
)
|
|
|
|
assert security_scan.check_dependencies() is False
|
|
|
|
|
|
def test_an_audit_that_crashes_cannot_report_success(monkeypatch, capsys):
|
|
monkeypatch.setattr(
|
|
security_scan.subprocess,
|
|
'run',
|
|
lambda *args, **kwargs: _result(1, stderr='audit unavailable'),
|
|
)
|
|
|
|
assert security_scan.check_dependencies() is False
|
|
assert '[FAIL] audit unavailable' in capsys.readouterr().out
|
|
|
|
|
|
def test_an_audit_timeout_cannot_report_success(monkeypatch):
|
|
def timeout(*args, **kwargs):
|
|
raise subprocess.TimeoutExpired('pip-audit', 60)
|
|
|
|
monkeypatch.setattr(security_scan.subprocess, 'run', timeout)
|
|
|
|
assert security_scan.check_dependencies() is False
|