sotashimozono_obsidian-remo.../plugin/src
Souta 64782eeff2 fix(adapter): harden config write-through against symlink clobber + traversal
Review of the write-through found two real defects it had introduced.

1. SYMLINK CLOBBER (the #455 bug class, reintroduced). writeThroughConfig
   mirrored every `<configDir>/**` write, and `fs.writeFileSync` FOLLOWS
   symlinks. `ShadowVaultBootstrap.installPlugin` symlinks remote-ssh's own
   main.js / manifest.json / styles.css in the shadow vault back to the
   SOURCE vault's real files, so any adapter write to those paths (e.g.
   updating the plugin from inside the shadow window) would have written
   straight through the link and overwritten the source vault's install —
   bricking it, exactly as #455 described.

   Now: lstat the target and refuse to mirror a symlink, and realpath the
   parent so a symlinked ANCESTOR (a stale whole-dir plugin symlink) cannot
   redirect the write out of the shadow root either. Skipping costs nothing —
   the remote write already succeeded, and for plugin CODE the local copy is
   owned by the pull/push binary round-trip, not by this cache.

   Pinned by a regression test that fails loudly without the guard: with it
   disabled the source vault's real file is observably overwritten
   ('SOURCE-REAL-FILE' -> 'NEW-BUNDLE-BYTES').

2. PATH TRAVERSAL. The containment guard was a `startsWith(configDir + '/')`
   on the RAW string, applied before `..` was resolved — so
   `.obsidian/../evil.txt` passed the check and `path.join` then resolved it
   out of the shadow root (on win32, backslash separators were a second way
   through). The vault path reaches the adapter from Obsidian and from other
   plugins; it is not trusted input.

   Now: resolve first, then verify the resolved path is the shadow root or
   inside it. Pinned by a test that asserts nothing lands outside the root.

Full suite green: 80 files, 1225 passed.
2026-07-14 14:39:00 +09:00
..
adapter fix(adapter): harden config write-through against symlink clobber + traversal 2026-07-14 14:39:00 +09:00
cache chore: monorepo restructure (plugin/ + server/ + proto/) 2026-04-25 10:52:52 +09:00
conflict refactor: extract ConflictResolver from SftpDataAdapter (#199) 2026-05-01 14:10:36 +09:00
offline fix(types): eliminate validator unsafe-* / CSS-portability warnings (#394) 2026-06-09 15:04:58 +09:00
path fix(config): persist third-party plugin settings across restarts (#342, #429) 2026-07-14 14:24:26 +09:00
proto fix(rpc): address PR #355 v2 review — pin startRpcSession + honest type 2026-05-18 00:28:26 +09:00
settings feat(ssh): support ProxyCommand and IdentityAgent (#430) 2026-06-30 14:13:37 +09:00
shadow fix(plugin): guard shadow bootstrap against self-install when Connect is clicked inside the shadow window (1.1.7-beta.0) 2026-07-11 11:25:41 +03:00
ssh feat(ssh): support ProxyCommand and IdentityAgent (#430) 2026-06-30 14:13:37 +09:00
transport feat(daemon): version-aware provisioning — refresh the daemon on plugin upgrade 2026-07-02 18:48:49 +09:00
ui chore(deps-dev): integrate dev-deps group + prefer-window-timers fix (1.1.1-beta.1) (#371) 2026-06-08 13:18:07 +09:00
util fix(shadow): address Phase B adversarial review — version-ordered binaries + unhandled rejection 2026-06-30 21:38:04 +09:00
vault fix(review): address /review-pr findings on #450 — preSpawnPull bypass + dotfile leak + misleading Notice 2026-07-02 22:10:37 +09:00
ConnectionManager.ts fix(daemon): address #406 review — reconnect downgrade, consent durability, loud tamper, atomic cache 2026-06-15 15:53:32 +09:00
constants.ts fix(config+vault): per-device Obsidian config (kills the perpetual write-conflict) + hide dotfiles 2026-07-02 21:41:35 +09:00
main.ts fix(plugin): guard shadow bootstrap against self-install when Connect is clicked inside the shadow window (1.1.7-beta.0) 2026-07-11 11:25:41 +03:00
types.ts feat(vault): lazy per-folder loading — deepen the remote tree on File-Explorer expand 2026-07-02 20:25:59 +09:00