conviso-ast 3.0.0.dev1__py3-none-any.whl → 3.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.
Files changed (28) hide show
  1. {conviso_ast-3.0.0.dev1.dist-info → conviso_ast-3.0.1.dist-info}/METADATA +4 -4
  2. {conviso_ast-3.0.0.dev1.dist-info → conviso_ast-3.0.1.dist-info}/RECORD +23 -24
  3. convisoappsec/common/retry_handler.py +2 -2
  4. convisoappsec/flow/util/__init__.py +1 -3
  5. convisoappsec/flowcli/ast/dry_run.py +99 -0
  6. convisoappsec/flowcli/ast/entrypoint.py +2 -1
  7. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/time_.py +0 -2
  8. convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/versioning_style.py +0 -2
  9. convisoappsec/flowcli/iac/dry_run.py +94 -0
  10. convisoappsec/flowcli/iac/entrypoint.py +2 -0
  11. convisoappsec/flowcli/iac/run.py +4 -1
  12. convisoappsec/flowcli/sast/dry_run.py +159 -0
  13. convisoappsec/flowcli/sast/entrypoint.py +2 -0
  14. convisoappsec/flowcli/sbom/generate.py +1 -1
  15. convisoappsec/flowcli/sca/dry_run.py +108 -0
  16. convisoappsec/flowcli/sca/entrypoint.py +2 -0
  17. convisoappsec/version.py +1 -1
  18. convisoappsec/flow/source_code_scanner/__init__.py +0 -9
  19. convisoappsec/flow/source_code_scanner/exceptions.py +0 -2
  20. convisoappsec/flow/source_code_scanner/scc.py +0 -68
  21. convisoappsec/flow/source_code_scanner/source_code_scanner.py +0 -177
  22. convisoappsec/flow/util/metrics.py +0 -16
  23. {conviso_ast-3.0.0.dev1.data → conviso_ast-3.0.1.data}/scripts/flow_bash_completer.sh +0 -0
  24. {conviso_ast-3.0.0.dev1.data → conviso_ast-3.0.1.data}/scripts/flow_fish_completer.fish +0 -0
  25. {conviso_ast-3.0.0.dev1.data → conviso_ast-3.0.1.data}/scripts/flow_zsh_completer.sh +0 -0
  26. {conviso_ast-3.0.0.dev1.dist-info → conviso_ast-3.0.1.dist-info}/WHEEL +0 -0
  27. {conviso_ast-3.0.0.dev1.dist-info → conviso_ast-3.0.1.dist-info}/entry_points.txt +0 -0
  28. {conviso_ast-3.0.0.dev1.dist-info → conviso_ast-3.0.1.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,22 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: conviso-ast
3
- Version: 3.0.0.dev1
3
+ Version: 3.0.1
4
4
  Maintainer: Conviso
5
5
  Maintainer-email: development@convisoappsec.com
6
6
  Project-URL: Source, https://github.com/convisoappsec/convisocli/
7
7
  Requires-Python: >=3.9
8
8
  Description-Content-Type: text/markdown
9
- Requires-Dist: GitPython==3.1.45
9
+ Requires-Dist: GitPython==3.1.46
10
10
  Requires-Dist: click==8.1.8
11
11
  Requires-Dist: requests==2.32.5
12
- Requires-Dist: urllib3==2.4.0
12
+ Requires-Dist: urllib3==2.6.3
13
13
  Requires-Dist: semantic-version==2.10.0
14
14
  Requires-Dist: docker==7.1.0
15
15
  Requires-Dist: PyYAML==6.0.3
16
16
  Requires-Dist: click-log==0.4.0
17
17
  Requires-Dist: transitions==0.9.2
18
18
  Requires-Dist: jsonschema==4.25.1
19
- Requires-Dist: giturlparse<=0.12.0
19
+ Requires-Dist: giturlparse<=0.14.0
20
20
  Requires-Dist: jmespath==1.0.1
21
21
  Requires-Dist: setuptools==78.1.0
22
22
  Dynamic: description
@@ -1,16 +1,16 @@
1
- conviso_ast-3.0.0.dev1.data/scripts/flow_bash_completer.sh,sha256=9q3HPuXq_FCUUV3IFGcOefsOLhPWatUkLY7txiBM7Uo,624
2
- conviso_ast-3.0.0.dev1.data/scripts/flow_fish_completer.fish,sha256=-wiuarawDJkms5N-rh99brIOzhy-ktsM1mi1ohQ3Mtg,147
3
- conviso_ast-3.0.0.dev1.data/scripts/flow_zsh_completer.sh,sha256=cAtTDGUs5sY4NAA7AjscmLWj0dbNZ9iZhLP6BTz6dEQ,844
1
+ conviso_ast-3.0.1.data/scripts/flow_bash_completer.sh,sha256=9q3HPuXq_FCUUV3IFGcOefsOLhPWatUkLY7txiBM7Uo,624
2
+ conviso_ast-3.0.1.data/scripts/flow_fish_completer.fish,sha256=-wiuarawDJkms5N-rh99brIOzhy-ktsM1mi1ohQ3Mtg,147
3
+ conviso_ast-3.0.1.data/scripts/flow_zsh_completer.sh,sha256=cAtTDGUs5sY4NAA7AjscmLWj0dbNZ9iZhLP6BTz6dEQ,844
4
4
  convisoappsec/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  convisoappsec/logger.py,sha256=aTNebqOau9nEadBySMTXtnbGkOkJ_q2kyFlX1mzizeg,1132
6
- convisoappsec/version.py,sha256=_q16h_zrZcZaVMRK1AHfgnIFLcCc08iv7IslC4pt-r0,28
6
+ convisoappsec/version.py,sha256=Ys8n4as2Wcnr8Aq6OV-e59RKmKVeyh9Oh2nzJ2FZPFk,22
7
7
  convisoappsec/common/__init__.py,sha256=QN7tV2C_jhTiWUrJHv2jbeq6ae3MssgLUWpQZwe8O2s,105
8
8
  convisoappsec/common/box.py,sha256=WTtPF3YWxkcdblPmFTzrzQlPPPUwVsDt2zoi6xFMy1U,7561
9
9
  convisoappsec/common/cleaner.py,sha256=Iy8BWCXj_v51oovcYzI_uhaJzLL-fCUyDxrbBglfwEs,2680
10
10
  convisoappsec/common/docker.py,sha256=SYkZCgKS_kuREyJS_Zb4d61MWb58HoiFbxkSRzLJr0g,12529
11
11
  convisoappsec/common/exceptions.py,sha256=Das7j6_nzB75-TY9xoVK12eswvxSntxI19nmXdjumzI,230
12
12
  convisoappsec/common/git_data_parser.py,sha256=-Ou1YC8D4bpmHUcibxLiJf2rxKi8-SuTuto-6nB-ML8,2167
13
- convisoappsec/common/retry_handler.py,sha256=MAwwD3QgxHZDJI87C8NPxYzxM4NBwGe3RflV7jRciAw,1495
13
+ convisoappsec/common/retry_handler.py,sha256=NwBNRQrqwk3Ohz9vcls2vTqD6wqxDWjm4MWI5WIfyj8,1533
14
14
  convisoappsec/common/strings.py,sha256=JqBqW1redAfWTWtUFya2MvrW5T26Y07Vn0pbee-BpMo,185
15
15
  convisoappsec/common/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  convisoappsec/common/graphql/error_handlers.py,sha256=1KUBa1zYiN_Gs2uwPsjl4LovoRFboWc16U7f680FfNE,2058
@@ -44,13 +44,8 @@ convisoappsec/flow/graphql_api/v1/models/project.py,sha256=CDZlufsT-_iQIOgpOPAtd
44
44
  convisoappsec/flow/graphql_api/v1/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  convisoappsec/flow/graphql_api/v1/schemas/mutations/__init__.py,sha256=R9LgniQyj694h1MD7cn1-HJRDjI4PLiOrCmsqjp16ho,3251
46
46
  convisoappsec/flow/graphql_api/v1/schemas/resolvers/__init__.py,sha256=2jAgzA-8te6HyyV8RVAx0BnLDeZhFulZynbxm5JR8Sc,2713
47
- convisoappsec/flow/source_code_scanner/__init__.py,sha256=UvfLXNR1B8Fy6LuUwesQMXV0oMkLjVMhPs0SJ5nDR0k,227
48
- convisoappsec/flow/source_code_scanner/exceptions.py,sha256=6ehUyZaFfMIRMzKdh0MND8gfyTNyHY_wsprmxkxSJD0,57
49
- convisoappsec/flow/source_code_scanner/scc.py,sha256=O_kdWsw2x0czuKcLORD3gP5wbXsizj4Bb2Sbsk5n_Sw,1645
50
- convisoappsec/flow/source_code_scanner/source_code_scanner.py,sha256=L9LVZnUO-o_JvT8dHUxBXcbxQlxSqRP8CVUBgTUEV7s,4726
51
- convisoappsec/flow/util/__init__.py,sha256=rpu69qnn68rqrK3rhPcgrVYWCIW9WVSrQ5FyCeHxng4,160
47
+ convisoappsec/flow/util/__init__.py,sha256=32E3AbPrBf0stKOzCIvz7BeWtBjAScIt7FNyERjN-p4,99
52
48
  convisoappsec/flow/util/ci_provider.py,sha256=VYDESwNFbtrRcWDtTEb8tYDN5qbnLksmQI_ntsciJ4I,2093
53
- convisoappsec/flow/util/metrics.py,sha256=4qGBMMR02OZN4ezFiB9iqtCuUYO8bXYqeUNDFRDpQaw,480
54
49
  convisoappsec/flow/util/source_code_compressor.py,sha256=b2iA8Exf8wVbxR1mnvwTbruDjdpYyVloUmSlyYLSJQU,508
55
50
  convisoappsec/flow/version_searchers/__init__.py,sha256=rJkVGlmWiiDHegvQl7d900RvnglzICXpTxuUiLlHSz0,294
56
51
  convisoappsec/flow/version_searchers/sorted_by_versioning_style.py,sha256=xLjaHy-WDOgY5jrASnaK-uM0UL-9sL3BALwzmM5PgSA,2657
@@ -71,7 +66,8 @@ convisoappsec/flowcli/assets/create.py,sha256=JDmxDH1WbyaQYLTxoi6dS_WosRm7kjvpJV
71
66
  convisoappsec/flowcli/assets/entrypoint.py,sha256=CEoev3d1ogclPNP3l31PBhGkoiZZ400kxsnnF02uxFk,310
72
67
  convisoappsec/flowcli/assets/ls.py,sha256=IYfKIca218BvZ5ecrtDgZ_T8xVg0XO3Eq1kK16BMBsc,1484
73
68
  convisoappsec/flowcli/ast/__init__.py,sha256=9SO9inH22PPm4jLlljVTJEeJKZujFKfwqTBbBo-TwFM,47
74
- convisoappsec/flowcli/ast/entrypoint.py,sha256=pwkXn9R1FNuUlTGrwUIMCacpklYSFR9BFDB59a_ivcU,15946
69
+ convisoappsec/flowcli/ast/dry_run.py,sha256=pb0eM-jXE83UpWTBcw3ulVSgY0WhWvWbcb-58j2YjC4,3588
70
+ convisoappsec/flowcli/ast/entrypoint.py,sha256=HI02I6r8v2cBYwCeOfQZLtFjGhTl3dF_83Tu2FXCM8Y,15999
75
71
  convisoappsec/flowcli/companies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
72
  convisoappsec/flowcli/companies/ls.py,sha256=0287VTXOkKnuXTaJh392crYjx0qank0pBvmESq3P_Bw,892
77
73
  convisoappsec/flowcli/container/__init__.py,sha256=Z666kQa4qVfbcuyLaW_hvORdAPtZ9dTQFcQb2H2Nkfg,59
@@ -89,8 +85,8 @@ convisoappsec/flowcli/deploy/create/with_/tag_tracker/context.py,sha256=IZjsKSze
89
85
  convisoappsec/flowcli/deploy/create/with_/tag_tracker/entrypoint.py,sha256=MUrx_fqAFQeJ2oUaAxRDPfk_qlgyNHKFMNZqmiDFWrU,675
90
86
  convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/__init__.py,sha256=c1sggCq3RGdgyq0tqdxx_yGW1iOeBti2aoNsoiMxKnc,56
91
87
  convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/entrypoint.py,sha256=J5dSGo0P__fKlPpeaVcAmyFnnAtZPi0E2y4Hv_U-ZQM,382
92
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/time_.py,sha256=Ipkz0bVXfJlbYHfPFICY3VUZYwlL2gxuHUqVVtvSyzQ,2721
93
- convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/versioning_style.py,sha256=-FJF4BOLzzpcJqYHlYJovRuvoUut7gLoxDWKnT6CzH0,3416
88
+ convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/time_.py,sha256=Up4tgYC5UFoDCjLYUo-6dPkmhVlJqx_eg6zioNegjI8,2608
89
+ convisoappsec/flowcli/deploy/create/with_/tag_tracker/sort_by/versioning_style.py,sha256=-BRqdRK-LFNjA6XiOrfoMKDo-ACetdsQaGEPQBTRcDo,3303
94
90
  convisoappsec/flowcli/findings/__init__.py,sha256=0wiNMaThYuum1QA9s9-LGtcmWFxUY-mWiYMtTSuaDqY,58
95
91
  convisoappsec/flowcli/findings/entrypoint.py,sha256=foc6wgD2BsoFZkJQiIuis260Zt-3DkTLsxej7cHv9Ko,344
96
92
  convisoappsec/flowcli/findings/create/__init__.py,sha256=l7eIySVkTKr3auZ8Fwe7G6AG6-pM06vnl3aZcEclVP4,54
@@ -101,16 +97,19 @@ convisoappsec/flowcli/findings/create/with_/version_tracker.py,sha256=NrnYx6OMQW
101
97
  convisoappsec/flowcli/findings/import_sarif/__init__.py,sha256=3iR7f9V9NdoIQTrD25EVu6OAYPPJ4RZEaM4P34BS0js,66
102
98
  convisoappsec/flowcli/findings/import_sarif/entrypoint.py,sha256=MIHi9ZWU2Jn2o7o5mDLp81xfb14gsa33aGnqh1YR7n8,13740
103
99
  convisoappsec/flowcli/iac/__init__.py,sha256=a3IZzSKpm987fMEliTECDeXO_Eduk7eg-aQzmaWvUXQ,47
104
- convisoappsec/flowcli/iac/entrypoint.py,sha256=vGsHdIss3KEWartTZkKl7k5w1qxhYIVqHGOJdklc3b8,241
105
- convisoappsec/flowcli/iac/run.py,sha256=q-bndWtZb9xYE9U_4aMHcZ3WtgHyXQBqUkjHTk-hdwI,11071
100
+ convisoappsec/flowcli/iac/dry_run.py,sha256=xvC0Wb2Sxl37yEjFaFMGcRvLJ4Q8evrNQoUXuahHtCg,2990
101
+ convisoappsec/flowcli/iac/entrypoint.py,sha256=WMlSwHd7cLxhUfy643OquQhUHEy4yNf7s0K5bkrXYno,295
102
+ convisoappsec/flowcli/iac/run.py,sha256=Y86MYTM8kTcF3TdvZuGgGLmNOEx7EPVaidKnStSbVpE,11203
106
103
  convisoappsec/flowcli/sast/__init__.py,sha256=S4O78eZGhgpT2lZY3GSUIUTQJB5a62uAVirEqbf4EQY,49
107
- convisoappsec/flowcli/sast/entrypoint.py,sha256=7bvQ6mVLWvykGfjD-o0xbu7ybm8Hj2DTqvCv5CstIas,245
104
+ convisoappsec/flowcli/sast/dry_run.py,sha256=lUi9LCfBlBjcAYm4v_Etl3raPZcTHVr5fVxGnB1eVSM,5787
105
+ convisoappsec/flowcli/sast/entrypoint.py,sha256=XMu8WpZNwSujWOwbHUThk3JK_WtRWHau9kYD2ttjULY,300
108
106
  convisoappsec/flowcli/sast/run.py,sha256=7uX6K1VLASU8RnoCKNYIIqXSsNkF4JQ8OKhAG2CKjuI,16353
109
107
  convisoappsec/flowcli/sbom/__init__.py,sha256=qzwiPWniK41Y41XvJJhxtRZguHrSSenb57lhy64KnSc,49
110
108
  convisoappsec/flowcli/sbom/entrypoint.py,sha256=ax2WL5BtCu24NeZYe6zzCVZ2ujlviXkvtY7PZihlz3s,263
111
- convisoappsec/flowcli/sbom/generate.py,sha256=Oke4JX4vARqpsMlGC2cPye_LMapIMRDyZv2W14hoD8g,7170
109
+ convisoappsec/flowcli/sbom/generate.py,sha256=YEhl4fVRXRscSApTMkTynyka3ygsVgJD7vhUHipUp18,7190
112
110
  convisoappsec/flowcli/sca/__init__.py,sha256=xnVoxwbpe4LrEemmWJ6svr3zdpo9S4kEIvM4HVRsLX8,47
113
- convisoappsec/flowcli/sca/entrypoint.py,sha256=LpFoiZ3iljhAyKzfMJ7pdBdHIUhnjh3ZguPgvWJZ-XA,241
111
+ convisoappsec/flowcli/sca/dry_run.py,sha256=fZ_tgc1k8Mn1JMznFWyi_CExR-gpLHLHwQ2erNldnHY,3438
112
+ convisoappsec/flowcli/sca/entrypoint.py,sha256=yEAANSG2fcD3HctUWebhx_win3CW-1Q2CO1i-ZIBUCk,295
114
113
  convisoappsec/flowcli/sca/run.py,sha256=FWnTHgMgnIRvJSpMIkFcb6YMtvWEjEpKJyXEkjAZpA4,16725
115
114
  convisoappsec/flowcli/vulnerability/__init__.py,sha256=c18E0J1KfZBBqpv8XGxF5dv7dxCDquFkjGkdnvFDSYI,67
116
115
  convisoappsec/flowcli/vulnerability/assert_security_rules.py,sha256=j7VcondMeZSRxWz118aWS9qUSGdvsq4Mg-_9UXp8Dyw,6075
@@ -121,8 +120,8 @@ convisoappsec/flowcli/vulnerability/run.py,sha256=6flmvr55cKxj-duX3w4PAFwJgC5AJ0
121
120
  convisoappsec/sast/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
122
121
  convisoappsec/sast/decision.py,sha256=d7dcNr9yZMzyccpFS_peAmDo0ZtfsE1qXDdYrvCux2U,1025
123
122
  convisoappsec/sast/sastbox.py,sha256=hXZLiYh_F3f6yd1ydPYVOMKg-tNOQOZiBvKmWyedagI,11031
124
- conviso_ast-3.0.0.dev1.dist-info/METADATA,sha256=ovtqoagXc5odGexeVR84FxKioLo-cfy5XUlgxjpPhrA,1080
125
- conviso_ast-3.0.0.dev1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
126
- conviso_ast-3.0.0.dev1.dist-info/entry_points.txt,sha256=0IvamweR_V0uG4O5Fo9NpVHTHfpZRwUE9kn7KEVZ668,109
127
- conviso_ast-3.0.0.dev1.dist-info/top_level.txt,sha256=ju5r0RSCF1HA7m9JOG10jrQS4SnqQEJzl6-YMCxbSl4,14
128
- conviso_ast-3.0.0.dev1.dist-info/RECORD,,
123
+ conviso_ast-3.0.1.dist-info/METADATA,sha256=BdZ7Ie84rkDmpp_x8q0H_ROeadkVM8QLidi9zadyDzU,1075
124
+ conviso_ast-3.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
125
+ conviso_ast-3.0.1.dist-info/entry_points.txt,sha256=0IvamweR_V0uG4O5Fo9NpVHTHfpZRwUE9kn7KEVZ668,109
126
+ conviso_ast-3.0.1.dist-info/top_level.txt,sha256=ju5r0RSCF1HA7m9JOG10jrQS4SnqQEJzl6-YMCxbSl4,14
127
+ conviso_ast-3.0.1.dist-info/RECORD,,
@@ -20,7 +20,7 @@ class RetryHandler:
20
20
  while retries < self.max_retries:
21
21
  try:
22
22
  return func(*args, **kwargs)
23
- except Exception:
23
+ except Exception as log_message:
24
24
  retries += 1
25
25
  time.sleep(delay)
26
26
  delay *= self.backoff_factor
@@ -28,7 +28,7 @@ class RetryHandler:
28
28
  if retries == self.max_retries:
29
29
  full_trace = traceback.format_exc()
30
30
  LOGGER.warning(
31
- "⚠️ Maximum retries reached. Our technical team has been notified."
31
+ f"⚠️ Maximum retries reached. Our technical team has been notified. Error: {log_message}"
32
32
  )
33
33
 
34
34
  try:
@@ -1,7 +1,5 @@
1
1
  from .source_code_compressor import SourceCodeCompressor
2
- from .metrics import project_metrics
3
2
 
4
3
  __all__ = [
5
- 'SourceCodeCompressor',
6
- 'project_metrics',
4
+ 'SourceCodeCompressor'
7
5
  ]
@@ -0,0 +1,99 @@
1
+ import click
2
+ import json
3
+ import traceback
4
+ import sys
5
+ from convisoappsec.flowcli import help_option
6
+ from convisoappsec.flowcli.context import pass_flow_context
7
+ from convisoappsec.logger import LOGGER
8
+ from convisoappsec.flowcli.common import on_http_error
9
+ from convisoappsec.common.cleaner import Cleaner
10
+ from convisoappsec.sast.sastbox import SASTBox
11
+ from convisoappsec.flowcli.sast.dry_run import execute_dry_run as execute_sast_dry_run
12
+ from convisoappsec.flowcli.sca.dry_run import execute_dry_run as execute_sca_dry_run
13
+ from convisoappsec.flowcli.iac.dry_run import execute_dry_run as execute_iac_dry_run
14
+
15
+ @click.command(name='dry-run')
16
+ @click.option(
17
+ "-s", "--start-commit", required=False,
18
+ help="If no value is set so the empty tree hash commit is used."
19
+ )
20
+ @click.option(
21
+ "-e", "--end-commit", required=False,
22
+ help="If no value is set so the HEAD commit from the current branch is used"
23
+ )
24
+ @click.option(
25
+ "-r", "--repository-dir", default=".", show_default=True,
26
+ type=click.Path(exists=True, resolve_path=True), required=False,
27
+ help="The source code repository directory."
28
+ )
29
+ @click.option(
30
+ "--sastbox-registry", default="", required=False, hidden=True,
31
+ envvar=("CONVISO_SASTBOX_REGISTRY", "FLOW_SASTBOX_REGISTRY"),
32
+ )
33
+ @click.option(
34
+ "--sastbox-repository-name", default="", required=False, hidden=True,
35
+ envvar=("CONVISO_SASTBOX_REPOSITORY_NAME", "FLOW_SASTBOX_REPOSITORY_NAME"),
36
+ )
37
+ @click.option(
38
+ "--sastbox-tag", default=SASTBox.DEFAULT_TAG, required=False, hidden=True,
39
+ envvar=("CONVISO_SASTBOX_TAG", "FLOW_SASTBOX_TAG"),
40
+ )
41
+ @click.option(
42
+ "--sastbox-skip-login/--sastbox-no-skip-login", default=False, required=False, hidden=True,
43
+ envvar=("CONVISO_SASTBOX_SKIP_LOGIN", "FLOW_SASTBOX_SKIP_LOGIN"),
44
+ )
45
+ @click.option(
46
+ "--custom-sca-tags", hidden=True, required=False, multiple=True, type=(str, str),
47
+ help="It should be passed as <repository_name> <image_tag>."
48
+ )
49
+ @click.option(
50
+ "--scanner-timeout", hidden=True, required=False, default=7200, type=int,
51
+ help="Set timeout for each scanner"
52
+ )
53
+ @click.option(
54
+ '--cleanup', default=False, is_flag=True, show_default=True,
55
+ help="Clean up system resources."
56
+ )
57
+ @help_option
58
+ @pass_flow_context
59
+ def dry_run(flow_context, end_commit, start_commit, repository_dir,
60
+ sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login,
61
+ custom_sca_tags, scanner_timeout, cleanup):
62
+ """
63
+ Perform a dry-run AST analysis (SAST, SCA, IaC).
64
+ Checks API Key, runs the scans, and outputs the results in JSON format to stdout.
65
+ Does NOT create assets or deploys on Conviso Platform.
66
+ """
67
+ try:
68
+ results = {}
69
+
70
+ # Run SAST
71
+ sast_results = execute_sast_dry_run(
72
+ flow_context, end_commit, start_commit, repository_dir,
73
+ sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login
74
+ )
75
+ results['sast'] = sast_results
76
+
77
+ # Run SCA
78
+ sca_results = execute_sca_dry_run(
79
+ flow_context, repository_dir, custom_sca_tags, scanner_timeout
80
+ )
81
+ results['sca'] = sca_results
82
+
83
+ # Run IaC
84
+ iac_results = execute_iac_dry_run(
85
+ flow_context, repository_dir, scanner_timeout
86
+ )
87
+ results['iac'] = iac_results
88
+
89
+ print(json.dumps(results, indent=2))
90
+
91
+ if cleanup:
92
+ LOGGER.info("🧹 Cleaning up ...")
93
+ cleaner = Cleaner()
94
+ cleaner.cleanup()
95
+
96
+ except Exception as e:
97
+ traceback.print_exc(file=sys.stderr)
98
+ on_http_error(e)
99
+ sys.exit(1)
@@ -15,7 +15,7 @@ from convisoappsec.flow import GitAdapter
15
15
  from convisoappsec.flowcli.context import pass_flow_context
16
16
  from convisoappsec.logger import LOGGER, log_and_notify_ast_event
17
17
  from convisoappsec.common.cleaner import Cleaner
18
-
18
+ from .dry_run import dry_run
19
19
 
20
20
  def get_default_params_values(cmd_params):
21
21
  """ Further information in https://click.palletsprojects.com/en/8.1.x/api/?highlight=params#click.Command.params
@@ -425,3 +425,4 @@ def ast():
425
425
 
426
426
 
427
427
  ast.add_command(run)
428
+ ast.add_command(dry_run)
@@ -1,6 +1,5 @@
1
1
  import click
2
2
  # TODO: refactoring. all deploy create share some behavior
3
- from convisoappsec.flow.util import project_metrics
4
3
  from convisoappsec.flow.version_searchers import TimeBasedVersionSearcher
5
4
  from convisoappsec.flow.version_control_system_adapter import GitAdapter
6
5
  from convisoappsec.flowcli.context import pass_flow_context
@@ -72,7 +71,6 @@ def time_(flow_context, create_context, tag_tracker_context, attach_diff):
72
71
  previous_version=previous_version,
73
72
  diff_content=diff_content,
74
73
  metrics=deploy_metrics,
75
- project_metrics=project_metrics(repository_dir),
76
74
  commit_authors=authors_data
77
75
  )
78
76
 
@@ -1,6 +1,5 @@
1
1
  import click
2
2
  # TODO: refactoring. all deploy create share some behavior
3
- from convisoappsec.flow.util import project_metrics
4
3
  from convisoappsec.flowcli.context import pass_flow_context
5
4
  from convisoappsec.flow.version_searchers import SortedByVersioningStyle
6
5
  from convisoappsec.flow.version_control_system_adapter import GitAdapter
@@ -103,7 +102,6 @@ def versioning_style(
103
102
  previous_version=previous_version,
104
103
  diff_content=diff_content,
105
104
  metrics=deploy_metrics,
106
- project_metrics=project_metrics(repository_dir),
107
105
  commit_authors=authors_data
108
106
  )
109
107
 
@@ -0,0 +1,94 @@
1
+ import click
2
+ import click_log
3
+ import json
4
+ import traceback
5
+ import sys
6
+ from convisoappsec.common.box import ContainerWrapper
7
+ from convisoappsec.flowcli import help_option
8
+ from convisoappsec.flowcli.context import pass_flow_context
9
+ from convisoappsec.logger import LOGGER
10
+ from convisoappsec.flowcli.common import on_http_error
11
+ from convisoappsec.common.cleaner import Cleaner
12
+
13
+ def execute_dry_run(flow_context, repository_dir, scanner_timeout):
14
+ REQUIRED_CODEBASE_PATH = '/code'
15
+ IAC_IMAGE_NAME = 'iac_scanner_checkov'
16
+ IAC_SCAN_FILENAME = '/{}.json'.format(IAC_IMAGE_NAME)
17
+ containers_map = {
18
+ IAC_IMAGE_NAME: {
19
+ 'repository_dir': repository_dir,
20
+ 'repository_name': IAC_IMAGE_NAME,
21
+ 'tag': 'unstable',
22
+ 'command': [
23
+ '-c', REQUIRED_CODEBASE_PATH,
24
+ '-o', IAC_SCAN_FILENAME,
25
+ ],
26
+ },
27
+ }
28
+
29
+ conviso_rest_api = flow_context.create_conviso_rest_api_client()
30
+ token = conviso_rest_api.docker_registry.get_sast_token()
31
+
32
+ LOGGER.info('💬 Preparing Environment...')
33
+ scanners_wrapper = ContainerWrapper(
34
+ token=token,
35
+ containers_map=containers_map,
36
+ logger=LOGGER,
37
+ timeout=scanner_timeout
38
+ )
39
+
40
+ LOGGER.info('💬 Starting IaC...')
41
+ scanners_wrapper.run()
42
+
43
+ results_list = []
44
+ for r in scanners_wrapper.scanners:
45
+ report_filepath = r.results
46
+ if report_filepath:
47
+ try:
48
+ with open(report_filepath, 'r') as f:
49
+ results_list.append(json.load(f))
50
+ except Exception as e:
51
+ click.echo(f"Error reading result file {report_filepath}: {e}", file=sys.stderr)
52
+
53
+ if len(results_list) == 1:
54
+ return results_list[0]
55
+ return results_list
56
+
57
+ @click.command(name='dry-run')
58
+ @click.option(
59
+ '-r', '--repository-dir', default=".", show_default=True,
60
+ type=click.Path(exists=True, resolve_path=True), required=False,
61
+ help="The source code repository directory."
62
+ )
63
+ @click.option(
64
+ "--scanner-timeout", hidden=True, required=False, default=7200, type=int,
65
+ help="Set timeout for each scanner"
66
+ )
67
+ @click.option(
68
+ '--cleanup', default=False, is_flag=True, show_default=True,
69
+ help="Clean up system resources."
70
+ )
71
+ @help_option
72
+ @pass_flow_context
73
+ def dry_run(flow_context, repository_dir, scanner_timeout, cleanup):
74
+ """
75
+ Perform a dry-run IAC analysis.
76
+ Checks API Key, runs the scan, and outputs the results in JSON format to stdout.
77
+ Does NOT create assets or deploys on Conviso Platform.
78
+ """
79
+ try:
80
+ results = execute_dry_run(flow_context, repository_dir, scanner_timeout)
81
+
82
+ if results:
83
+ print(json.dumps(results, indent=2))
84
+ else:
85
+ print(json.dumps({}, indent=2))
86
+
87
+ if cleanup:
88
+ LOGGER.info("🧹 Cleaning up ...")
89
+ cleaner = Cleaner()
90
+ cleaner.cleanup()
91
+
92
+ except Exception as e:
93
+ on_http_error(e)
94
+ sys.exit(1)
@@ -2,6 +2,7 @@ import click
2
2
 
3
3
  from convisoappsec.flowcli import help_option
4
4
  from .run import run
5
+ from .dry_run import dry_run
5
6
 
6
7
 
7
8
  @click.group()
@@ -11,6 +12,7 @@ def iac():
11
12
 
12
13
 
13
14
  iac.add_command(run)
15
+ iac.add_command(dry_run)
14
16
 
15
17
  iac.epilog = '''
16
18
  Run flow iac COMMAND --help for more information on a command.
@@ -142,6 +142,7 @@ def run(context, flow_context, asset_id, company_id, repository_dir, send_to_flo
142
142
  def deploy_results_to_conviso(
143
143
  conviso_api, results_filepaths, asset_id, company_id, flow_context, deploy_id, commit_ref=None, control_sync_status_id=None
144
144
  ):
145
+
145
146
  results_context = click.progressbar(results_filepaths, label="Sending results to the Conviso Platform...")
146
147
 
147
148
  with results_context as reports:
@@ -150,7 +151,7 @@ def deploy_results_to_conviso(
150
151
  with open(report_path) as report_file:
151
152
  data = parse_data(json.load(report_file))
152
153
  except Exception:
153
- LOGGER.warn(f"⚠️ Error processing report file. Our technical team has been notified.")
154
+ LOGGER.warning(f"⚠️ Error processing report file. Our technical team has been notified.")
154
155
  full_trace = traceback.format_exc()
155
156
  log_and_notify_ast_event(
156
157
  flow_context=flow_context, company_id=company_id, asset_id=asset_id,
@@ -181,6 +182,8 @@ def deploy_results_to_conviso(
181
182
  except ResponseError as error:
182
183
  if error.code == 'RECORD_NOT_UNIQUE':
183
184
  continue
185
+ elif error.code == "Record not found" or "Record not found" in str(error):
186
+ continue
184
187
  else:
185
188
  retry_handler = RetryHandler(
186
189
  flow_context=flow_context, company_id=company_id, asset_id=asset_id
@@ -0,0 +1,159 @@
1
+ import sys
2
+ import click
3
+ import traceback
4
+ import json
5
+ from convisoappsec.sast.sastbox import SASTBox
6
+ from docker.errors import APIError
7
+ import time
8
+ from convisoappsec.flow import GitAdapter
9
+ from convisoappsec.flowcli import help_option
10
+ from convisoappsec.flowcli.context import pass_flow_context
11
+ from convisoappsec.logger import LOGGER
12
+ from convisoappsec.common.cleaner import Cleaner
13
+ from convisoappsec.flowcli.common import on_http_error
14
+
15
+ class DryRunSASTBox(SASTBox):
16
+ def recovery_technologies_file(self):
17
+ # Skip technology recovery and update for dry-run
18
+ pass
19
+
20
+ def perform_dry_run_sastbox_scan(
21
+ conviso_rest_api, sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login, repository_dir, end_commit, start_commit, logger
22
+ ):
23
+ max_retries = 5
24
+ retries = 0
25
+ sastbox = DryRunSASTBox(registry=sastbox_registry, repository_name=sastbox_repository_name, tag=sastbox_tag)
26
+ pull_progress_bar = click.progressbar(length=sastbox.size, label="Performing SAST download...")
27
+
28
+ while retries < max_retries:
29
+ try:
30
+ if not sastbox_skip_login:
31
+ logger("Checking SASTBox authorization...")
32
+ token = conviso_rest_api.docker_registry.get_sast_token()
33
+ sastbox.login(token)
34
+
35
+ with pull_progress_bar as progressbar:
36
+ for downloaded_chunk in sastbox.pull():
37
+ progressbar.update(downloaded_chunk)
38
+ break
39
+ except APIError as e:
40
+ retries += 1
41
+ logger(f"Retrying {retries}/{max_retries}...")
42
+ time.sleep(1)
43
+
44
+ if retries == max_retries:
45
+ logger("Max retries reached. Failed to perform SAST download.")
46
+ raise Exception(f"Max retries reached. Could not complete the SAST download. Error: {str(e)}")
47
+
48
+ logger("Starting SAST scan diff...")
49
+
50
+ reports = sastbox.run_scan_diff(repository_dir, end_commit, start_commit, log=logger)
51
+
52
+ logger("SAST scan diff done.")
53
+
54
+ results_filepaths = []
55
+ for r in reports:
56
+ try:
57
+ file_path = str(r)
58
+ results_filepaths.append(file_path)
59
+ except Exception as e:
60
+ click.echo(f"Error decoding file path: {r} with error {e}.", file=sys.stderr)
61
+
62
+ return results_filepaths
63
+
64
+ def log_func(msg, new_line=True):
65
+ click.echo(msg, nl=new_line, err=True)
66
+
67
+ def execute_dry_run(flow_context, end_commit, start_commit, repository_dir,
68
+ sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login):
69
+ git_adapter = GitAdapter(repository_dir)
70
+ end_commit = end_commit or git_adapter.head_commit
71
+ start_commit = start_commit or git_adapter.empty_repository_tree_commit
72
+
73
+ if start_commit == end_commit:
74
+ return {}
75
+
76
+ conviso_rest_api = flow_context.create_conviso_rest_api_client()
77
+
78
+ results_filepaths = perform_dry_run_sastbox_scan(
79
+ conviso_rest_api, sastbox_registry, sastbox_repository_name, sastbox_tag,
80
+ sastbox_skip_login, repository_dir, end_commit, start_commit, log_func
81
+ )
82
+
83
+ results_list = []
84
+ for path in results_filepaths:
85
+ try:
86
+ with open(path, 'r') as f:
87
+ results_list.append(json.load(f))
88
+ except Exception as e:
89
+ click.echo(f"Error reading result file {path}: {e}", file=sys.stderr)
90
+
91
+ if len(results_list) == 1:
92
+ return results_list[0]
93
+ return results_list
94
+
95
+ @click.command(name='dry-run')
96
+ @click.option(
97
+ "-s", "--start-commit", required=False,
98
+ help="If no value is set so the empty tree hash commit is used."
99
+ )
100
+ @click.option(
101
+ "-e", "--end-commit", required=False,
102
+ help="If no value is set so the HEAD commit from the current branch is used"
103
+ )
104
+ @click.option(
105
+ "-r", "--repository-dir", default=".", show_default=True,
106
+ type=click.Path(exists=True, resolve_path=True), required=False,
107
+ help="The source code repository directory."
108
+ )
109
+ @click.option(
110
+ "--sastbox-registry", default="", required=False, hidden=True,
111
+ envvar=("CONVISO_SASTBOX_REGISTRY", "FLOW_SASTBOX_REGISTRY"),
112
+ )
113
+ @click.option(
114
+ "--sastbox-repository-name", default="", required=False, hidden=True,
115
+ envvar=("CONVISO_SASTBOX_REPOSITORY_NAME", "FLOW_SASTBOX_REPOSITORY_NAME"),
116
+ )
117
+ @click.option(
118
+ "--sastbox-tag", default=SASTBox.DEFAULT_TAG, required=False, hidden=True,
119
+ envvar=("CONVISO_SASTBOX_TAG", "FLOW_SASTBOX_TAG"),
120
+ )
121
+ @click.option(
122
+ "--sastbox-skip-login/--sastbox-no-skip-login", default=False, required=False, hidden=True,
123
+ envvar=("CONVISO_SASTBOX_SKIP_LOGIN", "FLOW_SASTBOX_SKIP_LOGIN"),
124
+ )
125
+ @click.option(
126
+ '--cleanup', default=False, is_flag=True, show_default=True,
127
+ help="Clean up system resources."
128
+ )
129
+ @click.option(
130
+ "-o", "--output", required=False, help="Output the results to a JSON file."
131
+ )
132
+ @help_option
133
+ @pass_flow_context
134
+ def dry_run(flow_context, end_commit, start_commit, repository_dir,
135
+ sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login, cleanup, output):
136
+ try:
137
+ results = execute_dry_run(
138
+ flow_context, end_commit, start_commit, repository_dir,
139
+ sastbox_registry, sastbox_repository_name, sastbox_tag, sastbox_skip_login
140
+ )
141
+
142
+ if output:
143
+ with open(output, "w") as f:
144
+ json.dump(results if results else {}, f, indent=2)
145
+ LOGGER.info(f"Results saved to {output}")
146
+ elif results:
147
+ print(json.dumps(results, indent=2))
148
+ else:
149
+ print(json.dumps({}, indent=2))
150
+
151
+ if cleanup:
152
+ LOGGER.info("🧹 Cleaning up ...")
153
+ cleaner = Cleaner()
154
+ cleaner.cleanup()
155
+
156
+ except Exception as e:
157
+ traceback.print_exc(file=sys.stderr)
158
+ on_http_error(e)
159
+ sys.exit(1)
@@ -2,6 +2,7 @@ import click
2
2
 
3
3
  from convisoappsec.flowcli import help_option
4
4
  from .run import run
5
+ from .dry_run import dry_run
5
6
 
6
7
 
7
8
  @click.group()
@@ -11,6 +12,7 @@ def sast():
11
12
 
12
13
 
13
14
  sast.add_command(run)
15
+ sast.add_command(dry_run)
14
16
 
15
17
  sast.epilog = '''
16
18
  Run flow sast COMMAND --help for more information on a command.
@@ -182,7 +182,7 @@ def generate(context, flow_context, asset_id, company_id, repository_dir, send_t
182
182
  stderr=subprocess.DEVNULL
183
183
  )
184
184
  command = [f"./conviso/syft scan {repository_dir} -o cyclonedx-json={file_name} "
185
- f"--select-catalogers '{','.join(catalogers)}'"]
185
+ f"--select-catalogers '{','.join(catalogers)}' --exclude ./conviso"]
186
186
 
187
187
  subprocess.run(command, shell=True, check=True, capture_output=True)
188
188
 
@@ -0,0 +1,108 @@
1
+ import click
2
+ import click_log
3
+ import traceback
4
+ import json
5
+ import sys
6
+ from convisoappsec.common.box import ContainerWrapper
7
+ from convisoappsec.flowcli import help_option
8
+ from convisoappsec.flowcli.context import pass_flow_context
9
+ from convisoappsec.logger import LOGGER
10
+ from convisoappsec.flowcli.common import on_http_error
11
+ from convisoappsec.common.cleaner import Cleaner
12
+
13
+ def log_func(msg, new_line=True):
14
+ click.echo(msg, nl=new_line, err=True)
15
+
16
+ def execute_dry_run(flow_context, repository_dir, custom_sca_tags, scanner_timeout):
17
+ REQUIRED_CODEBASE_PATH = '/code'
18
+ OSV_SCANNER_IMAGE_NAME = 'osv_scanner'
19
+
20
+ scanners = {
21
+ OSV_SCANNER_IMAGE_NAME: {
22
+ 'repository_name': OSV_SCANNER_IMAGE_NAME,
23
+ 'tag': 'latest',
24
+ 'command': [
25
+ '-c', REQUIRED_CODEBASE_PATH,
26
+ '-f', 'json',
27
+ '-o', '/{}.json'.format(OSV_SCANNER_IMAGE_NAME)
28
+ ],
29
+ 'repository_dir': repository_dir
30
+ },
31
+ }
32
+
33
+ if custom_sca_tags:
34
+ for custom_tag in custom_sca_tags:
35
+ scan_name, tag = custom_tag
36
+ if scan_name in scanners.keys():
37
+ scanners[scan_name]['tag'] = tag
38
+
39
+ conviso_rest_api = flow_context.create_conviso_rest_api_client()
40
+ token = conviso_rest_api.docker_registry.get_sast_token()
41
+
42
+ LOGGER.info('💬 Preparing Environment...')
43
+ scabox = ContainerWrapper(
44
+ token=token,
45
+ containers_map=scanners,
46
+ logger=LOGGER,
47
+ timeout=scanner_timeout
48
+ )
49
+ LOGGER.info('💬 Starting SCA...')
50
+ scabox.run()
51
+
52
+ results_list = []
53
+ for unit in scabox.scanners:
54
+ file_path = unit.results
55
+ if file_path:
56
+ try:
57
+ with open(file_path, 'r') as f:
58
+ results_list.append(json.load(f))
59
+ except Exception as e:
60
+ click.echo(f"Error reading result file {file_path}: {e}", file=sys.stderr)
61
+
62
+ if len(results_list) == 1:
63
+ return results_list[0]
64
+ return results_list
65
+
66
+
67
+ @click.command(name='dry-run')
68
+ @click.option(
69
+ '-r', '--repository-dir', default=".", show_default=True,
70
+ type=click.Path(exists=True, resolve_path=True), required=False,
71
+ help="The source code repository directory."
72
+ )
73
+ @click.option(
74
+ "--custom-sca-tags", hidden=True, required=False, multiple=True, type=(str, str),
75
+ help="It should be passed as <repository_name> <image_tag>."
76
+ )
77
+ @click.option(
78
+ "--scanner-timeout", hidden=True, required=False, default=7200, type=int,
79
+ help="Set timeout for each scanner"
80
+ )
81
+ @click.option(
82
+ '--cleanup', default=False, is_flag=True, show_default=True,
83
+ help="Clean up system resources."
84
+ )
85
+ @help_option
86
+ @pass_flow_context
87
+ def dry_run(flow_context, repository_dir, custom_sca_tags, scanner_timeout, cleanup):
88
+ """
89
+ Perform a dry-run SCA analysis.
90
+ Checks API Key, runs the scan, and outputs the results in JSON format to stdout.
91
+ Does NOT create assets or deploys on Conviso Platform.
92
+ """
93
+ try:
94
+ results = execute_dry_run(flow_context, repository_dir, custom_sca_tags, scanner_timeout)
95
+
96
+ if results:
97
+ print(json.dumps(results, indent=2))
98
+ else:
99
+ print(json.dumps({}, indent=2))
100
+
101
+ if cleanup:
102
+ LOGGER.info("🧹 Cleaning up ...")
103
+ cleaner = Cleaner()
104
+ cleaner.cleanup()
105
+
106
+ except Exception as e:
107
+ on_http_error(e)
108
+ sys.exit(1)
@@ -2,6 +2,7 @@ import click
2
2
 
3
3
  from convisoappsec.flowcli import help_option
4
4
  from .run import run
5
+ from .dry_run import dry_run
5
6
 
6
7
 
7
8
  @click.group()
@@ -11,6 +12,7 @@ def sca():
11
12
 
12
13
 
13
14
  sca.add_command(run)
15
+ sca.add_command(dry_run)
14
16
 
15
17
  sca.epilog = '''
16
18
  Run flow sca COMMAND --help for more information on a command.
convisoappsec/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '3.0.0-dev.1'
1
+ __version__ = '3.0.1'
@@ -1,9 +0,0 @@
1
- from .source_code_scanner import SourceCodeScanner # noqa
2
- from .exceptions import SourceCodeScannerException # noqa
3
- from .scc import SCC # noqa
4
-
5
- __all_ = [
6
- 'SourceCodeScanner',
7
- 'SourceCodeScannerException',
8
- 'SCC'
9
- ]
@@ -1,2 +0,0 @@
1
- class SourceCodeScannerException(RuntimeError):
2
- pass
@@ -1,68 +0,0 @@
1
- import yaml
2
- import tempfile
3
-
4
- from .source_code_scanner import SourceCodeScanner
5
- from .exceptions import SourceCodeScannerException
6
-
7
-
8
- class SCC(SourceCodeScanner):
9
-
10
- def __init__(
11
- self,
12
- source_code_dir,
13
- container_source_dir = '/code',
14
- create_source_code_volume = True
15
- ):
16
- super().__init__(
17
- source_code_dir,
18
- create_source_code_volume=create_source_code_volume
19
- )
20
- self.__scan_result = {}
21
- self.__container_source_dir = container_source_dir
22
-
23
- @property
24
- def repository(self):
25
- return 'convisoappsec/scc'
26
-
27
- @property
28
- def tag(self):
29
- return 'latest'
30
-
31
- @property
32
- def container_source_dir(self):
33
- return self.__container_source_dir
34
-
35
- def _read_scan_stdout(self, stdout_generator):
36
- with tempfile.TemporaryFile() as yaml_output:
37
- for chunk in stdout_generator:
38
- yaml_output.write(chunk)
39
-
40
- yaml_output.seek(0)
41
-
42
- self.__scan_result = yaml.load(
43
- yaml_output,
44
- Loader=yaml.FullLoader
45
- )
46
-
47
- @property
48
- def summary(self):
49
- summary = self.__scan_result.get('SUM')
50
- if not summary:
51
- raise SourceCodeScannerException(
52
- 'Unexpected error retrienving source code summary metrics'
53
- )
54
-
55
- return summary
56
-
57
- @property
58
- def total_source_code_lines(self):
59
- return self.summary.get('code')
60
-
61
- @property
62
- def command(self):
63
- return [
64
- '--no-cocomo',
65
- '--no-complexity',
66
- '--format',
67
- 'cloc-yaml'
68
- ]
@@ -1,177 +0,0 @@
1
- import docker
2
- from contextlib import suppress
3
- import tempfile
4
- from uuid import uuid4
5
-
6
- from convisoappsec.flow.util import SourceCodeCompressor
7
- from .exceptions import SourceCodeScannerException
8
-
9
-
10
- class SourceCodeScanner(object):
11
- SUCCESS_EXIT_CODE = 0
12
- '''
13
- hooks:
14
- def _pre_pull(self):
15
- :return: void
16
-
17
- def _capture_stdout(self, stdout_bytes)
18
- :param stdout_bytes: chunks generated by stdout
19
- :paramtype stdout_bytes: bytes
20
- :return: void
21
- _pre_scan
22
- _scan_stdout
23
- _post_scan
24
- '''
25
-
26
- def __init__(self, source_code_dir, create_source_code_volume = True):
27
- uuid = str(uuid4())
28
- self.docker = docker.from_env(version="auto")
29
- self.__container_name = "source_code_scanner_{0}".format(
30
- uuid
31
- )
32
- self.__source_code_dir = source_code_dir
33
- self.__create_source_code_volume = create_source_code_volume
34
-
35
- if self.__create_source_code_volume:
36
- self.__source_code_volume_name = "source_code_scanner_src_{0}".format(
37
- uuid
38
- )
39
- else:
40
- self.__source_code_volume_name = None
41
-
42
- @property
43
- def repository(self):
44
- raise Exception('Not implemented yet!')
45
-
46
- @property
47
- def tag(self):
48
- raise Exception('Not implemented yet!')
49
-
50
- @property
51
- def command(self):
52
- raise Exception('Not implemented yet!')
53
-
54
- @property
55
- def container_source_dir(self):
56
- raise Exception('Not implemented yet!')
57
-
58
- @property
59
- def image(self):
60
- return "{repository}:{tag}".format(
61
- repository=self.repository,
62
- tag=self.tag,
63
- )
64
-
65
- @property
66
- def volumes(self):
67
- if not self.__create_source_code_volume:
68
- return {}
69
-
70
- return {
71
- self.__source_code_volume_name: {
72
- 'bind': self.container_source_dir,
73
- 'mode': 'rw',
74
- }
75
- }
76
-
77
- def __get_container(self):
78
- return self.docker.containers.get(
79
- self.__container_name
80
- )
81
-
82
- def __get_source_code_volume(self):
83
- return self.docker.volumes.get(
84
- self.__source_code_volume_name
85
- )
86
-
87
- @property
88
- def __container(self):
89
- try:
90
- return self.__get_container()
91
- except docker.errors.NotFound:
92
- return self.__create_container()
93
-
94
- def __create_container(self):
95
- return self.docker.containers.create(
96
- self.image,
97
- name=self.__container_name,
98
- volumes=self.volumes,
99
- detach=True,
100
- command=self.command,
101
- working_dir=self.container_source_dir if self.container_source_dir != '/code' else '/code'
102
- )
103
-
104
- def __pull_image(self):
105
- if self.has_pre_pull:
106
- self._pre_pull()
107
-
108
- self.docker.images.pull(self.repository, self.tag)
109
-
110
- def __load_source_code(self):
111
- container = self.__container
112
-
113
- with tempfile.TemporaryFile() as fileobj:
114
- compressor = SourceCodeCompressor(
115
- self.__source_code_dir
116
- )
117
-
118
- compressor.write_to(fileobj)
119
- fileobj.seek(0)
120
-
121
- container.put_archive(
122
- self.container_source_dir,
123
- fileobj
124
- )
125
-
126
- def scan(self):
127
- self.__pull_image()
128
- self.__load_source_code()
129
- container = self.__container
130
-
131
- container.start()
132
-
133
- if self.has_read_scan_stderr:
134
- self._read_scan_stderr(
135
- container.logs(
136
- stream=True, stdout=False, stderr=True
137
- )
138
- )
139
-
140
- if self.has_read_scan_stdout:
141
- self._read_scan_stdout(
142
- container.logs(
143
- stream=True, stdout=True, stderr=False
144
- )
145
- )
146
-
147
- wait_result = container.wait()
148
- status_code = wait_result.get('StatusCode')
149
-
150
- if not status_code == self.SUCCESS_EXIT_CODE:
151
- raise SourceCodeScannerException(
152
- 'Source code scanning fail'
153
- )
154
-
155
- def __has_method(self, method_name):
156
- return hasattr(self, method_name)
157
-
158
- @property
159
- def has_read_scan_stdout(self):
160
- return self.__has_method('_read_scan_stdout')
161
-
162
- @property
163
- def has_read_scan_stderr(self):
164
- return self.__has_method('_read_scan_stderr')
165
-
166
- @property
167
- def has_pre_pull(self):
168
- return self.__has_method('_pre_pull')
169
-
170
- def __del__(self):
171
- with suppress(Exception):
172
- container = self.__get_container()
173
- container.remove()
174
-
175
- with suppress(Exception):
176
- source_code_volume = self.__get_source_code_volume()
177
- source_code_volume.remove()
@@ -1,16 +0,0 @@
1
- from convisoappsec.flow.source_code_scanner import SCC
2
- from convisoappsec.logger import LOGGER
3
- import docker
4
-
5
- def project_metrics(source_code_dir):
6
- try:
7
- scanner = SCC(source_code_dir, create_source_code_volume=False)
8
- scanner.scan()
9
- return {
10
- 'total_lines': scanner.total_source_code_lines
11
- }
12
- except docker.errors.APIError as e:
13
- LOGGER.error('Error on fetch project metrics')
14
- LOGGER.exception(e)
15
- return {}
16
-