# lpm trust (/docs/packages/trust)



```bash
lpm trust <subcommand>
```

`trustedDependencies` (in `package.json > lpm`) is the allowlist that decides which dependency packages may run lifecycle scripts under the default `script-policy: deny`. `lpm trust` is the inspection-and-cleanup tool for that list.

To **add** entries, use [`lpm approve-scripts`](/docs/packages/approve-scripts) (the interactive review flow). `lpm trust` is for everything that comes after — auditing the list and pruning stale entries.

**Project trust only.** `lpm trust` operates on `package.json > lpm > trustedDependencies` exclusively. Global trust lives in a separate file (`~/.lpm/global/trusted-dependencies.json`) and is managed through [`lpm approve-scripts --global`](/docs/packages/approve-scripts#global-vs-project) — there is no `lpm trust --global` today. Under the hood the storage is independent: a global approval doesn't show up in `lpm trust diff`, and pruning the project list doesn't touch the global file.

## Subcommands [#subcommands]

| Subcommand                  | What it does                                                                        |
| --------------------------- | ----------------------------------------------------------------------------------- |
| [`diff`](#lpm-trust-diff)   | Show how the current `trustedDependencies` differs from the last install's snapshot |
| [`prune`](#lpm-trust-prune) | Remove entries whose package is no longer in the resolved tree                      |

## Flag Reference [#flag-reference]

| Command           | Flag            | Effect                                                                                     |
| ----------------- | --------------- | ------------------------------------------------------------------------------------------ |
| `lpm trust diff`  | `--json`        | Emit the diff envelope instead of human output. Same as global `--json` for this command.  |
| `lpm trust diff`  | `--assert-none` | Exit non-zero if any added, removed, or changed entries are present.                       |
| `lpm trust prune` | `-y`, `--yes`   | Skip the confirmation prompt. Required on non-TTY / CI when pruning would write.           |
| `lpm trust prune` | `--dry-run`     | Preview stale entries without writing `package.json`.                                      |
| `lpm trust prune` | `--json`        | Emit the prune envelope instead of human output. Same as global `--json` for this command. |

## `lpm trust diff` [#lpm-trust-diff]

```bash
lpm trust diff
lpm trust diff --assert-none
lpm trust diff --json
lpm trust diff --assert-none --json
```

Read-only. Compares the current `package.json > lpm > trustedDependencies` against the snapshot LPM CLI took on the last `lpm install`. Surfaces three classes of change:

* **Additions** — entries that weren't there last install. Potential silent PR poisoning vector ("someone added `evil-package` to the trust list — was that reviewed?")
* **Removals** — entries that were there but are now gone. Usually intentional cleanup, but worth a glance.
* **Same-key binding changes** — same `name@version` key, but a different `integrity` or `scriptHash`. Indicates the package contents changed without a version bump (re-publish, tampering).

The snapshot lives at `<project>/.lpm/trust-snapshot.json`, written by every successful `lpm install`. If the project has never been installed with LPM CLI, `diff` reports `"no prior snapshot"` and exits cleanly — there's no baseline to compare against yet.

`trust diff` is informational by default — it prints whatever it found. For a built-in CI gate, use `--assert-none`:

```bash
lpm trust diff --assert-none
```

That exits non-zero when any `added`, `removed`, or `changed` entry is present.

If you still want machine-readable output for bots or logs, `--json` works with the same gate:

```bash
lpm trust diff --json --assert-none
```

The JSON envelope: `success`, `schema_version`, `command`, `assertion_failed`, `diff_count`, `snapshot_captured_at`, `current_binding_count`, `added[]`, `removed[]`, `changed[]`. Each entry carries `key` (e.g., `esbuild@0.25.1`), `previous`, and `current` (the integrity / scriptHash before and after). When `--assert-none` fails in JSON mode, LPM CLI emits this same single diff envelope with `success: false`, `error_code: "trust_diff_assert_none"`, and exits non-zero.

| Flag            | Effect                                         |
| --------------- | ---------------------------------------------- |
| `--json`        | Machine-readable output for CI gating via `jq` |
| `--assert-none` | Exit non-zero if any diff entries are present  |

## `lpm trust prune` [#lpm-trust-prune]

```bash
lpm trust prune                   # interactive — prompts before writing
lpm trust prune --dry-run         # preview, don't write
lpm trust prune -y                # skip the prompt (required on non-TTY / CI)
lpm trust prune --json
```

Removes `trustedDependencies` entries whose package isn't in the resolved tree anymore. "No longer in the tree" means: `lpm.lock` has zero entries with this name (regardless of version). Per-version drift on a name that's still installed is **not** considered stale — that's drift, handled by the install-time gate, not by prune.

Entries become stale when:

* A dep was removed from `package.json` but its trust entry stayed
* A dep was renamed (the old name's pin is now orphaned)
* A dep was moved (e.g., from `dependencies` to `optionalDependencies` and never reinstalled)

`lpm trust prune` reads `lpm.lock` to determine what's installed. **If the lockfile is missing**, the command exits with `no lpm.lock found — run \`lpm install\` before pruning trust entries\` — refusing to prune from an empty installed-set (which would mark everything stale).

The interactive prompt confirms the removal list before writing. In CI / non-TTY contexts, `-y` is required — without it, prune errors with `lpm trust prune needs a TTY for confirmation. Pass \`--yes\` to ...\`.

`--dry-run` runs the analysis normally but doesn't touch `package.json`.

The JSON envelope: `success`, `schema_version`, `command`, `dry_run`, `mutated` (the actual final state — `false` on `--dry-run` or no-op), `stale_count`, `stale[]` (the keys removed).

| Flag          | Effect                                             |
| ------------- | -------------------------------------------------- |
| `-y`, `--yes` | Skip the confirmation prompt (required on non-TTY) |
| `--dry-run`   | Preview without writing                            |
| `--json`      | Machine-readable output                            |

## CI usage [#ci-usage]

```yaml
- run: lpm install --offline
- run: lpm trust diff --assert-none
- run: lpm trust prune --dry-run --json # informational — would prune anything?
```

`trust diff --assert-none` is the built-in drift gate: fail the build if `trustedDependencies` changed since the last reviewed install. Add `--json` if you also want structured output in CI logs.

`prune --dry-run` is for hygiene reports only — it always exits zero. Gate it the same way if you want to fail on stale entries:

```bash
lpm trust prune --dry-run --json | jq -e '.stale_count == 0'
```

## See also [#see-also]

* [`lpm approve-scripts`](/docs/packages/approve-scripts) — add entries to the trust list
* [`lpm rebuild`](/docs/packages/rebuild) — runs dependency scripts for trusted packages
* [`package.json` "lpm.trustedDependencies"](/docs/reference/package-json-lpm#trusteddependencies) — the file format
