feat: add secret-safe reviewer adapter#88
Conversation
Co-Authored-By: Codex <noreply@openai.com>
🤖 Codex PR Review🚫 Merge blocked: 3 serious issue(s) found in high-risk files ⚖️ Codex Review Arbitration🚫 block: 🚫 Blocking IssuesThese issues must be fixed before this PR can be merged: 1. 🟠 [HIGH] Security in
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c223d8358b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
|
Remediation batch complete at
Validation: focused 11 passed; review tests 54 passed; full 631 passed (1 skipped); ruff, compileall, actionlint, and diff-check passed. This was the single allowed remediation batch. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6654f6d274
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def _pointer(path: str, key: Any) -> str: | ||
| value = str(key).replace("~", "~0").replace("/", "~1") | ||
| return f"{path.rstrip('/')}/{value}" if path != "/" else f"/{value}" |
There was a problem hiding this comment.
Redact attacker-controlled keys from error paths
The existing top-level unknown-field redaction does not cover nested keys: _pointer still preserves raw key text, and callers pass attacker-controlled JSON keys from _scan and _map_node. For example, a reviewer_output.v2 payload with an extra structured_tokens.scope key named ghp_<token> whose child is an invalid surrogate raises invalid_utf8_or_control_character at /findings/0/structured_tokens/scope/ghp_..., leaking the credential before schema validation can replace it with <unknown>.
Useful? React with 👍 / 👎.
| return value | ||
| def _display_text(value: Any, path: str, chars: int, byte_limit: int) -> str: | ||
| text = _bounded(value, path, chars, byte_limit, "invalid_display_field") | ||
| for pattern in PROSE_SHAPES: |
There was a problem hiding this comment.
Reuse existing credential scrub patterns for display
The display redaction loop only applies PROSE_SHAPES, which excludes credential formats the existing review pipeline already treats as sensitive, such as glpat-... tokens and password-bearing DSNs covered by tests/test_run_codex_pr_review.py:253. When reviewer summary or description text contains one of those values, _display_text returns it unchanged in display, so this secret-safe adapter can re-expose credentials that the current finding-history sanitizer suppresses.
Useful? React with 👍 / 👎.
| _fail("duplicate_json_key") | ||
| except (TypeError, ValueError, json.JSONDecodeError): | ||
| _fail("invalid_json") | ||
| _scan(value, 0, "/") |
There was a problem hiding this comment.
Bound parsed findings before full traversal
When callers pass an already-parsed reviewer object, which this public function accepts and the tests exercise, this unconditional recursive scan runs before the MAX_FINDINGS check and before the compact-size check can fail the payload. A malicious parsed payload with a huge findings list therefore forces traversal and serialization of every child instead of failing at 32 findings, turning the adapter's size limits into a CPU/memory DoS only for dict/list inputs.
Useful? React with 👍 / 👎.
Summary
structured_tokens.v2Validation
python3 -m unittest tests.test_secret_safe_reviewer_adapter_r2 tests.test_canonical_typed_identity_r1d(11 passed)python3 -m unittest tests.test_run_codex_pr_review(54 passed)python3 -m unittest discover -s tests(631 passed, 1 skipped)git diff --checkpassedScope