fix(client): re-validate OSC 8 activation and stop logging the URI #62
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!62
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/osc8-activation-13-v2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #13.
Supersedes #60: that branch was behind
mainand could not be rebase-merged(a
CHANGELOG.mdconflict), and force-pushing it was not an option, so thesame 24 commits were rebased onto current
mainhere.Summary
OSC 8 activation now crosses a typed boundary.
felis-client-coregainsActivationTarget, a validated newtype that re-checks the scheme allowlist andrejects NUL, C0/C1 controls, and bidi controls at activation time, so a URI
stored by any future grid path cannot reach a platform launcher as a raw string.
The Linux (
xdg-open), macOS (open), and Windows (ShellExecuteW) launcherstake only that type. Activation logging is reduced to outcome, scheme class, and
length — the URI itself is never logged, and
ActivationTarget'sDebugredacts it too.
While the activation modifier is held, a control-safe and bidi-safe preview
overlay shows the target: the renderer sanitizes the text, marks a clipped
preview, and the bottom-bar precedence rules keep the preview from being
overwritten or silently shortened by a preedit or by producer ink (an image
placement no longer claims a row a chrome bar holds). CONTROL is kept held when
the launcher never starts or the activation is refused.
Activation is tied to the preview it promises: it arms only on the frame that
actually showed the preview, refuses to arm when the atlas cut that frame
short, and the hovered cell is re-derived whenever the grid moves under it, so
a scrolled-away link cannot be activated. The hover is re-read only on frames
that can move it.
Doc cascade
docs/explanation/security-model.md— the activation boundary, the loggingrule, and the rejected alternatives.
docs/reference/security-audits.md,docs/reference/spec.md— the resultingfacts and the requirement wording.
docs/explanation/input.md,docs/reference/keybindings.md— the modifier-heldpreview and its interaction with preedit.
docs/explanation/rendering/pipeline.md, plus the Kitty graphicsreference/explanation twins — the chrome-row reservation and the clipping mark.
CHANGELOG.md— user-affecting behavior.Verified: just check green (fmt, clippy, nextest 3068 passed, deny), pi review PASS.
security-model.md and REQ-910 described only the grid-side scheme filter; they now state the independent client-side re-check, the rejected classes (interior NUL, other control chars, bidi codepoints), the Ctrl-hover preview that keeps the standing "hyperlinks display the target on hover" promise, and the scheme-class-and-length-only log contract. security-audits.md's OSC 8 entry follows the same typed boundary through both platform hand-offs. keybindings.md's Mouse section previously had no entry at all for Ctrl+Click hyperlink activation even though the gesture already shipped; it gains one alongside the new preview, since that page is where every other mouse gesture is already documented. The "Confusable URLs" bullet under "Text rendering" still promised the old, unbuilt shape ("on hover or in a status surface") instead of pointing at what shipped, leaving two bullets in the same doc making overlapping but inconsistent claims; it now points at the "OSC 8 hyperlinks and OSC 7 CWD" section for the actual guarantee. The precedence the preview loses to search/confirm, and the choice of SEARCH_BAR_BG over CONFIRM_BAR_BG, existed only as code comments; both are design decisions per CLAUDE.md's "record inline in the owning explanation doc" rule, so input.md gains a "Link preview" section alongside "Confirmation bar", the other decision about the same shared chrome row. Also thins the em dashes doc-prose flags as an LLM tell (the "not X — Y" contrast punch) out of the new security-model.md, security-audits.md, and spec.md prose. Refs #13 Assisted-by: Claude Code