Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
42be1af
fix(billing): enforce quota floor and unlimited-token relay safety
YUANJIA Jul 16, 2026
163f31c
fix(auth): DB-backed session refresh and TokenAuthReadOnly hardening
YUANJIA Jul 16, 2026
f59736a
feat(channel): adaptive load balancing with circuit breaker and scoring
YUANJIA Jul 16, 2026
cca5c86
feat(perf-metrics): performance metrics collection and index
YUANJIA Jul 16, 2026
c18e9f0
refactor(common): deduplicate constants, init ordering, and env wiring
YUANJIA Jul 16, 2026
fe98836
fix(frontend): security hardening and auth flow fixes
YUANJIA Jul 16, 2026
5cf7898
perf(frontend): pricing/channels rendering and interaction improvements
YUANJIA Jul 16, 2026
4b24572
feat(i18n): wallet payment hooks and locale file updates
YUANJIA Jul 16, 2026
9a1013d
fix(misc): log model, xAI relay test, and theme setting
YUANJIA Jul 16, 2026
39d99ac
fix(channel): use path+model filter in GetSatisfiedChannels
YUANJIA Jul 16, 2026
2e07d73
fix(web): repair channel drawer import block
YUANJIA Jul 16, 2026
d02d938
fix(channel): retry depleted channels with circuit-safe selection
YUANJIA Jul 17, 2026
5c85d17
fix(security): refresh sessions and bound affinity keys
YUANJIA Jul 17, 2026
3816131
fix(web): harden redirects and fill channel grid
YUANJIA Jul 17, 2026
d99f32e
feat(platform): harden runtime and production quality gates
YUANJIA Jul 17, 2026
25abf77
feat: harden runtime health and task shutdown
YUANJIA Jul 17, 2026
0c3a3e1
chore: make release builds traceable
YUANJIA Jul 17, 2026
00f4281
fix: sanitize legacy frontend HTML
YUANJIA Jul 17, 2026
82a36ce
fix: build embedded assets before Go quality gate
YUANJIA Jul 17, 2026
f0f7569
fix: correct embedded asset CI indentation
YUANJIA Jul 18, 2026
abf05c7
fix: install full workspace in classic image build
YUANJIA Jul 18, 2026
aa3d6ea
feat: add frontend/backend delivery seam for separated deploys
YUANJIA Jul 18, 2026
3213db0
fix: defer nginx upstream DNS so frontend config test works offline
YUANJIA Jul 18, 2026
ba71c8b
chore: harden separated delivery ops and pin nginx base in CI
YUANJIA Jul 18, 2026
f0d1dcd
chore: align local dev backend with frontend_external seam
YUANJIA Jul 18, 2026
0c41e6d
fix: default UI and API locale fallback to Simplified Chinese
YUANJIA Jul 18, 2026
cfff28c
fix: force Chinese UI default past browser English detection
YUANJIA Jul 18, 2026
6ce0799
fix: unwrap nested translation namespace for default frontend i18n
YUANJIA Jul 18, 2026
bbddd72
fix: stop SPA fallback from masking backend and metrics paths
YUANJIA Jul 18, 2026
186404f
docs: add cookie/https, oauth callback, and CF HSTS runbooks
YUANJIA Jul 18, 2026
3830dc0
feat: send HSTS on HTTPS-proxied requests
YUANJIA Jul 18, 2026
5f5a28c
docs: record production ServerAddress/passkey and HSTS execution
YUANJIA Jul 18, 2026
1a255bf
docs: mark GitHub OAuth callback verified; note homepage URL fix
YUANJIA Jul 18, 2026
a1b446a
docs: record GitHub OAuth homepage URL update
YUANJIA Jul 18, 2026
e047ba9
fix: clear session cookie and hard-redirect after sign-out
YUANJIA Jul 18, 2026
33be725
fix: suppress session-expired noise during intentional sign-out
YUANJIA Jul 18, 2026
3f80ca7
docs: add healthcheck regression report and refreshed project overview
YUANJIA Jul 18, 2026
796a9d4
Merge pull request #1 from xvyimu/feat/adaptive-channel-balance-rc12
xvyimu Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
# 端口号
# PORT=3000
# 前端基础URL
# FRONTEND_BASE_URL=https://your-frontend-url.com
# 前端交付模式(与 RUN_MODE / APP_PLANE 正交):
# auto - 默认兼容:slave + FRONTEND_BASE_URL 时跳转,否则使用嵌入资源
# embedded - 强制嵌入双主题;frontend_external 构建会启动失败
# redirect - 强制把未知页面 301 到 FRONTEND_BASE_URL(含 master)
# disabled - 纯后端,不注册前端 NoRoute;配合独立 Nginx 前端镜像
# FRONTEND_MODE=auto
# 前端基础 URL:仅 redirect/auto(slave) 使用;必须是无路径/查询/凭据的 HTTP(S) origin
# FRONTEND_BASE_URL=https://console.example.com
# 允许浏览器跨域访问 API 的可信来源,默认不允许跨域;多个来源用英文逗号分隔
# 同源 Nginx 反代时通常无需配置 CORS_ALLOWED_ORIGINS
# CORS_ALLOWED_ORIGINS=https://console.example.com,https://admin.example.com
# HTTP 慢连接防护;流式响应不设置全局 WriteTimeout
# HTTP_READ_HEADER_TIMEOUT_SECONDS=10
# HTTP_IDLE_TIMEOUT_SECONDS=120
# HTTP_MAX_HEADER_BYTES=1048576
# 进程职责与 HTTP 平面;默认 all 保持单进程兼容
# RUN_MODE=all # all|serve|worker|scheduler|migrate
# APP_PLANE=all # all|relay|management
# Prometheus 指标默认关闭;启用后建议同时配置随机 Bearer token
# 独立前端边缘默认不代理 /metrics,请在后端网络内抓取
# METRICS_ENABLED=false
# METRICS_TOKEN=


# 调试相关配置
Expand Down Expand Up @@ -33,6 +53,7 @@
# SQL_MAX_OPEN_CONNS=1000
# 数据库连接最大生命周期(秒)
# SQL_MAX_LIFETIME=60
# READINESS_TIMEOUT_SECONDS=3


# 缓存相关配置
Expand All @@ -58,6 +79,15 @@
# RELAY_TIMEOUT=0
# Relay HTTP 客户端空闲连接超时时间,单位秒,默认跟随 Go 标准库,设置为0表示不限制
# RELAY_IDLE_CONN_TIMEOUT=90
# RELAY_DIAL_TIMEOUT=10
# RELAY_TLS_HANDSHAKE_TIMEOUT=10
# RELAY_RESPONSE_HEADER_TIMEOUT=120
# RELAY_EXPECT_CONTINUE_TIMEOUT=1
# Comma-separated proxy IPs/CIDRs whose forwarding headers may be trusted.
# Leave unset to ignore X-Forwarded-For and X-Real-IP. For a local reverse proxy,
# use TRUSTED_PROXY_CIDRS=127.0.0.1/32,::1/128 only when port 3000 is not directly exposed.
# Separated frontend Nginx in Docker usually needs the compose bridge CIDR, e.g. 172.16.0.0/12.
# TRUSTED_PROXY_CIDRS=
# 流模式无响应超时时间,单位秒,如果出现空补全可以尝试改为更大值
# STREAMING_TIMEOUT=300

Expand Down
192 changes: 192 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
name: Quality Gate

on:
workflow_call:
pull_request:
push:
branches:
- main

permissions:
contents: read

concurrency:
group: quality-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
go-quality:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version: 1.26.5
cache: true

- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14

- name: Build embedded frontend assets
working-directory: web
env:
DISABLE_ESLINT_PLUGIN: 'true'
run: |
bun install --frozen-lockfile
(cd default && bun run build)
(cd classic && bun run build)

- name: Validate build metadata
run: |
test -s VERSION
test "$(go env GOVERSION)" = "go1.26.5"

- name: Build
run: go build -trimpath -buildvcs=true ./...

- name: Build pure backend without embedded frontend
# frontend_external excludes //go:embed web/*/dist so the backend can ship without Bun assets.
run: go build -trimpath -buildvcs=true -tags frontend_external .

- name: Test
env:
GOSUMDB: sum.golang.org
run: go test -count=1 ./...

- name: Test pure backend package with frontend_external
env:
GOSUMDB: sum.golang.org
run: go test -count=1 -tags frontend_external .

- name: Vet
run: go vet ./...

- name: Vulnerability scan
run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
govulncheck ./...

web-quality:
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Set up Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.3.14

- name: Install locked dependencies
working-directory: web
run: bun install --frozen-lockfile

- name: Audit dependencies
working-directory: web
run: bun audit

- name: Typecheck default frontend
working-directory: web/default
run: bun run typecheck

- name: Test default frontend
working-directory: web/default
run: bun test

- name: Build default frontend
working-directory: web/default
env:
DISABLE_ESLINT_PLUGIN: 'true'
run: bun run build

- name: Enforce entry bundle budget
working-directory: web/default
run: bun run bundle:check

- name: Test classic frontend
working-directory: web/classic
run: bun test

- name: Build classic frontend
working-directory: web/classic
run: bun run build

- name: Enforce classic bundle budget
working-directory: web/classic
run: bun run bundle:check

- name: Test shared web tooling
working-directory: web
run: bun run test:tooling

image-reproducibility:
needs: [go-quality, web-quality]
runs-on: ubuntu-latest
steps:
- name: Check out
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Build pinned integrated image
run: docker build --tag new-api:quality .

- name: Build pure backend image
run: docker build -f Dockerfile.backend --tag new-api-backend:quality .

- name: Resolve nginx unprivileged base digest
# Pin the frontend runtime base at build time so floating tags cannot silently drift.
id: nginx_base
run: |
set -euo pipefail
IMAGE_REF='nginxinc/nginx-unprivileged:1.27-alpine'
docker pull "$IMAGE_REF"
DIGEST_REF="$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_REF")"
test -n "$DIGEST_REF"
echo "image=${DIGEST_REF}" >> "$GITHUB_OUTPUT"
echo "Pinned frontend nginx base: ${DIGEST_REF}" >> "$GITHUB_STEP_SUMMARY"

- name: Build separated frontend image
run: |
docker build \
-f deploy/separated/Dockerfile.frontend \
--build-arg "NGINX_IMAGE=${{ steps.nginx_base.outputs.image }}" \
--tag new-api-frontend:quality .

- name: Validate frontend Nginx configuration
# Variable proxy_pass + resolver defers DNS; use loopback upstream so nginx -t
# does not require a live backend hostname in this single-container job.
run: |
docker run --rm --entrypoint /bin/sh new-api-frontend:quality -c '
set -eu
export BACKEND_UPSTREAM=127.0.0.1:3000
export DNS_RESOLVER=127.0.0.1
export NGINX_PORT=8080
export SERVER_NAME=_
export CLIENT_MAX_BODY_SIZE=100m
export PROXY_CONNECT_TIMEOUT=60s
export PROXY_SEND_TIMEOUT=3600s
export PROXY_READ_TIMEOUT=3600s
envsubst '\''${BACKEND_UPSTREAM} ${NGINX_PORT} ${SERVER_NAME} ${CLIENT_MAX_BODY_SIZE} ${PROXY_CONNECT_TIMEOUT} ${PROXY_SEND_TIMEOUT} ${PROXY_READ_TIMEOUT} ${DNS_RESOLVER}'\'' \
< /etc/nginx/templates/nginx.conf.template > /tmp/nginx-test.conf
nginx -t -c /tmp/nginx-test.conf
'

- name: Record separated image digests
if: always()
run: |
{
echo '### Separated delivery images'
for image in new-api:quality new-api-backend:quality new-api-frontend:quality; do
if docker image inspect "$image" >/dev/null 2>&1; then
id="$(docker image inspect --format='{{.Id}}' "$image")"
echo "- \`${image}\`: \`${id}\`"
else
echo "- \`${image}\`: missing"
fi
done
echo "- nginx base: \`${{ steps.nginx_base.outputs.image }}\`"
} >> "$GITHUB_STEP_SUMMARY"
29 changes: 19 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ on:
- '!*-alpha*'

jobs:
quality-gate:
name: Quality Gate
uses: ./.github/workflows/quality.yml
permissions:
contents: read

linux:
name: Linux Release
needs: quality-gate
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -28,7 +35,7 @@ jobs:
echo "VERSION=$VERSION" >> $GITHUB_ENV
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
bun-version: 1.3.14
- name: Build Frontend (default)
env:
CI: ""
Expand All @@ -50,16 +57,16 @@ jobs:
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version: '>=1.25.1'
go-version: 1.26.5
- name: Build Backend (amd64)
run: |
go mod download
go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-$VERSION
go build -trimpath -buildvcs=true -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-$VERSION
- name: Build Backend (arm64)
run: |
sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y gcc-aarch64-linux-gnu
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-arm64-$VERSION
CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -trimpath -buildvcs=true -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$VERSION' -extldflags '-static'" -o new-api-arm64-$VERSION
- name: Generate checksums
run: sha256sum new-api-* > checksums-linux.txt

Expand All @@ -75,6 +82,7 @@ jobs:

macos:
name: macOS Release
needs: quality-gate
runs-on: macos-latest
steps:
- name: Checkout
Expand All @@ -87,7 +95,7 @@ jobs:
echo "VERSION=$VERSION" >> $GITHUB_ENV
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
bun-version: 1.3.14
- name: Build Frontend (default)
env:
CI: ""
Expand All @@ -110,11 +118,11 @@ jobs:
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version: '>=1.25.1'
go-version: 1.26.5
- name: Build Backend
run: |
go mod download
go build -ldflags "-X 'new-api/common.Version=$VERSION'" -o new-api-macos-$VERSION
go build -trimpath -buildvcs=true -ldflags "-X 'github.com/QuantumNous/new-api/common.Version=$VERSION'" -o new-api-macos-$VERSION
- name: Generate checksums
run: shasum -a 256 new-api-macos-* > checksums-macos.txt

Expand All @@ -130,6 +138,7 @@ jobs:

windows:
name: Windows Release
needs: quality-gate
runs-on: windows-latest
defaults:
run:
Expand All @@ -145,7 +154,7 @@ jobs:
echo "VERSION=$VERSION" >> $GITHUB_ENV
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
bun-version: 1.3.14
- name: Build Frontend (default)
env:
CI: ""
Expand All @@ -167,11 +176,11 @@ jobs:
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version: '>=1.25.1'
go-version: 1.26.5
- name: Build Backend
run: |
go mod download
go build -ldflags "-s -w -X 'new-api/common.Version=$VERSION'" -o new-api-$VERSION.exe
go build -trimpath -buildvcs=true -ldflags "-s -w -X 'github.com/QuantumNous/new-api/common.Version=$VERSION'" -o new-api-$VERSION.exe
- name: Generate checksums
run: sha256sum new-api-*.exe > checksums-windows.txt

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ data/
token_estimator_test.go
skills-lock.json
.playwright-mcp
artifacts/

# Local-only live probes and scratch test workspaces.
.local-tests/
Expand Down
Loading
Loading