Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `cora config set --global` — write config to `~/.cora/config.yaml` instead of project `.cora.yaml`
- `cora config set base_url` — set base URL via CLI (previously only in YAML)
- Global config support (`~/.cora/config.yaml`) with priority chain: CLI flags → env vars → project → global → defaults
- Auto-migration from old `~/.cora/config.toml` to new YAML + `auth.toml` split

### Changed

- `cora config set` now writes YAML instead of TOML (compatible with config loader)
- API key storage moved from `~/.cora/config.toml` to `~/.cora/auth.toml` (0600 permissions)
- YAML serialization uses `skip_serializing_if` — no more `null` values in output

### Fixed

- **Severity comparison inverted** — `Critical` issues no longer silently pass `should_block` check (Ord ordering bug)
- Hook `mode: block` no longer exits with code 2 when "No issues found" (severity filter mismatch)
- Consistent severity logic across review, scan, and block mode paths

## [0.1.2] - 2025-05-29

### Added
Expand Down
43 changes: 30 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Be respectful, constructive, and inclusive. We follow the [Rust Code of Conduct]

### Prerequisites

- **Rust** 1.75+ (stable toolchain recommended)
- **Rust** 1.85+ (stable toolchain recommended)
- **Git** for version control
- An **LLM API key** (OpenAI, Anthropic, etc.) for testing review features

Expand All @@ -47,14 +47,30 @@ cargo clippy -- -D warnings
```
cora-cli/
├── src/
│ ├── main.rs # CLI entry point
│ ├── cli.rs # Argument parsing (clap)
│ ├── config.rs # Configuration management
│ ├── scanner.rs # File scanning and diff generation
│ ├── reviewer.rs # LLM integration for code review
│ ├── formatter.rs # Output formatting
│ └── ci.rs # CI/CD integration helpers
├── tests/ # Integration tests
│ ├── main.rs # CLI entry point + clap args
│ ├── cli.rs # Argument parsing (clap)
│ ├── commands/ # CLI subcommands
│ │ ├── review.rs # cora review
│ │ ├── scan.rs # cora scan
│ │ ├── config_cmd.rs # cora config show/set
│ │ ├── auth.rs # cora auth login/logout
│ │ └── init.rs # cora init
│ ├── config/
│ │ ├── loader.rs # Config resolution chain (global → project → env → CLI)
│ │ ├── schema.rs # YAML config structs + merge logic
│ │ └── providers.rs # Provider presets (OpenAI, Anthropic, etc.)
│ ├── engine/
│ │ ├── review.rs # LLM review + SARIF generation
│ │ ├── scanner.rs # File scanning and diff generation
│ │ ├── types.rs # Issue, Severity, ScanResponse types
│ │ └── llm.rs # LLM API abstraction
│ └── formatter/
│ └── mod.rs # Output formatting (pretty, compact, json, sarif)
├── .github/
│ ├── workflows/ # CI, release, deploy workflows
│ └── actions/
│ └── cora-review/ # Composite action for GitHub Actions
├── tests/ # Integration tests
├── Cargo.toml
└── README.md
```
Expand All @@ -68,7 +84,7 @@ cora-cli/
```
3. **Make your changes** and commit with meaningful messages:
```bash
git commit -s -m "feat: add support for SARIF output format"
git commit -m "feat: add support for SARIF output format"
```
4. **Push** to your fork and open a **Pull Request**

Expand Down Expand Up @@ -111,9 +127,10 @@ mod tests {
use super::*;

#[test]
fn test_scan_single_file() {
let result = scan_files(vec!["src/main.rs".into()]);
assert!(!result.is_empty());
fn test_severity_from_str() {
use crate::engine::types::Severity;
assert_eq!(Severity::from_str_lossy("critical"), Severity::Critical);
assert_eq!(Severity::from_str_lossy("info"), Severity::Info);
}
}
```
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 51 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,26 @@ cora scan --incremental

### `cora config`

Manage configuration.
Manage configuration. Supports both project-level (`.cora.yaml`) and global (`~/.cora/config.yaml`) config.

```bash
# Show current configuration
# Show current resolved configuration
cora config show

# Set a configuration value
# Set a project-level value (writes to .cora.yaml)
cora config set model claude-sonnet-4-20250514
cora config set base_url https://api.openai.com/v1
cora config set severity major

# Set a global value (writes to ~/.cora/config.yaml)
cora config set --global model gpt-4o-mini
cora config set --global provider anthropic

# Supported keys: model, provider, base_url, format, severity
```

**Priority**: CLI flags → env vars → `.cora.yaml` (project) → `~/.cora/config.yaml` (global) → defaults

### `cora init`

Create a `.cora.yaml` config file in the current directory.
Expand Down Expand Up @@ -207,7 +216,13 @@ cora hook uninstall

## ⚙️ Configuration

Create a `.cora.yaml` in your project root or `~/.config/cora/config.yaml` globally:
Cora reads configuration from multiple sources in priority order:

```
CLI flags → CORA_* env vars → .cora.yaml (project) → ~/.cora/config.yaml (global) → defaults
```

Create a `.cora.yaml` in your project root, or use `~/.cora/config.yaml` for global settings. Project config always overrides global.

```yaml
# .cora.yaml
Expand Down Expand Up @@ -265,37 +280,53 @@ output:
| `CORA_FORMAT` | Output format (`pretty`, `json`, `compact`, `sarif`) | `pretty` |
| `CORA_NO_COLOR` | Disable colored output | — |

### Authentication

API keys can be provided via environment variable (`CORA_API_KEY`), provider-specific env vars (`OPENAI_API_KEY`, etc.), or stored in `~/.cora/auth.toml` (auto-created by `cora auth login`, permission `0600`).

```bash
# Interactive login (stores key in ~/.cora/auth.toml)
cora auth login

# Or set via environment variable
export CORA_API_KEY=sk-...
```

## 🔗 CI/CD Integration

### GitHub Actions

```yaml
# .github/workflows/review.yml
name: Code Review
Using the official [cora-review composite action](.github/actions/cora-review):

```yaml
name: CI
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [develop]

jobs:
review:
cora-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: ./.github/actions/cora-review
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
infisical-identity-id: ${{ secrets.INFISICAL_IDENTITY_ID }}
severity: major
upload-sarif: 'true'
```

- name: Install cora-cli
run: |
VERSION=$(curl -s https://api.github.com/repos/ajianaz/cora-cli/releases/latest | grep tag_name | cut -d'"' -f4)
curl -L "https://github.com/ajianaz/cora-cli/releases/download/${VERSION}/cora-x86_64-unknown-linux-gnu-${VERSION}.tar.gz" | tar xz
sudo mv cora /usr/local/bin/

- name: Run code review
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: cora review --base origin/main --upload
Or install manually:

```yaml
# Manual install in CI
- name: Install cora-cli
run: |
curl -fsSL https://github.com/ajianaz/cora-cli/releases/latest/download/cora-x86_64-unknown-linux-gnu.tar.gz | tar xz
sudo mv cora /usr/local/bin/
```

### GitLab CI
Expand Down
166 changes: 166 additions & 0 deletions docs/CONFIG-REDESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Config System Redesign: Global + Project Config

## Status: Draft — Pending Approval

## Problem

Current `cora config set` writes to `~/.cora/config.toml` but the config loader only reads `.cora.yaml`. Values set via `config set` are silently ignored. Additionally, there's no way to set global defaults across all projects.

## Goal

Support both global and per-project configuration with clear priority:

```
CLI flags → CORA_* env vars → .cora.yaml (project) → ~/.cora/config.yaml (global) → Defaults
```

## Design

### Config Sources

| Source | Path | Format | Scope | Priority |
|--------|------|--------|-------|----------|
| **Global** | `~/.cora/config.yaml` | YAML | All projects | 4 (lowest, after env) |
| **Project** | `.cora.yaml` (walk parent dirs) | YAML | Current project | 3 |
| **Env vars** | `CORA_PROVIDER`, `CORA_MODEL`, `CORA_BASE_URL`, `CORA_API_KEY`, etc. | — | Current shell | 2 |
| **CLI flags** | `--provider`, `--model`, `--base-url`, etc. | — | Current command | 1 (highest) |

### Merge Strategy

Same as current `.cora.yaml` merge — global config is loaded first (into defaults), then project config overwrites any fields present. Each field is independently resolved.

Example:

**Global** (`~/.cora/config.yaml`):
```yaml
provider:
provider: openai
model: gpt-4o-mini
output:
format: compact
```

**Project** (`.cora.yaml`):
```yaml
provider:
model: glm-5.1
base_url: http://litellm:4000
hook:
mode: block
```

**Resolved:**
```yaml
provider:
provider: openai # from global
model: glm-5.1 # project overrides
base_url: http://litellm:4000 # project
output:
format: compact # from global
hook:
mode: block # from project
min_severity: major # default
```

### `cora config set` Redesign

```bash
# Default: write to project .cora.yaml (must be inside a git project)
cora config set model glm-5.1
cora config set base_url http://litellm:4000

# Explicit global
cora config set --global model gpt-4o-mini
cora config set --global provider openai

# All supported keys:
# model, provider, base_url, format, severity (maps to hook.min_severity)
```

Behavior:
- **No `--global`**: writes to `.cora.yaml` in current dir (creates if missing)
- **`--global`**: writes to `~/.cora/config.yaml` (creates if missing)
- **`--global --show`**: prints global config path + contents
- Works with the same TOML→YAML key mapping as before

### Auth File (Separate Concern)

API key storage stays separate at `~/.cora/auth.toml` (rename from `config.toml`):

- `cora auth login` → `~/.cora/auth.toml` (contains only `api_key`)
- `cora auth status` → reads from `~/.cora/auth.toml`
- `cora auth remove` → deletes `~/.cora/auth.toml`

This separation means:
- Config = `~/.cora/config.yaml` (global settings, no secrets)
- Auth = `~/.cora/auth.toml` (API key only, permissions 0o600)

### `cora config show` Enhancement

```bash
$ cora config show

╔══════════════════════════════════════════╗
║ Current Configuration ║
╚══════════════════════════════════════════╝

Config sources (priority ↓):
CLI flags —
Env vars —
Project config .cora.yaml ✅
Global config ~/.cora/config.yaml ✅

provider:
provider: openai (global)
model: glm-5.1 (project)
base_url: http://litellm:4000 (project)

focus:
security, performance, bugs (default)

hook:
mode: block (project)
min_severity: major (default)
max_diff_size: 51200 (default)

output:
format: compact (global)
color: true (default)
```

Each value shows its source — makes debugging config priority transparent.

## Files to Change

| File | Change |
|------|--------|
| `src/config/loader.rs` | Add `load_global_config()` → reads `~/.cora/config.yaml`. Update `load_config()` to merge: global → project → CLI. Rename `AUTH_FILENAME` to `auth.toml`. |
| `src/commands/config_cmd.rs` | Rewrite `execute_config_set()`: write YAML instead of TOML. Add `--global` flag support. Add `base_url` key. Keep `cora config show` but add source annotations. |
| `src/main.rs` | Add `--global` flag to `config set` subcommand. Add `config set base_url <value>`. |
| `src/config/schema.rs` | No changes needed — `CoraFile` schema already supports all fields. Global uses same `CoraFile` struct. |

## Migration

- **No breaking change** — existing `.cora.yaml` files work as-is
- `~/.cora/config.toml` (if exists) → auto-migrate to `~/.cora/config.yaml` on first run (read TOML, write YAML, delete TOML). For auth keys: rename `config.toml` → `auth.toml`
- `cora auth login` switches from writing `config.toml` to `auth.toml`

## Effort Estimate

| Item | LOC (est.) | Effort |
|------|-----------|--------|
| Global config loader | ~40 | 30 min |
| `config set` rewrite (YAML + `--global` + `base_url`) | ~80 | 1h |
| `config show` source annotations | ~40 | 30 min |
| Auth file rename (`config.toml` → `auth.toml`) | ~20 | 15 min |
| Migration logic (TOML → YAML) | ~30 | 30 min |
| Tests | ~60 | 45 min |
| **Total** | ~270 | **~3.5h** |

## Risks

| Risk | Mitigation |
|------|-----------|
| YAML serialization changes formatting | Use `serde_yaml_ng` with consistent output |
| Migration edge case (partial TOML) | Log warning, skip gracefully, user can manually edit |
| Two config sources confuse users | `config show` annotates source for each value |
Loading
Loading