import json
from pathlib import Path
import pytest
from domin8.tools.request_change import handle_request_change
from domin8.git_ops import create_diff
from domin8.storage import get_agent_data_root
VALID_LONG_SUMMARY = (
"This is a sufficiently long justification intended to satisfy the strict word-count rules. "
"It explains why the change is necessary because it removes an ambiguous API and clarifies the public surface, "
"therefore reducing future maintenance burden and preventing accidental misuse. "
"The change is limited in scope and targets a single file to keep blast radius minimal, and thus is safe to review."
)
@pytest.mark.asyncio
async def test_default_denylist_rejects_binary_like_extension():
# Attempt to modify an image asset (should be denied by default denylist)
target = Path('assets/logo.png')
original = ''
new = 'NEW BINARY PLACEHOLDER'
diff = create_diff(original, new, str(target))
res = await handle_request_change({
'summary': VALID_LONG_SUMMARY,
'diff': diff,
'actor_id': 'agent.test',
'tags': ['tests']
})
assert 'Path denied by repository policy' in res
@pytest.mark.asyncio
async def test_dist_path_denied():
# Modifying files under dist/ should be denied by default
target = Path('dist/app.min.js')
original = 'console.log("old")\n'
new = 'console.log("new")\n'
diff = create_diff(original, new, str(target))
res = await handle_request_change({
'summary': VALID_LONG_SUMMARY,
'diff': diff,
'actor_id': 'agent.test',
'tags': ['tests']
})
assert 'Path denied by repository policy' in res
@pytest.mark.asyncio
async def test_repo_level_allowlist_blocks_or_allows(tmp_path):
# Create a repo-level config to deny src/**
repo_root = Path('.').resolve()
cfg_dir = repo_root / 'config'
cfg_dir.mkdir(parents=True, exist_ok=True)
cfg_file = cfg_dir / 'request_change.json'
cfg_file.write_text(json.dumps({'deny': ['src/**']}))
try:
# Attempt to modify a file under src/ - should be denied
target = Path('src/domin8/__init__.py')
original = target.read_text()
new = original + '\n# noop change for testing\n'
diff = create_diff(original, new, str(target))
res = await handle_request_change({
'summary': VALID_LONG_SUMMARY,
'diff': diff,
'actor_id': 'agent.test',
'tags': ['tests']
})
assert 'Path denied by repository policy' in res
# Now allow a specific file by adding an allow pattern
cfg_file.write_text(json.dumps({'deny': ['src/**'], 'allow': ['src/domin8/__init__.py']}))
res2 = await handle_request_change({
'summary': VALID_LONG_SUMMARY,
'diff': diff,
'actor_id': 'agent.test',
'tags': ['tests']
})
assert 'Change request created and pending approval' in res2 or 'Artifact UUID' in res2
finally:
cfg_file.unlink()