Add independent Remote input helper with EOF and watchdog cleanup
This commit is contained in:
1 parent
cd9ae05bbe
commit
21d8904ee3
13 files changed
+1501
-20
No files matched your search
@@ -109,10 +109,12 @@ contract. None of these tests injects a desktop key.
|
||||
An unconnected [destination-key prerequisite](testing/remote-key-target.md) now
|
||||
retains native codes through layout changes and uncertain effects, with a
|
||||
quarantined Xorg resolver/backend. It is not attached to this mailbox and supplies
|
||||
no independent process/watchdog cleanup or physical collision guarantee.
|
||||
no physical collision guarantee. A subsequent [source-built helper](testing/remote-input-helper.md)
|
||||
now supplies private process-lifetime/EOF/watchdog cleanup, but no production
|
||||
reader launch or mailbox owner is attached.
|
||||
|
||||
No capture event API, production Xorg input owner, independent native cleanup
|
||||
helper, core escape/bypass integration or installed Remote keyboard command is
|
||||
No capture event API, production Xorg input owner, supervised helper attachment,
|
||||
core escape/bypass integration or installed Remote keyboard command is
|
||||
provided. Physical-source approval, physical collision/recovery, audible speech,
|
||||
Braille and real NVDA/Orca interoperability remain unverified. Private IPC and
|
||||
relay checks close no live release gate.
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
# Source-built Remote input helper prerequisite
|
||||
|
||||
`cmd/cthulhu-input-helper` now runs the quarantined Xorg destination target in
|
||||
its own process. `internal/remoteinput` supplies bounded private IPC, a separate
|
||||
EOF lifeline, and a three-second heartbeat watchdog. The helper owns its X
|
||||
connection and stored destination-key ledger on one locked OS thread.
|
||||
|
||||
No production reader owner launches this helper or attaches `remote.key`.
|
||||
Remote's UI still offers experimental speech only and discards keyboard traffic.
|
||||
The ordinary build/install script still builds the reader and Braille helper;
|
||||
this additional executable is source-built by the private test harness only.
|
||||
It has no manifest, catalog entry or service-manager dependency.
|
||||
|
||||
## Descriptors and process lifetime
|
||||
|
||||
The private launcher must supply three inherited anonymous pipe directions:
|
||||
|
||||
| Descriptor | Direction | Purpose |
|
||||
| --- | --- | --- |
|
||||
| stdin | Helper reads | Fixed operation records |
|
||||
| stdout | Helper writes | Fixed acknowledgements |
|
||||
| 3 | Helper reads | Empty lifetime pipe; EOF cancels the owner |
|
||||
|
||||
The launcher retains the sole write ends of control and lifetime. Neither the
|
||||
helper nor unrelated descendants may inherit these write ends. The lifetime
|
||||
pipe carries no bytes: any data is a protocol failure. Its EOF is observed
|
||||
independently of control buffering, so a queued or incomplete key record cannot
|
||||
postpone ownership cancellation until the control stream drains. Cancellation
|
||||
is checked before every queued effect and after native calls return.
|
||||
|
||||
The helper requires `--epoch` with a nonzero uint64. That epoch is bookkeeping,
|
||||
not consent or a secret. A future reader launcher must bind it to the original
|
||||
approved controlled lease, check `keyboard-inject` and policy at delivery, and
|
||||
keep all three pipes away from the network Tentacle. Possession of an inherited
|
||||
pipe is not an OS security boundary against arbitrary same-user processes.
|
||||
|
||||
Terminals, regular files and wrong-direction pipe descriptors are rejected.
|
||||
The helper adopts owned nonblocking pipe duplicates so Go's poller can interrupt blocked
|
||||
I/O on Close, including inherited stdin/stdout. No key names, raw frames, native
|
||||
diagnostics, channel keys or parser/argument excerpts are printed. Stdout is
|
||||
reserved for the private acknowledgement records; failure stderr is constant.
|
||||
|
||||
The future launcher must put the helper outside the writer/Tentacle process
|
||||
group. The private harness explicitly uses separate groups. Parent failure
|
||||
must close the lifeline and allow cleanup; it must not kill the helper before
|
||||
cleanup. Explicit cancellation can also use SIGTERM/SIGINT, which cancel the
|
||||
helper context and attempt orderly retirement. SIGKILL of the helper itself
|
||||
still cannot clean up XTEST keys.
|
||||
|
||||
## Private protocol version 1
|
||||
|
||||
All integers use unsigned big-endian representation. The frame version and all
|
||||
reserved/padding bytes are validated. There is no arbitrary JSON/text dispatch,
|
||||
network endpoint, path, script name or synthetic modifier fallback.
|
||||
|
||||
An operation is exactly 52 bytes:
|
||||
|
||||
| Bytes | Field |
|
||||
| --- | --- |
|
||||
| 0 | Version 1 |
|
||||
| 1 | Kind: heartbeat=1, down=2, up=3, close=4 |
|
||||
| 2 | Key-name byte length, 0–32 |
|
||||
| 3 | Reserved zero |
|
||||
| 4–11 | Original fixed epoch |
|
||||
| 12–19 | Strictly increasing positive operation sequence |
|
||||
| 20–51 | Canonical key name followed by zero padding |
|
||||
|
||||
Down/up require a name accepted by `input.ValidRemoteKeyName`. Heartbeat/close
|
||||
require an empty name. A different epoch, replay, unsupported version/kind,
|
||||
invalid name, nonzero padding or incomplete final record retires the helper.
|
||||
The sequence is private to this helper and must be ordered separately from
|
||||
public Tentacle RPC sequences. A running helper never accepts a new epoch.
|
||||
|
||||
An acknowledgement is exactly 20 bytes:
|
||||
|
||||
| Bytes | Field |
|
||||
| --- | --- |
|
||||
| 0 | Version 1 |
|
||||
| 1 | Kind: ready=1, accepted=2, closed=3 |
|
||||
| 2 | Closed reason; zero for other acknowledgement kinds |
|
||||
| 3 | Cleanup-failed flag, 0 or 1; zero except on closed |
|
||||
| 4–11 | Fixed epoch |
|
||||
| 12–19 | Operation sequence; ready uses zero |
|
||||
|
||||
Closed reasons are explicit close=1, EOF=2, expiry=3, protocol failure=4, target
|
||||
failure=5, output failure=6 and context cancellation=7. The terminal sequence is
|
||||
the last processed operation, which can include a failed native attempt.
|
||||
Accepted confirms operation processing; a duplicate down/unowned up can be an
|
||||
idempotent native no-op. It does not confirm application/reader command delivery.
|
||||
Close has no preliminary Accepted response. Only Closed with cleanup-failed=0
|
||||
confirms successful native retirement; missing confirmation, failed cleanup or
|
||||
an uncertain process exit must block replacement input. There is no reconnect
|
||||
or automatic restart that restores consent or held state.
|
||||
|
||||
## Watchdog, backpressure and cleanup
|
||||
|
||||
Only a valid heartbeat received before the current deadline renews the fixed
|
||||
three-second watchdog. Key traffic, partial input and ACK writes do not renew
|
||||
it. The owner checks the absolute deadline before each frame and after native
|
||||
effects, so busy traffic cannot starve expiry and a late heartbeat cannot revive
|
||||
an expired helper. Parent cancellation, lifetime EOF, malformed input or output
|
||||
failure also stop admission independently of control queue delivery.
|
||||
|
||||
One read worker retains at most a queued operation and one frame being read.
|
||||
One write worker owns a 32-record ACK queue plus one in-flight record. Native
|
||||
effects remain on the main owner. Full output capacity retires the helper;
|
||||
acknowledgements are not silently lost while native input continues. Cleanup
|
||||
runs before attempting the terminal ACK, including with stdout stalled. After
|
||||
cleanup, final ACK flushing is bounded by 250 milliseconds, then owned pipe
|
||||
directions close and all I/O workers join.
|
||||
|
||||
Native target failure triggers stored-code retirement. Failed retirement is
|
||||
reported with cleanup-failed=1 and a nonzero exit, rather than a false clean
|
||||
acknowledgement. The existing target ledger retains failed identities while
|
||||
alive; a parent must treat helper failure as uncertain and refuse fresh input.
|
||||
This helper does not solve recovery from its own death or a broken X server.
|
||||
|
||||
## Evidence and remaining gates
|
||||
|
||||
Run `python3 -B tests/native_remote_keys.py` from the reader checkout. It builds
|
||||
the actual helper with the race detector in a disposable directory and starts
|
||||
24-bit Xvfb before private D-Bus. It never uses the active display or reader.
|
||||
The supervising Go test owns a synthetic writer and the helper separately, so
|
||||
it can inspect key state and reap both after writer SIGKILL. The writer alone
|
||||
holds both write ends. This models writer/descriptor failure; it is not a
|
||||
production reader launch or actual reader-SIGKILL test.
|
||||
|
||||
Pure helper tests cover exact framing, fragmentation, stale epochs/sequences,
|
||||
reserved fields, lifetime data/EOF, cancellation of queued downs, blocked ACKs,
|
||||
key-only expiry, cleanup failure reporting, private errors and interruptible
|
||||
inherited reads. Eight private native process scenarios cover explicit close,
|
||||
writer SIGKILL, writer SIGSTOP with watchdog expiry, SIGTERM during a partial
|
||||
frame, replay, wrong epoch, successful heartbeat renewal beyond three seconds,
|
||||
and a full real ACK pipe. A separate X connection verifies owned Shift/Control
|
||||
are released. The six destination-target native tests remain regressions.
|
||||
|
||||
Production reader launch/supervision, mailbox ownership and retirement barriers
|
||||
are still absent. Physical same-code collisions, the check/inject race, input
|
||||
provenance, lock/AltGr/group/repeat policy and local escape/bypass remain open.
|
||||
The watchdog and signals cannot interrupt an Xlib call that blocks inside the
|
||||
native target; the private results require a responsive server. No hard desktop
|
||||
recovery bound, physical keyboard/Braille, audible speech, installed-package or
|
||||
live NVDA/Orca acceptance is established. Keyboard control remains unavailable.
|
||||
|
||||
The helper/input/wire/Xorg race suites, both private native harnesses, complete
|
||||
external Remote race suite, affected-package vet, separate reader build,
|
||||
existing speech regression harness and Tentacles `make check` passed. The
|
||||
repository check now includes private helper protocol/lifecycle tests and
|
||||
compiles the helper command, without launching it on a desktop. No full reader
|
||||
suite or active/installed-reader replacement was performed.
|
||||
@@ -3,13 +3,15 @@
|
||||
The reader has a destination-key ledger and an unconnected Xorg backend.
|
||||
`internal/input/remote_key_ledger.go` owns at most 32 native destination codes;
|
||||
`internal/platform/xorg/remote_keys.go` resolves and applies the supported
|
||||
logical keys on a dedicated X connection. No production code constructs this
|
||||
target, and no reader input owner is attached to `remote.key`. The Remote
|
||||
logical keys on a dedicated X connection. The [source-built helper](remote-input-helper.md)
|
||||
and private fixtures construct this target; no reader owner launches that helper
|
||||
or attaches `remote.key`. The Remote
|
||||
command still discards relay keyboard traffic and offers no keyboard grant.
|
||||
|
||||
This is a native prerequisite, not a usable input service. It must remain
|
||||
quarantined until independent helper cleanup, input provenance and physical
|
||||
collision handling are established.
|
||||
quarantined until production helper supervision, input provenance and physical
|
||||
collision handling are established. The source helper now demonstrates
|
||||
responsive-server EOF/watchdog cleanup in private process tests.
|
||||
|
||||
## Ownership and cleanup
|
||||
|
||||
@@ -39,8 +41,9 @@ Opening replacement input must wait for confirmed old cleanup; a new consent
|
||||
epoch does not make an old native release harmless. Closing an XTEST connection
|
||||
or killing this process does not release held keys. The earlier
|
||||
[Python feasibility harness](remote-input-feasibility.md) demonstrates that
|
||||
limitation; its separate EOF/watchdog mechanism is not implemented by this Go
|
||||
target.
|
||||
limitation. The ledger alone has no EOF/watchdog mechanism; the separate Go
|
||||
helper now supplies that process-lifetime owner. Helper death and blocked-server
|
||||
recovery remain unresolved.
|
||||
|
||||
## Native resolution and limits
|
||||
|
||||
@@ -72,10 +75,11 @@ concurrent-map-change or same-code collision guarantee is claimed.
|
||||
|
||||
All native wrapper methods require one serial caller on a locked OS thread.
|
||||
Xlib calls and the error guard can block or terminate a process after X-server
|
||||
failure. The future production target must run in an independent helper, with
|
||||
bounded inherited-descriptor IPC, watchdog/EOF cleanup, exclusive ownership,
|
||||
provenance, policy cancellation and explicit failure reporting. Do not attach
|
||||
this synchronous wrapper to the reader event loop or directly to its mailbox.
|
||||
failure. The source-built helper now provides independent execution, bounded
|
||||
inherited-descriptor IPC and watchdog/EOF cleanup. Production launch must preserve
|
||||
exclusive ownership, provenance, policy cancellation and explicit failure
|
||||
reporting. Do not attach this synchronous wrapper to the reader event loop or
|
||||
directly to its mailbox.
|
||||
|
||||
## Private verification
|
||||
|
||||
@@ -94,6 +98,8 @@ accessibility bus. Missing dependencies fail the harness rather than count as
|
||||
skipped acceptance. The native tests skip in ordinary unflagged Go suites;
|
||||
only an actual harness run establishes their private results.
|
||||
|
||||
The harness now builds and runs the source helper and tests its private process
|
||||
lifetime in addition to the destination target; see the linked helper contract.
|
||||
Unit tests cover stored-code releases, idempotent downs, unowned ups, alias and
|
||||
preexisting collisions, constant errors, held-key limits, uncertain down/up
|
||||
outcomes, partial cleanup and retry order. Six new native Go race tests verify
|
||||
|
||||
Reference in new issue
Block a user