Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8f52871
build(deps): bump github.com/go-git/go-git/v5 from 5.19.0 to 5.19.1 (…
dependabot[bot] May 25, 2026
184f21e
docs: document wiki catalog storage architecture
zhangyangyu May 25, 2026
81657a8
feat(wiki): add catalog storage substrate
zhangyangyu May 25, 2026
58cc49f
fix(wiki): use request-scoped DB for catalog writes
zhangyangyu May 25, 2026
4922617
test(wiki): add catalog performance benchmarks
zhangyangyu May 25, 2026
d19f240
feat(wiki): list wiki pages from catalog projection
zhangyangyu May 25, 2026
56f412b
feat(wiki): make catalog the wiki source of truth (#20)
zhangyangyu May 26, 2026
8b65a35
fix(wiki): refresh stale catalog asynchronously (#21)
zhangyangyu May 26, 2026
4f41bff
feat(wiki): add TiDB-backed wiki search (#22)
zhangyangyu May 26, 2026
bc6d040
fix(wiki): fuse lexical and vector search ranking (#23)
zhangyangyu May 26, 2026
5c5825a
fix: token-limit embedding inputs (#24)
zhangyangyu May 26, 2026
71287c7
chore: remove wiki auto reindex startup job (#25)
zhangyangyu May 26, 2026
30dae33
fix: treat canceled requests as client closed (#26)
zhangyangyu May 26, 2026
ecf6a47
feat: add admin wiki history compaction API (#27)
zhangyangyu May 26, 2026
57d12fa
fix: compact wiki history asynchronously (#28)
zhangyangyu May 26, 2026
1961021
fix: speed up wiki search reindexing (#29)
zhangyangyu May 26, 2026
b42cfc1
fix: recover wiki compaction from stale ref locks (#30)
zhangyangyu May 26, 2026
613b74e
fix: disable wiki compaction during incident response (#31)
zhangyangyu May 26, 2026
f48bfe1
fix: keep wiki compaction disabled and restore wiki list pagination (…
zhangyangyu May 26, 2026
944d609
fix: make wiki compaction insert-only (#33)
zhangyangyu May 26, 2026
a7d0775
fix: paginate REST issues in the database (#34)
zhangyangyu May 26, 2026
afde0c5
refactor: rename module path and expose config/server packages (#35)
zhangyangyu May 26, 2026
277de5d
feat: support bind grants for agent invites (#36)
zhangyangyu May 26, 2026
d26d555
feat: expose embeddable server lifecycle (#37)
zhangyangyu May 26, 2026
d20b3e1
fix: avoid ordering token lookups (#38)
zhangyangyu May 26, 2026
567f418
docs: add wiki storage v2 design baseline (#39)
zhangyangyu May 26, 2026
04c523a
fix: reduce issue list query fanout (#40)
zhangyangyu May 26, 2026
7bed0f7
docs: add wiki storage v2 implementation plan (#41)
zhangyangyu May 26, 2026
a7be60b
feat: add renewable agent switch sessions (#42)
zhangyangyu May 26, 2026
400baa0
feat: add wiki v2 foundation primitives (#43)
zhangyangyu May 26, 2026
a963623
feat: expose provisional wiki v2 reconcile routes (#44)
zhangyangyu May 26, 2026
fbdee16
feat: hydrate wiki search results from git (#45)
zhangyangyu May 26, 2026
c125b8e
docs: align wiki authority contract with v2 design (#46)
zhangyangyu May 26, 2026
6e1fc9c
feat: prefer current wiki v2 index for head reads (#47)
zhangyangyu May 26, 2026
45b4826
feat: add wiki v2 backlink and history indexes (#48)
zhangyangyu May 26, 2026
57ad3d4
docs: define wiki storage v2 cutover baseline (#49)
zhangyangyu May 26, 2026
346c586
feat: prefer git-first lexical wiki search (#50)
zhangyangyu May 26, 2026
47d200f
feat: derive wiki v2 history and backlink indexes (#51)
zhangyangyu May 26, 2026
357ddca
fix: remove custom REST API prefix (#52)
zhangyangyu May 26, 2026
208bd32
docs: clarify wiki storage cutover goal (#53)
zhangyangyu May 26, 2026
1c5fbfb
feat: add generic OIDC auth compatibility layer (#54)
zhangyangyu May 27, 2026
a04e878
feat: add wiki v2 provisional read routes (#55)
zhangyangyu May 27, 2026
e3a87e2
feat: add provisional wiki v2 tree endpoint (#56)
zhangyangyu May 27, 2026
4947e6a
feat: add provisional wiki v2 label routes (#57)
zhangyangyu May 27, 2026
331a49f
feat: remove provisional wiki v2 REST surface (#58)
zhangyangyu May 27, 2026
8f49006
feat: support embeddable identity injection (#59)
zhangyangyu May 27, 2026
9fbb950
feat!: remove Auth0 compatibility layer (#60)
zhangyangyu May 27, 2026
4547792
feat: add Login-with-Slock auth flow (#61)
zhangyangyu May 28, 2026
0cab993
fix: keep Slock agent token callback compatible
TennyZhuang May 28, 2026
40bc5b6
fix: tighten Slock callback compatibility
TennyZhuang May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 19 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,25 @@ AUTH0_ISSUER=""
AUTH0_CLIENT_ID=""
AUTH0_AUDIENCE=""

# Optional generic OIDC human login. When set, these enable the provider-neutral
# /api/v3/oidc/* endpoints. Existing Auth0-only deployments can continue using
# AUTH0_* without changing provider values for linked identities.
OIDC_PROVIDER=""
OIDC_ISSUER=""
OIDC_DISCOVERY_URL=""
OIDC_CLIENT_ID=""
OIDC_CLIENT_SECRET=""
OIDC_AUDIENCE=""
OIDC_SCOPES="openid profile email"
OIDC_ALLOW_INSECURE_HTTP="false"

# Optional Login-with-Slock OAuth. When set, these enable /auth/slock/login and
# /auth/slock/callback. The Slock callback URL is BASE_URL + /auth/slock/callback.
SLOCK_ORIGIN=""
SLOCK_API_ORIGIN=""
SLOCK_CLIENT_ID=""
SLOCK_CLIENT_SECRET=""

# ==============================================================================
# Optional workflow execution sandbox
# ==============================================================================
Expand Down
40 changes: 39 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,60 @@ jobs:
- name: Prepare e2e test environment
run: make test-setup

- name: Start mock OIDC issuer
shell: bash
run: |
set -euo pipefail
go run ./e2e/cmd/mock-oidc-server/main.go :8891 >/tmp/mock-oidc.log 2>&1 &
echo $! >/tmp/mock-oidc.pid
for _ in $(seq 1 30); do
if curl -sf http://localhost:8891/.well-known/openid-configuration >/dev/null; then
exit 0
fi
sleep 1
done
echo "mock issuer failed to start" >&2
cat /tmp/mock-oidc.log >&2 || true
exit 1

- name: Start e2e server
env:
GIT_REPO_DIR: /tmp/gh-server-e2e-repos
LISTEN_MODE: production
PORT: '80'
ADMIN_LOGIN: testadmin
ADMIN_TOKEN: mytoken
OIDC_PROVIDER: casdoor
OIDC_ISSUER: http://localhost:8891/
OIDC_CLIENT_ID: test-client-id
OIDC_ALLOW_INSECURE_HTTP: '1'
ENABLE_WORKFLOW_EXEC: "1"
run: make run-bg

- name: Run full e2e suite
env:
GIT_REPO_DIR: /tmp/gh-server-e2e-repos
LISTEN_MODE: production
PORT: '80'
ADMIN_LOGIN: testadmin
ADMIN_TOKEN: mytoken
OIDC_PROVIDER: casdoor
OIDC_ISSUER: http://localhost:8891/
OIDC_CLIENT_ID: test-client-id
OIDC_ALLOW_INSECURE_HTTP: '1'
ENABLE_WORKFLOW_EXEC: "1"
run: make test-e2e

- name: Clean e2e environment
if: always()
run: make test-clean-all
shell: bash
run: |
set -euo pipefail
make test-clean-all
if [[ -f /tmp/mock-oidc.pid ]]; then
kill "$(cat /tmp/mock-oidc.pid)" 2>/dev/null || true
rm -f /tmp/mock-oidc.pid
fi

backend-smoke:
name: Backend Smoke
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Binaries
gh-server
gh-server-bin
/gh-server
/gh-server-bin
/cli/gh

# Runtime data
Expand Down Expand Up @@ -40,3 +40,4 @@ coverage.out

# Frontend/tool caches
.vite/
visualization/.vite/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ RUN go mod download
COPY . .

ARG GIT_SHA=unknown
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w -X main.gitSHA=${GIT_SHA}" -o gh-server .
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w -X github.com/ngaut/agent-git-service/server.gitSHA=${GIT_SHA}" -o gh-server ./cmd/gh-server

# ---- Runtime stage ----
FROM alpine:3.21
Expand Down
37 changes: 32 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,31 @@ E2E_BASE_URL ?= http://$(TEST_HOST)
TIDB_TAG = gh-server
DB_NAME = gh-server
TEST_DB_DSN ?= root:@tcp(127.0.0.1:4000)/$(DB_NAME)?parseTime=true&timeout=10s
TIDB_TMP_DIR ?= /mnt/gh-server-tidb-tmp
TIDB_CONFIG_FILE ?= /tmp/gh-server-tidb.toml
EPIC130_CP_DB ?= e2e_mt_cp
EPIC130_A_DB ?= e2e_mt_a
EPIC130_B_DB ?= e2e_mt_b
EPIC130_TOKEN_ENV ?= /tmp/epic130_tokens.env
EPIC130_SCRIPT ?= multi-tenant-control-plane-integration
EPIC130_MAIN_DSN ?= $(TEST_DB_DSN)
EPIC130_CP_DSN ?= root:@tcp(127.0.0.1:4000)/$(EPIC130_CP_DB)?parseTime=true&timeout=10s
EPIC130_A_DSN ?= root:@tcp(127.0.0.1:4000)/$(EPIC130_A_DB)?parseTime=true&timeout=10s
EPIC130_B_DSN ?= root:@tcp(127.0.0.1:4000)/$(EPIC130_B_DB)?parseTime=true&timeout=10s

# ─── Build ────────────────────────────────────────────────────────────────────

.PHONY: build
build: ## Build the gh-server binary
go build -o $(BINARY) .
go build -o $(BINARY) ./cmd/gh-server

.PHONY: vet
vet: ## Run go vet
go vet ./...

.PHONY: fmt
fmt: ## Run goimports on all Go files
$$(go env GOPATH)/bin/goimports -w internal/ *.go
$$(go env GOPATH)/bin/goimports -w config/ internal/ server/ cmd/gh-server/

# ─── Docker ──────────────────────────────────────────────────────────────────

Expand Down Expand Up @@ -117,8 +128,21 @@ test-db-start: ## Start test-only TiDB via tiup playground
echo "✓ TiDB already running"; \
else \
echo "Starting TiDB playground..."; \
tmp_dir="$(TIDB_TMP_DIR)"; \
parent_dir="$$(dirname "$$tmp_dir")"; \
if [ ! -d "$$tmp_dir" ] || [ ! -w "$$tmp_dir" ]; then \
if command -v sudo >/dev/null 2>&1; then \
sudo mkdir -p "$$tmp_dir"; \
sudo chown "$$(id -u):$$(id -g)" "$$tmp_dir"; \
fi; \
fi; \
if [ ! -d "$$tmp_dir" ] || [ ! -w "$$tmp_dir" ]; then \
tmp_dir="/tmp/gh-server-tidb-tmp"; \
fi; \
mkdir -p "$$tmp_dir"; \
printf 'temp-dir = "%s"\n' "$$tmp_dir" > "$(TIDB_CONFIG_FILE)"; \
tiup clean $(TIDB_TAG) 2>/dev/null || true; \
setsid tiup playground --tag $(TIDB_TAG) --db 1 --pd 1 --kv 1 --tiflash 0 --without-monitor > /tmp/tiup-playground.log 2>&1 < /dev/null & \
setsid tiup playground --tag $(TIDB_TAG) --db 1 --pd 1 --kv 1 --tiflash 0 --without-monitor --db.config "$(TIDB_CONFIG_FILE)" > /tmp/tiup-playground.log 2>&1 < /dev/null & \
echo "Waiting for TiDB to be ready..."; \
for i in $$(seq 1 30); do \
if mysql -h 127.0.0.1 -P 4000 -u root -e "SELECT 1" >/dev/null 2>&1; then \
Expand All @@ -132,6 +156,7 @@ test-db-start: ## Start test-only TiDB via tiup playground
sleep 2; \
done; \
fi
@mysql -h 127.0.0.1 -P 4000 -u root -e "SET GLOBAL tidb_enable_dist_task=OFF; SET GLOBAL tidb_ddl_enable_fast_reorg=OFF;" 2>/dev/null
@mysql -h 127.0.0.1 -P 4000 -u root -e "CREATE DATABASE IF NOT EXISTS \`$(DB_NAME)\`" 2>/dev/null
@echo "✓ Database '$(DB_NAME)' ready"

Expand Down Expand Up @@ -288,7 +313,9 @@ run-bg: build ## Build and run in background (auto-detects sudo, falls back to u
echo "✓ passwordless sudo available, starting privileged listeners on :80/:443"; \
PID=$$(pgrep -x -n "$(BINARY)" 2>/dev/null) && [ -n "$$PID" ] && ps -p $$PID > /dev/null 2>&1 && sudo -n kill $$PID 2>/dev/null || true; \
sleep 1; \
setsid sudo -n -E ./$(BINARY) < /dev/null > $(LOG_FILE) 2>&1 & \
env_file="$$(mktemp /tmp/gh-server-run-bg-env.XXXXXX)"; \
env -0 > "$$env_file"; \
setsid sudo -n bash -lc 'set -euo pipefail; set -a; while IFS= read -r -d "" line; do export "$$line"; done < "'"$$env_file"'"; rm -f "'"$$env_file"'"; exec ./$(BINARY)' < /dev/null > $(LOG_FILE) 2>&1 & \
health_urls="http://$(TEST_HOST)/readyz http://127.0.0.1/readyz"; \
else \
echo "⚠ sudo unavailable in this context, falling back to unprivileged mode (port $(UNPRIVILEGED_PORT))"; \
Expand Down Expand Up @@ -401,7 +428,7 @@ test-run: test-preflight ## Run a single test suite, e.g. make test-run SUITE=Te
.PHONY: test-e2e
test-e2e: ## Run end-to-end tests. Usage: make test-e2e [SCRIPT=repo-rollback-compensation] [E2E_BASE_URL=http://...]
@if [ -z "$(SCRIPT)" ]; then \
for s in $$(find e2e -maxdepth 1 -type f -name "*.sh" ! -name "run.sh" ! -name "lib.sh" | sort); do \
for s in $$(find e2e -maxdepth 1 -type f -name "*.sh" ! -name "run.sh" ! -name "lib.sh" ! -name "helpers.sh" | sort); do \
script="$$(basename "$$s" .sh)"; \
E2E_BASE_URL="$(E2E_BASE_URL)" SCRIPT="$$script" bash e2e/run.sh || exit $$?; \
done; \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ printf 'TiDB Zero claim URL: %s\n' "$(
printf '%s' "$ZERO_INSTANCE" | jq -r '.instance.claimInfo.claimUrl'
)"

go run .
go run ./cmd/gh-server
```

Claim the TiDB Zero instance from its claim URL if you want to keep the database
Expand Down
12 changes: 12 additions & 0 deletions auth/identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package auth

// Identity is a trusted host-provided identity for embedded deployments.
type Identity struct {
Provider string
Subject string
Login string
Name string
Email string
Groups []string
SiteAdmin bool
}
43 changes: 43 additions & 0 deletions cmd/gh-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"log/slog"
"os"
"os/signal"
"syscall"

"github.com/joho/godotenv"

applog "github.com/ngaut/agent-git-service/internal/logging"
"github.com/ngaut/agent-git-service/server"
)

func main() {
if len(os.Args) > 1 && os.Args[1] == "wiki-reindex" {
_ = godotenv.Load()
applog.Init()
if err := server.RunWikiReindex(os.Args[2:]); err != nil {
slog.Error("wiki reindex failed", "error", err)
os.Exit(1)
}
return
}

_ = godotenv.Load()
applog.Init()

sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
defer signal.Stop(sigCh)

done := make(chan struct{})
go func() {
<-sigCh
close(done)
}()

if err := server.Run(done); err != nil {
slog.Error("bootstrap failed", "error", err)
os.Exit(1)
}
}
Loading
Loading