Files
omarchy/plugins/io.github.elevate08.qs-bitwarden-cli/docs/decisions/0003-request-deadline.md
T
asepharyana 1cdb82a76f Sync config from arch
- hypr/apps.lua
- hypr/autostart.lua
- hypr/envs.lua
- hypr/hyprland.lua
- hypr/hyprsunset.conf
- hypr/input.lua
- hypr/looknfeel.lua
- hypr/omasettings.lua
- hypr/xdph.conf
- omarchy/branding/about.txt
- omarchy/branding/screensaver.txt
- omarchy/extensions/omarchy-menu.jsonc
- omarchy/hooks/battery-low.d/play-warning-sound.sample
- omarchy/hooks/font-set.d/show-font-notification.sample
- omarchy/hooks/post-boot.d/weather.sample
- omarchy/hooks/post-update.d/install-voxtype.hook
- omarchy/hooks/post-update.d/setup-agent.hook
- omarchy/hooks/post-update.d/setup-fingerprint.hook
- omarchy/hooks/post-update.d/show-update-notification.sample
- omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample
- omarchy/hooks/theme-set.d/show-theme-notification.sample
- omarchy/shell.json
- omarchy/shell.toml
- omarchy/theme.name
- omarchy/themes/azure-glow/README.md
- omarchy/themes/azure-glow/alacritty.toml
- omarchy/themes/azure-glow/btop.theme
- omarchy/themes/azure-glow/hyprland.conf
- omarchy/themes/azure-glow/hyprlock.conf
- omarchy/themes/azure-glow/icons.theme
- … 269 more
2026-09-23 15:19:12 +07:00

95 lines
4.3 KiB
Markdown

# 3. A signing request gives the user two minutes, not thirty seconds
Date: 2026-08-27
## Status
Accepted. Adjusts the request-deadline figure in `docs/ideas/ssh-agent.md`
("Panel-to-Companion Contract"), which specified thirty seconds.
## Context
The control contract said:
> Reject overflow, give each request a 30-second deadline, and cancel it when
> its client disconnects.
Thirty seconds is ample for a machine and short for a person. A signing
request has to travel further than the socket: the panel opens or takes focus,
the user notices it, reads a key name and a `SHA256:` fingerprint, considers
which program is asking, and decides. During live testing against a real vault
that budget expired twice under a user who was doing nothing more unusual than
reading the prompt he had been asked to read. Both expiries were recorded as
refusals, which then fed the denial cooldown and suppressed further prompts —
so a deadline that was merely tight cascaded into signing being disabled.
A second problem was found at the same time and is the more serious of the
two. The socket server bounded its wait for the state loop's answer with the
same `CLIENT_IO_TIMEOUT` it used for reading a frame and writing a reply:
```rust
let bytes = match timeout(CLIENT_IO_TIMEOUT, response).await { .. };
```
Both were thirty seconds, so the two clocks expired together by coincidence
rather than by design. Raising only the approval deadline would have left the
client giving up first and the new deadline doing nothing — the human bound
would have been decorative. The two values were coupled without ever being
related.
## Decision
Three separate bounds, each sized for what it actually waits on.
| Bound | Value | Waits on |
|---|---:|---|
| `approvals::REQUEST_LIFETIME_MS` | 120s | a person deciding |
| `server::RESPONSE_TIMEOUT` | 150s | the state loop's answer, on behalf of a blocked client |
| `server::CLIENT_IO_TIMEOUT` | 30s | a socket read or write |
`RESPONSE_TIMEOUT` deliberately exceeds `REQUEST_LIFETIME_MS`, so the
companion's deadline is always what fires first and there is one authority on
when a request is over. A test asserts that ordering, and asserts the
literal 120s figure so that changing it stays a deliberate act rather than a
side effect.
The held-request deadline used while a vault unlock is pending is derived from
`REQUEST_LIFETIME_MS` rather than repeated, because unlocking asks more of the
user than approving does and certainly needs no less time.
## Consequences
**A blocked client may now wait up to two minutes.** In practice it will not:
the mechanism that actually reclaims a request promptly is the client
disconnect, which the server watches for while a request is pending. Pressing
Ctrl-C on a `git push` ends the request immediately, and the panel's prompt is
withdrawn with it. The deadline is the backstop for a client that neither
answers nor leaves.
**The four-request bound is unchanged**, so at most four requests can be
waiting at once regardless of how long each may wait. A same-UID process can
still occupy those slots with junk requests and delay a legitimate one; that
was already inside the threat model this feature does not defend against, and
a longer deadline widens the window without changing the conclusion.
**Two minutes is still a deadline.** A request that nobody answers is refused,
the client is told, and the prompt comes down. Removing the bound entirely
would leave prompts and blocked clients accumulating with nothing to clear
them.
## Alternatives considered
- **Keep 30s and make the panel more attention-grabbing.** Rejected: the
design explicitly forbids desktop notifications in v1, and the remaining
levers (opening and focusing the panel) are already used.
- **Restart the clock when the prompt is first displayed.** Fairer in
principle, since the wait should start when the user could first act. It
needs the panel to report display state back to the companion, which adds a
control message and a way for a wrong answer to extend a deadline. Not worth
the surface for the benefit.
- **Make it configurable.** Another setting for something almost nobody would
tune, and a badly chosen value degrades either usability or the bound. The
figure is documented here instead.
- **Remove the deadline while the panel is open and focused.** Attractive, but
it makes the bound depend on window state the companion cannot verify.