Repository navigation
fix(kernel): require verified caller identity on the five unattributed service bridges - #1339
Conversation
bdcf620 to
bc9aa3b
Compare
78dd4a0 to
f2ac0b5
Compare
…d service bridges NotificationServiceBridge, ContextMenuServiceBridge, DirectoryPickerServiceBridge, PanelEventServiceBridge and PerformanceServiceBridge accepted any authenticated process with no per-call attribution, while their siblings already enforce the documented verified-caller-identity pattern (BossConsole#53, introduced for the Secret Service in PR risa-labs-inc#505). A spawned process could spoof toasts, inject context-menu registrations, drive the native directory dialog, rearrange panels and forge performance mutations with nothing in the log to attribute them to. - Add the sibling AUTHENTICATED_PROCESS_ID helper (mirror + KDoc citing risa-labs-inc#53/risa-labs-inc#505) to all five bridges; unary RPCs refuse with PERMISSION_DENIED when no verified identity is present, even with no interceptor in front of them. - Performance watchers capture CURRENT_IDENTITY at subscription and revalidate the caller on every emission, the same mid-stream revocation shape LogServiceBridge uses. - ContextMenuServiceBridge keeps its passive acknowledge-and-drop contract (issue risa-labs-inc#30) for verified callers; only unattributed callers change behaviour. - New UnattributedBridgesIdentityTest: all five services over a real gRPC server with the production interceptor (no credential -> UNAUTHENTICATED, providers never reached), authenticated calls reach each provider, and direct calls with no identity context fail closed with PERMISSION_DENIED even without the interceptor. - ContextMenuServiceBridgeTest now pins the refusal half of the risa-labs-inc#53 contract directly. Gates: ktlintCheck + detekt + :composeApp:desktopTest --tests "ai.rever.boss.kernel.services.*" in one invocation - 13 suites, 104 tests, 0 failures, 0 errors, 0 skipped. Fixes risa-labs-inc#1218
f2ac0b5 to
b234d9b
Compare
|
Fresh CI on b234d9b: windows build-test had failed on the shared plugin-sandbox test |
|
@claude review this PR - security-sensitive changes, part of the backlog sweep. Focus on auth, signing, path handling, secrets, and injection surfaces. |
|
Claude finished @fluck-boss's task in 4m 25s —— View job Security review: verified caller identity on five kernel bridges
VerdictThe security change is correct and complete for what it claims. It mirrors the What I verified (not just read)
Findings1. The one genuinely new code shape has no allow-path test (
So a regression that read 2. Revocation is claimed in the PR body but not pinned - low, test only "revalidate the caller on every emission (mid-stream revocation honoured)" is asserted in the design section and in the new KDoc, but no test in this PR revokes anything. 3. The root-cause claim about attribution is stronger than the fix - low, doc/claim The PR says these calls happened "with nothing in the log to attribute any of it to". The return value of 4. Dead import (
5. Typo in the test constant (
6. Sixteen copies of the same helper - low, maintainability, follow-up not this PR
Out of scope, worth an issueIdentity presence is not authorization. After this change any authenticated child process can still summon the native directory dialog on demand, put arbitrary text in an operator-facing toast, and rearrange panels in an arbitrary |
Root cause
Issue #1218: five kernel service bridges — NotificationServiceBridge, ContextMenuServiceBridge, DirectoryPickerServiceBridge, PanelEventServiceBridge, PerformanceServiceBridge — served any authenticated process without re-checking that the call carries a verified caller identity. Eight-plus sibling bridges (Log, Secret, SplitView, Git, Download, …) already implement the documented
AUTHENTICATED_PROCESS_IDhelper pattern (BossConsole#53, introduced for the Secret Service in PR #505); these five never adopted it. A spawned process could spoof operator-facing toasts, inject context-menu registrations, summon the native directory dialog, rearrange panels, and drive GC/settings/metrics on the host process — with nothing in the log to attribute any of it to.Design
Mirrors the sibling helper shape exactly (
LogServiceBridge/ PR #505):ProcessIdentityInterceptor.AUTHENTICATED_PROCESS_IDand refuses withPERMISSION_DENIED("This call presented no verified process identity") when it is absent — fail-closed, even if the bridge is ever reached without the interceptor in front of it. Refusals are logged atLogCategory.AUTHwith the RPC name.PerformanceServicewatchers captureCURRENT_IDENTITYat subscription and revalidate the caller on every emission (mid-stream revocation honoured) — the same shapeLogServiceBridgeuses.ContextMenuServiceBridgekeeps its passive acknowledge-and-drop contract (issue ContextMenuServiceBridge never talks to the host ContextMenuProvider #30) for verified callers; only unattributed callers change behaviour. Its KDoc now states the identity requirement alongside the existing rationale.Tests + XML counts
UnattributedBridgesIdentityTest— all five services mounted on a real gRPC server (TLS + token registry + productionProcessIdentityInterceptor), three suites of coverage: (1) every RPC of all five bridges called with no credential →UNAUTHENTICATED, and the provider fakes prove the calls never reached the provider; (2) authenticated calls reach each provider and record the expected side effects; (3) direct construction with no identity context at all (no interceptor) →PERMISSION_DENIEDon every unary RPC and on the first emission of every watcher.ContextMenuServiceBridgeTestrewritten: the three acknowledge-and-drop tests become refusal tests pinning thePERMISSION_DENIEDhalf of the Remote UI: StreamUI has no plugin identity check — one plugin can bind another's surface #53 contract directly; the statelessness invariant test is kept.ktlintCheck :composeApp:detekt :composeApp:desktopTest --tests "ai.rever.boss.kernel.services.*"— 13 suites, 104 tests, 0 skipped, 0 failures, 0 errors (JUnit XML:tests="104" failures="0" errors="0"across TEST-*.xml, incl.UnattributedBridgesIdentityTest tests="3" failures="0" errors="0"andContextMenuServiceBridgeTest tests="4" failures="0" errors="0").Fixes #1218