regscale-cli 6.23.0.1__py3-none-any.whl → 6.24.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of regscale-cli might be problematic. Click here for more details.

Files changed (45) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/application.py +2 -0
  3. regscale/integrations/commercial/__init__.py +1 -0
  4. regscale/integrations/commercial/jira.py +95 -22
  5. regscale/integrations/commercial/sarif/sarif_converter.py +1 -1
  6. regscale/integrations/commercial/wizv2/click.py +132 -2
  7. regscale/integrations/commercial/wizv2/compliance_report.py +1574 -0
  8. regscale/integrations/commercial/wizv2/constants.py +72 -2
  9. regscale/integrations/commercial/wizv2/data_fetcher.py +61 -0
  10. regscale/integrations/commercial/wizv2/file_cleanup.py +104 -0
  11. regscale/integrations/commercial/wizv2/issue.py +775 -27
  12. regscale/integrations/commercial/wizv2/policy_compliance.py +599 -181
  13. regscale/integrations/commercial/wizv2/reports.py +243 -0
  14. regscale/integrations/commercial/wizv2/scanner.py +668 -245
  15. regscale/integrations/compliance_integration.py +534 -56
  16. regscale/integrations/due_date_handler.py +210 -0
  17. regscale/integrations/public/cci_importer.py +444 -0
  18. regscale/integrations/scanner_integration.py +718 -153
  19. regscale/models/integration_models/CCI_List.xml +1 -0
  20. regscale/models/integration_models/cisa_kev_data.json +18 -3
  21. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  22. regscale/models/regscale_models/control_implementation.py +13 -3
  23. regscale/models/regscale_models/form_field_value.py +1 -1
  24. regscale/models/regscale_models/milestone.py +1 -0
  25. regscale/models/regscale_models/regscale_model.py +225 -60
  26. regscale/models/regscale_models/security_plan.py +3 -2
  27. regscale/regscale.py +7 -0
  28. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/METADATA +17 -17
  29. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/RECORD +45 -28
  30. tests/fixtures/test_fixture.py +13 -8
  31. tests/regscale/integrations/public/__init__.py +0 -0
  32. tests/regscale/integrations/public/test_alienvault.py +220 -0
  33. tests/regscale/integrations/public/test_cci.py +458 -0
  34. tests/regscale/integrations/public/test_cisa.py +1021 -0
  35. tests/regscale/integrations/public/test_emass.py +518 -0
  36. tests/regscale/integrations/public/test_fedramp.py +851 -0
  37. tests/regscale/integrations/public/test_fedramp_cis_crm.py +3661 -0
  38. tests/regscale/integrations/public/test_file_uploads.py +506 -0
  39. tests/regscale/integrations/public/test_oscal.py +453 -0
  40. tests/regscale/models/test_form_field_value_integration.py +304 -0
  41. tests/regscale/models/test_module_integration.py +582 -0
  42. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/LICENSE +0 -0
  43. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/WHEEL +0 -0
  44. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/entry_points.txt +0 -0
  45. {regscale_cli-6.23.0.1.dist-info → regscale_cli-6.24.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,506 @@
1
+ import os
2
+ import tempfile
3
+ import unittest
4
+ from unittest.mock import patch, MagicMock, mock_open
5
+ import pytest
6
+ import xml.etree.ElementTree as ET
7
+ from regscale.core.app.internal.file_uploads import file_upload, upload_file
8
+ from regscale.models.regscale_models.file import File
9
+ from regscale.core.app.api import Api
10
+
11
+
12
+ class TestFileUploadsAndFileModel(unittest.TestCase):
13
+
14
+ @patch("regscale.core.app.internal.file_uploads.File.upload_file_to_regscale")
15
+ @patch("regscale.core.app.internal.file_uploads.encode_file_to_base64")
16
+ @patch("regscale.core.app.internal.file_uploads.decode_base64_to_bytesio")
17
+ def test_file_upload_success(self, mock_decode_b64, mock_encode_b64, mock_upload):
18
+ mock_encode_b64.return_value = "ZmFrZV9iYXNlNjQ="
19
+ mock_decode_b64.return_value = MagicMock(getvalue=lambda: b"fake_bytes")
20
+ mock_upload.return_value = {"result": "success"}
21
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
22
+ tmp.write(b"test content")
23
+ tmp_path = tmp.name
24
+ try:
25
+ result = file_upload(123, "test_module", tmp_path)
26
+ self.assertEqual(result, {"result": "success"})
27
+ mock_encode_b64.assert_called_once_with(tmp_path)
28
+ mock_upload.assert_called_once()
29
+ finally:
30
+ os.remove(tmp_path)
31
+
32
+ def test_file_upload_missing_file(self):
33
+ result = file_upload(123, "test_module", "nonexistent_file.txt")
34
+ self.assertIsNone(result)
35
+
36
+ @patch("regscale.core.app.internal.file_uploads.File.upload_file_to_regscale")
37
+ @patch("regscale.core.app.internal.file_uploads.decode_base64_to_bytesio")
38
+ def test_upload_file_success(self, mock_decode_b64, mock_upload):
39
+ mock_decode_b64.return_value = MagicMock(getvalue=lambda: b"fake_bytes")
40
+ mock_upload.return_value = {"id": 1, "result": "success"}
41
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
42
+ tmp.write(b"test content")
43
+ tmp_path = tmp.name
44
+ try:
45
+ result = upload_file(
46
+ ssp_id=123,
47
+ parent_module="test_module",
48
+ file_path=tmp_path,
49
+ filestring="ZmFrZV9iYXNlNjQ=",
50
+ filename="test.txt",
51
+ )
52
+ self.assertEqual(result, {"id": 1, "result": "success"})
53
+ mock_decode_b64.assert_called_once_with("ZmFrZV9iYXNlNjQ=")
54
+ mock_upload.assert_called_once()
55
+ finally:
56
+ os.remove(tmp_path)
57
+
58
+ @patch("regscale.core.app.internal.file_uploads.File.upload_file_to_regscale")
59
+ @patch("regscale.core.app.internal.file_uploads.decode_base64_to_bytesio")
60
+ def test_upload_file_exception(self, mock_decode_b64, mock_upload):
61
+ mock_decode_b64.return_value = MagicMock(getvalue=lambda: b"fake_bytes")
62
+ mock_upload.side_effect = Exception("upload failed")
63
+ result = upload_file(
64
+ ssp_id=123,
65
+ parent_module="test_module",
66
+ file_path="fake_path",
67
+ filestring="ZmFrZV9iYXNlNjQ=",
68
+ filename="test.txt",
69
+ )
70
+ self.assertFalse(result)
71
+
72
+ @patch("regscale.core.app.internal.file_uploads.process_base64_tags_in_xml")
73
+ @patch("regscale.core.app.internal.file_uploads.upload_file")
74
+ @patch("regscale.core.app.internal.file_uploads.encode_file_to_base64")
75
+ def test_process_base64_in_xml(self, mock_encode_b64, mock_upload_file, mock_process_tags):
76
+ from regscale.core.app.internal.file_uploads import process_base64_in_xml
77
+
78
+ mock_process_tags.return_value = [
79
+ {"filename": "file1.txt", "base64": "b64str1"},
80
+ {"filename": "file2.txt", "base64": "b64str2"},
81
+ ]
82
+ mock_upload_file.side_effect = ["result1", "result2", "xml_result"]
83
+ mock_encode_b64.return_value = "xml_b64"
84
+ results = process_base64_in_xml(
85
+ regscale_id=123,
86
+ regscale_module="test_module",
87
+ file_path="fake.xml",
88
+ file_name="optional.xml",
89
+ )
90
+ self.assertEqual(results, ["result1", "result2", "xml_result"])
91
+ self.assertEqual(mock_upload_file.call_count, 3)
92
+
93
+ def test_process_base64_tags_in_xml(self):
94
+ from regscale.core.app.internal.file_uploads import process_base64_tags_in_xml
95
+
96
+ xml_content = """<root>
97
+ <base64 filename=\"file1.txt\">YmFzZTY0X2NvbnRlbnQx</base64>
98
+ <base64 filename=\"file2.txt\">YmFzZTY0X2NvbnRlbnQy</base64>
99
+ </root>"""
100
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".xml", mode="w", encoding="utf-8") as tmp:
101
+ tmp.write(xml_content)
102
+ tmp_path = tmp.name
103
+ try:
104
+ results = process_base64_tags_in_xml(tmp_path)
105
+ self.assertEqual(
106
+ results,
107
+ [
108
+ {"filename": "file1.txt", "base64": "YmFzZTY0X2NvbnRlbnQx"},
109
+ {"filename": "file2.txt", "base64": "YmFzZTY0X2NvbnRlbnQy"},
110
+ ],
111
+ )
112
+ finally:
113
+ os.remove(tmp_path)
114
+
115
+ @patch(
116
+ "regscale.models.regscale_models.file.File.upload_file_to_regscale",
117
+ return_value={"id": 42, "result": "success"},
118
+ )
119
+ def test_upload_file_to_regscale_success(self, mock_upload):
120
+ result = File.upload_file_to_regscale(
121
+ file_name="test.txt", parent_id=123, parent_module="test_module", file_data=b"fake_bytes", api=MagicMock()
122
+ )
123
+ self.assertEqual(result, {"id": 42, "result": "success"})
124
+ mock_upload.assert_called_once()
125
+
126
+ @patch("regscale.models.regscale_models.file.Api")
127
+ def test_upload_file_to_regscale_failure(self, mock_api):
128
+ mock_api_instance = mock_api.return_value
129
+ mock_api_instance.upload_file.side_effect = Exception("upload failed")
130
+ result = File.upload_file_to_regscale(
131
+ file_name="fail.txt",
132
+ parent_id=999,
133
+ parent_module="fail_module",
134
+ file_data=b"fail_bytes",
135
+ api=mock_api_instance,
136
+ )
137
+ self.assertFalse(result)
138
+
139
+ @patch("regscale.models.regscale_models.file.Api")
140
+ def test_download_file_from_regscale_to_memory(self, mock_api_class):
141
+ mock_api = mock_api_class.return_value
142
+ mock_api.config = {"domain": "https://test.com"}
143
+ mock_response = MagicMock()
144
+ mock_response.content = b"file content"
145
+ mock_api.get.return_value = mock_response
146
+
147
+ result = File.download_file_from_regscale_to_memory(
148
+ api=mock_api, record_id=123, module="test_module", stored_name="test.txt", file_hash="abc123"
149
+ )
150
+
151
+ self.assertEqual(result, b"file content")
152
+
153
+ @patch("regscale.models.regscale_models.file.Api")
154
+ def test_get_files_for_parent_from_regscale(self, mock_api_class):
155
+ mock_api = mock_api_class.return_value
156
+ mock_api.config = {"domain": "https://test.com"}
157
+ mock_response = MagicMock()
158
+ mock_response.json.return_value = [
159
+ {
160
+ "id": "1",
161
+ "trustedDisplayName": "test1.txt",
162
+ "trustedStorageName": "test1.txt",
163
+ "size": 100,
164
+ "fullPath": "/test1.txt",
165
+ }
166
+ ]
167
+ mock_api.get.return_value = mock_response
168
+
169
+ result = File.get_files_for_parent_from_regscale(parent_id=123, parent_module="test_module", api=mock_api)
170
+
171
+ self.assertEqual(len(result), 1)
172
+ self.assertIsInstance(result[0], File)
173
+
174
+ @patch("regscale.models.regscale_models.file.Api")
175
+ def test_delete_file(self, mock_api_class):
176
+ mock_api = mock_api_class.return_value
177
+ mock_app = MagicMock()
178
+ mock_app.config = {"domain": "https://test.com"}
179
+ mock_response = MagicMock()
180
+ mock_response.ok = True
181
+ mock_api.delete.return_value = mock_response
182
+
183
+ file_obj = File(
184
+ id="123", trustedDisplayName="test.txt", trustedStorageName="test.txt", size=100, fullPath="/test.txt"
185
+ )
186
+
187
+ result = File.delete_file(app=mock_app, file=file_obj)
188
+
189
+ self.assertTrue(result)
190
+
191
+ def test_determine_mime_type(self):
192
+ self.assertEqual(
193
+ File.determine_mime_type(".xlsx"), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
194
+ )
195
+ self.assertEqual(File.determine_mime_type(".nessus"), "text/xml")
196
+ self.assertEqual(File.determine_mime_type(".msg"), "application/vnd.ms-outlook")
197
+ self.assertIsNone(File.determine_mime_type(".unknown"))
198
+
199
+ gz_mime = File.determine_mime_type(".gz")
200
+ self.assertIn(gz_mime, ["application/gzip", "application/x-gzip"])
201
+
202
+ def test_file_model_creation(self):
203
+ file_data = {
204
+ "id": "123",
205
+ "trustedDisplayName": "test.txt",
206
+ "trustedStorageName": "test.txt",
207
+ "size": 1024,
208
+ "fullPath": "/test.txt",
209
+ }
210
+
211
+ file_obj = File(**file_data)
212
+
213
+ self.assertEqual(file_obj.id, "123")
214
+ self.assertEqual(file_obj.trustedDisplayName, "test.txt")
215
+ self.assertEqual(file_obj.size, 1024)
216
+
217
+ @patch("regscale.models.regscale_models.file.Api")
218
+ def test_get_files_for_parent_general_error(self, mock_api_class):
219
+ mock_api = mock_api_class.return_value
220
+ mock_api.config = {"domain": "https://test.com"}
221
+ mock_api.get.side_effect = Exception("General error")
222
+
223
+ with self.assertRaises(SystemExit):
224
+ File.get_files_for_parent_from_regscale(parent_id=123, parent_module="test_module", api=mock_api)
225
+
226
+ @patch("regscale.models.regscale_models.file.File._create_regscale_file")
227
+ @patch("regscale.models.regscale_models.file.Api")
228
+ def test_upload_file_to_regscale_no_file_created(self, mock_api_class, mock_create_file):
229
+ mock_create_file.return_value = None
230
+ mock_api = MagicMock()
231
+
232
+ result = File.upload_file_to_regscale(
233
+ file_name="test.txt", parent_id=123, parent_module="test_module", api=mock_api, file_data=b"test content"
234
+ )
235
+
236
+ self.assertFalse(result)
237
+
238
+ @patch("regscale.models.regscale_models.file.File._create_regscale_file")
239
+ @patch("regscale.models.regscale_models.file.Api")
240
+ def test_upload_file_to_regscale_no_id_in_response(self, mock_api_class, mock_create_file):
241
+ mock_api = mock_api_class.return_value
242
+ mock_api.config = {"domain": "https://test.com", "token": "test_token", "userId": "user123"}
243
+ mock_create_file.return_value = {
244
+ "fullPath": "/test.txt",
245
+ "trustedDisplayName": "test.txt",
246
+ "trustedStorageName": "test.txt",
247
+ "uploadDate": "2024-01-01",
248
+ "fileHash": "hash123",
249
+ "shaHash": "sha123",
250
+ "size": 100,
251
+ }
252
+
253
+ result = File.upload_file_to_regscale(
254
+ file_name="test.txt", parent_id=123, parent_module="test_module", api=mock_api, file_data=b"test content"
255
+ )
256
+
257
+ self.assertFalse(result)
258
+
259
+ @patch("regscale.models.regscale_models.file.File._create_regscale_file")
260
+ @patch("regscale.models.regscale_models.file.Api")
261
+ def test_upload_file_to_regscale_unsupported_mime_type(self, mock_api_class, mock_create_file):
262
+ mock_api = mock_api_class.return_value
263
+ mock_api.config = {"domain": "https://test.com", "token": "test_token", "userId": "user123"}
264
+ mock_create_file.return_value = {
265
+ "id": "file123",
266
+ "fullPath": "/test.txt",
267
+ "trustedDisplayName": "test.txt",
268
+ "trustedStorageName": "test.txt",
269
+ "uploadDate": "2024-01-01",
270
+ "fileHash": "hash123",
271
+ "shaHash": "sha123",
272
+ "size": 100,
273
+ }
274
+
275
+ with patch.object(File, "determine_mime_type", return_value=None):
276
+ result = File.upload_file_to_regscale(
277
+ file_name="test.txt",
278
+ parent_id=123,
279
+ parent_module="test_module",
280
+ api=mock_api,
281
+ file_data=b"test content",
282
+ )
283
+
284
+ self.assertFalse(result)
285
+
286
+ @patch("regscale.models.regscale_models.file.Tag")
287
+ def test_get_existing_tags_dict(self, mock_tag_class):
288
+ mock_tag1 = MagicMock()
289
+ mock_tag1.title = "tag1"
290
+ mock_tag1.id = "1"
291
+ mock_tag2 = MagicMock()
292
+ mock_tag2.title = "tag2"
293
+ mock_tag2.id = "2"
294
+ mock_tag_class.get_list.return_value = [mock_tag1, mock_tag2]
295
+
296
+ result = File.get_existing_tags_dict()
297
+
298
+ self.assertEqual(result, {"tag1": "1", "tag2": "2"})
299
+ mock_tag_class.get_list.assert_called_once()
300
+
301
+ @patch("regscale.models.regscale_models.file.TagMapping")
302
+ def test_process_tag_with_existing_tag(self, mock_tag_mapping_class):
303
+ mock_tag_mapping = MagicMock()
304
+ mock_tag_mapping_class.return_value = mock_tag_mapping
305
+ tags_dict = {"test_tag": "123"}
306
+
307
+ File.process_tag("test_tag", "file123", tags_dict)
308
+
309
+ mock_tag_mapping_class.assert_called_once_with(parentId="file123", parentModule="files", tagId="123")
310
+ mock_tag_mapping.create.assert_called_once()
311
+
312
+ @patch("regscale.models.regscale_models.file.File.get_existing_tags_dict")
313
+ @patch("regscale.models.regscale_models.file.File.process_tag")
314
+ def test_create_tag_mappings(self, mock_process_tag, mock_get_tags_dict):
315
+ mock_get_tags_dict.return_value = {"tag1": "1", "tag2": "2"}
316
+ mock_response = MagicMock()
317
+ mock_response.json.return_value = {"id": "file123", "tags": "tag1,tag2"}
318
+
319
+ File.create_tag_mappings(mock_response)
320
+
321
+ mock_get_tags_dict.assert_called_once()
322
+ self.assertEqual(mock_process_tag.call_count, 2)
323
+
324
+ @patch("regscale.models.regscale_models.file.Application")
325
+ def test_check_compression_file_not_found(self, mock_app_class):
326
+ mock_app = mock_app_class.return_value
327
+ mock_app.logger.debug = MagicMock()
328
+ mock_app.logger.warning = MagicMock()
329
+
330
+ file_data = b"test content"
331
+ result_path, result_size = File._check_compression(file_path="nonexistent.txt", file_data=file_data)
332
+
333
+ self.assertEqual(result_path, "nonexistent.txt")
334
+ import sys
335
+
336
+ expected_size = sys.getsizeof(file_data) / 1024
337
+ self.assertEqual(result_size, expected_size)
338
+
339
+ def test_compress_file(self):
340
+ with tempfile.NamedTemporaryFile(delete=False) as input_file:
341
+ input_file.write(b"test content for compression")
342
+ input_path = input_file.name
343
+
344
+ output_path = input_path + ".gz"
345
+
346
+ try:
347
+ result = File._compress_file(input_path, output_path)
348
+
349
+ self.assertEqual(result, output_path)
350
+ self.assertTrue(os.path.exists(output_path))
351
+ self.assertGreater(os.path.getsize(output_path), 0)
352
+ finally:
353
+ os.remove(input_path)
354
+ if os.path.exists(output_path):
355
+ os.remove(output_path)
356
+
357
+ @patch("regscale.models.regscale_models.file.Api")
358
+ def test_create_regscale_file_success(self, mock_api_class):
359
+ mock_api = mock_api_class.return_value
360
+ mock_api.config = {"domain": "https://test.com", "token": "test_token"}
361
+ mock_response = MagicMock()
362
+ mock_response.ok = True
363
+ mock_response.json.return_value = {
364
+ "id": "file123",
365
+ "fullPath": "/test.txt",
366
+ "trustedDisplayName": "test.txt",
367
+ "trustedStorageName": "test.txt",
368
+ "uploadDate": "2024-01-01",
369
+ "fileHash": "hash123",
370
+ "shaHash": "sha123",
371
+ }
372
+ mock_api.post.return_value = mock_response
373
+
374
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
375
+ tmp.write(b"test content")
376
+ tmp_path = tmp.name
377
+
378
+ try:
379
+ with patch("os.path.getsize", return_value=1024):
380
+ result = File._create_regscale_file(
381
+ file_path=tmp_path, parent_id=123, parent_module="test_module", api=mock_api
382
+ )
383
+
384
+ self.assertIsNotNone(result)
385
+ self.assertEqual(result["id"], "file123")
386
+ self.assertEqual(result["size"], 1024)
387
+ finally:
388
+ os.remove(tmp_path)
389
+
390
+ def test_create_regscale_file_zero_size(self):
391
+ mock_api = MagicMock()
392
+
393
+ with self.assertRaises(ValueError):
394
+ with patch("os.path.getsize", return_value=0):
395
+ File._create_regscale_file(
396
+ file_path="test.txt", parent_id=123, parent_module="test_module", api=mock_api
397
+ )
398
+
399
+ @patch("regscale.models.regscale_models.file.Api")
400
+ def test_create_regscale_file_api_failure(self, mock_api_class):
401
+ mock_api = mock_api_class.return_value
402
+ mock_api.config = {"domain": "https://test.com", "token": "test_token"}
403
+ mock_response = MagicMock()
404
+ mock_response.ok = False
405
+ mock_response.status_code = 400
406
+ mock_response.text = "Bad Request"
407
+ mock_api.post.return_value = mock_response
408
+
409
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
410
+ tmp.write(b"test content")
411
+ tmp_path = tmp.name
412
+
413
+ try:
414
+ with patch("os.path.getsize", return_value=1024):
415
+ result = File._create_regscale_file(
416
+ file_path=tmp_path, parent_id=123, parent_module="test_module", api=mock_api
417
+ )
418
+
419
+ self.assertIsNone(result)
420
+ mock_api.logger.warning.assert_called()
421
+ finally:
422
+ os.remove(tmp_path)
423
+
424
+ @patch("regscale.models.regscale_models.file.Tag")
425
+ def test_process_tag_nonexistent_tag(self, mock_tag_class):
426
+ mock_tag_mapping_class = MagicMock()
427
+ with patch("regscale.models.regscale_models.file.TagMapping", mock_tag_mapping_class):
428
+ tags_dict = {"existing_tag": "123"}
429
+
430
+ File.process_tag("nonexistent_tag", "file123", tags_dict)
431
+
432
+ mock_tag_mapping_class.assert_not_called()
433
+
434
+ @patch("regscale.models.regscale_models.file.File.get_existing_tags_dict")
435
+ @patch("regscale.models.regscale_models.file.File.process_tag")
436
+ def test_create_tag_mappings_no_id(self, mock_process_tag, mock_get_tags_dict):
437
+ mock_get_tags_dict.return_value = {"tag1": "1", "tag2": "2"}
438
+ mock_response = MagicMock()
439
+ mock_response.json.return_value = {"tags": "tag1,tag2"}
440
+
441
+ File.create_tag_mappings(mock_response)
442
+
443
+ mock_process_tag.assert_not_called()
444
+
445
+ def test_determine_mime_type_known_types(self):
446
+ with patch("mimetypes.types_map", {".txt": "text/plain"}):
447
+ result = File.determine_mime_type(".txt")
448
+ self.assertEqual(result, "text/plain")
449
+
450
+ def test_determine_mime_type_unknown_type(self):
451
+ with patch("mimetypes.types_map", {}):
452
+ with patch("logging.getLogger") as mock_logger:
453
+ mock_logger_instance = MagicMock()
454
+ mock_logger.return_value = mock_logger_instance
455
+
456
+ result = File.determine_mime_type(".unknown")
457
+
458
+ self.assertIsNone(result)
459
+ mock_logger_instance.warning.assert_called_once()
460
+
461
+ @patch("regscale.models.regscale_models.file.Api")
462
+ def test_create_regscale_file_no_response(self, mock_api_class):
463
+ mock_api = mock_api_class.return_value
464
+ mock_api.config = {"domain": "https://test.com", "token": "test_token"}
465
+ mock_api.post.return_value = None
466
+
467
+ with tempfile.NamedTemporaryFile(delete=False) as tmp:
468
+ tmp.write(b"test content")
469
+ tmp_path = tmp.name
470
+
471
+ try:
472
+ with patch("os.path.getsize", return_value=1024):
473
+ result = File._create_regscale_file(
474
+ file_path=tmp_path, parent_id=123, parent_module="test_module", api=mock_api
475
+ )
476
+ self.assertIsNone(result)
477
+ mock_api.logger.warning.assert_called_once()
478
+ finally:
479
+ os.remove(tmp_path)
480
+
481
+ @patch("regscale.models.regscale_models.file.Api")
482
+ def test_create_regscale_file_with_file_data(self, mock_api_class):
483
+ mock_api = mock_api_class.return_value
484
+ mock_api.config = {"domain": "https://test.com", "token": "test_token"}
485
+ mock_response = MagicMock()
486
+ mock_response.ok = True
487
+ mock_response.json.return_value = {
488
+ "id": "file123",
489
+ "fullPath": "/test.txt",
490
+ "trustedDisplayName": "test.txt",
491
+ "trustedStorageName": "test.txt",
492
+ "uploadDate": "2024-01-01",
493
+ "fileHash": "hash123",
494
+ "shaHash": "sha123",
495
+ }
496
+ mock_api.post.return_value = mock_response
497
+
498
+ file_data = b"test file content"
499
+ with patch("os.path.getsize", return_value=len(file_data)):
500
+ result = File._create_regscale_file(
501
+ file_path="test.txt", parent_id=123, parent_module="test_module", api=mock_api, file_data=file_data
502
+ )
503
+
504
+ self.assertIsNotNone(result)
505
+ self.assertEqual(result["id"], "file123")
506
+ self.assertEqual(result["size"], len(file_data))