feat: import Ocelot review setup tooling & scanner documentation - #89
Conversation
Import remaining Ocelot-only files not yet present in SuperClaude: - bedrock_helper.py: shared Anthropic/Bedrock dual-provider auth utility - setup-claude-review.sh: interactive Claude Review phase setup wizard - Scanner docs: quickstart, status, and implementation summary - Review docs: setup guide, README, and deployment status All Ocelot repo references (Tony363/Ocelot) cleaned from imported docs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Reviewer's GuideAdds shared Anthropic/Bedrock helper for AI-powered scanner scripts plus comprehensive documentation and setup tooling for the autonomous scanner and three-phase Claude Review system, without modifying existing workflows. Sequence diagram for create_message Anthropic/Bedrock selectionsequenceDiagram
participant ScannerScript
participant bedrock_helper
participant Env as Environment
participant AnthropicAPI
participant BedrockAPI
ScannerScript->>bedrock_helper: create_message(model, max_tokens, temperature, messages, thinking)
bedrock_helper->>Env: read ANTHROPIC_API_KEY
alt ANTHROPIC_API_KEY set
bedrock_helper->>AnthropicAPI: messages.create(model, max_tokens, messages, temperature|thinking)
AnthropicAPI-->>bedrock_helper: Message
bedrock_helper-->>ScannerScript: MessageResponse(content, usage)
else ANTHROPIC_API_KEY not set
bedrock_helper->>Env: read AWS_BEARER_TOKEN_BEDROCK
alt AWS_BEARER_TOKEN_BEDROCK set
bedrock_helper->>Env: read AWS_REGION
bedrock_helper->>BedrockAPI: POST /model/{encoded_model}/invoke
BedrockAPI-->>bedrock_helper: JSON(content, usage)
bedrock_helper-->>ScannerScript: MessageResponse(content, usage)
else no credentials
bedrock_helper-->>ScannerScript: exit with error
end
end
Class diagram for bedrock_helper dual Anthropic/Bedrock clientclassDiagram
class bedrock_helper {
}
class MessageResponse {
+list~ContentBlock~ content
+Usage usage
}
class Usage {
+int input_tokens
+int output_tokens
}
class ContentBlock {
+str type
+str text
}
class Environment {
+str ANTHROPIC_API_KEY
+str AWS_BEARER_TOKEN_BEDROCK
+str AWS_REGION
}
class ScannerScript {
+run_scan()
+call_create_message(model, max_tokens, temperature, messages, thinking)
}
bedrock_helper ..> MessageResponse : returns
MessageResponse *-- Usage
MessageResponse *-- ContentBlock
ScannerScript ..> bedrock_helper : uses_create_message
Environment ..> bedrock_helper : env_vars
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds comprehensive documentation and setup scripts for an autonomous overnight AI-powered code scanner and a multi-phase Claude review system, and introduces Changes
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub Actions Workflow
participant Scripts as Repo Scripts
participant Anthropic as Anthropic (Claude)
participant Bedrock as AWS Bedrock
participant Repo as Git Repository / PRs
GH->>Scripts: start nightly scanner jobs (format, security, AST analyses)
Scripts->>Scripts: gather scannable files, apply protected-file filters
Scripts->>Anthropic: create_message() (uses ANTHROPIC_API_KEY if set)
alt ANTHROPIC_API_KEY not set and AWS_BEARER_TOKEN_BEDROCK set
Scripts->>Bedrock: create_message() (maps model via BEDROCK_MODEL_MAP, uses AWS_REGION)
Bedrock-->>Scripts: JSON with content[] and usage
else Anthropic used
Anthropic-->>Scripts: text + usage
end
Scripts->>GH: findings + token/cost usage
GH->>GH: evaluate gates (finding thresholds, budget)
alt gates pass
GH->>Repo: open draft PR(s) per issue type (with labels/reviewers)
else gates fail
GH-->>Repo: abort, upload artifacts, surface alerts
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PAL MCP Consensus Not AvailableSecurity-sensitive files were detected, but PAL MCP multi-model consensus is not configured. High-stakes files changed: To enable PAL MCP consensus:
Claude Code Review results are still available above. |
| def create_message( | ||
| *, | ||
| model: str, | ||
| max_tokens: int, | ||
| temperature: float, | ||
| messages: list[dict[str, Any]], | ||
| thinking: dict[str, Any] | None = None, | ||
| ) -> MessageResponse: |
Check notice
Code scanning / CodeQL
Explicit returns mixed with implicit (fall through) returns Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 months ago
In general, to fix mixed explicit/implicit returns, ensure every control-flow path in a function either explicitly returns a value compatible with the function’s return type or explicitly signals non-returning behavior (e.g., by raising an exception), and avoid simply falling off the end of the function.
For create_message, the two credentialed branches already explicitly return MessageResponse. The final branch should be made explicitly non-returning to avoid an implicit None. The cleanest way without changing existing functionality is: instead of printing the error and calling sys.exit(1) (which is just a convenience wrapper that raises SystemExit), directly raise SystemExit after printing. This makes it syntactically clear that this code path never returns a MessageResponse, and tools no longer see it as an implicit None return. No new imports or method definitions are needed; SystemExit is a built-in. The change is confined to lines 75–79 in .github/scripts/bedrock_helper.py.
| @@ -76,7 +76,7 @@ | ||
| "::error::No API credentials. Set ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK + AWS_REGION", | ||
| file=sys.stderr, | ||
| ) | ||
| sys.exit(1) | ||
| raise SystemExit(1) | ||
|
|
||
|
|
||
| def _create_via_anthropic(*, model, max_tokens, temperature, messages, thinking) -> MessageResponse: |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
bedrock_helper.create_message, the helper exits the entire process (sys.exit(1)) when credentials are missing; since this is a library-style helper used by other scripts, consider raising a specific exception instead so callers can handle credential errors in a context-appropriate way (including non-GitHub-Action environments). - The Bedrock integration in
bedrock_helper.pycurrently relies on a small hard-codedBEDROCK_MODEL_MAPand a defaultus-region prefix; it would be more robust to either accept an explicit Bedrock model ID/region via parameters or environment variables (with validation) so that new models/regions can be used without changing the code. - In
setup-claude-review.sh, the phase selection flow forPHASE=allskips copying any workflow toclaude-review.yml, which may leave users without an active default workflow; consider either prompting the user to choose which phase should be aliased toclaude-review.ymlor documenting that they must manually copy one after running the script.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `bedrock_helper.create_message`, the helper exits the entire process (`sys.exit(1)`) when credentials are missing; since this is a library-style helper used by other scripts, consider raising a specific exception instead so callers can handle credential errors in a context-appropriate way (including non-GitHub-Action environments).
- The Bedrock integration in `bedrock_helper.py` currently relies on a small hard-coded `BEDROCK_MODEL_MAP` and a default `us-` region prefix; it would be more robust to either accept an explicit Bedrock model ID/region via parameters or environment variables (with validation) so that new models/regions can be used without changing the code.
- In `setup-claude-review.sh`, the phase selection flow for `PHASE=all` skips copying any workflow to `claude-review.yml`, which may leave users without an active default workflow; consider either prompting the user to choose which phase should be aliased to `claude-review.yml` or documenting that they must manually copy one after running the script.
## Individual Comments
### Comment 1
<location path=".github/workflows/setup-claude-review.sh" line_range="74-76" />
<code_context>
+select_phase() {
+ echo ""
+ prompt "Select which phase to install:"
+ echo " 1) Phase 1 - Comment Only (Safest, $1.50/PR, 2-5 min)"
+ echo " 2) Phase 2 - Selective Consensus ($1.50-$5/PR, 5-13 min)"
+ echo " 3) Phase 3 - Draft PR Creation ($3-$8/PR, 8-20 min)"
+ echo " 4) All phases (for evaluation)"
+ echo ""
</code_context>
<issue_to_address>
**issue (bug_risk):** Dollar amounts in echo strings will be subject to parameter expansion and render incorrectly.
Because these are double-quoted, `$1.50` and `$3-$8` are treated as parameter expansions (`$1`, `$3`, `$8`) instead of literal prices, so the output will be wrong. Escape the dollar signs (e.g. `\$1.50`, `\$3-\$8`) or switch to single quotes for these lines.
</issue_to_address>
### Comment 2
<location path=".github/workflows/setup-claude-review.sh" line_range="122-131" />
<code_context>
+ read -p "Paste your Claude OAuth token: " claude_token
</code_context>
<issue_to_address>
**🚨 issue (security):** Secrets entered via `read -p` are echoed to the terminal, which is unsafe for credentials.
For all three credential prompts (`CLAUDE_CODE_OAUTH_TOKEN`, `PAL_MCP_API_KEY`, `PAT_TOKEN`), use `read -s -p` so the values aren’t displayed or captured in logs, then run a plain `echo` afterward to restore the prompt formatting.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| echo " 1) Phase 1 - Comment Only (Safest, $1.50/PR, 2-5 min)" | ||
| echo " 2) Phase 2 - Selective Consensus ($1.50-$5/PR, 5-13 min)" | ||
| echo " 3) Phase 3 - Draft PR Creation ($3-$8/PR, 8-20 min)" |
There was a problem hiding this comment.
issue (bug_risk): Dollar amounts in echo strings will be subject to parameter expansion and render incorrectly.
Because these are double-quoted, $1.50 and $3-$8 are treated as parameter expansions ($1, $3, $8) instead of literal prices, so the output will be wrong. Escape the dollar signs (e.g. \$1.50, \$3-\$8) or switch to single quotes for these lines.
| read -p "Paste your Claude OAuth token: " claude_token | ||
|
|
||
| if [ -z "$claude_token" ]; then | ||
| error "Token cannot be empty" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "$claude_token" | gh secret set CLAUDE_CODE_OAUTH_TOKEN | ||
| success "CLAUDE_CODE_OAUTH_TOKEN configured" | ||
| else |
There was a problem hiding this comment.
🚨 issue (security): Secrets entered via read -p are echoed to the terminal, which is unsafe for credentials.
For all three credential prompts (CLAUDE_CODE_OAUTH_TOKEN, PAL_MCP_API_KEY, PAT_TOKEN), use read -s -p so the values aren’t displayed or captured in logs, then run a plain echo afterward to restore the prompt formatting.
PAL MCP Consensus Code Review (Manual Analysis)OverviewThis PR imports Ocelot review setup tooling & scanner documentation, adding:
The PR focuses on infrastructure for AI-powered code review and scanning workflows, introducing dual authentication support (Anthropic API + AWS Bedrock) and automated setup tooling. Critical Issues🔴 CRITICAL-1: Sensitive Data Exposure in Bash ScriptFile: Issue: User secrets (API keys, OAuth tokens, PAT tokens) are read via Risk: Credential leakage if:
Recommendation: # Use read -s (silent mode) for all sensitive inputs
read -sp "Paste your Claude OAuth token: " claude_token
echo # Add newline after silent inputImpact: High - Could expose API keys worth hundreds of dollars 🔴 CRITICAL-2: Unvalidated URL Construction in Bedrock HelperFile: Issue: AWS region is used directly in URL construction without validation: url = f"https://bedrock-runtime.{region}.amazonaws.com/model/{encoded_model}/invoke"Risk: If
Recommendation: ALLOWED_REGIONS = {
'us-east-1', 'us-west-2', 'eu-west-1', 'ap-northeast-1',
'eu-central-1', 'ap-southeast-1', 'ap-southeast-2'
}
region = os.environ.get("AWS_REGION", "us-east-1")
if region not in ALLOWED_REGIONS:
raise ValueError(f"Invalid AWS region: {region}")Impact: Medium-High - Requires compromised environment variable, but consequences are severe High Priority🟠 HIGH-1: Missing Timeout and Error Handling in HTTP RequestsFile: Issue:
Code: with httpx.Client(timeout=300) as http_client:
response = http_client.post(url, headers=headers, json=body)
if response.status_code >= 400:
raise RuntimeError(
f"Bedrock API error: {response.status_code} - {response.text}"
)Recommendation: import httpx
from typing import Final
TIMEOUT_CONFIG: Final = httpx.Timeout(
connect=10.0,
read=300.0,
write=30.0,
pool=10.0
)
with httpx.Client(timeout=TIMEOUT_CONFIG) as http_client:
try:
response = http_client.post(url, headers=headers, json=body)
response.raise_for_status()
data = response.json()
except httpx.HTTPStatusError as e:
raise RuntimeError(
f"Bedrock API error: {e.response.status_code} - {e.response.text}"
) from e
except httpx.TimeoutException as e:
raise RuntimeError(f"Bedrock API timeout after {TIMEOUT_CONFIG.read}s") from e
except httpx.RequestError as e:
raise RuntimeError(f"Bedrock API request failed: {e}") from eImpact: Medium - Could cause silent failures or poor UX in production 🟠 HIGH-2: Shell Injection Risk in Bash ScriptFile: Issue: Unsanitized command execution with user-controlled input: REPO_FULL=$(gh repo view --json nameWithOwner -q .nameWithOwner)
TEST_BRANCH="test/ai-review-setup-$(date +%s)"While Recommendation:
Impact: Low-Medium - Limited attack surface currently, but pattern could propagate 🟠 HIGH-3: Missing Type Validation in Python HelperFile: Issue:
Recommendation: from typing import TypedDict, Literal
class Message(TypedDict):
role: Literal["user", "assistant", "system"]
content: str
def create_message(
*,
model: str,
max_tokens: int,
temperature: float,
messages: list[Message], # Typed instead of list[dict[str, Any]]
thinking: dict[str, Any] | None = None,
) -> MessageResponse:
# Add runtime validation
for msg in messages:
if "role" not in msg or "content" not in msg:
raise ValueError(f"Invalid message format: {msg}")Impact: Medium - Could lead to debugging nightmares in production Medium Priority🟡 MEDIUM-1: Inconsistent Error Handling Between API ProvidersFile: Issue: Anthropic API path uses Recommendation: Create custom exception hierarchy: class APIError(Exception):
"""Base exception for API errors"""
pass
class AnthropicAPIError(APIError):
"""Anthropic API specific errors"""
pass
class BedrockAPIError(APIError):
"""Bedrock API specific errors"""
passImpact: Low-Medium - Makes debugging harder, but doesn't affect functionality 🟡 MEDIUM-2: Hard-coded Model Mapping Could Become StaleFile: Issue: Model ID mapping is hard-coded: BEDROCK_MODEL_MAP: dict[str, str] = {
"claude-opus-4-20250514": "us.anthropic.claude-opus-4-20250514-v1:0",
"claude-haiku-4-5-20251001": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
}Risk: New models require code changes. No fallback for unknown models. Recommendation: def get_bedrock_model_id(anthropic_model: str) -> str:
"""Convert Anthropic model ID to Bedrock model ID."""
bedrock_model = BEDROCK_MODEL_MAP.get(anthropic_model)
if bedrock_model:
return bedrock_model
# Fallback: assume it's already a Bedrock ID or auto-convert
if anthropic_model.startswith("us.anthropic."):
return anthropic_model
# Auto-convert pattern: claude-opus-4-* → us.anthropic.claude-opus-4-*-v1:0
return f"us.anthropic.{anthropic_model}-v1:0"Impact: Low - Requires manual updates but predictable failure mode 🟡 MEDIUM-3: Missing File Existence Checks in Bash ScriptFile: Issue: Recommendation: case $PHASE in
phase1)
if [ ! -f .github/workflows/claude-review-phase1.yml ]; then
error "Phase 1 workflow file not found"
exit 1
fi
cp .github/workflows/claude-review-phase1.yml .github/workflows/claude-review.yml
success "Installed Phase 1 workflow"
;;Impact: Low - Only affects setup UX, but frustrating when it fails Positive Observations✅ Excellent Documentation: 3000+ lines of comprehensive setup guides, quickstarts, and status tracking Review Summary
Testing GapsMissing test coverage for:
Recommendation: Add test suite before merging: tests/
├── test_bedrock_helper.py
│ ├── test_create_message_with_anthropic_api()
│ ├── test_create_message_with_bedrock()
│ ├── test_create_message_no_credentials()
│ ├── test_bedrock_api_timeout()
│ ├── test_bedrock_api_error_handling()
│ ├── test_model_id_mapping()
│ └── test_invalid_region_validation()
└── test_setup_script.sh
├── test_prerequisites_check()
├── test_secret_configuration()
└── test_workflow_installation()Recommended Actions Before MergeMust Fix (Blocking):
Should Fix (Non-blocking but important): Nice to Have: Final VerdictRecommendation: This PR provides excellent infrastructure for AI-powered code review workflows with comprehensive documentation. The code quality is generally high, but has 2 critical security issues that must be addressed before production deployment:
The lack of test coverage is concerning for production infrastructure, but the code is well-structured enough that tests can be added post-merge if timeline is critical. Estimated Risk: Medium-High This review was generated by comprehensive manual analysis. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
.github/workflows/CLAUDE_REVIEW_SETUP.md (1)
72-87: Add language specifiers to secret configuration code blocks.Lines 72-87 have code blocks for secrets configuration without language specifiers. Using
textorbashwould improve rendering.📝 Suggested fix
#### Phase 1 (Required): -``` +```text CLAUDE_CODE_OAUTH_TOKEN=<your-oauth-token-from-claude-console>Phase 2 (Additional):
-
+text
PAL_MCP_API_KEY=</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.github/workflows/CLAUDE_REVIEW_SETUP.md around lines 72 - 87, The fenced
secret/config code blocks for CLAUDE_CODE_OAUTH_TOKEN,
PAL_MCP_API_KEY/PAL_MCP_ENDPOINT, and PAT_TOKEN should include a language
specifier (e.g.,textorbash) to improve rendering; update the three code
fences surrounding the lines containing the environment variables
CLAUDE_CODE_OAUTH_TOKEN, PAL_MCP_API_KEY and PAL_MCP_ENDPOINT, and PAT_TOKEN to
usetext (orbash) instead of plain ``` so the blocks render correctly.</details> </blockquote></details> <details> <summary>.github/AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md (1)</summary><blockquote> `201-210`: **Add language specifiers to fenced code blocks for better syntax highlighting.** Lines 201-210 and 294-312 have code blocks without language specifiers. Adding `text` or appropriate language identifiers improves documentation rendering. <details> <summary>📝 Suggested fix</summary> For line 201: ```diff -``` +```text .github/workflows/* # Prevent workflow self-modification ``` For line 294: ```diff -``` +```text security-check (Job 1) ``` </details> Also applies to: 294-312 <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.github/AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md around lines 201 - 210,
The fenced code blocks in AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md that
contain plain lists such as the block showing ".github/workflows/* # Prevent
workflow self-modification" and the block containing "security-check (Job 1)"
are missing language specifiers; update those backticked fences to include an
explicit short language (e.g., ```text) so rendering uses proper syntax
highlighting for those blocks; locate the two code fences around the list of
paths and the "security-check (Job 1)" job description and prefix their opening
triple-backticks with the chosen language identifier.</details> </blockquote></details> <details> <summary>.github/workflows/README_CLAUDE_REVIEW.md (1)</summary><blockquote> `71-80`: **Add language specifier to file structure code block.** <details> <summary>📝 Suggested fix</summary> ```diff -``` +```text .github/workflows/ ├── claude-review-phase1.yml # Phase 1: Comment-only ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In @.github/workflows/README_CLAUDE_REVIEW.md around lines 71 - 80, The code
block showing the repository tree (the block starting with ".github/workflows/")
is missing a language specifier; change the opening fence fromtotext so
the block becomes "text" and keep the closing fence as "" to ensure proper
syntax highlighting in README_CLAUDE_REVIEW.md.</details> </blockquote></details> <details> <summary>.github/workflows/setup-claude-review.sh (1)</summary><blockquote> `122-129`: **Consider using `read -s` for sensitive token input.** Lines 122, 142, and 171 read sensitive tokens (OAuth tokens, API keys, PAT) without the `-s` flag, meaning the input is echoed to the terminal and may be visible in shell history or over-the-shoulder. <details> <summary>🛡️ Suggested improvement</summary> ```diff - read -p "Paste your Claude OAuth token: " claude_token + read -sp "Paste your Claude OAuth token: " claude_token + echo # Add newline after hidden input ``` Apply similar changes to lines 142 and 171. </details> Also applies to: 142-143, 171-174 <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against the current code and only fix it if needed. In @.github/workflows/setup-claude-review.sh around lines 122 - 129, Change the interactive token prompts to hide input: use a silent read (read -s) when reading the claude_token so the token is not echoed, then print a newline after the read so the prompt/terminal formatting remains correct; keep the existing empty-check (if [ -z "$claude_token" ]) and the subsequent secret upload (echo "$claude_token" | gh secret set CLAUDE_CODE_OAUTH_TOKEN) unchanged. Apply the same pattern to the other sensitive reads referenced in the comment (the other token variables read at lines 142 and 171) so all OAuth/API/PAT inputs are read with read -s, validated for emptiness, and then passed to gh secret set as before. ``` </details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/AUTONOMOUS_SCANNER_STATUS.md:
- Around line 171-176: The vulnerability description is wrong: the code in
run_command uses subprocess.call(user_input, shell=True) which is a
command-injection risk (Bandit B602), not SQL injection; update the comment/text
to say "command injection risk" and either remove shell=True or refactor
run_command to use a safe API (e.g., subprocess.run with a list of args or
proper input validation/escaping) and/or sanitize/validate user_input before
passing it to subprocess.call to eliminate the shell injection vector.In @.github/scripts/bedrock_helper.py:
- Around line 1-169: The file fails CI due to formatting; run the formatter and
commit the changes: runruff format .github/scripts/bedrock_helper.py(or your
project's formatter) and reformat the file socreate_message,
_create_via_anthropic, and_create_via_bedrock(and their
imports/annotations) follow the project's ruff/PEP8 rules, then stage and push
the updated file so the pipeline passes.In @.github/workflows/setup-claude-review.sh:
- Around line 74-76: The printed phase descriptions contain unescaped dollar
signs (e.g., "$1.50/PR", "$1.50-$5/PR", "$3-$8/PR") so Bash treats $1 and $3 as
positional parameters; update the echo lines that print "Phase 1 - Comment
Only", "Phase 2 - Selective Consensus", and "Phase 3 - Draft PR Creation" to
escape the dollar signs (e.g., use $1.50 or wrap the entire string in single
quotes) so the dollar amounts appear literally.
Nitpick comments:
In @.github/AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md:
- Around line 201-210: The fenced code blocks in
AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md that contain plain lists such as
the block showing ".github/workflows/* # Prevent workflow self-modification"
and the block containing "security-check (Job 1)" are missing language
specifiers; update those backticked fences to include an explicit short language
(e.g., ```text) so rendering uses proper syntax highlighting for those blocks;
locate the two code fences around the list of paths and the "security-check (Job
1)" job description and prefix their opening triple-backticks with the chosen
language identifier.In @.github/workflows/CLAUDE_REVIEW_SETUP.md:
- Around line 72-87: The fenced secret/config code blocks for
CLAUDE_CODE_OAUTH_TOKEN, PAL_MCP_API_KEY/PAL_MCP_ENDPOINT, and PAT_TOKEN should
include a language specifier (e.g.,textorbash) to improve rendering;
update the three code fences surrounding the lines containing the environment
variables CLAUDE_CODE_OAUTH_TOKEN, PAL_MCP_API_KEY and PAL_MCP_ENDPOINT, and
PAT_TOKEN to usetext (orbash) instead of plain ``` so the blocks render
correctly.In @.github/workflows/README_CLAUDE_REVIEW.md:
- Around line 71-80: The code block showing the repository tree (the block
starting with ".github/workflows/") is missing a language specifier; change the
opening fence fromtotext so the block becomes "text" and keep the closing fence as "" to ensure proper syntax highlighting in
README_CLAUDE_REVIEW.md.In @.github/workflows/setup-claude-review.sh:
- Around line 122-129: Change the interactive token prompts to hide input: use a
silent read (read -s) when reading the claude_token so the token is not echoed,
then print a newline after the read so the prompt/terminal formatting remains
correct; keep the existing empty-check (if [ -z "$claude_token" ]) and the
subsequent secret upload (echo "$claude_token" | gh secret set
CLAUDE_CODE_OAUTH_TOKEN) unchanged. Apply the same pattern to the other
sensitive reads referenced in the comment (the other token variables read at
lines 142 and 171) so all OAuth/API/PAT inputs are read with read -s, validated
for emptiness, and then passed to gh secret set as before.</details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro **Run ID**: `e6e7819a-1e25-4dff-8000-25460c46b66d` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 335d5c3f7e8bffbede03444db1fa8c40d4a5bd4d and 1a28cdc0e21d68eca62b1980218c4d4fc9eb9b47. </details> <details> <summary>📒 Files selected for processing (8)</summary> * `.github/AUTONOMOUS_SCANNER_IMPLEMENTATION_SUMMARY.md` * `.github/AUTONOMOUS_SCANNER_QUICKSTART.md` * `.github/AUTONOMOUS_SCANNER_STATUS.md` * `.github/scripts/bedrock_helper.py` * `.github/workflows/CLAUDE_REVIEW_SETUP.md` * `.github/workflows/DEPLOYMENT_STATUS.md` * `.github/workflows/README_CLAUDE_REVIEW.md` * `.github/workflows/setup-claude-review.sh` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| ```python | ||
| # In app/test_security.py | ||
| import subprocess | ||
| def run_command(user_input): | ||
| subprocess.call(user_input, shell=True) # SQL injection risk | ||
| ``` |
There was a problem hiding this comment.
Incorrect vulnerability description: command injection, not SQL injection.
The comment on line 175 says "SQL injection risk" but the code demonstrates command injection via subprocess.call(..., shell=True) with user input. Bandit would flag this as B602 (subprocess_popen_with_shell_equals_true).
📝 Suggested fix
def run_command(user_input):
- subprocess.call(user_input, shell=True) # SQL injection risk
+ subprocess.call(user_input, shell=True) # Command injection risk🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/AUTONOMOUS_SCANNER_STATUS.md around lines 171 - 176, The
vulnerability description is wrong: the code in run_command uses
subprocess.call(user_input, shell=True) which is a command-injection risk
(Bandit B602), not SQL injection; update the comment/text to say "command
injection risk" and either remove shell=True or refactor run_command to use a
safe API (e.g., subprocess.run with a list of args or proper input
validation/escaping) and/or sanitize/validate user_input before passing it to
subprocess.call to eliminate the shell injection vector.
| echo " 1) Phase 1 - Comment Only (Safest, $1.50/PR, 2-5 min)" | ||
| echo " 2) Phase 2 - Selective Consensus ($1.50-$5/PR, 5-13 min)" | ||
| echo " 3) Phase 3 - Draft PR Creation ($3-$8/PR, 8-20 min)" |
There was a problem hiding this comment.
Bug: $1 is interpreted as a function argument, not a dollar amount.
In lines 74-76, $1.50, $1.50-$5, and $3-$8 contain unquoted $1 and $3 which Bash interprets as positional parameters. Since select_phase receives no arguments, these will expand incorrectly (e.g., .50/PR instead of $1.50/PR).
🐛 Proposed fix: escape the dollar signs
- echo " 1) Phase 1 - Comment Only (Safest, $1.50/PR, 2-5 min)"
- echo " 2) Phase 2 - Selective Consensus ($1.50-$5/PR, 5-13 min)"
- echo " 3) Phase 3 - Draft PR Creation ($3-$8/PR, 8-20 min)"
+ echo " 1) Phase 1 - Comment Only (Safest, \$1.50/PR, 2-5 min)"
+ echo " 2) Phase 2 - Selective Consensus (\$1.50-\$5/PR, 5-13 min)"
+ echo " 3) Phase 3 - Draft PR Creation (\$3-\$8/PR, 8-20 min)"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| echo " 1) Phase 1 - Comment Only (Safest, $1.50/PR, 2-5 min)" | |
| echo " 2) Phase 2 - Selective Consensus ($1.50-$5/PR, 5-13 min)" | |
| echo " 3) Phase 3 - Draft PR Creation ($3-$8/PR, 8-20 min)" | |
| echo " 1) Phase 1 - Comment Only (Safest, \$1.50/PR, 2-5 min)" | |
| echo " 2) Phase 2 - Selective Consensus (\$1.50-\$5/PR, 5-13 min)" | |
| echo " 3) Phase 3 - Draft PR Creation (\$3-\$8/PR, 8-20 min)" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/setup-claude-review.sh around lines 74 - 76, The printed
phase descriptions contain unescaped dollar signs (e.g., "$1.50/PR",
"$1.50-$5/PR", "$3-$8/PR") so Bash treats $1 and $3 as positional parameters;
update the echo lines that print "Phase 1 - Comment Only", "Phase 2 - Selective
Consensus", and "Phase 3 - Draft PR Creation" to escape the dollar signs (e.g.,
use \$1.50 or wrap the entire string in single quotes) so the dollar amounts
appear literally.
Co-Authored-By: Claude <noreply@anthropic.com>
PAL MCP Consensus Not AvailableSecurity-sensitive files were detected, but PAL MCP multi-model consensus is not configured. High-stakes files changed: To enable PAL MCP consensus:
Claude Code Review results are still available above. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/scripts/bedrock_helper.py (1)
75-79: Prefer raising an exception instead of exiting inside a shared helper.Hard-exiting here makes this module harder to reuse and test; let callers decide whether to terminate the process.
Suggested change
- print( - "::error::No API credentials. Set ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK + AWS_REGION", - file=sys.stderr, - ) - sys.exit(1) + raise RuntimeError( + "No API credentials. Set ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK + AWS_REGION" + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/scripts/bedrock_helper.py around lines 75 - 79, Replace the hard exit by raising an exception: remove the print(..., file=sys.stderr) and sys.exit(1) calls and instead raise a descriptive exception (e.g., RuntimeError or a custom CredentialsError) with the same message so callers of this helper can decide how to handle termination; update any callers/tests to catch or propagate the new exception as needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/scripts/bedrock_helper.py:
- Around line 146-147: The current RuntimeError raises include response.text
which can leak sensitive prompt/user data; change the error to return only the
status and a bounded/sanitized excerpt of the body (e.g. a fixed-length safe
excerpt or a redacted summary) instead of the full response.text. Update the
raise in the Bedrock call site (the block that checks response.status_code >=
400 and raises RuntimeError) to build a safe_message using a helper like
safe_excerpt(response.text, max_chars=200) or a parsed error code if available,
and include that sanitized message in the RuntimeError while ensuring no full
response body is included.
---
Nitpick comments:
In @.github/scripts/bedrock_helper.py:
- Around line 75-79: Replace the hard exit by raising an exception: remove the
print(..., file=sys.stderr) and sys.exit(1) calls and instead raise a
descriptive exception (e.g., RuntimeError or a custom CredentialsError) with the
same message so callers of this helper can decide how to handle termination;
update any callers/tests to catch or propagate the new exception as needed.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: f7f3e199-3761-4490-b364-96f84561a1a1
📒 Files selected for processing (1)
.github/scripts/bedrock_helper.py
| if response.status_code >= 400: | ||
| raise RuntimeError(f"Bedrock API error: {response.status_code} - {response.text}") |
There was a problem hiding this comment.
Avoid leaking full Bedrock response bodies in exceptions/logs.
Including response.text can expose prompt/user data or backend details in CI logs. Return status + bounded/sanitized context instead.
Suggested change
- if response.status_code >= 400:
- raise RuntimeError(f"Bedrock API error: {response.status_code} - {response.text}")
+ if response.status_code >= 400:
+ request_id = response.headers.get("x-amzn-requestid", "unknown")
+ raise RuntimeError(
+ f"Bedrock API error: status={response.status_code}, request_id={request_id}"
+ )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/scripts/bedrock_helper.py around lines 146 - 147, The current
RuntimeError raises include response.text which can leak sensitive prompt/user
data; change the error to return only the status and a bounded/sanitized excerpt
of the body (e.g. a fixed-length safe excerpt or a redacted summary) instead of
the full response.text. Update the raise in the Bedrock call site (the block
that checks response.status_code >= 400 and raises RuntimeError) to build a
safe_message using a helper like safe_excerpt(response.text, max_chars=200) or a
parsed error code if available, and include that sanitized message in the
RuntimeError while ensuring no full response body is included.
PAL MCP Consensus Code Review (Manual Analysis)OverviewPR #89 imports Ocelot review setup tooling and scanner documentation, adding 3,215 lines across 8 files. The PR introduces:
The changes are entirely additive (no modifications to existing code) and focus on developer tooling and documentation. Critical Issues🔴 CRITICAL-1: Inconsistent Environment Variable AccessFile: Issue: The code uses # Line 57: Check with os.getenv() - returns None if missing
if os.getenv("ANTHROPIC_API_KEY"):
# Line 86: Access with os.environ[] - raises KeyError if missing
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])Impact: If environment variables are unset between the check and access (race condition), or if concurrent modifications occur, the code will crash with Risk: HIGH - Runtime crash in CI/CD environment Recommendation: Use api_key = os.getenv("ANTHROPIC_API_KEY")
client = anthropic.Anthropic(api_key=api_key)🔴 CRITICAL-2: Missing Input Validation in Shell ScriptFile: Issue: User input for secrets is read directly without validation or sanitization. read -p "Paste your Claude OAuth token: " claude_token
# No validation - empty, whitespace-only, or malformed input accepted
echo "$claude_token" | gh secret set CLAUDE_CODE_OAUTH_TOKENImpact:
Risk: MEDIUM-HIGH - Workflow misconfiguration, potential security issue Recommendation: Add validation: read -p "Paste your Claude OAuth token: " claude_token
if [[ ! "$claude_token" =~ ^[A-Za-z0-9_-]+$ ]] || [ ${#claude_token} -lt 20 ]; then
error "Invalid token format (expected alphanumeric, min 20 chars)"
exit 1
fiHigh Priority🟠 HIGH-1: No Error Recovery for HTTP RequestsFile: Issue: HTTP requests to Bedrock have no retry logic or exponential backoff. with httpx.Client(timeout=300) as http_client:
response = http_client.post(url, headers=headers, json=body)
if response.status_code >= 400:
raise RuntimeError(f"Bedrock API error: {response.status_code} - {response.text}")Impact: Transient network errors (429 rate limits, 503 service unavailable) cause immediate failure instead of retry. Risk: MEDIUM - CI job failures from transient issues Recommendation: Add retry logic with exponential backoff: from httpx import HTTPStatusError
import time
max_retries = 3
for attempt in range(max_retries):
try:
response = http_client.post(url, headers=headers, json=body)
response.raise_for_status()
break
except HTTPStatusError as e:
if e.response.status_code in (429, 503) and attempt < max_retries - 1:
time.sleep(2 ** attempt) # Exponential backoff
continue
raise🟠 HIGH-2: Hardcoded Timeout ValueFile: Issue: 300-second timeout hardcoded with no configurability. with httpx.Client(timeout=300) as http_client:Impact:
Recommendation: Make timeout configurable: def create_message(
*,
timeout: int = 300, # Add parameter with default
...
):
...
with httpx.Client(timeout=timeout) as http_client:🟠 HIGH-3: Missing Unit TestsFile: Issue: No unit tests for critical authentication and API logic (diff shows 0 tests modified). Impact:
Risk: MEDIUM - Maintainability concern Recommendation: Add pytest tests: def test_model_mapping():
assert BEDROCK_MODEL_MAP["claude-opus-4-20250514"] == "us.anthropic.claude-opus-4-20250514-v1:0"
def test_create_message_missing_credentials(monkeypatch):
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
monkeypatch.delenv("AWS_BEARER_TOKEN_BEDROCK", raising=False)
with pytest.raises(SystemExit):
create_message(model="test", max_tokens=100, temperature=0.7, messages=[])🟠 HIGH-4: Shell Command Injection RiskFile: Issue: User-controlled branch name constructed with command substitution, then used in git commands. TEST_BRANCH="test/ai-review-setup-$(date +%s)"
git checkout -b "$TEST_BRANCH"
git push origin "$TEST_BRANCH"Impact: While Risk: LOW-MEDIUM (currently safe, but fragile pattern) Recommendation: Add comment warning and consider validation: # SAFETY: Branch name uses trusted date command only. Do NOT use user input.
TEST_BRANCH="test/ai-review-setup-$(date +%s)"Medium Priority🟡 MEDIUM-1: Incomplete Error MessagesFile: Issue: Error message doesn't specify what action failed or what component needs credentials. print(
"::error::No API credentials. Set ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK + AWS_REGION",
file=sys.stderr,
)Recommendation: Add context: print(
"::error::Failed to create message: No API credentials found. "
"Set ANTHROPIC_API_KEY or (AWS_BEARER_TOKEN_BEDROCK + AWS_REGION)",
file=sys.stderr,
)🟡 MEDIUM-2: Model ID Mapping FragilityFile: Issue: Model mapping is hardcoded without version fallback or validation. BEDROCK_MODEL_MAP: dict[str, str] = {
"claude-opus-4-20250514": "us.anthropic.claude-opus-4-20250514-v1:0",
"claude-haiku-4-5-20251001": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
}Impact: If new model versions are released, callers must update mapping manually or face silent fallback to unmapped model IDs. Recommendation: Add logging for unmapped models: bedrock_model = BEDROCK_MODEL_MAP.get(model, model)
if model not in BEDROCK_MODEL_MAP:
print(f"::warning::Using unmapped model ID '{model}' - may need Bedrock mapping", file=sys.stderr)🟡 MEDIUM-3: No Response ValidationFile: Issue: Bedrock response parsing assumes content structure without validation. content_blocks = [
ContentBlock(type="text", text=block["text"])
for block in data.get("content", [])
if block.get("type") == "text"
]Impact: If API returns unexpected structure, crashes or silently returns empty content. Recommendation: Add validation: if "content" not in data:
raise RuntimeError(f"Invalid Bedrock response: missing 'content' field. Response: {data}")🟡 MEDIUM-4: Documentation File SizeFile: Multiple markdown files totaling 3,215 lines Issue: Very large documentation files make review difficult and increase repo size. Files:
Recommendation: Consider splitting into smaller focused docs or moving to Wiki/external docs site. For repo docs, prefer concise quick-start with links to comprehensive guides. 🟡 MEDIUM-5: Temperature Forcing with Thinking ModeFile: Issue: Temperature is forced to 1.0 when thinking mode is enabled, overriding user choice. if thinking:
kwargs["thinking"] = thinking
kwargs["temperature"] = 1 # Overrides user-provided temperatureImpact: User cannot control temperature when using extended thinking, which may be desired for certain use cases. Recommendation: Add comment explaining API requirement, or raise warning: if thinking:
kwargs["thinking"] = thinking
# Anthropic API requires temperature=1 when thinking is enabled (API constraint)
if temperature != 1:
print("::warning::Temperature forced to 1.0 due to thinking mode requirement", file=sys.stderr)
kwargs["temperature"] = 1Positive Observations✅ EXCELLENT: Security Best Practices
✅ EXCELLENT: Type Safety
✅ EXCELLENT: API Abstraction
✅ GOOD: Error Handling Structure
✅ GOOD: Shell Script UX
✅ GOOD: Documentation Quality
Review Summary
Overall Risk Assessment: MEDIUM Recommended Actions Before MergeMust Fix (Blocking):
Should Fix (High Priority): Consider for Follow-up: Security Checklist
Cost & Performance NotesEstimated PR Review Cost:
Performance:
This review was generated by manual code analysis. Reviewer: Claude Sonnet 4.5 |
Replace os.environ[] with os.getenv() for env var access to match the check pattern already used on lines 57/66. Consistency fix only — not a real race condition (single-threaded CI script). 3-model consensus (GPT-5.2, Gemini-3-Pro, Grok-4) confirmed this was the only actionable item from 7 review issues. Remaining 6 issues were over-engineering or contradicted the Let It Crash philosophy. Co-Authored-By: Claude <noreply@anthropic.com>
PAL MCP Consensus Not AvailableSecurity-sensitive files were detected, but PAL MCP multi-model consensus is not configured. High-stakes files changed: To enable PAL MCP consensus:
Claude Code Review results are still available above. |
PAL MCP Consensus Code Review (Manual Review)OverviewPR #89: feat: import Ocelot review setup tooling & scanner documentation This PR imports comprehensive documentation and tooling for autonomous code scanning and review systems. The changes include:
Files Changed: 8 files, 3215 insertions Critical IssuesNone Found ✅ The code demonstrates good security practices with no blocking issues. High Priority1. Error Handling: Insufficient Exception Context (bedrock_helper.py:147)Location: Issue: The RuntimeError raised on Bedrock API failures could expose sensitive information through response.text, which may contain bearer tokens or internal error details. raise RuntimeError(f"Bedrock API error: {response.status_code} - {response.text}")Risk: Low-Medium. While unlikely in normal operation, API error responses could leak sensitive data in logs. Recommendation: # Sanitize error messages to avoid token leakage
error_msg = response.text[:200] if len(response.text) > 200 else response.text
raise RuntimeError(f"Bedrock API error: {response.status_code} - {error_msg}")Rationale: Limits potential information disclosure while preserving debugging utility. 2. Missing Input Validation (bedrock_helper.py:45-52)Location: Issue: The Risk: Medium. Invalid inputs could lead to unclear error messages or unexpected API behavior. Recommendation: def create_message(
*,
model: str,
max_tokens: int,
temperature: float,
messages: list[dict[str, Any]],
thinking: dict[str, Any] | None = None,
) -> MessageResponse:
"""Create a message using either Anthropic API or Bedrock bearer token."""
# Validate inputs
if not messages:
raise ValueError("messages list cannot be empty")
if max_tokens <= 0:
raise ValueError("max_tokens must be positive")
if not 0 <= temperature <= 1:
raise ValueError("temperature must be between 0 and 1")
# ... rest of functionRationale: Fail fast with clear error messages rather than obscure API errors. 3. Timeout Configuration Hardcoded (bedrock_helper.py:144)Location: Issue: The httpx client timeout is hardcoded to 300 seconds. For large requests or thinking mode, this may be insufficient. with httpx.Client(timeout=300) as http_client:Risk: Low. Requests could timeout prematurely for complex operations. Recommendation: # Make timeout configurable
timeout = int(os.getenv("BEDROCK_TIMEOUT", "300"))
with httpx.Client(timeout=timeout) as http_client:Rationale: Allows operators to adjust timeout based on workload without code changes. Medium Priority4. Documentation Files Size and RedundancyObservation: Several markdown files exceed 300-600 lines with overlapping content:
Issue: Large documentation files can become difficult to maintain and may contain stale information over time. Recommendation: Consider splitting into focused documents:
Rationale: Smaller, focused documents are easier to keep current and navigate. 5. Model Mapping Completeness (bedrock_helper.py:19-22)Location: Issue: BEDROCK_MODEL_MAP: dict[str, str] = {
"claude-opus-4-20250514": "us.anthropic.claude-opus-4-20250514-v1:0",
"claude-haiku-4-5-20251001": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
}Recommendation: Add a warning or validation: bedrock_model = BEDROCK_MODEL_MAP.get(model)
if not bedrock_model:
print(f"::warning::Model {model} not in BEDROCK_MODEL_MAP, using as-is", file=sys.stderr)
bedrock_model = modelRationale: Makes it clear when unexpected models are used, aiding troubleshooting. 6. Lazy Import Pattern ConsistencyObservation: Both Impact: Minimal. The lazy import pattern is reasonable for optional dependencies, but the inconsistency could confuse readers. Recommendation: Document why lazy imports are used (e.g., "Imported on-demand to avoid requiring both anthropic and httpx packages"). Positive Observations✅ Security Best Practices
✅ Code Quality
✅ Architecture
✅ Documentation Quality
Review Summary
Recommendations SummaryBefore Merge:
Post-Merge (Technical Debt):
ConclusionAPPROVED FOR MERGE ✅ This PR imports high-quality tooling and documentation for AI-powered code review and scanning systems. The Python code demonstrates excellent security practices and clean architecture. The documentation is comprehensive and production-ready. Risk Level: Low
Key Strengths:
Key Concerns (All Minor):
This review was generated by manual code analysis in the absence of PAL MCP. Reviewed: 2026-03-26 |
Summary
create_message()) used by scanner scripts — enables Bedrock fallback supportAll Ocelot-specific references (
Tony363/Ocelot,efsnetworksinc/OcelotV3) cleaned from imported docs.Context
All 14 Ocelot workflows already exist in SuperClaude (with evolved versions). These 8 files are the remaining Ocelot-only assets — scripts and documentation that complement the existing workflows.
Test plan
bedrock_helper.pyimports cleanly:python3 -c "from bedrock_helper import create_message"passessetup-claude-review.shis executable (chmod +xapplied)grep -r "Ocelot" .github/clean)🤖 Generated with Claude Code
Summary by Sourcery
Add shared Anthropic/Bedrock helper plus documentation and setup tooling for the autonomous scanner and multi-phase Claude review system.
New Features:
Enhancements:
Summary by CodeRabbit
New Features
Documentation