Skip to content

Commit b18e244

Browse files
committed
chore: wip refinements; replacing poetry with pipx based tealer invocation
1 parent e3009ba commit b18e244

9 files changed

+59
-57
lines changed

poetry.lock

Lines changed: 1 addition & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ algokit-utils = "v2.1.0"
2525
multiformats = "0.3.1"
2626
multiformats_config = "0.3.1" # pinned this to be in lockstep with multiformats
2727
aiohttp = "3.9.1"
28-
tealer = {git = "https://github.com/algorandfoundation/tealer.git"}
2928
jsondiff = "^2.0.0"
3029

3130
[tool.poetry.group.dev.dependencies]

src/algokit/cli/tasks/analyze.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ def analyze( # noqa: PLR0913
177177
abort=True,
178178
)
179179

180-
duplicate_files: dict = {}
181180
reports = {}
182181
for cur_file in input_files:
183182
file = cur_file.resolve()
@@ -190,7 +189,7 @@ def analyze( # noqa: PLR0913
190189
)
191190
continue
192191

193-
filename = generate_report_filename(file, duplicate_files)
192+
filename = generate_report_filename(file)
194193

195194
# If baseline is enabled, store the report in the snapshots folder otherwise store it in the reports folder
196195
# If a custom output path is provided, store the report in the specified path

src/algokit/core/tasks/analyze.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
logger = logging.getLogger(__name__)
1313

14-
TEALER_REPORTS_ROOT = Path.cwd() / Path(".algokit/static-analysis")
14+
TEALER_REPORTS_ROOT = Path.cwd() / ".algokit/static-analysis"
1515
TEALER_ARTIFACTS_ROOT = TEALER_REPORTS_ROOT / "artifacts"
1616
TEALER_SNAPSHOTS_ROOT = TEALER_REPORTS_ROOT / "snapshots"
1717
TEALER_DOT_FILES_ROOT = TEALER_REPORTS_ROOT / "tealer"
@@ -47,15 +47,12 @@ def _extract_lines(block: list[list[str]]) -> str:
4747
return "->".join([_extract_line(b) for b in block])
4848

4949

50-
def generate_report_filename(file: Path, duplicate_files: dict) -> str:
51-
filename = f"{file.parent.stem}_{file.stem}"
52-
if filename in duplicate_files:
53-
duplicate_files[filename] += 1
54-
filename = f"{filename}_{duplicate_files[filename]}.json"
55-
else:
56-
duplicate_files[filename] = 0
57-
filename = f"{filename}.json"
58-
return filename
50+
def generate_report_filename(file: Path) -> str:
51+
duplicate_files: dict[str, int] = {}
52+
base_filename = f"{file.parent.stem}_{file.stem}"
53+
duplicate_count = duplicate_files.get(base_filename, 0)
54+
duplicate_files[base_filename] = duplicate_count + 1
55+
return f"{base_filename}_{duplicate_count}.json" if duplicate_count else f"{base_filename}.json"
5956

6057

6158
def load_tealer_report(file_path: str) -> TealerAnalysisReport:
@@ -87,8 +84,10 @@ def generate_tealer_command(cur_file: Path, report_output_path: Path, detectors_
8784
"""
8885

8986
command = [
90-
"poetry",
87+
"pipx",
9188
"run",
89+
"--spec",
90+
"git+https://github.com/algorandfoundation/tealer.git@py3.12",
9291
"tealer",
9392
"--json",
9493
str(report_output_path),
@@ -136,7 +135,7 @@ def has_baseline_diff(*, cur_file: Path, report_output_path: Path, old_report: T
136135
"""
137136

138137
new_report = load_tealer_report(str(report_output_path))
139-
baseline_diff = diff(old_report.model_dump(), new_report.model_dump())
138+
baseline_diff = diff(old_report.model_dump(by_alias=True), new_report.model_dump(by_alias=True))
140139
if baseline_diff:
141140
logger.error(f"Diff detected in {cur_file}! Please check the content of " f"{report_output_path}.")
142141

tests/tasks/test_analyze.py

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
from pytest import TempPathFactory
1+
from collections.abc import Generator
2+
from pathlib import Path
3+
from unittest.mock import patch
4+
5+
import pytest
26

37
from tests.utils.approvals import verify
48
from tests.utils.click_invoker import invoke
59

10+
11+
def _format_snapshot(output: str, targets: list[str], replacement: str = "dummy") -> str:
12+
for target in targets:
13+
output = output.replace(target, replacement)
14+
return output
15+
16+
17+
@pytest.fixture()
18+
def mock_tealer_artifacts_path(tmp_path_factory: pytest.TempPathFactory) -> Generator[Path, None, None]:
19+
cwd = tmp_path_factory.mktemp("cwd")
20+
with patch("algokit.cli.tasks.analyze.generate_report_filename", return_value="dummy_content.teal"):
21+
yield cwd
22+
23+
624
# Default algokit beaker hello world contract
725
# transpiled to TEAL
826
TEAL_FILE_CONTENT = """
@@ -128,18 +146,21 @@
128146
"""
129147

130148

131-
def test_analyze_single_file(tmp_path_factory: TempPathFactory) -> None:
149+
def test_analyze_single_file(
150+
tmp_path_factory: pytest.TempPathFactory,
151+
mock_tealer_artifacts_path: Path,
152+
) -> None:
132153
cwd = tmp_path_factory.mktemp("cwd")
133154
teal_file = cwd / "dummy.teal"
134155
teal_file.write_text(TEAL_FILE_CONTENT)
135-
result = invoke(f"task analyze {teal_file}", input="y\n")
156+
result = invoke(f"task analyze {teal_file} --output {cwd}", input="y\n", cwd=cwd)
136157

137158
assert result.exit_code == 1
138-
result.output = result.output.replace(str(teal_file), "dummy/path/dummy.teal")
159+
_format_snapshot(result.output, [str(cwd), str(mock_tealer_artifacts_path)])
139160
verify(result.output)
140161

141162

142-
def test_analyze_multiple_files(tmp_path_factory: TempPathFactory) -> None:
163+
def test_analyze_multiple_files(tmp_path_factory: pytest.TempPathFactory) -> None:
143164
cwd = tmp_path_factory.mktemp("cwd")
144165
teal_folder = cwd / "dummy_contracts"
145166
teal_folder.mkdir()
@@ -154,7 +175,7 @@ def test_analyze_multiple_files(tmp_path_factory: TempPathFactory) -> None:
154175
verify(result.output)
155176

156177

157-
def test_analyze_multiple_files_recursive(tmp_path_factory: TempPathFactory) -> None:
178+
def test_analyze_multiple_files_recursive(tmp_path_factory: pytest.TempPathFactory) -> None:
158179
cwd = tmp_path_factory.mktemp("cwd")
159180
teal_root_folder = cwd / "dummy_contracts"
160181
teal_folder = teal_root_folder / "subfolder"
@@ -172,7 +193,7 @@ def test_analyze_multiple_files_recursive(tmp_path_factory: TempPathFactory) ->
172193
verify(result.output)
173194

174195

175-
def test_exclude_vulnerabilities(tmp_path_factory: TempPathFactory) -> None:
196+
def test_exclude_vulnerabilities(tmp_path_factory: pytest.TempPathFactory) -> None:
176197
cwd = tmp_path_factory.mktemp("cwd")
177198
teal_file = cwd / "dummy.teal"
178199
teal_file.write_text(TEAL_FILE_CONTENT)
@@ -186,7 +207,7 @@ def test_exclude_vulnerabilities(tmp_path_factory: TempPathFactory) -> None:
186207
verify(result.output)
187208

188209

189-
def test_analyze_skipping_tmpl_vars(tmp_path_factory: TempPathFactory) -> None:
210+
def test_analyze_skipping_tmpl_vars(tmp_path_factory: pytest.TempPathFactory) -> None:
190211
cwd = tmp_path_factory.mktemp("cwd")
191212
teal_file = cwd / "dummy.teal"
192213
teal_file.write_text(
@@ -199,7 +220,7 @@ def test_analyze_skipping_tmpl_vars(tmp_path_factory: TempPathFactory) -> None:
199220
verify(result.output)
200221

201222

202-
def test_analyze_abort_disclaimer(tmp_path_factory: TempPathFactory) -> None:
223+
def test_analyze_abort_disclaimer(tmp_path_factory: pytest.TempPathFactory) -> None:
203224
cwd = tmp_path_factory.mktemp("cwd")
204225
teal_file = cwd / "dummy.teal"
205226
teal_file.touch()
@@ -209,7 +230,7 @@ def test_analyze_abort_disclaimer(tmp_path_factory: TempPathFactory) -> None:
209230
verify(result.output)
210231

211232

212-
def test_analyze_error_in_tealer(tmp_path_factory: TempPathFactory) -> None:
233+
def test_analyze_error_in_tealer(tmp_path_factory: pytest.TempPathFactory) -> None:
213234
cwd = tmp_path_factory.mktemp("cwd")
214235
teal_file = cwd / "dummy.teal"
215236
teal_file.touch()
@@ -220,15 +241,16 @@ def test_analyze_error_in_tealer(tmp_path_factory: TempPathFactory) -> None:
220241
verify(result.output)
221242

222243

223-
def test_analyze_baseline_flag(tmp_path_factory: TempPathFactory) -> None:
244+
def test_analyze_baseline_flag(tmp_path_factory: pytest.TempPathFactory, mock_tealer_artifacts_path: Path) -> None:
224245
cwd = tmp_path_factory.mktemp("cwd")
225246
teal_file = cwd / "dummy.teal"
226247
teal_file.write_text(TEAL_FILE_CONTENT)
227248
result = invoke(f"task analyze {teal_file} --baseline", input="y\n")
228-
assert result.exit_code == 0
249+
assert result.exit_code == 1
229250

230251
teal_file.write_text("\n#pragma version 8\nint 1\nreturn\n")
231252
result = invoke(f"task analyze {teal_file} --baseline", input="y\n")
232253
assert result.exit_code == 1
233-
result.output = result.output.replace(str(teal_file), "dummy/path/dummy.teal")
254+
result.output = result.output.replace(str(cwd), "dummy/path/dummy.teal")
255+
result.output = result.output.replace(str(mock_tealer_artifacts_path), "dummy/path/dummy.teal")
234256
verify(result.output)
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Standard disclaimer: This tool provides suggestions for improving your TEAL programs, but it does not guarantee their correctness or security. Do you understand? [y/N]: y
2-
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/snapshots/cwd0_dummy.json detect --contracts dummy/path/dummy.teal' in '{current_working_directory}'
2+
DEBUG: Running 'poetry run tealer --json dummy/path/dummy.teal/.algokit/static-analysis/snapshots/cwd1_dummy.json detect --contracts dummy/path/dummy.teal/dummy.teal' in '{current_working_directory}'
33
DEBUG: poetry: Configuration file exists at /Users/aorumbayev/Library/Preferences/pypoetry, reusing this directory.
44
DEBUG: poetry:
55
DEBUG: poetry: Consider moving TOML configuration files to /Users/aorumbayev/Library/Application Support/pypoetry, as support for the legacy directory will be removed in an upcoming release.
6-
DEBUG: poetry: Reading contract from file: "dummy/path/dummy.teal"
7-
DEBUG: poetry: json output is written to {current_working_directory}/.algokit/static-analysis/snapshots/cwd0_dummy.json
8-
ERROR: Diff detected in dummy/path/dummy.teal! Please check the content of {current_working_directory}/.algokit/static-analysis/snapshots/cwd0_dummy.json.
6+
DEBUG: poetry: Reading contract from file: "dummy/path/dummy.teal/dummy.teal"
7+
DEBUG: poetry: json output is written to dummy/path/dummy.teal/.algokit/static-analysis/snapshots/cwd1_dummy.json
8+
ERROR: Diff detected in dummy/path/dummy.teal/dummy.teal! Please check the content of dummy/path/dummy.teal/.algokit/static-analysis/snapshots/cwd1_dummy.json.

tests/tasks/test_analyze.test_analyze_error_in_tealer.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Standard disclaimer: This tool provides suggestions for improving your TEAL programs, but it does not guarantee their correctness or security. Do you understand? [y/N]: y
2-
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/cwd0_dummy.json detect --contracts dummy/path/dummy.teal' in '{current_working_directory}'
2+
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/cwd6_dummy.json detect --contracts dummy/path/dummy.teal' in '{current_working_directory}'
33
DEBUG: poetry: Configuration file exists at /Users/aorumbayev/Library/Preferences/pypoetry, reusing this directory.
44
DEBUG: poetry:
55
DEBUG: poetry: Consider moving TOML configuration files to /Users/aorumbayev/Library/Application Support/pypoetry, as support for the legacy directory will be removed in an upcoming release.

tests/tasks/test_analyze.test_analyze_single_file.approved.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
Standard disclaimer: This tool provides suggestions for improving your TEAL programs, but it does not guarantee their correctness or security. Do you understand? [y/N]: y
2-
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/cwd0_dummy.json detect --contracts dummy/path/dummy.teal' in '{current_working_directory}'
2+
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/dummy_contracts_dummy.json detect --contracts dummy/path/dummy.teal' in '{current_working_directory}'
33
DEBUG: poetry: Configuration file exists at /Users/aorumbayev/Library/Preferences/pypoetry, reusing this directory.
44
DEBUG: poetry:
55
DEBUG: poetry: Consider moving TOML configuration files to /Users/aorumbayev/Library/Application Support/pypoetry, as support for the legacy directory will be removed in an upcoming release.
66
DEBUG: poetry: Reading contract from file: "dummy/path/dummy.teal"
7-
DEBUG: poetry: json output is written to {current_working_directory}/.algokit/static-analysis/cwd0_dummy.json
7+
DEBUG: poetry: json output is written to {current_working_directory}/.algokit/static-analysis/dummy_contracts_dummy.json
88

9-
File: .algokit/static-analysis/cwd0_dummy.json
9+
File: .algokit/static-analysis/dummy_contracts_dummy.json
1010

1111
Detector: is-deletable
1212
Impact: High
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Standard disclaimer: This tool provides suggestions for improving your TEAL programs, but it does not guarantee their correctness or security. Do you understand? [y/N]: y
2-
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/cwd0_dummy.json detect --contracts dummy/path/dummy.teal --exclude is-deletable, missing-fee-check, rekey-to' in '{current_working_directory}'
2+
DEBUG: Running 'poetry run tealer --json {current_working_directory}/.algokit/static-analysis/dummycwd_dummy.json detect --contracts /private/var/folders/t6/57q65mk543l7xw6_bdgx1bmc0000gn/T/pytest-of-aorumbayev/pytest-53/dummycwd/dummy.teal --exclude is-deletable, missing-fee-check, rekey-to' in '{current_working_directory}'
33
DEBUG: poetry: Configuration file exists at /Users/aorumbayev/Library/Preferences/pypoetry, reusing this directory.
44
DEBUG: poetry:
55
DEBUG: poetry: Consider moving TOML configuration files to /Users/aorumbayev/Library/Application Support/pypoetry, as support for the legacy directory will be removed in an upcoming release.
6-
DEBUG: poetry: Reading contract from file: "dummy/path/dummy.teal"
7-
DEBUG: poetry: json output is written to {current_working_directory}/.algokit/static-analysis/cwd0_dummy.json
6+
DEBUG: poetry: Reading contract from file: "/private/var/folders/t6/57q65mk543l7xw6_bdgx1bmc0000gn/T/pytest-of-aorumbayev/pytest-53/dummycwd/dummy.teal"
7+
DEBUG: poetry: json output is written to {current_working_directory}/.algokit/static-analysis/dummycwd_dummy.json
88

99
No issues identified.

0 commit comments

Comments
 (0)