"""Repository-grant v1 validation and identity compatibility.""" from __future__ import annotations import pytest from activity_core.models import ActionDef, InstructionDef from activity_core.orm import OpsRun from activity_core.repository_grant import ( RepositoryGrant, RepositoryGrantError, validate_repository_grant, ) def _grant(**changes: object) -> dict: value = { "version": "1", "allowed_paths": ["docs/", "README.md"], "commit_count": {"min": 1, "max": 1}, "publish": False, } value.update(changes) return value def test_repository_grant_preserves_payload_and_has_stable_identity() -> None: raw = _grant() grant = RepositoryGrant.model_validate(raw) reordered = RepositoryGrant.model_validate( _grant(allowed_paths=["README.md", "docs/"]) ) assert grant.payload() == raw assert grant.payload() is not raw assert grant.grant_id == reordered.grant_id assert grant.acceptance_policy_id == reordered.acceptance_policy_id assert grant.grant_id == "af2e7c8275c9ba8c8f78485067f9608e" assert grant.acceptance_policy_id == "2ed31282d721f4466bc9ea722067d9d0" def test_action_and_instruction_parse_repository_grant_as_typed_authority() -> None: action = ActionDef(task_template="Do work", repository_grant=_grant()) instruction = InstructionDef( id="do-work", trusted_fields=[], model="model", prompt="Do work", output_schema="schema.json", repository_grant=_grant(), ) assert isinstance(action.repository_grant, RepositoryGrant) assert isinstance(instruction.repository_grant, RepositoryGrant) @pytest.mark.parametrize( "value", [ _grant(extra="not-allowed"), _grant(version=1), _grant(allowed_paths=[]), _grant(allowed_paths=["docs/", "docs/"]), _grant(allowed_paths=["../escape"]), _grant(allowed_paths=[".git/config"]), _grant(commit_count={"min": True, "max": 1}), _grant(commit_count={"min": 2, "max": 1}), _grant(commit_count={"min": 1, "max": 33}), _grant(publish=True), _grant(publish=0), ], ) def test_repository_grant_rejects_ambiguous_or_unsafe_values(value: dict) -> None: with pytest.raises(RepositoryGrantError): validate_repository_grant(value) def test_ops_run_schema_has_separate_grant_and_close_identity_columns() -> None: columns = OpsRun.__table__.columns assert columns["repository_grant"].nullable is True assert columns["close_intent_digest"].nullable is True