sotashimozono_obsidian-remo.../plugin
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
..
e2e test(e2e): quarantine flaky reflect modify/large-image tests (#376) (#377) 2026-06-08 17:59:44 +09:00
scripts fix(daemon): sha-verify on the fast path + keep the dev-daemon marker in E2E 2026-07-02 19:07:38 +09:00
src fix(adapter): harden config write-through against symlink clobber + traversal 2026-07-14 14:39:00 +09:00
tests fix(adapter): harden config write-through against symlink clobber + traversal 2026-07-14 14:39:00 +09:00
esbuild.config.mjs fix(plugin): resolve Obsidian reviewer findings (CSS / disclosure / dynamic-exec) — 1.1.1-beta.2 (#373) 2026-06-08 17:17:41 +09:00
eslint.config.mjs chore(lint): tighten local config to mirror more of ObsidianReviewBot's checklist (0.4.76) 2026-04-29 20:50:14 +09:00
manifest.json fix(config): persist third-party plugin settings across restarts (#342, #429) 2026-07-14 14:24:26 +09:00
package-lock.json fix(ci): restore package-lock dep tree; bump version fields only 2026-07-14 14:29:00 +09:00
package.json fix(config): persist third-party plugin settings across restarts (#342, #429) 2026-07-14 14:24:26 +09:00
styles.css release: 1.1.2 (stable) — validator-clean (#395) 2026-06-09 15:28:18 +09:00
tsconfig.json fix(plugin): add node types to tsconfig to resolve unsafe-member warnings (#380) 2026-06-08 21:48:02 +09:00
versions.json chore(release): promote 1.1.6-beta.18 -> 1.1.6 (stable) 2026-07-03 14:56:25 +09:00
vitest.config.ts fix(tests): repair 6 CI failures + bump 1.0.36 (#278) 2026-05-09 23:26:01 +09:00
vitest.integration.config.ts chore(plugin): satisfy ObsidianReviewBot's stricter ruleset, round 2 (0.4.75) 2026-04-29 20:19:10 +09:00
vitest.replay.config.ts ci(replay): replay previous release tag's tests against current source 2026-04-30 17:54:22 +09:00
vitest.setup.ts 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