Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
da74bf1
fix(gemini): discover antigravity mappings in native model lists
HuntercodeT Sep 15, 2026
881f320
chore: sync VERSION to 0.2.5 [skip ci]
github-actions[bot] Sep 15, 2026
d7ee1ab
fix(openai): persist response affinity after client cancel
xO-ox-ai Sep 15, 2026
21532ad
fix(payment): reset the order page when changing status
ouchihao Sep 15, 2026
0ed735d
fix(proxies): reuse in-flight test guards during batch testing
ouchihao Sep 15, 2026
14636d2
fix(totp): display normalized API error messages
ouchihao Sep 15, 2026
6a4938b
fix(announcements): preserve successful bulk read results
ouchihao Sep 15, 2026
130ba63
fix(clipboard): report errors thrown by the copy fallback
ouchihao Sep 15, 2026
8e34ca5
fix(account): keep refreshing OAuth tokens for paused accounts
bitnom Sep 15, 2026
18d483c
fix: 分组用量汇总不再全表扫 usage_logs
HuntercodeT Sep 16, 2026
a9ed218
feat(redeem): paginate user redemption history
wucm667 Sep 16, 2026
2f16e09
fix(openai): avoid duplicate manifest parsing
xz-dev Sep 14, 2026
31f3003
fix(openai): preserve manifest key validation
xz-dev Sep 14, 2026
18bfa4b
fix(gateway): normalize developer roles for strict Chat upstreams
HypoxanthineOvO Sep 16, 2026
1a32b91
fix(pagination): handle numeric jump input
ouchihao Sep 16, 2026
ee9ac3e
fix(auth): keep TOTP setup digits in sync with state
ouchihao Sep 16, 2026
98321a0
fix(payment): restore accepted text after invalid amount input
ouchihao Sep 16, 2026
0838e0e
fix(admin): reject negative platform quota limits before saving
ouchihao Sep 16, 2026
f8e5a0d
fix(channels): allow tabbing out of an empty model input
ouchihao Sep 16, 2026
fe36f4a
fix: prevent promo code field flash on registration
Liu8Can Sep 16, 2026
881ab1b
fix(deepseek): lift Responses tool output images
laoxiechuzheng Sep 16, 2026
be4a499
fix(antigravity): strip Claude attribution metadata from system prompts
zhudaguaneren Sep 17, 2026
611c30f
chore(deps): 升级 google.golang.org/grpc 到 v1.83.2 修复 govulncheck 报告的两条公告
HuntercodeT Sep 17, 2026
017e9e9
fix(payment): base refund balance warnings on the requested amount
ouchihao Sep 17, 2026
be31373
fix(ui): keep dialog title IDs unique across instances
ouchihao Sep 17, 2026
b51f075
fix(payment): await in-flight configuration requests
ouchihao Sep 17, 2026
406be7c
fix(subscriptions): reset loading when clearing state
ouchihao Sep 17, 2026
acc0562
fix(deepseek): keep parallel Responses tool outputs contiguous
laoxiechuzheng Sep 17, 2026
4daabc3
Merge pull request #7234 from ouchihao/codex/bug-pagination-jump-number
Wei-Shaw Sep 17, 2026
131893e
Merge pull request #7237 from ouchihao/codex/bug-platform-quota-negative
Wei-Shaw Sep 17, 2026
44831bb
Merge pull request #7261 from HuntercodeT/chore/bump-grpc-1.83.2
Wei-Shaw Sep 17, 2026
7e4164c
Merge pull request #7207 from HuntercodeT/fix/group-usage-summary-seq…
Wei-Shaw Sep 17, 2026
d52ab27
Merge pull request #7173 from HuntercodeT/fix/gemini-native-mixed-mod…
Wei-Shaw Sep 17, 2026
40e7ce7
Merge pull request #7265 from ouchihao/codex/bug-payment-config-await
Wei-Shaw Sep 17, 2026
ea68c0e
Merge pull request #7263 from ouchihao/codex/bug-dialog-title-ids
Wei-Shaw Sep 17, 2026
efd86c6
Merge pull request #7235 from ouchihao/codex/bug-totp-setup-input-sync
Wei-Shaw Sep 17, 2026
5f75e0d
Merge pull request #7186 from ouchihao/codex/bug-clipboard-fallback-e…
Wei-Shaw Sep 17, 2026
55bde08
Merge pull request #7185 from ouchihao/codex/bug-announcement-read-re…
Wei-Shaw Sep 17, 2026
53fd5f8
Merge pull request #7183 from ouchihao/codex/bug-proxy-test-dedup
Wei-Shaw Sep 17, 2026
10fd1ad
Merge pull request #7182 from ouchihao/codex/bug-orders-filter-page
Wei-Shaw Sep 17, 2026
71c0eb5
Merge pull request #7184 from ouchihao/codex/bug-totp-error-messages
Wei-Shaw Sep 17, 2026
57e9f6a
Merge pull request #7238 from ouchihao/codex/bug-model-tag-tab-naviga…
Wei-Shaw Sep 17, 2026
ffa4360
Merge pull request #7236 from ouchihao/codex/bug-payment-amount-input
Wei-Shaw Sep 17, 2026
0932e8c
Merge pull request #7266 from ouchihao/codex/bug-subscription-loading…
Wei-Shaw Sep 17, 2026
cd1834e
Merge pull request #7262 from ouchihao/codex/bug-refund-balance-warning
Wei-Shaw Sep 17, 2026
c84a3d5
Merge pull request #7215 from xz-dev/fix/manifest-double-parse
Wei-Shaw Sep 17, 2026
5050471
Merge pull request #7239 from Liu8Can/fix/register-promo-code-flicker
Wei-Shaw Sep 17, 2026
9efc167
Merge pull request #7195 from bitnom/fix/refresh-paused-oauth-accounts
Wei-Shaw Sep 17, 2026
b4e5608
Merge pull request #7177 from xO-ox-ai/codex/fix-openai-response-bind…
Wei-Shaw Sep 17, 2026
48a86ec
Merge pull request #7224 from HypoxanthineOvO/codex/upstream-chat-rol…
Wei-Shaw Sep 17, 2026
18328ae
Merge pull request #7212 from wucm667/feat/issue-7203-redemption-pagi…
Wei-Shaw Sep 17, 2026
aeab57b
Merge pull request #7256 from zhudaguaneren/fix/antigravity-attributi…
Wei-Shaw Sep 17, 2026
efe9aab
Merge pull request #7246 from laoxiechuzheng/fix/deepseek-native-resp…
Wei-Shaw Sep 17, 2026
bc47e21
feat(openai): harvest and inject 292 x-codex-turn-state tickets for o…
Tinghecui Sep 18, 2026
d14054a
feat(openai): add live harvest proxy settings and protect ticket state
Tinghecui Sep 18, 2026
1ba0b4f
feat(openai): add admin toggle for Codex ticket harvest and inject
Tinghecui Sep 18, 2026
f79381b
fix(openai): harden Codex ticket lifecycle and account handling
Tinghecui Sep 18, 2026
c44e689
fix(openai): gate Codex tickets on the outbound compact model
Wei-Shaw Sep 18, 2026
3c2f05c
fix(openai): keep ticket writes off the scheduler and account edit paths
Wei-Shaw Sep 18, 2026
49a39b6
Merge pull request #7315 from Tinghecui/feat/openai-codex-turn-state-…
Wei-Shaw Sep 18, 2026
0d2a4e0
chore: recover upstream v0.2.6 codex ticket integration
Sep 18, 2026
c3795ee
docs: record v0.2.6 integration validation
Sep 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
2 changes: 1 addition & 1 deletion .downstream/upstream-base
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.2.5
v0.2.6
39 changes: 39 additions & 0 deletions .downstream/upstream-review-v0.2.6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Recovered upstream v0.2.6 integration review

## Source and provenance

- Downstream base: `v0.2.5-codexrip.14`, commit `a2f13d34a41bb89225e5d6864d466b4a35d6448f`.
- Recovered upstream commit: `49a39b6dc1abed30fd227611e8af1108bc427610`.
- Upstream parents: `efe9aab1e4ec89a42ba45e8dac20e882c5409a6a`, `3c2f05c957b4b93866318ec8695fc5a28fff70eb`.
- Upstream tree: `61de86700f217d58c337998f3c51a89969493267`.
- The public `v0.2.6` tag/Release is withdrawn. This review uses the exact commit object; it does not use a mutable tag or `latest` image.
- Machine-readable evidence: `.downstream/upstream-risk.json`. It records the exact commit, tree, parents, tag-unavailable state, overlap counts and the original Git conflict list.

## Integration scope

The complete recovered merge tree is integrated. This includes the upstream changes after the official v0.2.5 baseline and the six Codex ticket patches: ticket harvesting, live management settings, ticket injection, export/edit redaction, compact-model gating and scheduler-neutral ticket writes.

Ticket runtime defaults remain safe: `enabled=false`, empty harvest proxy, `fail_closed=true`, 292-character state, one-hour TTL, ten-minute refresh window, and the upstream target models. No harvest proxy is written during this release and the management switch stays off.

## Conflict decisions

- Account DTOs retain downstream fields for provider identity, folders, tags, Cindy state, quotas, shadow accounts and parent metadata; upstream `codex_turn_tickets` status is added without returning private state.
- Locked account Extra merging retains downstream model-context capacity/override/metadata values and upstream current ticket entries. Non-object historical Extra values degrade ticket preservation without blocking account edits.
- Account Extra updates preserve downstream reasoning/fingerprint/quota protections and reject administrator-supplied ticket material.
- Wire generation retains downstream account jobs, Cindy health/balance, system prompts, remote skills, Image Studio, traffic telemetry and identity backfill while wiring the upstream SettingService, PluginManager and ticket harvester lifecycle.
- OpenAI OAuth/Setup Token scheduling combines official outbound-model/compact ticket gating with downstream runtime-breaker, probe-ownership, cooldown and continuation/sticky protections. Cindy/API-key paths do not enter the ticket predicate.
- Response affinity uses the downstream cancellation-independent Redis context and upstream owner-binding diagnostics.
- Frontend settings and account views retain downstream Cindy and permission behavior while adding ticket status, masked proxy settings and live-toggle coverage.
- Public model management remains retired; Image Studio and Responses image bridge remain off by default.

## Validation status

- Passed: Wire regeneration, focused backend ticket/account/DTO tests, focused frontend settings/account/dialog/manifest tests, frontend production build and `git diff --check`.
- Passed: full backend compile (`go test -run '^$' ./...`), `go vet ./...`, `go mod verify`, focused runtime/continuation/Cindy tests and risk/automation contract tests.
- Passed: US `resource-preflight` baseline; evidence `artifacts/evidence/us-runtime-audit-2026-09-18_140357_769694.log` records the `.14` image, digest, healthy container, resource profile, guard hashes and unchanged companion services.
- Pending: required PR checks, Release and production deployment.
- Not run: real upstream model calls, harvest-proxy calls, management-page activation, canary, long observation and production deployment.

## Release boundary

The candidate release is `v0.2.6-codexrip.1`. Production deployment uses the existing immutable-digest `deploy-preserve` path and changes only the `sub2api` container. The release does not claim that ticket quality improvements have been model-validated while the feature remains disabled.
1,055 changes: 559 additions & 496 deletions .downstream/upstream-risk.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ deploy/docker-compose.override.yml
.gocache/
vite.config.js
docs/*
!docs/ANTIGRAVITY_ATTRIBUTION_429.md
!docs/PAYMENT.md
!docs/PAYMENT_CN.md
!docs/ADMIN_PAYMENT_INTEGRATION_API.md
Expand Down
7 changes: 7 additions & 0 deletions DOWNSTREAM.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ This fork maintains the `codexrip` patch set over official Sub2API releases.
- The operator workspace `docs/sub2api.md` owns the current production pointer.
A source merge or Release alone does not establish deployment completion.

### Recovered upstream v0.2.6

- The withdrawn upstream release is recovered from exact merge commit `49a39b6dc1abed30fd227611e8af1108bc427610`; the remote `v0.2.6` tag is not used as a source.
- The merge includes the official changes after v0.2.5 and the six Codex ticket patches. The ticket feature remains runtime-disabled in the published deployment until an administrator supplies a harvest proxy and enables it from the settings page.
- Ticket collection and injection apply only to OpenAI OAuth and Setup Token accounts. Cindy/API-key accounts retain their existing identity, health, quota and sticky-session behavior.
- The integration review and one-off exact-SHA risk evidence are recorded in `.downstream/upstream-review-v0.2.6.md` and `.downstream/upstream-risk.json`.

## Official behavior and downstream contracts

OpenCode Zen/GO, site billing states, WebSocket execution scope and pooling,
Expand Down
2 changes: 1 addition & 1 deletion backend/cmd/server/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.5
0.2.6
6 changes: 6 additions & 0 deletions backend/cmd/server/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,12 @@ func provideCleanup(
}
return nil
}},
{"OpenAICodexTicketHarvester", func() error {
if openAIGateway != nil {
openAIGateway.StopOpenAICodexTicketHarvester()
}
return nil
}},
{"ScheduledTestRunnerService", func() error {
if scheduledTestRunner != nil {
scheduledTestRunner.Stop()
Expand Down
11 changes: 9 additions & 2 deletions backend/cmd/server/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:E
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
Expand Down
27 changes: 27 additions & 0 deletions backend/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,9 @@ type GatewayConfig struct {
// OpenAICompactModel: /responses/compact 上游使用的模型。
// compact 端点支持模型滞后于普通 /responses 时,可用该配置降级规避上游错误。
OpenAICompactModel string `mapstructure:"openai_compact_model"`
// OpenAICodexTicket: ChatGPT OAuth 账号按 (账号, 模型) 捕获 292 长度
// x-codex-turn-state,并在住宅 IP 业务请求中注入该头。默认关闭。
OpenAICodexTicket OpenAICodexTicketConfig `mapstructure:"openai_codex_ticket"`
// OpenAIWS: OpenAI Responses WebSocket 配置(默认开启,可按需回滚到 HTTP)
OpenAIWS GatewayOpenAIWSConfig `mapstructure:"openai_ws"`
// Live: ChatGPT Frameless Live 会话配置。
Expand Down Expand Up @@ -1236,6 +1239,21 @@ func (c *UserMessageQueueConfig) GetEffectiveMode() string {
return ""
}

// OpenAICodexTicketConfig 控制 ChatGPT OAuth 的 x-codex-turn-state 门票。
// 打票走 harvest_proxy_url(SOCKS),业务出站仍用账号住宅 proxy_id,只替换该请求头。
// 门票默认有效 3600 秒,临近过期前 refresh_before_seconds 重新打票。
type OpenAICodexTicketConfig struct {
Enabled bool `mapstructure:"enabled"`
TargetLength int `mapstructure:"target_length"`
TTLSeconds int `mapstructure:"ttl_seconds"`
RefreshBeforeSeconds int `mapstructure:"refresh_before_seconds"`
HarvestProxyURL string `mapstructure:"harvest_proxy_url"`
HarvestProbeIntervalSeconds int `mapstructure:"harvest_probe_interval_seconds"`
HarvestAttemptTimeoutSeconds int `mapstructure:"harvest_attempt_timeout_seconds"`
FailClosed bool `mapstructure:"fail_closed"`
Models []string `mapstructure:"models"`
}

// DefaultOpenAIWSClientFirstMessageTimeoutSeconds preserves the legacy ingress deadline.
const DefaultOpenAIWSClientFirstMessageTimeoutSeconds = 30

Expand Down Expand Up @@ -2406,6 +2424,15 @@ func setDefaults() {
viper.SetDefault("gateway.codex_image_generation_bridge_enabled", false)
viper.SetDefault("gateway.openai_passthrough_allow_timeout_headers", false)
viper.SetDefault("gateway.openai_compact_model", "gpt-5.5")
viper.SetDefault("gateway.openai_codex_ticket.enabled", false)
viper.SetDefault("gateway.openai_codex_ticket.target_length", 292)
viper.SetDefault("gateway.openai_codex_ticket.ttl_seconds", 3600)
viper.SetDefault("gateway.openai_codex_ticket.refresh_before_seconds", 600)
viper.SetDefault("gateway.openai_codex_ticket.harvest_proxy_url", "")
viper.SetDefault("gateway.openai_codex_ticket.harvest_probe_interval_seconds", 6)
viper.SetDefault("gateway.openai_codex_ticket.harvest_attempt_timeout_seconds", 25)
viper.SetDefault("gateway.openai_codex_ticket.fail_closed", true)
viper.SetDefault("gateway.openai_codex_ticket.models", []string{"gpt-6-astra", "gpt-5.6-sol"})
viper.SetDefault("gateway.live.max_session_duration_seconds", 3600)
// OpenAI Responses WebSocket(默认开启;可通过 force_http 紧急回滚)
viper.SetDefault("gateway.openai_ws.enabled", true)
Expand Down
36 changes: 36 additions & 0 deletions backend/internal/handler/admin/account_codex_ticket_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package admin

import (
"github.com/Wei-Shaw/sub2api/internal/config"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/stretchr/testify/require"
"testing"
)

func TestAccountResponseCodexTicketsUsesConfiguredPolicy(t *testing.T) {
account := &service.Account{ID: 41, Platform: service.PlatformOpenAI, Type: service.AccountTypeOAuth}
h := &AccountHandler{cfg: &config.Config{}}
require.Empty(t, h.accountResponseFromService(account).CodexTurnTickets)
require.Empty(t, h.accountListResponseFromService(account).CodexTurnTickets)
h.cfg.Gateway.OpenAICodexTicket = config.OpenAICodexTicketConfig{Enabled: true, Models: []string{"configured-model"}, FailClosed: false}
status := h.accountListResponseFromService(account).CodexTurnTickets
require.Len(t, status, 1)
require.Equal(t, "configured-model", status[0].Model)
require.False(t, status[0].Blocked)
h.cfg.Gateway.OpenAICodexTicket.FailClosed = true
require.True(t, h.accountResponseFromService(account).CodexTurnTickets[0].Blocked)
}

func TestAccountResponseCodexTicketsReadsLiveSettingsAfterRestart(t *testing.T) {
cfg := &config.Config{}
repo := &settingHandlerRepoStub{values: map[string]string{service.SettingKeyOpenAICodexTicketEnabled: "true"}}
settings := service.NewSettingService(repo, cfg)
h := &AccountHandler{cfg: cfg}
h.SetCodexTicketSettings(settings)
account := &service.Account{ID: 41, Platform: service.PlatformOpenAI, Type: service.AccountTypeSetupToken}
require.Len(t, h.accountListResponseFromService(account).CodexTurnTickets, 2)
require.False(t, cfg.Gateway.OpenAICodexTicket.Enabled)
repo.values[service.SettingKeyOpenAICodexTicketEnabled] = "false"
settings.InvalidateOpenAICodexTicketEnabledCache()
require.Empty(t, h.accountResponseFromService(account).CodexTurnTickets)
}
2 changes: 1 addition & 1 deletion backend/internal/handler/admin/account_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func (h *AccountHandler) ExportData(c *gin.Context) {
Platform: acc.Platform,
Type: acc.Type,
Credentials: acc.Credentials,
Extra: acc.Extra,
Extra: service.RedactOpenAICodexTicketExtra(acc.Extra),
ProxyKey: proxyKey,
Concurrency: acc.Concurrency,
Priority: acc.Priority,
Expand Down
22 changes: 22 additions & 0 deletions backend/internal/handler/admin/account_data_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,25 @@ func TestImportDataReusesProxyAndSkipsDefaultGroup(t *testing.T) {
require.Len(t, adminSvc.createdAccounts, 1)
require.True(t, adminSvc.createdAccounts[0].SkipDefaultGroupBind)
}

func TestExportDataExcludesCodexTicketMaterial(t *testing.T) {
router, adminSvc := setupAccountDataRouter()
extra := map[string]any{
"codex_turn_ticket:gpt-6-astra": map[string]any{"state": "private-ticket-blob", "length": 292},
"codex_harvest_proxy_url": "http://user:legacy-proxy-secret@proxy.example.com:8080",
"ordinary": "retained",
}
adminSvc.accounts = []service.Account{{ID: 21, Name: "account", Platform: service.PlatformOpenAI, Type: service.AccountTypeOAuth, Credentials: map[string]any{"access_token": "backup-token"}, Extra: extra}}
rec := httptest.NewRecorder()
router.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/v1/admin/accounts/data?include_proxies=false", nil))
require.Equal(t, http.StatusOK, rec.Code)
var resp dataResponse
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp))
require.Len(t, resp.Data.Accounts, 1)
require.Equal(t, map[string]any{"ordinary": "retained"}, resp.Data.Accounts[0].Extra)
require.Equal(t, "backup-token", resp.Data.Accounts[0].Credentials["access_token"])
require.NotContains(t, rec.Body.String(), "private-ticket-blob")
require.NotContains(t, rec.Body.String(), "legacy-proxy-secret")
require.Contains(t, extra, "codex_turn_ticket:gpt-6-astra")
require.Contains(t, extra, "codex_harvest_proxy_url")
}
Loading
Loading