feat(gitsync): synka wiki-repot mot remote över SSH

- ed25519-deploy-nyckel genereras av servern (config-volymen, 0600),
  GIT_SSH_COMMAND med egen known_hosts (accept-new)
- inställningar: remote-URL, live-gren, read-only, auto-synk-intervall
- bakgrundssynk: endast fast-forward, flaggar attention vid merge-behov
- pull/push, skapa/byt gren, merge-popup (ours/theirs per fil eller allt),
  abort, reset från remote med automatisk backup-gren
- headless-konfig via config.json eller updateGitSync-mutationen
- openssh-client tillagd i runtime-imagen; mutex kring alla git-operationer

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-02 23:10:34 +02:00
parent 952ff5f951
commit e181e8e68e
11 changed files with 1506 additions and 1 deletions

View File

@@ -33,6 +33,13 @@ type Server struct {
authMgr *auth.Manager
gitRepo *git.Repo
oidc *auth.OIDCProvider
// Git-sync engine state (see gitsync.go).
syncMu sync.Mutex
syncStop chan struct{}
lastSyncAt string
lastSyncErr string
syncAttention bool
}
func NewServer(cfg *config.Config, configPath string) http.Handler {
@@ -112,6 +119,7 @@ func (s *Server) initRuntime(cfg *config.Config) {
s.mu.Unlock()
s.configureOIDC(cfg)
s.configureGitSync(cfg)
}
// configureOIDC (re)initialises the OIDC provider from config. Discovery
@@ -225,6 +233,44 @@ func (s *Server) dispatchAuthenticated(
q := req.Query
switch {
// ── Git sync (matched first; none of these names collide with the
// generic "config"/"document"/"history" substrings further down) ────────
case strings.Contains(q, "updateGitSync"):
s.handleUpdateGitSync(w, req, sess)
case strings.Contains(q, "gitSyncSettings"):
s.handleGitSyncSettings(w, sess)
case strings.Contains(q, "gitSyncStatus"):
s.handleGitSyncStatus(w, sess)
case strings.Contains(q, "gitBranches"):
s.handleGitBranches(w, sess)
case strings.Contains(q, "gitCreateBranch"):
s.handleGitCreateBranch(w, req, sess)
case strings.Contains(q, "gitSwitchBranch"):
s.handleGitSwitchBranch(w, req, sess)
case strings.Contains(q, "gitPull"):
s.handleGitPull(w, sess)
case strings.Contains(q, "gitPush"):
s.handleGitPush(w, sess)
case strings.Contains(q, "gitResolveMerge"):
s.handleGitResolveMerge(w, req, sess)
case strings.Contains(q, "gitAbortMerge"):
s.handleGitAbortMerge(w, sess)
case strings.Contains(q, "gitResetFromRemote"):
s.handleGitResetFromRemote(w, sess)
case strings.Contains(q, "gitRegenerateKey"):
s.handleGitRegenerateKey(w, sess)
// ── Effective-access queries (matched before generic acl/subject cases) ────
case strings.Contains(q, "myAccess"):
s.handleMyAccess(w, req, sess)