certora-cli-alpha-master 20250520.17.33.568414__py3-none-macosx_10_9_universal2.whl → 20250521.12.50.829403__py3-none-macosx_10_9_universal2.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.
@@ -44,7 +44,9 @@ from CertoraProver.certoraContextValidator import KEY_ENV_VAR
44
44
  from Mutate import mutateConstants as MConstants
45
45
  from Shared import certoraUtils as Util
46
46
  from Shared.certoraLogging import LoggingManager
47
- from certoraRun import run_certora, CertoraRunResult, CertoraFoundViolations
47
+ from certoraRun import run_certora
48
+ from Shared.proverCommon import CertoraRunResult, CertoraFoundViolations
49
+ from certoraSorobanProver import run_soroban_prover
48
50
  from Shared import certoraValidateFuncs as Vf
49
51
  from CertoraProver.Compiler.CompilerCollectorFactory import get_relevant_compiler
50
52
  from Mutate import mutateUtil as MutUtil
@@ -1416,7 +1418,10 @@ class MutateApp:
1416
1418
  certora_args.extend(["--disable_local_typechecking"])
1417
1419
  mutation_logger.debug(f"Running the Prover: {certora_args}")
1418
1420
  try:
1419
- certora_run_result = run_certora(certora_args)
1421
+ if self.is_soroban_run():
1422
+ certora_run_result = run_soroban_prover(certora_args)
1423
+ else:
1424
+ certora_run_result = run_certora(certora_args)
1420
1425
  except CertoraFoundViolations as e:
1421
1426
  assert e.results, "expect e.results not to be None"
1422
1427
  certora_run_result = e.results
@@ -0,0 +1,300 @@
1
+ # The Certora Prover
2
+ # Copyright (C) 2025 Certora Ltd.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, version 3 of the License.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+
16
+ """
17
+ Shared helpers for certoraRun entry points (Solana & Soroban & EVM).
18
+
19
+ Placing the context_build environment preparation logic and verification helpers in one module
20
+ reduces duplication from the dedicated entry scripts.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import sys
26
+ import logging
27
+ import functools
28
+ from pathlib import Path
29
+ from dataclasses import dataclass
30
+ from rich.console import Console
31
+ from typing import List, Tuple, Type, Optional, Dict, NoReturn, Callable
32
+
33
+ scripts_dir_path = Path(__file__).parent.parent.resolve() # containing directory
34
+ sys.path.insert(0, str(scripts_dir_path))
35
+
36
+ from CertoraProver.certoraCloudIO import validate_version_and_branch
37
+ from Shared.certoraLogging import LoggingManager
38
+ from Shared import certoraUtils as Util
39
+ from Shared.certoraAttrUtil import Attributes
40
+ import CertoraProver.certoraContext as Ctx
41
+ from CertoraProver.certoraContextClass import CertoraContext
42
+ import CertoraProver.certoraContextAttributes as Attrs
43
+ from CertoraProver.certoraCollectRunMetadata import collect_run_metadata
44
+ from CertoraProver.certoraCollectConfigurationLayout import collect_configuration_layout
45
+ from CertoraProver import certoraContextValidator as Cv
46
+ from CertoraProver.certoraCloudIO import CloudVerification
47
+
48
+ log = logging.getLogger(__name__)
49
+
50
+
51
+ VIOLATIONS_EXIT_CODE = 100
52
+
53
+ @dataclass
54
+ class CertoraRunResult:
55
+ link: Optional[str] # Path to emv_dir if running locally, or the link to the job status page
56
+ is_local_link: bool
57
+ src_dir: Path
58
+ rule_report_link: Optional[str]
59
+
60
+ class CertoraFoundViolations(Exception):
61
+ def __init__(self, message: str, results: Optional[CertoraRunResult] = None) -> None:
62
+ super().__init__(message)
63
+ self.results = results
64
+
65
+ # --------------------------------------------------------------------------- #
66
+ # Setup Environment
67
+ # --------------------------------------------------------------------------- #
68
+ def build_context(args: List[str], attributes: Type[Attributes]) -> Tuple[CertoraContext, LoggingManager]:
69
+ """
70
+ Build the context for the Certora Prover.
71
+ This function is responsible for setting up the context and logging manager
72
+ for the Certora Prover. It handles the following tasks:
73
+ 1. Setting up the logging manager
74
+ 2. Parsing the command line arguments
75
+ 3. Setting up the context
76
+
77
+ Args:
78
+ args: The command line arguments to parse.
79
+ attributes: The attributes class to use for the context. (e.g., SolanaProverAttributes or SorobanProverAttributes)
80
+ Returns:
81
+ A tuple containing the CertoraContext object and the LoggingManager object.
82
+ """
83
+ Attrs.set_attribute_class(attributes)
84
+ non_str_els = [x for x in args if not isinstance(x, str)]
85
+ if non_str_els:
86
+ print(f"args for run_certora that are not strings: {non_str_els}")
87
+ exit(1)
88
+
89
+ # If we are not in debug mode, we do not want to print the traceback in case of exceptions.
90
+ if '--debug' not in args: # We check manually, because we want no traceback in argument parsing exceptions
91
+ sys.tracebacklimit = 0
92
+
93
+ # creating the default internal dir, files may be copied to user defined build directory after
94
+ # parsing the input
95
+
96
+ if not ('--help' in args or '--version' in args):
97
+ Util.reset_certora_internal_dir()
98
+ Util.safe_create_dir(Util.get_build_dir())
99
+ logging_manager = LoggingManager()
100
+
101
+ Ctx.handle_flags_in_args(args)
102
+ context = Ctx.get_args(args) # Parse arguments
103
+
104
+ assert logging_manager, "logging manager was not set"
105
+ logging_manager.set_log_level_and_format(is_quiet=Ctx.is_minimal_cli_output(context),
106
+ debug=context.debug,
107
+ debug_topics=context.debug_topics,
108
+ show_debug_topics=context.show_debug_topics)
109
+
110
+ return context, logging_manager
111
+
112
+
113
+ def collect_and_dump_metadata(context: CertoraContext) -> None:
114
+ """
115
+ Collect and validate run metadata.
116
+
117
+ Args:
118
+ context: The Certora context containing verification settings
119
+
120
+ Raises:
121
+ Util.TestResultsReady: If this is a metadata test run
122
+ """
123
+ metadata = collect_run_metadata(wd=Path.cwd(), raw_args=sys.argv, context=context)
124
+
125
+ if context.test == str(Util.TestValue.CHECK_METADATA):
126
+ raise Util.TestResultsReady(metadata)
127
+
128
+ metadata.dump()
129
+
130
+
131
+ def collect_and_dump_config_layout(context: CertoraContext) -> None:
132
+ """
133
+ Collect and dump the configuration layout.
134
+
135
+ Args:
136
+ context: The Certora context containing verification settings
137
+
138
+ Raises:
139
+ Util.TestResultsReady: If this is a configuration layout test run
140
+ """
141
+ configuration_layout = collect_configuration_layout()
142
+
143
+ if context.test == str(Util.TestValue.CHECK_CONFIG_LAYOUT):
144
+ raise Util.TestResultsReady(configuration_layout)
145
+
146
+ configuration_layout.dump()
147
+
148
+
149
+ def ensure_version_compatibility(context: CertoraContext) -> None:
150
+ if not (context.local or context.build_only or context.compilation_steps_only):
151
+ """
152
+ Before running the local type checker, we see if the current package version is compatible with
153
+ the latest. We check it before running the local type checker, because local type checking
154
+ errors could be simply a result of syntax introduced in the newest version.
155
+ The line below will raise an exception if the local version is incompatible.
156
+ """
157
+ validate_version_and_branch(context)
158
+
159
+ # --------------------------------------------------------------------------- #
160
+ # Verification helpers
161
+ # --------------------------------------------------------------------------- #
162
+
163
+ def run_local(context: CertoraContext, timings: Dict, additional_commands: Optional[List[str]] = None, compare_with_expected_file: bool = False) -> int:
164
+ """
165
+ Run the verifier locally and return its exit code (0 = success).
166
+ Args:
167
+ context: The CertoraContext object containing the configuration.
168
+ timings: A dictionary to store timing information.
169
+ additional_commands: A list of additional commands to pass to the verifier.
170
+ Returns:
171
+ An integer representing the exit code of the verifier run.
172
+ """
173
+ cmd: List[str] = Ctx.get_local_run_cmd(context)
174
+
175
+ if additional_commands:
176
+ cmd.extend(additional_commands)
177
+
178
+ print("Verifier run command:\n %s", " ".join(cmd))
179
+ rc = Util.run_jar_cmd(
180
+ cmd,
181
+ override_exit_code=compare_with_expected_file,
182
+ logger_topic="verification",
183
+ print_output=True,
184
+ )
185
+
186
+ if rc == 0:
187
+ Util.print_completion_message("Finished running verifier:")
188
+ print("\t%s", " ".join(cmd))
189
+ timings.setdefault("buildTime", 0.0) # ensure key exists
190
+ return 0
191
+
192
+ return 1
193
+
194
+
195
+ def run_remote(
196
+ context: CertoraContext,
197
+ args: List[str],
198
+ timings: Dict,
199
+ ) -> Tuple[int, Optional[CertoraRunResult]]:
200
+ """
201
+ Run verification in Certora Cloud.
202
+
203
+ Args:
204
+ context: The CertoraContext object containing the configuration.
205
+ args: The command line arguments to pass to the cloud verification.
206
+ timings: A dictionary to store timing information.
207
+ Returns:
208
+ A tuple containing the exit code (0 = success) and an optional CertoraRunResult object.
209
+ """
210
+ if context.compilation_steps_only:
211
+ return 0, CertoraRunResult(None, False, Util.get_certora_sources_dir(), None)
212
+
213
+ context.key = Cv.validate_certora_key()
214
+ cloud = CloudVerification(context, timings)
215
+
216
+ pretty_args = [f"'{a}'" if " " in a else a for a in args]
217
+
218
+ ok = cloud.cli_verify_and_report(" ".join(pretty_args), context.wait_for_results)
219
+
220
+ exit_code = 0 if ok else VIOLATIONS_EXIT_CODE
221
+ result: Optional[CertoraRunResult] = None
222
+ if cloud.statusUrl:
223
+ result = CertoraRunResult(
224
+ cloud.statusUrl,
225
+ False,
226
+ Util.get_certora_sources_dir(),
227
+ cloud.reportUrl,
228
+ )
229
+ return exit_code, result
230
+
231
+
232
+ def handle_exit(exit_code: int, return_value: Optional[CertoraRunResult]) -> Optional[CertoraRunResult]:
233
+ """
234
+ Handle the exit code of the verification run.
235
+ Args:
236
+ exit_code: The exit code of the verification run.
237
+ return_value: The CertoraRunResult object containing the results of the verification run.
238
+ Raises:
239
+ CertoraFoundViolations: If violations were found during the verification run.
240
+ Util.CertoraUserInputError: If there was an error with the user input.
241
+ Returns:
242
+ The CertoraRunResult object containing the results of the verification run.
243
+ """
244
+ if exit_code == VIOLATIONS_EXIT_CODE:
245
+ raise CertoraFoundViolations("violations were found", return_value)
246
+ if exit_code != 0:
247
+ raise Util.CertoraUserInputError(f"run_certora failed (code {exit_code})")
248
+ return return_value
249
+
250
+
251
+ # --------------------------------------------------------------------------- #
252
+ # Entry point decorator
253
+ # --------------------------------------------------------------------------- #
254
+
255
+ console = Console()
256
+
257
+ def catch_exits(fn: Callable[..., None]) -> Callable[..., NoReturn]:
258
+ """
259
+ Wrap any entry-point in a standard try/except + sys.exit logic.
260
+ The wrapped function should do its work and then return normally;
261
+ this decorator will exit(0) on success or exit(1/other) on failure.
262
+ """
263
+ @functools.wraps(fn)
264
+ def wrapper(*args, **kwargs) -> NoReturn: # type: ignore
265
+ try:
266
+ fn(*args, **kwargs)
267
+ sys.exit(0)
268
+
269
+ except KeyboardInterrupt:
270
+ console.print("[bold red]\nInterrupted by user")
271
+ sys.exit(1)
272
+
273
+ except Util.TestResultsReady:
274
+ print("reached checkpoint")
275
+ sys.exit(0)
276
+
277
+ except CertoraFoundViolations as e:
278
+ link = getattr(e.results, "rule_report_link", None)
279
+ if link:
280
+ print(f"report url: {link}")
281
+ console.print("[bold red]\nViolations were found\n")
282
+ sys.exit(1)
283
+
284
+ except Util.CertoraUserInputError as e:
285
+ if e.orig:
286
+ print(f"\n{str(e.orig).strip()}")
287
+ if e.more_info:
288
+ print(f"\n{e.more_info.strip()}")
289
+ console.print(f"[bold red]\n{e}\n")
290
+ sys.exit(1)
291
+
292
+ except Util.ExitException as e:
293
+ console.print(f"[bold red]{e}")
294
+ sys.exit(e.exit_code)
295
+
296
+ except Exception as e:
297
+ console.print(f"[bold red]{e}")
298
+ sys.exit(1)
299
+
300
+ return wrapper
@@ -0,0 +1,62 @@
1
+ # The Certora Prover
2
+ # Copyright (C) 2025 Certora Ltd.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, version 3 of the License.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
+
16
+ """
17
+ Shared helpers for Rust-based targets (Solana & Soroban).
18
+
19
+ Placing the build logic in one module removes
20
+ duplication from the dedicated entry scripts.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import sys
26
+ from pathlib import Path
27
+
28
+ scripts_dir_path = Path(__file__).parent.parent.resolve() # containing directory
29
+ sys.path.insert(0, str(scripts_dir_path))
30
+
31
+ import time
32
+ import logging
33
+ from typing import Dict
34
+
35
+ from Shared import certoraUtils as Util
36
+
37
+ from CertoraProver.certoraContextClass import CertoraContext
38
+
39
+ from CertoraProver.certoraBuildRust import set_rust_build_directory
40
+
41
+
42
+ log = logging.getLogger(__name__)
43
+
44
+
45
+ # --------------------------------------------------------------------------- #
46
+ # Build
47
+ # --------------------------------------------------------------------------- #
48
+
49
+ def build_rust_project(context: CertoraContext, timings: Dict) -> None:
50
+ """
51
+ Compile the Rust artefact and record elapsed time in *timings*.
52
+
53
+ Args:
54
+ context: The CertoraContext object containing the configuration.
55
+ timings: A dictionary to store timing information.
56
+ """
57
+ log.debug("Build Rust target")
58
+ start = time.perf_counter()
59
+ set_rust_build_directory(context)
60
+ timings["buildTime"] = round(time.perf_counter() - start, 4)
61
+ if context.test == str(Util.TestValue.AFTER_BUILD):
62
+ raise Util.TestResultsReady(context)
@@ -22,7 +22,8 @@ scripts_dir_path = Path(__file__).parent.resolve() # containing directory
22
22
  sys.path.insert(0, str(scripts_dir_path))
23
23
 
24
24
  import CertoraProver.certoraContextAttributes as Attrs
25
- from certoraRun import run_certora, CertoraRunResult
25
+ from Shared.proverCommon import CertoraRunResult
26
+ from certoraRun import run_certora
26
27
  from typing import List, Optional
27
28
 
28
29
 
@@ -17,15 +17,13 @@
17
17
 
18
18
  import sys
19
19
  from pathlib import Path
20
- from rich.console import Console
21
-
22
20
 
23
21
  scripts_dir_path = Path(__file__).parent.resolve() # containing directory
24
22
  sys.path.insert(0, str(scripts_dir_path))
25
23
 
26
24
  import CertoraProver.certoraContextAttributes as Attrs
27
- from Shared import certoraUtils as Util
28
- from certoraRun import run_certora, CertoraRunResult, CertoraFoundViolations
25
+ from certoraRun import run_certora
26
+ from Shared.proverCommon import CertoraRunResult, catch_exits
29
27
 
30
28
  from typing import List, Optional
31
29
 
@@ -33,39 +31,9 @@ from typing import List, Optional
33
31
  def run_ranger(args: List[str]) -> Optional[CertoraRunResult]:
34
32
  return run_certora(args, Attrs.RangerAttributes, prover_cmd=sys.argv[0])
35
33
 
34
+ @catch_exits
36
35
  def entry_point() -> None:
37
- try:
38
- run_ranger(sys.argv[1:])
39
- sys.exit(0)
40
- except KeyboardInterrupt:
41
- Console().print("[bold red]\nInterrupted by user")
42
- sys.exit(1)
43
- except Util.TestResultsReady:
44
- print("reached checkpoint")
45
- sys.exit(0)
46
- except CertoraFoundViolations as e:
47
- try:
48
- assert e.results
49
- print(f"report url: {e.results.rule_report_link}")
50
- except Exception:
51
- pass
52
- Console().print("[bold red]\nViolations were found\n")
53
- sys.exit(1)
54
- except Util.CertoraUserInputError as e:
55
- if e.orig:
56
- print(f"\n{str(e.orig).strip()}")
57
- if e.more_info:
58
- print(f"\n{e.more_info.strip()}")
59
- Console().print(f"[bold red]\n{e}\n")
60
- sys.exit(1)
61
-
62
- except Util.ExitException as e:
63
- Console().print(f"[bold red]{e}")
64
- sys.exit(e.exit_code)
65
-
66
- except Exception as e:
67
- Console().print(f"[bold red]{e}")
68
- sys.exit(1)
36
+ run_ranger(sys.argv[1:])
69
37
 
70
38
  if __name__ == '__main__':
71
39
  entry_point()