mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 20:57:03 +00:00
Every secret now has a category derived from its name (db, social, server,
api, cloud, finance, crypto, ai, email, messaging, storage, dns, analytics,
devtools, auth, config, other). One rule table in @logicsrc/opencreds serves
both vaults; services win over generic words, so STRIPE_WEBHOOK_SECRET is
finance, not auth. Checked against the 1,208 distinct key names in the
profullstack team: 74 fall to "other".
Team vaults (where the shared .env secrets live):
- teams categories [team] the filter words, with per-category counts
- teams secrets <team> [project] [env] --category/-c --search/-s
names + categories, never decrypts; --format csv
- teams export <team> [project] [env] --category -o file.csv [--yes]
decrypts into team,project,env,category,key,
value,updated_at (0600); skips vaults without a
grant and names them
Personal vault (OpenCreds):
- vault list --category, and the category column in list output
- vault export --format csv: one flat row per item, keeps key/account
secrets that a Bitwarden CSV drops; --category on every export format
DX:
- examples in `logicsrc vault help` / -h / --help that start by saying which
of the two vaults you want, plus examples on teams and each subcommand
- password prompts go to stderr, so eval "$(logicsrc vault unlock)" works
- hints name the command you actually ran (logicsrc vault init, not
opencreds init)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
171 lines
6.7 KiB
Markdown
171 lines
6.7 KiB
Markdown
# The OpenCreds CLI
|
|
|
|
The CLI is part of the conformance surface: flags, output shapes and exit codes
|
|
are specified, not incidental. The same commands ship twice — as
|
|
`logicsrc vault …` and as the standalone `opencreds` binary — from one
|
|
implementation, so the two can never drift.
|
|
|
|
## Exit codes
|
|
|
|
| Code | Meaning |
|
|
| --- | --- |
|
|
| 0 | Success. |
|
|
| 1 | Usage error — unknown flag, missing argument, unreadable file. |
|
|
| 2 | Validation failure — a document did not conform. |
|
|
| 3 | Crypto failure — wrong password, failed tag, manifest mismatch. |
|
|
| 4 | Refused — the operation needs a confirmation that was not given. |
|
|
|
|
## Vault
|
|
|
|
```bash
|
|
opencreds init [--namespace opencreds] [--iterations 600000] [--password-stdin]
|
|
```
|
|
|
|
Creates a vault. Prompts for a master password twice, prints a recovery key
|
|
once, and never prints it again. Refuses if a vault already exists at the target
|
|
unless `--force`. `--password-stdin` reads one line instead and skips the
|
|
confirmation — for scripted provisioning, where there is nobody to mistype.
|
|
|
|
```bash
|
|
opencreds unlock # prints a session token to export
|
|
opencreds unlock --persist [--timeout 15]
|
|
opencreds lock # drops a persisted session
|
|
opencreds status # vault present? locked? counts by type
|
|
```
|
|
|
|
Unlocking has two shapes, and the difference is a flag rather than a default
|
|
because it is a real trade:
|
|
|
|
- **Token (default).** `unlock` prints `export OPENCREDS_SESSION="…"`. Nothing
|
|
touches disk and the session dies with the shell.
|
|
- **Persisted (`--persist`).** The same token in a 0600 file with an expiry, so
|
|
a script can unlock once and run many commands. A readable user key on disk is
|
|
the vault; the command says so when you use it, and `lock` removes it.
|
|
|
|
`status` is the one command that works locked. It reports counts and never
|
|
values, because counts are already observable to whoever holds the storage.
|
|
|
|
```bash
|
|
opencreds recover # unlock with the recovery key, set a new password
|
|
```
|
|
|
|
A password change re-wraps the user key. Not one item is re-encrypted, which is
|
|
why it is instant on a vault of any size.
|
|
|
|
## Items
|
|
|
|
```bash
|
|
opencreds add <type> --name <name> [type flags…]
|
|
opencreds list [--type <type>] [--category <names>] [--folder <name>] [--search <text>] [--json]
|
|
opencreds get <id|name> [--field <path>] [--reveal]
|
|
opencreds edit <id|name> [flags…]
|
|
opencreds rm <id|name> [--purge]
|
|
opencreds restore <id>
|
|
```
|
|
|
|
`list` and `get` MUST NOT print secret values by default. `get` prints the item
|
|
with every secret field masked; `--reveal` prints one field named by `--field`,
|
|
so revealing is always a deliberate act naming a single value. `--json` output is
|
|
masked identically — a pipeline is not an authorization.
|
|
|
|
`list` prints one line per item: short id, type, category, name. The category
|
|
(`db`, `social`, `server`, `api`, `finance`, … and `other`) is derived from the
|
|
item type, name, account provider and login hosts, and is never stored, so it
|
|
cannot disagree between implementations that share the rule table.
|
|
`--category db,social` filters on it and accepts aliases (`database`,
|
|
`payments`); an unknown word exits 1 and names the valid ones.
|
|
|
|
Type flags follow the field group names, kebab-cased:
|
|
`--username`, `--password`, `--totp`, `--url`,
|
|
`--cardholder-name`, `--number`, `--exp-month`, `--exp-year`, `--code`,
|
|
`--first-name`, `--last-name`, `--email`, `--phone`, `--address1`, …,
|
|
`--key-type`, `--algorithm`, `--public-key`, `--private-key`, `--file`, `--path`, `--mode`,
|
|
`--provider`, `--account-id`, `--handle`, `--access-token`, `--refresh-token`, `--scope`.
|
|
|
|
`--password -` and every other secret flag read from stdin when given `-`, so a
|
|
secret need not appear in the shell history or the process list.
|
|
|
|
## Database
|
|
|
|
```bash
|
|
opencreds export [--out vault.opencreds] [--passphrase-stdin]
|
|
opencreds export --plaintext --out vault.json --yes
|
|
opencreds export --format csv --out vault.csv --yes
|
|
opencreds export --format bitwarden-csv --out vault.csv --yes
|
|
opencreds export --format csv --category db --out db.csv --yes
|
|
|
|
opencreds import <file> [--dry-run] [--merge skip|replace|duplicate]
|
|
opencreds import <file> --source bitwarden|onepassword|chrome|lastpass|keepass
|
|
```
|
|
|
|
`export` writes the encrypted form. `--plaintext` prints what it is about to do
|
|
and exits 4 without `--yes`.
|
|
|
|
`--format csv` writes one flat row per item —
|
|
`folder,category,type,name,username,password,url,value,totp,notes` — where
|
|
`value` is the single opaque secret of a key, account or card. It keeps the key
|
|
and account items a Bitwarden CSV has no column for, and is meant for people and
|
|
scripts, not re-import. `--format bitwarden-csv` is the one to hand another
|
|
password manager. `--category` limits any export format to those categories.
|
|
|
|
`import` with `--dry-run` reports counts by type, folders to be created,
|
|
duplicates detected and rows that could not be mapped, and writes nothing. A
|
|
manifest mismatch exits 3 and writes nothing regardless of flags.
|
|
|
|
Output of a dry run:
|
|
|
|
```
|
|
opencreds import vault.opencreds --dry-run
|
|
|
|
Source vault.opencreds (opencreds 0.1, encrypted, namespace opencreds)
|
|
Exported 2026-08-29T18:00:00.000Z by @logicsrc/opencreds 0.1.0
|
|
Manifest verified — 42 items, 3 folders
|
|
|
|
login 38 2 already present (skip)
|
|
card 2
|
|
key 1
|
|
account 1
|
|
|
|
Folders Work, Personal (new), Archive
|
|
Skipped 0
|
|
|
|
Nothing written. Re-run without --dry-run to import.
|
|
```
|
|
|
|
## Validation
|
|
|
|
```bash
|
|
opencreds validate <file> # a database, or a plaintext item document
|
|
opencreds validate --stdin
|
|
```
|
|
|
|
Exits 0 when the document conforms, 2 when it does not, and prints one diagnostic
|
|
per failure with a JSON pointer into the document:
|
|
|
|
```
|
|
/items/17/login/uris/0/match "fuzzy" is not a valid match rule
|
|
/manifest/itemCount says 42, payload has 41
|
|
```
|
|
|
|
## Conformance
|
|
|
|
```bash
|
|
opencreds conformance # a table, one row per requirement
|
|
opencreds conformance --json # the report, for CI
|
|
opencreds conformance --emit-fixtures <dir> # generate the fixture set
|
|
```
|
|
|
|
Runs the suite against this implementation and reports each requirement as pass,
|
|
fail or skip. Exits 2 when a MUST does not pass, so it can gate CI directly. An
|
|
implementation claiming conformance SHOULD run it there.
|
|
|
|
`--emit-fixtures` writes the generated fixture set, so another implementation
|
|
can be tested against exactly what this one produces and accepts. See
|
|
[conformance.md](./conformance.md).
|
|
|
|
## What the CLI never does
|
|
|
|
- It never prints a secret value except through `get --reveal --field`.
|
|
- It never writes a plaintext file without an explicit flag and a confirmation.
|
|
- It never sends anything anywhere. There is no telemetry, no account, and no
|
|
network call in any command listed on this page.
|