Skip to content
Draft
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
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Passbolt provider** (`passbolt://`): store and read secrets in a
self-hosted [Passbolt](https://www.passbolt.com/) server via the official
[`go-passbolt-cli`](https://github.com/passbolt/go-passbolt-cli). Convention
secrets map to a resource named `secretspec/{project}/{profile}/{key}` with
the value in the `password` field; a secret's `ref` can instead point at an
existing resource by id or name and pick a `field`
(`password`/`username`/`uri`/`description`). Credentials are supplied either
through the `passbolt` CLI's own configuration or through secretspec-owned env
vars (`SECRETSPEC_PASSBOLT_SERVER`, `SECRETSPEC_PASSBOLT_PRIVATE_KEY_FILE` /
`SECRETSPEC_PASSBOLT_PRIVATE_KEY`, `SECRETSPEC_PASSBOLT_PASSPHRASE`) that the
provider forwards to the CLI — the passphrase and inline key via the child's
environment, never the argv — so no credentials live in `secretspec.toml` or
the provider URI.

## [0.14.0] - 2026-07-09

### Added
Expand Down
1 change: 1 addition & 0 deletions docs/astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ Secrets can be stored in: keyring (default), dotenv files, environment variables
{ label: "Environment Variables", slug: "providers/env" },
{ label: "Pass", slug: "providers/pass" },
{ label: "Proton Pass", slug: "providers/protonpass" },
{ label: "Passbolt", slug: "providers/passbolt" },

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs drift: the sidebar entry is here, but the other provider listings from the CLAUDE.md "Adding Provider Documentation" checklist were missed:

  • the providers sentence in the starlightLlmsTxt description block in this file (still ends at "Bitwarden Secrets Manager")
  • docs/src/pages/index.astro: the providerMetadata array has no passbolt entry, and the page's "11 backends" counts and provider enumerations are now stale
  • README.md: the Providers bullet list and the secretspec config init example output (quick-start.mdx got the new line, the README didn't)

After this lands, llms.txt, the landing page, and the GitHub README all advertise a provider list that no longer matches what the binary prints.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work, thanks. I had done the pull request to document the possibility of using secretspec for Passbolt, but I'll take up the challenge and go through these implementation drawbacks and make it proper.

And many thanks for secretspec, it's awesome. Have been using it for every project since becoming aware of it!

{ label: "LastPass", slug: "providers/lastpass" },
{ label: "1Password", slug: "providers/onepassword" },
{
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/concepts/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Providers are pluggable storage backends that handle the storage and retrieval o
| **env** | Read-only access to existing environment variables | ✓ | ✗ | ✗ |
| **pass** | Unix password manager with GPG encryption | ✓ | ✓ | ✓ |
| **protonpass** | Integration with Proton password manager | ✓ | ✓ | ✓ |
| **passbolt** | Self-hosted Passbolt via go-passbolt-cli | ✓ | ✓ | ✓ |
| **onepassword** | Integration with OnePassword password manager | ✓ | ✓ | ✓ |
| **lastpass** | Integration with LastPass password manager | ✓ | ✓ | ✓ |
| **gcsm** | Google Cloud Secret Manager (requires `--features gcsm`) | ✓ | ✓ | ✓ |
Expand Down
147 changes: 147 additions & 0 deletions docs/src/content/docs/providers/passbolt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
title: Passbolt Provider
description: Passbolt self-hosted password manager via go-passbolt-cli
---

The Passbolt provider integrates with [Passbolt](https://www.passbolt.com/), the
self-hosted, open-source password manager, via the official
[`go-passbolt-cli`](https://github.com/passbolt/go-passbolt-cli) (`passbolt`).

It fits the workflow where **a human enters an API key or service password once**
(via the Passbolt web UI or CLI) and **dev machines read it at runtime** — no
secret material is ever written to `secretspec.toml` or to disk.

## Prerequisites

- The `passbolt` CLI installed and on `PATH` (build from
[go-passbolt-cli](https://github.com/passbolt/go-passbolt-cli)).
- Credentials for your Passbolt account: the server address, your OpenPGP
private key, and its passphrase.

## Authentication

The private key and passphrase are the bootstrap secrets that unlock every
other secret, so they never belong in `secretspec.toml` or the provider URI.
There are two ways to supply them.

### Option A — secretspec-owned env vars (no separate CLI config)

Set these in your environment (e.g. via your shell profile, a `.envrc`, or your
CI secret store) and secretspec forwards them to the CLI for you — the
passphrase and inline key go through the child process environment, never the
command line:

| Variable | Purpose |
|----------|---------|
| `SECRETSPEC_PASSBOLT_SERVER` | Server address (or use the URI's `?server=`) |
| `SECRETSPEC_PASSBOLT_PRIVATE_KEY_FILE` | Path to your OpenPGP private key file |
| `SECRETSPEC_PASSBOLT_PRIVATE_KEY` | Inline OpenPGP private key (alternative to the file) |
| `SECRETSPEC_PASSBOLT_PASSPHRASE` | Private-key passphrase |

```bash
export SECRETSPEC_PASSBOLT_SERVER=https://pass.example.com
export SECRETSPEC_PASSBOLT_PRIVATE_KEY_FILE=~/.config/passbolt/ada.asc
export SECRETSPEC_PASSBOLT_PASSPHRASE='<passphrase>'

secretspec get STRIPE_SECRET_KEY --provider passbolt
```

### Option B — the CLI's own configuration

Run `passbolt configure` once; with none of the env vars above set, the
provider inherits that configuration:

```bash
passbolt configure \
--serverAddress https://pass.example.com \
--userPrivateKeyFile ada.asc \
--userPassword '<passphrase>'
```

Either way, no credentials appear in `secretspec.toml` or the provider URI.

## Configuration

### URI Format

```
passbolt://[name-template][?folder=<folder-id>&server=<server-address>]
```

- `name-template`: resource-name pattern for convention secrets, supporting the
`{project}`, `{profile}`, `{key}` placeholders. Defaults to
`secretspec/{project}/{profile}/{key}`.
- `folder` (optional): a Passbolt folder id. New convention resources are
created inside it (`--folderParentID`) and name lookups are scoped to it.
- `server` (optional): overrides the CLI's configured server address
(`--serverAddress`). Useful when one machine talks to several Passbolt servers.

### Examples

```bash
# Default resource name (secretspec/{project}/{profile}/{key})
passbolt://

# Custom resource-name template
passbolt://secretspec/{project}/{profile}/{key}

# Pin the server address (e.g. a tailnet-internal Passbolt)
passbolt://?server=https://pass.example.com

# Scope convention resources to a folder
passbolt://?folder=a9230ec4-5507-4870-b8b5-b3f500587e4c
```

## Storage model

Each convention secret maps to one Passbolt **resource**:

- The resource **name** encodes `{project}/{profile}/{key}`.
- The secret value lives in the resource's **password** field.

## Secret references

A secret's [`ref`](/reference/configuration/#secret-references) points at an
existing, human-provisioned resource instead of the convention layout — the
common case for "someone added the API key in Passbolt, I just want to read it":

- `item`: the resource **id** (a UUID, copied from the Passbolt UI) or the exact
resource **name**.
- `field` (optional): which resource field holds the value — one of `password`
(default), `username`, `uri`, `description`.

```toml
[profiles.production]
# By resource id (unambiguous — recommended for refs)
STRIPE_SECRET_KEY = { description = "Stripe key", ref = { item = "a9230ec4-5507-4870-b8b5-b3f500587e4c" }, providers = ["passbolt://?server=https://pass.example.com"] }

# By resource name, reading a non-default field
SERVICE_USER = { description = "Service account user", ref = { item = "Payments service account", field = "username" }, providers = ["passbolt"] }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs: this example fails at runtime. A bare name in a per-secret providers chain must be a declared alias (project [providers] table or user config), not a provider name; only full scheme:// URIs pass through directly. Copying this line as-is yields "Provider alias 'passbolt' is not defined". Either use providers = ["passbolt://"] like the STRIPE example above effectively does, or add the [providers] alias table to the example.

```

Reads fetch the resource by id (or resolve the name to an id first) and decrypt
the requested field. Writes update that field on the existing resource; a `ref`
whose id resolves to nothing is an error (secretspec never creates a detached
resource for an externally managed reference).

## Usage

```bash
# Set a secret (creates or updates the secretspec/... resource's password)
$ secretspec set STRIPE_SECRET_KEY --provider passbolt
Enter value for STRIPE_SECRET_KEY: sk_live_...

# Get a secret
$ secretspec get STRIPE_SECRET_KEY --provider passbolt

# Run a process with secrets injected
$ secretspec run --provider passbolt -- npm start
```

## Environment variables

- `SECRETSPEC_PASSBOLT_SERVER`, `SECRETSPEC_PASSBOLT_PRIVATE_KEY_FILE`,
`SECRETSPEC_PASSBOLT_PRIVATE_KEY`, `SECRETSPEC_PASSBOLT_PASSPHRASE`: credentials
forwarded to the CLI (see [Authentication](#authentication)).
- `SECRETSPEC_PASSBOLT_CLI_PATH`: path to the `passbolt` binary when it is not
simply `passbolt` on `PATH`.
1 change: 1 addition & 0 deletions docs/src/content/docs/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ $ secretspec config init
env: Read-only environment variables
pass: Unix password manager with GPG encryption
protonpass: Proton Pass via official pass-cli
passbolt: Passbolt self-hosted password manager via go-passbolt-cli
lastpass: LastPass password manager
gcsm: Google Cloud Secret Manager
awssm: AWS Secrets Manager
Expand Down
16 changes: 16 additions & 0 deletions docs/src/content/docs/reference/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ protonpass://Work/{project}/{profile}/{key} # Custom vault and title temp
**Prerequisites**: `pass-cli`, authenticated with `pass-cli login` (or `pass-cli login --pat $PAT` for CI)
**Storage**: Note item titled `{project}/{profile}/{key}` inside the configured vault

## Passbolt Provider

**URI**: `passbolt://[name-template][?folder=<id>&server=<address>]` - Stores secrets in self-hosted Passbolt via the official `go-passbolt-cli`

```bash
passbolt:// # Default name (secretspec/{project}/{profile}/{key})
passbolt://secretspec/{project}/{profile}/{key} # Custom resource-name template
passbolt://?server=https://pass.example.com # Pin the server address
passbolt://?folder=<folder-id> # Create/scope resources in a folder
```

**Features**: Read/write, end-to-end encryption, self-hosted, `ref` by resource id or name (fields: `password`/`username`/`uri`/`description`)
**Prerequisites**: `passbolt` CLI, configured with `passbolt configure --serverAddress https://... --userPrivateKeyFile key.asc --userPassword <passphrase>`
**Storage**: Resource named `secretspec/{project}/{profile}/{key}`, value in the `password` field

## Google Cloud Secret Manager Provider

**URI**: `gcsm://PROJECT_ID` - Stores secrets in Google Cloud Secret Manager
Expand Down Expand Up @@ -189,6 +204,7 @@ export SECRETSPEC_PROVIDER="dotenv:///config/.env"
| Keyring | ✅ System encryption | System keychain | ❌ No |
| Pass | ✅ GPG encryption | Local filesystem | ❌ No |
| Proton Pass | ✅ End-to-end | Cloud (Proton) | ✅ Yes |
| Passbolt | ✅ End-to-end | Self-hosted (Passbolt server) | ✅ Yes |
| LastPass | ✅ End-to-end | Cloud (LastPass) | ✅ Yes |
| OnePassword | ✅ End-to-end | Cloud (OnePassword) | ✅ Yes |
| GCSM | ✅ Google-managed | Cloud (GCP) | ✅ Yes |
Expand Down
1 change: 1 addition & 0 deletions secretspec/src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ pub mod keyring;
pub mod lastpass;
pub mod onepassword;
pub mod pass;
pub mod passbolt;
pub mod protonpass;
#[cfg(feature = "vault")]
pub mod vault;
Expand Down
Loading
Loading