Files
IronStorage/AGENTS.md
Chili Palmer a3da9fda69
Some checks failed
Dependency security audit / rustsec (push) Has been cancelled
Complete SSH transport release audit (#118)
2026-08-25 22:07:47 +02:00

4.3 KiB

Repository instructions

Architecture boundary

crates/storage owns all password-store behavior and all objects stored in or derived from a password-store repository. This includes filesystem layout, .gpg-id handling, GPG-compatible encryption and key handling, Git, synchronization, conflict handling, entry parsing, password generation, OTP, QR payloads, server/application identities, HTTPS Git credentials, and secure-secret-storage orchestration. Git remotes are typed HTTPS or optional SSH endpoints; reject local, helper, executable, and unknown transports before entering Git transport code. Builds without the ssh feature must still parse SSH endpoints and return a typed unsupported-transport error before connection or repository mutation.

The SSH feature must keep its algorithm allowlist, strict known-host checking, single configured identity, bounded channel/diagnostic limits, and ambiguous push outcome rules in crates/storage. Do not add OpenSSH configuration, proxy commands, password or keyboard-interactive authentication, host-key bypasses, or frontend transport policy.

The CLI, Ratatui, Iced, Swift, SwiftUI, AutoFill, and watchOS code may collect input, invoke the Rust API, and present Rust-provided state. They must not duplicate storage rules, derive domain state from display strings, or directly read or mutate a password-store repository.

Application code must not launch external processes. Do not invoke pass, git, gpg, shell commands, or helper executables. Use pure Rust libraries. Use FFI only where an operating-system API has no feasible Rust interface, such as Apple authentication and secure-storage APIs; keep domain decisions in crates/storage.

Keep project crates free of unsafe Rust. Isolate any unavoidable future FFI implementation in the smallest platform-specific module and document its safety contract.

Compatibility

Compatibility means the upstream pass repository format and observable behavior, including pass-otp; IronStorage must not introduce a competing on-disk format. Prove new behavior with fixtures usable by both upstream tools and crates/storage without executing those tools at application runtime.

Required checks

Run these from the repository root before committing:

cargo fmt --all -- --check
RUSTFLAGS="-D warnings" cargo check --workspace --all-targets
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

For Apple project changes, also run xcodegen generate from apple/ and build the affected simulator targets.

Updating the Simulator app

Treat the booted simulator and its app container as persistent test state. To update IronStorage, build for that simulator and install the new .app over the existing installation with xcrun simctl install <device-udid> <app-path>. Keep the same device UDID and bundle identifier.

Do not uninstall IronStorage, erase or recreate the simulator, reset its keychain, install app-data packages, or delete its app container during an app update. Those are destructive reset operations, not update steps, and can remove preferences, repositories, credentials, and biometric enrollment state.

Simulator biometric validation

For initial setup only, select Features > Face ID > Enrolled before enabling Biometric Unlock in the iPhone app. The user must then enable Biometric Unlock and enter the GPG passphrase once so the protected passphrase is enrolled.

For normal validation, do not toggle Enrolled again. Tap the entry's Unlock control first so an authentication request is active, then select Features > Face ID > Matching Face and verify the app changes from locked to unlocked. A matching face presented before Unlock does nothing. Use Non-matching Face to test rejection without changing enrollment.

Apple's biometryCurrentSet access control invalidates a protected Keychain item when Face ID is re-enrolled. Clearing or toggling Enrolled is therefore a destructive negative test, not part of the normal unlock sequence. Only do it when the issue explicitly requires changed-enrollment coverage and the user is available to enter the GPG passphrase again. When deliberately returning to a manual baseline, disable Biometric Unlock in IronStorage while the protected record is still valid, then clear Enrolled.