Skip to content

fix bugs - #29

Merged
CSCITech merged 24 commits into
mainfrom
cscitech
Aug 9, 2026
Merged

CSCITech merged 24 commits into
mainfrom
cscitech

Conversation

@CSCITech

@CSCITech CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3cc1895d-af1a-4f0c-9f83-4c6ae11fb0e1

📥 Commits

Reviewing files that changed from the base of the PR and between d19614d and b152ca0.

📒 Files selected for processing (16)
  • common/pprof.go
  • common/pprof_test.go
  • controller/oauth.go
  • controller/oauth_test.go
  • main.go
  • main_test.go
  • model/auth_flow_test.go
  • oauth/http_client_test.go
  • oauth/oidc.go
  • relay/channel/ali/image.go
  • relay/channel/ali/text_test.go
  • relay/channel/coze/adaptor.go
  • relay/channel/coze/relay_coze_test.go
  • relay/common/pass_through_body.go
  • service/auth_flow_cleanup.go
  • service/auth_flow_cleanup_test.go
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • main_test.go
  • common/pprof_test.go
  • service/auth_flow_cleanup.go
  • model/auth_flow_test.go
  • relay/channel/coze/adaptor.go
  • oauth/oidc.go
  • relay/channel/coze/relay_coze_test.go
  • relay/channel/ali/text_test.go
  • common/pprof.go
  • service/auth_flow_cleanup_test.go
  • main.go
  • relay/channel/ali/image.go
  • relay/common/pass_through_body.go
  • controller/oauth_test.go
  • controller/oauth.go
  • oauth/http_client_test.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/coze/adaptor.go
  • relay/channel/coze/relay_coze_test.go
  • relay/channel/ali/text_test.go
  • relay/channel/ali/image.go
🔇 Additional comments (19)
service/auth_flow_cleanup_test.go (1)

12-30: LGTM!

service/auth_flow_cleanup.go (1)

13-28: LGTM!

Also applies to: 30-44

main_test.go (1)

29-29: LGTM!

common/pprof_test.go (2)

4-4: LGTM!


27-57: LGTM!

model/auth_flow_test.go (1)

23-23: LGTM!

relay/channel/coze/adaptor.go (2)

76-85: LGTM!


110-116: LGTM!

oauth/oidc.go (1)

143-144: LGTM!

relay/channel/coze/relay_coze_test.go (1)

25-28: LGTM!

relay/channel/ali/text_test.go (2)

86-110: LGTM!


112-132: LGTM!

common/pprof.go (1)

4-4: LGTM!

Also applies to: 15-20, 22-45, 47-84

main.go (1)

73-74: LGTM!

Also applies to: 133-133, 161-171, 201-206, 247-264, 323-337

relay/channel/ali/image.go (1)

27-56: LGTM!

Also applies to: 65-70

relay/common/pass_through_body.go (1)

30-34: LGTM!

Also applies to: 420-444

controller/oauth_test.go (1)

119-136: LGTM!

controller/oauth.go (1)

114-175: LGTM!

oauth/http_client_test.go (1)

100-119: LGTM!


📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Payment processing validates amounts, currencies, and methods across providers.
    • OAuth login and account binding use secure, one-time authentication flows.
    • Channel updates preserve omitted settings and support targeted changes.
    • Midjourney billing, refunds, and duplicate submissions are handled transactionally.
    • Graceful shutdown is supported for monitoring and rate limiting.
    • Safer trusted proxy, code highlighting, chart styling, pass-through requests, and video uploads.
  • Bug Fixes

    • Sensitive credentials, logs, and error messages are protected and sanitized.
    • Failed payment sessions remain pending and duplicate notifications are handled safely.
    • Authentication rejects disabled or deleted accounts.
    • External operations now respect timeouts and secure randomness.
    • Audit logs are retained correctly during cleanup.

Walkthrough

The change adds payment validation, transactional Midjourney billing, secure randomness, scoped updates, lifecycle shutdown controls, SSRF and trusted-proxy validation, secret redaction, replayable request bodies, and defensive service and frontend handling.

Changes

Payment integrity and order completion

Layer / File(s) Summary
Payment validation and model enforcement
model/payment_validation.go, model/topup.go, model/subscription.go, model/payment_method_guard_test.go
Payment amounts, currencies, and payment methods are validated before quota or subscription changes.
Provider payment wiring
controller/topup*.go, controller/subscription_payment*.go, controller/topup_*_test.go
Provider callbacks pass validated payment data to model operations. Checkout failures preserve pending orders.

Transactional Midjourney billing

Layer / File(s) Summary
Billing claims and settlement persistence
model/midjourney.go, model/task.go, model/main.go, service/billing_session.go
Claims, duplicate detection, task failure settlement, and refund inputs use transactional state changes.
Relay submission and polling integration
relay/mjproxy_handler.go, service/midjourney.go, service/midjourney_task.go, controller/midjourney.go, service/task_billing.go
Submission outcomes distinguish accepted, failed, and ambiguous requests. Polling applies channel-scoped updates and settlement handling.

Scoped state updates

Layer / File(s) Summary
Allowlisted channel persistence
model/channel.go, controller/channel.go, model/channel_update_fields_test.go, controller/channel_update_test.go
Channel updates persist selected fields, recalculate multi-key metadata, and apply transactional ability changes.
User, token, log, and task persistence
controller/user.go, model/user.go, model/token.go, model/log.go, model/task.go, *_test.go
User rewards, quota changes, token deletion, log sanitization, task failure reasons, and log cleanup use scoped persistence.

Runtime and input safeguards

Layer / File(s) Summary
Secure randomness and bounded access
common/*, controller/model_sync.go, common/email.go, middleware/turnstile-check.go
Random generation uses secure helpers. SMTP and Turnstile operations use bounded timeouts.
Lifecycle and shutdown controls
common/rate-limit.go, common/system_monitor.go, common/pprof.go, service/auth_flow_cleanup.go, main.go
Background components support synchronized initialization, cancellation, stopping, and shutdown reporting.
Network, body, and authentication safeguards
oauth/*, common/trusted_proxy.go, service/http.go, common/body_storage.go, relay/common/*, middleware/auth.go
OAuth, trusted-proxy, upstream-header, replay-body, pass-through, and authentication paths validate inputs and state.
Defensive service and frontend handling
pkg/billingexpr/*, relay/channel/*, service/*, controller/video_proxy.go, web/default/src/components/*
Invalid expression results, stream failures, oversized responses, upstream errors, video data URLs, cache growth, and rendered HTML/CSS receive explicit handling.

Estimated code review effort: 5 (Critical) | ~100 minutes

Possibly related PRs

Poem

A rabbit checks each payment trail,
Secure bits hop without fail.
Channels patch the fields they need,
Logs stay clean and streams succeed.
Timers stop when shutdown calls,
Safe paths guard the service halls.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "fix bugs" is too generic and does not identify the main changes across security, payment, OAuth, and lifecycle handling. Use a concise title that identifies the primary change, such as "Harden payment, OAuth, and task-processing flows".
Description check ❓ Inconclusive The description contains only an uncompleted submission template and does not explain the changes, rationale, testing, or proof of work. Provide a concise summary of the implemented changes, their rationale, related issues, validation results, and proof of work.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cscitech

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
controller/channel.go (1)

1078-1085: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

UpdateChannel writes channel_info without the channel polling lock.

Lines 1079-1085 read originChannel.ChannelInfo, mutate it, and later persist the whole channel_info column through UpdateFields. ManageMultiKeys performs the same read-modify-write but first takes model.GetChannelPollingLock(request.ChannelId) (line 1534) and reloads the channel under that lock. UpdateChannel takes no lock.

If an operator disables a key through ManageMultiKeys while an UpdateChannel request is in flight, the UpdateChannel write restores the stale MultiKeyStatusList and silently re-enables the disabled key.

Take model.GetChannelPollingLock(patch.Id) before loading originChannel, and release it after UpdateFields returns.

🔒 Proposed fix to serialize the two writers
+	lock := model.GetChannelPollingLock(patch.Id)
+	lock.Lock()
+	defer lock.Unlock()
+
 	// Preserve existing ChannelInfo to ensure multi-key channels keep correct state even if the client does not send ChannelInfo in the request.
 	originChannel, err := model.GetChannelById(patch.Id, true)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` around lines 1078 - 1085, Update UpdateChannel to
acquire model.GetChannelPollingLock(patch.Id) before loading originChannel, hold
it through the ChannelInfo read-modify-write and UpdateFields persistence, and
release it only after UpdateFields returns. Preserve the existing ChannelInfo
copy and MultiKeyMode update behavior while serializing it with ManageMultiKeys.
model/channel.go (1)

581-618: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The multi-key recalculation result is discarded when channel_info is not selected.

Lines 582-618 recalculate MultiKeySize and prune MultiKeyStatusList. editableUpdateMap writes channel_info only when the caller passes "channel_info" in fields. If a caller passes "key" without "channel_info", the new key list is persisted and the stored MultiKeySize stays stale. Line 626 then reloads the old ChannelInfo over the recalculated value.

Add "channel_info" to the update map whenever the recalculation runs and "key" is selected.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel.go` around lines 581 - 618, The multi-key recalculation in the
channel update flow is discarded when only “key” is selected because
“channel_info” is absent from editableUpdateMap. In the recalculation block
around channel.ChannelInfo.MultiKeySize, ensure the update map includes
“channel_info” whenever recalculation runs for a selected key update, so the
recalculated size and pruned MultiKeyStatusList are persisted before the later
reload.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/channel_update_test.go`:
- Around line 117-131: Strengthen TestUpdateChannelRejectsUnknownStatus by
asserting the response error message specifically identifies the invalid status
validation, not merely response.Success. Extend the channel update tests with
key_mode cases for “append” and “replace”, exercising the corresponding
UpdateChannel paths and asserting both the persisted key list and resulting
MultiKeySize.
- Around line 15-16: Update the test setup around openTokenControllerTestDB to
use the returned db handle consistently for subsequent read assertions, rather
than relying on model.DB; keep the existing migration setup unchanged and
replace any model.DB.First calls in this test with the local db handle.

In `@controller/channel.go`:
- Line 1710: Update the channel field-persistence flow around UpdateFields and
UpdateAbilities so ability rows are rebuilt only when the requested update set
contains an ability-relevant field (models, group, status, priority, weight, or
tag). Keep channel_info-only updates from invoking UpdateAbilities(nil), while
preserving the existing rebuild behavior for updates that affect those fields.

In `@model/channel.go`:
- Around line 619-630: Update model/channel.go lines 619-630 in UpdateFields to
execute the field update, channel reload, and conditional UpdateAbilities(tx)
within one DB.Transaction; invoke the rebuild only when updates include models,
group, status, priority, weight, or tag, and pass the transaction to
UpdateAbilities. No direct change is needed at controller/channel.go line 1710
or its sibling call sites, as the model-level gating handles channel_info-only
updates.

---

Outside diff comments:
In `@controller/channel.go`:
- Around line 1078-1085: Update UpdateChannel to acquire
model.GetChannelPollingLock(patch.Id) before loading originChannel, hold it
through the ChannelInfo read-modify-write and UpdateFields persistence, and
release it only after UpdateFields returns. Preserve the existing ChannelInfo
copy and MultiKeyMode update behavior while serializing it with ManageMultiKeys.

In `@model/channel.go`:
- Around line 581-618: The multi-key recalculation in the channel update flow is
discarded when only “key” is selected because “channel_info” is absent from
editableUpdateMap. In the recalculation block around
channel.ChannelInfo.MultiKeySize, ensure the update map includes “channel_info”
whenever recalculation runs for a selected key update, so the recalculated size
and pruned MultiKeyStatusList are persisted before the later reload.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 59c0d7c2-e7d1-4d09-bdd9-0df929930d5c

📥 Commits

Reviewing files that changed from the base of the PR and between 923aaad and c74ed57.

📒 Files selected for processing (10)
  • common/str.go
  • common/utils.go
  • controller/channel.go
  • controller/channel_update_test.go
  • controller/model_sync.go
  • controller/oauth.go
  • model/channel.go
  • model/channel_cache.go
  • model/checkin.go
  • tools/jsonwrapcheck/allowlist.txt
💤 Files with no reviewable changes (1)
  • tools/jsonwrapcheck/allowlist.txt
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/channel_cache.go
  • controller/oauth.go
  • controller/channel_update_test.go
  • common/str.go
  • model/checkin.go
  • controller/model_sync.go
  • common/utils.go
  • model/channel.go
  • controller/channel.go
🔇 Additional comments (18)
common/utils.go (1)

10-11: LGTM!

Also applies to: 255-270, 296-300

common/str.go (1)

10-11: LGTM!

Also applies to: 42-46

model/channel_cache.go (1)

5-6: LGTM!

Also applies to: 225-228

model/checkin.go (1)

4-5: LGTM!

Also applies to: 72-76

controller/model_sync.go (1)

8-9: LGTM!

Also applies to: 28-35, 166-166, 238-238

controller/oauth.go (1)

82-92: LGTM!

model/channel.go (4)

260-264: LGTM!


341-341: LGTM!


704-705: 🗄️ Data Integrity & Integration

No change needed for channel_info serialization.

ChannelInfo implements driver.Valuer and sql.Scanner, so placing it in the update map uses the same JSON-driver path as the model field.


548-575: 🗄️ Data Integrity & Integration

No change needed.

Update() maps only non-pointer fields unconditionally, but there are no direct Channel.Update() callers outside model/channel.go, so the current path does not introduce a new partial-update regression.

controller/channel.go (6)

922-947: LGTM!


949-1049: LGTM!


1051-1069: LGTM!


1096-1098: LGTM!

Also applies to: 1123-1139, 1171-1178


1210-1210: LGTM!


1753-1753: LGTM!

Also applies to: 1778-1778, 1826-1826, 1907-1907, 1976-1976

controller/channel_update_test.go (2)

49-93: LGTM!


95-115: LGTM!

Comment thread controller/channel_update_test.go
Comment thread controller/channel_update_test.go
Comment thread controller/channel.go
Comment thread model/channel.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/custom_oauth_test.go`:
- Around line 36-37: Update the test setup around fetchSetting.AllowedPorts to
parse the port from the httptest.NewServer URL and append it to the allowed
ports before making the request. Preserve the existing fixed ports and ensure
the ephemeral test-server port is permitted so validation reaches the private-IP
check.

In `@controller/topup_waffo_pancake_test.go`:
- Around line 194-200: Update the response assertion in the
RequestWaffoPancakePay test to require the specific checkout-session failure
message rather than the generic `"message":"error"` text. Keep the existing
status and database assertions unchanged.

In `@controller/topup_waffo_pancake.go`:
- Around line 501-502: Update the PaymentValidationFromMajorString call in the
Pancake subscription callback to pass an empty expected-currency value instead
of "USD", allowing validatePaymentAgainstSubscriptionOrder to use the
subscription plan’s currency. Keep the remaining amount and currency arguments
unchanged.

In `@controller/topup.go`:
- Around line 371-375: Update the ignore-event log in the webhook handler around
the TradeStatus check to remove the repeated verifyInfo payload. Retain the
trade number and trade status fields, while omitting the
common.GetJsonString(verifyInfo) argument and any other unnecessary duplicated
request data.
- Around line 355-358: Remove the immediately invoked writeErr closure and
directly assign the result of c.Writer.Write to writeErr, preserving the
existing "fail" response bytes and error handling.

In `@controller/user_setting_test.go`:
- Around line 182-227: Add tests alongside
TestUpdateUserSettingPreservesStoredSecretsWhenRedactedFieldsAreOmitted covering
Gotify token retention: preserve an existing token when the request omits it
while the stored notification type is Gotify, and verify the token is not
retained when the stored notification type is non-Gotify. Reuse the existing
setup, request, and persistence assertions while targeting the Gotify-specific
branches.

In `@model/log_cleanup_test.go`:
- Around line 44-61: Extend TestDeleteOldLogBatchPreservesManagementAuditLogs to
call CountOldLog with the same context and cutoff used by DeleteOldLogBatch,
asserting it returns 1 before deletion and 0 afterward; retain the existing
deletion and management-log assertions.

In `@model/payment_method_guard_test.go`:
- Around line 415-417: The currency-mismatch tests around
CompleteSubscriptionOrder should also cover plan-currency fallback. Add a case
using PaymentValidationFromMinorUnits with an empty expected-currency argument,
while retaining the same subscription and plan setup, and assert
ErrPaymentCurrencyMismatch so validatePaymentAgainstSubscriptionOrder exercises
its plan-derived currency branch.
- Around line 385-406: Update
TestRechargeEpayRejectsPaidAmountMismatchBeforeCompletingOrder to pass a payment
method different from the stored TopUp.PaymentMethod, then assert the persisted
payment method remains unchanged after ErrPaymentAmountMismatch. Keep the
existing pending-status and quota assertions.

In `@model/topup.go`:
- Around line 302-304: Update the RecordTopupLog message in the quotaToAdd
branch to use the same Chinese wording as Recharge, and format topUp.Money with
%.2f to match the other providers.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 75395e34-bd54-456b-87cc-cc9a95ab24cd

📥 Commits

Reviewing files that changed from the base of the PR and between c74ed57 and f842a95.

📒 Files selected for processing (21)
  • controller/custom_oauth.go
  • controller/custom_oauth_test.go
  • controller/subscription_payment_epay.go
  • controller/subscription_payment_waffo_pancake.go
  • controller/topup.go
  • controller/topup_creem.go
  • controller/topup_stripe.go
  • controller/topup_waffo.go
  • controller/topup_waffo_pancake.go
  • controller/topup_waffo_pancake_test.go
  • controller/user.go
  • controller/user_setting_test.go
  • model/log.go
  • model/log_cleanup_test.go
  • model/payment_method_guard_test.go
  • model/payment_validation.go
  • model/subscription.go
  • model/topup.go
  • service/task_polling.go
  • service/task_polling_test.go
  • tools/jsonwrapcheck/allowlist.txt
💤 Files with no reviewable changes (2)
  • tools/jsonwrapcheck/allowlist.txt
  • controller/subscription_payment_waffo_pancake.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/log_cleanup_test.go
  • service/task_polling_test.go
  • model/log.go
  • controller/custom_oauth_test.go
  • controller/custom_oauth.go
  • model/subscription.go
  • controller/user_setting_test.go
  • controller/topup_stripe.go
  • controller/topup_waffo.go
  • service/task_polling.go
  • controller/topup.go
  • controller/subscription_payment_epay.go
  • model/payment_validation.go
  • controller/user.go
  • model/payment_method_guard_test.go
  • controller/topup_waffo_pancake.go
  • controller/topup_waffo_pancake_test.go
  • controller/topup_creem.go
  • model/topup.go
🔇 Additional comments (34)
controller/custom_oauth.go (3)

15-15: LGTM!


170-184: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

SSRF (CWE-918): Server-Side Request Forgery (SSRF)

Reachability: External

Reachability path
● Entry
  controller/custom_oauth_test.go:15
  TestFetchCustomOAuthDiscoveryRejectsPrivateURLWhenSSRFProtectionEnabled
│
▼
● Sink
  controller/custom_oauth.go

Prevent DNS rebinding after URL validation.

Line 171 makes the destination decision before Line 197 dials the host. The default transport resolves the hostname during the later connection. An attacker-controlled domain can resolve to an allowed address during validation and to a private address during the outbound dial.

Enforce the resolved-address policy in a custom DialContext, or pin the validated address for the request.


170-184: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

SSRF (CWE-918): Server-Side Request Forgery (SSRF)

Reachability: External

Reachability path
● Entry
  controller/custom_oauth_test.go:15
  TestFetchCustomOAuthDiscoveryRejectsPrivateURLWhenSSRFProtectionEnabled
│
▼
● Sink
  controller/custom_oauth.go

Validate each redirect target.

Line 171 validates only the initial targetURL. Line 197 uses the default http.Client redirect behavior. If an attacker supplies an allowed public URL that redirects to a private address, the redirected request bypasses ValidateURLWithFetchSetting.

Validate req.URL in CheckRedirect, or disable automatic redirects and validate each resolved Location before sending the next request.

service/task_polling.go (1)

175-175: LGTM!

service/task_polling_test.go (1)

13-31: LGTM!

controller/user.go (1)

471-485: LGTM!

Also applies to: 526-526, 1445-1455, 1501-1502, 1519-1523

controller/user_setting_test.go (1)

132-180: LGTM!

model/log.go (2)

1023-1023: 🗄️ Data Integrity & Integration

Check logs.type null handling before changing the cleanup predicates.

The count and delete selection both use type <> ?, which excludes SQL NULL rows. Log.Type has no not null GORM tag in the model, and the available migration SQL does not show the logs table schema. If old NULL log rows exist, cleanup can miss both CountOldLog rows and DeleteOldLogBatch rows. Check production schema/data; add OR type IS NULL if appropriate, or backfill and enforce NOT NULL.


1040-1040: 🔒 Security & Privacy

Other (CWE-367): Time-of-check Time-of-use (TOCTOU) Race Condition

Reachability path
● Entry
  model/log_cleanup_test.go:44
  TestDeleteOldLogBatchPreservesManagementAuditLogs
│
▼
● Sink
  model/log.go

Recheck the retention predicate during deletion.

DeleteOldLogBatch selects IDs with the predicate at Line 1040, but Line 1060 deletes by ID only. If another transaction changes a selected row to LogTypeManage before the delete, the cleanup still removes that management log.

Reapply the timestamp and type predicates to the DELETE, or verify and enforce that Log.Type cannot change after insertion.

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 6 \
  'LogTypeManage|Type\s*[:=]|UpdateColumn[s]?\(|Updates\(|Save\(' \
  --glob '*.go' .
model/payment_validation.go (4)

33-45: LGTM!


77-87: LGTM!


89-106: LGTM!


65-70: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Other (CWE-840)

Reachability: External

Reachability path
● Entry
  controller/subscription_payment_epay.go:118
  SubscriptionEpayNotify: POST 请求:从 POST body 解析参数
│
▼
● Hop
  model/subscription.go:612
  CompleteSubscriptionOrder: still allow completion for already purchased orders
│
▼
● Sink
  model/payment_validation.go

Confirm the intended lower bound for discounted payments.

When AllowDiscount is true, the check only enforces an upper bound. Any paid amount from 1 minor unit up to expectedMinor passes, and the order is credited with the full quota. controller/topup_stripe.go sets AllowDiscount from setting.StripePromotionCodesEnabled for the top-up path, so a promotion code of any size grants the full quota. Confirm that no minimum paid fraction is required.

#!/bin/bash
# Description: Inspect how AllowDiscount is set and whether a discount floor exists anywhere.
set -euo pipefail

rg -n -C4 'AllowDiscount|StripePromotionCodesEnabled' --type=go
model/subscription.go (2)

545-549: LGTM!


612-612: LGTM!

Also applies to: 649-651

model/topup.go (5)

50-55: LGTM!


162-162: LGTM!

Also applies to: 189-192, 211-213


230-301: LGTM!


529-529: LGTM!

Also applies to: 557-560, 589-591


625-625: LGTM!

Also applies to: 656-659, 681-683, 694-694, 725-728, 748-750

controller/subscription_payment_epay.go (1)

163-164: LGTM!

Also applies to: 213-214

controller/topup.go (1)

377-386: LGTM!

controller/topup_creem.go (3)

62-77: LGTM!

Also applies to: 95-95, 427-427, 468-468


321-322: LGTM!


367-371: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Security Misconfiguration (CWE-807)

Reachability: External

Reachability path
● Entry
  controller/topup_stripe.go:64
  RequestPay
│
▼
● Sink
  controller/topup_creem.go

Do not derive the expected currency from the webhook payload.

When expectedCreemCurrencyForProduct returns an empty value, Line 370 sets ExpectedCurrency from event.Object.Product.Currency. Currency on Line 321 already comes from event.Object.Order.Currency. Both values then come from the same payload, so the currency check compares the payload against itself and always passes. The local expectation is lost exactly when the product is missing from setting.CreemProducts.

Leave ExpectedCurrency empty when the configured product is unknown, or reject the callback. An empty expected currency skips the check, which is no weaker than the self-comparison and does not create a false guarantee.

🛡️ Proposed fix
 	topUpValidation := paymentValidation
 	topUpValidation.ExpectedCurrency = expectedCreemCurrencyForProduct(event.Object.Product.Id)
-	if topUpValidation.ExpectedCurrency == "" {
-		topUpValidation.ExpectedCurrency = event.Object.Product.Currency
-	}
+	if topUpValidation.ExpectedCurrency == "" {
+		logger.LogWarn(c.Request.Context(), fmt.Sprintf("Creem 未找到产品货币配置,跳过货币校验 trade_no=%s product_id=%s", referenceId, event.Object.Product.Id))
+	}
#!/bin/bash
# Description: Check whether CreemProducts is expected to list every product id, and find other expected-currency sources.
set -euo pipefail

rg -n -C4 'CreemProducts' --type=go
rg -n -C3 'ExpectedCurrency' --type=go
controller/topup_stripe.go (3)

226-236: LGTM!


238-248: LGTM!

Also applies to: 298-305


312-314: 🎯 Functional Correctness

No change needed. Stripe top-ups use CustomCurrencyExchangeRate for local display while Stripe prices stay USD; subscription checkout does not enable Stripe promotion codes, so these lines do not break the described flows.

controller/topup_waffo.go (2)

63-71: LGTM!

Also applies to: 9-9


404-405: LGTM!

controller/topup_waffo_pancake.go (1)

528-529: LGTM!

controller/topup_waffo_pancake_test.go (1)

4-67: LGTM!

model/payment_method_guard_test.go (2)

336-357: LGTM!


359-383: LGTM!

Comment thread controller/custom_oauth_test.go Outdated
Comment thread controller/topup_waffo_pancake_test.go
Comment thread controller/topup_waffo_pancake.go Outdated
Comment thread controller/topup.go Outdated
Comment thread controller/topup.go
Comment thread controller/user_setting_test.go
Comment thread model/log_cleanup_test.go
Comment thread model/payment_method_guard_test.go
Comment thread model/payment_method_guard_test.go
Comment thread model/topup.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/user_setting_test.go`:
- Around line 251-275: Complete the persistence assertions in
controller/user_setting_test.go:251-275 by asserting
setting.QuotaWarningThreshold equals 0.8 after the successful update. In
controller/user_setting_test.go:318-323, replace the partial rejected-update
checks with a comparison of the full setting against initialSettings, ensuring
every field remains unchanged.

In `@model/channel.go`:
- Around line 585-586: Preserve explicit key selection in the field-update logic
around `keySelected` and its corresponding handling near the multi-key state
updates: determine selection solely from the presence of `"key"` in `fieldSet`,
without requiring `channel.Key` to be non-empty. Ensure clearing the final key
recalculates `MultiKeySize` and `MultiKeyStatusList` from the empty key list,
and add a regression test covering `UpdateFields("key")` with an empty key and
asserting size zero.

In `@model/log.go`:
- Line 1062: Update DeleteOldLog so a short delete batch caused by the
oldLogCleanupScope re-check does not immediately terminate cleanup: re-count
eligible logs with CountOldLog and continue processing whenever the count is
nonzero, returning only when none remain. Add a regression test covering a
promoted first candidate followed by a later eligible consume log.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3ee44f34-4e11-4ee5-a716-0a5d2fc88dd8

📥 Commits

Reviewing files that changed from the base of the PR and between f842a95 and 48c1a65.

📒 Files selected for processing (16)
  • controller/channel.go
  • controller/channel_update_test.go
  • controller/custom_oauth.go
  • controller/custom_oauth_test.go
  • controller/topup.go
  • controller/topup_creem.go
  • controller/topup_creem_test.go
  • controller/topup_waffo_pancake.go
  • controller/topup_waffo_pancake_test.go
  • controller/user_setting_test.go
  • model/channel.go
  • model/channel_update_fields_test.go
  • model/log.go
  • model/log_cleanup_test.go
  • model/payment_method_guard_test.go
  • model/topup.go
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend checks
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • controller/topup_waffo_pancake.go
  • model/channel_update_fields_test.go
  • controller/topup_creem_test.go
  • controller/topup_waffo_pancake_test.go
  • controller/topup.go
  • model/log.go
  • model/channel.go
  • controller/user_setting_test.go
  • model/log_cleanup_test.go
  • model/payment_method_guard_test.go
  • controller/topup_creem.go
  • controller/channel_update_test.go
  • controller/custom_oauth.go
  • model/topup.go
  • controller/custom_oauth_test.go
  • controller/channel.go
🔇 Additional comments (11)
model/topup.go (1)

303-303: LGTM!

controller/topup_waffo_pancake.go (1)

502-502: LGTM!

controller/topup.go (1)

355-355: LGTM!

Also applies to: 369-369

controller/topup_creem.go (1)

79-93: LGTM!

Also applies to: 383-389

model/payment_method_guard_test.go (1)

401-407: LGTM!

Also applies to: 421-431

controller/topup_waffo_pancake_test.go (1)

195-195: LGTM!

controller/topup_creem_test.go (1)

10-25: LGTM!

Also applies to: 27-41

model/log.go (1)

1023-1045: LGTM!

model/log_cleanup_test.go (1)

54-108: LGTM!

controller/custom_oauth.go (1)

15-15: LGTM!

Also applies to: 170-174, 185-185

controller/custom_oauth_test.go (1)

37-39: LGTM!

Also applies to: 53-53

Comment thread controller/user_setting_test.go
Comment thread model/channel.go Outdated
Comment thread model/log.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
model/channel_update_fields_test.go (1)

14-46: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Register t.Cleanup before fallible setup.

The helper changes global state before Line 38 registers cleanup. If gorm.Open, AutoMigrate, or db.DB() fails, later tests inherit the modified DB, LOG_DB, and common flags. The SQLite handle can also remain open.

Register cleanup immediately after saving the original state. Hoist sqlDB and close it only when it is non-nil.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel_update_fields_test.go` around lines 14 - 46, Move the t.Cleanup
registration in setupChannelUpdateFieldsTestDB immediately after capturing the
original DB and common-state values, before changing globals or performing
SQLite setup. Hoist sqlDB outside the cleanup closure and close it only when
non-nil, while restoring all saved state regardless of whether gorm.Open,
AutoMigrate, or db.DB fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model/channel.go`:
- Around line 627-640: The channel cleanup currently mutates the caller’s
ChannelInfo before transaction success, leaving the in-memory receiver
inconsistent on rollback. Deep-copy the channel for all cleanup and tentative
reload/update work in the transaction, use that copy as the transaction
receiver, and assign the completed copy to *channel only after DB.Transaction
succeeds; extend the rollback test to assert the original in-memory channel
remains unchanged.

---

Outside diff comments:
In `@model/channel_update_fields_test.go`:
- Around line 14-46: Move the t.Cleanup registration in
setupChannelUpdateFieldsTestDB immediately after capturing the original DB and
common-state values, before changing globals or performing SQLite setup. Hoist
sqlDB outside the cleanup closure and close it only when non-nil, while
restoring all saved state regardless of whether gorm.Open, AutoMigrate, or db.DB
fails.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fa979d67-049d-43ab-aa54-27d9c8df9f29

📥 Commits

Reviewing files that changed from the base of the PR and between 48c1a65 and 39017dd.

📒 Files selected for processing (5)
  • controller/user_setting_test.go
  • model/channel.go
  • model/channel_update_fields_test.go
  • model/log.go
  • model/log_cleanup_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/log_cleanup_test.go
  • model/channel_update_fields_test.go
  • model/log.go
  • controller/user_setting_test.go
  • model/channel.go
🔇 Additional comments (4)
controller/user_setting_test.go (1)

276-276: LGTM!

Also applies to: 321-321

model/log.go (1)

1029-1030: LGTM!

Also applies to: 1042-1045, 1062-1062, 1093-1099

model/log_cleanup_test.go (1)

110-140: LGTM!

model/channel.go (1)

627-640: 🗄️ Data Integrity & Integration

No change needed for MultiKeyPollingIndex.

NextMultiKey normalizes the saved polling index before lookup with start < 0 || start >= len(keys), and MultiKeyPollingIndex is only updated in the polling code path when a key is selected.

Comment thread model/channel.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
model/channel.go (1)

622-650: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve an empty JSON key array.

When Key is [], common.Unmarshal succeeds with zero keys. The len(keys) == 0 fallback then splits [] as one newline key. GetKeys treats the same value as zero keys. This persists MultiKeySize as 1 and can retain metadata for index 0 when no key exists.

Track JSON parsing success separately. Use newline splitting only when JSON parsing fails. Add a regression test for UpdateFields("key") with Key == "[]".

Proposed fix
 		keys := []string{}
+		parsedJSONKeys := false
 		if keyStr != "" {
 			trimmed := strings.TrimSpace(keyStr)
 			if strings.HasPrefix(trimmed, "[") {
 				var arr []json.RawMessage
 				if err := common.Unmarshal([]byte(trimmed), &arr); err == nil {
+					parsedJSONKeys = true
 					keys = make([]string, len(arr))
 					for i, v := range arr {
 						keys[i] = string(v)
 					}
 				}
 			}
-			if len(keys) == 0 { // fallback to newline split
+			if !parsedJSONKeys {
 				keys = strings.Split(strings.Trim(keyStr, "\n"), "\n")
 			}
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel.go` around lines 622 - 650, Update the key parsing block in the
channel update flow to track whether JSON unmarshalling succeeded separately
from the parsed key count, so a valid empty array preserves zero keys and does
not fall back to newline splitting. Keep newline splitting only for non-JSON or
failed JSON input, and add a regression test covering UpdateFields("key") with
Key set to "[]" and verifying MultiKeySize remains zero.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model/channel.go`:
- Around line 694-705: In the channel update flow around cloneChannelForUpdate
and the final *channel assignment, clear workingChannel.Keys when keySelected is
true after the update succeeds and before copying it to the caller, so GetKeys
reloads the updated Key instead of returning the stale cache. Add coverage that
prepopulates Keys, updates Key, and verifies GetKeys returns the new key list.

---

Outside diff comments:
In `@model/channel.go`:
- Around line 622-650: Update the key parsing block in the channel update flow
to track whether JSON unmarshalling succeeded separately from the parsed key
count, so a valid empty array preserves zero keys and does not fall back to
newline splitting. Keep newline splitting only for non-JSON or failed JSON
input, and add a regression test covering UpdateFields("key") with Key set to
"[]" and verifying MultiKeySize remains zero.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7b56a354-5dda-4c44-a865-6be8876cc738

📥 Commits

Reviewing files that changed from the base of the PR and between 39017dd and 42d6694.

📒 Files selected for processing (2)
  • model/channel.go
  • model/channel_update_fields_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/channel_update_fields_test.go
  • model/channel.go
🔇 Additional comments (2)
model/channel_update_fields_test.go (1)

95-163: LGTM!

model/channel.go (1)

8-8: 📐 Maintainability & Code Quality

No compatibility issue with maps.

The module declares Go 1.25.1, and the referenced CI/docker toolchains also use Go 1.25/1.26+, so maps.Clone is supported at all listed sites.

Comment thread model/channel.go
@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
model/channel.go (1)

622-676: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Build multi-key metadata in the update transaction.

At Line 629, GetChannelById runs before DB.Transaction, and its error is ignored. If that read fails, this code treats the key list as empty and persists zeroed metadata.

A concurrent key update can also commit after this read and before Line 691. This update can then overwrite the new key metadata with metadata calculated from an old key list. Load the persisted key with tx, return lookup errors, and construct updates["channel_info"] inside the same transaction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/channel.go` around lines 622 - 676, Move multi-key key loading and
metadata construction from the pre-transaction path into the DB transaction,
using the transaction handle for the persisted lookup and propagating lookup
errors instead of treating failures as an empty key list. Build and assign
updates["channel_info"] inside that transaction after calculating MultiKeySize
and cleaning status maps, so key metadata is derived from the same transactional
state and cannot overwrite concurrent updates with stale data.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model/channel_update_fields_test.go`:
- Around line 99-121: Update the failed UpdateFields call in the channel
rollback test to include "priority" alongside the existing fields. After
reloading the stored Channel, assert that its priority remains equal to the
original value, covering rollback of the pending channel.Priority change.

---

Outside diff comments:
In `@model/channel.go`:
- Around line 622-676: Move multi-key key loading and metadata construction from
the pre-transaction path into the DB transaction, using the transaction handle
for the persisted lookup and propagating lookup errors instead of treating
failures as an empty key list. Build and assign updates["channel_info"] inside
that transaction after calculating MultiKeySize and cleaning status maps, so key
metadata is derived from the same transactional state and cannot overwrite
concurrent updates with stale data.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a774acf8-201d-4ad3-9db7-9fb7b8feba45

📥 Commits

Reviewing files that changed from the base of the PR and between 39017dd and 53091e9.

📒 Files selected for processing (2)
  • model/channel.go
  • model/channel_update_fields_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/channel_update_fields_test.go
  • model/channel.go
🔇 Additional comments (4)
model/channel.go (3)

8-8: LGTM!


578-606: LGTM!


690-709: LGTM!

model/channel_update_fields_test.go (1)

124-147: LGTM!

Also applies to: 154-157

Comment thread model/channel_update_fields_test.go
@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@common/rate-limit.go`:
- Around line 19-30: Protect the limiter lifecycle with a mutex-protected
stopped state: update Init to check that state before creating channels or
launching clearExpiredItems, and update Stop to mark the limiter stopped while
holding the mutex before releasing it. Preserve one-time initialization while
ensuring concurrent or later Init calls cannot start cleanup after Stop returns,
and add a concurrent Init/Stop test covering this race.

In `@relay/channel/zhipu/relay-zhipu.go`:
- Line 6: Update the panic-recovery logic in the relay stream handler around the
deferred shutdown sender and recovery block so a recovered panic is propagated
to the consumer as a relay error, rather than signaling normal completion
through stopChan. Suppress data: [DONE] for the recovered-failure path, and
return the relay error when response headers are still writable.

In `@service/channel_affinity_template_test.go`:
- Around line 343-351: Update the cache sequence in the test around
loadChannelAffinityRegex so ^first$ is accessed after the initial inserts, then
insert ^third$ and assert ^second$ is absent. Preserve the existing no-error
checks while making the eviction assertion distinguish LRU behavior from FIFO.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aaf585ca-e8bf-4e1d-b34c-505062211e3b

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea3ded and 612a5e1.

📒 Files selected for processing (24)
  • common/email.go
  • common/email_test.go
  • common/go-channel.go
  • common/go_channel_test.go
  • common/rate-limit.go
  • common/rate_limit_test.go
  • common/system_monitor.go
  • common/system_monitor_test.go
  • main.go
  • middleware/audit.go
  • middleware/email-verification-rate-limit.go
  • middleware/model-rate-limit.go
  • middleware/rate-limit.go
  • middleware/turnstile-check.go
  • middleware/turnstile_check_test.go
  • pkg/billingexpr/billingexpr_test.go
  • pkg/billingexpr/run.go
  • relay/channel/gemini/relay-gemini.go
  • relay/channel/gemini/relay_gemini_usage_test.go
  • relay/channel/zhipu/relay-zhipu.go
  • service/channel_affinity.go
  • service/channel_affinity_template_test.go
  • service/tiered_settle.go
  • service/tiered_settle_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • pkg/billingexpr/run.go
  • relay/channel/gemini/relay_gemini_usage_test.go
  • common/email_test.go
  • main.go
  • common/go_channel_test.go
  • relay/channel/gemini/relay-gemini.go
  • common/system_monitor_test.go
  • service/channel_affinity.go
  • service/tiered_settle_test.go
  • middleware/model-rate-limit.go
  • middleware/audit.go
  • common/rate_limit_test.go
  • relay/channel/zhipu/relay-zhipu.go
  • service/channel_affinity_template_test.go
  • middleware/rate-limit.go
  • middleware/email-verification-rate-limit.go
  • middleware/turnstile-check.go
  • service/tiered_settle.go
  • common/email.go
  • common/system_monitor.go
  • common/go-channel.go
  • middleware/turnstile_check_test.go
  • pkg/billingexpr/billingexpr_test.go
  • common/rate-limit.go
pkg/billingexpr/**/*.{go,md}

📄 CodeRabbit inference engine (AGENTS.md)

When working on tiered/dynamic billing expression pricing, first read pkg/billingexpr/expr.md and ensure all code changes in the billing expression system follow the documented design, architecture, token normalization, quota conversion, and versioning patterns.

Files:

  • pkg/billingexpr/run.go
  • pkg/billingexpr/billingexpr_test.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/gemini/relay_gemini_usage_test.go
  • relay/channel/gemini/relay-gemini.go
  • relay/channel/zhipu/relay-zhipu.go
🔇 Additional comments (22)
common/rate-limit.go (1)

4-4: LGTM!

Also applies to: 33-54

common/rate_limit_test.go (1)

13-37: LGTM!

middleware/email-verification-rate-limit.go (1)

58-58: LGTM!

Also applies to: 78-78

middleware/model-rate-limit.go (1)

133-133: LGTM!

common/email.go (1)

8-16: LGTM!

Also applies to: 64-93

common/email_test.go (1)

223-268: LGTM!

middleware/turnstile-check.go (1)

4-9: LGTM!

Also applies to: 22-61, 81-81, 91-91

middleware/turnstile_check_test.go (1)

4-20: LGTM!

Also applies to: 48-67

common/system_monitor.go (1)

4-5: LGTM!

Also applies to: 33-37, 39-58, 60-82, 84-105

common/system_monitor_test.go (1)

1-18: LGTM!

main.go (1)

246-251: LGTM!

middleware/rate-limit.go (1)

20-23: LGTM!

common/go-channel.go (1)

37-43: LGTM!

common/go_channel_test.go (1)

1-29: LGTM!

middleware/audit.go (1)

150-150: LGTM!

pkg/billingexpr/billingexpr_test.go (1)

9-19: LGTM!

Also applies to: 33-33, 47-47, 327-327, 358-358, 432-435, 450-450, 469-469, 518-518, 550-550, 582-582, 648-655, 688-704

pkg/billingexpr/run.go (1)

115-117: LGTM!

relay/channel/gemini/relay-gemini.go (1)

1782-1788: LGTM!

relay/channel/gemini/relay_gemini_usage_test.go (1)

70-90: LGTM!

service/channel_affinity.go (1)

40-44: LGTM!

Also applies to: 258-290

service/tiered_settle.go (1)

7-7: LGTM!

Also applies to: 192-196

service/tiered_settle_test.go (1)

117-133: LGTM!

Comment thread common/rate-limit.go
Comment thread relay/channel/zhipu/relay-zhipu.go
Comment thread service/channel_affinity_template_test.go Outdated
@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@middleware/auth_session_test.go`:
- Around line 180-204: Update TestUserAuthRejectsNonEnabledStatus to assert the
specific HTTP status returned by UserAuth for a rejected request, replacing the
broad NotEqual check. Preserve the existing stale-session setup and request flow
so the test verifies rejection due to the non-enabled user status.

In `@model/log_test.go`:
- Around line 108-122: Update TestRecordConsumeLogSanitizesPersistedContent to
save the original common.LogConsumeEnabled value, enable it for the test before
calling RecordConsumeLog, and restore the original value with t.Cleanup. Keep
the existing database cleanup and assertions unchanged.

In `@model/token.go`:
- Around line 292-296: Update GetTokenByKey so its database predicate always
includes the Key field, including when key is empty; replace the struct-based
DB.Where condition with an explicit-condition form while preserving the existing
First and success assignment behavior.

In `@service/task_polling.go`:
- Around line 205-206: Update the unsuccessful-response branch after
common.Unmarshal in the task polling flow to return a newly constructed non-nil
error after logging, instead of returning the nil err variable. Preserve the
existing success handling and include sufficient context about the Suno response
failure for the polling caller.

In `@setting/ratio_setting/pricing_validation.go`:
- Around line 96-100: Update loadPricingMapWithOptions so it loads a rewritten
JSON map whose keys are trimmed and normalized, rather than the original
jsonStr; reuse the same normalization rules used by validatePricingMapJSONString
and preserve collision validation. Add a test verifying that one normalized
alias resolves to its configured ratio after an update.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 624b0d1e-b982-446b-a2f1-489dc24c8073

📥 Commits

Reviewing files that changed from the base of the PR and between 42c52e5 and 57b221b.

📒 Files selected for processing (32)
  • common/str.go
  • common/str_test.go
  • controller/task_video.go
  • controller/user_setting_test.go
  • controller/video_proxy.go
  • controller/video_proxy_test.go
  • middleware/auth.go
  • middleware/auth_session_test.go
  • model/billing_settlement.go
  • model/log.go
  • model/log_test.go
  • model/midjourney.go
  • model/option.go
  • model/option_test.go
  • model/task.go
  • model/token.go
  • relay/channel/minimax/tts.go
  • relay/channel/openai/audio.go
  • relay/helper/price.go
  • relay/helper/price_test.go
  • relay/relay_task.go
  • service/error.go
  • service/error_test.go
  • service/http.go
  • service/http_client_test.go
  • service/midjourney_task.go
  • service/task_billing.go
  • service/task_polling.go
  • setting/ratio_setting/model_ratio.go
  • setting/ratio_setting/pricing_validation.go
  • setting/ratio_setting/pricing_validation_test.go
  • setting/task_billing_setting/rate_card.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • setting/ratio_setting/pricing_validation_test.go
  • setting/ratio_setting/model_ratio.go
  • setting/task_billing_setting/rate_card.go
  • model/billing_settlement.go
  • model/option_test.go
  • relay/channel/openai/audio.go
  • controller/task_video.go
  • middleware/auth.go
  • relay/helper/price_test.go
  • model/log_test.go
  • model/option.go
  • common/str_test.go
  • service/http_client_test.go
  • model/token.go
  • relay/relay_task.go
  • controller/video_proxy_test.go
  • controller/video_proxy.go
  • relay/channel/minimax/tts.go
  • service/error.go
  • service/midjourney_task.go
  • model/task.go
  • service/error_test.go
  • common/str.go
  • service/task_billing.go
  • service/http.go
  • relay/helper/price.go
  • setting/ratio_setting/pricing_validation.go
  • controller/user_setting_test.go
  • model/log.go
  • service/task_polling.go
  • middleware/auth_session_test.go
  • model/midjourney.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/openai/audio.go
  • relay/channel/minimax/tts.go
🔇 Additional comments (43)
service/error.go (1)

138-165: LGTM!

Also applies to: 167-203, 205-208

service/error_test.go (1)

200-239: LGTM!

service/midjourney_task.go (1)

47-47: LGTM!

service/task_billing.go (1)

152-152: LGTM!

Also applies to: 186-186

service/task_polling.go (1)

202-204: LGTM!

Also applies to: 228-228, 376-376, 421-421, 465-465

setting/task_billing_setting/rate_card.go (1)

45-47: LGTM!

Also applies to: 143-145

common/str.go (1)

22-23: LGTM!

Also applies to: 33-63

common/str_test.go (1)

1-31: LGTM!

relay/channel/openai/audio.go (1)

49-49: LGTM!

relay/helper/price.go (1)

22-22: LGTM!

Also applies to: 36-40, 182-194, 204-205

relay/relay_task.go (1)

327-327: LGTM!

service/http.go (4)

16-27: LGTM!


39-61: LGTM!


63-84: LGTM!


86-122: LGTM!

Also applies to: 138-138

service/http_client_test.go (1)

5-10: LGTM!

Also applies to: 33-86

controller/task_video.go (1)

8-15: LGTM!

controller/user_setting_test.go (1)

182-224: LGTM!

controller/video_proxy.go (3)

23-30: LGTM!


173-179: 🎯 Functional Correctness | ⚡ Quick win

Confirm the loss of upstream Content-Length for streamed video responses.

CopyUpstreamResponseHeaders blocks content-length. This handler streams the upstream body with io.Copy and never sets Content-Length itself, so responses now use chunked transfer encoding. Video players lose the total-size hint that the previous manual copy forwarded. If clients depend on that hint, set Content-Length explicitly from resp.ContentLength when it is non-negative.

Proposed change
 	service.CopyUpstreamResponseHeaders(c, resp.Header)
 
 	c.Writer.Header().Set("Cache-Control", "public, max-age=86400")
+	if resp.ContentLength >= 0 {
+		c.Writer.Header().Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10))
+	}
 	c.Writer.WriteHeader(resp.StatusCode)

190-241: LGTM!

middleware/auth.go (3)

337-344: LGTM!


462-465: LGTM!


195-202: 🔒 Security & Privacy

No change needed. User status has only UserStatusEnabled and UserStatusDisabled, so this check does not hide pending or unverified states.

model/log_test.go (1)

8-11: LGTM!

Also applies to: 123-173

model/task.go (4)

491-491: LGTM!


627-627: LGTM!

Also applies to: 644-681, 690-690, 710-710


728-728: 🗄️ Data Integrity & Integration

No change needed for sanitizeFailReasonUpdateParam key matching.

The helper sanitizes the same fail_reason key used by the calling bulk update paths.


75-80: 🗄️ Data Integrity & Integration

No change needed. SanitizePersistedLogContent is idempotent for truncated text, so reloading and saving the same FailReason does not append another ... [truncated] suffix.

			> Likely an incorrect or invalid review comment.
relay/channel/minimax/tts.go (1)

193-193: LGTM!

relay/helper/price_test.go (2)

9-14: LGTM!

Also applies to: 66-93


95-116: LGTM!

setting/ratio_setting/model_ratio.go (1)

398-401: LGTM!

Also applies to: 449-452

setting/ratio_setting/pricing_validation.go (1)

6-42: LGTM!

Also applies to: 44-87

setting/ratio_setting/pricing_validation_test.go (1)

10-29: LGTM!

controller/video_proxy_test.go (1)

14-57: LGTM!

middleware/auth_session_test.go (2)

32-32: LGTM!

Also applies to: 57-73


42-54: 🎯 Functional Correctness

No change needed for user-cache isolation in these tests.

The middleware test setup disables Redis, so GetUserCache falls back to fresh database reads for both disabled and deleted-token-owner cases.

model/billing_settlement.go (1)

512-514: LGTM!

model/log.go (1)

76-76: LGTM!

Also applies to: 398-398, 418-418, 449-449, 470-470, 496-496, 526-526, 590-590, 683-683

model/midjourney.go (1)

39-44: LGTM!

Also applies to: 214-214, 448-468

model/option.go (1)

357-362: LGTM!

model/option_test.go (1)

4-5: LGTM!

Also applies to: 211-230

Comment thread middleware/auth_session_test.go
Comment thread model/log_test.go
Comment thread service/task_polling.go
Comment thread setting/ratio_setting/pricing_validation.go Outdated
@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (1)
middleware/auth_session_test.go (1)

196-204: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the rejection reason, not only status 200.

freshAuthHelper returns HTTP 200 with "success": false for every rejection branch (banned, insufficient privilege, invalid user info). The handler returns 204. So require.Equal(t, http.StatusOK, ...) proves that the middleware aborted, but it does not prove that the non-enabled status caused the abort. Assert the response body as well.

💚 Proposed assertion
 	require.Equal(t, http.StatusOK, recorder.Code)
+	require.Contains(t, recorder.Body.String(), `"success":false`)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middleware/auth_session_test.go` around lines 196 - 204, Update the test
around the cookie loop and router.ServeHTTP call to assert the response body’s
failure payload in addition to the existing status assertion. Verify the body
indicates the expected rejection reason, such as `"success": false`, so the test
distinguishes middleware rejection from an unrelated successful response.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@common/str.go`:
- Around line 22-23: The truncation logic using PersistedLogContentLimit and
persistedLogContentTruncatedSuffix must reserve the suffix length when retaining
content, so the complete sanitized result stays within the limit. Update
common/str.go lines 22-23 accordingly, and adjust the expectation in
common/str_test.go lines 29-30 to assert the complete truncated result contains
at most PersistedLogContentLimit runes.

In `@model/token.go`:
- Around line 293-297: Update the token lookup around dbToken to use the
existing commonKeyCol helper in the DB.Where condition, replacing the manually
constructed clause.Eq reference to the reserved key column while preserving the
current query and assignment behavior.

In `@relay/helper/price_test.go`:
- Around line 95-116: Stabilize TestModelPriceHelperPerCallUsesDefaultTaskPrice
by controlling the group ratio and other pricing inputs used by
ModelPriceHelperPerCall. Prefer setting the default group ratio explicitly and
restoring it in t.Cleanup, and assert GroupRatioInfo.GroupRatio and ModelPrice
alongside Quota; also pin the free-model pre-consume setting if it is mutable so
the expected quota remains deterministic.

In `@service/http.go`:
- Around line 43-61: Remove the Gin-context mutation from
ShouldCopyUpstreamHeader, keeping it as a side-effect-free predicate. In
CopyUpstreamResponseHeaders, detect the request ID header and set
common.UpstreamRequestIdKey on the provided context before or alongside the
existing predicate-based filtering, preserving the current request-ID capture
behavior.

In `@service/task_polling.go`:
- Line 233: Update taskNeedsUpdate to sanitize newTask.FailReason with
common.SanitizePersistedLogContent before comparing it to oldTask.FailReason,
matching the normalization used by the task.FailReason assignment. Preserve the
existing fallback behavior for empty failure reasons and avoid repeated updates
when the persisted values are equivalent.
- Around line 207-212: Update the error construction in UpdateSunoTasks to apply
common.MaskSensitiveInfo to responseItems.Message before passing it to
common.SanitizePersistedLogContent, matching the transformation used by
TaskErrorFromUpstreamResponse while preserving the existing error format.

---

Duplicate comments:
In `@middleware/auth_session_test.go`:
- Around line 196-204: Update the test around the cookie loop and
router.ServeHTTP call to assert the response body’s failure payload in addition
to the existing status assertion. Verify the body indicates the expected
rejection reason, such as `"success": false`, so the test distinguishes
middleware rejection from an unrelated successful response.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 18de7509-14c7-4732-8f3e-4755470da483

📥 Commits

Reviewing files that changed from the base of the PR and between 42c52e5 and 3b1be2f.

📒 Files selected for processing (34)
  • common/str.go
  • common/str_test.go
  • controller/task_video.go
  • controller/user_setting_test.go
  • controller/video_proxy.go
  • controller/video_proxy_test.go
  • middleware/auth.go
  • middleware/auth_session_test.go
  • model/billing_settlement.go
  • model/log.go
  • model/log_test.go
  • model/midjourney.go
  • model/option.go
  • model/option_test.go
  • model/task.go
  • model/token.go
  • model/token_readonly_test.go
  • relay/channel/minimax/tts.go
  • relay/channel/openai/audio.go
  • relay/helper/price.go
  • relay/helper/price_test.go
  • relay/relay_task.go
  • service/error.go
  • service/error_test.go
  • service/http.go
  • service/http_client_test.go
  • service/midjourney_task.go
  • service/task_billing.go
  • service/task_polling.go
  • service/task_polling_test.go
  • setting/ratio_setting/model_ratio.go
  • setting/ratio_setting/pricing_validation.go
  • setting/ratio_setting/pricing_validation_test.go
  • setting/task_billing_setting/rate_card.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • model/token_readonly_test.go
  • controller/task_video.go
  • relay/channel/openai/audio.go
  • setting/task_billing_setting/rate_card.go
  • model/billing_settlement.go
  • setting/ratio_setting/pricing_validation_test.go
  • common/str_test.go
  • setting/ratio_setting/model_ratio.go
  • service/task_billing.go
  • model/option.go
  • model/log_test.go
  • model/option_test.go
  • relay/helper/price.go
  • relay/channel/minimax/tts.go
  • service/error.go
  • service/midjourney_task.go
  • middleware/auth_session_test.go
  • controller/user_setting_test.go
  • controller/video_proxy.go
  • middleware/auth.go
  • service/http.go
  • service/task_polling.go
  • common/str.go
  • model/task.go
  • setting/ratio_setting/pricing_validation.go
  • model/token.go
  • controller/video_proxy_test.go
  • relay/helper/price_test.go
  • service/task_polling_test.go
  • model/log.go
  • service/error_test.go
  • relay/relay_task.go
  • service/http_client_test.go
  • model/midjourney.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/openai/audio.go
  • relay/channel/minimax/tts.go
🔇 Additional comments (30)
relay/helper/price.go (1)

22-22: LGTM!

Also applies to: 36-39, 182-205

relay/relay_task.go (1)

327-327: LGTM!

service/error.go (1)

138-208: LGTM!

service/midjourney_task.go (1)

47-47: LGTM!

service/task_billing.go (1)

152-152: LGTM!

Also applies to: 186-186

setting/task_billing_setting/rate_card.go (1)

45-47: LGTM!

Also applies to: 143-145

service/error_test.go (1)

200-239: LGTM!

controller/task_video.go (1)

8-15: LGTM!

controller/video_proxy.go (1)

24-32: LGTM!

Also applies to: 174-174, 183-192, 201-207, 217-226, 228-252

middleware/auth.go (1)

195-195: LGTM!

Also applies to: 337-344, 462-465

middleware/auth_session_test.go (1)

32-32: LGTM!

Also applies to: 42-42, 54-74, 233-267

model/log_test.go (1)

8-11: LGTM!

Also applies to: 108-137, 139-153, 155-179

model/task.go (2)

491-491: LGTM!

Also applies to: 627-627, 644-681, 690-690, 710-710, 728-728, 743-743


75-81: 📐 Maintainability & Code Quality

Only model/task.go declares (*Task).BeforeSave; the matching BeforeSave definitions use different receiver types.

model/token_readonly_test.go (1)

8-8: LGTM!

Also applies to: 53-62

relay/helper/price_test.go (1)

9-14: LGTM!

Also applies to: 65-93

service/http.go (1)

16-28: LGTM!

Also applies to: 63-122, 138-138

service/http_client_test.go (1)

5-10: LGTM!

Also applies to: 33-50, 52-86

controller/user_setting_test.go (1)

182-223: LGTM!

controller/video_proxy_test.go (1)

14-25: LGTM!

Also applies to: 27-38, 40-57, 59-77

model/billing_settlement.go (1)

512-514: LGTM!

model/log.go (1)

76-76: LGTM!

Also applies to: 398-398, 418-418, 449-449, 470-470, 496-496, 526-526, 590-590, 683-683

model/midjourney.go (1)

9-9: LGTM!

Also applies to: 39-44, 214-214, 448-468

model/option.go (1)

357-362: LGTM!

model/option_test.go (1)

4-5: LGTM!

Also applies to: 211-230

relay/channel/minimax/tts.go (1)

193-193: LGTM!

relay/channel/openai/audio.go (1)

49-49: LGTM!

setting/ratio_setting/model_ratio.go (1)

398-401: LGTM!

Also applies to: 449-452

setting/ratio_setting/pricing_validation.go (1)

6-119: LGTM!

setting/ratio_setting/pricing_validation_test.go (1)

1-55: LGTM!

Comment thread common/str.go
Comment thread model/token.go
Comment on lines +293 to +297
var dbToken Token
err = DB.Where(clause.Eq{Column: clause.Column{Name: "key"}, Value: key}).First(&dbToken).Error
if err == nil {
token = &dbToken
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Inspect commonKeyCol definition and existing key-column predicates in the model package.
rg -nP --type=go -C3 '\bcommonKeyCol\b' 
echo "---- other key predicates ----"
rg -nP --type=go -C2 'Where\(.*\bkey\b' model

Repository: MAX-API-Next/MAX-API

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -u

echo "---- repo files matching token.go/common-related ----"
git ls-files | rg -n '(^|/)(token\.go|common|.*_test\.go)$' | head -200

echo "---- search commonKeyCol/text key predicates broad ----"
rg -n --hidden --glob '!vendor/**' --glob '!node_modules/**' --glob '!dist/**' '\bcommonKeyCol\b|Where\(.*\bkey\b|clause\.Column\{\s*Name:\s*"key"' . || true

echo "---- model/token.go relevant section ----"
if [ -f model/token.go ]; then
  wc -l model/token.go
  sed -n '260,320p' model/token.go | cat -n
fi

Repository: MAX-API-Next/MAX-API

Length of output: 12259


Use commonKeyCol for the token key lookup.

commonKeyCol is the repository’s DB-specific helper for the reserved key column, and it is already used around model/token.go. Use DB.Where(commonKeyCol+" = ?", key) instead of clause.Eq{Column: clause.Column{Name: "key"}, Value: key} here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/token.go` around lines 293 - 297, Update the token lookup around
dbToken to use the existing commonKeyCol helper in the DB.Where condition,
replacing the manually constructed clause.Eq reference to the reserved key
column while preserving the current query and assignment behavior.

Source: Coding guidelines

Comment thread relay/helper/price_test.go
Comment thread service/http.go Outdated
Comment thread service/task_polling.go
Comment thread service/task_polling.go
@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
service/http.go (1)

68-72: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove headers nominated by Connection.

The code rejects Connection itself, but it does not reject headers named by its values. An upstream Connection: X-Request-ID with X-Request-ID: value captures a hop-by-hop value before filtering. Other nominated headers can also be forwarded.

Build a case-insensitive set of header names from all Connection values before this loop. Skip those names before request-ID capture and response-header copying. Add a test for a nominated safe-looking header.

Proposed fix
 func CopyUpstreamResponseHeaders(c *gin.Context, header http.Header) {
   if c == nil || c.Writer == nil {
     return
   }
+  connectionScoped := make(map[string]struct{})
+  for key, values := range header {
+    if !strings.EqualFold(key, "Connection") {
+      continue
+    }
+    for _, value := range values {
+      for _, name := range strings.Split(value, ",") {
+        name = strings.TrimSpace(name)
+        if isSafeResponseHeaderName(name) {
+          connectionScoped[strings.ToLower(name)] = struct{}{}
+        }
+      }
+    }
+  }
   for key, values := range header {
+    if _, ok := connectionScoped[strings.ToLower(key)]; ok {
+      continue
+    }
     if len(values) > 0 && strings.EqualFold(key, common.RequestIdKey) && isSafeResponseHeaderName(key) && isSafeResponseHeaderValue(values[0]) {
       c.Set(common.UpstreamRequestIdKey, values[0])
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@service/http.go` around lines 68 - 72, Build a case-insensitive set of
hop-by-hop header names nominated by all Connection header values before the
header iteration. In the loop over header, skip any nominated name before the
RequestId capture condition and before shouldCopyUpstreamHeader, while
continuing to reject Connection itself. Add coverage for a nominated
safe-looking header to verify it is neither captured nor forwarded.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@service/http.go`:
- Around line 68-72: Build a case-insensitive set of hop-by-hop header names
nominated by all Connection header values before the header iteration. In the
loop over header, skip any nominated name before the RequestId capture condition
and before shouldCopyUpstreamHeader, while continuing to reject Connection
itself. Add coverage for a nominated safe-looking header to verify it is neither
captured nor forwarded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6dd16236-7160-490e-a14c-a19938430f3e

📥 Commits

Reviewing files that changed from the base of the PR and between 683dbd5 and cab7051.

📒 Files selected for processing (5)
  • service/http.go
  • service/http_client_test.go
  • service/task_billing_test.go
  • service/task_polling.go
  • service/task_polling_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • service/task_billing_test.go
  • service/http_client_test.go
  • service/task_polling_test.go
  • service/http.go
  • service/task_polling.go
🔇 Additional comments (4)
service/task_billing_test.go (1)

566-596: LGTM!

service/http_client_test.go (1)

35-48: LGTM!

service/task_polling_test.go (1)

93-100: LGTM!

service/task_polling.go (1)

282-284: LGTM!

@CSCITech

CSCITech commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
main.go (1)

240-255: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use the original shutdown context for background runners.

Line 240 starts a second full shutdownTimeout after shutdownHTTPServer(ctx, srv) returns. If HTTP shutdown consumes its deadline, the process can wait for another full timeout while stopping background runners.

Pass ctx to every background shutdown call. This enforces the configured shutdown deadline for the complete shutdown sequence.

Proposed fix
-	stopBackgroundRunnerCtx, stopBackgroundRunnerCancel := context.WithTimeout(context.Background(), shutdownTimeout)
-	if err := common.StopSystemMonitor(stopBackgroundRunnerCtx); err != nil {
+	if err := common.StopSystemMonitor(ctx); err != nil {
 		common.SysError(fmt.Sprintf("timed out stopping system monitor: %v", err))
 	}
-	if err := middleware.StopInMemoryRateLimiter(stopBackgroundRunnerCtx); err != nil {
+	if err := middleware.StopInMemoryRateLimiter(ctx); err != nil {
 		common.SysError(fmt.Sprintf("timed out stopping in-memory rate limiter: %v", err))
 	}
-	if err := model.StopBillingSettlementTaskRunner(stopBackgroundRunnerCtx); err != nil {
+	if err := model.StopBillingSettlementTaskRunner(ctx); err != nil {
 		common.SysError(fmt.Sprintf("timed out stopping billing settlement runner: %v", err))
 	}
 	if common.RedisEnabled {
-		if err := model.StopCacheInvalidationTaskRunner(stopBackgroundRunnerCtx); err != nil {
+		if err := model.StopCacheInvalidationTaskRunner(ctx); err != nil {
 			common.SysError(fmt.Sprintf("timed out stopping cache invalidation runner: %v", err))
 		}
 	}
-	stopBackgroundRunnerCancel()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.go` around lines 240 - 255, Use the original shutdown context ctx for
all background shutdown calls after shutdownHTTPServer, removing the separate
stopBackgroundRunnerCtx/stopBackgroundRunnerCancel timeout context. Pass ctx to
StopSystemMonitor, StopInMemoryRateLimiter, StopBillingSettlementTaskRunner, and
StopCacheInvalidationTaskRunner so the complete shutdown sequence shares one
deadline.
relay/channel/ali/image.go (1)

30-69: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Carry the OpenAI n value into Parameters.N when request.Extra is nil.

When request.Extra is nil, imageRequest.Parameters.N becomes nil, so NValue() returns 0, dto.ValidateImageN("parameters.n", 0) passes, no n pricing ratio is added, and the upstream request omits n. Use the same unconditional default from request.N as oaiFormEdit2AliImageEdit for this standard field.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/ali/image.go` around lines 30 - 69, Ensure the image request
conversion initializes imageRequest.Parameters.N from request.N even when
request.Extra is nil, matching the unconditional default behavior used by
oaiFormEdit2AliImageEdit. Preserve any parameters parsed from request.Extra,
while ensuring NValue(), validation, pricing, and the upstream request all use
the OpenAI n value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/oauth.go`:
- Around line 133-136: Update the unauthenticated branch in GenerateOAuthCode to
replace the hardcoded Chinese bind-login message with the existing i18n key for
“login required,” using the same common.ApiErrorI18n pattern as the other error
paths. Preserve the 401 Unauthorized status and response behavior required by
TestGenerateOAuthCodeRejectsAnonymousBind.

In `@model/auth_flow_test.go`:
- Around line 20-33: Update setupAuthFlowTestDB to add a SQLite busy timeout
parameter to the shared in-memory DSN used by gorm.Open. Keep the shared
in-memory configuration intact so concurrent ConsumeAuthFlow calls wait for the
writer lock and preserve the expected ErrAuthFlowConsumed result.

In `@model/auth_flow.go`:
- Around line 62-64: Update authFlowTokenHash to use a stable persisted signing
key rather than common.SessionSecret, which may be regenerated when
SESSION_SECRET is unset. Source the key from the configured environment variable
or database-backed setting, and ensure the same key is used by session storage
so persisted AuthFlow tokens remain valid across restarts and instances.

In `@oauth/oidc.go`:
- Around line 143-146: Update the required identity-field check in the OIDC
user-info flow to reject only when oidcUser.OpenID is empty; allow an empty
oidcUser.Email so findOrCreateOAuthUser can handle subject-only authentication.

In `@relay/channel/coze/adaptor.go`:
- Line 82: Check the error returned by common2.Unmarshal in the response
handling flow before accessing cozeResponse or starting polling; return or
propagate the decode error immediately when unmarshalling fails, while
preserving the existing behavior for successfully decoded responses.

In `@relay/common/pass_through_body.go`:
- Around line 418-432: Optimize passThroughJSONScanner byte scanning by avoiding
separate bufio.Reader calls from peekByte and readByte for the same byte. Update
these methods and their scanner state to support one-byte pushback or equivalent
buffered-slice scanning, while preserving readByte offset increments only when a
byte is consumed and maintaining existing EOF/error behavior.

In `@service/auth_flow_cleanup.go`:
- Around line 12-23: The background loops in StartAuthFlowCleanup in
service/auth_flow_cleanup.go (lines 12-23) and Monitor in common/pprof.go (lines
15-19) need shutdown control. Pass the existing shutdown context or stop channel
into both loops, select on cancellation alongside ticker events, and stop the
auth cleanup ticker and CPU monitor during graceful shutdown.

---

Outside diff comments:
In `@main.go`:
- Around line 240-255: Use the original shutdown context ctx for all background
shutdown calls after shutdownHTTPServer, removing the separate
stopBackgroundRunnerCtx/stopBackgroundRunnerCancel timeout context. Pass ctx to
StopSystemMonitor, StopInMemoryRateLimiter, StopBillingSettlementTaskRunner, and
StopCacheInvalidationTaskRunner so the complete shutdown sequence shares one
deadline.

In `@relay/channel/ali/image.go`:
- Around line 30-69: Ensure the image request conversion initializes
imageRequest.Parameters.N from request.N even when request.Extra is nil,
matching the unconditional default behavior used by oaiFormEdit2AliImageEdit.
Preserve any parameters parsed from request.Extra, while ensuring NValue(),
validation, pricing, and the upstream request all use the OpenAI n value.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 502414f8-8b00-4b9c-99b4-7a70d592f0c1

📥 Commits

Reviewing files that changed from the base of the PR and between 06b8245 and d19614d.

📒 Files selected for processing (71)
  • common/body_storage.go
  • common/body_storage_replay_test.go
  • common/email.go
  • common/pprof.go
  • common/pprof_test.go
  • common/random_failure_test.go
  • common/str.go
  • common/utils.go
  • controller/codex_oauth.go
  • controller/oauth.go
  • controller/oauth_test.go
  • controller/subscription_payment_epay.go
  • controller/topup.go
  • controller/user.go
  • docs/openapi/api.json
  • dto/openai_request.go
  • dto/values.go
  • main.go
  • main_test.go
  • model/ability.go
  • model/auth_flow.go
  • model/auth_flow_test.go
  • model/main.go
  • model/subscription.go
  • model/twofa.go
  • model/user.go
  • oauth/generic.go
  • oauth/http_client.go
  • oauth/http_client_test.go
  • oauth/oidc.go
  • relay/channel/ali/dto.go
  • relay/channel/ali/image.go
  • relay/channel/ali/image_wan.go
  • relay/channel/ali/rerank.go
  • relay/channel/ali/text.go
  • relay/channel/ali/text_test.go
  • relay/channel/api_request.go
  • relay/channel/api_request_test.go
  • relay/channel/baidu/dto.go
  • relay/channel/baidu/relay-baidu.go
  • relay/channel/baidu/relay_baidu_test.go
  • relay/channel/coze/adaptor.go
  • relay/channel/coze/dto.go
  • relay/channel/coze/relay-coze.go
  • relay/channel/coze/relay_coze_test.go
  • relay/channel/siliconflow/adaptor.go
  • relay/channel/siliconflow/adaptor_test.go
  • relay/channel/siliconflow/dto.go
  • relay/channel/siliconflow/relay-siliconflow.go
  • relay/channel/vertex/adaptor.go
  • relay/channel/vertex/service_account.go
  • relay/channel/vertex/service_account_test.go
  • relay/channel/zhipu/adaptor.go
  • relay/channel/zhipu/relay-zhipu.go
  • relay/channel/zhipu/relay_zhipu_test.go
  • relay/claude_handler.go
  • relay/common/outbound_body.go
  • relay/common/outbound_body_test.go
  • relay/common/override_test.go
  • relay/common/pass_through_body.go
  • relay/common/relay_info.go
  • relay/compatible_handler.go
  • relay/responses_handler.go
  • router/api-router.go
  • router/api_router_test.go
  • service/auth_flow_cleanup.go
  • service/system_task.go
  • tools/jsonwrapcheck/allowlist.txt
  • web/default/src/features/auth/api.ts
  • web/default/src/features/auth/hooks/use-oauth-login.ts
  • web/default/src/lib/oauth.ts
💤 Files with no reviewable changes (1)
  • tools/jsonwrapcheck/allowlist.txt
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: In Go business code, all JSON marshal/unmarshal operations must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) and must not directly call encoding/json for actual encode/decode work.
All database code must be compatible with SQLite, MySQL 5.7.8+, and PostgreSQL 9.6+; prefer GORM abstractions over raw SQL, avoid direct AUTO_INCREMENT/SERIAL, use commonGroupCol/commonKeyCol and commonTrueVal/commonFalseVal for DB-specific SQL, branch with common.UsingPostgreSQL/common.UsingSQLite/common.UsingMySQL, avoid unsupported DB-specific functions/operators without fallback, and make migrations work across all three databases.
When implementing a new relay channel, confirm whether the provider supports StreamOptions; if it does, add that channel to streamSupportedChannels.
For request structs parsed from client JSON and re-marshaled to upstream providers, optional scalar fields must use pointer types with omitempty so explicit zero/false values are preserved instead of dropped.
When working on tiered/dynamic billing expression code, read pkg/billingexpr/expr.md first and follow its documented expression language, architecture, token normalization, quota conversion, and versioning patterns.

**/*.go: All JSON marshal/unmarshal operations in Go business code must use the wrapper functions in common/json.go (common.Marshal, common.Unmarshal, common.UnmarshalJsonStr, common.DecodeJson, common.GetJsonType) instead of directly importing or calling encoding/json for actual marshal/unmarshal work.
All database code in Go must remain compatible with SQLite, MySQL >= 5.7.8, and PostgreSQL >= 9.6; prefer GORM abstractions, avoid raw SQL unless necessary, use the shared DB helper variables for reserved words and boolean literals, branch with the common.UsingPostgreSQL / common.UsingSQLite / common.UsingMySQL flags when need...

Files:

  • relay/channel/zhipu/relay_zhipu_test.go
  • common/pprof_test.go
  • oauth/http_client.go
  • model/main.go
  • relay/channel/coze/dto.go
  • common/body_storage_replay_test.go
  • relay/channel/baidu/dto.go
  • relay/claude_handler.go
  • relay/channel/vertex/service_account_test.go
  • controller/codex_oauth.go
  • relay/channel/ali/image_wan.go
  • relay/compatible_handler.go
  • relay/responses_handler.go
  • relay/common/outbound_body_test.go
  • main_test.go
  • common/pprof.go
  • relay/channel/coze/relay_coze_test.go
  • relay/channel/siliconflow/relay-siliconflow.go
  • dto/values.go
  • relay/channel/baidu/relay_baidu_test.go
  • relay/channel/ali/text.go
  • relay/channel/ali/rerank.go
  • relay/channel/zhipu/adaptor.go
  • relay/channel/vertex/adaptor.go
  • model/twofa.go
  • common/random_failure_test.go
  • relay/channel/siliconflow/adaptor.go
  • relay/channel/coze/adaptor.go
  • common/utils.go
  • service/system_task.go
  • relay/channel/siliconflow/adaptor_test.go
  • router/api-router.go
  • relay/channel/ali/image.go
  • service/auth_flow_cleanup.go
  • relay/channel/siliconflow/dto.go
  • common/str.go
  • controller/subscription_payment_epay.go
  • relay/channel/vertex/service_account.go
  • model/auth_flow_test.go
  • router/api_router_test.go
  • relay/common/outbound_body.go
  • relay/channel/ali/text_test.go
  • relay/common/override_test.go
  • model/ability.go
  • relay/common/relay_info.go
  • controller/user.go
  • model/subscription.go
  • oauth/oidc.go
  • relay/channel/baidu/relay-baidu.go
  • relay/channel/coze/relay-coze.go
  • relay/channel/ali/dto.go
  • relay/channel/api_request.go
  • dto/openai_request.go
  • common/email.go
  • main.go
  • oauth/http_client_test.go
  • relay/common/pass_through_body.go
  • relay/channel/api_request_test.go
  • common/body_storage.go
  • model/user.go
  • controller/oauth_test.go
  • relay/channel/zhipu/relay-zhipu.go
  • model/auth_flow.go
  • controller/topup.go
  • controller/oauth.go
  • oauth/generic.go
relay/channel/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

When implementing a new channel, confirm whether the provider supports StreamOptions; if it does, add the channel to streamSupportedChannels.

Files:

  • relay/channel/zhipu/relay_zhipu_test.go
  • relay/channel/coze/dto.go
  • relay/channel/baidu/dto.go
  • relay/channel/vertex/service_account_test.go
  • relay/channel/ali/image_wan.go
  • relay/channel/coze/relay_coze_test.go
  • relay/channel/siliconflow/relay-siliconflow.go
  • relay/channel/baidu/relay_baidu_test.go
  • relay/channel/ali/text.go
  • relay/channel/ali/rerank.go
  • relay/channel/zhipu/adaptor.go
  • relay/channel/vertex/adaptor.go
  • relay/channel/siliconflow/adaptor.go
  • relay/channel/coze/adaptor.go
  • relay/channel/siliconflow/adaptor_test.go
  • relay/channel/ali/image.go
  • relay/channel/siliconflow/dto.go
  • relay/channel/vertex/service_account.go
  • relay/channel/ali/text_test.go
  • relay/channel/baidu/relay-baidu.go
  • relay/channel/coze/relay-coze.go
  • relay/channel/ali/dto.go
  • relay/channel/api_request.go
  • relay/channel/api_request_test.go
  • relay/channel/zhipu/relay-zhipu.go
dto/**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

For request structs parsed from client JSON and then re-marshaled to upstream providers, especially in relay/convert paths, optional scalar fields must use pointer types with omitempty so that absent fields stay omitted while explicit zero/false values are preserved.

Files:

  • dto/values.go
  • dto/openai_request.go
web/default/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/default/AGENTS.md)

web/default/src/**/*.{ts,tsx}: 前端页面文本与组件内文案必须支持 i18n:React 组件中应使用 useTranslation() 取得 t,并通过 t() 渲染用户可见文本;子组件也应自行使用 useTranslation() 保持独立性。
禁止使用两层及以上嵌套三元表达式;复杂逻辑应改用 if-else、提前返回或抽取函数。
控制函数圈复杂度,复杂逻辑应拆成更小的函数;变量与函数命名应有意义并遵循驼峰等常规命名约定。
TypeScript 代码应避免使用 any,优先使用具体类型或 unknown;参数与返回值应显式标注类型;仅类型用途的导入应使用 import type
修改 TypeScript 或 TSX 代码后必须执行类型检查,并修复所有类型错误,不得遗留。
对象非必要不要解构,尤其是组件 props;优先直接使用 props.xxx 以保持代码清晰。
组件应使用函数式组件与 Hooks,遵循单一职责;组件 props 必须有明确类型(接口或类型别名)。
单文件超过约 200 行时应考虑拆分子组件或抽取自定义 Hooks;类型定义可与组件同文件或放在同模块的 types 中。
在 React 中应合理使用 useMemouseCallbackReact.memo,避免在渲染路径中创建新对象或数组;必要时进行代码分割与动态 import
React Query 的数据获取应使用 useQuery、变更应使用 useMutation;每个查询需配置唯一 queryKey,并在成功后对相关查询执行 invalidateQueries;服务端错误应统一交给 handleServerError
Axios 请求应使用项目统一的 api 实例;GET 请求默认去重,特殊请求可显式关闭;认证与通用错误应在拦截器中统一处理。
服务端错误应统一使用 handleServerError,展示层应使用 toast.error 等统一方式;文案需走 i18n;路由级错误应由 errorComponent 承接;表单错误应通过 form.setError 等方式映射到字段。
样式应以 Tailwind 工具类为主,动态类名使用 cn() 合并;非动态场景避免内联样式;响应式采用移动优先与 Tailwind 断点,主题与暗色模式通过 CSS 变量与 dark: 处理。
应使用语义化 HTML、正确关联 label 与输入、保证键盘可操作与合理焦点顺序;必要时添加 ARIA 属性,装饰性图标应使用 aria-hidden="true"
认证与权限应在路由与接口层校验;前后端都应做数据校验(如 Zod);敏感信息不得落前端存储;避免使用 dangerouslySetInnerHTML;跨域与 Cookie 需配合 withCredentials 并按后端要求处理 CSRF。
组件测试应使用 React Testing Library,关注交互与行为,避免测试实现细节;关键流程可补充集成与 E2E 测试。
环境变量应通过 .env 读取,并使用 VITE_ 前缀;代码中不得硬编码密钥。

Files:

  • web/default/src/features/auth/api.ts
  • web/default/src/features/auth/hooks/use-oauth-login.ts
  • web/default/src/lib/oauth.ts
web/default/src/features/**

📄 CodeRabbit inference engine (web/default/AGENTS.md)

功能模块应放在 src/features/<feature>/,并按需包含 components/lib/hooks/api.tstypes.tsconstants.ts 等;通用组件应放在 src/components/,通用工具与类型应放在 src/lib/

Files:

  • web/default/src/features/auth/api.ts
  • web/default/src/features/auth/hooks/use-oauth-login.ts
🪛 ast-grep (0.45.0)
relay/channel/zhipu/relay_zhipu_test.go

[warning] 9-9: A credential is hard-coded as a string literal. Secrets stored in source code, such as passwords, API keys, and tokens, can be leaked through version control or binaries and used by internal or external malicious actors. Rotate the exposed secret and load it at runtime from a secure secret vault, a Hardware Security Module (HSM), or an environment variable if permitted by your company policy (e.g. password := os.Getenv("APP_PASSWORD")).
Context: apiKey = "test-id.test-secret"
Note: [CWE-798] Use of Hard-coded Credentials.

(hardcoded-credentials-string-literal-go)

🔇 Additional comments (70)
model/user.go (2)

867-920: LGTM!


928-952: 🗄️ Data Integrity & Integration

Dispatch InsertWithTx cache invalidation after the commit.

InsertWithTx stores a CacheInvalidationTask, but controller/oauth.go never calls dispatchStagedCacheInvalidation after the outer transaction commits. The registered cache retry worker can eventually run this task, so cache invalidation is not lost.

common/utils.go (1)

243-243: LGTM!

Also applies to: 255-258

model/ability.go (1)

97-100: LGTM!

Also applies to: 172-225

common/email.go (1)

24-28: LGTM!

common/pprof.go (1)

12-12: LGTM!

Also applies to: 22-50

common/pprof_test.go (1)

11-24: LGTM!

common/random_failure_test.go (1)

12-46: LGTM!

common/body_storage.go (1)

23-31: LGTM!

Also applies to: 92-100, 250-262, 336-360

relay/channel/zhipu/relay_zhipu_test.go (1)

1-26: LGTM!

relay/channel/baidu/dto.go (1)

15-26: LGTM!

docs/openapi/api.json (1)

869-922: LGTM!

relay/channel/ali/text.go (1)

11-22: LGTM!

service/system_task.go (1)

7-7: LGTM!

Also applies to: 101-106

relay/channel/vertex/service_account.go (1)

12-12: LGTM!

Also applies to: 47-66, 134-143, 177-185

relay/channel/baidu/relay-baidu.go (1)

26-51: LGTM!

Also applies to: 136-161, 164-189

main.go (1)

131-131: LGTM!

Also applies to: 197-197, 275-284

controller/topup.go (1)

12-12: LGTM!

Also applies to: 222-228

oauth/generic.go (1)

129-133: LGTM!

Also applies to: 200-214, 260-261

oauth/http_client.go (1)

11-18: LGTM!

relay/channel/coze/dto.go (1)

22-24: LGTM!

relay/channel/vertex/service_account_test.go (1)

10-28: LGTM!

relay/channel/ali/rerank.go (1)

7-7: LGTM!

Also applies to: 43-43, 67-67

relay/channel/zhipu/adaptor.go (1)

53-56: LGTM!

relay/channel/vertex/adaptor.go (1)

269-269: LGTM!

relay/channel/siliconflow/adaptor.go (1)

52-56: LGTM!

relay/channel/siliconflow/adaptor_test.go (1)

15-38: LGTM!

relay/channel/siliconflow/dto.go (1)

20-31: LGTM!

relay/channel/coze/relay-coze.go (4)

43-43: LGTM!


58-88: LGTM!


156-205: LGTM!


244-244: LGTM!

model/main.go (1)

345-345: LGTM!

model/twofa.go (1)

182-182: LGTM!

Also applies to: 208-208, 307-307

controller/subscription_payment_epay.go (1)

79-85: LGTM!

oauth/oidc.go (1)

72-75: LGTM!

Also applies to: 118-121, 86-86, 137-137, 148-148

oauth/http_client_test.go (1)

19-41: LGTM!

Also applies to: 43-98

controller/oauth_test.go (1)

31-44: LGTM!

Also applies to: 46-71, 73-117, 119-127, 129-162, 201-201, 226-226, 250-250, 277-277

relay/channel/zhipu/relay-zhipu.go (2)

69-77: LGTM!

Also applies to: 165-182, 223-232, 241-247, 258-269, 280-280, 291-291


31-45: 🗄️ Data Integrity & Integration

No Zhipu getZhipuToken call-site updates needed.

Each production and test call receives the error value and either returns or asserts on it.

model/auth_flow.go (1)

80-86: LGTM!

Also applies to: 88-109, 111-129, 131-148, 150-154

controller/oauth.go (1)

36-50: LGTM!

Also applies to: 115-132, 137-169, 191-225, 236-254, 270-283, 314-314, 351-361, 397-397, 484-486

common/body_storage_replay_test.go (1)

10-53: LGTM!

relay/responses_handler.go (1)

79-87: LGTM!

relay/common/outbound_body_test.go (1)

15-38: LGTM!

Also applies to: 40-189

router/api-router.go (1)

46-54: LGTM!

Also applies to: 89-89, 109-109

router/api_router_test.go (1)

52-88: LGTM!

Also applies to: 210-295

relay/common/outbound_body.go (1)

7-7: LGTM!

Also applies to: 22-43

controller/user.go (1)

391-396: LGTM!

Also applies to: 459-465

relay/common/pass_through_body.go (2)

100-221: LGTM!

Also applies to: 291-337, 434-456, 458-510, 512-555


45-62: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Consider failing open when the pass-through scan rejects the body.

Pass-through mode forwards the client body unchanged. newPassThroughFilteredBody now returns a scan error for any body this scanner cannot parse. Callers in relay/responses_handler.go, relay/claude_handler.go, and relay/compatible_handler.go convert that error into ErrorCodeConvertRequestFailed with skip-retry. A body that the upstream provider would accept, but this scanner rejects, therefore fails at the gateway instead of upstream.

If the scan fails and no controlled field can be present, forwarding the raw body preserves the previous behavior. If you intend to reject unparsable bodies, keep the current behavior and confirm the error code and message are correct for clients.

🛡️ Optional fail-open variant
 	ranges, scannedSize, scanErr := scanPassThroughJSON(reader, settings)
 	closeErr := reader.Close()
 	if scanErr != nil {
-		return nil, scanErr
+		// Pass-through promises raw forwarding; an unparsable body cannot
+		// contain a controlled field we are able to locate.
+		basecommon.SysError("pass-through JSON scan failed, forwarding raw body: " + scanErr.Error())
+		return nil, nil
 	}
			> Likely an incorrect or invalid review comment.
relay/channel/api_request_test.go (1)

132-144: LGTM!

Also applies to: 146-175

relay/channel/ali/dto.go (1)

29-33: 🩺 Stability & Availability

No nil-dereference issue here.

The relevant Ali pointer fields are either guarded before dereference or not dereferenced in the ali channel handlers shown.

relay/claude_handler.go (1)

158-166: LGTM!

controller/codex_oauth.go (1)

167-173: LGTM!

relay/channel/ali/image_wan.go (1)

19-21: LGTM!

Also applies to: 36-40

relay/compatible_handler.go (1)

107-115: LGTM!

main_test.go (1)

131-137: LGTM!

web/default/src/features/auth/api.ts (1)

90-97: 📐 Maintainability & Code Quality

Run the frontend type check.

The PR does not provide a TypeScript type-check result for the changed OAuth request contracts and callers.

  • web/default/src/features/auth/api.ts#L90-L97: validate the login state request contract.
  • web/default/src/features/auth/hooks/use-oauth-login.ts#L96-L96: validate the GitHub caller.
  • web/default/src/features/auth/hooks/use-oauth-login.ts#L127-L127: validate the Discord caller.
  • web/default/src/features/auth/hooks/use-oauth-login.ts#L148-L148: validate the OIDC caller.
  • web/default/src/features/auth/hooks/use-oauth-login.ts#L173-L173: validate the LinuxDO caller.
  • web/default/src/features/auth/hooks/use-oauth-login.ts#L198-L198: validate the custom-provider caller.
  • web/default/src/lib/oauth.ts#L151-L156: validate the binding state request contract.

Source: Coding guidelines

relay/channel/api_request.go (1)

30-45: LGTM!

Also applies to: 326-326, 356-356, 563-563

relay/channel/coze/relay_coze_test.go (1)

14-22: LGTM!

relay/channel/siliconflow/relay-siliconflow.go (1)

7-7: LGTM!

Also applies to: 23-23, 37-37

dto/values.go (1)

7-8: LGTM!

Also applies to: 12-29, 34-41, 52-78

relay/channel/baidu/relay_baidu_test.go (1)

43-48: LGTM!

common/str.go (1)

84-85: LGTM!

relay/channel/ali/text_test.go (1)

14-83: LGTM!

relay/common/override_test.go (1)

2001-2017: LGTM!

Also applies to: 2035-2049

relay/common/relay_info.go (1)

868-868: LGTM!

model/subscription.go (1)

787-796: LGTM!

Also applies to: 839-839

dto/openai_request.go (1)

493-500: LGTM!

Also applies to: 690-690, 715-722, 733-733, 749-749, 760-760

Comment thread controller/oauth.go
Comment thread model/auth_flow_test.go
Comment thread model/auth_flow.go
Comment on lines +62 to +64
func authFlowTokenHash(token string) string {
return common.GenerateHMACWithKey([]byte("auth-flow-v1:"+common.SessionSecret), token)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Determine how SessionSecret is initialized and whether it persists.
rg -nP -C5 '\bSessionSecret\b' --type=go
# Description: Confirm the output encoding and length of GenerateHMACWithKey to validate the char(64) column.
ast-grep run --pattern 'func GenerateHMACWithKey($$$) $$$ { $$$ }' --lang go

Repository: MAX-API-Next/MAX-API

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -u

echo "== files =="
git ls-files | sed -n '1,120p'

echo "== SessionSecret occurrences case-insensitive (all files) =="
rg -n -i -C 4 'SessionSecret|sessionsecret|\.Secret|generatehmacwithkey|TokenHash|auth-flow-v1|auth_flow' . || true

echo "== Go files common auth_flow nearby =="
fd -t f -e go . | sort | sed -n '1,200p'

Repository: MAX-API-Next/MAX-API

Length of output: 22425


Use a persisted key for auth_flow token hashing.

common.SessionSecret falls back to uuid.New().String() when SESSION_SECRET is unset, so process restarts or multi-instance deployments can compute different TokenHash values. That makes persisted AuthFlow rows unreadable and causes ErrAuthFlowInvalid on callbacks. Store the signing key in an environment variable or database and use it for authFlowTokenHash and session storage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@model/auth_flow.go` around lines 62 - 64, Update authFlowTokenHash to use a
stable persisted signing key rather than common.SessionSecret, which may be
regenerated when SESSION_SECRET is unset. Source the key from the configured
environment variable or database-backed setting, and ensure the same key is used
by session storage so persisted AuthFlow tokens remain valid across restarts and
instances.

Comment thread oauth/oidc.go Outdated
Comment thread relay/channel/coze/adaptor.go Outdated
Comment thread relay/common/pass_through_body.go
Comment thread service/auth_flow_cleanup.go
@CSCITech

CSCITech commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech

CSCITech commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CSCITech
CSCITech merged commit c2ef01d into main Aug 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant