nimvault/commands

Vault commands: seal, unseal, add, rm, mv, list, status, scan.

All commands take a repo path and GpgConfig. Parallel GPG via startProcess with direct invocation (no shell).

Procs

proc add(repo, path: string; cfg: GpgConfig; noGitignore = false) {.
    ...raises: [NimvaultError, Exception, OSError, IOError, ValueError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, ExecIOEffect,
    WriteIOEffect, TimeEffect, WriteDirEffect], forbids: [].}
Add a file by its target path.
proc addDir(repo, dirPath: string; cfg: GpgConfig; noGitignore = false) {.
    ...raises: [NimvaultError, OSError, IOError, ValueError, Exception], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, WriteIOEffect, WriteDirEffect,
    ExecIOEffect, RootEffect, TimeEffect], forbids: [].}
Add a directory recursively to the vault.
proc addDirReport(repo, dirPath: string; cfg: GpgConfig; noGitignore = false): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError, Exception], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, WriteIOEffect, WriteDirEffect,
    ExecIOEffect, RootEffect, TimeEffect], forbids: [].}
proc addReport(repo, path: string; cfg: GpgConfig; noGitignore = false): string {.
    ...raises: [NimvaultError, Exception, OSError, IOError, ValueError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, RootEffect, ExecIOEffect,
    WriteIOEffect, TimeEffect, WriteDirEffect], forbids: [].}
proc get(repo, path: string; cfg: GpgConfig; allowUnsigned = false): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect], forbids: [].}

Decrypt one tracked entry and return its plaintext. Nothing is written to disk and nothing else in the vault is touched.

unseal is all-or-nothing and materialises every entry, which is the wrong shape for a caller that wants one credential: a forced-command SSH gate serving a single allowlisted secret, a service reading one token at start up. Without this those callers shell out to gpg against the blobs directly, which works but puts secrets outside anything list, status or scan can see.

The same checks unseal performs still apply. A caller asking for one entry has no less need of a path-safety check and an integrity check than one asking for all of them.

proc list(repo: string; cfg: GpgConfig) {.
    ...raises: [IOError, NimvaultError, OSError, ValueError], tags: [WriteIOEffect,
    ReadDirEffect, ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect,
    TimeEffect], forbids: [].}
proc listReport(repo: string; cfg: GpgConfig): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect], forbids: [].}
Library-friendly list (no terminal styling). Used by CLI and C ABI.
proc move(repo, oldPath, newPath: string; cfg: GpgConfig) {.
    ...raises: [Exception, NimvaultError, OSError, IOError, ValueError], tags: [
    ReadEnvEffect, ReadIOEffect, RootEffect, ReadDirEffect, ExecIOEffect,
    WriteIOEffect, TimeEffect, WriteDirEffect], forbids: [].}
proc moveReport(repo, oldPath, newPath: string; cfg: GpgConfig): string {.
    ...raises: [Exception, NimvaultError, OSError, IOError, ValueError], tags: [
    ReadEnvEffect, ReadIOEffect, RootEffect, ReadDirEffect, ExecIOEffect,
    WriteIOEffect, TimeEffect, WriteDirEffect], forbids: [].}
proc remove(repo, path: string; cfg: GpgConfig) {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadEnvEffect,
    ReadIOEffect, ReadDirEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
proc removeReport(repo, path: string; cfg: GpgConfig): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadEnvEffect,
    ReadIOEffect, ReadDirEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
proc scan(repo: string; target: string; cfg: GpgConfig) {.
    ...raises: [ValueError, OSError, NimvaultError, IOError, RegexError], tags: [
    ReadEnvEffect, ReadIOEffect, ReadDirEffect, ExecIOEffect, RootEffect,
    WriteIOEffect, TimeEffect], forbids: [].}
Walk target (file or dir) and flag any file containing a secret pattern that is NOT already in the vault.
proc scanReport(repo, target: string; cfg: GpgConfig): string {.
    ...raises: [ValueError, OSError, RegexError, IOError], tags: [ReadEnvEffect,
    ReadIOEffect, ReadDirEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect], forbids: [].}
Scan without process exit. Returns report; raises only on I/O errors. If secrets found, still returns the report text (no raise) so MCP can show it.
proc seal(repo: string; cfg: GpgConfig) {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
proc sealReport(repo: string; cfg: GpgConfig): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
proc status(repo: string; cfg: GpgConfig) {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
Terminal status (colors). Delegates logic to statusReport for library reuse.
proc statusReport(repo: string; cfg: GpgConfig): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError], tags: [ReadDirEffect,
    ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect, WriteIOEffect,
    TimeEffect, WriteDirEffect], forbids: [].}
Library-friendly status (no colors). Fast path uses contentHash when present.
proc unseal(repo: string; cfg: GpgConfig; allowUnsigned = false;
            only: seq[string] = @[]) {....raises: [NimvaultError, OSError, IOError,
    ValueError, Exception], tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect,
                                   ExecIOEffect, RootEffect, WriteIOEffect,
                                   TimeEffect, WriteDirEffect], forbids: [].}

Decrypt tracked entries back to their target paths. With no selector this restores the whole vault; with one it restores only what was named.

The selective form exists because all-or-nothing forces the caller to express any partial restore somewhere else. A machine that should hold a subset of the vault otherwise has to model that split in whatever tool sits above this one, which is both duplicated and invisible from here.

proc unsealReport(repo: string; cfg: GpgConfig; allowUnsigned = false;
                  only: seq[string] = @[]): string {.
    ...raises: [NimvaultError, OSError, IOError, ValueError, Exception], tags: [
    ReadDirEffect, ReadEnvEffect, ReadIOEffect, ExecIOEffect, RootEffect,
    WriteIOEffect, TimeEffect, WriteDirEffect], forbids: [].}