Repository navigation
release: v0.20.0 - #710
Merged
Merged
release: v0.20.0#710
Conversation
## What Raise `timeout-minutes` of the Cora Review job from 10 to 30. ## Why The review action allows up to three LLM attempts of 600 s each, but the job was cancelled at 10 minutes. Medium sized PRs (about 850 added lines) were cancelled four times in a row (PRs for #674) although the same review finishes locally in about 5 minutes with no findings. Cancelled runs leave the required check red without any result. ## Testing - Config-only change; the job runs on this PR. - Local `cora review --base develop` on the affected diff passed. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
) ## What Part 1 of 3 for #674 (split from #675 so each PR fits the review time limit). - `engine/commit_gate.rs`: change-set fingerprint, marker store under the git dir, `check`, and a fail-closed parser for agent `git commit` command lines. - `cora hook verify` (exit 0 validated, 10 blocking, 11 not validated) and `cora hook claude-guard` (Claude Code PreToolUse). - `cora review --staged` and `cora.review_finalize` record a verdict marker for the exact staged diff. ## Why Agents should always run the judge review before committing; the verdict must be bound to the exact change set. Part of #674. Follow-ups: part 2 (pre-commit hook v2 and e2e tests), part 3 (skill, docs, changelog). ## Testing - Unit tests for fingerprinting, marker store, bypass parsing (`--no-verify` prefixes, `-c core.hooksPath`, chained commands, pathspecs). - fmt, clippy `-D warnings` and the full test suite pass locally. --------- Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…in place (#688) ## What Part 2 of 3 for #674 (part 1 is #676). - Hook template v2: `cora hook verify --quiet` first (0 pass, 10 deny), then the fallback `cora review --staged --ci --severity major`; a tooling error is reported as not a pass. - `cora hook install` recognises legacy v1 hooks and upgrades them in place instead of wrapping them a second time. - 12 end-to-end tests with real temporary git repos (agent verdict through MCP, hook, guard, upgrade). ## Why The hook is the fallback when the agent judge was not used, and must not re-review a diff that was already validated. Part of #674. ## Testing - Unit tests for the template and legacy detection. - tests/commit_gate.rs: 12 e2e tests, all passing; fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What Part 3 of 3 for #674 (parts 1 and 2: #676, #688). - `/cora-review` skill: review the staged diff before every commit. - `docs/usage.md`: the three-layer commit gate and the Claude Code guard snippet. - `docs/cli-reference.md`: `cora hook verify` and `cora hook claude-guard`. - CHANGELOG entry. ## Why Agents need to know to review before committing, and users need the setup steps. Closes #674. ## Testing - Docs and skill text only; the skill is embedded in the binary, so the build and full test suite were run (pass). Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
… secrets (#690) ## What - `scripts/hooks/pre-commit` and `scripts/setup-hooks.sh` (`core.hooksPath`): fmt, clippy when Rust files are staged, then `cora hook verify` with `cora review --staged --ci --severity major` as fallback. - `cora-review.yml`: the secret guard now errors with the name of each empty secret among CORA_API_KEY, CORA_BASE_URL and CORA_MODEL. - AGENTS.md: a before-committing line; CHANGELOG entry. ## Why Uses the commit gate from #674 in this repository, and makes sure a Cora Review without its secrets can never pass silently. ## Testing - bash -n on the hook, workflow YAML parses, local review passes. - The secret guard runs on this PR (secrets are set, so it must pass). Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…run (#691) ## What - `Config::validate` (so config load and `cora config validate`) now rejects an invalid regex, an empty or duplicate id, an id shadowing a built-in rule, an empty message, an empty `languages` list and unknown `languages` values, naming the rule. - `languages` accepts language names (`rust`) as well as extensions (`rs`); `languages` and `exclude` are optional. - `cora config validate --dry-run [--path DIR]` runs each custom rule over the project and prints how many lines it matched (0 matches is flagged). - `docs/configuration.md` shows the real schema (`rules_engine.custom`, the free-text `rules:` list, required fields); the 0.19.0 changelog line says `custom`. ## Why A mistyped pattern or language made a rule silently inactive while `config validate` said valid. Closes #684, closes #678. ## Testing - Unit tests for validation, language normalisation and optional YAML fields. - 4 end-to-end tests in tests/custom_rules.rs (invalid regex fails validation, docs example loads and fires, unknown language, dry run flags a silent rule). - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…d a reason separator (#692) ## What - A `cora-ignore` marker on a line that has findings but names none of them (typo, unknown rule, or explanation text that became part of the rule name) now prints a warning on stderr with the marker location, what it named and the rule ids on that line. - ` -- ` ends the rule list: `cora-ignore: sec-hardcoded-secret -- env var name` suppresses the finding and keeps the reason in the source. - Docs (Inline Suppression) and CHANGELOG updated. ## Why A suppression that silently does nothing makes people widen `ignore.rules` instead. Closes #679. Not done: warning about stale markers on clean lines (too noisy for diff reviews where only part of the file is visible); JSON/SARIF reporting of unmatched markers and a `--strict-markers` flag can follow. ## Testing - Unit tests: separator, trailing text, unknown rule, matching markers and clean-line markers not reported. - 3 end-to-end tests in tests/inline_ignore.rs reproducing the issue (warning, finding kept; separator suppresses). - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What Remove the CLA gate from this repo: delete `.github/workflows/cla-check.yml`, and replace the CLA section in CONTRIBUTING.md with a single inbound=outbound license paragraph. (README CLA badge removed if present.) ## Why Fleet CLA retirement — owner decision 2026-10-22, tracked in codecoradev/uteke#1548. CLA's only real function (future relicensing of third-party contributions) is ~zero-value here (2 external contributors / 3 commits org-wide, ever); Apache-2.0 inbound=outbound legally suffices for our open-core model (hosted-service monetization is lawful without a CLA); CLA-free matches the repos we benchmark against and removes contributor friction. Re-introduction, if ever needed, is prospective-only. ## Testing - `git show --stat HEAD` shows only the CLA-related files changed - No other workflow touched (cora-review / lint / ci / release intact) - Branch CI green on this PR --------- Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What Dependency-audit fixes: lockfile refreshes + targeted minor updates for the vulnerable packages; transitive advisories with no compatible fix get a documented, dated audit-ignore (`.cargo/audit.toml`). ## Why Closes #695. The Security audit gates have been red on `develop` (pre-existing; isolated during the fleet CLA retirement, uteke#1548). This PR makes the gates honestly green. ## Testing - `cargo audit` before/after locally (advisory DB refreshed): remaining findings = none beyond the documented ignores - JS audits re-run locally; remaining lows documented (not gate-failing) - CI on this PR: all audit gates expected green Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…rs (#693) ## What - New optional input `batches_judged` on `cora.scan_finalize`; the batches are recomputed statelessly from the project, like `scan_prepare`. - Result fields: `coverage` (`complete`, `partial`, or `unverified` when not declared), `total_batches`, `batches_judged`, `files_judged`, `files_total`. - A partial run says `Judged 1/11 batches (3/23 files)` and `should_block` is null instead of false. Undeclared runs keep the boolean and are labelled unverified. - The `/cora-review` skill passes `batches_judged`; CHANGELOG updated. ## Why Judging one batch and finalizing read as a clean verdict for the whole directory. Closes #685. ## Testing - Unit tests: partial, complete (dedupe, out-of-range ignored), unverified, and `scan_finalize` end to end. - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…riant expect (#698) ## What - `bug-todo`: only an upper-case `TODO`, `FIXME`, `HACK` or `XXX` whole word inside a comment. `pub mod todo;`, `todo_state` and prose like "the todo list" are no longer flagged. - `bug-println`: no longer matches `eprintln!` / `eprint!`; `println!`, `print!` and `dbg!` are still flagged. - `bug-expect`: flags only `.expect("")`; a non-empty message states an invariant. `bug-unwrap` still covers bare `unwrap()`. ## Why 22 of 22 `bug-todo` hits and all library `bug-println` hits on a real workspace were false positives (#681, #682). Closes #681. Refs #682: treating the modules of a binary crate as program code is not done here and stays open. ## Testing - Regression tests for the issue repros: identifier, module name, prose, lower-case, and the real markers; stdout vs stderr macros; `expect` with and without a message. - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…the stored key (#700) ## What - The Cora Review job exchanges its GitHub OIDC token for a short-lived Anthropic access token when the four federation identifiers (`ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID`, `ANTHROPIC_WORKSPACE_ID`) are available as organization or repository secrets or variables. Model: `ANTHROPIC_MODEL`, default `claude-opus-5-5`. - With a federation token, API key, base URL and model switch together: the token is only ever sent to `https://api.anthropic.com/v1`, never to `CORA_BASE_URL`. - Without one (variables missing, or the exchange fails: it is only a warning) the job uses `CORA_API_KEY`, `CORA_BASE_URL` and `CORA_MODEL` as before, and the guard still fails with an error naming a missing secret. - `id-token: write` added to the job permissions; docs (`docs/examples.md`) and CHANGELOG updated. ## Why A stored API key can leak and does not expire; the exchanged token lives for one job. The exchange and a Bearer call to `/v1/chat/completions` (the way cora sends its key) were verified by the smoke test in the previous PR. ## Testing - The smoke workflow passed: token exchange HTTP 200, `/v1/chat/completions` with Bearer HTTP 200. - Not testable in this PR: the Cora Review job runs from the base branch for `pull_request_target`, so this change takes effect on the next PR after merge. The fallback keeps the required check working if the exchange fails there (the subject for `pull_request_target` may differ from `pull_request`). Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What A workflow that runs when it changes and checks, without printing any token: 1. GitHub OIDC token for audience `https://api.anthropic.com`; 2. exchange for a short-lived Anthropic access token (`/v1/oauth/token`, federation); 3. one tiny call to `/v1/chat/completions` with `Authorization: Bearer <token>`, exactly how cora sends its key. The four identifiers come from repository variables (`ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID`, `ANTHROPIC_WORKSPACE_ID`) because this repository is public. ## Why Before moving the Cora Review job from a stored API key to workload identity federation, we need to know the exchanged token is accepted on the endpoint cora uses. ## Testing - The job runs on this PR (it needs the repository variables to be set first, otherwise it fails with a message naming the missing one). --------- Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What - A 400 response that names `temperature` is retried once without that key, and the model is remembered for the rest of the process (no repeated failing request, and no extra cost on later chunks). Streaming and non-streaming share the same path. - Any other 400 (and every other status) is returned unchanged; providers that accept `temperature` keep the configured value (default `0.0`, deterministic). ## Why `claude-opus-5-5` answers HTTP 400 "`temperature` is deprecated for this model", so every review through the Anthropic workload identity federation path (#700) ended as "Review could not complete" while the check still turned green. Closes #701. ## Testing - Unit tests: request body without a `temperature` key, recognising the 400, per-model memory. - Two end-to-end tests against a local fake server: the first request carries `temperature`, the retry does not and succeeds; a different 400 is not retried (one request only). - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…indings in review_prepare (#703) ## What - `crypto/hardcoded-secret`: the value after a single `:` can no longer start with another `:`, so `CancelToken::default()`, `Token::from_parts(..)` and `ApiKey::generate_random()` (paths) are not read as `token: <value>`. Real cases (`password = "..."`, `token: "..."`, JSON `api_key`) are still flagged. - `cora.review_prepare` runs the same post-processing as `review_finalize` on `deterministic_findings` (`ignore.rules`, inline `cora-ignore` markers, context filter), without the findings cap (the note still explains it), so the agent no longer sees and fixes a finding that finalize would drop. ## Why A project had to silence the rule by title, which hid real secrets too, and an agent changed code to avoid a finding the repository already ignored (#697). ## Testing - Regression test for type paths versus real secrets in the scanner. - Test that an ignored finding is not listed by prepare. - fmt, clippy -D warnings and the full suite pass. Closes #697. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…--help (#704) ## What `--help` no longer prints the values of `CORA_BASE_URL`, `CORA_MODEL` and `CORA_PROVIDER` (clap `hide_env_values`), like the API key and GitHub token already. ## Why A base URL can carry credentials (`user:pass@host`, `?key=...`) and the other two name internal deployments; `--help` output ends up in logs, CI output and screenshots. Closes #687. ## Testing - New test: `CORA_BASE_URL=https://u:pass@gateway.internal/v1?key=...`, `CORA_MODEL` and `CORA_PROVIDER` never appear in `--help`, `review --help` or `scan --help`. - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…mary (#705) ## What - `qual-clone` (`.clone()` in Rust, info) is opt-in: `rules_engine.clone_hints: true` turns it on. A default scan of a Rust project no longer lists `Arc::clone`-style sites. - New `cora scan --min-severity <info|minor|major|critical>`: hides lower findings in every output format and in the count. Blocking is unchanged (still `hook.min_severity`). - The scan summary (pretty and JSON output) counts by severity: `found 457 issues (1 critical, 150 minor, 306 info)`. - Docs (`cli-reference`, `configuration`) and CHANGELOG updated. ## Why On a 133-file Rust workspace 306 of 457 findings were `qual-clone` info; the count hid the one critical finding and the `max_findings` cap spent its slots on noise. Closes #683. ## Testing - Unit test: `qual_clone_is_opt_in` (off by default, on with `clone_hints`). - 3 end-to-end tests in tests/scan_noise.rs: no clone sites by default, the JSON summary counts by severity, `--min-severity major` hides minor findings. - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
## What
`ignore.rules` entries can now be objects, backwards compatible with
plain strings:
```yaml
ignore:
rules:
- "Hardcoded password or secret" # whole project, unchanged
- rule: bug-println
files: ["crates/cli/**", "evals/**"] # only these paths
reason: "stdout is the cli interface" # optional, documentation
```
- `rule` is matched like a plain entry (rule id or title fragment);
`files` uses the `ignore.files` glob syntax.
- Applied in `review`, `scan` and the MCP tools, before the
`max_findings` cap.
- An empty `files` list (or an empty `rule`) is a config error instead
of a rule that applies nowhere.
- Docs (`configuration.md`, new section) and CHANGELOG updated.
## Why
A rule can be noise in one crate and a real design guard in another
(`bug-println` in a CLI vs an embedder-safe core); today the only
options are silencing it everywhere or excluding directories from every
check. Closes #680.
## Testing
- Unit tests: a scoped rule is silenced only under its globs, plain
strings still silence everywhere, `**/file.rs` globs.
- Config tests: YAML with strings and scoped objects (with `reason`)
loads; empty `files` fails validation.
- 2 end-to-end tests (tests/scoped_ignore.rs): silenced in `crates/cli`,
still fires in `crates/core`; plain form unchanged.
- fmt, clippy -D warnings and the full suite pass.
Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…de for bug-println (#707) ## What `bug-println` now exempts every module of a binary-only package (a `src/main.rs` and no `src/lib.rs` in the same package), not just `main.rs`, `src/bin/`, `examples/` and `benches/`. A library package, or one that has both `main.rs` and `lib.rs`, keeps the rule. The package is looked up relative to the scan root (`cora scan --path`, the MCP scan tools) or, for a diff review, the git toplevel, never the process working directory (found by the pre-commit review of this change). ## Why In a binary crate stdout is the program's interface, yet its non-entry modules still produced 64 `bug-println` hits on a real workspace, while a core crate must keep guarding against writing to stdout. The `eprintln!` and `expect("...")` halves of #682 shipped earlier; this is the remaining part. Closes #682. ## Testing - Unit test with a temporary package layout: binary-only module exempt, library module flagged, lib+bin package keeps the rule, entry points and `examples/` exempt, unknown package flagged. - End-to-end tests (tests/binary_crate_println.rs): `println!` in `crates/cli/src/commands.rs` is not reported, in `crates/core/src/lib.rs` it is, `eprintln!` never is; the same holds for `cora scan --path proj` run from the parent directory. - fmt, clippy -D warnings and the full suite pass. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…ning data (#686) (#709) ## What Implements #686 for the MCP agent-as-reviewer scan tools: - `cora.scan_prepare` + `cora.scan_finalize` now accept the CLI's selection inputs: `include` (globs), `exclude` (globs, merged with `config.ignore.files`), `extensions`, `incremental` (same cache as `cora scan --incremental`), `changed_since` (git rev — files changed since it, untracked included), and `order` (`source-first` default | `path` legacy walk order). - `source-first` ordering: code extensions first, then shallower paths, then path — deterministic. - Every prepare response carries planning data: `total_chars`, `estimated_tokens` (`total_chars/4`), per-batch `files` + `chars`, plus the effective `order`/`include`/`exclude`. - Finalize consistency: both tools go through one `scan_selection()` + `scan_files_for()`; `files_fingerprint` still guards — different filters/order refuse with "project files changed". `incremental` finalize depends on the cache not changing between calls. - `changed_since` implementation: `git diff --name-only --relative <rev>` + untracked files, filtered into the walked set; revs starting with `-` are rejected. ## Why Issue #686: agent mode on a real workspace was unusable — no way to narrow scope beyond `path`, path-ordered batches put core sources last, and no size/token estimate before committing to hundreds of thousands of tokens. ## Testing - TDD: 5 of 6 new tests RED on the old code, all GREEN after (26/26 agent_tools tests). - Full suite: `cargo test --features tree-sitter` = 1312 passed, 0 failed (independently re-verified by CTO: 10/10 suites ok). - Gates: fmt clean; clippy `--all-targets --features tree-sitter -D warnings` clean (CTO re-ran); pre-commit hook (fmt+clippy+cora code review) passed at commit. - Done-when check from the issue: `scan_prepare {"include": ["crates/**/*.rs"], "exclude": ["**/tests/**"]}` returns only matching files, reports estimated totals, orders sources first — covered by `include_exclude_filter_and_planning_data_is_reported` against a fixture. Fixes #686 Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
- Bump version 0.19.0 -> 0.20.0 (Cargo.toml, Cargo.lock) - CHANGELOG: [Unreleased] -> [0.20.0] - 2026-10-27 (14 entries): Anthropic workload identity federation + smoke test, commit gate (hook v2, claude-guard, validate-before-commit marker), path-scoped ignore.rules, temperature retry (#701), secret redaction in --help (#687), review_prepare parity and Token::default() fix (#697), scan clone hints/--min-severity/summary (#683), scan_finalize coverage report (#685), rule idiom fixes (#681/#682), custom rule validation (#684), cora-ignore warnings (#679), CI fixes
ajianaz
force-pushed
the
release/v0.20.0
branch
from
October 27, 2026 16:46
da8249f to
34ff4a8
Compare
ajianaz
added a commit
that referenced
this pull request
Oct 28, 2026
…lop (#711) ## What Brings the v0.20.0 release bump back into `develop`: `Cargo.toml` / `Cargo.lock` 0.19.0 -> 0.20.0 and the CHANGELOG `[Unreleased]` entries moved under `[0.20.0] - 2026-10-27`, exactly as on `main` (after this PR the `develop` tree equals `main`). ## Why The release (#710) bumped the version and cut the changelog on `main` only. `develop` still said 0.19.0 and kept every shipped entry under `[Unreleased]`, so the next release would have repeated them. ## Testing - `git diff origin/main` on this branch is empty. - `cargo build`; `cora --version` prints 0.20.0. No code change. Signed-off-by: ajianaz <ajianaz@users.noreply.github.com> Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
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.
What
Release v0.20.0: version bump and CHANGELOG.
Why
Ships everything merged to develop since v0.19.0: path-scoped ignore.rules, commit gate (hook v2 + claude-guard), Anthropic workload identity federation for Cora Review, temperature-retry for models that reject it, scan_finalize coverage report, quieter scan (clone hints opt-in, --min-severity), custom-rule validation, rule false-positive fixes, --help secret redaction, dependency-audit fixes.
Changes
Testing
fmt, clippy (-D warnings) clean; cargo test --features tree-sitter: 1367 passed, 0 failed.