Commit d4bbf635ef
Unsigned
Layout: unified · split
applications/aws/aws_password_policy/evaluate_policy.py +8 −8
| @@ -21,7 +21,7 @@ import json | |||
| 21 | import sys | 21 | import sys |
| 22 | from datetime import datetime, timezone | 22 | from datetime import datetime, timezone |
| 23 | from pathlib import Path | 23 | from pathlib import Path |
| 24 | from typing import Any, Dict, List, Optional | 24 | from typing import Any |
| 25 | 25 | ||
| 26 | # ---------------------------------------------------------------------- | 26 | # ---------------------------------------------------------------------- |
| 27 | # Mapping of the 10 password‑policy fields we care about | 27 | # Mapping of the 10 password‑policy fields we care about |
| @@ -49,7 +49,7 @@ def utc_now() -> datetime: | |||
| 49 | return datetime.datetime.now(timezone.utc) | 49 | return datetime.datetime.now(timezone.utc) |
| 50 | 50 | ||
| 51 | 51 | ||
| 52 | def prompt_expected(field_type: str, description: str) -> Optional[Any]: | 52 | def prompt_expected(field_type: str, description: str) -> Any | None: |
| 53 | """ | 53 | """ |
| 54 | Ask the auditor for the expected value. | 54 | Ask the auditor for the expected value. |
| 55 | Returns: | 55 | Returns: |
| @@ -78,7 +78,7 @@ def prompt_expected(field_type: str, description: str) -> Optional[Any]: | |||
| 78 | return raw | 78 | return raw |
| 79 | 79 | ||
| 80 | 80 | ||
| 81 | def evaluate(expect: Optional[Any], actual: Any, field_type: str) -> str: | 81 | def evaluate(expect: Any | None, actual: Any, field_type: str) -> str: |
| 82 | """Return PASS / FAIL / N/A.""" | 82 | """Return PASS / FAIL / N/A.""" |
| 83 | if expect is None: | 83 | if expect is None: |
| 84 | return "N/A" | 84 | return "N/A" |
| @@ -89,7 +89,7 @@ def evaluate(expect: Optional[Any], actual: Any, field_type: str) -> str: | |||
| 89 | return "FAIL" | 89 | return "FAIL" |
| 90 | 90 | ||
| 91 | 91 | ||
| 92 | def load_json(path: Path) -> Dict[str, Any]: | 92 | def load_json(path: Path) -> dict[str, Any]: |
| 93 | """Read the JSON file generated by the Bash script.""" | 93 | """Read the JSON file generated by the Bash script.""" |
| 94 | try: | 94 | try: |
| 95 | with path.open("r", encoding="utf-8") as fh: | 95 | with path.open("r", encoding="utf-8") as fh: |
| @@ -100,8 +100,8 @@ def load_json(path: Path) -> Dict[str, Any]: | |||
| 100 | 100 | ||
| 101 | def write_csv( | 101 | def write_csv( |
| 102 | out_path: Path, | 102 | out_path: Path, |
| 103 | metadata: Dict[str, Any], | 103 | metadata: dict[str, Any], |
| 104 | rows: List[List[Any]], | 104 | rows: list[list[Any]], |
| 105 | ) -> None: | 105 | ) -> None: |
| 106 | """Write the CSV report, including a metadata header block.""" | 106 | """Write the CSV report, including a metadata header block.""" |
| 107 | with out_path.open("w", newline="", encoding="utf-8") as csvfile: | 107 | with out_path.open("w", newline="", encoding="utf-8") as csvfile: |
| @@ -136,7 +136,7 @@ def main() -> None: | |||
| 136 | # -------------------------------------------------------------- | 136 | # -------------------------------------------------------------- |
| 137 | # 1. Prompt the auditor for expectations | 137 | # 1. Prompt the auditor for expectations |
| 138 | # -------------------------------------------------------------- | 138 | # -------------------------------------------------------------- |
| 139 | expectations: Dict[str, Optional[Any]] = {} | 139 | expectations: dict[str, Any | None] = {} |
| 140 | print("\n=== Expected / Minimum Values (press <Enter> for N/A) ===\n") | 140 | print("\n=== Expected / Minimum Values (press <Enter> for N/A) ===\n") |
| 141 | for _, key, friendly, typ in POLICY_FIELDS: | 141 | for _, key, friendly, typ in POLICY_FIELDS: |
| 142 | expectations[key] = prompt_expected(typ, friendly) | 142 | expectations[key] = prompt_expected(typ, friendly) |
| @@ -144,7 +144,7 @@ def main() -> None: | |||
| 144 | # -------------------------------------------------------------- | 144 | # -------------------------------------------------------------- |
| 145 | # 2. Build the CSV rows (including PASS/FAIL) | 145 | # 2. Build the CSV rows (including PASS/FAIL) |
| 146 | # -------------------------------------------------------------- | 146 | # -------------------------------------------------------------- |
| 147 | csv_rows: List[List[Any]] = [] | 147 | csv_rows: list[list[Any]] = [] |
| 148 | for rule_no, key, friendly, typ in POLICY_FIELDS: | 148 | for rule_no, key, friendly, typ in POLICY_FIELDS: |
| 149 | expected = expectations[key] | 149 | expected = expectations[key] |
| 150 | actual = policy.get(key, "(missing)") | 150 | actual = policy.get(key, "(missing)") |
applications/github/audit.py +1 −1
| @@ -34,7 +34,7 @@ import sys | |||
| 34 | from datetime import date | 34 | from datetime import date |
| 35 | 35 | ||
| 36 | import config | 36 | import config |
| 37 | from collectors import members, branch_protections, commits, audit_log | 37 | from collectors import audit_log, branch_protections, commits, members |
| 38 | from reporters import csv_reporter | 38 | from reporters import csv_reporter |
| 39 | 39 | ||
| 40 | 40 | ||
applications/github/collectors/audit_log.py +1 −1
| @@ -5,9 +5,9 @@ Requires GitHub Enterprise Cloud. Skips gracefully with a warning if not | |||
| 5 | available. | 5 | available. |
| 6 | """ | 6 | """ |
| 7 | 7 | ||
| 8 | from datetime import date, datetime, timezone, timedelta | ||
| 9 | import json | 8 | import json |
| 10 | import sys | 9 | import sys |
| 10 | from datetime import date, datetime, timedelta, timezone | ||
| 11 | 11 | ||
| 12 | import requests | 12 | import requests |
| 13 | 13 | ||
project_management/dash/app.py +1 −1
| @@ -3,9 +3,9 @@ Extensible dashboard for project status. | |||
| 3 | """ | 3 | """ |
| 4 | 4 | ||
| 5 | # Import packages | 5 | # Import packages |
| 6 | from dash import Dash, html, dcc | ||
| 7 | import pandas as pd | 6 | import pandas as pd |
| 8 | import plotly.express as px | 7 | import plotly.express as px |
| 8 | from dash import Dash, dcc, html | ||
| 9 | 9 | ||
| 10 | # Incorporate data | 10 | # Incorporate data |
| 11 | df = pd.read_excel("project_data.xlsx") | 11 | df = pd.read_excel("project_data.xlsx") |
ruff.toml added +14
| @@ -0,0 +1,14 @@ | |||
| 1 | # Ruff configuration for audit-tools. | ||
| 2 | # | ||
| 3 | # A few lint rules are disabled because they flag patterns this project uses | ||
| 4 | # deliberately: | ||
| 5 | # | ||
| 6 | # BLE001 - The audit collectors and their CLI wrappers intentionally catch | ||
| 7 | # broad exceptions so that one failing check never aborts a whole | ||
| 8 | # audit run. The error is reported and collection continues. | ||
| 9 | # DTZ011 - date.today() is used to build human-facing, date-stamped output | ||
| 10 | # folder names, where the local date is the intended value. | ||
| 11 | # S112 - try/except/continue is used to skip resources that are unavailable | ||
| 12 | # during collection (e.g. a repo without the requested branch). | ||
| 13 | [lint] | ||
| 14 | ignore = ["BLE001", "DTZ011", "S112"] | ||
sampling/audit_sample.py +1 −3
| @@ -1,15 +1,13 @@ | |||
| 1 | #!/usr/bin/env python3 | 1 | #!/usr/bin/env python3 |
| 2 | """Command-line entrypoint for the audit sampling tool.""" | 2 | """Command-line entrypoint for the audit sampling tool.""" |
| 3 | 3 | ||
| 4 | from pathlib import Path | ||
| 5 | import sys | 4 | import sys |
| 6 | 5 | from pathlib import Path | |
| 7 | 6 | ||
| 8 | if __package__ is None or __package__ == "": | 7 | if __package__ is None or __package__ == "": |
| 9 | sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) | 8 | sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) |
| 10 | 9 | ||
| 11 | from sampling.sampling_tool.cli import main | 10 | from sampling.sampling_tool.cli import main |
| 12 | 11 | ||
| 13 | |||
| 14 | if __name__ == "__main__": | 12 | if __name__ == "__main__": |
| 15 | raise SystemExit(main()) | 13 | raise SystemExit(main()) |
sampling/sampling_tool/cli.py +1 −1
| @@ -2,11 +2,11 @@ | |||
| 2 | 2 | ||
| 3 | from __future__ import annotations | 3 | from __future__ import annotations |
| 4 | 4 | ||
| 5 | import sys | ||
| 5 | from argparse import ArgumentParser, Namespace | 6 | from argparse import ArgumentParser, Namespace |
| 6 | from datetime import datetime, timezone | 7 | from datetime import datetime, timezone |
| 7 | from pathlib import Path | 8 | from pathlib import Path |
| 8 | from types import SimpleNamespace | 9 | from types import SimpleNamespace |
| 9 | import sys | ||
| 10 | 10 | ||
| 11 | import pandas as pd | 11 | import pandas as pd |
| 12 | 12 | ||
sampling/sampling_tool/io.py +1 −2
| @@ -2,12 +2,11 @@ | |||
| 2 | 2 | ||
| 3 | from __future__ import annotations | 3 | from __future__ import annotations |
| 4 | 4 | ||
| 5 | from pathlib import Path | ||
| 6 | import hashlib | 5 | import hashlib |
| 6 | from pathlib import Path | ||
| 7 | 7 | ||
| 8 | import pandas as pd | 8 | import pandas as pd |
| 9 | 9 | ||
| 10 | |||
| 11 | SUPPORTED_EXCEL_SUFFIXES = {".xlsx", ".xls", ".xlsm"} | 10 | SUPPORTED_EXCEL_SUFFIXES = {".xlsx", ".xls", ".xlsm"} |
| 12 | 11 | ||
| 13 | 12 | ||
sampling/sampling_tool/manifest.py +1 −1
| @@ -2,8 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | from __future__ import annotations | 3 | from __future__ import annotations |
| 4 | 4 | ||
| 5 | from pathlib import Path | ||
| 6 | import json | 5 | import json |
| 6 | from pathlib import Path | ||
| 7 | 7 | ||
| 8 | from . import __version__ | 8 | from . import __version__ |
| 9 | 9 | ||
sampling/sampling_tool/validation.py +1 −1
| @@ -69,7 +69,7 @@ def validate_and_prepare(population: pd.DataFrame, options) -> ValidationResult: | |||
| 69 | keep=False | 69 | keep=False |
| 70 | ) | 70 | ) |
| 71 | duplicate_rows = working.loc[nonblank_ids].loc[duplicate_mask].copy() | 71 | duplicate_rows = working.loc[nonblank_ids].loc[duplicate_mask].copy() |
| 72 | duplicate_id_count = int(len(duplicate_rows)) | 72 | duplicate_id_count = len(duplicate_rows) |
| 73 | if duplicate_id_count: | 73 | if duplicate_id_count: |
| 74 | if options.dedupe_id == "fail": | 74 | if options.dedupe_id == "fail": |
| 75 | raise AuditSamplingError( | 75 | raise AuditSamplingError( |
sampling/stratified_sample.py +2 −1
| @@ -1,7 +1,8 @@ | |||
| 1 | # Import packages | 1 | # Import packages |
| 2 | import pandas as pd | ||
| 3 | import math | 2 | import math |
| 4 | 3 | ||
| 4 | import pandas as pd | ||
| 5 | |||
| 5 | # Load data | 6 | # Load data |
| 6 | df = pd.read_csv("FILENAME_GOES_HERE.csv") | 7 | df = pd.read_csv("FILENAME_GOES_HERE.csv") |
| 7 | 8 | ||
tui/app.py +1 −1
| @@ -226,7 +226,7 @@ class RunScreen(Screen): | |||
| 226 | keys, | 226 | keys, |
| 227 | lambda ev: self.app.call_from_thread(self._handle_event, ev), | 227 | lambda ev: self.app.call_from_thread(self._handle_event, ev), |
| 228 | ) | 228 | ) |
| 229 | except Exception as e: # noqa: BLE001 - report unexpected failures in the UI | 229 | except Exception as e: |
| 230 | self.app.call_from_thread(self._log, f"[red]Run failed:[/] {e}") | 230 | self.app.call_from_thread(self._log, f"[red]Run failed:[/] {e}") |
| 231 | finally: | 231 | finally: |
| 232 | self.app.call_from_thread(self._finish) | 232 | self.app.call_from_thread(self._finish) |
tui/github_runner.py +2 −2
| @@ -147,7 +147,7 @@ def run_audit( | |||
| 147 | on_event(ProgressEvent("fetch", "Repo collaborators (shared cache)")) | 147 | on_event(ProgressEvent("fetch", "Repo collaborators (shared cache)")) |
| 148 | try: | 148 | try: |
| 149 | repo_collabs = members.fetch_repo_collaborators(org, cfg) | 149 | repo_collabs = members.fetch_repo_collaborators(org, cfg) |
| 150 | except Exception as e: # noqa: BLE001 - surface, keep going | 150 | except Exception as e: |
| 151 | on_event( | 151 | on_event( |
| 152 | ProgressEvent( | 152 | ProgressEvent( |
| 153 | "error", "Repo collaborators (shared cache)", message=str(e) | 153 | "error", "Repo collaborators (shared cache)", message=str(e) |
| @@ -165,7 +165,7 @@ def run_audit( | |||
| 165 | rows = c.fn(org, cfg, branch) | 165 | rows = c.fn(org, cfg, branch) |
| 166 | else: | 166 | else: |
| 167 | rows = c.fn(org, cfg) | 167 | rows = c.fn(org, cfg) |
| 168 | except Exception as e: # noqa: BLE001 - one bad check shouldn't kill the run | 168 | except Exception as e: |
| 169 | on_event(ProgressEvent("error", c.label, message=str(e))) | 169 | on_event(ProgressEvent("error", c.label, message=str(e))) |
| 170 | sections.append((c.label, 0)) | 170 | sections.append((c.label, 0)) |
| 171 | continue | 171 | continue |
tui/gitlab_runner.py +2 −2
| @@ -136,7 +136,7 @@ def run_audit( | |||
| 136 | on_event(ProgressEvent("fetch", "Projects (shared cache)")) | 136 | on_event(ProgressEvent("fetch", "Projects (shared cache)")) |
| 137 | try: | 137 | try: |
| 138 | project_cache = projects.fetch_projects(group, cfg) | 138 | project_cache = projects.fetch_projects(group, cfg) |
| 139 | except Exception as e: # noqa: BLE001 - surface, keep going | 139 | except Exception as e: |
| 140 | on_event(ProgressEvent("error", "Projects (shared cache)", message=str(e))) | 140 | on_event(ProgressEvent("error", "Projects (shared cache)", message=str(e))) |
| 141 | project_cache = [] | 141 | project_cache = [] |
| 142 | 142 | ||
| @@ -148,7 +148,7 @@ def run_audit( | |||
| 148 | rows = c.fn(group, cfg, project_cache or []) | 148 | rows = c.fn(group, cfg, project_cache or []) |
| 149 | else: | 149 | else: |
| 150 | rows = c.fn(group, cfg) | 150 | rows = c.fn(group, cfg) |
| 151 | except Exception as e: # noqa: BLE001 - one bad check shouldn't kill the run | 151 | except Exception as e: |
| 152 | on_event(ProgressEvent("error", c.label, message=str(e))) | 152 | on_event(ProgressEvent("error", c.label, message=str(e))) |
| 153 | sections.append((c.label, 0)) | 153 | sections.append((c.label, 0)) |
| 154 | continue | 154 | continue |