# tsafe-agent

Local unlock-session agent for [tsafe](https://crates.io/crates/tsafe-cli).

Holds an unlocked vault session over a named pipe (Windows) or Unix socket
(macOS / Linux) so subsequent `tsafe` commands skip the password prompt during
the TTL window.

`tsafe-agent` is a local IPC surface, not a telemetry service. It holds one
profile's unlock state in memory for the configured TTL and does not send
product analytics, crash reports, update pings, secret names, or secret values
to a vendor service.

In Agent Authority Firewall deployments, this agent is the local unlock-state
companion used by safe command execution and bound MCP status checks. The
bound MCP server still runs through a fixed authority contract and workdir; the
agent does not turn the MCP server into a model-facing vault browser.

## Install

Standalone Cargo install:

```
cargo install tsafe-agent
```

Some release channels bundle `tsafe-agent` beside the main `tsafe` binary. A
plain `cargo install tsafe-cli` installs the compiled CLI only; it does not
install this companion binary unless that channel says so explicitly. The
meta-crate path `cargo install tsafe` builds the bundled suite.

## Usage

Start the agent and unlock the vault:

```sh
eval $(tsafe agent unlock --ttl 8h)
```

`eval` is required because the agent prints the socket address and session
token as a shell assignment. The token is never written to shell history this
way.

Once the agent is running, subsequent commands in the same shell session skip
the password prompt:

```sh
tsafe get MY_SECRET
tsafe exec -- my-app
```

To unlock with a specific profile:

```sh
eval $(tsafe agent unlock --profile work --ttl 4h)
```

## TTL

Two TTL values control agent lifetime:

- **Idle TTL** — the agent exits if no request arrives within this window.
- **Absolute TTL** — a hard deadline regardless of activity. Set via
  `--ttl`; defaults to 8 hours.

A background watchdog thread enforces the absolute deadline and wakes the
accept loop when it fires so the agent exits promptly.

## Status

```sh
tsafe agent status --json
```

Returns machine-readable agent state including the socket path, profile, and
time remaining.

## Password acquisition

The agent acquires the vault password using this priority chain:

1. **OS keychain** — macOS Keychain or Linux Secret Service, using the same
   entry as `tsafe biometric enable`. Single call, no double-prompt.
2. **`TSAFE_VAULT_PASSWORD` env var** — accepted but warned loudly because the
   value is visible in `/proc/self/environ` and `docker inspect`. Prefer the
   keychain.
3. **Interactive TTY prompt** — via `rpassword`, the original behaviour.

## Security model

- **PID verification** — on each `OpenVault` request, the agent checks that
  the `requesting_pid` field in the JSON matches the actual PID of the
  connecting process (via `SO_PEERCRED` on Linux, `getpeereid` + `LOCAL_PEERPID`
  on macOS, `GetNamedPipeClientProcessId` on Windows). A PID mismatch is
  rejected.
- **Socket permissions** — the Unix socket file is created with mode `0600`
  (owner-only). On Windows, only one named-pipe instance is created per
  session.
- **Zeroize on drop** — the vault password is held in a `Password(String)`
  newtype that implements `ZeroizeOnDrop`; the memory is overwritten before
  deallocation.
- **Signal handling (Unix)** — `SIGTERM` and `SIGINT` set the stop flag so
  the accept loop drains cleanly and the `SocketCleanup` RAII guard unlinks
  the socket file. `SIGHUP` is ignored so terminal hangup does not kill the
  agent mid-session.

## CellOS broker (Unix only)

On macOS and Linux the agent also binds a second Unix socket for the CellOS
subsystem. CellOS callers authenticate by UID match (`SO_PEERCRED` / `getpeereid`)
and a per-cell token. Supported requests:

- `Resolve` — look up a secret by key and cell ID; registers the cell on first
  call and validates the token on subsequent calls.
- `RevokeForCell` — mark a cell ID as revoked; subsequent `Resolve` calls for
  that cell are rejected.

Both operations are appended to the profile audit log.

## License

Same as the tsafe workspace — see the repository root.
