Commit Graph

5 Commits

Author SHA1 Message Date
Diego Rodrigues de Sa e Souza
df87e9363b fix(auth): close the JWT_SECRET bootstrap chain — real-peer loopback, obsidian always-protected, DATA_DIR vault refusal (#13791)
GHSA-7pq4-8pvv-rx7r (critical). Every link of the reported chain held on the
release tip:

1. First boot without JWT_SECRET generates one and writes it in cleartext to
   $DATA_DIR/server.env.
2. With no password configured, isAuthRequired() returned false for
   POST /api/settings/require-login unconditionally — before the loopback
   check — so any network peer could switch requireLogin off.
3. With requireLogin off, POST /api/settings/obsidian/webdav accepted an
   arbitrary vault root and echoed freshly minted Basic credentials.
4. The WebDAV file service is served by the custom Node layer before Next.js,
   outside the authz pipeline.
5. Pointing it at DATA_DIR reads server.env, and JWT_SECRET forges an
   `{"authenticated":true}` admin session.

A second, worse problem surfaced while verifying: isLoopbackRequest() decided
"loopback" from nextUrl.hostname / the Host header, which the client controls.
`Host: localhost` from a remote address made the whole fresh-install bootstrap
reachable, not just the write path.

Three cuts, plus the root cause:

- isLoopbackRequest() now reads the trusted peer: the token-stamped real TCP
  peer the custom server writes (peerStamp), then the pipeline's own locality
  verdict once a stamp token exists, then a real socket peer. The bootstrap
  write path honours the same constraint instead of returning false, and
  managementPolicy hands down the peerContext verdict explicitly, because at
  policy time the original request still carries client-supplied headers.
- Host is consulted only when the process has no stamp token at all — no
  stamping server in front, which in practice means route handlers invoked
  directly by the unit-test harness. Every supported runtime (run-next dev and
  start, standalone-server-ws for Docker, the npm CLI and Electron) calls
  ensurePeerStampToken() at boot, so there a signal-less request fails closed.
  Without this fallback ~340 route tests that call handlers with
  `new Request("http://localhost/…")` turned into 401s.
- /api/settings/obsidian joins ALWAYS_PROTECTED_API_PATHS: issuing and rotating
  reusable WebDAV credentials is credential export, the same rationale as the
  GHSA-62vw entry for the password reveal.
- enableObsidianVaultSync() refuses a vault that is, sits inside, or contains
  DATA_DIR, comparing realpath-resolved paths so a symlink cannot dodge it.

Tests are red-first: remote stamped peer → auth required on the bootstrap
write; Host: localhost plus a forged locality header from a non-loopback
stamped peer → 401 through the full pipeline; the local operator keeps the
first-password flow; obsidian inventory and DATA_DIR overlap cases.
2026-09-15 16:58:24 -03:00
Webman
700819a29b fix(ci): boot protocol E2E on the peer-stamped custom server with preserved open bootstrap (#11535) (#11549)
Validated in a combined 3-PR batch worktree off release/v3.8.51 tip.
- Focused test: protocol-e2e-server-stamping-11535.test.ts — part of batch's 165/165 node:test run
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity, check:docs-counts-sync — all OK
- Full-repo lint: 228 pre-existing dashboard react-hooks/* findings, unrelated to this diff

Thanks for the meticulous root-causing here — three distinct issues (server flavor, HOST pin, open-bootstrap env leak) traced to exact line numbers with live-boot before/after evidence.
2026-08-25 18:54:09 -03:00
Arnav Rastogi
397ec88751 fix(ci): repair and wire the two live-server E2E suites (#10050)
tests/e2e/ecosystem.test.ts and tests/e2e/protocol-clients.test.ts appear in the
AGENTS.md test matrix but ran in no workflow, and could not run at all: both are
listed in vitest.config.ts include AND exclude, and their runners invoked Vitest
without --config, so the default config's exclusion discarded the very file each
passed as a positional filter.

  No test files found, exiting with code 1
  filter: tests/e2e/ecosystem.test.ts

Add vitest.e2e-live.config.ts covering only these two suites, point both runners
at it, and drop the contradictory include entries. The exclusions stay: these
drive a real server and must never run in the jsdom UI job.

Wire both into CI. test-ecosystem is blocking (20/20 green). test-protocols-e2e
is advisory pending #10049 — restoring it surfaced a pre-existing discrepancy
where GET /api/mcp/audit answers 403 over loopback against an expected 200|401.
2026-08-13 07:52:22 -03:00
backryun
c6b269a4d5 node dependency updates (#2259)
chore: node dependency updates (#2259 — thanks @backryun)
2026-05-14 20:20:54 -03:00
diegosouzapw
f3b944a55a refactor(scripts): organize into build/dev/check/docs/i18n/ad-hoc subfolders
Reorganizes the 29 active scripts under scripts/ into purpose-driven
subfolders:

- scripts/build/    (11) — Build, install, publish, runtime env
- scripts/dev/      (13) — Dev servers, test runners, healthchecks
- scripts/check/    (10) — Lint/validation/coverage checks
- scripts/docs/      (2) — Docs index and provider reference generation
- scripts/i18n/     (+3) — Adds Python translation utilities (check/validate/autotranslate)
- scripts/ad-hoc/    (4) — One-shot maintenance utilities

Updates all references in package.json, electron/package.json,
.husky/pre-commit, .github/workflows/ci.yml, Dockerfile, src/,
tests/, scripts/ internal cross-imports, playwright.config.ts,
and English docs (CODEBASE_DOCUMENTATION, ENVIRONMENT, FEATURES,
RELEASE_CHECKLIST, COVERAGE_PLAN, ELECTRON_GUIDE, I18N, GEMINI).

Also patches scripts/build/pack-artifact-policy.ts so the npm pack
allowlist mirrors the new layout.

Validates with:
- npm run lint            (exit 0 — pre-existing minified-bundle errors only)
- npm run typecheck:core  (exit 0)
- npm run check:docs-all  (exit 0)
- unit tests for moved scripts (57 tests pass)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:14:25 -03:00