envpkt 0.13.3 → 0.13.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -181,6 +181,15 @@ const result = boot() // decrypts sealed values, injects into process.env
181
181
 
182
182
  Mixed mode is supported — sealed values take priority, with fnox as fallback for keys without `encrypted_value`.
183
183
 
184
+ ### Where it injects: self-launched vs serverless
185
+
186
+ Whether envpkt can replace a cloud secret store depends on one thing: **do you control how the process starts?**
187
+
188
+ - **You launch it** (server, container, VM, k8s, systemd) → `envpkt exec -- yourapp` or `boot()` injects the decrypted values straight into the process environment. No cloud secret store needed: the sealed `envpkt.toml` ships with the app, and only the age key has to reach the runtime (N secrets collapse to 1 key).
189
+ - **A platform launches it** (Cloudflare Workers, AWS Lambda, Vercel) → you don't own the launch, and the `age` CLI can't run inside the per-request isolate, so the platform's secret store is unavoidable. envpkt becomes the source of truth that populates and audits that store — not the injector.
190
+
191
+ > Rule of thumb: **own the launch → `exec`/`boot`, no store. Platform owns the launch → store required, envpkt feeds and audits it.** Full details: [Runtime injection guide](https://envpkt.dev/guides/runtime-injection/).
192
+
184
193
  ## GitHub Actions
185
194
 
186
195
  A composite action resolves the credentials in `envpkt.toml` into the CI job — with secret values masked in the log — so later steps just see them as environment variables:
@@ -191,7 +200,7 @@ A composite action resolves the credentials in `envpkt.toml` into the CI job —
191
200
  # Sealed packets are decrypted with the `age` CLI (not preinstalled on runners).
192
201
  - run: sudo apt-get update && sudo apt-get install -y age
193
202
 
194
- - uses: jordanburke/envpkt@v0.12.0
203
+ - uses: jordanburke/envpkt@v0
195
204
  with:
196
205
  config: ./envpkt.toml
197
206
  strict: "true" # fail the build if a credential is expired/unhealthy
@@ -205,7 +214,36 @@ A composite action resolves the credentials in `envpkt.toml` into the CI job —
205
214
 
206
215
  **Inputs:** `config`, `version` (npm version to run, default `latest`), `strict`, `profile`.
207
216
 
208
- > Decrypting sealed packets requires the [`age`](https://github.com/FiloSottile/age) CLI on the runner (install it first, as above) — not needed if you only inject plaintext `[env.*]` defaults or resolve via fnox. Pin to a released tag (e.g. `@v0.12.0`); no moving major tag (`@v1`) is published yet. Node is assumed present; add `actions/setup-node` first to pin a version.
217
+ > Decrypting sealed packets requires the [`age`](https://github.com/FiloSottile/age) CLI on the runner (install it first, as above) — not needed if you only inject plaintext `[env.*]` defaults or resolve via fnox. Reference `@v0` for the moving major tag (re-pointed to each `0.x` release), or pin an exact release like `@v0.13.4` for immutability. `@v1` ships when envpkt reaches 1.0. Node is assumed present; add `actions/setup-node` first to pin a version.
218
+
219
+ ### Anti-rot CI gate
220
+
221
+ A hand-maintained `envpkt.toml` is documentation, and documentation rots. The fix is a failing build: each `--strict` check exits non-zero so a stale or drifted config blocks the merge. Each gate is **metadata-only** (no secret values) and targets a different failure mode — compose the ones that fit:
222
+
223
+ ```bash
224
+ # 1. Secret health — runs anywhere, no live env or age key needed.
225
+ # Fails on expired / stale (> lifecycle.stale_warning_days) / missing / missing-metadata.
226
+ envpkt audit --strict # exit 1 = degraded, 2 = critical
227
+
228
+ # 2. Cross-environment parity — keep dev/staging/prod tracking the same keys.
229
+ envpkt diff dev.envpkt.toml prod.envpkt.toml --exit-code
230
+
231
+ # 3. Drift vs the live environment — run where the env is actually populated
232
+ # (a deployed host or a pre-deploy step), NOT a bare CI runner: with no env
233
+ # set, every var reads as "missing" and the gate false-fails.
234
+ envpkt env check --strict # exit 1 on any drift (missing / untracked)
235
+ ```
236
+
237
+ **Where each belongs.** `audit --strict` and `diff --exit-code` are environment-independent — drop them in any PR/CI job as a merge gate. `env check --strict` compares the config against the _live_ environment, so it belongs in a pre-deploy step or a host healthcheck, after the env is populated (e.g. `eval "$(envpkt env export)"`), not in a stock CI runner.
238
+
239
+ ```yaml
240
+ # PR gate: block merges when the config rots (no secrets, no age key required)
241
+ - uses: jordanburke/envpkt@v0.13.4
242
+ with: { config: ./envpkt.toml, strict: "true" }
243
+ - run: envpkt diff dev.envpkt.toml prod.envpkt.toml --exit-code
244
+ ```
245
+
246
+ > Freshness in the sense of "verified live within N days" (a credential that still _authenticates_, not just one that hasn't _expired_ on paper) is a [verification](#) capability reserved for the hosted offering — `--strict` enforces everything checkable offline today.
209
247
 
210
248
  ## For agents and fleets
211
249
 
@@ -424,6 +462,20 @@ envpkt diff a.toml b.toml --format json # structured diff
424
462
  envpkt diff a.toml b.toml --exit-code # exit non-zero on any difference (CI drift gate)
425
463
  ```
426
464
 
465
+ ### `envpkt copy`
466
+
467
+ Copy a secret or env entry from one config to another. For a sealed secret, the value is unsealed with the **source's** age key and resealed for the **destination's** `identity.recipient` automatically — so you can move a credential between configs that use different keys without ever handling the plaintext yourself. Env entries (and secrets with no sealed value) copy as metadata only. The kind (secret vs env) is detected from where the key lives in the source.
468
+
469
+ ```bash
470
+ envpkt copy DATABASE_URL --from prod.envpkt.toml --to staging.envpkt.toml
471
+ envpkt copy DATABASE_URL --from prod.envpkt.toml --to staging.envpkt.toml --as DB_URL # rename on copy
472
+ envpkt copy PORT --to other.envpkt.toml # --from defaults to the resolved config here
473
+ envpkt copy API_KEY --to b.toml --force # overwrite if it already exists in the destination
474
+ envpkt copy API_KEY --to b.toml --dry-run # preview without writing
475
+ ```
476
+
477
+ `--from`/`--to` default to the config resolved for the current directory (and must already exist). On copy, `created` is reset to today and `last_rotated_at` is dropped (it's the source's rotation history). Copying a sealed secret needs the source key to unseal and the destination's `identity.recipient` to reseal.
478
+
427
479
  ### `envpkt exec`
428
480
 
429
481
  Run a pre-flight audit, inject secrets from fnox into the environment, then execute a command.