mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-10 17:27:10 +00:00
|
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
* fix(channels): scope pairing and allowlist state by workspace PairingStore keyed its on-disk files by channel name alone, under the global ~/.qwen/channels/ directory. Two workspace-scoped channel configurations using the same channel name therefore shared pairing requests and allowlist entries: a sender approved for workspace A was implicitly approved for workspace B — an authorization-boundary violation in multi-workspace daemon deployments. PairingStore now takes the channel's workspace cwd and stores state under channels/<basename>-<sha256[:12]>/, ChannelBase passes config.cwd, and the pairing CLI commands gain a --cwd option (defaulting to the current directory) so list/approve address the same workspace-scoped store the channel worker uses. Migration is a conservative one-time grandfather: on first scoped use, existing legacy global files are COPIED into the scope (so already-approved senders stay approved and other workspaces can grandfather the same baseline later), after which the stores diverge — no ongoing cross-workspace sharing, and legacy content can never overwrite scoped state. Fixes #7017 * fix(channels): canonicalize scope identity and gate migration per directory Address the review findings on #7065: 1. Scope identity now follows the repo's workspace-canonicalization contract: getWorkspaceScopeDirName realpaths the resolved path (with the same ENOENT fallback as acp-bridge's canonicalizeWorkspace, which channel-base mirrors locally to stay dependency-free). Symlinked and platform-case-variant spellings of one directory — macOS /tmp/ws vs /private/tmp/ws — now address the same store from a daemon worker and from the CLI's --cwd. 2. Legacy grandfathering is gated at the scope-directory level instead of per file: once the scoped directory exists, legacy files are never consulted again. A per-file gate let a legacy allowlist silently re-approve senders an operator had revoked by deleting the scoped allowlist file, and let an in-use scope absorb a legacy file that appeared later. The README now spells out that revocation means removing entries, not deleting files. 3. The empty `pairing list` output names the workspace scope and points at --cwd, mirroring the approve error, since a scope mismatch surfaces there first. Four new regression tests (symlink collapse, ENOENT fallback, no resurrection after revoke, no late-legacy absorption) fail on the previous commit and pass here. Refs #7017 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(channels): state the broad realpath fallback is intentional; make the ENOENT scope assertion meaningful Two round-2 review notes on #7065: - canonicalizeWorkspacePath's docblock claimed to match acp-bridge's ENOENT-only fallback while the catch swallows every realpath error. Keep the broad catch — pairing storage is best-effort and a transient FS error must not stop the channel from starting — and document that divergence explicitly instead. - The ENOENT-fallback test's second assertion compared a scope name to itself. It now compares against the scope computed from the resolved spelling, pinning that the realpath step degrades to a no-op for nonexistent paths. Refs #7017 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(channels): always close the migration gate, normalize nonexistent-path scopes, copy atomically Address the automated round-2 inline findings on #7065: - The migration gate is now closed on the very first construction even when no legacy files existed: the scope directory itself is the "migration decided" marker. Previously a workspace that first ran on new code before any legacy state existed left the gate open, and a legacy allowlist written later by an older version still running concurrently would have been absorbed. - resolvePath now runs every input through path.resolve, so trailing-separator and dot-dot spellings of a path that does not exist on disk (where the realpath step cannot help) canonicalize to the same scope instead of three different ones. - Legacy files are copied via temp file + atomic rename, so a crash mid-copy cannot leave a truncated scoped file behind the now-closed gate, and a concurrent first construction cannot observe a half-written allowlist. Adds three regression tests (late-legacy not absorbed after empty first startup, nonexistent-path spelling collapse, unreadable legacy file keeps the constructor best-effort); the first two fail on the previous commit. Refs #7017 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(channels): encode channel names in scoped paths, gate migration per channel, wire tests into CI Three independently reproduced problems in the workspace-scoping change, found in external review of d8c155ab3: - Channel names come from unrestricted config keys and were joined into the scoped path verbatim, so a name like `../support` climbed out of the scope directory and landed every workspace on one shared file at the channels root — silently undoing the isolation this PR exists to establish. File names now URI-encode the channel name (mirroring GroupHistoryStore), common names encode to themselves, and the legacy source path is containment-checked as defense in depth. - The directory-level migration gate let only the FIRST channel of a workspace migrate: one process starts several channels in turn, and once the first construction created the scope directory, every other channel's legacy state was skipped forever. The gate is now a per-channel `<channel>.migrated` sentinel inside the scope directory, written even when there was nothing to copy. - A single unreadable legacy file aborted the whole migration loop and the gate still closed, so the other (valid) file was never migrated and never retried. Files are now copied independently, best-effort, via uniquely-named temp files + atomic rename, and scoped files are never overwritten. Also adds the missing test/test:ci scripts to channels/base (matching its sibling packages), so the package's 784 tests actually run in CI's `npm run test:ci --workspaces --if-present` sweep. Four new regression tests (traversal-name isolation, multi-channel migration, late-channel migration, unreadable-file independence) all fail on d8c155ab3 and pass here. Refs #7017 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(channels): read legacy files under the raw name, retry partial migrations, log failures Round-3 review findings on #7065: - Legacy sources are read under the RAW channel name again: pre-scoping code wrote them unencoded, so looking them up under the encoded name made any channel whose name changes under encoding (e.g. "my channel") skip its legacy state and permanently lose approved senders behind the sentinel. Encoded names remain in use for the scoped destinations; the containment check keeps traversal-style raw names from reading outside the channels root. - The sentinel is only written when every present legacy file was copied (or already existed). A partial failure (ENOSPC, transient I/O) previously closed the gate with incomplete state; now the next construction retries the failed file, and per-file stderr warnings are emitted so operators can see why senders are missing instead of instrumenting the constructor. - The symlink test cleans up with unlinkSync — rmSync throws EISDIR for a symlink to a directory on macOS. - The pairing CLI gains tests covering --cwd scoping end to end (list isolation, empty-scope hint, approve scoping, cross-workspace code rejection), plus an explicit return after the mocked-in-tests process.exit(1). The raw-name and partial-retry regression tests fail on 954e76af4. Refs #7017 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| channels | ||
| _meta.ts | ||
| approval-mode.md | ||
| arena.md | ||
| auto-mode.md | ||
| code-review.md | ||
| commands.md | ||
| computer-use.md | ||
| dual-output.md | ||
| followup-suggestions.md | ||
| headless.md | ||
| hooks.md | ||
| language.md | ||
| lsp.md | ||
| markdown-rendering.md | ||
| mcp.md | ||
| memory.md | ||
| sandbox.md | ||
| scheduled-tasks.md | ||
| skills.md | ||
| status-line.md | ||
| structured-output.md | ||
| sub-agents.md | ||
| tips.md | ||
| token-caching.md | ||
| tool-use-summaries.md | ||
| worktree.md | ||