mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
fix(gateway): local devices stall on scope upgrade pending approval despite autoApproveLocal (#124589)
* fix(cli): announce when nodes list degrades to paired-only data tryReadNodeList swallowed every enrichment failure, so the unfiltered nodes list silently rendered a table without connected/commands state. The fallback is now announced on stderr, keeping --json stdout parseable. * fix(gateway): silently widen local pairing scopes as documented `autoApproveLocal` has documented "silently approves pairing, role upgrades, and scope upgrades from trusted local connections" since the loopback auto-approval landed, but a later hardening pass forced every scope-upgrade pairing request non-silent. That block protected nothing locally — silent initial pairing grants a fresh identity arbitrary requested scopes, so any local process could mint a new keypair instead of upgrading — while it stranded every row-authorized client (CLI, native apps, node hosts) on a manual approval no local surface could perform. Scope upgrades now ride the same silent-local rule as initial pairing, with one new restriction that encodes the real boundary: the connect must itself prove local-grade credentials (auth mode none, or the shared token/password). Identity-proxy connects (tailscale, trusted-proxy) and bearer device tokens never did, so their pairing rows remain a durable scope cap, and `autoApproveLocal: false` still forces manual approval for everything. The silent self-grant also approves the union of requested plus already-held scopes: approval merges the existing row back in, so a client requesting only its missing scope no longer fails the caller-authority check. The decision surface shrinks with the behavior change: the scope-upgrade veto contradicted shouldAllowSilentLocalPairing's answer, the CLI-container locality was a duplicate of the shared-secret-loopback predicate, and three classifiers re-derived the same shared-secret auth check. Live-verified on an isolated auth-none loopback gateway: a CLI identity paired at operator.pairing silently widens to operator.read on the next wider command, with the scope-upgrade security audit line still emitted. * test(gateway): rewrite veto-era pairing locks for silent local widening Five control-ui pairing suite cases and the silent-scope-upgrade poc locked the removed non-silent veto. The suite cases now assert the new invariant (local shared-auth upgrades widen silently, malformed and legacy-shaped rows are repaired by the fresh approval, node-then-operator grants complete without a stranded prompt), and the poc case now exercises the surviving manual-approval gate by disabling autoApproveLocal after its watcher connects, keeping the pairing-request broadcast and remediation-hint assertions alive on a real remaining path. The voice-node bootstrap failure was leakage from the aborted sibling tests, and passes again once they complete their flows.
This commit is contained in:
committed by
GitHub
parent
16cde04136
commit
086f5916fa
@@ -215,6 +215,12 @@ describe("cli program (nodes basics)", () => {
|
||||
const output = getRuntimeOutput();
|
||||
expect(output).toContain("Pending: 0 · Paired: 1");
|
||||
expect(output).toContain("Pairing Scoped");
|
||||
// The degraded table must never look authoritative: the fallback is
|
||||
// announced on stderr so --json stdout stays parseable.
|
||||
expect(runtime.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("live node view unavailable"),
|
||||
);
|
||||
expect(output).not.toContain("live node view unavailable");
|
||||
});
|
||||
|
||||
it("sanitizes untrusted nodes list table fields while preserving JSON values", async () => {
|
||||
|
||||
Reference in New Issue
Block a user