Skip to content

feat(core): v0.4 Phase 3 — timeout_secs + 1Password set safe-by-default#52

Merged
TechAlchemistX merged 1 commit intomainfrom
feat/v0.4-timeout-and-op-set-polish
Apr 20, 2026
Merged

feat(core): v0.4 Phase 3 — timeout_secs + 1Password set safe-by-default#52
TechAlchemistX merged 1 commit intomainfrom
feat/v0.4-timeout-and-op-set-polish

Conversation

@TechAlchemistX
Copy link
Copy Markdown
Owner

Summary

v0.4 Phase 3 lands per build-plan-v0.4. Two operational-polish changes:

Per-instance `timeout_secs` config override

  • New optional `timeout_secs = N` field on every backend's `[backends.]` config block. When set, the value (positive seconds) is applied to every fetch-class operation on that instance: `get`, `set`, `delete`, `list`, `history`. Defaults to `DEFAULT_GET_TIMEOUT` (30s) when absent.
  • The `check` (doctor) timeout deliberately does NOT consult this — `DEFAULT_CHECK_TIMEOUT` (10s) keeps doctor parallelism predictable across instances regardless of any per-instance fetch deadlines.
  • Implementation: new `Backend::timeout()` trait method (default returns `DEFAULT_GET_TIMEOUT`), new `optional_duration_secs` + `optional_bool` helpers in `secretenv-core::factory_helpers` exported for plugin authors. All 7 backends (local, aws-ssm, aws-secrets, vault, 1password, gcp, azure) read the field at factory time. Call sites in `runner::fetch_one` and `resolver::fetch_layer` wrap their backend-op futures with `with_timeout(backend.timeout(), ...)`.

1Password `set` is now safe-by-default

Closes the v0.3 TODO deferred from v0.2.4. Previously the 1password set path silently passed the secret value through `op item edit`'s `field=value` argv tokens (CV-1 exposure: visible via `/proc//cmdline` on multi-user Linux hosts). The `op` CLI still has no portable stdin-fed value form across the 1.x and 2.x generations, so the only honest fix is to flip the default.

v0.4 makes `set()` refuse with a clear error explaining the exposure and the two remediations:

  1. Edit the field manually with `op item edit`.
  2. Opt in by adding `op_unsafe_set = true` to `[backends.]` in `config.toml`.

The opt-in retains the previous argv-based behavior with the existing tracing warning. This is a behavior change for anyone running `secretenv registry set` against 1Password backends. Downloading v0.4.0 surfaces the new error immediately; the remediation is one config line. Documented as a pre-launch breaking change per the feedback_prelaunch_breaking_changes policy.

Tests

  • +7 factory_helpers tests for `optional_bool` + `optional_duration_secs` (none / some / wrong-type / zero / negative).
  • +2 aws-ssm factory tests locking `timeout_secs` propagation (positive-integer happy path + negative-integer rejection).
  • +2 1password tests locking the safe-default behavior (`set` refuses with `op_unsafe_set=false`; `set` proceeds with `op_unsafe_set=true`, same strict-mock argv as before).
  • All 7 backend test fixtures updated to construct with the new `timeout` field.
  • Workspace total: 505/505 (was 493; +12). fmt + clippy `--deny warnings` (CI-style form) + deny + audit clean.

Test plan

  • `cargo test --workspace` — 505/505 green
  • `cargo fmt --all -- --check` — clean
  • `cargo clippy --all-targets --workspace -- --deny warnings` — clean
  • `cargo deny check` — `advisories ok, bans ok, licenses ok, sources ok`
  • `cargo audit` — no advisories
  • CI to confirm cross-platform parity

Out of scope

  • CLI `get` / `registry get` call sites still call `backend.get/list` directly without a `with_timeout` wrap. The runner + resolver paths (the high-volume ones) are wrapped in this PR; the one-off interactive CLI commands are user-driven (Ctrl-C is the natural escape hatch). Worth a follow-up but not load-bearing for v0.4.
  • Live-backend integration smoke stays bundled with the v0.4 closing audit per the aggregate-release posture.

🤖 Generated with Claude Code

Two operational-polish changes per build-plan-v0.4 §Phase 3.

## Per-instance timeout_secs config override

Adds an optional `timeout_secs = N` field to every backend's
[backends.<name>] config block. When set, the value (positive
seconds) is applied to every fetch-class operation on that instance:
get, set, delete, list, history. Defaults to DEFAULT_GET_TIMEOUT
(30s) when absent.

The check (doctor) timeout deliberately does NOT consult this —
DEFAULT_CHECK_TIMEOUT (10s) keeps doctor parallelism predictable
across instances regardless of any per-instance fetch deadlines.

Implementation:
- New `Backend::timeout()` trait method, defaults to
  DEFAULT_GET_TIMEOUT. Backends override.
- New `optional_duration_secs` factory helper in secretenv-core
  exported alongside `optional_bool` for plugin authors. Validates
  positive integer and rejects zero/negative with a clear message.
- All 7 backends (local, aws-ssm, aws-secrets, vault, 1password,
  gcp, azure) read `timeout_secs` at factory time, store on the
  struct, and override Backend::timeout().
- Call sites in `runner::fetch_one` and `resolver::fetch_layer`
  now wrap their backend-op futures with
  `with_timeout(backend.timeout(), ...)`.

## 1Password set is now safe-by-default

Closes the v0.3 TODO that deferred from v0.2.4. Previously the
1password set path silently passed the secret value through
`op item edit`'s `field=value` argv tokens (CV-1 exposure: visible
via /proc/<pid>/cmdline on multi-user Linux hosts). The `op` CLI
still has no portable stdin-fed value form across the 1.x and 2.x
generations, so the only honest fix is to flip the default.

v0.4 makes set() refuse with a clear error explaining the exposure
and the two remediations: edit the field manually with `op item
edit`, or opt in by adding `op_unsafe_set = true` to
[backends.<name>] in config.toml. The opt-in retains the previous
argv-based behavior with the existing tracing warning.

Behavior change for anyone running `secretenv registry set` against
1Password backends; downloading v0.4.0 surfaces the new error and
the remediation is one config line. Documented as a pre-launch
breaking change per [[feedback_prelaunch_breaking_changes]].

Tests:
- 7 new factory_helpers tests for optional_bool +
  optional_duration_secs (none/some/wrong-type/zero/negative).
- 2 new aws-ssm factory tests locking timeout_secs propagation
  (positive-integer happy + negative-integer rejection).
- 2 new 1password tests locking the safe-default (set refuses
  with op_unsafe_set=false; set proceeds with op_unsafe_set=true,
  same argv as before).
- All 7 backend test fixtures updated to construct with the new
  timeout field.
- Workspace tests: 505/505 (was 493; +12).

Refs build-plan-v0.4 §Phase 3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: TechAlchemistX <mandeep@techalchemist.io>
@TechAlchemistX TechAlchemistX merged commit e6a03a6 into main Apr 20, 2026
7 checks passed
@TechAlchemistX TechAlchemistX deleted the feat/v0.4-timeout-and-op-set-polish branch April 20, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant