Repository navigation
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Reject symlinks or verify canonical paths remain within the avatar cache before granting access.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Fixes Linux cached-avatar loading by granting explicit Tauri asset-protocol access to validated avatar files.
Changes:
- Adds avatar path validation and canonicalization tests.
- Grants avatar access during snapshots, broadcasts, and member listing.
- Avoids broad hidden-directory scope expansion.
| File | Description |
|---|---|
src-tauri/src/commands/auth.rs |
Implements avatar scope grants and validation tests. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
643a279 to
6490ea9
Compare
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
6490ea9 to
abcbc78
Compare
On Linux, cached profile avatars are stored in app_config_dir()
(~/.config/dev.atlas.ide/avatar-<hash>.<ext>). Because Tauri's Unix
glob matcher sets requireLiteralLeadingDot: true, the $HOME/** asset
protocol scope skips dot-directories such as ~/.config. This resulted in
Tauri asset protocol errors ("asset protocol not configured to allow the path")
and silently caused avatars to fall back to initials.
Rather than broadly opening hidden directories, this explicitly grants
access to the specific avatar files via allow_file upon auth broadcast,
initial auth_snapshot, and auth_list_members.
dunce::canonicalize resolved a symlink like avatar-evil.png -> ~/.config/dev.atlas.ide/auth-token.json to the secret, and the webview was then granted asset-protocol read access to it. The prefix/extension checks only constrained the symlink's name, not its target. resolve_avatar_grant_path now also canonicalizes the avatar cache dir and requires the resolved file to be a regular file directly inside it (with an avatar-shaped name/extension), plus add symlink-guard tests.
abcbc78 to
572ab27
Compare

What?
Cached avatars, your own and org members', load on Linux. Each validated avatar file gets explicit asset-protocol access via
app.asset_protocol_scope().allow_file(...), instead of the scope being widened.Why?
On Linux, cached avatars live in
app_config_dir()(~/.config/dev.atlas.ide/avatar-<hash>.<ext>). The configured asset scope is$HOME/**, and Tauri's Unix glob matching usesrequireLiteralLeadingDot: true, so it never matches hidden directories such as~/.config. Every avatar load fails, logging:Widening the scope to hidden directories, or to the whole config dir, would expose what lives next to the avatars (the session file and credentials) to the webview. Granting one validated file at a time doesn't.
No new dependencies, no telemetry changes.
How?
All in
src-tauri/src/commands/auth.rs:Where grants happen:
broadcast(launch restore, revalidation, sign-in, org changes),auth_snapshot(initial frontend hydration) andauth_list_members(org roster avatars).What gets granted:
resolve_avatar_grant_pathonly grants a file that:avatar-name and an image extension (png, jpg, jpeg, webp, gif), anddunce::canonicalize) to a regular file directly inside the avatar cache dir, still with anavatar-name and an image extension.The second rule closes a symlink bypass Copilot flagged on an earlier revision: a link named
avatar-x.pngpointing at a credential file passed the name checks, and would have had its target granted.AuthStatenow keeps the config dir it handsAuthCore(where the avatar cache lives), so the check compares against the real cache dir. Both sides are canonicalized, so a symlinked~/.configdoesn't break it.Why this is safe with Tauri (checked against 2.11.1):
Scope::is_allowedcanonicalizes the requested path before matching, so swapping a granted file for a symlink later doesn't extend access.HashSet, so re-granting on every snapshot or broadcast doesn't pile up duplicates.macOS: unaffected. The avatar cache there is already inside
$HOME/**, so the grant is a no-op.Tests (
#[cfg(test)]inauth.rs):resolve_avatar_grant_path_validates_path: valid avatar accepted; relative path, missing file, wrong prefix, non-image extension, directory, and an avatar-named file outside the cache dir all rejected.resolve_avatar_grant_path_rejects_symlink_escape(unix): anavatar-*.pngsymlink to a file outside the cache dir, and one to a non-avatar file inside it, are both rejected.Verification:
oxlint,oxfmt --check,cargo fmt --check,bun run typecheck,bun run test:contracts(248/248) andbun run test src/features/authall passed on the first revision.rustfmtpasses on the current file. The Rust tests run in CI's macOSappjob.The only failing check,
app (src-tauri, Windows), also fails on0.4.0itself and is unrelated to this change. #367 fixes it.Fixes #365
Checklist