Conversation
…#325) * fix(review): add post-LLM filter for hardcoded secret false positives Cora LLM sometimes flags struct field declarations (e.g. api_key: String) as 'Hardcoded password or secret in variable' even when no literal value is present. The built-in sec-hardcoded-secret regex only matches actual assignments like api_key = "sk-...", but the LLM can hallucinate these findings regardless of .cora.yaml rules. Add apply_llm_secret_fp_filter that cross-validates LLM security findings against actual diff lines. If a finding about hardcoded secrets points to a line that doesn't match the sec-hardcoded-secret regex, it's removed as a false positive. Unknown/unresolvable lines are kept (safe default). 4 unit tests cover: FP removal, real secret retention, non-security pass-through, and unknown-line preservation. * fix(deps): bump git2 0.20 → 0.21 to resolve RUSTSEC advisories - git2 0.21.0 fixes RUSTSEC-2026-0183 (null ptr in Remote::list) and RUSTSEC-2026-0184 (null ptr in Blame::blame_buffer Signature) - Remote::url() API changed from Option<&str> to Result<&str, Error> - Adapted get_repo_info() to use .url().ok() chain * fix(deps): bump quinn-proto 0.11.14 → 0.11.15 (RUSTSEC-2026-0185) Resolves remote memory exhaustion DoS vulnerability in quinn-proto unbounded out-of-order stream reassembly. --------- Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…ging (#328) - Tighten injection/exec regex: only flag subprocess.run when dynamic input signals present (f-string, format(), shell=True, string concat with user input). Literal list calls like subprocess.run(cmd) are safe. - Add debug logging to apply_ignore_rules for better diagnostics - Add unit tests for ignore_rules (title match, issue_type match, empty, case insensitive) - Add unit tests for security_scanner (no FP on literal list, triggers on f-string and shell=True) Fixes #326 Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…cy and new usage field names GPT-5.4 (and potentially other newer models) return both legacy (prompt_tokens/completion_tokens) and new (input_tokens/output_tokens) field names in the usage object simultaneously. serde_json >= 1.0.120 tracks visited fields during struct deserialization. When an alias maps to a field already set from the primary key, it raises 'duplicate field' error, breaking all reviews using affected models. Fix: Replace serde alias-based Usage deserialization with manual parse_usage_value() that extracts from serde_json::Value with explicit preference order (primary > camelCase > new). Updated both streaming and non-streaming code paths. Closes #330
fix: handle serde duplicate field error when providers send both legacy and new usage field names
- Fix #32: Command injection via in commit_cmd.rs Replace sh -c shell execution with direct Command::new(program).args(args) to prevent shell injection through EDITOR env variable. - Fix #61: Path traversal in JS/TS import resolver Add safe_join() helper that canonicalizes paths and verifies containment within project root. Apply to JS/TS import resolution and all other project_root.join() calls involving user-controlled paths. - Fix #62: Path traversal in symbol resolver Use safe_join() in resolve_symbols, test file resolution, and read_entry_content to prevent reading files outside project root. - Fix #91: API key file written before chmod (TOCTOU race) Create file with 0o600 permissions from the start using OpenOptionsExt on Unix, eliminating the window between write and chmod. Closes #332
fix: resolve 4 critical security vulnerabilities (P0)
Fixes: - #42 Severity sort inverted: sort descending (Critical first) so max_findings truncation drops least important findings - #45 Security findings dropped on LLM failure: include security_findings in fallback condition and summary - #52 HashMap nondeterministic hash: sort HashMap entries by key before hashing for deterministic filenames - #53 Debt score trend wrong: compute recent_avg_quality from recent slice instead of overall average - #54 Category trend change inflated: build recent_category_counts from recent slice for accurate delta - #92 Config precedence inverted: env vars > config > auto-detect > defaults - #93 context_chain config ignored: copy context_chain from ReviewSection in merge_into - #96 Hook install overwrites existing hooks: use sentinel marker, backup non-cora hooks, compose wrapper Refs #333
fix: resolve silent data corruption bugs (P1)
fix: update project-sync workflow — add PR trigger, continue-on-error, robust helpers
) LLM API providers use different parameter names for max output tokens: - OpenAI (legacy): max_tokens - OpenAI (new): max_completion_tokens - Anthropic: max_tokens - Google Gemini/Vertex: max_output_tokens cora-cli previously hardcoded 'max_tokens' everywhere, causing HTTP 400 errors ('Unsupported parameter: max_output_tokens') when providers don't accept it. Changes: - Add max_tokens_param to LlmSection config schema (supports 'auto' for provider-based detection, or explicit override) - Add resolve_max_tokens_param() in loader.rs for auto-detection logic - Replace hardcoded 'max_tokens' JSON key with dynamic key in both streaming and non-streaming LLM request paths - Add max_tokens_param to LLMConfig struct for runtime use - Display max_tokens_param in 'cora config' output Auto-detection maps: - gemini/google/vertex -> max_output_tokens - All other providers -> max_tokens Co-authored-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: Hermes Agent <hermes@nousresearch.com>
* perf: resolve scan/review pipeline performance bottlenecks (P2) Fix 10 performance issues — all 'repeated work in loops' patterns: #41 - Pre-compile regex patterns once per rule instead of per line #5 - Batch DB queries in handle_find_affected_tests (single IN clause) #13 - Batch symbol fetch for Affected command (single query) #14 - Prepare SQL statement once outside test-pattern loop #59 - Early cutoff in secrets scanner when max_findings reached #70 - Break out of all loops when symbol cap hit per file #67 - Cache file reads during sibling search in resolver #3 - Reuse single Tokio runtime for MCP tool calls (static LazyLock) #22 - Static LazyLock regexes in detect_function_entry #24 - Single transaction for prune_deleted instead of per-file Refs #335 * fix(ci): resolve clippy + security audit failures - clippy: remove redundant borrow in format! arg (llm.rs:456 &user_prompt) - security: bump anyhow 1.0.102 -> 1.0.103 (RUSTSEC-2026-0190, downcast_mut unsoundness) - security: bump crossbeam-epoch 0.9.18 -> 0.9.20 (RUSTSEC-2026-0204, fmt::Pointer null deref) Refs #335 --------- Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…eyword (#341) A merged PR that references issues via "Refs #N" (not "Closes #N") has no closingIssuesReferences — a legitimate non-error outcome. Previously the script could abort with exit 1 under 'set -e' when get_item_id() hit an unexpected GraphQL response shape (e.g. node: null), surfacing as a red 'sync' check on otherwise-green PRs (e.g. PR #338 merge). - Make get_item_id() and the LINKED query python defensive against null/unexpected shapes - Guard the empty-LINKED branch call sites with '|| true' so a missing board item never aborts the job
…e) (#342) Resolves the P3-core items from #334 — config values and profile values were accepted without semantic checks, so typos and out-of-range values propagated silently to runtime. #94 — Config::validate() at load time: - temperature 0.0..=2.0, max_tokens/timeout >= 1 - max_tokens_param, response_format, output.format, hook.mode/on_violation/min_severity - provider.base_url must have an http(s)/ws/unix scheme - multiple errors aggregated into one message #81 — Profile::validate(): focus weight 1-10, recognized action/tone/detail_level #57 — CategoryAction enum (case-insensitive deserialize): unknown values like 'blok' now fail loudly instead of silently becoming blocking #58 — evaluate() forces Pass when enabled=false (disabled gate never fails) #80 — deny_unknown_fields on all config sections: misspelled YAML keys (e.g. 'quailty_gate', 'temprature') rejected at parse time 24 new tests covering validation acceptance/rejection and deny_unknown_fields. All 637 tests pass; clippy + fmt clean. Refs #334
…) (#343) Markdown files (.md/.mdx/.markdown) frequently contain fenced code blocks that are documentation examples, not executable code. Treating their contents like real source code produced false positives — e.g. a `git push` inside a fenced bash block flagged as SQL injection (#329). New module `engine::markdown` detects fenced code blocks (triple-backtick / triple-tilde) within a diff chunk and exposes which new-file line numbers fall inside them. A new filter `apply_markdown_code_block_filter()` drops findings (from all sources: security/secrets/rules scanners + LLM) whose file:line lands inside a code block of a markdown file. Fence state is tracked across full hunk context (Add + Context lines, skipping Removed lines) so it works even when only the body of a code block was edited — the opening fence does not need to be part of the diff. Findings without a resolvable line number are kept (safe default). 11 new tests (7 unit for fence detection + 4 integration for the filter, including the exact #329 git-push/SQL-injection scenario). All 648 tests pass; clippy + fmt + audit clean. Refs #329
Closes the remaining minor items tracked under #334 so the issue can be fully resolved. Each fix is small and targeted. - #87 is_test_file: path-segment awareness so `latest`, `aspect`, `attestation`, `protest` are not mistaken for test files. - #66 glob_matches: directory excludes (`src/`) match only at segment boundaries (`mysrc/`, `docs/src-guide/` no longer caught). - #68 estimate_tokens: non-empty content returns at least 1 token (was 0 under integer division). - #72 RE_JAVA_IMPORT: allow wildcard capture (`import com.example.*` keeps the `*`), plus `import static`. - #73 RE_RUST_MOD: extract `mod foo;` declarations as dependency symbols, matching the documented behavior. - #23 index_stats: query `PRAGMA page_size` instead of assuming 4096 bytes. - #48 ReviewIssue.issue_type: serialize as `issue_type` (consistent with the field name); keep `type` as a deserialize alias. - #10 Severity::from_str_lossy: use `eq_ignore_ascii_case` (no allocation). Already-resolved items verified (no change needed): - #88 max_findings cutoff already sorts severity-descending before truncate. - #30 debt snapshot save already emits a warn! on write failure. 8 new tests. All 652 tests pass; clippy + fmt + audit clean. Closes #334
…ture slicing (#345) Review previously only resolved OUTBOUND dependencies (what changed code calls/imports). This adds the INBOUND axis — who calls the changed code (blast radius) — which is the highest-value context for flagging breaking signature/type changes, while staying token-economical. Bug fix (G2): review.rs passed `ignore.rules` (finding-type strings) to the context resolver instead of `ignore.files` (globs like target/**, node_modules/**). The resolver could inject build-artifact code, wasting tokens and adding noise. Now uses ignore.files. Changes - G2: review.rs build_context_chain now receives &config.ignore.files. - Config: new ContextConfig.include_callers (default true); max_context_tokens default 3000 -> 5000. - extraction.rs: extract_definitions_from_diff() — detects functions/types DECLARED in added lines for Rust/Python/JS-TS/Go/Java-Kotlin (per-language regexes). - resolver.rs: resolve_callers() walks source files (gitignore-aware via the `ignore` crate, so build artifacts are never scanned), bounded by MAX_CALLER_FILES_SCAN (400) and MAX_CALLERS_PER_SYMBOL (3). Caller slices are tiny (call line + 1 line of context, MAX_CALLER_LINES=4). - resolver.rs: signature_only() budget fallback — when the full body won't fit the remaining budget, inject the signature (up to `{` / 4 lines) instead of skipping the entry entirely. New ContextPriority::CallerSite. Design notes - follow_depth (outbound recursion) remains at its default of 1; recursive outbound resolution was previously a no-op placeholder and properly implementing it (cycle-safe, budget-bounded) is a separate larger task. The new include_callers axis delivers the real "deeper review" value, token-economically. - Caller resolution never self-reports (defining file excluded), respects include_tests, and skips ignored paths. Tests: 7 new (definition extraction across languages + dedup, caller resolution finds/skips, signature_only header-only). All 659 tests pass; clippy + fmt + audit clean.
Consolidates the [Unreleased] entries accumulated since v0.6.2 into a
versioned [0.7.0] release section and updates related documentation.
- Cargo.toml / Cargo.lock: 0.6.2 -> 0.7.0 (minor bump: new caller-context
feature + deny_unknown_fields is a breaking-minor change for configs
that previously relied on silently-ignored typos).
- CHANGELOG.md: reorganized into Highlights + Added/Changed/Fixed with
the v0.7.0 - 2026-07-16 header; fresh empty [Unreleased] on top.
- docs/changelog.md: matching concise release notes.
- docs/configuration.md:
- new "Cross-File Review Context" section documenting context_chain
(enabled, max_context_tokens=5000, follow_depth, include_tests,
include_callers) + outbound/inbound axes + signature fallback.
- "Config Resolution Order": note that values are validated at load
and typos rejected via deny_unknown_fields.
- Quality Gate: note CategoryAction is a case-insensitive validated
enum and a disabled gate never fails.
No behavior change (docs + version only). All 659 tests pass; clippy +
fmt clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.7.0 → main
Merges
developintomainfor the v0.7.0 release. Av0.7.0tag will be pushed to the resulting main commit to trigger the publish workflow (cross-platform binaries + GitHub Release + crates.io publish).What's in v0.7.0 (20 commits since v0.6.2)
Highlights
deny_unknown_fields(fix(config): add config validation + deny_unknown_fields (#334 P3-core) #342).Why minor (0.7.0)
New feature (caller context) +
deny_unknown_fieldsis a breaking-minor change for configs relying on silently-ignored typos.See
CHANGELOG.md## [0.7.0]for the full breakdown.All CI green on develop; 659 tests pass; clippy/fmt/audit clean.