793 lines
39 KiB
Python
793 lines
39 KiB
Python
import hashlib
|
|
import json
|
|
import os
|
|
import sqlite3
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest import mock
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
APP_DIR = ROOT / 'app'
|
|
sys.path.insert(0, str(APP_DIR))
|
|
|
|
import keycheck_runner
|
|
import runtime_security
|
|
from keycheckers import keycheck_common
|
|
from keycheckers.anthropic import anthropicKeycheck as anthropic
|
|
from keycheckers.dockerhub import dockerhubKeycheck as dockerhub
|
|
from keycheckers.openai import Keycheck as openai
|
|
from keycheckers.openrouter import OpenrouterKeycheck as openrouter
|
|
from keycheckers.qwen import qwenKeycheck as qwen
|
|
from scanner_db import ScannerDB
|
|
|
|
|
|
class OpenRouterLegacyMigrationDurabilityTests(unittest.TestCase):
|
|
MOVED_KEY = 'sk-or-v1-' + ('a' * 32)
|
|
KEEP_KEY = 'sk-or-v1-' + ('b' * 32)
|
|
|
|
@staticmethod
|
|
def harden_write(path, text):
|
|
Path(path).write_text(text, encoding='utf-8')
|
|
runtime_security.harden_private_file(path)
|
|
|
|
def paths(self, root):
|
|
return {
|
|
'ALIVE_FILE': os.path.join(root, 'openrouterAlive.txt'),
|
|
'NO_BALANCE_FILE': os.path.join(root, 'openrouterNoBalance.txt'),
|
|
'CHECKED_FILE': os.path.join(root, 'openrouterChecked.txt'),
|
|
'RESULTS_FILE': os.path.join(root, 'openrouterResults.jsonl'),
|
|
}
|
|
|
|
def seed(self, paths):
|
|
self.harden_write(
|
|
paths['ALIVE_FILE'],
|
|
f'{self.MOVED_KEY}:-1.25\n{self.KEEP_KEY}:3.5\nplain-legacy-key\n\n',
|
|
)
|
|
for name in ('NO_BALANCE_FILE', 'CHECKED_FILE', 'RESULTS_FILE'):
|
|
self.harden_write(paths[name], '')
|
|
|
|
def assert_converged(self, paths):
|
|
self.assertEqual(
|
|
Path(paths['ALIVE_FILE']).read_text(encoding='utf-8'),
|
|
f'{self.KEEP_KEY}:3.5\nplain-legacy-key\n\n',
|
|
)
|
|
no_balance_rows = [
|
|
line for line in Path(paths['NO_BALANCE_FILE']).read_text(encoding='utf-8').splitlines()
|
|
if openrouter.legacy_status_key(line) == self.MOVED_KEY
|
|
]
|
|
checked_rows = [
|
|
line for line in Path(paths['CHECKED_FILE']).read_text(encoding='utf-8').splitlines()
|
|
if line.split('\t')[:2] == [self.MOVED_KEY, 'NO_BALANCE']
|
|
]
|
|
events = [
|
|
json.loads(line)
|
|
for line in Path(paths['RESULTS_FILE']).read_text(encoding='utf-8').splitlines()
|
|
if line.strip()
|
|
]
|
|
events = [event for event in events if event.get('key_hash') == openrouter.sha256_text(self.MOVED_KEY)]
|
|
self.assertEqual(len(no_balance_rows), 1)
|
|
self.assertEqual(len(checked_rows), 1)
|
|
self.assertEqual(len(events), 1)
|
|
self.assertEqual(events[0]['status'], 'NO_BALANCE')
|
|
|
|
def test_fault_around_each_publication_stage_preserves_and_converges(self):
|
|
publication_stages = (
|
|
'_publish_legacy_no_balance',
|
|
'_publish_legacy_balance_events',
|
|
'_publish_legacy_checked',
|
|
)
|
|
for stage in publication_stages:
|
|
for position in ('before', 'after'):
|
|
with self.subTest(stage=stage, position=position), tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
paths = self.paths(temp_dir)
|
|
self.seed(paths)
|
|
real_stage = getattr(openrouter, stage)
|
|
|
|
def publish_then_crash(*args, _real=real_stage, **kwargs):
|
|
if position == 'after':
|
|
_real(*args, **kwargs)
|
|
raise OSError(f'injected crash {position} {stage}')
|
|
|
|
with mock.patch.multiple(openrouter, **paths):
|
|
with mock.patch.object(openrouter, stage, side_effect=publish_then_crash):
|
|
with self.assertRaisesRegex(OSError, 'injected crash'):
|
|
openrouter.migrate_legacy_alive_balances()
|
|
source = openrouter.load_openrouter_keys(paths['ALIVE_FILE'])
|
|
destination = openrouter.load_openrouter_keys(paths['NO_BALANCE_FILE'])
|
|
self.assertIn(self.MOVED_KEY, source | destination)
|
|
openrouter.migrate_legacy_alive_balances()
|
|
self.assert_converged(paths)
|
|
|
|
def test_fault_around_durable_alive_replace_preserves_and_converges(self):
|
|
for position in ('before', 'after'):
|
|
with self.subTest(position=position), tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
paths = self.paths(temp_dir)
|
|
self.seed(paths)
|
|
writer_module = sys.modules[openrouter.private_atomic_writer.__module__]
|
|
real_replace = writer_module.durable_replace
|
|
|
|
def replace_then_crash(source, destination):
|
|
if position == 'after':
|
|
real_replace(source, destination)
|
|
raise OSError(f'injected crash {position} durable replace')
|
|
|
|
with mock.patch.multiple(openrouter, **paths):
|
|
with mock.patch.object(writer_module, 'durable_replace', side_effect=replace_then_crash):
|
|
with self.assertRaisesRegex(OSError, 'injected crash'):
|
|
openrouter.migrate_legacy_alive_balances()
|
|
source = openrouter.load_openrouter_keys(paths['ALIVE_FILE'])
|
|
destination = openrouter.load_openrouter_keys(paths['NO_BALANCE_FILE'])
|
|
self.assertIn(self.MOVED_KEY, source | destination)
|
|
openrouter.migrate_legacy_alive_balances()
|
|
self.assert_converged(paths)
|
|
|
|
|
|
class QwenStatusTransactionDurabilityTests(unittest.TestCase):
|
|
KEY = 'sk-' + ('f' * 32)
|
|
|
|
@staticmethod
|
|
def write_private(path, text):
|
|
Path(path).write_text(text, encoding='utf-8')
|
|
runtime_security.harden_private_file(path)
|
|
|
|
@staticmethod
|
|
def provider_args(input_file):
|
|
return SimpleNamespace(
|
|
input=input_file, plain=[], proxy_file='unused-proxy.txt', timeout=1,
|
|
max_keys=0, base_url=[], no_default_base_urls=False,
|
|
retry_network=True, retry_limited=False, retry_unknown=False,
|
|
retry_restricted=False, retry_no_balance=False, retry_valid=False,
|
|
recheck_all=False, debug=False,
|
|
)
|
|
|
|
@staticmethod
|
|
def runner_args():
|
|
return SimpleNamespace(
|
|
retry_network=False, retry_limited=False, retry_unknown=False,
|
|
retry_restricted=False, retry_no_balance=False, retry_valid=False,
|
|
recheck_all=False,
|
|
)
|
|
|
|
def test_fault_at_each_projection_stage_recovers_and_retries(self):
|
|
stages = (
|
|
'publish_status_transaction_target',
|
|
'publish_status_transaction_checked',
|
|
'remove_status_transaction_old_copies',
|
|
'delete_status_transaction_journal',
|
|
)
|
|
for stage in stages:
|
|
for position in ('before', 'after'):
|
|
with self.subTest(stage=stage, position=position), tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
input_file = os.path.join(temp_dir, 'findings.jsonl')
|
|
checked_file = os.path.join(temp_dir, 'qwenChecked.txt')
|
|
results_file = os.path.join(temp_dir, 'qwenResults.jsonl')
|
|
status_files = {
|
|
'VALID': os.path.join(temp_dir, 'qwenAlive.txt'),
|
|
'NETWORK': os.path.join(temp_dir, 'qwenNetwork.txt'),
|
|
'UNKNOWN': os.path.join(temp_dir, 'qwenUnknown.txt'),
|
|
}
|
|
self.write_private(input_file, '')
|
|
self.write_private(results_file, '')
|
|
self.write_private(checked_file, f'{self.KEY}\tUNKNOWN\t2026-07-19T00:00:00+00:00\n')
|
|
self.write_private(status_files['VALID'], '')
|
|
self.write_private(status_files['NETWORK'], '')
|
|
self.write_private(status_files['UNKNOWN'], f'{self.KEY}\tUNKNOWN\tprior retry\tfixture\n')
|
|
db_path = os.path.join(temp_dir, 'scanner.db')
|
|
ScannerDB(db_path=db_path, db_url='').close()
|
|
real_stage = getattr(keycheck_common, stage)
|
|
|
|
def publish_then_crash(*args, _real=real_stage, **kwargs):
|
|
if position == 'after':
|
|
_real(*args, **kwargs)
|
|
raise OSError(f'injected crash {position} {stage}')
|
|
|
|
with mock.patch.object(keycheck_common, stage, side_effect=publish_then_crash):
|
|
with self.assertRaisesRegex(OSError, 'injected crash'):
|
|
keycheck_common.commit_status_transaction(
|
|
checked_file,
|
|
status_files,
|
|
self.KEY,
|
|
'NETWORK',
|
|
'fixture network failure',
|
|
'fixture',
|
|
)
|
|
|
|
journal = keycheck_common.status_transaction_journal_path(checked_file)
|
|
if os.path.exists(journal):
|
|
self.assertTrue(keycheck_runner.provider_replay_required(
|
|
'qwen', self.runner_args(), temp_dir,
|
|
))
|
|
|
|
args = self.provider_args(input_file)
|
|
environment = {
|
|
'KEYCHECK_OUTPUT_DIR': temp_dir,
|
|
'KEYCHECK_STATE_DIR': temp_dir,
|
|
'KEYCHECK_SERVICE': 'qwen',
|
|
'KEYCHECK_DB_URL': '',
|
|
'KEYCHECK_DB_PATH': db_path,
|
|
}
|
|
with mock.patch.dict(os.environ, environment, clear=False), mock.patch.multiple(
|
|
qwen,
|
|
CHECKED_FILE=checked_file,
|
|
RESULTS_FILE=results_file,
|
|
STATUS_FILES=status_files,
|
|
), mock.patch.object(qwen, 'require_provider_authority'), mock.patch.object(
|
|
qwen, 'parse_args', return_value=args,
|
|
), mock.patch.object(qwen, 'load_proxies', return_value=None), mock.patch.object(
|
|
qwen, 'check_key', return_value={
|
|
'status': 'NETWORK', 'message': 'fixture network failure',
|
|
},
|
|
) as check_key, mock.patch.object(qwen, 'write_keycheck_event'), mock.patch.object(
|
|
qwen, 'record_validation_result', return_value=True,
|
|
):
|
|
qwen.main()
|
|
|
|
check_key.assert_called_once()
|
|
self.assertFalse(os.path.exists(journal))
|
|
matching_statuses = []
|
|
for status, path in status_files.items():
|
|
matching_statuses.extend(
|
|
status for line in Path(path).read_text(encoding='utf-8').splitlines()
|
|
if keycheck_common.normalize_status_key(line) == self.KEY
|
|
)
|
|
self.assertEqual(matching_statuses, ['NETWORK'])
|
|
checked_rows = [
|
|
line for line in Path(checked_file).read_text(encoding='utf-8').splitlines()
|
|
if keycheck_common.normalize_status_key(line) == self.KEY
|
|
]
|
|
self.assertEqual(len(checked_rows), 1)
|
|
self.assertEqual(checked_rows[0].split('\t')[1], 'NETWORK')
|
|
|
|
|
|
class ProviderStatusTransactionTests(unittest.TestCase):
|
|
OPENAI_KEY = 'sk-' + ('z' * 40)
|
|
|
|
@staticmethod
|
|
def private_directory(path):
|
|
runtime_security.ensure_private_directory(path, reject_reparse=True)
|
|
|
|
def test_standard_provider_rows_are_transactional_and_keep_metadata(self):
|
|
cases = (
|
|
(
|
|
'anthropic', anthropic, 'sk-ant-' + ('a' * 86),
|
|
{'status': 'VALID', 'message': 'accepted'},
|
|
{'VALID': 'alive.txt', 'UNKNOWN': 'unknown.txt'},
|
|
{},
|
|
'fixture-source',
|
|
),
|
|
(
|
|
'dockerhub-alias', dockerhub, 'fixture-user:dckr_pat_' + ('b' * 27),
|
|
{'status': 'VALID_2FA', 'message': '2fa required', 'username': 'fixture-user'},
|
|
{'VALID': 'alive.txt', 'VALID_2FA': 'alive.txt', 'UNKNOWN': 'unknown.txt'},
|
|
{'PLAIN_FILE': 'plain.txt'},
|
|
'fixture-user',
|
|
),
|
|
)
|
|
for name, provider, key, result, filenames, extra_paths, expected_extra in cases:
|
|
with self.subTest(provider=name), tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
checked_file = os.path.join(temp_dir, 'checked.txt')
|
|
results_file = os.path.join(temp_dir, 'results.jsonl')
|
|
status_files = {
|
|
status: os.path.join(temp_dir, filename)
|
|
for status, filename in filenames.items()
|
|
}
|
|
patches = {
|
|
'CHECKED_FILE': checked_file,
|
|
'RESULTS_FILE': results_file,
|
|
'STATUS_FILES': status_files,
|
|
**{
|
|
field: os.path.join(temp_dir, filename)
|
|
for field, filename in extra_paths.items()
|
|
},
|
|
}
|
|
with mock.patch.multiple(provider, **patches), mock.patch.object(
|
|
provider, 'record_validation_result', return_value=True,
|
|
) as db_write:
|
|
provider.ensure_files()
|
|
provider.write_result(key, result, 'fixture-source', {})
|
|
|
|
target = status_files[result['status']]
|
|
self.assertEqual(
|
|
Path(target).read_text(encoding='utf-8'),
|
|
f"{key}\t{result['status']}\t{result['message']}\t{expected_extra}\n",
|
|
)
|
|
checked = Path(checked_file).read_text(encoding='utf-8').splitlines()
|
|
self.assertEqual(len(checked), 1)
|
|
self.assertEqual(checked[0].split('\t')[:2], [key, result['status']])
|
|
events = [
|
|
json.loads(line)
|
|
for line in Path(results_file).read_text(encoding='utf-8').splitlines()
|
|
]
|
|
self.assertEqual([event['status'] for event in events], [result['status']])
|
|
db_write.assert_called_once()
|
|
|
|
def test_openai_compaction_replacement_remains_exact_private(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
path = os.path.join(temp_dir, 'openaiNetwork.txt')
|
|
Path(path).write_bytes(b'key-one\tNETWORK\told\nkey-one\tNETWORK\tnew\n')
|
|
runtime_security.harden_private_file(path)
|
|
|
|
openai.compact_status_file(path)
|
|
|
|
self.assertEqual(Path(path).read_text(encoding='utf-8'), 'key-one\tNETWORK\tnew\n')
|
|
self.assertTrue(runtime_security.private_file_ready(path))
|
|
|
|
def test_gcp_structured_status_rows_use_a_bounded_provider_capability(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
key = '{"type":"service_account","private_key":"' + ('A' * 110000) + '"}'
|
|
checked_file = os.path.join(temp_dir, 'gcpChecked.txt')
|
|
alive_file = os.path.join(temp_dir, 'gcpAlive.txt')
|
|
unknown_file = os.path.join(temp_dir, 'gcpUnknown.txt')
|
|
Path(alive_file).write_text(f'{key}\tVALID\tlegacy\n', encoding='utf-8')
|
|
runtime_security.harden_private_file(alive_file)
|
|
with mock.patch.dict(os.environ, {
|
|
'KEYCHECK_SERVICE': 'gcp',
|
|
'KEYCHECK_OUTPUT_DIR': temp_dir,
|
|
'KEYCHECK_INPUT_LIST_MAX_LINE_BYTES': str(256 * 1024),
|
|
}, clear=False):
|
|
self.assertEqual(
|
|
keycheck_common.load_known_statuses(
|
|
checked_file, {'VALID': alive_file, 'UNKNOWN': unknown_file},
|
|
)[key],
|
|
'VALID',
|
|
)
|
|
keycheck_common.commit_status_transaction(
|
|
checked_file,
|
|
{'VALID': alive_file, 'UNKNOWN': unknown_file},
|
|
key,
|
|
'UNKNOWN',
|
|
message='fixture',
|
|
)
|
|
self.assertIn(key, Path(unknown_file).read_text(encoding='utf-8'))
|
|
self.assertTrue(runtime_security.private_file_ready(checked_file))
|
|
|
|
def test_private_output_rejects_permissive_existing_file_before_mutation(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
path = os.path.join(temp_dir, 'existing-results.jsonl')
|
|
Path(path).write_text('original\n', encoding='utf-8')
|
|
runtime_security.harden_private_directory(temp_dir)
|
|
self.assertFalse(runtime_security.private_file_ready(path))
|
|
|
|
with self.assertRaises(runtime_security.PrivateFileError):
|
|
with keycheck_common.private_append_writer(path) as handle:
|
|
handle.write('mutated\n')
|
|
|
|
self.assertEqual(Path(path).read_text(encoding='utf-8'), 'original\n')
|
|
|
|
def test_atomic_output_is_private_before_payload_and_after_replace(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
path = os.path.join(temp_dir, 'checked.txt')
|
|
keycheck_common.ensure_output_files([path])
|
|
|
|
with keycheck_common.private_atomic_writer(path) as handle:
|
|
temporary = next(
|
|
candidate for candidate in Path(temp_dir).iterdir()
|
|
if candidate.name != 'checked.txt'
|
|
)
|
|
self.assertTrue(runtime_security.private_file_ready(str(temporary)))
|
|
handle.write('key\tVALID\n')
|
|
|
|
self.assertEqual(Path(path).read_text(encoding='utf-8'), 'key\tVALID\n')
|
|
self.assertTrue(runtime_security.private_file_ready(path))
|
|
|
|
def test_summary_rejects_permissive_existing_destination(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
summary = os.path.join(temp_dir, 'summary.tsv')
|
|
Path(summary).write_text('original\n', encoding='utf-8')
|
|
runtime_security.harden_private_directory(temp_dir)
|
|
self.assertFalse(runtime_security.private_file_ready(summary))
|
|
layout = {'keycheck_dir': temp_dir}
|
|
|
|
with mock.patch.object(keycheck_runner, 'service_summary', return_value={}), \
|
|
self.assertRaises(runtime_security.PrivateFileError):
|
|
keycheck_runner.write_summary(layout, ['fixture'], summary_tsv=summary)
|
|
|
|
self.assertEqual(Path(summary).read_text(encoding='utf-8'), 'original\n')
|
|
|
|
def test_postgres_status_projection_merges_legacy_and_updates_known_keys(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
keycheck_dir = os.path.join(temp_dir, 'keychecks')
|
|
service_dir = os.path.join(keycheck_dir, 'openai')
|
|
runtime_security.ensure_private_directory(keycheck_dir, reject_reparse=True)
|
|
runtime_security.ensure_private_directory(service_dir, reject_reparse=True)
|
|
legacy = 'sk-' + ('l' * 40)
|
|
reclassified = 'sk-' + ('r' * 40)
|
|
fresh = 'sk-' + ('n' * 40)
|
|
alive_path = os.path.join(service_dir, 'openaiAlive.txt')
|
|
dead_path = os.path.join(service_dir, 'openaiDead.txt')
|
|
checked_path = os.path.join(service_dir, 'openaiChecked.txt')
|
|
self.private_directory(service_dir)
|
|
Path(alive_path).write_text(
|
|
f'{legacy}:[gpt-5]:legacy\n{reclassified}:[gpt-4]:legacy\n',
|
|
encoding='utf-8',
|
|
)
|
|
Path(dead_path).write_text('', encoding='utf-8')
|
|
Path(checked_path).write_text(
|
|
f'{reclassified}\tALIVE\tlegacy-time\n', encoding='utf-8',
|
|
)
|
|
for path in (alive_path, dead_path, checked_path):
|
|
runtime_security.harden_private_file(path)
|
|
|
|
rows = [
|
|
{
|
|
'service': 'openai', 'secret_text': reclassified, 'secret_json': '',
|
|
'status': 'INVALID_OR_REVOKED', 'checked_at': '2026-07-27T00:00:00+00:00',
|
|
'metadata_json': json.dumps({'message': 'revoked'}),
|
|
},
|
|
{
|
|
'service': 'openai', 'secret_text': fresh, 'secret_json': '',
|
|
'status': 'ALIVE', 'checked_at': '2026-07-27T00:01:00+00:00',
|
|
'metadata_json': json.dumps({
|
|
'message': 'accepted', 'llm_probe_model': 'gpt-5.6-sol',
|
|
'llm_probe_status': 'GENERATION_OK', 'model_count': 2,
|
|
'model_inventory': ['gpt-5.6-sol', 'o3-pro'],
|
|
}),
|
|
},
|
|
]
|
|
report = keycheck_runner.project_postgres_status_files(
|
|
{'keycheck_dir': keycheck_dir}, ['openai'], rows,
|
|
)
|
|
second = keycheck_runner.project_postgres_status_files(
|
|
{'keycheck_dir': keycheck_dir}, ['openai'], rows,
|
|
)
|
|
|
|
alive_keys = [
|
|
keycheck_runner.status_key(line)
|
|
for line in Path(alive_path).read_text(encoding='utf-8').splitlines()
|
|
]
|
|
dead_keys = [
|
|
keycheck_runner.status_key(line)
|
|
for line in Path(dead_path).read_text(encoding='utf-8').splitlines()
|
|
]
|
|
self.assertEqual(alive_keys, [legacy, fresh])
|
|
self.assertEqual(dead_keys, [reclassified])
|
|
alive_text = Path(alive_path).read_text(encoding='utf-8')
|
|
self.assertIn('probe_model=gpt-5.6-sol', alive_text)
|
|
self.assertIn('models=gpt-5.6-sol,o3-pro', alive_text)
|
|
self.assertEqual(len(Path(checked_path).read_text(encoding='utf-8').splitlines()), 2)
|
|
self.assertEqual(report['projected_rows'], 2)
|
|
self.assertGreaterEqual(report['changed_files'], 3)
|
|
self.assertEqual(second['changed_files'], 0)
|
|
self.assertTrue(all(
|
|
runtime_security.private_file_ready(path)
|
|
for path in (alive_path, dead_path, checked_path)
|
|
))
|
|
|
|
def test_postgres_status_projection_removes_managed_key_without_current_state(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
keycheck_dir = os.path.join(temp_dir, 'keychecks')
|
|
service_dir = os.path.join(keycheck_dir, 'deepseek')
|
|
runtime_security.ensure_private_directory(keycheck_dir, reject_reparse=True)
|
|
runtime_security.ensure_private_directory(service_dir, reject_reparse=True)
|
|
routed = 'sk-' + ('a' * 32)
|
|
unmanaged = 'sk-' + ('b' * 32)
|
|
alive_path = os.path.join(service_dir, 'deepseekAlive.txt')
|
|
checked_path = os.path.join(service_dir, 'deepseekChecked.txt')
|
|
Path(alive_path).write_text(
|
|
f'{routed}\tVALID\tlegacy\tlegacy\n{unmanaged}\tVALID\tlegacy\tlegacy\n',
|
|
encoding='utf-8',
|
|
)
|
|
Path(checked_path).write_text(
|
|
f'{routed}\tVALID\tlegacy\n{unmanaged}\tVALID\tlegacy\n',
|
|
encoding='utf-8',
|
|
)
|
|
for name in keycheck_runner.POSTGRES_STATUS_FILE_NAMES['deepseek'].values():
|
|
path = os.path.join(service_dir, name)
|
|
if not os.path.exists(path):
|
|
Path(path).write_text('', encoding='utf-8')
|
|
runtime_security.harden_private_file(path)
|
|
runtime_security.harden_private_file(checked_path)
|
|
|
|
report = keycheck_runner.project_postgres_status_files(
|
|
{'keycheck_dir': keycheck_dir}, ['deepseek'], [],
|
|
managed_rows=[{
|
|
'service': 'deepseek', 'secret_text': routed, 'secret_json': '',
|
|
}],
|
|
)
|
|
|
|
self.assertEqual(
|
|
[keycheck_runner.status_key(line) for line in Path(alive_path).read_text(
|
|
encoding='utf-8'
|
|
).splitlines()],
|
|
[unmanaged],
|
|
)
|
|
self.assertEqual(
|
|
[keycheck_runner.status_key(line) for line in Path(checked_path).read_text(
|
|
encoding='utf-8'
|
|
).splitlines()],
|
|
[unmanaged],
|
|
)
|
|
self.assertEqual(report['projected_rows'], 0)
|
|
self.assertEqual(report['changed_files'], 2)
|
|
|
|
def test_postgres_status_projection_restores_gcp_and_gemini_auxiliary_files(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
keycheck_dir = os.path.join(temp_dir, 'keychecks')
|
|
runtime_security.ensure_private_directory(keycheck_dir, reject_reparse=True)
|
|
gcp_key = json.dumps({'type': 'service_account', 'private_key': 'fixture'}, separators=(',', ':'))
|
|
gemini_key = 'AIza' + ('A' * 35)
|
|
rows = [
|
|
{
|
|
'service': 'gcp', 'secret_text': '', 'secret_json': gcp_key,
|
|
'status': 'VERTEX', 'checked_at': '2026-07-27T00:00:00+00:00',
|
|
'metadata_json': json.dumps({
|
|
'vertex_google_enabled': True, 'vertex_anthropic_enabled': True,
|
|
}),
|
|
},
|
|
{
|
|
'service': 'gemini', 'secret_text': gemini_key, 'secret_json': '',
|
|
'status': 'VALID_RATE_LIMITED', 'checked_at': '2026-07-27T00:00:00+00:00',
|
|
'metadata_json': '{}',
|
|
},
|
|
]
|
|
|
|
report = keycheck_runner.project_postgres_status_files(
|
|
{'keycheck_dir': keycheck_dir}, ['gcp', 'gemini'], rows,
|
|
)
|
|
|
|
for filename in ('gcpVertex.txt', 'gcpVertexGemini.txt', 'gcpVertexAnthropic.txt'):
|
|
path = os.path.join(keycheck_dir, 'gcp', filename)
|
|
self.assertEqual(keycheck_runner.status_key(Path(path).read_text(encoding='utf-8')), gcp_key)
|
|
rate_limited = os.path.join(keycheck_dir, 'gemini', 'geminiAliveRateLimited.txt')
|
|
self.assertEqual(
|
|
keycheck_runner.status_key(Path(rate_limited).read_text(encoding='utf-8')),
|
|
gemini_key,
|
|
)
|
|
self.assertEqual(report['projected_rows'], 2)
|
|
self.assertEqual(report['skipped_rows'], 0)
|
|
|
|
def test_all_legacy_provider_initializers_create_exact_private_outputs(self):
|
|
from keycheckers.gemini import geminiKeycheck as gemini
|
|
|
|
providers = (
|
|
(openai, 'ensure_output_files', ['CHECKED_FILE', 'RESULTS_FILE'], 'STATUS_FILES'),
|
|
(openrouter, 'ensure_output_files', ['CHECKED_FILE', 'RESULTS_FILE'], 'STATUS_FILES'),
|
|
(gemini, 'ensure_output_files', ['CHECKED_FILE', 'RESULTS_FILE'], 'STATUS_FILES'),
|
|
)
|
|
for provider, initializer, fixed_names, status_name in providers:
|
|
with self.subTest(provider=provider.SERVICE), tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
fixed = {name: os.path.join(temp_dir, name.lower() + '.txt') for name in fixed_names}
|
|
original_status = getattr(provider, status_name)
|
|
if isinstance(original_status, dict):
|
|
statuses = {name: os.path.join(temp_dir, f'{name.lower()}.txt') for name in original_status}
|
|
extra = {'STATUS_BY_FILE': {path: name for name, path in statuses.items()}} if provider is openai else {}
|
|
else:
|
|
statuses = [os.path.join(temp_dir, f'status-{index}.txt') for index, _ in enumerate(original_status)]
|
|
extra = {'STATUS_BY_FILE': {path: f'STATUS_{index}' for index, path in enumerate(statuses)}}
|
|
with mock.patch.multiple(provider, OUTPUT_DIR=temp_dir, **fixed, **{status_name: statuses}, **extra):
|
|
getattr(provider, initializer)()
|
|
paths = [*fixed.values(), *(statuses.values() if isinstance(statuses, dict) else statuses)]
|
|
self.assertTrue(all(runtime_security.private_file_ready(path) for path in paths))
|
|
|
|
def test_custom_projection_lines_validate_key_status_and_bounds(self):
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
checked_file = os.path.join(temp_dir, 'checked.txt')
|
|
status_files = {
|
|
'ALIVE': os.path.join(temp_dir, 'alive.txt'),
|
|
'UNKNOWN': os.path.join(temp_dir, 'unknown.txt'),
|
|
}
|
|
custom_status = f'{self.OPENAI_KEY}:[gpt-5]:tier-1\n'
|
|
custom_checked = f'{self.OPENAI_KEY}\tALIVE\tfixture-time\n'
|
|
keycheck_common.commit_status_transaction(
|
|
checked_file,
|
|
status_files,
|
|
self.OPENAI_KEY,
|
|
'ALIVE',
|
|
status_line=custom_status,
|
|
checked_line=custom_checked,
|
|
)
|
|
self.assertEqual(Path(status_files['ALIVE']).read_text(encoding='utf-8'), custom_status)
|
|
self.assertEqual(Path(checked_file).read_text(encoding='utf-8'), custom_checked)
|
|
|
|
invalid = (
|
|
{'status_line': f'other-key:[gpt-5]:tier-1\n'},
|
|
{'checked_line': f'{self.OPENAI_KEY}\tUNKNOWN\tfixture-time\n'},
|
|
{'status_line': self.OPENAI_KEY + ':' + ('x' * 8192) + '\n'},
|
|
)
|
|
for kwargs in invalid:
|
|
with self.subTest(kwargs=tuple(kwargs)), self.assertRaises(ValueError):
|
|
keycheck_common.commit_status_transaction(
|
|
checked_file,
|
|
status_files,
|
|
self.OPENAI_KEY,
|
|
'ALIVE',
|
|
**kwargs,
|
|
)
|
|
|
|
def test_openai_network_to_alive_recovers_every_projection_crash_window(self):
|
|
stages = (
|
|
'publish_status_transaction_target',
|
|
'publish_status_transaction_checked',
|
|
'remove_status_transaction_old_copies',
|
|
'delete_status_transaction_journal',
|
|
)
|
|
transaction_module = sys.modules[openai.commit_status_transaction.__module__]
|
|
for stage in stages:
|
|
for position in ('before', 'after'):
|
|
with self.subTest(stage=stage, position=position), tempfile.TemporaryDirectory() as temp_dir:
|
|
self.private_directory(temp_dir)
|
|
paths = {
|
|
'ALIVE': os.path.join(temp_dir, 'openaiAlive.txt'),
|
|
'DEAD': os.path.join(temp_dir, 'openaiDead.txt'),
|
|
'NETWORK': os.path.join(temp_dir, 'openaiNetwork.txt'),
|
|
'LIMITED': os.path.join(temp_dir, 'openaiLimited.txt'),
|
|
'RESTRICTED': os.path.join(temp_dir, 'openaiRestricted.txt'),
|
|
'UNKNOWN': os.path.join(temp_dir, 'openaiUnknown.txt'),
|
|
'NO_TARGET_MODELS': os.path.join(temp_dir, 'openaiNoTarget.txt'),
|
|
}
|
|
checked_file = os.path.join(temp_dir, 'openaiChecked.txt')
|
|
results_file = os.path.join(temp_dir, 'openaiResults.jsonl')
|
|
by_file = {path: status for status, path in paths.items()}
|
|
provider_paths = {
|
|
'ALIVE_FILE': paths['ALIVE'],
|
|
'DEAD_FILE': paths['DEAD'],
|
|
'NETWORK_FILE': paths['NETWORK'],
|
|
'LIMITED_FILE': paths['LIMITED'],
|
|
'RESTRICTED_FILE': paths['RESTRICTED'],
|
|
'UNKNOWN_FILE': paths['UNKNOWN'],
|
|
'NO_TARGET_FILE': paths['NO_TARGET_MODELS'],
|
|
'CHECKED_FILE': checked_file,
|
|
'RESULTS_FILE': results_file,
|
|
'STATUS_FILES': list(paths.values()),
|
|
'STATUS_BY_FILE': by_file,
|
|
}
|
|
|
|
with mock.patch.multiple(openai, **provider_paths), mock.patch.object(
|
|
openai, 'record_validation_result', return_value=True,
|
|
):
|
|
openai.ensure_output_files()
|
|
openai.write_key_status(
|
|
self.OPENAI_KEY,
|
|
paths['NETWORK'],
|
|
'network_error',
|
|
'fixture network failure',
|
|
'fixture-source',
|
|
{},
|
|
)
|
|
real_stage = getattr(transaction_module, stage)
|
|
|
|
def publish_then_crash(*args, _real=real_stage, **kwargs):
|
|
if position == 'after':
|
|
_real(*args, **kwargs)
|
|
raise OSError(f'injected crash {position} {stage}')
|
|
|
|
with mock.patch.object(transaction_module, stage, side_effect=publish_then_crash):
|
|
with self.assertRaisesRegex(OSError, 'injected crash'):
|
|
openai.move_key_to_alive(
|
|
self.OPENAI_KEY, {'gpt-5'}, 'tier-1', 'fixture-source', {},
|
|
)
|
|
|
|
# Startup recovery must run before checked/status precedence is loaded.
|
|
openai.ensure_output_files()
|
|
known = openai.load_known_statuses(checked_file, by_file)
|
|
|
|
journal = transaction_module.status_transaction_journal_path(checked_file)
|
|
self.assertFalse(os.path.exists(journal))
|
|
self.assertEqual(known[self.OPENAI_KEY], 'ALIVE')
|
|
self.assertEqual(
|
|
Path(paths['ALIVE']).read_text(encoding='utf-8'),
|
|
f'{self.OPENAI_KEY}:[gpt-5]:tier-1\n',
|
|
)
|
|
for status, path in paths.items():
|
|
matching = [
|
|
line for line in Path(path).read_text(encoding='utf-8').splitlines()
|
|
if openai.key_from_line(line) == self.OPENAI_KEY
|
|
]
|
|
self.assertEqual(len(matching), 1 if status == 'ALIVE' else 0)
|
|
checked = [
|
|
line for line in Path(checked_file).read_text(encoding='utf-8').splitlines()
|
|
if openai.key_from_line(line) == self.OPENAI_KEY
|
|
]
|
|
self.assertEqual(len(checked), 1)
|
|
self.assertEqual(checked[0].split('\t')[1], 'ALIVE')
|
|
events = [
|
|
json.loads(line)
|
|
for line in Path(results_file).read_text(encoding='utf-8').splitlines()
|
|
]
|
|
self.assertEqual([event['status'] for event in events], ['NETWORK_ERROR', 'ALIVE'])
|
|
|
|
|
|
class KeycheckResetRetirementTests(unittest.TestCase):
|
|
def test_reset_helper_rejects_before_reading_layout_or_constructing_db(self):
|
|
class UnreadableLayout:
|
|
def get(self, key, default=None):
|
|
raise AssertionError(f'layout read: {key}')
|
|
|
|
with mock.patch.object(keycheck_runner, 'ScannerDB') as scanner_db:
|
|
with self.assertRaisesRegex(SystemExit, 'reset-keycheck-results is retired'):
|
|
keycheck_runner.sync_keycheck_results_to_db(UnreadableLayout(), ['openai'], reset=True)
|
|
scanner_db.assert_not_called()
|
|
|
|
def test_reset_cli_rejects_before_authority_config_files_or_db(self):
|
|
with mock.patch.object(sys, 'argv', [
|
|
'keycheck_runner.py', '--sync-keychecks-to-db', '--reset-keycheck-results',
|
|
]):
|
|
args = keycheck_runner.parse_args()
|
|
with mock.patch.object(keycheck_runner, 'parse_args', return_value=args), \
|
|
mock.patch.object(keycheck_runner, 'require_active_supervisor_child') as authority, \
|
|
mock.patch.object(keycheck_runner, 'load_config') as load_config, \
|
|
mock.patch.object(keycheck_runner, 'ScannerDB') as scanner_db, \
|
|
mock.patch('builtins.open') as open_file:
|
|
with self.assertRaisesRegex(SystemExit, 'reset-keycheck-results is retired'):
|
|
keycheck_runner.main()
|
|
authority.assert_not_called()
|
|
load_config.assert_not_called()
|
|
scanner_db.assert_not_called()
|
|
open_file.assert_not_called()
|
|
|
|
def test_incremental_ingest_observes_rotated_result_generation(self):
|
|
clean_database_env = {
|
|
'SCANNER_DB_URL': '',
|
|
'DATABASE_URL': '',
|
|
'TRUF_MANAGED_POSTGRES_DSN': '',
|
|
'KEYCHECK_DB_URL': '',
|
|
}
|
|
with tempfile.TemporaryDirectory() as temp_dir, mock.patch.dict(
|
|
os.environ, clean_database_env, clear=False,
|
|
):
|
|
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
|
|
keycheck_dir = os.path.join(temp_dir, 'keychecks')
|
|
service_dir = os.path.join(keycheck_dir, 'openai')
|
|
runtime_security.ensure_private_directory(keycheck_dir, reject_reparse=True)
|
|
runtime_security.ensure_private_directory(service_dir, reject_reparse=True)
|
|
db_path = os.path.join(temp_dir, 'scanner.db')
|
|
ScannerDB(db_path=db_path).close()
|
|
results_path = os.path.join(service_dir, 'openaiResults.jsonl')
|
|
|
|
def event(event_id, key):
|
|
digest = hashlib.sha256(key.encode('utf-8')).hexdigest()
|
|
return {
|
|
'event_id': event_id,
|
|
'status': 'VALID',
|
|
'key_hash': digest,
|
|
'secret_hash': digest,
|
|
'key_masked': key,
|
|
'checked_at': '2026-07-19T00:00:00+00:00',
|
|
}
|
|
|
|
old_event = event('old-generation', 'old-key')
|
|
self.harden_result(results_path, old_event)
|
|
layout = {'database_path': db_path, 'keycheck_dir': keycheck_dir}
|
|
self.assertEqual(keycheck_runner.ingest_keycheck_results_to_db(layout, ['openai'], 10), 1)
|
|
|
|
keycheck_common.rotate_jsonl_if_needed(results_path, 1)
|
|
new_event = event('new-generation', 'new-key')
|
|
with open(results_path, 'ab') as handle:
|
|
handle.write((json.dumps(new_event) + '\n').encode('utf-8'))
|
|
handle.flush()
|
|
os.fsync(handle.fileno())
|
|
runtime_security.harden_private_file(results_path)
|
|
self.assertEqual(keycheck_runner.ingest_keycheck_results_to_db(layout, ['openai'], 10), 1)
|
|
|
|
connection = sqlite3.connect(db_path)
|
|
try:
|
|
event_ids = {row[0] for row in connection.execute('SELECT event_id FROM keycheck_results')}
|
|
finally:
|
|
connection.close()
|
|
self.assertEqual(event_ids, {'old-generation', 'new-generation'})
|
|
|
|
@staticmethod
|
|
def harden_result(path, payload):
|
|
Path(path).write_text(json.dumps(payload) + '\n', encoding='utf-8')
|
|
runtime_security.harden_private_file(path)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|