Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/titmas_action_gate/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import hashlib
import hmac
import json
from dataclasses import dataclass
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any
Expand All @@ -20,7 +21,6 @@
from .provider import GitHubProvider
from .signing import HmacRecordSigner
from .store import AppendOnlyStore
from dataclasses import dataclass


@dataclass(frozen=True)
Expand Down
77 changes: 76 additions & 1 deletion tests/test_pr_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from contextlib import redirect_stdout
from datetime import timedelta
from pathlib import Path
from unittest import mock

import yaml

Expand All @@ -18,7 +19,7 @@
from titmas_action_gate.cli import main as cli_main
from titmas_action_gate.evidence import AGENT_EVIDENCE_VERSION, AGENT_EVIDENCE_WHEEL_SHA256, AgentEvidenceAdapter
from titmas_action_gate.policy import PolicyEngine
from titmas_action_gate.pr_gate import PUBLIC_EXIT_CODES, _missing_evidence_result, verify_pull_request
from titmas_action_gate.pr_gate import PUBLIC_EXIT_CODES, _missing_evidence_result, resolve_pull_request_context, verify_pull_request

ROOT = Path(__file__).resolve().parents[1]
REPOSITORY = "joy7758/titmas-merge-gate-sandbox"
Expand Down Expand Up @@ -402,5 +403,79 @@ def test_cli_returns_public_nonzero_exit_code_and_writes_outputs(self) -> None:
self.assertTrue((output / "summary.md").is_file())


class ResolvePullRequestContextTests(unittest.TestCase):
def test_explicit_arguments(self):
context = resolve_pull_request_context(
repository="repo",
pull_request=123,
head_sha="sha",
execution_identity="identity",
environment={}
)
self.assertEqual(context.repository, "repo")
self.assertEqual(context.pull_request, 123)
self.assertEqual(context.head_sha, "sha")
self.assertEqual(context.execution_identity, "identity")

def test_environment_variables_titmas_precedence(self):
env = {
"TITMAS_CURRENT_REPOSITORY": "env_repo",
"GITHUB_REPOSITORY": "gh_repo",
"TITMAS_CURRENT_PULL_REQUEST": "456",
"TITMAS_CURRENT_HEAD_SHA": "env_sha",
"GITHUB_SHA": "gh_sha",
"TITMAS_EXECUTION_IDENTITY": "env_identity",
}
context = resolve_pull_request_context(environment=env)
self.assertEqual(context.repository, "env_repo")
self.assertEqual(context.pull_request, 456)
self.assertEqual(context.head_sha, "env_sha")
self.assertEqual(context.execution_identity, "env_identity")

def test_environment_variables_github_fallback(self):
env = {
"GITHUB_REPOSITORY": "gh_repo",
"GITHUB_SHA": "gh_sha",
}
context = resolve_pull_request_context(environment=env)
self.assertEqual(context.repository, "gh_repo")
self.assertIsNone(context.pull_request)
self.assertEqual(context.head_sha, "gh_sha")
self.assertEqual(context.execution_identity, "")

def test_github_event_path_pull_request(self):
with tempfile.TemporaryDirectory() as tempdir:
event_path = Path(tempdir) / "event.json"
event_path.write_text(json.dumps({"pull_request": {"number": 789}}))
env = {
"GITHUB_EVENT_PATH": str(event_path)
}
context = resolve_pull_request_context(environment=env)
self.assertEqual(context.pull_request, 789)

def test_invalid_titmas_current_pull_request(self):
env = {
"TITMAS_CURRENT_PULL_REQUEST": "not-a-number",
"GITHUB_EVENT_PATH": "/nonexistent"
}
context = resolve_pull_request_context(environment=env)
self.assertIsNone(context.pull_request)

def test_invalid_github_event_path_pull_request(self):
with tempfile.TemporaryDirectory() as tempdir:
event_path = Path(tempdir) / "event.json"
event_path.write_text(json.dumps({"pull_request": {"number": "not-a-number"}}))
env = {
"GITHUB_EVENT_PATH": str(event_path)
}
context = resolve_pull_request_context(environment=env)
self.assertIsNone(context.pull_request)

def test_missing_environment_defaults_to_os_environ(self):
with mock.patch.dict(os.environ, {"TITMAS_CURRENT_REPOSITORY": "os_repo"}, clear=True):
context = resolve_pull_request_context()
self.assertEqual(context.repository, "os_repo")


if __name__ == "__main__":
unittest.main()
5 changes: 2 additions & 3 deletions tests/test_security_argument_injection.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import unittest
import subprocess
from unittest.mock import patch, MagicMock
from unittest.mock import MagicMock, patch

from titmas_action_gate.provider import GhCliProvider
from titmas_action_gate.errors import ActionGateError


class ProviderSecurityTests(unittest.TestCase):
@patch("subprocess.run")
Expand Down
6 changes: 3 additions & 3 deletions tests/test_workflow.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json
import tempfile
import unittest
from pathlib import Path

import json
from titmas_action_gate.workflow import validate_agentteams_template, write_demo_report


Expand Down Expand Up @@ -83,7 +83,7 @@ def test_write_demo_report(self):
self.assertEqual(result_path, output_file)
self.assertTrue(output_file.exists())

with open(output_file, "r", encoding="utf-8") as f:
with open(output_file, encoding="utf-8") as f:
content = json.load(f)

self.assertEqual(content, report_data)
Expand All @@ -95,7 +95,7 @@ def test_write_demo_report_creates_directories(self):
write_demo_report(report_data, output_file)

self.assertTrue(output_file.exists())
with open(output_file, "r", encoding="utf-8") as f:
with open(output_file, encoding="utf-8") as f:
content = json.load(f)

self.assertEqual(content, report_data)
Loading