Skip to content

release: sync develop → main for v0.13.0 - #503

Merged
ajianaz merged 18 commits into
mainfrom
develop
Aug 5, 2026
Merged

release: sync develop → main for v0.13.0#503
ajianaz merged 18 commits into
mainfrom
develop

Conversation

@ajianaz

@ajianaz ajianaz commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

What

Sync 18 commits from develop to main for v0.13.0 release.

Includes:

Why

Per CONTRIBUTING.md release flow:

develop (default) → PR → main → tag vX.Y.Z → release workflow

Tags must be on main, not develop. This PR brings main up to date so the v0.13.0 tag is on the correct branch.

Testing

All changes passed CI on develop (13/13 checks green on PR #501 and #502). main is behind by 18 commits and needs to catch up.

Checklist

  • Branch is develop (release sync)
  • All commits passed CI individually
  • No secrets or credentials

ajianaz and others added 18 commits August 4, 2026 13:07
* docs: comprehensive documentation audit — fill gaps, fix outdated info

CLI Reference (docs/cli-reference.md):
- Added 6 missing commands: dead-code, query, routes, serve, install, profile
- Added missing flags across all commands (--memory, --learn, --stdin,
  --filter, --coalesce, etc.)

Configuration (docs/configuration.md):
- New section: Ignore Files (ignore.files) with full 7-pattern glob syntax table
- New section: Static Analysis (review.static_analysis: auto_clippy, clippy_output_file)
- New section: Bundling (max_chars_per_group, strategy, coalesce options)
- New section: Analysis (entry_point_patterns)
- MCP tools table expanded from 5 → 18 tools
- Added cora serve (auto-reindex variant) alongside cora mcp
- Improved .cora.yaml example to be more comprehensive

Code Intelligence (docs/code-intelligence.md):
- Schema version updated v4 → v6 (added v5: reviews/findings/finding_events,
  v6: index config hash)
- New section: cora dead-code (dead code detection)
- New section: cora query (code graph query patterns)
- New section: cora routes (HTTP route listing)
- Fixed: --test-glob → --filter (renamed flag)
- Added --stdin to cora affected examples

README.md:
- Code Intelligence table: added dead-code, query, routes
- Config & Setup table: added config validate, profile list, serve, install
- MCP tools count: 15 → 18

docs/index.md:
- MCP tools count: 15 → 18

* docs: fix wrong defaults and add missing fields from subagent audit

Fixes identified by parallel subagent audit:
- Profile names: strict/balanced/lax → actual 8 profiles (security-first, performance, clean-code, beginner-friendly, minimal, rust-strict, typescript-strict, go-pragmatic)
- max_findings default: 50 → 5
- bundling.max_chars_per_group: 12000 → 60000
- bundling.strategy: directory → smart (actual enum: smart | flat)
- --lang → --language in code-intelligence.md
- +3 context_chain fields: use_brain, impact_depth, prefer_index
- +hook.on_violation, ignore.rules, output.color, llm.max_tokens_param
- +cora profile list reference in profiles section

---------

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…riting (#477)

Config merge used clone_from/clone for ignore.files and index_skip_files,
which silently overwrote default patterns when a user specified any custom
value. This caused build artifacts (target/**, dist/**, node_modules/**,
.git/**) and framework config files (*.config.ts, *.config.js) to leak
into review context, scan walks, and index-based scanner output.

Fix: extend defaults with user values instead of replacing, with
deduplication to avoid redundant entries.

Impact:
- cora review: context_chain now correctly filters default-ignored paths
- cora scan: walk_project exclude patterns now include defaults
- cora index: index-based scanner skip files preserved
- cora config show: effective config displays merged patterns

Tests: 3 new tests (merge_ignore updated, dedup, index_skip_files).
776 unit + 22 integration tests pass. Clippy clean.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
The global --config flag (CORA_CONFIG env) was silently ignored by
5 commands because they called load_config(None, ...) instead of
forwarding the user-provided config path.

Affected commands:
- cora config show        (config_cmd.rs)
- cora config validate    (config_cmd.rs)
- cora debt               (debt.rs)
- cora index              (main.rs - skip pattern loading)
- cora dead-code          (main.rs - entry_point_patterns)

Fix: thread cli.global.config.as_deref() through every call site.
DebtOptions gains a config_path field to receive the global flag.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…provider/base_url to cache key (#479)

Bug 1: post_match_filter ID mismatch (sec-hardcoded-secret vs crypto/hardcoded-secret)
- Builtin rule 'sec-hardcoded-secret' was never filtered by post_match_filter
  because the match arm only checked 'crypto/hardcoded-secret' (security_scanner.rs ID)
- Added 'sec-hardcoded-secret' as an alias in the match arm
- Added regression tests for builtin rule ID

Bug 2: Cache key missing provider and base_url
- cache_key() only hashed diff+model+temperature
- Switching providers with same model name returned stale cache from previous provider
- Added provider and base_url to cache_key, get_cached_review, save_cached_review
- Added regression tests for provider/base_url cache isolation

Tests: 781 pass (5 new), clippy clean, 6 integration pass

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…vent data loss (#480)

install_hook() backed up existing non-cora hooks to 'pre-commit.bak',
but uninstall_hook() looked for 'pre-commit.cora.bak' and
'pre-commit.pre-cora.bak'. Neither matched — so uninstall would delete
the cora hook WITHOUT restoring the user's original, losing it forever.

Fix: install now writes 'pre-commit.pre-cora.bak' (matching what
uninstall searches for), and the dead 'pre-commit.cora.bak' path in
uninstall is removed.

Added regression test that verifies backup filename consistency.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…list (#481)

* fix(findings): use parameterized queries to prevent SQL injection in list

The severity and file filters in list_findings() interpolated user input
directly into SQL strings via format!():

  format!("f.severity = '{}'", s.to_uppercase())
  format!("f.file_path LIKE '%{}%'", f.replace('"', "'"))

This allowed SQL injection through --severity or --file flags. The
f.replace('"', "'") only escaped double-quotes, not the single-quote
SQL string delimiter, making it ineffective.

Fix: build WHERE clause with ? placeholders and pass user input via
rusqlite::params!, matching the pattern already used by dismiss() and
reopen().

* fix(findings): use parameterized queries + fix flaky data_dir tests

SQL injection:
The severity and file filters in list_findings() interpolated user
input directly into SQL strings via format!().

Flaky test:
data_dir tests mutated CODECORA_HOME without synchronization, causing
intermittent failures when tests ran in parallel.

---------

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…filter (#483) (#484)

The static security scanner's CORS rule used an overly broad regex that
matched any occurrence of the word 'cors' followed by '*' anywhere on the
line. This triggered false positives on:
- Env var names like TITEN_CORS_ORIGINS (contains 'cors' + '*' from markdown bold)
- Documentation prose mentioning CORS configuration
- Comments instructing developers NOT to use wildcards

Three-layer fix:

1. Narrow regex to require actual code patterns:
   - Access-Control-Allow-Origin: *  (HTTP header)
   - cors = * / allow_origin(*) / origin: * / allowed_origins = *
   - Method calls like .allow_origin(*) now matched via [=:(] delimiter

2. Skip non-code files (.md, .txt, .rst, .adoc, .tex, .org, etc.)
   Security patterns are designed for source code, not prose.

3. Post-match negation context filter:
   Suppresses matches in negation contexts like 'no wildcard',
   'do not use *', 'without wildcard', and env var name patterns
   (cors_origins, cors_allowed, cors_config).

Tests: 25 new test cases covering true positives, false positives from
issue #483, doc file detection, and negation context suppression.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
Fix three unsafe byte-slice operations that panic when the slice boundary
falls inside a multi-byte UTF-8 codepoint:

1. build_commit_prompt() — &diff[..max_chars] in commit_cmd.rs
2. mask_secret() — &s[..4] and &s[s.len()-4..] in secrets_scanner.rs
3. parse_commit_message() — &subject[..69] in commit_cmd.rs

All three now use is_char_boundary() to floor the index, matching the
existing safe pattern in static_analysis.rs.

Added 4 regression tests covering emoji and multi-byte chars at slice
boundaries. All 786 tests pass.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…filter edge cases (#488, #489) (#491)

Rewrote CORS regex with 10 framework pattern alternatives using (?ix)
extended mode: HTTP header, generic assignment, Django, Spring Boot,
.NET, tower-http, Express, FastAPI, nginx, actix-web.

Also fixes:
- Removed unsupported lookahead (?!\w) — Rust regex crate limitation
- Negation filter skips suppression when comment has code indicators
- cors_config suppression scoped to env::var() reads only
- Pre-compiled negation regexes with LazyLock
- is_doc_file() checks for dot before extracting extension

Tests: 836 pass, 0 fail, 0 clippy warnings, fmt clean.
Closes #488, closes #489.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…#485, #486, #490) (#492)

sql-concat: require SQL keyword inside string literal + post-match
filter for comments/docstrings. Regex now needs a quote char before
the + to qualify as SQL injection.

debug-enabled: remove bare --debug from regex (too many false positives
on CLI flags, Dockerfiles, argument parsers). Keep DEBUG = True and
debug: true assignments. Add post-match filter for comment lines,
argument parser definitions, and env var references.

hardcoded-role: add quoted patterns ("admin", 'admin'), strict
equality (===), property access (user.role), and superuser to the
regex. Now covers JS, TS, Python, Go patterns.

Tests: 854 pass (18 new), 0 clippy warnings, fmt clean.
Closes #485, closes #486, closes #490.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
) (#493)

Add defense-in-depth post-match false-positive filters for the 3
remaining security scanner rules without them:

- injection/eval: suppress comments, docstrings, 'evaluate' (not eval),
  ast.literal_eval (safe)
- crypto/weak-hash: suppress comments, docstrings, import/use statements,
  type annotations
- crypto/ssl-verify-disabled: suppress comments, docstrings, env var
  references, schema definitions, negation patterns

This completes epic #487 — all 11 security patterns now have
defense-in-depth coverage (narrow regex + post-match filter + doc skip).

18 new tests covering both detection and suppression for each rule.

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
Extract config read/write/merge logic from install.rs into a standalone
agent_config module with comprehensive edge-case handling.

Changes:
- New src/commands/agent_config.rs module
- String-aware JSONC comment stripping (state machine, not regex)
- String-aware trailing comma removal (state machine)
- BOM (UTF-8/16) stripping for cross-platform configs
- Public API: read/write/add/remove for JSON, JSONC, YAML formats
- Format-agnostic dispatch: read_config(), write_config()
- Refactored install.rs to delegate to agent_config (removed duplication)
- 21 unit tests covering all edge cases

Closes #432

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…#495)

Add uninstall mode and post-install validation to cora install:

- `cora install --remove`: removes cora MCP entry from all detected agents
- `cora install --validate`: validates config files parse correctly after
  install/remove (JSON/JSONC only, YAML skipped)
- Multi-agent config validation with error reporting
- Uninstall works for both JSON/JSONC and YAML format agents
- Updated MCP tools.rs to include new fields

Closes #430

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…496)

Add standalone file-system watcher that auto-reindexes on change:

- `cora watch` command with debounce, --git-only, --filter glob
- Poll-based change detection (no new dependency needed)
- Skips hidden dirs, node_modules, target
- Initial full index then incremental reindex on detected changes
- 5 unit tests covering walk, detect, git-only, glob filter

Closes #436

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…#497)

- TypeScript: extract extends (Inherits) and implements (Implements) from class_heritage
- PHP: extract base_clause (Inherits) and class_interface_clause (Implements)
- Scala: extract extends_clause base (Inherits) and with_clause traits (Implements)
- Add first_type_identifier() helper for walking extends/implements clauses
- Extend node_name() to handle PHP name/qualified_name node kinds
- Add 6 test cases covering all new edge extractions

Closes #437

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
'cora watch' was opening a project-local SQLite database at
.cora/index.db without running schema migrations, causing a crash
('no such table: projects') on any project that had not been indexed
before.

Fix: use index::open_global_index() (which runs migrations) instead
of manually opening a project-local DB. Also resolve project root
via index::resolve_project_root() for consistency with other commands,
and expand the file-extension filter to cover all tree-sitter supported
languages (php, scala, cs, kt, svelte, jsx, tsx).

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…ing (#501)

- Add BrainConfig to .cora.yaml with brain.embedding mode (auto|hashing|pretrained)
- Refactor embed dispatch from compile-time to runtime via resolve_backend()
- Migration v7: add embed_fingerprint column to symbols table
- Incremental embedding: only re-embed symbols whose name+signature changed
- Wire resolve_backend() in cora index, cora brain, cora watch commands

Closes #499

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
@ajianaz ajianaz closed this Aug 5, 2026
@ajianaz ajianaz reopened this Aug 5, 2026
@ajianaz ajianaz closed this Aug 5, 2026
@ajianaz ajianaz reopened this Aug 5, 2026
@ajianaz
ajianaz merged commit 278c8ad into main Aug 5, 2026
39 of 45 checks passed
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