Pass
GPG-encrypted password store using the pass CLI (passwordstore.org). Can return just the first line of a multiline entry (the password, by pass convention) or a named metadata field such as login. Emits OpenTelemetry spans for get, put, and list so vault reads are visible in traces, including reads during model and workflow runs where the host emits nothing. Span attributes carry the vault name, key and field names, and backend only — never secret values or error messages.
2026.10.21.1
Fixed: Tracing spans reported a stale instrumentation version
(2026.10.20.1) instead of the published version. The tracer version now
matches manifest.yaml, and a test fails if the two drift apart again.
Fixed: The README showed model arguments in a source: vault / vault: /
key: form. swamp does not support that form; secrets reach a model only
through ${{ vault.get("<vault>", "<key>") }}. Both examples, including the
field-selection one (smtp/example#login), now use vault.get.
Changed: The swamp vault read-secret --force example now warns that it
prints the plaintext value, and the multiline-entry example no longer prints a
password-shaped literal.
Upgrade note: Secret storage and retrieval behave as before; only the instrumentation version on emitted spans changes.
GPG-encrypted password store using the pass CLI
Config Fields
| Field | Type | Description |
|---|---|---|
| storeDir? | string | PASSWORD_STORE_DIR override (defaults to ~/.password-store) |
| prefix? | string | Key prefix for namespacing secrets (defaults to 'swamp'). |
| extraEnv? | array | Additional environment variable names to forward to the pass subprocess. |
| passwordOnly? | boolean | Return only the first line of an entry (the password, by pass |
| fieldSeparator? | string | Enables per-key field selection. With fieldSeparator '#', the key |
2026.10.20.1
Added: passwordOnly config option. When true, get returns only the
first line of an entry, which is the password by pass convention, instead of the
whole decrypted file. Defaults to false.
Added: fieldSeparator config option for per-key field selection. With
fieldSeparator: "#", the key smtp/example#login returns the value of the
login: line of smtp/example. Field names match case-insensitively, line 1 is
never searched, and URI lines such as otpauth://... are not fields. A key
whose text after the separator is not a field name (team#a/entry, a#) names
an entry and is read whole. An entry named like smtp#login cannot be read
whole while the separator is set. Separators containing / or whitespace are
rejected. A missing field fails with an error naming the entry and field, never
its content. put rejects a key that selects a field. Unset by default, so keys
are taken literally.
Added: A get or put whose key selects a field records the field name in a
new vault.secret_field span attribute, and vault.secret_key carries the
entry path without the selector. Neither ever carries a value.
Added: With passwordOnly or a field selection, a key naming a directory
fails with "is a directory, not an entry". pass prints a tree listing for a
directory and exits 0, so without this check the first line of that listing
would come back as the password. These modes read file metadata under storeDir
to tell the two apart, and fail rather than guess if they cannot.
Fixed: Spans reported a stale instrumentation-scope version
(2026.08.20.1); they now report the published version.
Upgrade note: No behavior changes unless you opt in. get still returns the
whole multiline entry by default. The README now documents that default and how
it breaks a consumer that expects a bare password (#499).
Modified 1 vaults
2026.10.14.1
Added: The manifest now declares license: Apache-2.0 (SPDX). The registry quality rubric scores a declared license separately from the bundled LICENSE.md.
Upgrade note: Metadata only. No code, schema, or behavioral changes.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.09.18.1
Upgrade note: Normalized npm:zod dependency version to 4.6.5 across the
repo. No behavioral changes in this extension.
2026.09.15.1
Changed: Bump zod 4.4.3 → 4.6.5
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.28.1
Changed: Normalized the extension license to Apache-2.0 and corrected the copyright holder to "Sean Escriva". Extensions that previously shipped an MIT LICENSE.md are now Apache-2.0, consistent with the repository root and every other extension. No code or behavioral changes.
Upgrade note: License text only. No API, schema, or runtime behavior changed.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.3
Fixed: Restored inline npm:zod@4.4.3 import specifiers so the registry
quality scorer can resolve dependencies and score the extension. An earlier
release used a bare "zod" import-map specifier, which published but scored as
unscored.
Changed: Retained explicit compilerOptions.strict in deno.json. No
behavioral or schema changes.
2026.08.26.1
Changed: Normalized deno.json configuration for repo-wide consistency:
added explicit compilerOptions.strict and migrated zod dependency to the
import map (bare "zod" specifier instead of inline npm:zod@4.4.3). No
behavioral changes — runtime resolution is identical.
2026.08.25.1
Changed: Updated labels for improved extension discoverability. Added cross-cutting category labels (security, observability, finops, infrastructure, networking, compliance, devops, ai, incident-response) where applicable.
updated labels
2026.08.23.1
Fixed: README's Usage section documented invented CLI flags/subcommands
(--vault, --key, --value) that don't exist. Corrected to the real
swamp vault put/read-secret/list-keys command forms.
Changed: Documentation only — no code changes otherwise. Added a
## Troubleshooting section covering the narrowed subprocess environment
(ENV_ALLOWLIST plus clearEnv: true, with extraEnv as the escape hatch),
the find-exit-code-vs-empty-store distinction in list, assertSafeKey,
and the breaking prefix-migration behavior from 2026.04.22.1 (prefix: ""
to read legacy unprefixed secrets).
2026.08.21.1
Fixed: list() no longer reports a missing or unreadable password store
directory as an empty listing. Previously, if the underlying find
subprocess failed for any reason — a bad storeDir, permissions, find not
being installed — the provider silently returned [], indistinguishable
from a store that legitimately has no secrets yet. It now throws an error
naming the directory and the find exit code/stderr.
Changed: When the pass CLI exits non-zero, the thrown error now names
the subcommand that failed (e.g. pass show swamp/my-key exited with code 1: Error: swamp/my-key is not in the password store.) instead of just the
exit code and bare stderr. Secret values passed on stdin to insert are
still redacted before the error is constructed, as before.
2026.08.20.1
Upgrade note: Bumped zod from 4.3.6 to 4.4.3. No behavioral changes — dependency version alignment only.
2026.07.27.1
Changed: Bump @opentelemetry/api 1.9.0 → 1.9.1
2026.07.26.2
Added: OpenTelemetry spans on get, put, and list, named pass get,
pass put, and pass list. Attributes: vault.name, vault.secret_key,
vault.prefix when a prefix is configured, rpc.system, rpc.service,
rpc.method, and vault.keys_returned on list.
This closes a real observability gap rather than duplicating the host. swamp
emits swamp.vault.* spans when a human runs a swamp vault subcommand, with
no attributes at all — and emits nothing when a model or workflow resolves a
vault expression. A secret read during a run was invisible in traces. These
spans appear on both paths.
The extension uses @opentelemetry/api only and never constructs a
TracerProvider. With no provider configured the tracer is a no-op and the cost is
a few property lookups.
There are deliberately no spans around the pass or find invocations. Each
public method is exactly one subprocess call, so a child span would be a renamed
duplicate of its parent, and keeping span code out of the exec helper means no
edit can attach argv or stdin — which hold the plaintext — to a span.
Changed: Error messages no longer echo a submitted secret value. If pass
fails an insert and quotes the value back on stderr, that value is replaced
with [redacted] before the message is thrown. The swamp host publishes thrown
error messages into its own span as a status description, an exception.message,
and a stack trace, so an echoed value reached the trace backend regardless of
what this extension recorded.
Note on what spans deliberately omit: spans record error.type and an ERROR
status on failure, and never recordException and never a status description. A
pass error message is the CLI's stderr, which this extension does not control,
and the host already publishes it once. Recording key names is intentional — a
vault span without the key is close to useless for debugging — so treat key names
as visible to anyone with access to your trace backend and do not encode
sensitive information in them.
2026.07.26.2
Added: OpenTelemetry spans on get, put, and list, named pass get,
pass put, and pass list. Attributes: vault.name, vault.secret_key,
vault.prefix when a prefix is configured, rpc.system, rpc.service,
rpc.method, and vault.keys_returned on list.
This closes a real observability gap rather than duplicating the host. swamp
emits swamp.vault.* spans when a human runs a swamp vault subcommand, with
no attributes at all — and emits nothing when a model or workflow resolves a
vault expression. A secret read during a run was invisible in traces. These
spans appear on both paths.
The extension uses @opentelemetry/api only and never constructs a
TracerProvider. With no provider configured the tracer is a no-op and the cost is
a few property lookups.
There are deliberately no spans around the pass or find invocations. Each
public method is exactly one subprocess call, so a child span would be a renamed
duplicate of its parent, and keeping span code out of the exec helper means no
edit can attach argv or stdin — which hold the plaintext — to a span.
Changed: Error messages no longer echo a submitted secret value. If pass
fails an insert and quotes the value back on stderr, that value is replaced
with [redacted] before the message is thrown. The swamp host publishes thrown
error messages into its own span as a status description, an exception.message,
and a stack trace, so an echoed value reached the trace backend regardless of
what this extension recorded.
Note on what spans deliberately omit: spans record error.type and an ERROR
status on failure, and never recordException and never a status description. A
pass error message is the CLI's stderr, which this extension does not control,
and the host already publishes it once. Recording key names is intentional — a
vault span without the key is close to useless for debugging — so treat key names
as visible to anyone with access to your trace backend and do not encode
sensitive information in them.
updated labels
2026.07.26.1
Fixed: Secrets with leading or trailing whitespace came back altered. The
CLI output was passed through trim(), which strips spaces and tabs at both
ends, not just the line terminator the CLI adds. Only a single trailing newline
is removed now, so " padded " round-trips intact.
Fixed: Keys were not validated, so get("../../other/secret") escaped the
configured prefix and read — or with put, overwrote — a secret outside the
namespace the config pinned the caller to. Keys containing . or .. path
segments, empty path segments (a//b, trailing/), absolute keys, empty keys,
and keys starting with - (which pass would parse as a flag) are now rejected
before the CLI runs.
Changed: The pass subprocess no longer inherits the entire parent
environment. It previously received a copy of every variable in the calling
process, handing pass and every GPG agent hook it invokes any AWS key,
database URL, or API token that happened to be set. Only variables that pass
or GPG need are forwarded: HOME, PATH, USER, LOGNAME, TMPDIR, SHELL,
the locale variables, GNUPGHOME, GPG_AGENT_INFO, GPG_TTY, SSH_AUTH_SOCK,
TERM, the display and session variables pinentry needs (DISPLAY,
WAYLAND_DISPLAY, XAUTHORITY, DBUS_SESSION_BUS_ADDRESS,
PINENTRY_USER_DATA, XDG_*), and the PASSWORD_STORE_* settings. The find
subprocess used by list is narrowed the same way.
Added: extraEnv, a list of additional environment variable names to
forward to the subprocess. Use it if an unusual GPG or pinentry setup needs a
variable outside the default set.
Upgrade note: If your GPG or pinentry setup depends on an environment
variable outside that list, pass operations will fail where they previously
worked. Add the variable name to extraEnv in your vault config to restore it,
and open an issue so it can be considered for the default list.
Known limitation: A secret whose own final character is a newline cannot be distinguished from the terminator the CLI appends, so that byte is still lost. This is inherent to reading secrets from a line-oriented CLI.
Modified 1 vaults
2026.07.18.2
Changed: Version bump only, no code changes.
2026.07.18.1
Changed: Renamed the manifest tags: field to labels: — the schema's
actual field name. No runtime or install behavior change.
2026.07.18.1
Changed: Renamed the manifest tags: field to labels: — the schema's
actual field name. No runtime or install behavior change.
updated labels
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned