oth_rvault 0.4.0

Partial Ansible Vault encoder and decoder
Documentation
[![crates.io](https://img.shields.io/crates/v/oth_rvault.svg)](https://crates.io/crates/oth_rvault)
[![Docker Hub](https://img.shields.io/badge/docker-okieoth%2Frvault-blue?logo=docker)](https://hub.docker.com/r/okieoth/rvault)

# rvault

A tool to encrypt or decrypt JSON or YAML files that contain partial Ansible vault encrypted values.

This is a Rust port from here: https://github.com/OkieOth/partial-vaults/tree/main

## Overview

rvault allows you to work with files that have a mix of plain text and Ansible Vault encrypted values. Unlike standard Ansible Vault which encrypts entire files, this tool lets you:

- Encrypt specific values within JSON or YAML files
- Decrypt specific values while leaving others encrypted
- Process nested structures with selective encryption
- Interactively edit encrypted values in-place
- Copy decrypted values to the clipboard with auto-clear

## Install

```bash
# install from crates.io
cargo install oth_rvault

# use
rvault --help
```

## Usage

rvault has four subcommands: `encrypt`, `decrypt`, `edit`, and `clip`.

### Password resolution

All subcommands need a vault password. It is resolved in this priority order:

1. `--password <PASSWORD>` — pass the password directly on the command line
2. `--pfile <FILE>` — read the password from a file
3. `MY_RVAULT_PWD` environment variable — path to a password file

```bash
# inline password
rvault decrypt -i secrets.yaml --stdout --password mypassword

# password from file
rvault decrypt -i secrets.yaml --stdout --pfile ~/.vault_pass

# password from environment (recommended for scripts)
export MY_RVAULT_PWD=~/.vault_pass
rvault decrypt -i secrets.yaml --stdout
```

### Output target

For `encrypt`, `decrypt`, and `edit`, exactly one output option must be given:

| Flag | Behaviour |
|------|-----------|
| `-o <FILE>` | Write result to a new file |
| `--overwrite` | Replace the input file in-place |
| `--stdout` | Print result to standard output |

---

### encrypt

Encrypt scalar values inside a JSON or YAML file using Ansible Vault AES256.

```
rvault encrypt -i <INPUT> (-o <OUTPUT> | --overwrite | --stdout)
               --password <PASSWORD>
               [-k <KEY>]...
               [--level <DEPTH>]
               [--ansible]
```

**Encrypt all values** in a file:

```bash
rvault encrypt -i example.json -o encrypted.json --password secret
```

**Encrypt specific keys** using dot-notation paths:

```bash
# single key
rvault encrypt -i example.json -o encrypted.json --password secret -k first.a

# multiple keys (repeat the flag or use comma-separation)
rvault encrypt -i example.json -o encrypted.json --password secret \
    -k first.a -k first.z

rvault encrypt -i example.json -o encrypted.json --password secret \
    -k first.a,first.z
```

**Encrypt by nesting depth** with `--level` (cannot be combined with `--key`):

```bash
# encrypt all values at the top level (depth 1)
rvault encrypt -i example.json -o encrypted.json --password secret --level 1

# encrypt all values two levels deep
rvault encrypt -i example.yaml --overwrite --password secret --level 2
```

**Overwrite the file in-place:**

```bash
rvault encrypt -i secrets.yaml --overwrite --password secret
```

**Print to stdout** (useful for piping):

```bash
rvault encrypt -i example.json --stdout --password secret
```

---

### decrypt

Decrypt some or all encrypted values in a partially-encrypted file.

```
rvault decrypt -i <INPUT> (-o <OUTPUT> | --overwrite | --stdout)
               --password <PASSWORD>
               [-k <KEY>]...
               [--value-only]
               [--interactive]
```

**Decrypt all values:**

```bash
rvault decrypt -i encrypted.json -o plain.json --password secret
```

**Decrypt specific keys:**

```bash
rvault decrypt -i encrypted.json --stdout --password secret -k second.a.v
```

**Value-only mode** (`--value-only` / `-v`) — output only the selected key(s) as a minimal nested document (requires at least one `--key` or `--interactive`):

```bash
# prints just the nested sub-document for the selected keys
rvault decrypt -i encrypted.json --stdout --password secret \
    -k second.a.v --value-only
```

**Interactive (fuzzy) mode** — opens an interactive prompt to select which encrypted keys to decrypt:

```bash
rvault decrypt -i encrypted.json --stdout --password secret --interactive

# combine with --value-only to output only the selected values
rvault decrypt -i encrypted.json --stdout --password secret \
    --interactive --value-only
```

---

### edit

Decrypt a value, open it in `$EDITOR`, then re-encrypt and save.

```
rvault edit -i <INPUT> (-o <OUTPUT> | --overwrite | --stdout)
            --password <PASSWORD>
            [-k <KEY>]...
            [-a | --interactive]
```

**Edit a specific key:**

```bash
rvault edit -i secrets.yaml --overwrite --password secret -k database.password
```

**Edit multiple keys:**

```bash
rvault edit -i secrets.yaml --overwrite --password secret \
    -k database.password -k api.token
```

**Fuzzy-select which key to edit** (default when no `--key` is given):

```bash
rvault edit -i secrets.yaml --overwrite --password secret
```

**Edit all encrypted values without selection** (`-a`):

```bash
rvault edit -i secrets.yaml --overwrite --password secret -a
```

---

### clip

Fuzzy-search encrypted values and copy the decrypted result to the clipboard. The clipboard is automatically cleared after a timeout.

```
rvault clip -i <INPUT> --password <PASSWORD>
            [--timeout <SECONDS>]
            [--pfile <FILE>]
```

```bash
# default: clear clipboard after 30 seconds
rvault clip -i secrets.yaml --password secret

# keep clipboard for 60 seconds
rvault clip -i secrets.yaml --password secret --timeout 60

# never clear the clipboard automatically
rvault clip -i secrets.yaml --password secret --timeout 0
```

---

## File format

rvault works with plain JSON or YAML files. Encrypted values are stored inline as Ansible Vault strings:

```yaml
# example.yaml — mixed plain/encrypted YAML
first:
    z: last
    a: first
    m: middle
second:
    a:
        v: true   # plain boolean
        w: 14     # plain integer
        x: "$ANSIBLE_VAULT;1.1;AES256\n..."  # encrypted string
```

```json
{
  "first": {
    "z": "last",
    "a": "$ANSIBLE_VAULT;1.1;AES256\n...",
    "m": "middle"
  }
}
```

The original Rust type (bool, integer, float, string) is preserved across an encrypt→decrypt round-trip.

---

## Docker

```bash
# decrypt a file
docker run --rm -u $(id -u):$(id -g) \
    -v /path/to/input:/input \
    -v /path/to/output:/output \
    docker.io/okieoth/rvault:latest decrypt \
     -i /input/secrets.yaml -o /output/decrypted.yaml \
     --password mypassword

# encrypt a file
docker run --rm -u $(id -u):$(id -g) \
    -v /path/to/input:/input \
    -v /path/to/output:/output \
    docker.io/okieoth/rvault:latest encrypt \
     -i /input/plain.yaml -o /output/secrets.yaml \
     --password mypassword
```

---

## Build

```bash
# build binary
cargo build

# run tests
cargo test

# build docker image
make docker-build
```

---

# Mac OS Builds

To do `cargo install` under Mac OS you need at first to install Rust.
That the linking of the final program works you need the Mac OS developer
tools too. You can install them with `xcode-select --install`.
Attention, after executing the `xcode-select` command a new window opens.
Sometimes this window is hidden in the stack of other open program windows.

# Additional

* Password for `resources/tests/partial.yaml`: `aa`
* Password for `resources/tests/partial_encrypted_example.json`: `test999`
* Password for `resources/tests/partial_encrypted_example.yaml`: `test999`