Metadata-Version: 2.4
Name: pocket-protector
Version: 26.3.0
Summary: Handy secret management system with a convenient CLI and readable storage format.
Author: Mahmoud Hashemi
Author-email: Kurt Rose <kurt@kurtrose.com>
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
License-File: LICENSE.txt
Requires-Dist: attrs
Requires-Dist: boltons
Requires-Dist: PyNaCl
Requires-Dist: ruamel.yaml
Requires-Dist: schema
Requires-Dist: face>=26.0.1
Project-URL: Changelog, https://github.com/mahmoud/pocket_protector/blob/master/CHANGELOG.md
Project-URL: Documentation, https://pocket-protector.readthedocs.io/
Project-URL: Homepage, https://github.com/mahmoud/pocket_protector
Project-URL: Repository, https://github.com/mahmoud/pocket_protector

# Pocket Protector 🔏

Pocket Protector provides a cryptographically-strong, serverless secret
management infrastructure. Pocket Protector enables *key management as
code*, securely storing secrets in a versionable format, right
alongside the corresponding application code.

> **Note:** The canonical repository is now [github.com/mahmoud/pocket_protector](https://github.com/mahmoud/pocket_protector). The original home was [github.com/SimpleLegal/pocket_protector](https://github.com/SimpleLegal/pocket_protector).

> See the [debut meetup talk](https://www.youtube.com/watch?v=7Zhxu_4qhyM) for an introduction.

Pocket Protector's approach lets you:

* Leverage existing user, versioning, and backup systems, with no
  infrastructure to set up
* Support multiple environments
* Integrate easily with existing key management systems
  (AWS/Heroku/GitHub Actions)

Pocket Protector also:

* Minimizes the number of passphrases and keys your team has to
  remember and secure
* Beats the heck out of hardcoded plaintext secrets!


## Installation

Right now the easiest way to install Pocket Protector across all
platforms is with `pip`:

```sh
pip install pocket_protector
```

This will install the command-line application `pocket_protector`,
conveniently shortened to `pprotect`, which you can use to test your
installation:

```sh
$ pprotect version
pocket_protector version 26.0.0
```

Once the above is working, we're ready to start using Pocket Protector!


## Usage

Pocket Protector aims to be as easy to use as a secret management
system can get. That said, understanding security takes time, so be
sure to go beyond the quick start and reference below, and read our
[User Guide](https://github.com/mahmoud/pocket_protector/blob/master/USER_GUIDE.md)
as well.


### Quick start

Pocket Protector's CLI is its primary interface. It presents a compact
set of commands, each representing one action you might want to take
on a secret store. Basic usage starts on your laptop, inside your
checked out code repository:

```sh
# create a new protected file
pprotect init

# add a key domain
pprotect add-domain

# add a secret to the new key domain
pprotect add-secret

# decrypt and read out the secret
pprotect decrypt-domain
```

Each of these will prompt the user for credentials when necessary. See
the section below on passing credentials.

When you're done updating the secret store, simply `git commit` (or
equivalent) to save your changes. Should you make any mistakes, use
your VCS to revert the changes.


### Passing credentials

By default, the `pocket_protector` command prompts you for credentials
when necessary. But convenience and automation both demand more
options, highlighted here:

* Command-line Flags
  * `-u / --user USER_EMAIL` - specifies the user email for subcommands which require it
  * `--passphrase-file PATH` - specifies a path to a readable file
    which contains the passphrase (useful for mount-based key
    management, like Docker)
  * `--domain DOMAIN` - specifies the name of the domain
  * `--non-interactive` - causes the command to fail when credentials cannot be gotten by other means
  * `--env-prefix PREFIX` - sets the env var prefix for credential
    lookup (default: `PPROTECT`). When set, credentials are read from
    `PREFIX_USER` and `PREFIX_PASSPHRASE` instead of the defaults
  * `--key-type TYPE` - custodian key type: `hard` (default, slow KDF for
    production), `fast` (quick KDF for development/testing), or `raw` (no KDF,
    generated hex key for automation)

* Environment variables
  * `PPROTECT_USER` - environment variable which contains the user email
  * `PPROTECT_PASSPHRASE` - environment variable which contains the
    passphrase (useful for environment variable-based key management,
    used by AWS/Heroku/many CI systems)
  * `PPROTECT_ENV_PREFIX` - sets the default `--env-prefix` without
    needing the flag (e.g., `PPROTECT_ENV_PREFIX=MYAPP` makes
    credential lookup use `MYAPP_USER` and `MYAPP_PASSPHRASE`)

In all cases, flags take precedence over environment variables, and
both take precedence over and bypass interactive prompts. In the event
an incorrect credential is passed, `pocket_protector` does *not*
automatically check other sources.

#### Custom env var prefix

In environments where multiple pocket_protector-managed projects coexist,
use `--env-prefix` to namespace credential env vars per project:

```sh
# Project A
export PROJECTA_USER=alice@example.com
export PROJECTA_PASSPHRASE=secret_a
pprotect decrypt-domain prod --env-prefix PROJECTA

# Project B (simultaneously)
export PROJECTB_USER=bob@example.com
export PROJECTB_PASSPHRASE=secret_b
pprotect decrypt-domain staging --env-prefix PROJECTB
```

The default prefix remains `PPROTECT`, so existing workflows are unaffected.
You can also set `PPROTECT_ENV_PREFIX` in your environment to avoid repeating
the flag on every invocation:

```sh
export PPROTECT_ENV_PREFIX=PROJECTA
export PROJECTA_USER=alice@example.com
export PROJECTA_PASSPHRASE=secret_a
pprotect decrypt-domain prod   # uses PROJECTA_USER / PROJECTA_PASSPHRASE
```

The `--env-prefix` flag always takes precedence over `PPROTECT_ENV_PREFIX`.
When using `pprotect exec`, both the custom prefix vars
and the default `PPROTECT_*` vars are scrubbed from the child process.


See our
[User Guide](https://github.com/mahmoud/pocket_protector/blob/master/USER_GUIDE.md)
for more usage tips.


### Command summary

Here is a summary of all commands:

```
usage: pprotect subcommand [FLAGS]

Subcommands:

  init                  create a new protected
  version               print the PocketProtector version and exit
  list-audit-log        print a list of actions from the audit log, one per line

  Access Management:
    add-key-custodian   add a new key custodian to the protected
    list-user-secrets   display domains and secrets accessible to the
                        authenticated user
    set-key-custodian-passphrase
                        update a key custodian passphrase
    rekey-custodian     change a custodian key type (hard/fast/raw) and
                        passphrase, re-encrypting all owned domains

  Domain Management:
    add-domain          add a new domain to the protected
    add-owner           add a key custodian to the owner list of a specific domain
    list-domains        print a list of domain names, if any
    rotate-domain-keys  rotate the internal encryption keys for a given domain
    migrate-owner       grant a custodian ownership of all domains you own
    rm-owner            remove a key custodian from the owner list of a domain
    rm-domain           remove a domain and all of its keys from the protected

  Secret Management:
    add-secret          add a secret to a domain
    list-domain-secrets print a list of secret names for a given domain
    list-all-secrets    print a list of all secret names, along with the
                        domains that define each
    update-secret       update a secret value in a domain
    rm-secret           remove a secret from a domain

  Secret Access:
    decrypt-domain      decrypt and display cleartext for a domain, with
                        optional format and secret filter
    exec                run a command with decrypted domain secrets injected
                        as environment variables
```


## Agent & Automation Security

Pocket Protector is commonly used in CI/CD pipelines and increasingly
alongside AI coding agents. In these contexts, secret hygiene matters
more than usual. Any process with shell access can read environment
variables, `cat .env`, or inspect `/proc/*/environ`.

### Credential injection: from safest to weakest

1. **`pprotect exec`** (safest): decrypts a domain and injects
   secrets as env vars into a child process. The custodian passphrase
   is scrubbed from the child environment. Secrets exist only in the
   child process memory, never on disk or in the parent env.

   ```sh
   pprotect exec --domain prod -- ./myapp --flag arg
   ```

2. **`--passphrase-file`** from a restricted mount: store the
   passphrase on a tmpfs or Docker secret mount with `0400`
   permissions. Keeps the passphrase off the command line and out of
   the process environment.

   ```sh
   pprotect decrypt-domain prod --passphrase-file /run/secrets/pp_pass
   ```

3. **`PPROTECT_PASSPHRASE` env var** (simplest): the classic option
   but not the safest. Readable by any subprocess, including AI agents, build
   scripts, and debug tooling. Use only when other options are not
   available.

### Output formats for `decrypt-domain`

`decrypt-domain` supports `--output-format json` (default), `--output-format env`
(dotenv-style), and `--output-format shell` (`eval`-able exports). Use
`--secret SECRET_NAME` to extract a single value.

Secret names are case-sensitive and stored exactly as provided. The
validation rule is: start with a letter, then ASCII letters, digits,
hyphens, or underscores (e.g. `db-pass`, `API_KEY`, `tls-cert`).

```sh
# JSON (default)
pprotect decrypt-domain prod

# .env format
pprotect decrypt-domain prod --output-format env

# Shell export format
eval $(pprotect decrypt-domain prod --output-format shell)

# Single secret, raw value (name must match exactly)
db_pass=$(pprotect decrypt-domain prod --secret db-pass)
```

### What Pocket Protector is not

Pocket Protector manages **static deploy-time secrets** -- database
passwords, API keys, TLS certificates. It is not a runtime credential
manager. For dynamic credentials (OAuth tokens, short-lived sessions,
PKCE flows), use a runtime credential manager alongside Pocket
Protector.

Other explicit non-goals:

* **Network daemon / SaaS mode** -- serverless is the value prop
* **Time-limited credentials** -- no clock-based expiry; use
  `pprotect exec` to limit secret lifetime to a process
* **Per-secret access control** -- domains are the access boundary
* **MCP server mode** -- use `pprotect exec` to inject secrets into
  MCP server processes at startup

### Security note on `pprotect exec`

An agent or process that can run arbitrary commands could call
`pprotect decrypt-domain` directly. `exec` reduces *accidental*
exposure (logged output, env dumps, process listings), not adversarial
exfiltration by a fully compromised agent. Defense in depth still
applies: restrict filesystem access, use scoped custodians, and audit
the protected.yaml change log.


## Design

The theory of operation is that the `protected.yaml` file consists of
"key domains" at the root level. Each domain stores data encrypted by
a keypair. The public key of the keypair is stored in plaintext, so
that anyone may encrypt and add a new secret. The private key is
encrypted with the owner's passphrase. The owners are known as "key
custodians", and their private keys are protected by passphrases.

Secrets are broken up into domains for the purposes of granting
security differently. For example, `prod`, `dev`, and `stage` may all
be different domains. Protected stores may have as few or as many
domains as the team and application require.

To allow secrets to be accessed in a certain environment, Pocket
Protector must be invoked with a user and passphrase. As long as the
credentials are correct and the user has permissions to a domain, all
secrets within that domain are unlocked.

Passphrase security will depend on the domain. For instance, a domain
used for local development may set the passphrase as an environment
variable, or hardcode it in a configuration file.

On the other hand, a production domain would likely require manual
entry of an authorized release engineer, or use AWS/GCP/Heroku key
management solutions to inject the passphrase.

for prod domains, use AWS / heroku key management to store
the passphrase

An application / script wants to get its secrets:
```python
# at initialization
secrets = KeyFile.decrypt_domain(domain_name, Creds(name, passphrase))
# ... later to access a secret
secrets[secret_name]
```

An application / script that wants to add / overwrite a secret:
```python
KeyFile.from_file(path).with_secret(
    domain_name, secret_name, value).write()
```

Note -- the secure environment key is needed to read secrets, but not write them.
Change management on secrets is intended to follow normal source-code
management.

File structure:
```yaml
[key-domain]:
  meta:
    owners:
      [name]: [encrypted-private-key]
    public_key: [b64-bytes]
    private_key: [b64-bytes]
  secret-[name]: [b64-bytes]
key-custodians:
  [name]:
    public-key: [b64-bytes]
    encrypted-private-key: [b64-bytes]
```


### Threat model

An attacker is presumed to be able to read but not write the contents
of `protected.yaml`. This could happen because a developer's laptop
is compromised, GitHub credentials are compromised, or (most likely)
Git history is accidentally pushed to a publicly acessible repo.

With read access, an attacker gets environment and secret names,
and which secrets are used in which environments.

Neither the file as a whole nor individual entries are signed,
since the security model assumes an attacker does not have
write access.


### Notes

Pocket Protector is a streamlined, people-centric secret management
system, custom built to work with distributed version control systems.

* Pocket Protector is a data protection tool, not a change management
  tool. While it has convenient affordances like an informal
  `audit_log`, Pocket Protector is meant to be used in conjunction with
  your version management tool. Signed commits are a particularly good
  complement.
* Pocket Protector is designed for single-user usage. This is not a
  scaling limitation as much as it is a scaling feature. Single-user
  means that every `pprotect` command needs at most one credentialed
  user present. No sideband communication is required, minimizing
  leakage, while maintaining a system as distributed as your version
  management.


## FAQ


### Securing Write Access

Pocket Protector does not provide any security against unauthorized writes
to the `protected.yaml` file, by design. Firstly, without any Public Key Infrastructure,
Pocket Protector is not a good basis for cryptographic signatures. (An attacker
that modifies the file could also replace the signing keypair with their own;
the only way to detect this would be to have a data-store outside of the file.)

Secondly -- and more importantly -- the Git or Mercurial repository already has
good controls around write access. All changes are auditable, authenticated with
ssh keypairs or user passphrases. For futher security, consider using signed commits:

* https://git-scm.com/book/id/v2/Git-Tools-Signing-Your-Work
* https://help.github.com/articles/signing-commits-using-gpg/
* https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/index.html

