Initial server source import

This commit is contained in:
sashatrask
2026-09-30 20:30:56 +03:00
commit 170dd941b9
498 changed files with 261563 additions and 0 deletions
+904
View File
@@ -0,0 +1,904 @@
import base64
import copy
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import time
import unittest
from unittest import mock
ROOT = Path(__file__).resolve().parents[1]
APP = ROOT / 'app'
sys.path.insert(0, str(APP))
import scan_execution
import scanner
import scanner_db
from lifecycle_authority import LifecycleAuthorityError
from parity_helpers import (
configured_trufflehog, native_streamed_command, normalized_bundle_evidence,
)
from result_bundle import BundleReservation, FORMAT_VERSION, ResultBundleReader
from worker_contracts import WorkerPhase, validate_phase_transition
def reservation(platform='github'):
return BundleReservation(
reservation_id=7, reservation_token='request-token', bundle_id='a' * 32,
scan_event_id='b' * 32, queue_id=11, claim_lease_token='lease-token',
declared_bytes=1024, ready_path='ready/aa/' + 'a' * 32 + '.trb',
source=platform, platform=platform, query='fixture',
target='https://example.invalid/repo',
normalized_target='https://example.invalid/repo',
)
def scan_policy():
return {
'drop_detectors': ['generic'],
'strict_git_provider_token_filter': True,
'trufflehog_stdout_max_mb': 2,
'trufflehog_stderr_max_mb': 1,
'result_bundle_max_event_bytes': 64 * 1024 * 1024,
'trufflehog_max_findings_per_target': 20000,
'trufflehog_job_memory_limit_bytes': 0,
'trufflehog_windows_job_cpu_weight': 0,
'trufflehog_windows_memory_priority': 0,
'trufflehog_diagnostic_max_lines': 100,
'trufflehog_diagnostic_max_line_chars': 1000,
'trufflehog_diagnostic_max_line_bytes': 1000,
'trufflehog_diagnostic_max_errors': 10,
'trufflehog_diagnostic_max_warnings': 10,
'trufflehog_diagnostic_max_unclassified': 5,
}
def source_reservation(platform, target, bundle_id='a' * 32, reservation_id=7):
return BundleReservation(
reservation_id=reservation_id, reservation_token='request-token',
bundle_id=bundle_id, scan_event_id='b' * 32, queue_id=11,
claim_lease_token='lease-token', declared_bytes=1024 * 1024,
ready_path=f'ready/{bundle_id[:2]}/{bundle_id}.trb',
source=platform, platform=platform, query='fixture', target=target,
normalized_target=scanner.normalize_target(target, platform),
)
def noop_git_plan():
head = 'a' * 40
return {
'version': 1, 'provider': 'github',
'repo_url': 'https://github.com/Owner/Repo.git',
'repo_path': 'Owner/Repo', 'branch': 'Feature/Main',
'ref': 'refs/heads/Feature/Main', 'head_sha': head,
'ref_source': 'explicit', 'base_sha': head, 'mode': 'noop',
'baseline_depth': 100,
}
class ScanExecutionTests(unittest.TestCase):
def test_compatibility_requires_exact_policy_and_platform(self):
value = scan_execution.ScanCompatibility(
scan_execution.PROTOCOL_VERSION, FORMAT_VERSION, 'windows-x86_64',
'a' * 64, 'b' * 64, 'c' * 64,
)
self.assertIs(scan_execution.validate_scan_compatibility(value, value), value)
for field in ('platform_tag', 'code_manifest_sha256', 'effective_config_sha256',
'detector_policy_sha256'):
changed = dict(value.as_dict())
changed[field] = 'linux-x86_64' if field == 'platform_tag' else 'd' * 64
with self.subTest(field=field), self.assertRaises(scan_execution.ScanExecutionError):
scan_execution.validate_scan_compatibility(value, changed)
def test_scan_kwargs_reject_unknown_commands_and_unbounded_timeout(self):
self.assertEqual(
scan_execution.validate_scan_kwargs('github', {'timeout_sec': 60, 'git_plan': {}}),
{'timeout_sec': 60.0, 'git_plan': {}},
)
for value in ({'timeout_sec': 60, 'command': ['calc']}, {'timeout_sec': 0}):
with self.assertRaises(scan_execution.ScanExecutionError):
scan_execution.validate_scan_kwargs('github', value)
def test_remote_assignment_deadlines_are_exact_and_immutable(self):
reservation_value = {
'remote_issued_at': '2026-09-17T00:00:00+00:00',
'remote_expires_at': '2026-09-18T00:00:00+00:00',
}
deadlines = {
'target_scan_timeout_seconds': 60,
'result_upload_body_timeout_seconds': 1800,
'assignment_ttl_seconds': 86400,
'assignment_issued_at': reservation_value['remote_issued_at'],
'assignment_deadline_at': reservation_value['remote_expires_at'],
}
self.assertEqual(
scan_execution._normalize_remote_assignment_deadlines(
deadlines, reservation_value, {'timeout_sec': 60.0},
),
deadlines,
)
invalid = []
extra = copy.deepcopy(deadlines)
extra['unknown'] = 1
invalid.append((extra, reservation_value, {'timeout_sec': 60.0}))
boolean = copy.deepcopy(deadlines)
boolean['assignment_ttl_seconds'] = True
invalid.append((boolean, reservation_value, {'timeout_sec': 60.0}))
wrong_scan = copy.deepcopy(deadlines)
wrong_scan['target_scan_timeout_seconds'] = 61
invalid.append((wrong_scan, reservation_value, {'timeout_sec': 60.0}))
wrong_interval = copy.deepcopy(deadlines)
wrong_interval['assignment_ttl_seconds'] = 86399
invalid.append((wrong_interval, reservation_value, {'timeout_sec': 60.0}))
changed_reservation = copy.deepcopy(reservation_value)
changed_reservation['remote_expires_at'] = '2026-09-18T00:00:01+00:00'
invalid.append((deadlines, changed_reservation, {'timeout_sec': 60.0}))
noncanonical = copy.deepcopy(deadlines)
noncanonical['assignment_issued_at'] = '2026-09-17T00:00:00Z'
noncanonical_reservation = copy.deepcopy(reservation_value)
noncanonical_reservation['remote_issued_at'] = noncanonical[
'assignment_issued_at'
]
invalid.append((noncanonical, noncanonical_reservation, {'timeout_sec': 60.0}))
for value, reserved, scan_kwargs in invalid:
with self.subTest(value=value), self.assertRaises(
scan_execution.ScanExecutionError,
):
scan_execution._normalize_remote_assignment_deadlines(
value, reserved, scan_kwargs,
)
def test_every_remote_scan_policy_field_changes_effective_identity(self):
kwargs = {'timeout_sec': 60, 'trufflehog_config': '@package/detector_policy'}
event = {'timeout_sec': 60.0, 'trufflehog_config': '@package/detector_policy'}
limits = {'candidate_max_items': 20, 'candidate_max_bytes': 4096}
policy = scan_policy()
original, _ = scan_execution.remote_execution_identity(
'github', kwargs, event, {}, limits, policy,
)
for name, value in policy.items():
changed = dict(policy)
if name == 'drop_detectors':
changed[name] = ['other']
elif isinstance(value, bool):
changed[name] = not value
else:
changed[name] = value + 1
with self.subTest(name=name):
updated, _ = scan_execution.remote_execution_identity(
'github', kwargs, event, {}, limits, changed,
)
self.assertNotEqual(updated, original)
def test_remote_scan_policy_overrides_inherited_process_settings(self):
findings = [
{'DetectorName': 'Generic', 'Raw': 'fixture'},
{'DetectorName': 'GitHub', 'Raw': 'not-a-token', 'Verified': False},
]
with mock.patch.dict(os.environ, {
'TRUFFLEHOG_STDOUT_MAX_MB': '999',
'TRUFFLEHOG_STDERR_MAX_MB': '999',
'TRUFFLEHOG_MAX_FINDINGS_PER_TARGET': '999999',
}):
with scanner.client_scan_execution_policy(scan_policy()):
kept, dropped, _ = scanner.filter_dropped_detectors(findings)
self.assertEqual(dropped, 1)
kept, noisy = scanner.filter_noisy_findings(kept)
self.assertEqual((kept, noisy), ([], 1))
self.assertEqual(
scanner.command_output_limits(), (2 * 1024 * 1024, 1024 * 1024),
)
self.assertEqual(scanner._trufflehog_diagnostic_limits(), {
'lines': 100, 'line_chars': 1000, 'line_bytes': 1000,
'errors': 10, 'warnings': 10, 'unclassified': 5,
})
def test_queue_disposition_preserves_existing_retry_classes(self):
policy = scan_execution.QueueDispositionPolicy(
target_retry_max_attempts=3, target_retry_base_delay_sec=10,
target_retry_max_delay_sec=100, target_timeout_retry_delay_sec=60,
soft_skip_reasons=('no_ci_runs',),
)
cases = (
({'errors': []}, 1, 'done', False),
({'errors': ['bad'], 'retryable': False}, 1, 'failed', False),
({'errors': ['timeout'], 'error_class': 'timeout'}, 1, 'deferred', False),
({'errors': ['source'], 'source_failure': True, 'retryable': True}, 3,
'deferred', True),
({'errors': [], 'skipped': 'no_ci_runs'}, 1, 'deferred', True),
)
for result, attempts, status, reset in cases:
with self.subTest(status=status, result=result):
disposition = scan_execution.queue_disposition_for_result(
result, 'github_actions', attempts, policy,
)
self.assertEqual(disposition['queue_status'], status)
self.assertEqual(disposition['reset_attempts'], reset)
def test_planned_execution_reuses_scanner_and_canonical_bundle_staging(self):
result = {'findings': [], 'errors': [], 'target': 'wrong', 'scan_type': 'wrong'}
staged = object()
with mock.patch.object(scan_execution, 'scan_target_result', return_value=result) as scan, \
mock.patch.object(scan_execution, 'stage_result_bundle', return_value=staged) as stage:
actual = scan_execution.execute_planned_result_in_scope(
reservation(), '/private/bundles', {'timeout_sec': 60}, {'detectors': 'OpenAI'},
scan_execution.QueueDispositionPolicy(), attempts=1,
scan_meta_defaults={'assignment': {'mode': 'remote'}},
)
self.assertIs(actual, staged)
scan.assert_called_once_with(
'https://example.invalid/repo', 'github', 'b' * 32, {'timeout_sec': 60.0},
)
args = stage.call_args.args
self.assertEqual(args[0]['target'], reservation().target)
self.assertEqual(args[0]['scan_type'], 'github')
self.assertEqual(args[0]['scan_meta']['assignment']['mode'], 'remote')
self.assertEqual(args[4]['queue_status'], 'done')
def test_runner_phase_callback_tracks_real_execution_boundaries_and_cleanup_counts(self):
phases = []
def scan(*_args, **_kwargs):
scanner.emit_client_scan_phase('scanning', {'records_seen': 3})
scanner.emit_client_scan_phase('filtering', {'records_seen': 3})
return {'findings': [], 'errors': []}
with mock.patch.object(
scan_execution, 'scan_slot_scope', return_value=mock.MagicMock(),
), mock.patch.object(
scan_execution, 'scan_target_result', side_effect=scan,
), mock.patch.object(
scan_execution, 'cleanup_assignment_work_dir',
return_value={'enumerated': 2, 'removed': 2, 'retained': 0},
), mock.patch.object(
scan_execution, 'stage_result_bundle', return_value=object(),
):
scan_execution.execute_planned_claim(
reservation(), '/private/bundles', {'timeout_sec': 60}, {},
scan_execution.QueueDispositionPolicy(), scan_policy(), attempts=1,
phase_callback=lambda phase, progress=None: phases.append(
(phase, dict(progress or {})),
),
)
self.assertEqual([item[0] for item in phases], [
'waiting_permit', 'scanning', 'filtering',
'cleaning', 'cleaning', 'bundling',
])
self.assertEqual(phases[-2][1]['removed'], 2)
self.assertEqual(phases[1][1], {'records_seen': 3})
self.assertEqual(phases[0][1], {'boundary': 'scan_slot_scope'})
def test_provider_callbacks_expose_only_observable_or_integrated_boundaries(self):
def streamed_output():
output = mock.MagicMock()
output.returncode = 0
output.stderr_lines.return_value = iter(())
output.stdout_lines.return_value = iter(())
context = mock.MagicMock()
context.__enter__.return_value = output
context.__exit__.return_value = False
return context
docker_target = 'docker.io/library/alpine@sha256:' + ('a' * 64)
docker_phases = []
manifest = scanner._client_scan_manifest.set({'executables': {}})
direct = scanner._client_remote_execution_kind.set('docker_direct_v1')
try:
with scanner.client_scan_phase_events(
lambda phase, progress=None: docker_phases.append(
(phase, dict(progress or {})),
)
), mock.patch.object(
scanner, 'get_trufflehog_cmd', return_value='trufflehog',
), mock.patch.object(
scanner, 'run_command_streamed', return_value=streamed_output(),
):
scanner.scan_docker_image(docker_target, timeout_sec=60)
finally:
scanner._client_remote_execution_kind.reset(direct)
scanner._client_scan_manifest.reset(manifest)
self.assertEqual(docker_phases[0], (
'scanning', {'integrated_operation': 'docker_pull_and_scan'},
))
self.assertNotIn('downloading', [item[0] for item in docker_phases])
hf_phases = []
direct = scanner._client_remote_execution_kind.set('huggingface_space_v1')
try:
with scanner.client_scan_phase_events(
lambda phase, progress=None: hf_phases.append(
(phase, dict(progress or {})),
)
), mock.patch.object(
scanner, 'get_trufflehog_cmd', return_value='trufflehog',
), mock.patch.object(
scanner, 'run_command_streamed', return_value=streamed_output(),
):
scanner.scan_huggingface_space('Example/Public-Space', timeout_sec=60)
finally:
scanner._client_remote_execution_kind.reset(direct)
self.assertEqual(hf_phases[0], (
'scanning', {'integrated_operation': 'huggingface_clone_and_scan'},
))
self.assertNotIn('cloning', [item[0] for item in hf_phases])
resolving = []
with scanner.client_scan_phase_events(
lambda phase, progress=None: resolving.append((phase, dict(progress or {}))),
), mock.patch.object(
scanner, 'recent_commit_boundary',
return_value={'skip': True, 'reason': 'fixture'},
):
scanner.scan_git_repo('https://example.invalid/repo', timeout_sec=60)
self.assertEqual(resolving[0][0], 'resolving')
self.assertEqual(resolving[0][1]['operation'], 'recent_commit_boundary')
docker_resolution = []
with scanner.client_scan_phase_events(
lambda phase, progress=None: docker_resolution.append(
(phase, dict(progress or {}), time.monotonic()),
)
), mock.patch.object(
scanner, 'resolve_docker_content_manifest',
side_effect=scanner.DockerContentScanError(
'fixture_resolution', 'fixture resolution stopped',
),
):
scanner._recover_docker_image_contents(
docker_target, time.monotonic() + 60, None, None, 0,
None, None, False, None, anonymous_public_client=True,
)
self.assertEqual(docker_resolution[0][0], 'resolving')
self.assertEqual(
docker_resolution[0][1]['operation'],
'docker_manifest_resolution_recovery',
)
self.assertEqual(
validate_phase_transition(
WorkerPhase.SCANNING, WorkerPhase(docker_resolution[0][0]),
),
WorkerPhase.RESOLVING,
)
def test_native_git_checkout_recovery_emits_real_cloning_boundary(self):
plan = {**noop_git_plan(), 'mode': 'baseline'}
phases = []
outputs = []
for returncode in (1, 0, 0):
output = mock.MagicMock()
output.returncode = returncode
output.stderr_lines.return_value = iter(())
output.stdout_lines.return_value = iter(())
context = mock.MagicMock()
context.__enter__.return_value = output
context.__exit__.return_value = False
outputs.append(context)
diagnostics = [0]
def apply(result, *_args, **_kwargs):
diagnostics[0] += 1
if diagnostics[0] == 1:
result['errors'] = ['checkout failed']
with tempfile.TemporaryDirectory() as temporary, \
scanner.client_scan_phase_events(
lambda phase, progress=None: phases.append(
(phase, dict(progress or {}), time.monotonic()),
),
), mock.patch.object(
scanner, 'get_trufflehog_cmd', return_value='trufflehog',
), mock.patch.object(
scanner, 'get_git_cmd', return_value='git',
), mock.patch.object(
scanner, 'run_command_streamed', side_effect=outputs,
), mock.patch.object(
scanner, 'apply_trufflehog_diagnostics', side_effect=apply,
), mock.patch.object(
scanner, 'append_trufflehog_findings',
), mock.patch.object(
scanner, 'git_checkout_recovery_allowed', return_value=True,
), mock.patch.object(
scanner, 'create_command_work_dir', return_value=temporary,
), mock.patch.object(
scanner, 'cleanup_command_work_dir',
):
scanner.scan_exact_git_plan(
plan['repo_url'], plan, 'f' * 64, 60,
None, None, False, None, None, False,
)
names = [item[0] for item in phases]
self.assertEqual(names[:3], ['scanning', 'cloning', 'scanning'])
for previous, current in zip(names, names[1:]):
validate_phase_transition(WorkerPhase(previous), WorkerPhase(current))
measured = [
later[2] - earlier[2]
for earlier, later in zip(phases, phases[1:])
]
self.assertTrue(measured)
self.assertTrue(all(duration >= 0 for duration in measured))
def test_docker_direct_claim_executes_bound_target_and_stages_bundle(self):
target = 'docker.io/library/alpine@sha256:' + ('a' * 64)
claim = BundleReservation(
reservation_id=17, reservation_token='docker-request-token',
bundle_id='d' * 32, scan_event_id='e' * 32, queue_id=23,
claim_lease_token='docker-lease-token', declared_bytes=1024 * 1024,
ready_path='ready/dd/' + ('d' * 32) + '.trb',
source='dockerhub', platform='docker', query='fixture',
target=target, normalized_target=scanner.normalize_target(target, 'docker'),
)
validated = {
'reservation': claim,
'planning_kind': 'docker_direct_v1',
'execution_target': target,
}
options = {'timeout_sec': 60.0}
manifest_token = scanner._client_scan_manifest.set({'executables': {}})
try:
with tempfile.TemporaryDirectory() as temp_dir:
bundle_root = os.path.join(temp_dir, 'bundles')
scanner.ensure_private_directory(bundle_root, reject_reparse=True)
with mock.patch.object(
scan_execution, 'scan_slot_scope', return_value=mock.MagicMock(),
), mock.patch.object(
scanner, 'scan_docker_image',
return_value={'findings': [], 'errors': [], 'scan_meta': {}},
) as docker_scan, mock.patch.object(
scanner.docker_token_manager, 'get_next_config',
side_effect=AssertionError('direct Docker cannot select server credentials'),
):
staged = scan_execution.execute_protocol2_remote_claim(
validated, bundle_root, options, options,
scan_execution.QueueDispositionPolicy(), scan_policy(), attempts=1,
)
docker_scan.assert_called_once()
self.assertEqual(docker_scan.call_args.args[0], target)
self.assertIsNone(docker_scan.call_args.kwargs['config_dir'])
reader = ResultBundleReader(
os.path.join(bundle_root, staged.relative_path),
)
metadata = reader.metadata()
self.assertEqual(metadata['target'], target)
self.assertEqual(metadata['scan_type'], 'docker')
encoded = json.dumps(metadata, sort_keys=True)
for forbidden in (
'docker_layer_work', 'docker_registry_auth',
'git_scan_plan', 'git_scan_execution',
):
self.assertNotIn(forbidden, encoded)
finally:
scanner._client_scan_manifest.reset(manifest_token)
self.assertIsNone(scanner._client_remote_execution_kind.get())
def test_huggingface_direct_claim_is_tokenless_and_stages_bundle(self):
target = 'ExampleOrg/Public-Space'
claim = BundleReservation(
reservation_id=18, reservation_token='hf-request-token',
bundle_id='f' * 32, scan_event_id='1' * 32, queue_id=24,
claim_lease_token='hf-lease-token', declared_bytes=1024 * 1024,
ready_path='ready/ff/' + ('f' * 32) + '.trb',
source='huggingface', platform='huggingface', query='fixture',
target=target,
normalized_target=scanner.normalize_target(target, 'huggingface'),
)
validated = {
'reservation': claim,
'planning_kind': 'huggingface_space_v1',
'execution_target': target,
}
options = {'timeout_sec': 60.0}
manifest_token = scanner._client_scan_manifest.set({'executables': {}})
try:
with tempfile.TemporaryDirectory() as temp_dir:
bundle_root = os.path.join(temp_dir, 'bundles')
scanner.ensure_private_directory(bundle_root, reject_reparse=True)
with mock.patch.object(
scan_execution, 'scan_slot_scope', return_value=mock.MagicMock(),
), mock.patch.object(
scanner, 'scan_huggingface_space',
return_value={'findings': [], 'errors': [], 'scan_meta': {}},
) as hf_scan:
staged = scan_execution.execute_protocol2_remote_claim(
validated, bundle_root, options, options,
scan_execution.QueueDispositionPolicy(), scan_policy(), attempts=1,
)
hf_scan.assert_called_once()
self.assertEqual(hf_scan.call_args.args[0], target)
self.assertIsNone(hf_scan.call_args.kwargs.get('token'))
reader = ResultBundleReader(
os.path.join(bundle_root, staged.relative_path),
)
metadata = reader.metadata()
self.assertEqual(metadata['target'], target)
self.assertEqual(metadata['scan_type'], 'huggingface')
encoded = json.dumps(metadata, sort_keys=True)
for forbidden in (
'huggingface_token', 'hf_token', 'authorization',
'docker_layer_work', 'docker_registry_auth',
'git_scan_plan', 'git_scan_execution',
):
self.assertNotIn(forbidden, encoded.lower())
finally:
scanner._client_scan_manifest.reset(manifest_token)
self.assertIsNone(scanner._client_remote_execution_kind.get())
def test_exact_git_noop_local_and_db_free_bundles_have_identical_coverage(self):
plan = noop_git_plan()
claim = source_reservation('github', plan['repo_url'])
kwargs = {'timeout_sec': 60, 'git_plan': plan}
queue_policy = scan_execution.QueueDispositionPolicy()
with tempfile.TemporaryDirectory() as temp_dir:
local_root = os.path.join(temp_dir, 'local')
remote_root = os.path.join(temp_dir, 'remote')
scanner.ensure_private_directory(local_root, reject_reparse=True)
scanner.ensure_private_directory(remote_root, reject_reparse=True)
with mock.patch.object(
scanner, 'run_command_streamed',
side_effect=AssertionError('noop Git plan must not launch a scanner'),
):
local_result = scanner.scan_target_result(
claim.target, claim.platform, claim.scan_event_id, kwargs,
)
local = scan_execution.stage_scan_result_in_scope(
local_result, claim, local_root, {}, queue_policy, attempts=1,
)
remote = scan_execution.execute_planned_result_in_scope(
claim, remote_root, kwargs, {}, queue_policy, attempts=1,
)
local_metadata = ResultBundleReader(
os.path.join(local_root, local.relative_path),
).metadata()
remote_metadata = ResultBundleReader(
os.path.join(remote_root, remote.relative_path),
).metadata()
self.assertEqual(local.queue_status, remote.queue_status)
for name in ('git_scan_plan', 'git_scan_execution'):
self.assertEqual(local_metadata[name], remote_metadata[name])
self.assertEqual(
local_metadata['scan_meta']['exact_git_scope'],
remote_metadata['scan_meta']['exact_git_scope'],
)
encoded_plan = scanner_db.canonical_git_scan_plan_bytes(plan)
stored = {
'git_scan_plan_json': encoded_plan.decode('ascii'),
'git_scan_plan_sha256': hashlib.sha256(encoded_plan).hexdigest(),
}
for metadata in (local_metadata, remote_metadata):
self.assertEqual(
scanner_db.matching_git_coverage(
stored, metadata, metadata['queue_status'], metadata['error_count'],
),
(True, plan['ref'], plan['head_sha']),
)
@unittest.skipUnless(
configured_trufflehog() and shutil.which('git'),
'configured TruffleHog and Git executables are required',
)
def test_native_exact_git_local_and_db_free_bundles_are_equivalent(self):
executable = configured_trufflehog()
git_executable = shutil.which('git')
xai_before = 'xai-' + hashlib.sha512(b'xai-before-parity').hexdigest()[:48]
xai_after = 'xai-' + hashlib.sha512(b'xai-after-parity').hexdigest()[:48]
zai_before = 'zai-' + base64.urlsafe_b64encode(
hashlib.sha512(b'zai-before-parity').digest()
).decode('ascii')[:48]
zai_after = 'zai-' + base64.urlsafe_b64encode(
hashlib.sha512(b'zai-after-parity').digest()
).decode('ascii')[:48]
fixtures = (
('xai-before.env', f'XAI_API_KEY={xai_before}\n'),
('xai-after.env', f'{xai_after} api.x.ai\n'),
('zai-before.env', f'ZAI_API_KEY={zai_before}\n'),
('zai-after.env', f'{zai_after} api.z.ai\n'),
)
policy = str(APP / 'trufflehog-custom-detectors.yaml')
repo_url = 'https://gitlab.com/Fixture/Parity.git'
with tempfile.TemporaryDirectory() as temp_dir:
source = Path(temp_dir) / 'source'
source.mkdir()
git_env = os.environ.copy()
git_env.update({
'GIT_CONFIG_NOSYSTEM': '1', 'GIT_CONFIG_GLOBAL': os.devnull,
'GIT_TERMINAL_PROMPT': '0', 'GIT_ALLOW_PROTOCOL': 'file',
})
def git(*args):
completed = subprocess.run(
[git_executable, '-c', 'user.name=Parity Fixture', '-c',
'user.email=parity@example.invalid', '-c', 'commit.gpgsign=false',
*args],
cwd=source, env=git_env, stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=False, timeout=30,
)
self.assertEqual(
completed.returncode, 0,
completed.stderr.decode('utf-8', errors='replace'),
)
return completed.stdout.decode('ascii').strip()
git('init', '--quiet', '--initial-branch=main', '--template=')
for name, content in fixtures:
(source / name).write_text(content, encoding='ascii', newline='\n')
git('add', '--', name)
git('commit', '--quiet', '-m', name)
head = git('rev-parse', 'HEAD')
plan = {
'version': 1, 'provider': 'gitlab', 'repo_url': repo_url,
'repo_path': 'Fixture/Parity', 'branch': 'main',
'ref': 'refs/heads/main', 'head_sha': head, 'base_sha': None,
'mode': 'baseline', 'baseline_depth': len(fixtures),
'ref_source': 'explicit',
}
claim = source_reservation('gitlab', repo_url)
kwargs = {
'timeout_sec': 60, 'git_plan': plan, 'no_verification': True,
'trufflehog_config': policy,
'external_trufflehog_lifecycle': True,
}
local_root = os.path.join(temp_dir, 'local')
remote_root = os.path.join(temp_dir, 'remote')
scanner.ensure_private_directory(local_root, reject_reparse=True)
scanner.ensure_private_directory(remote_root, reject_reparse=True)
execution_env = dict(git_env)
execution_env.update({
'GIT_CONFIG_COUNT': '1',
'GIT_CONFIG_KEY_0': f'url.{source.as_uri()}.insteadOf',
'GIT_CONFIG_VALUE_0': repo_url,
})
with mock.patch.dict(os.environ, execution_env, clear=True), \
mock.patch.object(
scanner, 'get_trufflehog_cmd', return_value=str(executable),
), mock.patch.object(
scanner, 'run_command_streamed',
side_effect=native_streamed_command,
):
local_result = scanner.scan_target_result(
claim.target, claim.platform, claim.scan_event_id, kwargs,
)
local = scan_execution.stage_scan_result_in_scope(
local_result, claim, local_root, {},
scan_execution.QueueDispositionPolicy(), attempts=1,
)
remote = scan_execution.execute_planned_result_in_scope(
claim, remote_root, kwargs, {},
scan_execution.QueueDispositionPolicy(), attempts=1,
)
local_evidence = normalized_bundle_evidence(
os.path.join(local_root, local.relative_path),
)
remote_evidence = normalized_bundle_evidence(
os.path.join(remote_root, remote.relative_path),
)
self.assertEqual(local_evidence, remote_evidence)
self.assertEqual(local.queue_status, 'done')
self.assertEqual(local.queue_status, remote.queue_status)
findings = local_evidence['findings']
self.assertEqual(
{item.get('DetectorName') for item in findings}, {'Xai', 'ZaiGLM'},
)
self.assertEqual(
{item.get('ExtraData', {}).get('name') for item in findings},
{'Xai', 'XaiContextAfter', 'ZaiGLM', 'ZaiGLMContextAfter'},
)
self.assertEqual(
{item.get('service') for item in local_evidence['candidates']},
{'xai', 'zai'},
)
encoded_plan = scanner_db.canonical_git_scan_plan_bytes(plan)
stored = {
'git_scan_plan_json': encoded_plan.decode('ascii'),
'git_scan_plan_sha256': hashlib.sha256(encoded_plan).hexdigest(),
}
metadata = local_evidence['metadata']
self.assertEqual(
scanner_db.matching_git_coverage(
stored, metadata, metadata['queue_status'], metadata['error_count'],
),
(True, plan['ref'], plan['head_sha']),
)
@unittest.skipUnless(
configured_trufflehog(), 'configured TruffleHog executable is required',
)
def test_native_postman_local_and_db_free_bundles_are_equivalent(self):
executable = configured_trufflehog()
gemini_key = 'AIza' + ('A' * 35)
azure_key = 'a' * 32
endpoint = 'fixture.openai.azure.com'
content = json.dumps({
'values': [
{'key': 'GEMINI_API_KEY', 'value': gemini_key},
{'key': 'AZURE_OPENAI_KEY', 'value': azure_key},
{'url': f'https://{endpoint}/openai/deployments/demo'},
],
}, sort_keys=True).encode('utf-8')
with tempfile.TemporaryDirectory() as temp_dir:
cache_root = os.path.join(temp_dir, 'cache')
work_root = os.path.join(temp_dir, 'work')
local_root = os.path.join(temp_dir, 'local')
remote_root = os.path.join(temp_dir, 'remote')
for path in (cache_root, work_root, local_root, remote_root):
scanner.ensure_private_directory(path, reject_reparse=True)
with mock.patch.multiple(
scanner.scan_config, postman_cache_dir=cache_root, runtime_dir=temp_dir,
postman_cache_min_free_bytes=0, min_free_gb=0,
):
cache_path, digest, size = scanner.write_postman_cache(
content, kind='collection', cache_dir=cache_root,
)
postman = {
'source': 'fixture', 'repo': 'Owner/Repo',
'path': 'collection.json', 'kind': 'collection',
'cache_path': cache_path, 'sha256': digest, 'size': size,
}
target = json.dumps(postman, sort_keys=True)
claim = source_reservation('postman', target)
kwargs = {
'timeout_sec': 60, 'max_artifact_size_mb': 1,
'no_verification': True,
}
with mock.patch.object(
scanner, 'get_work_dir', return_value=work_root,
), mock.patch.object(
scanner, 'require_scanner_runtime_initialized', return_value=None,
), mock.patch.object(
scanner, 'get_trufflehog_cmd', return_value=str(executable),
), mock.patch.object(
scanner, 'run_command_streamed', side_effect=native_streamed_command,
):
result = scanner.scan_target_result(
target, 'postman', claim.scan_event_id, kwargs,
)
self.assertTrue(
result.get('structured_keycheck_pending'),
result.get('warnings') or result.get('errors'),
)
local = scan_execution.stage_scan_result_in_scope(
result, claim, local_root, {},
scan_execution.QueueDispositionPolicy(), attempts=1,
)
remote = scan_execution.execute_planned_result_in_scope(
claim, remote_root, kwargs, {},
scan_execution.QueueDispositionPolicy(), attempts=1,
)
local_evidence = normalized_bundle_evidence(
os.path.join(local_root, local.relative_path),
)
remote_evidence = normalized_bundle_evidence(
os.path.join(remote_root, remote.relative_path),
)
self.assertEqual(local_evidence, remote_evidence)
self.assertEqual(local.queue_status, remote.queue_status)
self.assertEqual(local.queue_status, 'done')
candidates = local_evidence['candidates']
self.assertEqual({item['service'] for item in candidates}, {'gemini', 'azure'})
self.assertTrue(all(
item['candidate_kind'] == 'structured_postman' for item in candidates
))
origin = f'fixture:Owner/Repo:collection.json:{digest}'
expected = {
'gemini': (gemini_key, gemini_key, 'GoogleAIStudio'),
'azure': (
f'{endpoint}:{azure_key}', f'{azure_key}:{endpoint}', 'AzureOpenAI',
),
}
for item in candidates:
probe, raw, detector = expected[item['service']]
self.assertEqual(item['metadata']['origin'], origin)
self.assertEqual(item['metadata']['detector_name'], detector)
self.assertTrue(item['metadata']['structured_origin'].startswith(f'{origin}:$'))
self.assertEqual(item['attribution']['origin'], item['metadata']['structured_origin'])
self.assertEqual(
item['provider_key_hash'], hashlib.sha256(probe.encode('utf-8')).hexdigest(),
)
self.assertEqual(
item['secret_hash'], hashlib.sha256(raw.encode('utf-8')).hexdigest(),
)
self.assertEqual(item['credential_hash'], hashlib.sha256(
f"truf-credential-v2|{item['service']}|{probe}".encode('utf-8')
).hexdigest())
encoded = json.dumps(item, sort_keys=True)
for forbidden in ('status', 'status_group', 'checked_at', 'result_source'):
self.assertNotIn(f'"{forbidden}"', encoded)
self.assertEqual(len(candidates), 2)
def test_structured_postman_candidate_staging_rejects_size_or_hash_drift(self):
content = json.dumps({'token': 'AIza' + ('A' * 35)}).encode('utf-8')
with tempfile.TemporaryDirectory() as temp_dir:
cache_root = os.path.join(temp_dir, 'cache')
scanner.ensure_private_directory(cache_root, reject_reparse=True)
with mock.patch.multiple(
scanner.scan_config, postman_cache_dir=cache_root, runtime_dir=temp_dir,
postman_cache_min_free_bytes=0,
):
cache_path, digest, size = scanner.write_postman_cache(
content, cache_dir=cache_root,
)
for index, drift in enumerate(('size', 'hash'), start=1):
with self.subTest(drift=drift):
bundle_root = os.path.join(temp_dir, f'bundles-{index}')
scanner.ensure_private_directory(bundle_root, reject_reparse=True)
declared_digest = 'c' * 64 if drift == 'hash' else digest
target = f'postman:sha256:{declared_digest}'
claim = source_reservation(
'postman', target, bundle_id=str(index) * 32,
reservation_id=index,
)
result = {
'scan_event_id': claim.scan_event_id, 'target': target,
'scan_type': 'postman', 'findings': [], 'errors': [],
'structured_keycheck_pending': True,
'postman': {
'source': 'fixture', 'cache_path': cache_path,
'sha256': declared_digest, 'size': size,
},
'bytes': size + 1 if drift == 'size' else size,
'postman_max_artifact_size_mb': 1,
}
staged = scan_execution.stage_scan_result_in_scope(
result, claim, bundle_root, {},
scan_execution.QueueDispositionPolicy(), attempts=1,
)
reader = ResultBundleReader(
os.path.join(bundle_root, staged.relative_path),
)
self.assertEqual(list(reader.iter_candidates()), [])
metadata = reader.metadata()
self.assertTrue(metadata['degraded'])
self.assertTrue(any(
'structured keycheck extraction failed' in warning.lower()
for warning in metadata['warnings']
))
def test_client_manifest_authorizes_only_manifested_tools_and_policy(self):
manifest = {
'executables': {
'trufflehog': {'path': os.path.abspath('trufflehog'), 'sha256': 'a' * 64},
'git': {'path': os.path.abspath('git'), 'sha256': 'b' * 64},
},
'assets': {},
}
with mock.patch.object(scanner, 'verify_code_manifest', return_value=manifest), \
mock.patch.object(scanner, 'resolve_manifest_executable',
return_value=manifest['executables']['trufflehog']['path']):
with scanner.client_scan_launch_authority({}, expected_sha256='c' * 64):
self.assertEqual(scanner.get_git_cmd(), manifest['executables']['git']['path'])
metadata = scanner.require_trufflehog_launch_authority(
[manifest['executables']['trufflehog']['path'], 'filesystem', '/fixture'],
)
self.assertEqual(metadata['authority'], 'remote-worker')
with mock.patch.object(scanner.os.path, 'isabs', return_value=True):
metadata = scanner.require_git_clone_launch_authority([
manifest['executables']['git']['path'], 'clone', '--no-checkout',
'--no-recurse-submodules', '--', 'https://example.invalid/repo',
os.path.abspath('checkout'),
])
self.assertEqual(metadata['authority'], 'remote-worker')
with self.assertRaises(LifecycleAuthorityError):
scanner.require_trufflehog_launch_authority(
[manifest['executables']['trufflehog']['path'], 'filesystem', '/fixture'],
)
if __name__ == '__main__':
unittest.main()