Skip to content

Commit 1cd5d30

Browse files
committed
Address remaining Codacy + SonarCloud suppressions
- templates.py: branch the Jinja Environment ctor so autoescape is a literal True/False, satisfying Bandit B701 / SonarCloud S5496; the False branch carries the suppression for caller-opted-out renders. - Use NOSONAR(rule_key) syntax (parentheses) to fix python:S7632 'invalid suppression comment' across archive_ops, ftp/client, _websocket, test_archive_ops, test_cross_backend, test_fsspec_bridge. - _websocket SHA-1: add nosemgrep + NOSONAR inline on the call so Codacy's semgrep scanner skips the RFC 6455 handshake digest. - test_fsspec_bridge: narrow the import-order disable to pylint so Codacy stops flagging the pytest.importorskip pattern. - test_smb_client: annotate the smbclient_module fixture parameter whose only job is to trigger the smbprotocol patch.
1 parent 47566b8 commit 1cd5d30

File tree

8 files changed

+25
-13
lines changed

8 files changed

+25
-13
lines changed

automation_file/local/archive_ops.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def list_archive(path: str | os.PathLike[str]) -> list[str]:
5757
with zipfile.ZipFile(path) as zf:
5858
return zf.namelist()
5959
if fmt.startswith("tar"):
60-
with tarfile.open(path) as tf: # nosec B202 - metadata listing only, no extraction
60+
with tarfile.open(path) as tf: # nosec B202 # NOSONAR(python:S5042) metadata listing only, no extraction
6161
return tf.getnames()
6262
if fmt == "7z":
6363
return _seven_zip_namelist(path)
@@ -88,13 +88,13 @@ def extract_archive(
8888
def _is_tar_stream(path: Path, compression: str) -> bool:
8989
try:
9090
if compression == "gz":
91-
with tarfile.open(path, mode="r:gz"): # nosec B202 - read-only probe
91+
with tarfile.open(path, mode="r:gz"): # nosec B202 # NOSONAR(python:S5042) read-only probe, no extraction
9292
return True
9393
if compression == "bz2":
94-
with tarfile.open(path, mode="r:bz2"): # nosec B202 - read-only probe
94+
with tarfile.open(path, mode="r:bz2"): # nosec B202 # NOSONAR(python:S5042) read-only probe, no extraction
9595
return True
9696
if compression == "xz":
97-
with tarfile.open(path, mode="r:xz"): # nosec B202 - read-only probe
97+
with tarfile.open(path, mode="r:xz"): # nosec B202 # NOSONAR(python:S5042) read-only probe, no extraction
9898
return True
9999
except (tarfile.TarError, OSError):
100100
return False
@@ -125,7 +125,7 @@ def _extract_tar(source: Path, dest: Path) -> list[str]:
125125
names: list[str] = []
126126
# Per-member path containment + link rejection below; on 3.12+ the
127127
# tarfile.data_filter enforces the same rules at the C layer.
128-
with tarfile.open(source) as tf: # nosec B202 - entries validated before extract
128+
with tarfile.open(source) as tf: # nosec B202 # NOSONAR(python:S5042) entries validated before extract
129129
_apply_tar_data_filter(tf)
130130
for member in tf.getmembers():
131131
out = dest / member.name

automation_file/local/templates.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ def _render_with_jinja(
9797
from jinja2 import TemplateError as JinjaTemplateError
9898
except ImportError:
9999
return None
100-
env = Environment(autoescape=autoescape, undefined=StrictUndefined)
100+
# Autoescape is enabled by default for HTML-like outputs (_wants_autoescape).
101+
# Callers that explicitly pass autoescape=False own the safety of the context.
102+
if autoescape:
103+
env = Environment(autoescape=True, undefined=StrictUndefined)
104+
else:
105+
# nosec B701 # NOSONAR(pythonsecurity:S5496) caller opted out for non-HTML output
106+
env = Environment(autoescape=False, undefined=StrictUndefined)
101107
try:
102108
return env.from_string(template).render(**context)
103109
except JinjaTemplateError as error:

automation_file/remote/ftp/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def later_init(self, options: FTPConnectOptions | None = None, **kwargs: Any) ->
4747
ftp: FTP = FTP_TLS(timeout=opts.timeout)
4848
else:
4949
# Plaintext FTP only when caller opts in via tls=False.
50-
ftp = FTP(timeout=opts.timeout) # nosec B321 NOSONAR python:S5332
50+
ftp = FTP(timeout=opts.timeout) # nosec B321 # NOSONAR(python:S4423) plaintext FTP is opt-in via tls=False
5151
try:
5252
ftp.connect(opts.host, opts.port, timeout=opts.timeout)
5353
if opts.tls and isinstance(ftp, FTP_TLS):

automation_file/server/_websocket.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ def compute_accept_key(sec_websocket_key: str) -> str:
2727
security primitive. ``usedforsecurity=False`` tells static analysers to
2828
skip the standard SHA-1 "insecure hash" warning.
2929
"""
30-
# nosec B303 B324 - RFC 6455 handshake, not a security primitive.
31-
digest = hashlib.sha1(
30+
digest = hashlib.sha1( # nosec B303 B324 # nosemgrep: python.lang.security.audit.hashlib-insecure-functions # NOSONAR(python:S4790) RFC 6455 handshake, not a security primitive
3231
(sec_websocket_key + _GUID).encode("ascii"),
3332
usedforsecurity=False,
3433
).digest()

tests/test_archive_ops.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ def _make_zip(path: Path, entries: dict[str, bytes]) -> None:
2525

2626

2727
def _make_tar(path: Path, entries: dict[str, bytes], mode: str = "w") -> None:
28-
with tarfile.open(path, mode) as tf:
28+
with tarfile.open(
29+
path, mode
30+
) as tf: # NOSONAR(python:S5042) test fixture writes a known archive
2931
for name, data in entries.items():
3032
info = tarfile.TarInfo(name)
3133
info.size = len(data)

tests/test_cross_backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_missing_local_source_returns_false(tmp_path: Path) -> None:
4444
def test_unknown_source_scheme_raises() -> None:
4545
# The target path is unused — the call must fail on the source scheme
4646
# before touching the filesystem. nosec B108 - filesystem never touched here.
47-
unused_target = "/tmp/x" # nosec B108 NOSONAR python:S5443
47+
unused_target = "/tmp/x" # nosec B108 # NOSONAR(python:S5443) filesystem never touched
4848
with pytest.raises(CrossBackendException):
4949
copy_between("gopher://a/b", unused_target)
5050

tests/test_fsspec_bridge.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
fsspec = pytest.importorskip("fsspec")
1212

13+
# pylint: disable=wrong-import-position # importorskip must precede these imports
1314
from automation_file.exceptions import FsspecException # noqa: E402
1415
from automation_file.remote.fsspec_bridge import ( # noqa: E402
1516
FsspecEntry,
@@ -25,7 +26,8 @@
2526

2627
def _purge_memory_fs() -> None:
2728
fs = fsspec.filesystem("memory")
28-
for path in list(fs.store):
29+
# list() snapshot required — fs.rm() mutates fs.store during iteration.
30+
for path in list(fs.store): # NOSONAR(python:S7504)
2931
with contextlib.suppress(FileNotFoundError):
3032
fs.rm(path)
3133

tests/test_smb_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ def write(self, chunk: bytes) -> None:
100100
assert call_kwargs["mode"] == "wb"
101101

102102

103-
def test_upload_rejects_missing_local(smbclient_module: ModuleType, tmp_path: Path) -> None:
103+
def test_upload_rejects_missing_local(
104+
smbclient_module: ModuleType, # pylint: disable=unused-argument # fixture triggers the smbprotocol patch
105+
tmp_path: Path,
106+
) -> None:
104107
client = SMBClient("fs", "pub")
105108
with pytest.raises(SMBException):
106109
client.upload(tmp_path / "absent", "remote/data.bin")

0 commit comments

Comments
 (0)