1. SECRET_PATTERN had [A-Za-z0-9+/_\-!@#] -- backslash-escaped hyphen
is invalid POSIX ERE; grep parsed it as a range with invalid bounds.
Fix: move hyphen to end of class: [A-Za-z0-9+/_!@#-].
2. printf -- '---\n' fails with 'invalid option' in bash because the
builtin does not accept -- as end-of-options. Removed -- from all
four printf calls.
Shell heredocs with unindented bodies (line 1 content) terminate YAML
run: | block scalars. The YAML parser sees the unindented heredoc body
as leaving the block, making the workflow file unparseable -- Gitea
silently stops creating runs for a workflow with invalid YAML.
Replace the single-quoted heredoc prompt with a group of printf + cat
calls. Every line stays properly indented within the YAML block scalar.
Use jq --rawfile instead of --arg to load the prompt from a temp file,
which also eliminates shell escaping hazards for large strings.
Gitea 1.22 cancel-in-progress does not behave like GitHub Actions: when
a new synchronize event arrives while a review is running, instead of
cancelling the running job and starting a new one, it drops the new run
silently. Remove the concurrency block entirely so every commit to a PR
gets its own review run.
The PROMPT string contained backtick-quoted text for the Evidence field
example. Inside a double-quoted bash string, backticks trigger command
substitution, causing 'exact: command not found' at runtime.
Fix: build the prompt using a single-quoted heredoc (no shell expansion
inside) then splice dynamic values via sed and python3 replace() instead
of shell variable interpolation.
Two changes to reduce hallucinations in pr-review:
1. Codebase index (new step "Build codebase index"):
Generates a compact manifest of everything that EXISTS in the project:
- All registered Tauri commands (from lib.rs generate_handler![])
- All TypeScript exports (from tauriCommands.ts)
- All public Rust fn signatures in commands/
- All DB migration names
This index is prepended to the prompt so the model cannot invent
functions like authenticate_sudo or continue_chat_history that are
absent from both the index and the file contents.
2. Full-repo verification (updated "Verify findings" step):
Previously only grepped changed files, which falsely tagged findings
about unchanged-but-real code as UNVERIFIED. Now runs git ls-files
to load all tracked source files, so verification only fails for
code that genuinely does not exist anywhere in the codebase.
If qwen3-coder continues to hallucinate after these changes, swap the
model name on line 184 to bedrock-personal or claude-haiku.
qwen3-coder-next fabricates plausible-looking code in its Evidence
blocks instead of quoting from the actual files provided. This adds a
Python verification step that greps each fenced code block against the
real changed files and tags any finding whose evidence cannot be found
as UNVERIFIED.
This is a safeguard, not a fix — the model is fundamentally unreliable
for grounded code review. The longer-term fix is to replace qwen3-coder
with a model that stays grounded to context (Claude Haiku, devstral,
or deepseek-coder-v2 via the LiteLLM proxy / vLLM at 172.0.1.42).
The previous regex matched any line containing "password", "token", etc.
near certain punctuation characters. This silently removed function
signatures, variable declarations, and test assertions from the context
sent to the LLM — causing it to hallucinate 3 BLOCKERs per review:
- "function signature missing" (the `password: &str` param was scrubbed)
- "filter body empty" (the filter condition containing "password" was scrubbed)
- "password passed unencrypted" (the decrypt_token call line was scrubbed)
Fix: match actual credential VALUES only:
- Well-known token formats (AKIA..., ghp_..., xox...)
- keyword = "long_quoted_literal" (25+ chars, clearly a value not a name)
- Standalone base64 blob lines (60+ chars, PEM-style)
Never scrub a line just because it contains a credential-related word.
Three changes:
- Exclude Cargo.lock/lockfiles from the diff — removes ~163 lines of
hash noise that waste the review budget with no value
- Raise line cap from 500 to 3000 and add a truncation notice when
the diff is cut, so the model knows the diff is incomplete
- Harden prompt: require quoted evidence for every finding; add explicit
self-verification step for missing-identifier claims (search full diff
before raising); tighten no-hallucinate instruction
- call_tool: 30s hard timeout via tokio::time::timeout
- discover_server: 60s hard timeout wrapping full connect+discover sequence
- delete_mcp_server: write_audit_event before cascade delete, capturing
server name, tool count, and resource count
- initiate_mcp_oauth: append cryptographically random state nonce for CSRF
- pr-review.yml: rewrite prompt to require line-quoted evidence for every
finding and eliminate hallucinated false positives
Replace direct Ollama API calls with liteLLM proxy at
172.0.0.29:11434 using qwen2.5-72b (72B VLLM model). Increase
timeouts to 300s for larger model inference. Reuses existing
OLLAMA_API_KEY secret for liteLLM auth.
Also add push-to-master trigger on test.yml so merges to master
run the full CI suite (previously only pull_request events triggered).
- Replace flawed sed-based redaction with grep -v line-removal covering
JS/YAML assignments, Authorization headers, AWS keys (AKIA…), Slack
tokens (xox…), GitHub tokens (gh[opsu]_…), URLs with embedded
credentials, and long Base64 strings
- Add -c flag to jq -n when building Ollama request body (compact JSON)
- Remove jq . full response dump to prevent LLM-echoed secrets in logs
- Change Gitea API Authorization header from `token` to `Bearer`
Root cause of false-positive "critical" errors:
- sed pattern was matching api_key/token within YAML variable names
(e.g. OLLAMA_API_KEY:) and redacting the ${{ secrets.X }} value,
producing mangled syntax that confused the AI reviewer
- Fix: use [^$[:space:]] to skip values starting with $ (template
expressions and shell variable references)
Other fixes:
- Replace --retry-all-errors with --retry-connrefused --retry-max-time 120
to avoid wasting retries on unrecoverable 4xx errors
- Check HTTP_CODE before jq validation so error messages are meaningful
- Add permissions: pull-requests: write to job
- Add edited to pull_request.types so title changes trigger re-review
- Change git diff .. to git diff ... (three-dot merge-base diff)
- Replace hardcoded server/repo URLs with github.server_url and
github.repository context variables (portability)
- Log review length before posting to detect truncation
Security:
- Replace http://172.0.0.29:3000 git remote with https://gogs.tftsr.com
- Replace http://172.0.0.29:3000 Gitea API URL with https://gogs.tftsr.com
- Remove internal 172.0.0.29 from container DNS (keep 8.8.8.8, 1.1.1.1)
- Move PR_TITLE and PR_NUMBER to env vars to prevent shell injection
Correctness:
- Fix diff_size comparison from lexicographic > '0' to != '0'
- Strip leading whitespace from wc -l output via tr -d ' '
- Switch diff truncation from head -c 20000 to head -n 500 (line-safe)
- Add jq empty validation before parsing Ollama response
Reliability:
- Add --connect-timeout 30 and --retry 3 --retry-delay 5 to Ollama curl
- Add --connect-timeout 10 to review POST curl
- Change Post review comment to if: always() so it runs on analysis failure
- Post explicit failure comment when analysis produces no output
Workflow changes:
- Switch Ollama to https://ollama-ui.tftsr.com/ollama/v1 (OpenAI-compat)
with OLLAMA_API_KEY secret — removes hardcoded internal IP
- Update endpoint to /chat/completions and response parsing to
.choices[0].message.content for OpenAI-compat format
- Add concurrency block to prevent racing on same PR number
- Add shell: bash + set -euo pipefail to all steps
- Add TF_TOKEN presence validation before posting review
- Add --max-time 30 and HTTP status check to comment POST curl
- Redact common secret patterns from diff before sending to Ollama
- Add binary diff warning via grep for "^Binary files"
- Add UTC timestamps to Ollama call and review post log lines
- Add always-run Cleanup step to remove /tmp artifacts
Version consistency:
- Sync Cargo.toml and package.json from 0.1.0 to 0.2.50 to match
tauri.conf.json
- Restore 014_create_ai_providers migration and tests missing due to
branch diverging from master before PR #34 merged
- Bump version from 0.2.10 to 0.2.50 to match master and avoid regression
- Trim diff input to 20 KB to prevent Ollama token overflow
- Add --max-time 120 to curl to prevent workflow hanging indefinitely
- Fix OLLAMA_URL to point at actual Ollama server (172.0.1.42:11434)
- Fix API path from /v1/chat to /api/chat (Ollama native endpoint)
- Fix response parsing from OpenAI format to Ollama native (.message.content)
- Use jq to safely construct JSON bodies in both Analyze and Post steps
- Add HTTP status code check and response body logging for diagnostics