gloves 0.5.11

seamless secret manager and handoff
Documentation
# Gloves CLI Bootstrap Config Spec (`.gloves.toml`)

Status: Implemented (`v0.2.x`)
Target release: `v0.2.x`
Owner: `gloves` CLI/runtime

## Implementation Status

Implemented now:

- `src/config.rs` parser and validator for `.gloves.toml`
- Config precedence and discovery resolver (`flag` / `env` / `discovered` / `none`)
- Strict validation for schema, agent policies, daemon/default values, and path literals
- Unix permission checks for config files, including symlink rejection
- Agent path visibility resolver API (`GlovesConfig::agent_paths`)
- Integration test suite: `tests/config_parser.rs`
- CLI flags: `--config`, `--no-config`, `--vault-mode`
- CLI commands: `gloves config validate`, `gloves access paths`, `gloves audit`
- Runtime wiring for effective root/defaults (`set`, `request`, `daemon`, `vault`)
- Vault mode enforcement (`auto` / `required` / `disabled`) with dependency checks
- Config-driven secret pipe URL policies under `[secrets.pipe.commands.<command>]`
- CLI integration coverage for bootstrap/config/access/vault mode paths

Pending from this spec:

- none

## 1. Problem

`gloves` currently requires repeated CLI flags (for example `--root`) and has no first-class bootstrap config file.

We need a repository-local config model like `openclaw.json`:

- predictable bootstrap from a checked-in config file
- explicit secure/private path definitions
- explicit agent access visibility for private paths
- strict permissions for config and sensitive directories

## 2. Goals

- Add `.gloves.toml` as the default bootstrap config file.
- Allow explicit config file path via CLI.
- Add explicit vault runtime mode (`auto` / `required` / `disabled`) for better operator control.
- Keep secure permissions as a hard invariant.
- Provide an operator-visible command to show agent access to private paths.
- Keep current behavior backward compatible when no config file exists.

## 3. Non-goals

- No secret values in config.
- No replacement of `pass` or vault crypto internals.
- No dynamic policy engine.
- No implicit trust handoff beyond explicit config + existing audit trail.

## 4. CLI Surface

### 4.1 Global options

Add global options to `gloves`:

- `--config <PATH>`: absolute or relative path to config TOML
- `--no-config`: disable config discovery and use current defaults only
- `--vault-mode <auto|required|disabled>`: one-shot override for vault runtime behavior

### 4.2 Environment variable

- `GLOVES_CONFIG=<PATH>` provides config path when `--config` is not set.

### 4.3 New subcommands

Add:

- `gloves config validate`
  - Validates schema, permissions, and resolved paths.
  - Exit `0` on success, non-zero on failure.
- `gloves access paths --agent <AGENT_ID> [--json]`
  - Shows path-level access visibility for one agent.
  - Intended for operators to audit private path reachability.

## 5. Config Discovery and Precedence

Config selection order (first match wins):

1. `--no-config` set: skip config load entirely.
2. `--config <PATH>`.
3. `GLOVES_CONFIG` env value.
4. Auto-discovery: `.gloves.toml` in current directory, then parent directories up to filesystem root.
5. No config found: use existing defaults.

Notes:

- If an explicit path is provided (`--config` or `GLOVES_CONFIG`) and file is missing, fail fast.
- If auto-discovery finds no file, continue with defaults.

## 6. `.gloves.toml` Schema (v1)

```toml
version = 1

[paths]
# Equivalent to current --root default if omitted.
root = ".openclaw/secrets"

# Named private path aliases. Values may be absolute or config-relative.
[private_paths]
password_store = "~/.password-store"
workspace_private = "./.private"
runtime_root = ".openclaw/secrets"

[daemon]
bind = "127.0.0.1:7788"
io_timeout_seconds = 5
request_limit_bytes = 16384

[vault]
# Recommended default: "auto"
# - auto: vault commands work when binaries exist; otherwise return actionable errors.
# - required: config validation/runtime fails when vault binaries are missing.
# - disabled: vault commands are blocked intentionally.
mode = "auto"

[defaults]
agent_id = "default-agent"
secret_ttl_days = 30
vault_mount_ttl = "1h"
vault_secret_ttl_days = 365
vault_secret_length_bytes = 64

# Use `gloves secrets set ... --ttl never` when one secret should not expire.

# Agent path visibility and allowed operations.
# Agent IDs must satisfy existing AgentId validation rules.
[agents.default-agent]
paths = ["runtime_root", "workspace_private"]
operations = ["read", "write", "list", "mount"]

[agents.agent-b]
paths = ["runtime_root"]
operations = ["read", "list"]

# Optional per-agent secret ACLs.
# Pattern forms:
# - "*" (all secrets)
# - "namespace/*" (all descendants)
# - "exact/secret-id" (one secret)
[secrets.acl.default-agent]
paths = ["github/*", "shared/*"]
operations = ["read", "write", "list", "revoke", "request", "status", "approve", "deny"]

[secrets.acl.agent-relationships]
paths = ["contacts/*", "shared/contacts/*"]
operations = ["read", "write", "list", "request", "status"]

[secrets.acl.agent-workflows]
paths = ["workflows/*", "shared/webhooks/*"]
operations = ["read", "write", "list", "request", "status", "approve", "deny"]

# Optional per-command URL policy for `get --pipe-to-args`.
# - require_url=true enforces that the template contains at least one URL argument.
# - url_prefixes restrict URL args to approved prefixes.
[secrets.pipe.commands.curl]
require_url = true
url_prefixes = [
  "https://api.example.com/v1/",
  "http://127.0.0.1:4001/carddav/"
]
```

Secret ACL operation mapping:

- `read`: `gloves secrets get`
- `write`: `gloves secrets set`
- `list`: `gloves list`
- `revoke`: `gloves secrets revoke`
- `request`: `gloves request`
- `status`: `gloves secrets status`
- `approve`: `gloves requests approve`
- `deny`: `gloves requests deny`

Secret pipe URL policy mapping:

- `[secrets.pipe.commands.<command>]`: policy entry keyed by executable name
- `require_url`: when `true`, `--pipe-to-args` templates must include at least one `http://` or `https://` URL argument
- `url_prefixes`: allowed URL prefixes for URL arguments in that template
- Behavior applies to `get --pipe-to-args` only

## 7. Validation Rules

### 7.1 File and ownership permissions

On Unix:

- config file MUST exist as a regular file.
- config file mode MUST NOT allow group/world write (`mode & 0o022 == 0`).
- if config defines any `private_paths`, file mode SHOULD be `0600` or `0640`.
- referenced runtime directories/files created by gloves continue to enforce existing private modes (`0700` dirs, `0600` files).

On non-Unix:

- enforce existing secure write helpers and skip Unix mode checks.

### 7.2 Path safety

- Resolve `~` to home directory.
- Resolve relative paths against the config file directory.
- Canonicalize for display and access checks where possible.
- Reject empty path values.
- Reject duplicate `private_paths` aliases.
- Reject unknown alias references under `[agents.<id>.paths]`.

### 7.3 Agent access model

- Unknown agent in `gloves access paths --agent` returns `NotFound`.
- Operations are constrained to enum: `read`, `write`, `list`, `mount`.
- Access output is visibility metadata only; it does not bypass existing secret/vault authorization.
- Secret ACL policy is optional under `[secrets.acl.<agent>]`.
- When secret ACL policy is configured, only matching path patterns + operations are permitted.

### 7.4 Vault mode and dependency checks

- `vault.mode` must be one of `auto`, `required`, `disabled`.
- Runtime dependencies for vault mode checks: `gocryptfs`, `fusermount`, `mountpoint`.
- `auto`:
  - non-vault commands run normally regardless of vault dependencies.
  - vault commands attempt execution and fail with actionable missing-binary errors when deps are absent.
- `required`:
  - `gloves config validate` fails if required vault binaries are missing.
  - runtime bootstrap for vault-enabled flows must fail fast when binaries are missing.
- `disabled`:
  - vault commands are blocked with explicit error.
  - non-vault commands remain available.

### 7.5 Secret pipe URL policy checks

- Command keys under `[secrets.pipe.commands]` must be bare executable names (`[a-zA-Z0-9._+-]`).
- Each command policy must either:
  - set `require_url = true`, or
  - define at least one `url_prefixes` entry.
- `url_prefixes` entries:
  - must be non-empty
  - must include an authority and must not contain whitespace in authority
  - must start with `http://` or `https://`
  - must not include query (`?`) or fragment (`#`) components
  - must not contain duplicates
- At runtime, if config defines a policy for a command, that policy is applied before env URL policy fallback.
- Runtime matching is strict by scheme + authority + path-segment prefix.
  - `https://api.example.com` does not match `https://api.example.com.evil/...`
  - `/v1` does not match `/v10`

## 8. Effective Config and Overrides

- CLI flags continue to override config values for that invocation.
- `--root` overrides `[paths].root`.
- `--vault-mode` overrides `[vault].mode`.
- Command-specific options (for example daemon bind, vault ttl, agent id) override config defaults.
- Effective value resolution should be deterministic and auditable.

## 9. Output Contract for `gloves access paths`

### 9.1 JSON mode

`gloves access paths --agent agent-b --json` returns:

```json
{
  "agent": "agent-b",
  "paths": [
    {
      "alias": "runtime_root",
      "path": "/abs/path/.openclaw/secrets",
      "operations": ["read", "list"]
    }
  ]
}
```

### 9.2 Text mode

Human-readable table:

- `alias`
- `resolved path`
- `operations`

## 10. Backward Compatibility

- No `.gloves.toml`: current behavior remains unchanged.
- Existing scripts that pass `--root` continue working.
- Current default constants remain fallback values.
- `vault.mode = "auto"` preserves existing operational behavior.

## 11. Security Considerations

- Config can contain private path metadata; enforce strict file permissions.
- Never persist secret material in `.gloves.toml`.
- Always treat config contents as untrusted input and validate fully.
- Audit events SHOULD include config path source (`flag`, `env`, `discovered`, `none`) for sensitive operations.

## 12. Implementation Outline

1. Done: add config types and parser module (`src/config.rs`).
2. Done: add bootstrap resolver for discovery + precedence.
3. Done: integrate effective config into CLI runtime initialization.
4. Done: add `config validate` and `access paths` commands.
5. Done: enforce `vault.mode` semantics and dependency checks in CLI runtime.
6. Done: add permission/path validation and error mapping.
7. Done: update README and command reference.

## 13. TDD Plan

Add tests before implementation.

### Unit tests

- `config_roundtrip_v1`
- `config_discovery_prefers_flag`
- `config_discovery_prefers_env_over_discovery`
- `config_discovery_walks_parent_dirs`
- `config_validate_rejects_unknown_agent_path_alias`
- `config_validate_rejects_duplicate_private_alias`
- `config_validate_rejects_invalid_operation`
- `config_resolve_relative_paths_against_file_dir`
- `config_resolve_home_expansion`
- `config_vault_mode_defaults_to_auto`
- `config_validate_rejects_invalid_vault_mode`

### Unix permission tests

- `config_validate_rejects_group_world_writable_file`
- `config_validate_accepts_private_modes`

### CLI integration tests

- `cli_bootstrap_uses_discovered_gloves_toml`
- `cli_bootstrap_uses_explicit_config_path`
- `cli_bootstrap_no_config_keeps_existing_defaults`
- `cli_config_validate_success`
- `cli_config_validate_failure_invalid_alias`
- `cli_access_paths_json`
- `cli_access_paths_unknown_agent_fails`
- `cli_vault_mode_disabled_blocks_vault_commands`
- `cli_vault_mode_required_fails_without_binaries`
- `cli_vault_mode_auto_keeps_non_vault_commands_available`

## 14. Open Questions

- Should `gloves access paths` include inherited/default policy blocks, or only explicit per-agent entries?
- Should config source (`flag/env/discovered`) be emitted in `gloves verify` output?
- Should we allow a strict mode that requires config presence (`--require-config`)?