rsecure 0.8.0

A simple file encryption and decryption tool using AES-GCM.
# AGENTS.md

Context for any AI coding agent working in this repo (Claude Code, OpenCode, Cursor,
Codex, Aider, Zed, …). Keep this file short and authoritative — anything that grows
beyond a quick reference belongs in a dedicated doc and should be linked from here.

## Project

`rsecure` is a small Rust CLI for file encryption using AES-256-GCM via the
[`aes-gcm`](https://crates.io/crates/aes-gcm) crate. It encrypts and decrypts files
or directories in 128 KiB chunks using STREAM (`EncryptorBE32`), parallelized with
`rayon` and shown via `indicatif` progress bars. CLI parsing is `clap` derive.

The master key comes from one of two sources:

- a 32-byte key file (`-p` flag), or
- a passphrase (`--passphrase` flag) run through [Argon2id]https://crates.io/crates/argon2.
  Argon2 cost parameters can be tuned via `--argon2-memory`, `--argon2-time`, and
  `--argon2-parallelism`; the chosen values are stored in the file header so
  decryption is transparent. Passphrases, master keys, and derived subkeys are
  wrapped in [`zeroize`]https://crates.io/crates/zeroize guards.

In both modes, the master key feeds [HKDF-SHA256](https://crates.io/crates/hkdf) to
derive a unique per-file AES-256 subkey, so the `(key, nonce)` pair is globally
unique across files. The on-disk file header is bound as AAD on every chunk —
tampering with magic, version, flags, chunk_size, or salt invalidates the first
GCM tag. The format is versioned: v1 (rsecure ≤ 0.5.0, legacy decrypt-only),
v2 (interim HKDF-only), v3 (current, with flags byte for keyfile vs passphrase).
See `SECURITY.md` and `src/format.rs` for the wire layout.

Source layout:

- `src/main.rs` — entry point, forbids `unsafe` crate-wide.
- `src/cli/``clap` argument definitions.
- `src/commands/` — one module per subcommand (`create_key`, `encrypt_file`, `decrypt_file`).
- `src/format.rs` — on-disk file format constants, `Header` enum, parser, and v3 header builders. Single source of truth for the wire layout.
- `src/crypto.rs` — KDF helpers: `derive_subkey_v2/v3` (HKDF-SHA256) and `derive_master_key_argon2`.
- `src/file_ops.rs` — keyfile I/O and the `prompt_passphrase` TTY/stdin helper.
- `src/utils.rs` — small `is_file` / `is_dir` shared helpers.
- `tests/cli.rs` — integration tests via `assert_cmd` + `predicates`.

## Setup & common commands

Rust toolchain is pinned via `rust-toolchain.toml` (currently 1.96.0). Use the
`Makefile` targets when possible — they match what CI runs.

```bash
make test         # cargo nextest run
make lint         # cargo clippy -- -D warnings
make fmt          # cargo fmt --all
make ci           # fmt + lint + test (run before pushing)
make build        # debug build
make release      # release build
```

Run a single test: `cargo nextest run -E 'test(/<name>/)'`.

## Conventions

- **Commits**: Conventional Commits, enforced by [cocogitto]https://docs.cocogitto.io/.
  Use `cog commit <type> "<msg>" [scope]` rather than `git commit -m`. Common types:
  `feat`, `fix`, `chore`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`.
- **No `unsafe`** in `rsecure` itself — `src/main.rs` declares `#![forbid(unsafe_code)]`.
  Dependencies may use unsafe; that is acceptable.
- **Auto-push**: a `post-commit` git hook pushes every commit to `origin/main`. Do not
  `git commit` work-in-progress to `main` — branch first.
- **Pre-commit hook** (`pre-commit.sh`) runs `pre-commit run -a`, `cargo nextest run`,
  `cargo fmt`, and `cargo check`. If a hook fails, fix the underlying issue and create
  a NEW commit — do not bypass with `--no-verify`.
- **Documentation hygiene**: every code change must be accompanied by a sweep of the
  doc surface. Before declaring a task done or shipping a release, review
  `README.md`, `SECURITY.md`, `AGENTS.md`, anything in `docs/`, and the relevant
  `.claude/skills/**/SKILL.md`, and update whatever has drifted. Update docs in the
  same commit as the code when feasible, or as an immediate follow-up. `CHANGELOG.md`
  is regenerated by `cog changelog` and must not be edited by hand.
- **Codebase-memory index hygiene**: whenever code or another important part of the
  repo changes (source under `src/`, `tests/`, `Cargo.toml` deps, `cog.toml`,
  `.github/workflows/`, `AGENTS.md`, `SECURITY.md`, or the file format), re-index
  the project into `codebase-memory` so future graph/trace queries stay accurate.
  Run `mcp__codebase-memory-mcp__index_repository` on the current working directory
  after the change lands (or `detect_changes` first if you want to confirm drift).
  Do this as a persistent habit — do not wait to be asked. When the call flow
  itself changes (new functions/subcommands, or a refactor of the encrypt/decrypt
  path), also regenerate the diagrams in [`docs/architecture.md`]docs/architecture.md
  from the graph (`trace_path`/`search_graph`) rather than hand-editing the Mermaid.

## Releases

A new version is cut with the [release skill](.claude/skills/release/SKILL.md) — invoke
it via "release" / "bump version" in Claude Code, or follow the steps manually. In short:

```bash
cog bump --version X.Y.Z
```

`cog.toml`'s `pre_bump_hooks` update `Cargo.toml` (via `cargo set-version`), refresh
`Cargo.lock`, regenerate `CHANGELOG.md`, and create a tagged bump commit. The
`post_bump_hook` pushes the tag. The `Cargo.toml` version and the latest git tag
MUST stay in sync — verify before and after.

Required local tools: `cog` (cocogitto 7+) and `cargo-set-version` (from `cargo-edit`).

## CI

`.github/workflows/ci-cd.yml` runs on PRs, pushes to `main`/`dependabot/*`, and tag
pushes. Jobs: `security` (cargo-audit + cargo-deny), `linting` (fmt + check), `test`
(`cargo test`), `build` (cross-platform matrix), `goreleaser` and `publish-crate` on
tag. The `security` job also runs weekly on a cron to surface new advisories.

`cargo-deny` policy lives in `deny.toml` — keep advisories at `version = 2` and only
permissive licenses allowed.

## Security

This is a cryptographic tool. Read `SECURITY.md` before changing any code in
`src/commands/encrypt_file.rs`, `src/commands/decrypt_file.rs`,
`src/commands/create_key.rs`, `src/crypto.rs`, `src/format.rs`, or
`src/file_ops.rs`. The threat model and what `rsecure` does and does not guarantee
are documented there. Vulnerability reports go through GitHub Security Advisories —
never open a public issue for a security bug.

Format changes are also versioning changes: bump `VERSION_V3` (or define a new
constant) and extend `Header` rather than mutating the existing v3 layout, so
already-encrypted files remain decryptable.

## Things to avoid

- Do not introduce `unsafe` (`#![forbid(unsafe_code)]` will fail the build).
- Do not skip pre-commit hooks (`--no-verify`).
- Do not bump the version manually in `Cargo.toml` — use `cog bump`.
- Do not edit `CHANGELOG.md` by hand — it is regenerated by `cog changelog`.
- Do not commit credentials, key files, or `.enc` artifacts; the `.gitignore` covers
  the obvious cases but be aware when adding test fixtures.
- Do not commit scratch, review, or analysis files (e.g. `review.md`, `notes.md`,
  `plan.md`) that you produce as intermediate artifacts while working on a task.
  Keep them out of the repo — the scratchpad directory or a local ignored path is
  the right home. Before committing, `git status` the tree and drop anything that
  is not part of the actual change.