Release: multi-host vault support (GitHub / Codeberg / Forgejo) + audit fixes - #269
Merged
Conversation
Introduces the host-abstraction seam for vault sync (GitHostProvider interface, HostKind/HostRepo/HostUser/FileChange types), a GitHubProvider that wraps the existing github.ts helpers plus the ETag-conditional cache, and a ForgejoProvider that talks to the Gitea REST API (reads via git-data endpoints, writes via the ChangeFiles batch endpoint). Adds makeGitHostProvider() to pick a provider from a connection's host kind. githubStore gains host/baseUrl connection state (default 'github'/null, reset on disconnect, no persist version bump needed since Zustand merges a legacy blob with no host key over the initial default).
syncPush.ts (syncToGitHub) now builds a host-neutral FileChange[] and hands
it to provider.commitChanges instead of calling the GitHub blob/tree/commit/
ref primitives directly; the write path uses the provider's plain (non-
cached) reads so a stale tree can never cause a non-fast-forward commit.
Delete/update FileChanges carry the remote blob sha (Forgejo's ChangeFiles
batch endpoint requires it; GitHub ignores it).
syncPull.ts (pullFromGitHub / pullFromZipball) now takes a GitHostProvider
and reads through its cached variants (getTreeMapCached / getBlobContentCached
/ fetchArchive), preserving GitHub's ETag-conditional caching behind the seam
instead of calling githubETagCache directly.
useGitHubSync builds the provider per call via makeGitHostProvider({host,
token, baseUrl}) read from the githubStore connection state, so a refreshed
token is always honored and the GitHub path behaves identically to before.
Mirrors e2eSyncLive.test.ts but drives the pipeline through ForgejoProvider against a real Codeberg repo (pull/push/update/no-churn/delete plus a concurrency probe on the ChangeFiles write path). Self-skips without CODEBERG_TEST_TOKEN so CI stays green without secrets. Adds the e2e:sync:codeberg npm script that loads the token from ~/.config/noteser/codeberg-test-token.env and runs only this file.
connect-src now statically includes https://codeberg.org (the built-in Forgejo preset). Self-hosted Forgejo/Gitea is allow-listed at deploy time via the new NEXT_PUBLIC_FORGEJO_BASE_URL env var (deriveGitHostOrigin, same posture as deriveCollabWsOrigin: a single validated origin, never a wildcard). Adds docs/codeberg.md and the README env-var entry.
The connect modal now opens to a host picker (GitHub / Codeberg / Forgejo). GitHub keeps the existing device-flow + fine-grained-PAT path unchanged. Codeberg and self-hosted Forgejo go through a new PAT form (Forgejo also takes a base-URL field, type=text so the custom https:// validation always runs instead of being pre-empted by native URL constraint validation). On a valid PAT, makeGitHostProvider().getAuthenticatedUser() validates it, then setHost() is called before setSession(), then the repo picker opens. GitHubRepoModal is now host-blind: it lists/creates repos through the active host's provider (HostRepo fields replace the GitHub-specific repo shape); the modal title and disconnect label are host-neutral. GitHub-only features are hidden when the connection isn't GitHub: 'View history' and 'Publish as gist' in ContextMenu, the RecentCommits block in SourceControlPanel. SourceControlPanel's repo web-link is host-aware (Forgejo uses the Gitea /src/branch/ path instead of GitHub's /tree/, and the tooltip reads 'Open in browser' for non-GitHub hosts).
…Codeberg / Forgejo) Integrate the fork PR onto dev for staging then promotion to prod, independent of the contributor. Sole conflict was in GitHubRepoModal.tsx: resolved in favour of the PR's host-neutral HostRepo model (repo.isPrivate / repo.defaultBranch / key), keeping main's Tailwind shrink-0 shorthand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…yaml, sharp) (#268) * chore(deps): clear high-severity audit findings in root and collab-server Root (lock-only, no package.json change): - brace-expansion 1.1.14 -> 1.1.16 and 5.0.6 -> 5.0.7 (GHSA-3jxr-9vmj-r5cp, the advisory range widened to cover the versions we were pinning). - js-yaml 4.2.0 -> 4.3.0 (GHSA-52cp-r559-cp3m), same npm audit fix run. collab-server: override sharp to ^0.35.0 (GHSA-f88m-g3jw-g9cj, libvips CVEs). Bumping wrangler does not fix this: miniflare still pins sharp 0.34.5 as of 4.20260721.0, so every wrangler >=4.16.0 is affected and `npm audit fix --force` would downgrade wrangler 4.110.0 -> 4.15.2. PR #256 (wrangler 4.112.0) does not clear the advisory either. sharp only serves miniflare's local Images binding emulation, which this Worker does not use, and it never ships to the Worker. Verified: root typecheck, eslint, 3232 jest tests; collab-server typecheck, 11 vitest tests, `wrangler deploy --dry-run`, and `wrangler dev` serving 200. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(deps): override sharp at root too, clearing the last audit gate CI runs `npm audit --audit-level=high` as a blocking step, so leaving the root next -> sharp advisory (GHSA-f88m-g3jw-g9cj, the same libvips CVEs as collab-server) kept the check job red. `npm audit fix --force` would have downgraded next to 14.2.35, so override sharp to ^0.35.0 instead, matching the collab-server fix and the existing overrides block here. next declares sharp as an OPTIONAL dependency at ^0.34.3, and nothing in this repo uses it: there is not a single `next/image` import: every mention of it in src/ is a comment explaining why we deliberately use a plain <img> instead (blob: URLs from IndexedDB attachments, animated GIFs). Image optimization is never exercised, so the out-of-range bump has no runtime surface here. Gate (all green, .next cleared first per CLAUDE.md's overrides note): lint, typecheck, 3232 jest tests, production build, and `npm audit --audit-level=high` reporting 0 vulnerabilities at root. Note: `npm audit fix` in the previous commit also took next 15.5.18 -> 15.5.21 (a patch bump inside the existing ^15.5.18 range, lock-only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(deps): keep next at 15.5.18, drop the incidental patch bump The `npm audit fix` in f3aa243 also carried next 15.5.18 -> 15.5.21 along for the ride. Nothing asked for it and no advisory needs it: the only next-related finding was the transitive sharp one, which the override in 8f36dee fixes independently of the next version. `npm audit` still reports 0 vulnerabilities with next pinned back. It is also not free. Jest transforms through `next/jest` (jest.config.js), so a next bump swaps the SWC transform and shifts transpile timing — the exact mechanism the comment in publishGistModal.test.tsx:219-227 already blames for this suite's modal tests unmounting mid-test under CI load ("body collapsed to <div/>"). Two CI runs on 15.5.21 tripped two different userEvent modal tests (taskEditModal, then publishGistModal) with that signature; both pass locally and on dev at 15.5.18. That test fragility is a real latent problem worth fixing on its own, but it is not this PR's job, and a dependency-audit change should not be carrying an unrequested framework bump that destabilises CI. Lock delta vs origin/dev is now exactly the intended set: brace-expansion, js-yaml, sharp (+ its platform binaries), and a transitive semver patch. Gate: lint, typecheck, 3232 jest tests, build, audit 0 vulnerabilities. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: noteser-agent <noteser-agent@claude> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…270) npm audit fix (lockfile-only). Clears the Next.js advisory batch published 2026-07-22 (GHSA-m99w-x7hq-7vfj, GHSA-89xv-2m56-2m9x, GHSA-68g3-v927-f742, GHSA-4633-3j49-mh5q, GHSA-4c39-4ccg-62r3, GHSA-p9j2-gv94-2wf4, GHSA-q8wf-6r8g-63ch, GHSA-955p-x3mx-jcvp), which fail the CI audit gate. Stays within the existing ^15.5.18 range; no package.json change. The @tailwindcss/oxide-wasm32-wasi bundled-dependency entries are churn from npm 12 re-expanding the tree, not a dependency change. Co-authored-by: noteser-agent <noteser-agent@claude> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges
devintomain.Contents
GitHostProviderseam — GitHub / Codeberg / Forgejo, host-picker UI, CSPconnect-srcallowance, live Codeberg e2e harness.sharpoverride^0.35.0(root + collab-server),js-yaml4.3.0,brace-expansion1.1.16.Effect
Clears open Dependabot alert #85 (brace-expansion, GHSA-3jxr-9vmj-r5cp) on the default branch and unblocks the 11 open Dependabot PRs currently failing the
npm audit --audit-level=highgate.Supersedes #266, which carries the same audit fix against
main.🤖 Generated with Claude Code