Skip to content
Open
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
9 changes: 9 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## 2024-03-24 - Insecure Default File Permissions
**Vulnerability:** The CLI application creates sensitive configuration files and directories (like wallets and snapshot data) using standard `fs::create_dir_all` and `fs::write` in Rust. These standard functions create files/directories using the system's default umask, which typically allows other users on the same Unix-like system to read the sensitive files.
**Learning:** This could lead to a local privilege escalation or exposure of sensitive user data if the user runs the CLI on a shared machine. Relying on default system configurations for sensitive files is unsafe.
**Prevention:** Always use `std::os::unix::fs::DirBuilderExt` and `std::os::unix::fs::OpenOptionsExt` to explicitly set file permissions (e.g., `0o700` for directories and `0o600` for files) when creating sensitive data on disk.

## 2024-05-24 - Command Injection via Configured `bitcoin_cli` Binary
**Vulnerability:** The application allowed arbitrary command execution by reading the `bitcoin_cli` command to run from a user-provided profile configuration and executing it directly with `std::process::Command::new` without validating the binary name.
**Learning:** Profile configurations or configuration files can often be manipulated by users. Trusting arbitrary paths or commands specified in these files can lead to remote code execution (RCE) or local privilege escalation if the application is run with elevated privileges.
**Prevention:** Implement a strict whitelist on the binary name allowed to be executed when the binary path is sourced from user configuration or input. Always extract the base filename and compare it against the expected executable name (e.g., `bitcoin-cli` or `bitcoin-cli.exe`).
38 changes: 37 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,42 @@ All notable changes to this project will be documented in this file.

- No changes yet.

## [0.3.0] - 2026-03-27

### Changed
- Removed `quiet` mode from CLI surface and config plumbing:
- removed `--quiet` global flag,
- removed `ZINC_CLI_QUIET` env handling,
- removed persisted config key `quiet`,
- removed setup `--quiet-default`.
- Updated command contract/docs to reflect the current global flag set.
- Improved wallet/account config resolution and wallet-info consistency with effective runtime network/scheme values.
- Improved wallet-info recency presentation in human output.

### Fixed
- Fixed account-switch address preview paths to use receive index `0` consistently.
- Refined offer/PSBT input-source handling and stdin conflict validation.
- Updated dependency pin to `zinc-core = =0.1.2`.

## [0.2.1] - 2026-03-26

### Fixed
- Updated `zinc-core` dependency pin to `=0.1.1` for compatibility with current CLI features.
- Removed local `path` dependency override for release packaging so `cargo package`/`cargo publish` resolve from crates.io in CI.

## [0.2.0] - 2026-03-26

### Added
- ANSI logo asset and branded `version` command output.

### Changed
- `inscription list` now shows newest received inscriptions first.
- `offer` commands remain available via `zinc-cli offer ...` but are hidden from top-level help output.
- Improved human-output inscription thumbnail rendering fidelity in terminal-friendly output modes.

### Docs
- Aligned README/usage/contract/schema docs with the current CLI surface, including `--agent` output mode and thumbnail toggles (`--thumb`, `--no-thumb`).

## [0.1.1] - 2026-03-21

### Fixed
Expand All @@ -15,7 +51,7 @@ All notable changes to this project will be documented in this file.

### Added
- Initial standalone public packaging for `zinc-cli`.
- Human-friendly command output plus stable `--json` agent envelope.
- Human-friendly command output plus stable agent envelope.
- Wallet profile management with profile lock and atomic writes.
- PSBT create/analyze/sign/broadcast command family.
- Snapshot, account switching, and diagnostic command support.
Expand Down
46 changes: 22 additions & 24 deletions COMMAND_CONTRACT_V1.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,24 @@ This document defines the active `v1` command contract. It is additive with curr
## 1) Design Goals

1. One wallet engine and one command model for both humans and agents.
2. Stable machine-readable responses in `--json` mode.
2. Stable machine-readable responses in `--agent` mode.
3. Strict, typed error taxonomy for automation reliability.
4. Backward-compatible rollout from current `SCHEMAS.md` behavior.

## 2) Execution Profiles

1. Human profile
- CLI called without `--json`.
- Output may be user-friendly text.
- Default output mode (`ZINC_CLI_OUTPUT=human`).
- Output is a curated, styled, user-friendly presentation.

2. Agent profile
- CLI called with `--agent` (preferred) or `--json`.
- `--agent` implies `--json --quiet --ascii`.
- CLI called with `--agent` or `ZINC_CLI_OUTPUT=agent`.
- Exactly one JSON object on `stdout` per invocation.
- Non-JSON noise must not be printed to `stdout`.

## 3) Global Flags (Supported)

`--json`, `--agent`, `--quiet`, `--yes`, `--password`, `--password-env`, `--password-stdin`, `--reveal`, `--data-dir`, `--profile`, `--network`, `--scheme`, `--esplora-url`, `--ord-url`, `--ascii`, `--no-images`, `--correlation-id`, `--log-json`, `--idempotency-key`, `--network-timeout-secs`, `--network-retries`, `--policy-mode`
`--agent`, `--yes`, `--password`, `--password-env`, `--password-stdin`, `--reveal`, `--data-dir`, `--profile`, `--network`, `--scheme`, `--esplora-url`, `--ord-url`, `--ascii`, `--no-images`, `--thumb`, `--no-thumb`, `--correlation-id`, `--log-json`, `--idempotency-key`, `--network-timeout-secs`, `--network-retries`, `--policy-mode`

Global flags are supported both before and after command tokens.

Expand All @@ -38,6 +37,11 @@ Reliability defaults:
- `--network-retries` defaults to `0`.
- `--policy-mode` defaults to `warn`.

Human-output defaults:
- Thumbnails are enabled by default in human mode.
- `--no-thumb` or `--no-images` disables thumbnails.
- In `--agent` mode thumbnails are disabled by default unless `--thumb` is set.

## 4) JSON Envelope

## Success
Expand Down Expand Up @@ -117,7 +121,7 @@ Idempotency for mutating commands:

## 7) Command Contracts

All commands below describe `--json` response payloads.
All commands below describe `--agent` response payloads.

## 7.1 wallet init

Expand Down Expand Up @@ -333,37 +337,31 @@ Command:
`scenario mine [--blocks N] [--address <addr>]`

Success fields:
`action`, `blocks`, `address`, `raw`
`blocks`, `address`, `raw_output`

## 7.24 scenario fund

Command:
`scenario fund [--amount-btc <decimal>] [--address <addr>] [--mine-blocks N]`

Success fields:
`action`, `address`, `amount_btc`, `txid`, `mine_blocks`, `mine_address`, `generated_blocks`
`address`, `amount_btc`, `txid`, `mine_blocks`, `mine_address`, `generated_blocks`

## 7.25 scenario reset

Command:
`scenario reset [--remove-profile] [--remove-snapshots]`

Success fields:
`action`, `removed`
`removed`

## 7.26 doctor

Command:
`doctor`

Success fields:
`healthy`, `esplora`, `ord`

`esplora` shape:
`{ url: string, reachable: bool }`

`ord` shape:
`{ url: string, reachable: bool, indexing_height: u32 | null, error: string | null }`
`healthy`, `esplora_url`, `esplora_reachable`, `ord_url`, `ord_reachable`, `ord_indexing_height`, `ord_error`

## 7.27 offer create

Expand All @@ -376,47 +374,47 @@ Notes:
- `--seller-payout-address` overrides payout destination output while preserving seller input metadata from ord inscription output.

Success fields:
`inscription`, `seller_address`, `seller_outpoint`, `postage_sats`, `ask_sats`, `fee_rate_sat_vb`, `seller_input_index`, `buyer_input_count`, `psbt`, `offer`, `submitted_ord`, `ord_url`
`inscription`, `ask_sats`, `fee_rate_sat_vb`, `seller_address`, `seller_outpoint`, `seller_pubkey_hex`, `expires_at_unix`, `thumbnail_lines?`, `hide_inscription_ids`, `raw_response`

## 7.28 offer publish

Command:
`offer publish [--offer-json <json> | --offer-file <path> | --offer-stdin] --secret-key-hex <hex> --relay <url>... [--created-at-unix <unix>] [--timeout-ms N]`

Success fields:
`event`, `publish_results`, `accepted_relays`, `total_relays`
`event_id`, `accepted_relays`, `total_relays`, `publish_results`, `raw_response`

## 7.29 offer discover

Command:
`offer discover --relay <url>... [--limit N] [--timeout-ms N]`

Success fields:
`events`, `offers`, `event_count`, `offer_count`
`event_count`, `offer_count`, `offers`, `thumbnail_lines?`, `hide_inscription_ids`, `raw_response`

## 7.30 offer submit-ord

Command:
`offer submit-ord [--psbt <base64> | --psbt-file <path> | --psbt-stdin]`

Success fields:
`submitted`, `ord_url`
`ord_url`, `submitted`, `raw_response`

## 7.31 offer list-ord

Command:
`offer list-ord`

Success fields:
`ord_url`, `offers`, `count`
`ord_url`, `count`, `offers`, `raw_response`

## 7.32 offer accept

Command:
`offer accept [--offer-json <json> | --offer-file <path> | --offer-stdin] [--expect-inscription <id>] [--expect-ask-sats <u64>] [--dry-run]`

Success fields:
`accepted`, `dry_run`, `offer_id`, `seller_input_index`, `input_count`, `inscription_id`, `ask_sats`, `safe_to_send`, `inscription_risk`, `policy_reasons`, `analysis`, `txid?`
`inscription`, `ask_sats`, `txid`, `dry_run`, `inscription_risk`, `thumbnail_lines?`, `hide_inscription_ids`, `raw_response`

## 8) Input Source Rules (PSBT and Offer Commands)

Expand Down Expand Up @@ -455,7 +453,7 @@ When `--policy-mode strict` is set, `psbt sign`, `psbt broadcast`, and `offer ac

## 10) Security Contract for Agent Usage

1. Agents should always use `--json`.
1. Agents should always use `--agent`.
2. Agents should prefer password env variables over plaintext flags.
3. Policy/ordinals failures must be surfaced as `error.type = "policy"` with actionable messages.
4. Commands that mutate wallet state should remain explicit and single-purpose.
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ cargo doc -p zinc-core --no-deps

1. Publish `zinc-core` to crates.io first.
2. Update `Cargo.toml` to an exact `zinc-core` pin:
- `zinc-core = { version = "=X.Y.Z", path = "../zinc-core-public" }`
- `zinc-core = { version = "=X.Y.Z" }`
3. Push a `zinc-cli` release tag.
4. Ensure tag CI passes:
- exact pin validation succeeds,
Expand Down
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "zinc-wallet-cli"
version = "0.1.1"
version = "0.3.0"
edition = "2021"
rust-version = "1.88"
license = "MIT"
Expand Down Expand Up @@ -52,7 +52,6 @@ ui = [
"dep:figlet-rs",
"dep:rand",
"dep:bip39",
"dep:image",
]

[dependencies]
Expand All @@ -77,10 +76,12 @@ tui-big-text = { version = "0.8.2", optional = true }
figlet-rs = { version = "0.1.5", optional = true }
supports-unicode = "3.0.0"

zinc-core = { version = "=0.1.0", path = "../zinc-core-public" }
zinc-core = { version = "=0.1.2" }
rand = { version = "0.8", optional = true }
bip39 = { version = "2.1.0", optional = true }
image = { version = "0.25.10", features = ["avif", "webp"], optional = true }
image = { version = "0.25.10", features = ["avif", "webp"] }
console = "0.15"
viuer = "0.11.0"



Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ It uses an account-based model where each account has:
- a native segwit address for BTC payments

Default behavior is optimized for automation (`--agent` JSON envelopes).
Optional human mode is available via `--features ui`.
Optional interactive dashboard mode is available via `--features ui`.

## Install

Expand Down Expand Up @@ -62,6 +62,10 @@ The `ui` feature enables a basic terminal dashboard for humans that shows:
- inscriptions
- ordinals/payment addresses per account

Even without `ui`, human command output can be tuned with:
- `--thumb` to force thumbnail rendering on
- `--no-thumb` to disable thumbnail rendering

Run dashboard:

```bash
Expand All @@ -83,7 +87,7 @@ Reports are written to `demo/artifacts/`.
- sync: `sync chain|ordinals`
- addresses and balance: `address taproot|payment`, `balance`
- transfers: `psbt create|analyze|sign|broadcast`
- offers: `offer create|publish|discover|accept|submit-ord|list-ord`
- advanced offers (hidden from top-level help): `offer create|publish|discover|accept|submit-ord|list-ord`
- accounts: `account list|use`
- waits and tx: `wait tx-confirmed|balance`, `tx list`
- operations: `snapshot save|restore|list`, `lock info|clear`, `doctor`
Expand All @@ -101,7 +105,7 @@ Reports are written to `demo/artifacts/`.

- Prefer `ZINC_WALLET_PASSWORD` (default password env) or `--password-stdin`.
- Use `--password-env` only when you need a non-default env var name.
- In `--json` mode, mnemonic output is redacted unless `--reveal` is set.
- In `--agent` mode, mnemonic output is redacted unless `--reveal` is set.
- See [SECURITY.md](./SECURITY.md).

## License
Expand Down
Loading
Loading