2828
2929from app .core .security import crypto_timestamp_serializer
3030from app .sep .apps .framework .base import BaseApp
31- from app .sep .artifact_constants import ARTIFACT_DOWNLOAD_SALT
31+ from app .sep .artifact_constants import ARTIFACT_DOWNLOAD_SALT , STATIC_ARTIFACT_BASE_DIRS
3232from app .sep .routes .artifacts import collect_base_dirs
33+ from app .sep .snippets .constants import ARTIFACT_TYPE_SNIPPET
3334
3435
3536def _make_token (payload : dict , salt : str = ARTIFACT_DOWNLOAD_SALT ) -> str :
@@ -60,29 +61,69 @@ def test_raises_on_duplicate_artifact_type(self, mocker) -> None:
6061 collect_base_dirs ()
6162
6263 def test_flattens_distinct_artifact_types (self , mocker ) -> None :
63- """Merge distinct per-app declarations into one map."""
64- snippet_dir = Path ("/tmp/snippets" )
64+ """Merge distinct per-app declarations over the static seed."""
6565 dipper_dir = Path ("/tmp/dipper" )
66- first = BaseApp (
67- name = "snippets" ,
68- uri_path = "/snippets" ,
69- artifact_base_dirs = {"snippet" : lambda : snippet_dir },
70- )
71- second = BaseApp (
66+ other_dir = Path ("/tmp/other" )
67+ dipper = BaseApp (
7268 name = "dipper" ,
7369 uri_path = "/dipper" ,
7470 artifact_base_dirs = {"dipper" : lambda : dipper_dir },
7571 )
72+ other = BaseApp (
73+ name = "other" ,
74+ uri_path = "/other" ,
75+ artifact_base_dirs = {"other" : lambda : other_dir },
76+ )
7677 mocker .patch (
7778 "app.sep.routes.artifacts.get_app_registry" ,
78- return_value = [first , second ],
79+ return_value = [dipper , other ],
7980 )
8081
8182 result = collect_base_dirs ()
8283
83- assert result .keys () == {"snippet" , "dipper" }
84- assert result ["snippet" ]() == snippet_dir
84+ assert result .keys () == {ARTIFACT_TYPE_SNIPPET , "dipper" , "other" }
8585 assert result ["dipper" ]() == dipper_dir
86+ assert result ["other" ]() == other_dir
87+
88+ def test_seeds_the_static_snippet_type_without_the_snippets_app (
89+ self , mocker
90+ ) -> None :
91+ """Resolve the snippet type from the static map, with no app declaring it."""
92+ mocker .patch (
93+ "app.sep.routes.artifacts.get_app_registry" ,
94+ return_value = [BaseApp (name = "atw" , uri_path = "/atw" )],
95+ )
96+
97+ assert ARTIFACT_TYPE_SNIPPET in collect_base_dirs ()
98+
99+ def test_raises_when_an_app_redeclares_a_static_type (self , mocker ) -> None :
100+ """Reject an app that re-declares a statically registered type."""
101+ redeclaring = BaseApp (
102+ name = "snippets" ,
103+ uri_path = "/snippets" ,
104+ artifact_base_dirs = {ARTIFACT_TYPE_SNIPPET : lambda : Path ("/tmp/other" )},
105+ )
106+ mocker .patch (
107+ "app.sep.routes.artifacts.get_app_registry" , return_value = [redeclaring ]
108+ )
109+
110+ with pytest .raises (ValueError , match = ARTIFACT_TYPE_SNIPPET ):
111+ collect_base_dirs ()
112+
113+ def test_does_not_mutate_the_static_map (self , mocker ) -> None :
114+ """Return a fresh dict so an app declaration cannot leak into the constant."""
115+ declaring = BaseApp (
116+ name = "dipper" ,
117+ uri_path = "/dipper" ,
118+ artifact_base_dirs = {"dipper" : lambda : Path ("/tmp/dipper" )},
119+ )
120+ mocker .patch (
121+ "app.sep.routes.artifacts.get_app_registry" , return_value = [declaring ]
122+ )
123+
124+ collect_base_dirs ()
125+
126+ assert "dipper" not in STATIC_ARTIFACT_BASE_DIRS
86127
87128
88129class TestDownloadArtifact :
@@ -100,9 +141,7 @@ def test_valid_snippet_token_existing_file_returns_200(self, test_client, tmp_pa
100141 }
101142 token = _make_token (payload )
102143
103- with patch (
104- "app.sep.apps.snippets.app.snippets_settings.SNIPPETS_DIR" , tmp_path
105- ):
144+ with patch ("app.sep.snippets.config.snippets_settings.SNIPPETS_DIR" , tmp_path ):
106145 response = test_client .get (f"/artifacts/download/{ token } " )
107146
108147 assert response .status_code == HTTP_200_OK
@@ -143,7 +182,7 @@ def test_expired_token_returns_400(self, test_client, tmp_path):
143182
144183 with (
145184 patch ("app.sep.routes.artifacts.sep_settings.ARTIFACT_DOWNLOAD_TTL" , 60 ),
146- patch ("app.sep.apps. snippets.app .snippets_settings.SNIPPETS_DIR" , tmp_path ),
185+ patch ("app.sep.snippets.config .snippets_settings.SNIPPETS_DIR" , tmp_path ),
147186 ):
148187 response = test_client .get (
149188 f"/artifacts/download/{ token } " , follow_redirects = False
@@ -176,9 +215,7 @@ def test_valid_token_nonexistent_file_returns_404(self, test_client, tmp_path):
176215 }
177216 token = _make_token (payload )
178217
179- with patch (
180- "app.sep.apps.snippets.app.snippets_settings.SNIPPETS_DIR" , tmp_path
181- ):
218+ with patch ("app.sep.snippets.config.snippets_settings.SNIPPETS_DIR" , tmp_path ):
182219 response = test_client .get (
183220 f"/artifacts/download/{ token } " , follow_redirects = False
184221 )
@@ -194,9 +231,7 @@ def test_path_traversal_in_filename_returns_400(self, test_client, tmp_path):
194231 }
195232 token = _make_token (payload )
196233
197- with patch (
198- "app.sep.apps.snippets.app.snippets_settings.SNIPPETS_DIR" , tmp_path
199- ):
234+ with patch ("app.sep.snippets.config.snippets_settings.SNIPPETS_DIR" , tmp_path ):
200235 response = test_client .get (
201236 f"/artifacts/download/{ token } " , follow_redirects = False
202237 )
0 commit comments