regscale-cli 6.27.2.0__py3-none-any.whl → 6.27.3.0__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 (40) hide show
  1. regscale/_version.py +1 -1
  2. regscale/core/app/application.py +1 -0
  3. regscale/core/app/internal/control_editor.py +73 -21
  4. regscale/core/app/internal/login.py +4 -1
  5. regscale/core/app/internal/model_editor.py +219 -64
  6. regscale/core/login.py +21 -4
  7. regscale/core/utils/date.py +77 -1
  8. regscale/integrations/commercial/aws/scanner.py +4 -1
  9. regscale/integrations/commercial/synqly/query_builder.py +4 -1
  10. regscale/integrations/control_matcher.py +78 -23
  11. regscale/integrations/public/csam/csam.py +572 -763
  12. regscale/integrations/public/csam/csam_agency_defined.py +179 -0
  13. regscale/integrations/public/csam/csam_common.py +154 -0
  14. regscale/integrations/public/csam/csam_controls.py +432 -0
  15. regscale/integrations/public/csam/csam_poam.py +124 -0
  16. regscale/integrations/public/fedramp/click.py +17 -4
  17. regscale/integrations/public/fedramp/fedramp_cis_crm.py +271 -62
  18. regscale/integrations/public/fedramp/poam/scanner.py +74 -7
  19. regscale/integrations/scanner_integration.py +16 -1
  20. regscale/models/integration_models/cisa_kev_data.json +49 -19
  21. regscale/models/integration_models/synqly_models/capabilities.json +1 -1
  22. regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +35 -2
  23. regscale/models/integration_models/synqly_models/ocsf_mapper.py +41 -12
  24. regscale/models/platform.py +3 -0
  25. regscale/models/regscale_models/__init__.py +5 -0
  26. regscale/models/regscale_models/component.py +1 -1
  27. regscale/models/regscale_models/control_implementation.py +55 -24
  28. regscale/models/regscale_models/organization.py +3 -0
  29. regscale/models/regscale_models/regscale_model.py +17 -5
  30. regscale/models/regscale_models/security_plan.py +1 -0
  31. regscale/regscale.py +11 -1
  32. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/METADATA +1 -1
  33. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/RECORD +40 -36
  34. tests/regscale/core/test_login.py +171 -4
  35. tests/regscale/integrations/test_control_matcher.py +24 -0
  36. tests/regscale/models/test_control_implementation.py +118 -3
  37. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/LICENSE +0 -0
  38. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/WHEEL +0 -0
  39. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/entry_points.txt +0 -0
  40. {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.27.3.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  regscale/__init__.py,sha256=ZygAIkX6Nbjag1czWdQa-yP-GM1mBE_9ss21Xh__JFc,34
2
- regscale/_version.py,sha256=Lq40cZd2OT7sJZZWQh9y8KbuzbrUJbNhz2k2NIgwDVs,1198
3
- regscale/regscale.py,sha256=4LzcbkBxPh23cCLANVEEr6uNoZ0sebHec0N-VJm5_vA,31480
2
+ regscale/_version.py,sha256=TDfjUJGKm_DKWR346hYXsEe1aGpeyu_Zbob4p2aME5Q,1198
3
+ regscale/regscale.py,sha256=SiwZoh8r1ZfVqMluzI1czdvkqrtMePYkcB0eKuvLtf8,31702
4
4
  regscale/airflow/__init__.py,sha256=yMwN0Bz4JbM0nl5qY_hPegxo_O2ilhTOL9PY5Njhn-s,270
5
5
  regscale/airflow/click_dags.py,sha256=H3SUR5jkvInNMv1gu-VG-Ja_H-kH145CpQYNalWNAbE,4520
6
6
  regscale/airflow/click_mixins.py,sha256=BTwKWsEu6KVtlrzFbXpD_RuEpMzc-CSnCCySUzqzCgQ,3571
@@ -33,24 +33,24 @@ regscale/ansible/__init__.py,sha256=5l22v8ZPkIR5Yp8NvBZZU4TFdlJVaGtcCaZq_S1iD4I,
33
33
  regscale/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  regscale/core/decorators.py,sha256=YuX9VCbCJh76qlc_6ungu0nD4VT1VsV2spXH_bsDTfY,894
35
35
  regscale/core/lazy_group.py,sha256=S2-nA5tzm47A929NOTqGkzrzKuZQDlq2OAPbNnG1W1Q,2046
36
- regscale/core/login.py,sha256=-8vy1HVAtv1iARnZh6uzYtwmx8VFYPwLYR0QAf1ttCk,2714
36
+ regscale/core/login.py,sha256=DsGgAxWlsiNJnWfERoOTlNQ-O7I07MQ6HdUHFrkbAXQ,3511
37
37
  regscale/core/app/__init__.py,sha256=nGcCN1vWBAnZzoccIlt0jwWQdegCOrBWOB7LPhQkQSs,96
38
38
  regscale/core/app/api.py,sha256=yJhlKICpy8irEcZaFWq36_Bi2I_VcQ7Fh_LtGm0-H98,23632
39
- regscale/core/app/application.py,sha256=vN2ppgS9sNXg7KAYt3RtQKErTckln1aUADFnRDXKN30,33141
39
+ regscale/core/app/application.py,sha256=UPAag-VGTv2VOzXx5a1bCJmv8eCgHcx3yhNAo9etNVk,33181
40
40
  regscale/core/app/logz.py,sha256=8AdBKmquv45JGi5fCMc38JqQg6-FpUONGmqfd5EGwrI,2583
41
41
  regscale/core/app/internal/__init__.py,sha256=rod4nmE7rrYDdbuYF4mCWz49TK_2r-v4tWy1UHW63r0,4808
42
42
  regscale/core/app/internal/admin_actions.py,sha256=hOdma7QGwFblmxEj9UTjiWWmZGUS5_ZFtxL2qZdhf-Q,7443
43
43
  regscale/core/app/internal/assessments_editor.py,sha256=UozEaQR1v3eXbkFgOY11CkjMLEAF27ej5vlMQ4O9XVA,31477
44
44
  regscale/core/app/internal/catalog.py,sha256=svBAgFZaGrkNHh2gZEo1ex2vdjllAIc4940soGykHOc,11088
45
45
  regscale/core/app/internal/comparison.py,sha256=eRnCKhq3Kyzh-aUgD6phQH0eONCSCkl5Vz0dr2ymDpQ,16720
46
- regscale/core/app/internal/control_editor.py,sha256=bvltPfUJERVcPW14njFzMHLzb4KLcXlmtAJMRDXegXI,19338
46
+ regscale/core/app/internal/control_editor.py,sha256=aLOScsQadNwL0ekv_NJuj5Xt-PMWygmkEu6Lploo-Gk,20997
47
47
  regscale/core/app/internal/encrypt.py,sha256=yOEMDDlpI0Sc0LkoeCtXbypnOF8cxoDrzKRU5d3POFQ,5927
48
48
  regscale/core/app/internal/evidence.py,sha256=yXHBWWYfo471oJ9jTgGkWDtiB0wsVuq6AQ2zQEWFP6E,68006
49
49
  regscale/core/app/internal/file_uploads.py,sha256=EfQ4ViJBHzU9bxnFunK3ahA6T9A6pnA-Jk2NrtgmrQY,4776
50
50
  regscale/core/app/internal/healthcheck.py,sha256=ef4Mwk19vi71bv-Xkny5_EGG1UXTbCO5dvEIzHyyfVA,2010
51
- regscale/core/app/internal/login.py,sha256=AKmZq9kxwpNV3LnAGwtdI2dn0qh1SG_mZ7OtIRSce1Q,10968
51
+ regscale/core/app/internal/login.py,sha256=CDuaH5U27jm4Tr2s7-VVUsA8GxaKuwB181eIjplCZ4k,11103
52
52
  regscale/core/app/internal/migrations.py,sha256=wHIzb1uglLVOXawnb-K3Yt70Z5QyfQYb8ZZOMDrNRU4,7983
53
- regscale/core/app/internal/model_editor.py,sha256=0sxfg92TJYyECU9KwgHooXeY3ZdaF2i5gGWe1gButFY,61696
53
+ regscale/core/app/internal/model_editor.py,sha256=ii8qKvAT6lAjeWqkJoDmUya-eARiFfE2vy18aldRqnE,68316
54
54
  regscale/core/app/internal/poam_editor.py,sha256=3PtpSMpV7bqKFuTHD2ACYcTyB3EEtTRKuYv-XArjd0A,22929
55
55
  regscale/core/app/internal/set_permissions.py,sha256=BfdzT-2l2bBFKgho4lwh5IhcqoDTZbLyxNyliGW-Yv8,6470
56
56
  regscale/core/app/internal/workflow.py,sha256=SpgYk1QyzdilVLOK1fFzaKhdLspumaugf5VezgboxhQ,4007
@@ -94,7 +94,7 @@ regscale/core/static/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
94
94
  regscale/core/static/regex.py,sha256=KLg-do2oPuUD6bQG9usqqSy5sxqlSEAEuUUbGVkZ6eU,384
95
95
  regscale/core/utils/__init__.py,sha256=Eyvc210t-KRqvTcV5DNWRjKO99CdWy_dC57wfggFWcw,3876
96
96
  regscale/core/utils/click_utils.py,sha256=y6vAbaPoT0Abb8siS1tvJxJQTm4sbWQTeq5nTDIgBtI,375
97
- regscale/core/utils/date.py,sha256=yGte1ttWRwKRKfU0LT5yPNfr62xn5YnDo4zMgAhua7k,10114
97
+ regscale/core/utils/date.py,sha256=q5uHQ-eoiAUxH9EEGTDkSFukbFE_jjYw3k-po9MtcIc,12853
98
98
  regscale/core/utils/graphql.py,sha256=oXGBcAuDa0uasMnD4CokIzzKKa-IgExdKXLwtaK2_tA,8386
99
99
  regscale/core/utils/urls.py,sha256=ZcU9OJqDmVQXgu6BrLESIp2KMkkUuzTZZ_wHsZMzfA4,687
100
100
  regscale/dev/__init__.py,sha256=wVP59B1iurp36ul8pD_CjmunJLHOdKWWodz1r5loNvw,190
@@ -112,12 +112,12 @@ regscale/integrations/__init__.py,sha256=Sqthp3Jggo7co_go380cLn3OAb0cHwqL609_4QJ
112
112
  regscale/integrations/api_paginator.py,sha256=73rjaNM9mGv8evHAeoObXEjZPg-bJuGPo60ewCLEil8,33192
113
113
  regscale/integrations/api_paginator_example.py,sha256=lEuYI-xEGcjnXuIzbCobCP0YRuukLF0s8S3d382SAH4,12119
114
114
  regscale/integrations/compliance_integration.py,sha256=_KzzmUGoXvA2o4nXR3jzdd4-yO56nSn2fMDLNzRgJRI,91699
115
- regscale/integrations/control_matcher.py,sha256=vZjzQz2NhFwP6in-jLDQeBGnigQ78e2mcSaKumkUrZI,14595
115
+ regscale/integrations/control_matcher.py,sha256=g2adPda4AwKlpOe3R_GD-zPQY4T8n9ioSAzsNOQfjs0,16706
116
116
  regscale/integrations/due_date_handler.py,sha256=EAKSOsqpj5CpFQphzvkYcHgDrJ4BQlKayDGeiZVUvWo,14122
117
117
  regscale/integrations/integration_override.py,sha256=HjYBCuvNpU3t3FptaqYAkdexLFOZBAFrFE9xU0RD1Nc,5867
118
118
  regscale/integrations/jsonl_scanner_integration.py,sha256=l8nq_T3rE1XX-6HxrNHm3xzxCNWbIjxQvGMdtZWs7KQ,57003
119
119
  regscale/integrations/milestone_manager.py,sha256=td5m-2LIUkHY7S3rtGwj-SLLuSGN4aiJOPAiKRcE4A4,10779
120
- regscale/integrations/scanner_integration.py,sha256=VcHldJCmSIy0oGL0G5tF6ivnrLAUuhGgWisC_F24G3g,194028
120
+ regscale/integrations/scanner_integration.py,sha256=2l3h0MV--FMGeo7ShmyaLo7aylNpGnbZTNmk-LyVH_w,194725
121
121
  regscale/integrations/variables.py,sha256=MfQ34WuYVN5437A9sZ2ssHRkA3gFhMHfk1DVasceGmY,2336
122
122
  regscale/integrations/commercial/__init__.py,sha256=9IWhVfJec2O67JJnFs5T0cM-nSxadgOdl7jcIGXnJDE,14532
123
123
  regscale/integrations/commercial/ad.py,sha256=YXSmK8vRf6yi2GnREGa5GrE6GelhFrLj44SY8AO1pK0,15509
@@ -145,7 +145,7 @@ regscale/integrations/commercial/aqua/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
145
145
  regscale/integrations/commercial/aqua/aqua.py,sha256=bdwqyir9ztGRwqZlWBQIHjtBEo2utSy5HJoraAx823I,2656
146
146
  regscale/integrations/commercial/aws/__init__.py,sha256=Pii3CMGvIwZnTSenuvDvuybWXBtIRdGyvF02sykzg1A,203
147
147
  regscale/integrations/commercial/aws/cli.py,sha256=Q2QlUcbYRzZzg9VZ5RDOTdVkkWc4UFYX7f5cMNlOZMY,14853
148
- regscale/integrations/commercial/aws/scanner.py,sha256=2XtHT3En5VoFYt-qGnIsNenThofZHkzC3fbJwHA6gPI,56765
148
+ regscale/integrations/commercial/aws/scanner.py,sha256=Zt7Om-vNqNGxIkfCrXz3pskhTVlX_NQD32kYyM7fRMs,56866
149
149
  regscale/integrations/commercial/aws/inventory/__init__.py,sha256=nBWBRs_lTbp3tfCcnmN855qQpnXtwyJ5miTXlD7Uhcs,4302
150
150
  regscale/integrations/commercial/aws/inventory/base.py,sha256=KL1Ntz0h0WGDu84LQf3y92uLl9a0sl4yIFi6-ZIFAMI,2068
151
151
  regscale/integrations/commercial/aws/inventory/resources/__init__.py,sha256=wP8TMIixWGCn2rBNFW6XzhME-xO8kpxi9edMUJgpso4,523
@@ -222,7 +222,7 @@ regscale/integrations/commercial/stigv2/stig_integration.py,sha256=-UlfL0BBI3jFG
222
222
  regscale/integrations/commercial/synqly/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
223
  regscale/integrations/commercial/synqly/assets.py,sha256=Lwv_qVuQVwZTBWJuJjyjdhiYc8LxUJA_SN6_1_LfczI,8145
224
224
  regscale/integrations/commercial/synqly/edr.py,sha256=4EQSI2-5QnaWXh1idhndToFDOHOb3xycWAdc8NY4Auk,2836
225
- regscale/integrations/commercial/synqly/query_builder.py,sha256=1MAheCLG_3zUkvDeXbnCFEBybbG09OV-vUtBD0GLx0o,19306
225
+ regscale/integrations/commercial/synqly/query_builder.py,sha256=-wEIGpNihHqB0Snf7AYm-ULoaGzAujApZrv-pRsORV0,19434
226
226
  regscale/integrations/commercial/synqly/ticketing.py,sha256=akucc9Ok4cTcivH_rmG927WJetJDhZ0L4IF27OC_KOE,8352
227
227
  regscale/integrations/commercial/synqly/vulnerabilities.py,sha256=R9n_2AfB_CVKEza7MQ92YNdw1r36_rTvLzNHnQkpHvo,13623
228
228
  regscale/integrations/commercial/tenablev2/__init__.py,sha256=UpSY_oww83kz9c7amdbptJKwDB1gAOBQDS-Q9WFp588,295
@@ -280,13 +280,17 @@ regscale/integrations/public/nist_catalog.py,sha256=lHevdsSBTwwVzynJl_ckCyQ4cFOY
280
280
  regscale/integrations/public/oscal.py,sha256=GcPqRQqCmijCp7TmjBG4303YcJ7U4hfu6KiFSb9QC7Y,72675
281
281
  regscale/integrations/public/otx.py,sha256=i6mukISHLYmFJkxkkxhTkqtgcmXioZ00xLQ9YMg2Yzo,5401
282
282
  regscale/integrations/public/csam/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
283
- regscale/integrations/public/csam/csam.py,sha256=yCdaqphyK__v7ws1dtX4VN8Yx1m2futcfDG-kdibCdQ,40350
283
+ regscale/integrations/public/csam/csam.py,sha256=obq0oPPf_uZ8d8u6LdMSSJ7s9zX5AKfSwDZoWQLfkng,33303
284
+ regscale/integrations/public/csam/csam_agency_defined.py,sha256=e8FKwLCMyhIs83Cy_Np3ghuxXe_A1dZDfZwVi70Kt4M,6606
285
+ regscale/integrations/public/csam/csam_common.py,sha256=LiP20trTV2fkfgGCs9nBSjiWBqJosSV-LxfdOGDLBjg,5141
286
+ regscale/integrations/public/csam/csam_controls.py,sha256=rXUFzxlnmqRXE3iN-a3Q5byN6s9kuwREgKtJjovDqKs,15008
287
+ regscale/integrations/public/csam/csam_poam.py,sha256=VXyEQf-gamThqcnbXpyNQcIY6pp7FKz2sA2VfjfwZgc,4422
284
288
  regscale/integrations/public/fedramp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
285
289
  regscale/integrations/public/fedramp/appendix_parser.py,sha256=u3Q_NHxAvYTQ1RAr1T-y3hOfqcFnkLnTmJoWnndrzeA,38281
286
- regscale/integrations/public/fedramp/click.py,sha256=kacrGQ0D4L2rfxWd3KMsES_l96lL-O-oZWv_e8PfOlI,16795
290
+ regscale/integrations/public/fedramp/click.py,sha256=hb2HkoX6taCjVT12E1kMf8-PQ-vmL_GjcRhBKxeJD2c,17420
287
291
  regscale/integrations/public/fedramp/components.py,sha256=z6PMObm-kjRR42bT04EfnjisrEULfXlwxb7576uuMmY,27010
288
292
  regscale/integrations/public/fedramp/docx_parser.py,sha256=9QP4GoPxv23A553fXrz2Tvvfci8454re3XoWgC58YwE,10989
289
- regscale/integrations/public/fedramp/fedramp_cis_crm.py,sha256=5yOOszmC4fo1wmCZ8yXnsSSnp7X_qDRE_SWgq8UMb5k,70526
293
+ regscale/integrations/public/fedramp/fedramp_cis_crm.py,sha256=s-GqxVTvNzueZmvKaHS5GvrShC7JV7pSbfSBTvtfg1A,79819
290
294
  regscale/integrations/public/fedramp/fedramp_common.py,sha256=Mdy3_WdCEcTwSXEEKXiODmr2YJTWcTg6jfyWZJWfruQ,115406
291
295
  regscale/integrations/public/fedramp/fedramp_docx.py,sha256=eKkRwfcIi4aHJp4ajKDUGJECItwrZwYfCiKzmfB2W1Q,13703
292
296
  regscale/integrations/public/fedramp/fedramp_five.py,sha256=oaLcbTTDfm1korv4fmVrMfZzmgoOyVMQV2CK1d_R3-g,96739
@@ -315,7 +319,7 @@ regscale/integrations/public/fedramp/models/__init__.py,sha256=SPtfXUaVhdehAeL8r
315
319
  regscale/integrations/public/fedramp/models/leveraged_auth_new.py,sha256=MIJ7pMYaPdVRIgMZQQ4VLlq3IB5bYOsaRJSfeRORjC4,6775
316
320
  regscale/integrations/public/fedramp/models/poam_importer.py,sha256=UP98NOwzmCgN7666q1IgiVrwfPyXbCeCalDQmXctic8,20993
317
321
  regscale/integrations/public/fedramp/poam/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
318
- regscale/integrations/public/fedramp/poam/scanner.py,sha256=M15Mx6xC1IjSbJ4ZHXjF9nZvJRlAH8FrTX-tvhBNZuM,34134
322
+ regscale/integrations/public/fedramp/poam/scanner.py,sha256=mYuXZvIPEoCtaHVa7PmRfYl6l2Gr5shhZTlfabwPcns,37341
319
323
  regscale/integrations/transformer/__init__.py,sha256=XFmkvjPjpZkQPknz0NEC0pQsWA2JNtPygbeUCf_b5jk,484
320
324
  regscale/integrations/transformer/data_transformer.py,sha256=J2FlY1vqPVzVafE4AwjJZvuN_rmsg4xP6qZjNqQtBt8,15407
321
325
  regscale/integrations/transformer/mappings/__init__.py,sha256=Pp6Qb0dVtr0ehIujmSbNLzQy2nVogLajiDfP4XY_7-w,247
@@ -326,7 +330,7 @@ regscale/models/email_style.css,sha256=d8PlsCiOxmmkp2Qc7T4qI9Ha5mT12Jn9kRBMOk2xx
326
330
  regscale/models/hierarchy.py,sha256=XnQ-pjE3LKViwRQpxdCEU0TWBGzMJo1MqWgbEJgumAU,241
327
331
  regscale/models/inspect_models.py,sha256=oRJnLeeAUYIbYXsbPKNpMCyazxQnyH5r-2XxVc5Ih9c,2521
328
332
  regscale/models/locking.py,sha256=r-nLQDgLI28F5g9vY7WOLj18syzWXJiqhFpDh43Fur4,3348
329
- regscale/models/platform.py,sha256=joM423jBiS4rDfQALFWfkOR75ab-FStgvGPpKe8fV4g,4188
333
+ regscale/models/platform.py,sha256=HN6ex1p31-1dY-WgrFPzC0zOqUS0AMdoFTuLSDfjvS8,4312
330
334
  regscale/models/app_models/__init__.py,sha256=0V4Em8RqK83EZeMIa3tm_sDh9yOS7mzvKF01v-kJug0,219
331
335
  regscale/models/app_models/catalog_compare.py,sha256=gLD8ti933nW70FcGlx6gp0Lbdo8cFnKky7JkRFAKfOU,7557
332
336
  regscale/models/app_models/click.py,sha256=2kZuBOpHFjpFKtI7rT_ht26G9bjHL_EUUoYlLC-O3B4,9961
@@ -341,7 +345,7 @@ regscale/models/integration_models/azure_alerts.py,sha256=2etrpvcxa7jVQrc98bJlVG
341
345
  regscale/models/integration_models/base64.py,sha256=sxV6O5qY1_TstJENX5jBPsSdQwmA83-NNhgJFunXiZE,570
342
346
  regscale/models/integration_models/burp.py,sha256=FBEBkH3U0Q8vq71FFoWnvgLRF5Hkr9GYmQFmNNHFrVk,16932
343
347
  regscale/models/integration_models/burp_models.py,sha256=UytDTAcCaxyu-knFkm_mEUH6UmWK3OTXKSC9Sc6OjVs,3669
344
- regscale/models/integration_models/cisa_kev_data.json,sha256=g9yH6zg8DARdu4A1E4VvQJ5pGGffuCZRpsd2RkhwjGY,1306997
348
+ regscale/models/integration_models/cisa_kev_data.json,sha256=MrdJwSzF2H1u351GL86g0uJriXERdzl-FrBSesO3BPs,1309009
345
349
  regscale/models/integration_models/defender_data.py,sha256=jsAcjKxiGmumGerj7xSWkFd6r__YpuKDnYX5o7xHDiE,2844
346
350
  regscale/models/integration_models/defenderimport.py,sha256=Ze4kgwns-IYPyO7sBjEzW8PXWlxwU-DAo2fIyRcTC3k,6242
347
351
  regscale/models/integration_models/drf.py,sha256=Aq7AdLa_CH97NrnR-CxaFI22JjVN9uCxVN7Z-BBUaNU,18896
@@ -372,10 +376,10 @@ regscale/models/integration_models/flat_file_importer/__init__.py,sha256=8RNe5LU
372
376
  regscale/models/integration_models/sbom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
373
377
  regscale/models/integration_models/sbom/cyclone_dx.py,sha256=0pFR0BWBrF5c8_cC_8mj2MXvNOMHOdHbBYXvTVfFAh8,4058
374
378
  regscale/models/integration_models/synqly_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
375
- regscale/models/integration_models/synqly_models/capabilities.json,sha256=oV1EzsM5z2abuVWhoxcgJ7Sg1mT6DQ7sNtJPbYwS330,442978
379
+ regscale/models/integration_models/synqly_models/capabilities.json,sha256=xczk-CO5iDiLbaapaXnvMVcouhte24plnimrCbk6c1g,446333
376
380
  regscale/models/integration_models/synqly_models/connector_types.py,sha256=8nxptkTexpskySnmL0obNAff_iu_fx6tJ7i1-4hJvao,461
377
381
  regscale/models/integration_models/synqly_models/filter_parser.py,sha256=8rdnHH7gW1A_uWRTexZXzCH-HzRVy5nlvFgtc7ztcsQ,12160
378
- regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=3M1O8yz0jBRav30lK8BU1xUL5STixetRSpIp5bWhRzg,18746
382
+ regscale/models/integration_models/synqly_models/ocsf_mapper.py,sha256=OlheLLAQ5_kKipo6JUdfmqvPgMXdOy0bcjAtPu56cMk,19907
379
383
  regscale/models/integration_models/synqly_models/param.py,sha256=Xt5Zm6lC_VkLj7LF2qXo72TJZHysqttsp5ai0NCf1po,2643
380
384
  regscale/models/integration_models/synqly_models/synqly_model.py,sha256=RPxieh3r9dVdkt7IliiNEqEqvhbXv3UFuEEZ4-MNqGc,37965
381
385
  regscale/models/integration_models/synqly_models/tenants.py,sha256=kewIZw-iv18bNXJGG3ghwuFJ4CK5iXQhn_x2-xvV0iM,1078
@@ -383,11 +387,11 @@ regscale/models/integration_models/synqly_models/connectors/__init__.py,sha256=J
383
387
  regscale/models/integration_models/synqly_models/connectors/assets.py,sha256=HHNIAVh5pRuJe8sStqhFEc6VnX2wT0FcY5178nbQgkQ,3705
384
388
  regscale/models/integration_models/synqly_models/connectors/edr.py,sha256=kio3uoEYubCHretpDOJqxdwmzid1IzbVYz0BF64zeL0,5547
385
389
  regscale/models/integration_models/synqly_models/connectors/ticketing.py,sha256=yRBuCkRAVfa_C91r3WqJ9gxrQsoD0qV9cY48YXpJl70,25358
386
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=7fsPHtWSrHxlqAXGURvQ4VWunmAs-acz7O8ABHshdBw,8240
390
+ regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py,sha256=UJr9t9qdOWXwJk8ZiMT4Y6QLYYuyen3NO6nHhGLcQJU,9763
387
391
  regscale/models/integration_models/tenable_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
388
392
  regscale/models/integration_models/tenable_models/integration.py,sha256=lplL8zmjTFuhLreW-4y7G1fiCOBgzNAaATq800jgTQc,10271
389
393
  regscale/models/integration_models/tenable_models/models.py,sha256=dmG7btkN4YkDWwnfW5Ldc3tWEAGjPiaRgJjrqMOkPEU,15846
390
- regscale/models/regscale_models/__init__.py,sha256=gOGDxUUaWQ--0Kc3WmeApjeNzcBxGdBHHXrrlZ6KEpA,2602
394
+ regscale/models/regscale_models/__init__.py,sha256=f36bxlmGVy3WU1pWfnKGBU-j7a9-Ki1f13vnZFC5WH4,2719
391
395
  regscale/models/regscale_models/assessment.py,sha256=ekzNlcsfDGBu97PMCi7hBRGbzVgxk7Ij0RfrdGh1Rfw,20440
392
396
  regscale/models/regscale_models/assessment_plan.py,sha256=qo2YA5ckSbUKDHnC_2BUc2I9kMTje9Gq-qTCXqvEKCY,1716
393
397
  regscale/models/regscale_models/assessment_result.py,sha256=K48yjYKwgY1-d_Y3aQUDcCvaqcTIVYdbKV5Wgicf4Ts,1283
@@ -402,10 +406,10 @@ regscale/models/regscale_models/checklist.py,sha256=GM15N9krNmKNDJnOgtSDRlUTBVwY
402
406
  regscale/models/regscale_models/classification.py,sha256=kz1TxaxnqEwAS3mF8jTH7wbu6EQRZPZqGwxlXb-QEw0,775
403
407
  regscale/models/regscale_models/comment.py,sha256=EJtnk04JcyFUYeiVAHTPkoZuS8XndgmCr8KaprrywRo,1555
404
408
  regscale/models/regscale_models/compliance_settings.py,sha256=F2q7OQEgYK-HrPmDHMcV-6ywzrjnBnU5KGG3StVgK3E,4902
405
- regscale/models/regscale_models/component.py,sha256=Zbl-glM2WYtDRKtnQSyhXRDY9fqBTSSGz_2pMkAsawg,14196
409
+ regscale/models/regscale_models/component.py,sha256=zTE8JGL5ft0TbneuWfPYULXgLzF4mvdyiz3kE5CoYSw,14193
406
410
  regscale/models/regscale_models/component_mapping.py,sha256=g0cbbW4X49SDdlB_YtKMrP4eiK9OkrJqiut0ucdyVDA,2162
407
411
  regscale/models/regscale_models/control.py,sha256=mO46F1IfiXnLSb3YhylaS3SyjtT51s-r8b3hjix9Gbc,1072
408
- regscale/models/regscale_models/control_implementation.py,sha256=oLDypbjM1yi4OkkN5FdeAUo7UFoQ-b-eISl_scyNc1I,57484
412
+ regscale/models/regscale_models/control_implementation.py,sha256=VRCLginT2sIO8d4KmCRjFaFDQyD8S43x5KWTq0z1Y5Y,58505
409
413
  regscale/models/regscale_models/control_objective.py,sha256=qGh8OtATjjc4JS-3bC1AX6TbgtRtz-I0dckbuZ2RzVo,9496
410
414
  regscale/models/regscale_models/control_parameter.py,sha256=5VVkbVZTb2Hzy_WiybU2JtrvhQp8DLSWxRcbSKxktiI,3499
411
415
  regscale/models/regscale_models/control_test.py,sha256=FG-fLS9JJf8__a84W2LtBXtEjzOH9iq2EO949vBx3eY,949
@@ -442,7 +446,7 @@ regscale/models/regscale_models/milestone.py,sha256=KNd9Ce4bBb6FuUnol0gwwhow5d9I
442
446
  regscale/models/regscale_models/module.py,sha256=a7lalHmVTQ04ZILnJxuFWdHYDtyusBMTtonD4ICL-Wc,7272
443
447
  regscale/models/regscale_models/modules.py,sha256=yeva_tct88o2NFt93_zmqUcXZ3LucVbAv5FvQPru3cQ,8551
444
448
  regscale/models/regscale_models/objective.py,sha256=aJIpmkZ-NscqV2y8SGB4HYzm615b6mklyHnW9bL2ljk,249
445
- regscale/models/regscale_models/organization.py,sha256=E3Y5bwtgaIRL4rbKxU3DyfFVYUzP3d-1umG_CIUG3gE,714
449
+ regscale/models/regscale_models/organization.py,sha256=xNnpVbdRH92r34QIs5sMGm0EfPskZbjL-mcgSko3t44,812
446
450
  regscale/models/regscale_models/parameter.py,sha256=IEOVGaTUxRVNfwc6vN_y6eN45P5R1C4O4mz3uukiCSA,3915
447
451
  regscale/models/regscale_models/policy.py,sha256=IQ-niE1PP8L2OavYfOQQsvSInw1sw371mkJrGFyWZ94,2382
448
452
  regscale/models/regscale_models/ports_protocol.py,sha256=RGdXdNTn2C_elWPBZxwu7cs8v24oSgTiTjPnLk_tCiI,2347
@@ -457,7 +461,7 @@ regscale/models/regscale_models/questionnaire.py,sha256=QMSXfNpSoaS8tkeo80C7OWLj
457
461
  regscale/models/regscale_models/questionnaire_instance.py,sha256=1LgGTwFACmWx2xOOqUKhAUOms4_3L6NZySzuteg0_sI,8241
458
462
  regscale/models/regscale_models/rbac.py,sha256=ulT9BzOpYNNVlBVfOmreGDTTAgzkAY5Si2rQhhIcUmY,5302
459
463
  regscale/models/regscale_models/reference.py,sha256=P_7jT6H-NZIa7TyH3j98N-ZHlB6FsjpZVRZCCpms-D4,3253
460
- regscale/models/regscale_models/regscale_model.py,sha256=lVmwg65AsWg_0BbpurEp2T7-c-t4CL9mrD-2NPYKqoQ,76446
464
+ regscale/models/regscale_models/regscale_model.py,sha256=nD34_o9BvLeHQwW8mvJr230H0jdURMHQ0_yATvYuUlI,77359
461
465
  regscale/models/regscale_models/requirement.py,sha256=-8PnMbuWAZHol5X1w-fzm-moD784Et0oevSVbz6xLhU,767
462
466
  regscale/models/regscale_models/risk.py,sha256=lZFDYPpTt0aEYCrYz5FBKk1Y4y2CKXYU1A8eEKT3zzg,8661
463
467
  regscale/models/regscale_models/risk_issue_mapping.py,sha256=j6uR0x6xymJ0BsIwgnadeUQDshHNhU3VnpyItZp4dc4,2393
@@ -466,7 +470,7 @@ regscale/models/regscale_models/sbom.py,sha256=UYS3lBizGqz7A7vNPYBYzpL8PWIaXLl7Z
466
470
  regscale/models/regscale_models/scan_history.py,sha256=o4e9P2rQlqlLj4mbgSPX44jutTJo1nocI1DDXyWyf6w,16741
467
471
  regscale/models/regscale_models/search.py,sha256=rPbFDCnnBRHY5JJv9Ev3_6GjMlkdhUAsaUzC97eE2Ys,1015
468
472
  regscale/models/regscale_models/security_control.py,sha256=GJEMkIh6IDX7Gs_z7ppmm0hqiXjC5qSbSYRYt85wOUg,6365
469
- regscale/models/regscale_models/security_plan.py,sha256=Gccun2-rBf4SgOHGE1AJCNXFCEf_XO7oOvMJWB5qe3w,8676
473
+ regscale/models/regscale_models/security_plan.py,sha256=BrqoPG8ZFqfwJuw6wgWzkkH5aytvk1Zk1GGxSsaIT0k,8729
470
474
  regscale/models/regscale_models/software_inventory.py,sha256=FRAIfoUlS0kaX1HQRDyV5q4yxwRHilXbS52NSj6exo0,5555
471
475
  regscale/models/regscale_models/stake_holder.py,sha256=JIuDTIky_3acDl-NOMwylTHkppN38JgPDZ1A6wM-BGE,1956
472
476
  regscale/models/regscale_models/stig.py,sha256=y-PQuGg3pwDTfsNZGW6anaNAjIZBQoNe7GOLMiT5zfw,26329
@@ -529,7 +533,7 @@ tests/regscale/test_about.py,sha256=32YZC8XJW5QkIYIfwEVGIdIxQNUIbyzn3OzVcX_5X24,
529
533
  tests/regscale/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
530
534
  tests/regscale/core/test_api.py,sha256=25AsIT-jg8SrlkPeynUwwm4PvTOrHcRO2Ba_omnNLUY,7512
531
535
  tests/regscale/core/test_app.py,sha256=wvxpp5Wyag2T5-LmPZL02yrYiH8tedVSRle8RhrlB38,42380
532
- tests/regscale/core/test_login.py,sha256=Kl7ySS8JU7SzhmupaDexeUH8VOMjtMRJvW8-CimxHqU,1166
536
+ tests/regscale/core/test_login.py,sha256=xHQoXjwcALhhJEhpo3A5kmv91-SGje5OYEnTDBtmjXo,6759
533
537
  tests/regscale/core/test_logz.py,sha256=Yf6tAthETLlYOEp3hee3ovDw-WnZ_6fTw3e1rjx4xSw,2621
534
538
  tests/regscale/core/test_sbom_generator.py,sha256=lgzo1HRbkNIIDZIeKiM2JbbIYQsak0BpU0GlvbrcexM,2935
535
539
  tests/regscale/core/test_validation_utils.py,sha256=5GHQfSVEr3f1HzEatI5CyCgGriyc-OPyKbc1YQ9zRjI,5464
@@ -537,7 +541,7 @@ tests/regscale/core/test_version.py,sha256=q8F2ERXxdToXbYxfOcP9f6lkUYaxF4jEmsPUm
537
541
  tests/regscale/core/test_version_regscale.py,sha256=9DA1hFltt7pSWdFb3wP2bL3t4hAHsojoHvs1bolUjUw,2052
538
542
  tests/regscale/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
539
543
  tests/regscale/integrations/test_api_paginator.py,sha256=42-F8FMkJwkZ1Xlsj7YYVyOb6-rbxwI4F4H6Y4ZI9jA,18973
540
- tests/regscale/integrations/test_control_matcher.py,sha256=ff-1vZmOBZKErZqd6-M842TQhGxgSS82_BgFszsC5JA,58191
544
+ tests/regscale/integrations/test_control_matcher.py,sha256=OX5iSgEhY7Da9CvUoDVplOqTsNf5ZGQ0CBmLkSDhXbg,59182
541
545
  tests/regscale/integrations/test_control_matching.py,sha256=lejjVlnNA6aX2e4qgMGFpvEGG-ofzepyjeArax9J8aQ,4593
542
546
  tests/regscale/integrations/test_integration_mapping.py,sha256=cXfWuE1h5Wrs-Nb--d83v0fllMQOs_IxYxquBJ90YNg,22549
543
547
  tests/regscale/integrations/test_issue_creation.py,sha256=L4Fjww16S6sst2kqLoE0PK6WYL_pijSMzzxpWzdajRo,12089
@@ -624,7 +628,7 @@ tests/regscale/integrations/transformer/test_data_transformer.py,sha256=Na-trXL2
624
628
  tests/regscale/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
625
629
  tests/regscale/models/test_asset.py,sha256=YVQ0wAyjOf6LyhbUnNCHgI5-7VMKlBvb7dU886r7br8,16668
626
630
  tests/regscale/models/test_config.py,sha256=r2mIJJDpmnLYZjw8Nw7yTzwZCsHbmfZD4rHSupfeOec,797
627
- tests/regscale/models/test_control_implementation.py,sha256=r3J5B5TnsVJfnKnQq6KlYiJnt7F1kwRr5FzZh58YcFE,1060
631
+ tests/regscale/models/test_control_implementation.py,sha256=45wWukH_GE1ZYvdEYuNv8x5kuTIno4k4fq36yjitYSA,5832
628
632
  tests/regscale/models/test_form_field_value_integration.py,sha256=HDYrJvEbvl9B_ql72onVbbeQEoCJdcinIx0FuGQvFn4,12391
629
633
  tests/regscale/models/test_import.py,sha256=wG6KThJOXJe4wlFZpv4J0Lnpe4IBmU7VE13Sl4FT7xw,3949
630
634
  tests/regscale/models/test_issue.py,sha256=ant0hGYt8OuInuKkN212JtSDFsAreW0L_WMqNnXIX9w,17167
@@ -635,9 +639,9 @@ tests/regscale/models/test_regscale_model.py,sha256=ZsrEZkC4EtdIsoQuayn1xv2gEGcV
635
639
  tests/regscale/models/test_report.py,sha256=IqUq7C__a1_q_mLaz0PE9Lq6fHggBsB14-AzEYNBxLw,4666
636
640
  tests/regscale/models/test_tenable_integrations.py,sha256=y1qaW77H094VSGHjZdlvF66UCt-nPEib9Mv3cdwbM94,32435
637
641
  tests/regscale/models/test_user_model.py,sha256=e9olv28qBApgnvK6hFHOgXjUC-pkaV8aGDirEIWASL4,4427
638
- regscale_cli-6.27.2.0.dist-info/LICENSE,sha256=ytNhYQ9Rmhj_m-EX2pPq9Ld6tH5wrqqDYg-fCf46WDU,1076
639
- regscale_cli-6.27.2.0.dist-info/METADATA,sha256=urTKR5zkhFizHfI1rxRo29oWv7HRbGHOxLSVbO8U_Ts,34231
640
- regscale_cli-6.27.2.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
641
- regscale_cli-6.27.2.0.dist-info/entry_points.txt,sha256=cLOaIP1eRv1yZ2u7BvpE3aB4x3kDrDwkpeisKOu33z8,269
642
- regscale_cli-6.27.2.0.dist-info/top_level.txt,sha256=Uv8VUCAdxRm70bgrD4YNEJUmDhBThad_1aaEFGwRByc,15
643
- regscale_cli-6.27.2.0.dist-info/RECORD,,
642
+ regscale_cli-6.27.3.0.dist-info/LICENSE,sha256=ytNhYQ9Rmhj_m-EX2pPq9Ld6tH5wrqqDYg-fCf46WDU,1076
643
+ regscale_cli-6.27.3.0.dist-info/METADATA,sha256=3X7DDulppqXYZw0cMrnWPPPxfXQKOwAIdxZrlu2-4xg,34231
644
+ regscale_cli-6.27.3.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
645
+ regscale_cli-6.27.3.0.dist-info/entry_points.txt,sha256=cLOaIP1eRv1yZ2u7BvpE3aB4x3kDrDwkpeisKOu33z8,269
646
+ regscale_cli-6.27.3.0.dist-info/top_level.txt,sha256=Uv8VUCAdxRm70bgrD4YNEJUmDhBThad_1aaEFGwRByc,15
647
+ regscale_cli-6.27.3.0.dist-info/RECORD,,
@@ -1,6 +1,7 @@
1
1
  """Test the login module."""
2
2
 
3
- from unittest.mock import patch
3
+ from unittest.mock import patch, MagicMock
4
+ from requests.exceptions import HTTPError
4
5
 
5
6
  from regscale.core.login import get_regscale_token
6
7
  from regscale.core.app.api import Api
@@ -10,13 +11,32 @@ from regscale.core.app.application import Application
10
11
  @patch("regscale.core.login.Api.post")
11
12
  @patch.dict("os.environ", {"REGSCALE_DOMAIN": "example_value"})
12
13
  def test_get_regscale_token(mock_post):
14
+ """Test get_regscale_token with fallback to old API (backward compatibility)"""
13
15
  api = Api()
14
- mock_response = mock_post.return_value
15
- mock_response.status_code = 200
16
- mock_response.json.return_value = {
16
+
17
+ # Mock responses for fallback scenario
18
+ mock_response_v2 = MagicMock()
19
+ mock_response_v2.status_code = 400
20
+ mock_response_v2.raise_for_status.side_effect = HTTPError()
21
+
22
+ mock_response_v1 = MagicMock()
23
+ mock_response_v1.status_code = 200
24
+ mock_response_v1.url = "example_value/api/authentication/login"
25
+ mock_response_v1.json.return_value = {
17
26
  "id": "example_id",
18
27
  "auth_token": "example_token",
19
28
  }
29
+
30
+ # Set up side_effect for multiple calls
31
+ mock_post.side_effect = [
32
+ mock_response_v2,
33
+ mock_response_v1, # First call
34
+ mock_response_v2,
35
+ mock_response_v1, # Second call
36
+ mock_response_v2,
37
+ mock_response_v1, # Third call
38
+ ]
39
+
20
40
  result = get_regscale_token(api=api, username="example_user", password="example_password")
21
41
  result2 = get_regscale_token(
22
42
  api=api,
@@ -35,3 +55,150 @@ def test_get_regscale_token(mock_post):
35
55
  assert result == ("example_id", "example_token")
36
56
  assert result2 == ("example_id", "example_token")
37
57
  assert result3 == ("example_id", "example_token")
58
+
59
+
60
+ @patch("regscale.core.login.Api.post")
61
+ @patch.dict("os.environ", {"REGSCALE_DOMAIN": "https://example.com"})
62
+ def test_get_regscale_token_with_app_id_success(mock_post):
63
+ """Test successful authentication with app_id (API version 2.0)"""
64
+ api = Api()
65
+ mock_response = MagicMock()
66
+ mock_response.status_code = 200
67
+ mock_response.url = "https://example.com/api/authentication/login"
68
+ mock_response.json.return_value = {
69
+ "accessToken": {
70
+ "id": "new_user_id",
71
+ "authToken": "new_auth_token",
72
+ }
73
+ }
74
+ mock_post.return_value = mock_response
75
+
76
+ result = get_regscale_token(
77
+ api=api,
78
+ username="test_user",
79
+ password="test_password",
80
+ domain="https://example.com",
81
+ app_id=1,
82
+ )
83
+
84
+ assert result == ("new_user_id", "new_auth_token")
85
+ assert mock_post.call_count == 1
86
+ call_args = mock_post.call_args
87
+ assert call_args[1]["json"]["appId"] == 1
88
+ assert call_args[1]["headers"] == {"X-Api-Version": "2.0"}
89
+
90
+
91
+ @patch("regscale.core.login.Api.post")
92
+ @patch.dict("os.environ", {"REGSCALE_DOMAIN": "https://example.com"})
93
+ def test_get_regscale_token_with_custom_app_id(mock_post):
94
+ """Test authentication with custom app_id value"""
95
+ api = Api()
96
+ mock_response = MagicMock()
97
+ mock_response.status_code = 200
98
+ mock_response.url = "https://example.com/api/authentication/login"
99
+ mock_response.json.return_value = {
100
+ "accessToken": {
101
+ "id": "custom_user_id",
102
+ "authToken": "custom_auth_token",
103
+ }
104
+ }
105
+ mock_post.return_value = mock_response
106
+
107
+ result = get_regscale_token(
108
+ api=api,
109
+ username="test_user",
110
+ password="test_password",
111
+ domain="https://example.com",
112
+ app_id=5,
113
+ )
114
+
115
+ assert result == ("custom_user_id", "custom_auth_token")
116
+ call_args = mock_post.call_args
117
+ assert call_args[1]["json"]["appId"] == 5
118
+ assert call_args[1]["headers"] == {"X-Api-Version": "2.0"}
119
+
120
+
121
+ @patch("regscale.core.login.Api.post")
122
+ @patch.dict("os.environ", {"REGSCALE_DOMAIN": "https://example.com"})
123
+ def test_get_regscale_token_fallback_to_old_api(mock_post):
124
+ """Test fallback to old API version when app_id authentication fails"""
125
+ import copy
126
+
127
+ api = Api()
128
+
129
+ # Capture the arguments passed to each call
130
+ captured_calls = []
131
+
132
+ def capture_and_respond(*args, **kwargs):
133
+ # Make a deep copy of the json argument to preserve its state at call time
134
+ captured_calls.append({"json": copy.deepcopy(kwargs.get("json", {})), "headers": kwargs.get("headers", {})})
135
+
136
+ # First call raises HTTPError
137
+ if len(captured_calls) == 1:
138
+ mock_response_v2 = MagicMock()
139
+ mock_response_v2.status_code = 400
140
+ mock_response_v2.raise_for_status.side_effect = HTTPError()
141
+ return mock_response_v2
142
+ # Second call succeeds
143
+ else:
144
+ mock_response_v1 = MagicMock()
145
+ mock_response_v1.status_code = 200
146
+ mock_response_v1.url = "https://example.com/api/authentication/login"
147
+ mock_response_v1.json.return_value = {
148
+ "id": "old_user_id",
149
+ "auth_token": "old_auth_token",
150
+ }
151
+ return mock_response_v1
152
+
153
+ mock_post.side_effect = capture_and_respond
154
+
155
+ result = get_regscale_token(
156
+ api=api,
157
+ username="test_user",
158
+ password="test_password",
159
+ domain="https://example.com",
160
+ app_id=1,
161
+ )
162
+
163
+ assert result == ("old_user_id", "old_auth_token")
164
+ assert mock_post.call_count == 2
165
+
166
+ # Verify first call had app_id
167
+ assert captured_calls[0]["json"]["appId"] == 1
168
+ assert captured_calls[0]["headers"] == {"X-Api-Version": "2.0"}
169
+
170
+ # Verify second call did not have app_id
171
+ assert "appId" not in captured_calls[1]["json"]
172
+ assert captured_calls[1]["headers"] == {}
173
+
174
+
175
+ @patch("regscale.core.login.Api.post")
176
+ @patch.dict("os.environ", {"REGSCALE_DOMAIN": "https://example.com"})
177
+ def test_get_regscale_token_with_mfa_and_app_id(mock_post):
178
+ """Test authentication with both MFA token and app_id"""
179
+ api = Api()
180
+ mock_response = MagicMock()
181
+ mock_response.status_code = 200
182
+ mock_response.url = "https://example.com/api/authentication/login"
183
+ mock_response.json.return_value = {
184
+ "accessToken": {
185
+ "id": "mfa_user_id",
186
+ "authToken": "mfa_auth_token",
187
+ }
188
+ }
189
+ mock_post.return_value = mock_response
190
+
191
+ result = get_regscale_token(
192
+ api=api,
193
+ username="test_user",
194
+ password="test_password",
195
+ domain="https://example.com",
196
+ mfa_token="123456",
197
+ app_id=2,
198
+ )
199
+
200
+ assert result == ("mfa_user_id", "mfa_auth_token")
201
+ call_args = mock_post.call_args
202
+ assert call_args[1]["json"]["mfaToken"] == "123456"
203
+ assert call_args[1]["json"]["appId"] == 2
204
+ assert call_args[1]["headers"] == {"X-Api-Version": "2.0"}
@@ -1111,6 +1111,30 @@ class TestControlMatcherLeadingZeros:
1111
1111
  }
1112
1112
  assert result == expected
1113
1113
 
1114
+ @patch("regscale.integrations.control_matcher.Api")
1115
+ @patch("regscale.integrations.control_matcher.Application")
1116
+ def test_get_control_id_variations_with_letter_enhancement(self, mock_app_class, mock_api_class):
1117
+ """Test generating variations for control IDs with letter-based enhancements"""
1118
+ matcher = ControlMatcher()
1119
+
1120
+ result = matcher._get_control_id_variations("AC-1.a")
1121
+ expected = {
1122
+ "AC-1.A",
1123
+ "AC-01.A",
1124
+ "AC-1(A)",
1125
+ "AC-01(A)",
1126
+ }
1127
+ assert result == expected
1128
+
1129
+ @patch("regscale.integrations.control_matcher.Api")
1130
+ @patch("regscale.integrations.control_matcher.Application")
1131
+ def test_get_control_id_variations_invalid_input(self, mock_app_class, mock_api_class):
1132
+ """Test generating variations for invalid control ID returns empty set"""
1133
+ matcher = ControlMatcher()
1134
+
1135
+ result = matcher._get_control_id_variations("Invalid")
1136
+ assert result == set()
1137
+
1114
1138
  @patch("regscale.integrations.control_matcher.ControlMatcher._get_catalog_controls")
1115
1139
  @patch("regscale.integrations.control_matcher.Api")
1116
1140
  @patch("regscale.integrations.control_matcher.Application")
@@ -1,12 +1,13 @@
1
1
  import unittest
2
2
  from unittest.mock import MagicMock, patch
3
3
 
4
+ from regscale.core.app.application import Application
4
5
  from regscale.models import ControlImplementation
5
6
 
6
7
 
7
8
  class TestControlImplementation(unittest.TestCase):
8
- @patch("regscale.models.regscale_models.control_implementation.ControlImplementation._get_api_handler().get")
9
- def test_get_control_map_by_plan_lower_case_keys(self, mock_get):
9
+ @patch("regscale.models.regscale_models.control_implementation.ControlImplementation._get_api_handler")
10
+ def test_get_control_map_by_plan_lower_case_keys(self, mock_api_handler):
10
11
  # Create a mock response object with 'ok' attribute and 'json' method
11
12
  mock_response = MagicMock()
12
13
  mock_response.ok = True
@@ -15,7 +16,10 @@ class TestControlImplementation(unittest.TestCase):
15
16
  {"control": {"controlId": "AC-6"}, "id": 2},
16
17
  ]
17
18
 
18
- mock_get.return_value = mock_response
19
+ # Set up the mock API handler to return the mock response when .get() is called
20
+ mock_handler = MagicMock()
21
+ mock_handler.get.return_value = mock_response
22
+ mock_api_handler.return_value = mock_handler
19
23
 
20
24
  # Expected result should have lower case control IDs as keys
21
25
  expected_result = {"ca-1": 1, "ac-6": 2}
@@ -25,3 +29,114 @@ class TestControlImplementation(unittest.TestCase):
25
29
 
26
30
  # Assert that the result matches the expected result
27
31
  self.assertEqual(result, expected_result)
32
+
33
+ @patch("regscale.core.app.api.Api.graph")
34
+ def test_get_export_query_with_none_control_owner(self, mock_graph):
35
+ """Test get_export_query handles None controlOwner gracefully."""
36
+ # Mock API response with None controlOwner
37
+ mock_graph.return_value = {
38
+ "controlImplementations": {
39
+ "totalCount": 1,
40
+ "items": [
41
+ {
42
+ "id": 1,
43
+ "controlID": 100,
44
+ "controlOwner": None, # None control owner
45
+ "control": {
46
+ "title": "Test Control",
47
+ "description": "Test Description",
48
+ "controlId": "AC-1",
49
+ },
50
+ "status": "Implemented",
51
+ "policy": "Test Policy",
52
+ "implementation": "Test Implementation",
53
+ "responsibility": "Provider",
54
+ "inheritable": True,
55
+ }
56
+ ],
57
+ }
58
+ }
59
+
60
+ # Call the method under test
61
+ app = Application()
62
+ result = ControlImplementation.get_export_query(app, parent_id=1, parent_module="securityplans")
63
+
64
+ # Verify the result handles None gracefully
65
+ self.assertEqual(len(result), 1)
66
+ self.assertEqual(result[0]["controlOwnerId"], "Unassigned")
67
+
68
+ @patch("regscale.core.app.api.Api.graph")
69
+ def test_get_export_query_with_none_control(self, mock_graph):
70
+ """Test get_export_query handles None control gracefully."""
71
+ # Mock API response with None control
72
+ mock_graph.return_value = {
73
+ "controlImplementations": {
74
+ "totalCount": 1,
75
+ "items": [
76
+ {
77
+ "id": 1,
78
+ "controlID": 100,
79
+ "controlOwner": {
80
+ "firstName": "John",
81
+ "lastName": "Doe",
82
+ "userName": "jdoe",
83
+ },
84
+ "control": None, # None control
85
+ "status": "Implemented",
86
+ "policy": "Test Policy",
87
+ "implementation": "Test Implementation",
88
+ "responsibility": "Provider",
89
+ "inheritable": True,
90
+ }
91
+ ],
92
+ }
93
+ }
94
+
95
+ # Call the method under test
96
+ app = Application()
97
+ result = ControlImplementation.get_export_query(app, parent_id=1, parent_module="securityplans")
98
+
99
+ # Verify the result handles None gracefully
100
+ self.assertEqual(len(result), 1)
101
+ self.assertEqual(result[0]["controlName"], "")
102
+ self.assertEqual(result[0]["controlTitle"], "")
103
+ self.assertEqual(result[0]["description"], "")
104
+
105
+ @patch("regscale.core.app.api.Api.graph")
106
+ def test_get_export_query_with_partial_control_owner(self, mock_graph):
107
+ """Test get_export_query handles partial controlOwner data gracefully."""
108
+ # Mock API response with partial controlOwner data
109
+ mock_graph.return_value = {
110
+ "controlImplementations": {
111
+ "totalCount": 1,
112
+ "items": [
113
+ {
114
+ "id": 1,
115
+ "controlID": 100,
116
+ "controlOwner": {
117
+ "firstName": None,
118
+ "lastName": "Doe",
119
+ "userName": "jdoe",
120
+ },
121
+ "control": {
122
+ "title": "Test Control",
123
+ "description": "Test Description",
124
+ "controlId": "AC-1",
125
+ },
126
+ "status": "Implemented",
127
+ "policy": "Test Policy",
128
+ "implementation": "Test Implementation",
129
+ "responsibility": "Provider",
130
+ "inheritable": True,
131
+ }
132
+ ],
133
+ }
134
+ }
135
+
136
+ # Call the method under test
137
+ app = Application()
138
+ result = ControlImplementation.get_export_query(app, parent_id=1, parent_module="securityplans")
139
+
140
+ # Verify the result handles partial data gracefully
141
+ self.assertEqual(len(result), 1)
142
+ self.assertEqual(result[0]["controlOwnerId"], "Doe, (jdoe)")