from __future__ import annotations from pathlib import Path import sys import hashlib import io import json import tempfile from unittest import mock import unittest ROOT = Path(__file__).parents[1] sys.path.insert(0, str(ROOT / "tools")) from fetch_sources import _archive_url, _request, fetch class FetchSourcesAuthenticationTest(unittest.TestCase): def test_same_origin_request_carries_forgejo_token(self) -> None: request = _request( "https://forgejo.coulomb.social/api/v1/repos/coulomb/policy-nexus", token="test-secret", token_origin="https://forgejo.coulomb.social", ) self.assertEqual("token test-secret", request.get_header("Authorization")) self.assertNotIn("test-secret", request.full_url) def test_cross_origin_request_refuses_source_token(self) -> None: with self.assertRaisesRegex(ValueError, "refusing to send source credential"): _request( "https://example.invalid/coulomb/policy-nexus/archive/main.tar.gz", token="test-secret", token_origin="https://forgejo.coulomb.social", ) def test_token_and_origin_must_be_configured_together(self) -> None: with self.assertRaisesRegex(ValueError, "must be provided together"): _request( "https://forgejo.coulomb.social/coulomb/policy-nexus", token="test-secret", ) def test_anonymous_request_has_no_authorization_header(self) -> None: request = _request("https://forgejo.coulomb.social/public/repository") self.assertIsNone(request.get_header("Authorization")) def test_archive_uses_full_resolved_revision(self) -> None: revision = "a" * 40 self.assertEqual( f"https://forgejo.coulomb.social/coulomb/policy-nexus/archive/{revision}.tar.gz", _archive_url( "https://forgejo.coulomb.social/coulomb/policy-nexus.git", revision, ), ) def test_fetch_locks_workflow_self_sha_and_exact_resolved_upstream_archive(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) config = root / "config.json" config.write_text(json.dumps({"schema_version": 1, "repositories": { "policy-nexus": {"local": True}, "owner": {"remote": "https://forgejo.coulomb.social/coulomb/owner.git", "branch": "main"}, }})) self_sha, owner_sha = "b" * 40, "a" * 40 with mock.patch("fetch_sources._revision", return_value=owner_sha) as resolve, \ mock.patch("fetch_sources.urllib.request.urlopen", return_value=io.BytesIO(b"archive")) as opened, \ mock.patch("fetch_sources._extract"): lock = fetch(config, root / "sources", self_sha) self.assertEqual(lock["repositories"]["policy-nexus"]["revision"], self_sha) self.assertEqual(lock["repositories"]["owner"]["revision"], owner_sha) self.assertEqual(resolve.call_count, 1) self.assertEqual(opened.call_args.args[0].full_url, "https://forgejo.coulomb.social/coulomb/owner/archive/" + owner_sha + ".tar.gz") canonical = json.dumps({"owner": owner_sha, "policy-nexus": self_sha}, sort_keys=True, separators=(",", ":")).encode() self.assertEqual(lock["source_set_digest"], hashlib.sha256(canonical).hexdigest()) self.assertEqual(json.loads((root / "sources/source-lock.json").read_text()), lock) def test_mutable_self_reference_refused_before_fetch(self) -> None: with tempfile.TemporaryDirectory() as directory: root = Path(directory) with self.assertRaisesRegex(ValueError, "clean 40-hex"), \ mock.patch("fetch_sources.urllib.request.urlopen") as opened: fetch(root / "config.json", root / "sources", "main") opened.assert_not_called() if __name__ == "__main__": unittest.main()