Skip to content

Commit b0d01ab

Browse files
authored
fix: add debug logging and fix bandit multi-target separator (#36)
* fix: add debug logging and fix bandit multi-target separator * fix: handle empty RUNNER_DEBUG env var in bool validator
1 parent 674cb71 commit b0d01ab

5 files changed

Lines changed: 78 additions & 5 deletions

File tree

action.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ inputs:
3333
artifact_name:
3434
description: Name of the artifact uploaded by the action
3535
default: security-audit-reports
36+
debug:
37+
description: Enable debug logging for the Python audit module
38+
default: 'false'
3639

3740
runs:
3841
using: composite
@@ -52,7 +55,7 @@ runs:
5255
IFS=',' read -ra parts <<< "$BANDIT_SCAN_DIRS"
5356
for part in "${parts[@]}"; do
5457
[[ "$part" == "." ]] && t="$WORKING_DIRECTORY" || t="$WORKING_DIRECTORY/$part"
55-
resolved="${resolved:+$resolved,}$t"
58+
resolved="${resolved:+$resolved }$t"
5659
done
5760
echo "targets=$resolved" >> "$GITHUB_OUTPUT"
5861
fi
@@ -84,6 +87,8 @@ runs:
8487
POST_PR_COMMENT: ${{ inputs.post_pr_comment }}
8588
GITHUB_TOKEN: ${{ inputs.github_token }}
8689
PR_NUMBER: ${{ github.event.pull_request.number }}
90+
INPUT_DEBUG: ${{ inputs.debug }}
91+
RUNNER_DEBUG: ${{ runner.debug }}
8792
run: uv run --no-project --with "${{ github.action_path }}" python -m python_security_auditing
8893

8994
- name: Upload ${{ inputs.artifact_name }}

src/python_security_auditing/__main__.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,35 @@
1515
def main() -> None:
1616
settings = Settings()
1717

18+
if settings.debug:
19+
print(f"[debug] settings: {settings.model_dump()}", file=sys.stderr)
20+
1821
bandit_report: dict[str, Any] = {}
1922
pip_audit_report: list[dict[str, Any]] = []
2023

2124
if "bandit" in settings.enabled_tools:
25+
if settings.debug:
26+
print(
27+
f"[debug] reading bandit SARIF from {settings.bandit_sarif_path}", file=sys.stderr
28+
)
2229
bandit_report = read_bandit_sarif(Path(settings.bandit_sarif_path))
30+
if settings.debug:
31+
print(
32+
f"[debug] bandit findings: {len(bandit_report.get('results', []))}", file=sys.stderr
33+
)
2334

2435
if "pip-audit" in settings.enabled_tools:
36+
if settings.debug:
37+
print(
38+
f"[debug] generating requirements for package_manager={settings.package_manager}",
39+
file=sys.stderr,
40+
)
2541
requirements_path = generate_requirements(settings)
26-
pip_audit_report = run_pip_audit(requirements_path)
42+
if settings.debug:
43+
print(f"[debug] running pip-audit on {requirements_path}", file=sys.stderr)
44+
pip_audit_report = run_pip_audit(requirements_path, settings)
45+
if settings.debug:
46+
print(f"[debug] pip-audit findings: {len(pip_audit_report)}", file=sys.stderr)
2747

2848
markdown = build_markdown(bandit_report, pip_audit_report, settings)
2949
write_step_summary(markdown, settings)

src/python_security_auditing/runners.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,25 @@ def generate_requirements(settings: Settings) -> Path:
2929
out_path = Path(tmp.name)
3030

3131
if pm == "uv":
32+
cmd = ["uv", "export", "--format", "requirements-txt", "--no-hashes", "-o", str(out_path)]
33+
if settings.debug:
34+
print(f"[debug] uv export command: {cmd}", file=sys.stderr)
3235
subprocess.run(
33-
["uv", "export", "--format", "requirements-txt", "--no-hashes", "-o", str(out_path)],
36+
cmd,
3437
check=True,
3538
capture_output=True,
3639
text=True,
3740
)
41+
if settings.debug:
42+
print(
43+
f"[debug] generated requirements ({out_path}):\n{out_path.read_text()}",
44+
file=sys.stderr,
45+
)
3846
elif pm == "pip":
3947
result = subprocess.run(["pip", "freeze"], capture_output=True, text=True, check=True)
4048
out_path.write_text(result.stdout)
49+
if settings.debug:
50+
print(f"[debug] pip freeze output ({out_path}):\n{result.stdout}", file=sys.stderr)
4151
elif pm == "poetry":
4252
subprocess.run(
4353
["poetry", "self", "add", "poetry-plugin-export"],
@@ -59,11 +69,21 @@ def generate_requirements(settings: Settings) -> Path:
5969
capture_output=True,
6070
text=True,
6171
)
72+
if settings.debug:
73+
print(
74+
f"[debug] poetry export output ({out_path}):\n{out_path.read_text()}",
75+
file=sys.stderr,
76+
)
6277
elif pm == "pipenv":
6378
result = subprocess.run(
6479
["pipenv", "requirements"], capture_output=True, text=True, check=True
6580
)
6681
out_path.write_text(result.stdout)
82+
if settings.debug:
83+
print(
84+
f"[debug] pipenv requirements output ({out_path}):\n{result.stdout}",
85+
file=sys.stderr,
86+
)
6787

6888
return out_path
6989

@@ -110,11 +130,16 @@ def read_bandit_sarif(sarif_path: Path) -> dict[str, Any]:
110130
return {"results": results, "errors": []}
111131

112132

113-
def run_pip_audit(requirements_path: Path) -> list[dict[str, Any]]:
133+
def run_pip_audit(
134+
requirements_path: Path, settings: Settings | None = None
135+
) -> list[dict[str, Any]]:
114136
"""Run pip-audit, write pip-audit-report.json, return parsed report."""
115137
output_file = Path("pip-audit-report.json")
116138
cmd = ["pip-audit", "-r", str(requirements_path), "-f", "json"]
117139

140+
if settings and settings.debug:
141+
print(f"[debug] pip-audit command: {cmd}", file=sys.stderr)
142+
118143
result = subprocess.run(cmd, capture_output=True, text=True)
119144
# pip-audit exits 1 when vulnerabilities are found — that is expected
120145
if result.returncode not in (0, 1):
@@ -123,6 +148,13 @@ def run_pip_audit(requirements_path: Path) -> list[dict[str, Any]]:
123148
file=sys.stderr,
124149
)
125150

151+
if settings and settings.debug:
152+
print(
153+
f"[debug] pip-audit exit={result.returncode} "
154+
f"stdout_len={len(result.stdout)} stderr={result.stderr!r}",
155+
file=sys.stderr,
156+
)
157+
126158
raw = result.stdout.strip()
127159
if raw:
128160
parsed: Any = json.loads(raw)

src/python_security_auditing/settings.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ class Settings(BaseSettings):
1313

1414
model_config = SettingsConfigDict(case_sensitive=False)
1515

16+
# Debug mode — enabled via INPUT_DEBUG=true or RUNNER_DEBUG=1 (GitHub re-run with debug logging)
17+
input_debug: bool = False
18+
runner_debug: bool = False
19+
20+
@field_validator("runner_debug", mode="before")
21+
@classmethod
22+
def _runner_debug_from_int(cls, v: object) -> object:
23+
# GitHub sets RUNNER_DEBUG="1" when enabled; it may also be "" when not set
24+
if v == "" or v == "0":
25+
return False
26+
return v
27+
28+
@property
29+
def debug(self) -> bool:
30+
return self.input_debug or self.runner_debug
31+
1632
# Tool selection
1733
tools: str = "bandit,pip-audit"
1834

uv.lock

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

0 commit comments

Comments
 (0)