Skip to content

Security and robustness hardening - #30

Merged
lightos merged 8 commits into
mainfrom
hardening-review
Jul 29, 2026
Merged

Security and robustness hardening#30
lightos merged 8 commits into
mainfrom
hardening-review

Conversation

@lightos

@lightos lightos commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • harden URL, header, request-body, file-output, checkpoint, and self-update handling
  • improve traversal payload construction, response comparison, case expansion, and structured output
  • expand CLI/config validation and document the supported scan modes
  • add comprehensive unit coverage, a minimum-dependency job, pinned CI actions, and grouped dependency updates
  • link the reproducible Panoptic LFI Testbed from the README

Verification

  • 270 unit and integration tests pass
  • Python 3.10 minimum runtime dependency versions pass with pip check
  • Ruff lint and format checks pass
  • strict mypy checks pass
  • wheel and source distribution build successfully and pass Twine validation
  • pip-audit reports no known vulnerabilities
  • all 28 Panoptic LFI Testbed behavioral cases pass, including artifact permissions, CSV output, and checkpoint resume

Summary by CodeRabbit

  • New Features
    • Added --version, richer --list output (JSON/CSV/text), and improved proxy support (SOCKS5/SOCKS5H).
    • Enhanced resume/checkpointing behavior and output list serialization with safer file writing.
  • Bug Fixes
    • Strengthened validation for URLs/headers/config/flags and improved FUZZ substitution (including JSON handling and encoding).
    • Improved scan retry behavior on connection failures, hardened redaction, and tightened checkpoint fingerprint validation.
  • Documentation
    • Expanded README with configuration precedence, proxy semantics, checkpointing, and testing details.
  • Chores
    • Updated CI/pre-commit tooling, packaging constraints, and enforced CR-at-EOL line endings for specific CSVs.

lightos added 5 commits July 28, 2026 20:37
Core hardening:
- Symlink/TOCTOU-safe file writes (open_secure_write), owner-only perms
- Versioned, fingerprinted checkpoints; fail-safe against new config fields
- Trusted-remote verification for self-update; explicit refs/heads/main pull
- Rich-markup escaping of attacker-influenced output; CSV formula-injection guard
- CRLF/NUL header validation; structured FUZZ/param substitution (no regex)
- TOML config type validation and unknown-key warnings

Review fixes:
- Fix pre-commit hooks: drop unsupported `run --staged`; correct pip-audit --desc
- Dedup composite-OS CSV rows (no duplicate requests; 958 default cases)
- Partial transient request failures no longer fail an otherwise good scan
- Text output files no longer hard-wrap long paths
- Non-interactive EOF no longer auto-approves OS narrowing
- CLI headers extend config headers with CLI precedence
- Consistent header deprecation warnings and FUZZ detection

Detection change (intentional): full response comparison replaces
Content-Length-only shortcut; quick_ratio() upper-bound preserves perf.
Pending end-to-end validation against a live LFI target.

CI: SHA-pinned GitHub Actions, least-privilege permissions, Dependabot,
minimum-version job. 268 tests pass.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: eaad7a6a-c597-45ec-a3b2-f8f00385175d

📥 Commits

Reviewing files that changed from the base of the PR and between 30a2c6f and 8e5dd95.

📒 Files selected for processing (1)
  • .githooks/pre-commit

Walkthrough

Panoptic adds stricter configuration and validation, OS-aware case expansion, secure output and checkpoint handling, revised scanning and retry behavior, hardened update logic, expanded output redaction, and CI/pre-commit automation with corresponding tests and documentation.

Changes

Panoptic hardening and validation

Layer / File(s) Summary
Configuration and input contracts
panoptic/config.py, panoptic/utils.py, panoptic/cases.py, panoptic/models.py, tests/test_config.py, tests/test_utils.py, tests/test_cases.py
Configuration types, URL/header validation, OS matching, case expansion, and secure file writes are strengthened and tested.
CLI and scan orchestration
panoptic/cli.py, panoptic/core.py, panoptic/network.py, panoptic/__main__.py, tests/test_cli.py, tests/test_core.py, tests/test_network.py
CLI/config precedence, payload substitution, retries, checkpoints, worker supervision, output status, and process exit codes are updated and tested.
Output, heuristics, parsing, and updates
panoptic/output.py, panoptic/heuristic.py, panoptic/parsers.py, panoptic/update.py, tests/test_output.py, tests/test_update.py, tests/test_parsers.py, tests/test_heuristic.py
Redaction, Rich escaping, response comparison, binlog parsing, and secure git updates are revised with coverage.
Repository automation and documentation
.github/*, .githooks/pre-commit, .pre-commit-config.yaml, pyproject.toml, README.md, .gitignore, .gitattributes
CI, minimum-version checks, hooks, dependency metadata, ignore rules, line-ending rules, and runtime documentation are updated.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Config
  participant Scanner
  participant NetworkClient
  participant Output
  CLI->>Config: merge arguments and config
  Config->>Scanner: create ScanConfig
  Scanner->>NetworkClient: fetch scan responses
  NetworkClient-->>Scanner: responses or failures
  Scanner->>Output: write findings and status
  Output-->>CLI: return exit code
Loading

Poem

I’m a rabbit with a checklist bright,
Hopping through hooks that guard the night.
Safe little files and checkpoints align,
Fuzzy paths resolve in a neat design.
CI carrots grow, tests thump with cheer—
Panoptic’s burrow is polished here!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main theme of the change set: broad security and robustness hardening across CLI, config, networking, output, and update paths.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hardening-review

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.githooks/pre-commit:
- Around line 99-103: Update the npx fallback in the pre-commit hook to invoke
the CLI package via markdownlint-cli instead of the library package
markdownlint, while preserving the existing staged-file arguments and
CHECKS_RAN/EXIT_CODE handling.

In @.github/workflows/ci.yml:
- Line 20: Disable persisted checkout credentials by adding persist-credentials:
false to each actions/checkout step in .github/workflows/ci.yml at lines 20, 33,
and 50; no other workflow behavior needs to change.

In `@panoptic/config.py`:
- Around line 131-136: Update the legacy header migration in the configuration
merge logic to reject unsupported types instead of silently dropping them. Keep
string and list values mapped to merged["headers"], but raise the same
established configuration/type error used for other malformed TOML values when
legacy_headers is neither a str nor a list.
- Around line 177-182: Update the output_format handling in the configuration
merge/validation flow so every present value, including non-strings, is
validated and converted to OutputFormat rather than bypassing validation. Ensure
invalid types and values raise TypeError or ValueError for the existing run()
error handler, while preserving valid enum instances and string conversion
behavior.

In `@tests/test_core.py`:
- Around line 624-625: Bound the wait loop in the test around save_started so it
cannot spin indefinitely when _flush_checkpoint exits without starting a save.
Add a deadline or apply asyncio.wait_for to the wait operation, and ensure
timeout causes the test to fail rather than hang.
- Line 246: Guard the 0o600 permission assertion in test_no_filename_collision
with the same os.name != "posix" skipif used by
test_discovered_file_write_refuses_symlink and TestScanOutputFilePermissions,
while leaving the collision behavior assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0a0e8c85-b947-4a60-b553-da53a61566f3

📥 Commits

Reviewing files that changed from the base of the PR and between 2900f53 and c3c9b19.

⛔ Files ignored due to path filters (1)
  • panoptic/data/cases.csv is excluded by !**/*.csv
📒 Files selected for processing (33)
  • .gitattributes
  • .githooks/pre-commit
  • .github/constraints-min.txt
  • .github/dependabot.yml
  • .github/workflows/ci.yml
  • .gitignore
  • .pre-commit-config.yaml
  • README.md
  • panoptic/__main__.py
  • panoptic/cases.py
  • panoptic/cli.py
  • panoptic/config.py
  • panoptic/core.py
  • panoptic/heuristic.py
  • panoptic/models.py
  • panoptic/network.py
  • panoptic/output.py
  • panoptic/parsers.py
  • panoptic/update.py
  • panoptic/utils.py
  • pyproject.toml
  • tests/test_cases.py
  • tests/test_cli.py
  • tests/test_config.py
  • tests/test_core.py
  • tests/test_heuristic.py
  • tests/test_integration.py
  • tests/test_models.py
  • tests/test_network.py
  • tests/test_output.py
  • tests/test_parsers.py
  • tests/test_update.py
  • tests/test_utils.py
👮 Files not reviewed due to content moderation or server errors (14)
  • panoptic/core.py
  • tests/test_cli.py
  • panoptic/heuristic.py
  • panoptic/parsers.py
  • panoptic/update.py
  • tests/test_heuristic.py
  • tests/test_parsers.py
  • tests/test_models.py
  • tests/test_update.py
  • panoptic/network.py
  • tests/test_integration.py
  • tests/test_network.py
  • panoptic/output.py
  • tests/test_output.py

Comment thread .githooks/pre-commit Outdated
Comment thread .github/workflows/ci.yml
Comment thread panoptic/config.py
Comment thread panoptic/config.py
Comment thread tests/test_core.py Outdated
Comment thread tests/test_core.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
panoptic/config.py (1)

146-164: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Do not skip validation for falsey configuration values.

The truthiness checks silently discard malformed values such as proxy.url = 0, headers.cookie = false, or headers.values = "", so _validate_merged_types() never rejects them. Use is not None for these optional fields and add regression cases to tests/test_config.py.

🛠️ Proposed fix
-    if proxy_url:
+    if proxy_url is not None:
         merged["proxy"] = proxy_url
...
-    if header_ua:
+    if header_ua is not None:
         merged["user_agent"] = header_ua
...
-    if header_cookie:
+    if header_cookie is not None:
         merged["cookie"] = header_cookie
...
-    if header_values:
+    if header_values is not None:
         if not isinstance(header_values, list) or not all(
             isinstance(header, str) for header in header_values
         ):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@panoptic/config.py` around lines 146 - 164, Update the optional-field checks
in the configuration merge logic around proxy_url, header_ua, header_cookie, and
header_values to use explicit None checks, ensuring falsey values are copied
into merged and reach _validate_merged_types() for rejection. Add regression
cases in tests/test_config.py covering malformed falsey values such as
proxy.url=0, headers.cookie=false, and headers.values="".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.githooks/pre-commit:
- Line 100: Update the markdownlint invocation in the pre-commit hook to prevent
npx from auto-installing packages: use a declared, pinned/preinstalled
markdownlint-cli binary or invoke npx with --no-install. Ensure the hook fails
clearly when markdownlint-cli is unavailable.

---

Outside diff comments:
In `@panoptic/config.py`:
- Around line 146-164: Update the optional-field checks in the configuration
merge logic around proxy_url, header_ua, header_cookie, and header_values to use
explicit None checks, ensuring falsey values are copied into merged and reach
_validate_merged_types() for rejection. Add regression cases in
tests/test_config.py covering malformed falsey values such as proxy.url=0,
headers.cookie=false, and headers.values="".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 439932e0-a01c-4a86-8f9e-a523e7e6cf72

📥 Commits

Reviewing files that changed from the base of the PR and between c3c9b19 and eef07b7.

📒 Files selected for processing (5)
  • .githooks/pre-commit
  • .github/workflows/ci.yml
  • panoptic/config.py
  • tests/test_config.py
  • tests/test_core.py

Comment thread .githooks/pre-commit Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.githooks/pre-commit (1)

49-84: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Align the fallback with .pre-commit-config.yaml.
The fallback uses different checks from the pinned hooks (ruff check/ruff format --check/pyright on PATH vs. ruff --fix/ruff-format/mypy --strict). If pre-commit isn’t installed, reuse the same toolchain/options or fail fast so commits aren’t validated differently across environments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.githooks/pre-commit around lines 49 - 84, The Python fallback checks in the
pre-commit hook must match the pinned hooks in .pre-commit-config.yaml. Update
the Python checks block to reuse the configured ruff --fix, ruff-format, and
mypy --strict toolchain/options, or fail fast when those dependencies are
unavailable; remove the current ruff check, ruff format --check, and pyright
path so validation is consistent across environments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.githooks/pre-commit:
- Around line 49-84: The Python fallback checks in the pre-commit hook must
match the pinned hooks in .pre-commit-config.yaml. Update the Python checks
block to reuse the configured ruff --fix, ruff-format, and mypy --strict
toolchain/options, or fail fast when those dependencies are unavailable; remove
the current ruff check, ruff format --check, and pyright path so validation is
consistent across environments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 44e3026c-7dae-40ad-8ff3-69486e2c1e6e

📥 Commits

Reviewing files that changed from the base of the PR and between eef07b7 and 30a2c6f.

📒 Files selected for processing (1)
  • .githooks/pre-commit

@lightos
lightos merged commit c7dc6d5 into main Jul 29, 2026
10 checks passed
@lightos
lightos deleted the hardening-review branch July 29, 2026 05:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant