Skip to content

feat(channel): add Baichuan type + fix max_tokens & Azure AI Foundry /openai/v1 - #6597

Open
aiastia wants to merge 8 commits into
QuantumNous:mainfrom
aiastia:feat/baichuan-channel
Open

feat(channel): add Baichuan type + fix max_tokens & Azure AI Foundry /openai/v1#6597
aiastia wants to merge 8 commits into
QuantumNous:mainfrom
aiastia:feat/baichuan-channel

Conversation

@aiastia

@aiastia aiastia commented Aug 2, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

AI 辅助生成声明:本 PR 的代码由 AI 辅助生成(提交者 未来 <aiastia@users.noreply.github.com> 不属于项目历史核心开发者),提交前已由人工核对编译通过与改动逻辑。描述已人工整理,未直接粘贴 AI 原始输出。

本 PR 包含三个独立改动,合并提交以便一并审阅。可按需拆分(三个 commit 相互独立)。

📝 变更描述 / Description

1. 新增百川(Baichuan)渠道类型

为百川平台(https://platform.baichuan-ai.com)新增独立渠道类型(`ChannelTypeBaichuan = 61)。百川提供 OpenAI 兼容的 /v1/chat/completions端点,复用现有openai.Adaptor,仅注册类型与默认 base URL。同时修复其「获取上游模型」:GET /v1/modelsdata[].model而非标准data[].id`,新增专门分支解析。

2. 修复渠道测试对 max_tokens 的处理

渠道测试请求 buildTestRequest 硬编码 max_tokens=16。Azure OpenAI 与 OpenAI reasoning 模型要求 max_completion_tokens,导致 Azure 上批量测试 gpt-4o / gpt-5.x 返回 400。转发链路已对 o 系列/gpt-5 系列转换,但测试路径只特判 o 系列,且未考虑 Azure 对 gpt-4o/gpt-4.1 也拒绝 max_tokens。将规则集中到 useMaxCompletionTokens(),在两个分支统一应用。

3. 支持新版 Azure AI Foundry /openai/v1 端点

Azure 渠道适配器总是构建经典 deployment 路径(/openai/deployments/{model}/{task}?api-version=)。新版 Azure AI Foundry 资源(host *.services.ai.azure.com,base URL 含 /openai/v1)使用标准 OpenAI 路径 /openai/v1/chat/completions,模型名放请求体,不带 api-version。新版资源走经典路径会返回 404 DeploymentNotFound

参照 one-hub 已有逻辑:当请求路径以 /v1 开头时,构建 /openai{path}(无 api-version),否则走经典 deployment 路径。经典 Azure OpenAI 资源的请求路径不以 /v1 开头,行为不变。这让用户对 AI Foundry 资源可继续用 Azure 渠道类型(及其 api-key 头),不必改用 Custom 渠道。

🚀 变更类型 / Type of change

  • ✨ 新功能 (New feature) — 百川渠道类型
  • 🐛 Bug 修复 (Bug fix) — max_tokens 测试 & Azure AI Foundry 端点

🔗 关联任务 / Related Issue

  • 无对应 Issue。

✅ 提交前检查项 / Checklist

  • 人工确认: 描述已亲自整理,未直接粘贴未经处理的 AI 输出。
  • 非重复提交: 已搜索 Issues/PRs,未见重复。
  • Bug fix 说明: max_tokens 与 Azure /v1 问题均为代码与转发逻辑/上游规范不一致导致,非设计取舍或理解偏差。
  • 变更理解: 百川复用 OpenAI 转发;测试请求规则与转发对齐;Azure /v1 分支参照 one-hub 既有实现。
  • 范围聚焦: 三项改动各自独立,共 17 个文件,均与所述任务相关。
  • 本地验证: 后端 go build ./... 编译通过(golang:1.25 容器内 exit 0)。
  • 安全合规: 无敏感凭据;遵循 common.Unmarshal 包装规范。

📸 运行证明 / Proof of Work

后端编译:

$ go build ./...
(exit 0)

百川 /v1/models 返回格式(改动 1 修复的解析问题):

{"data":[{"model":"Baichuan-M3",...},{"model":"Baichuan4-Turbo",...}]}

Azure 批量测试对比(改动 2,实测):

模型 修复前 修复后
gpt-4o ❌ 400 max_tokens
gpt-5.4 系列(已部署) ❌ 400 max_tokens

Azure AI Foundry 端点(改动 3):

  • 修复前:AI Foundry 资源(*.services.ai.azure.com)选 Azure 类型 → 强制走 /openai/deployments/{model}/ → 404
  • 修复后:请求路径以 /v1 开头时走 /openai/v1/chat/completions → 正常工作

Summary by CodeRabbit

  • New Features

    • Added Baichuan as a supported AI provider.
    • Added Baichuan configuration, branding, icon, localized names, model discovery, and streaming options.
    • Added automated publishing of multi-architecture container images.
  • Bug Fixes

    • Improved channel connectivity tests with appropriate token limits for supported models.
    • Improved connectivity with newer Azure AI Foundry endpoints.
    • Improved model list retrieval from Baichuan responses, including clearer handling of malformed responses.

Add a dedicated Baichuan (百川) channel type (type 61) instead of
configuring it as a generic OpenAI-compatible channel. The Baichuan
platform (https://platform.baichuan-ai.com) exposes an OpenAI-compatible
/v1/chat/completions endpoint, so this change reuses the existing OpenAI
relay adaptor while registering a proper channel type with its default
base URL and icon.

It also fixes the upstream model-list fetch for Baichuan: the
GET /v1/models endpoint returns model names under data[].model instead
of the OpenAI-standard data[].id, which caused "Fetch from Upstream" to
return an empty list. A dedicated parser branch now handles the Baichuan
response shape.

Backend:
- constant/channel.go: register ChannelTypeBaichuan = 61, default base
  URL https://api.baichuan-ai.com, and display name.
- constant/api_type.go + common/api_type.go: add APITypeBaichuan and the
  ChannelType2APIType mapping.
- relay/relay_adaptor.go: dispatch APITypeBaichuan to openai.Adaptor.
- relay/common/relay_info.go: enable stream_options support.
- controller/channel_upstream_update.go: parse data[].model for Baichuan.

Frontend:
- channels/constants.ts: add type 61 to the type map, display order, and
  MODEL_FETCHABLE_TYPES so the "Fetch from Upstream" button appears.
- channels/lib/channel-utils.ts: map type 61 to the Baichuan icon.
- i18n locales (en/zh/zh-TW/fr/ja/ru/vi): add the "Baichuan" label.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

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: CHILL

Plan: Pro Plus

Run ID: 18cd24d0-4d85-43a5-a995-8b274e38e17e

📥 Commits

Reviewing files that changed from the base of the PR and between eacc213 and 1f0c83e.

📒 Files selected for processing (1)
  • relay/channel/openai/adaptor.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/channel/openai/adaptor.go

Walkthrough

Baichuan is added as channel type 61. Backend routing, streaming support, model discovery, and frontend metadata recognize Baichuan. Channel tests select token parameters for additional models. Azure supports newer /v1 endpoints. A workflow builds and publishes multi-architecture Docker images to GHCR.

Changes

Baichuan integration

Layer / File(s) Summary
Backend channel registration and routing
constant/api_type.go, constant/channel.go, common/api_type.go, relay/relay_adaptor.go, relay/common/relay_info.go
Registers Baichuan, maps it to the OpenAI adaptor, assigns its base URL and display name, and enables streaming support.
Baichuan model response parsing
controller/channel_upstream_update.go
Reads model names from Baichuan data[].model responses, normalizes them, and returns errors for malformed JSON.
Frontend channel metadata
web/src/features/channels/constants.ts, web/src/features/channels/lib/channel-utils.ts, web/src/i18n/locales/*
Adds Baichuan to channel labels, ordering, model fetching, icon mapping, and locale catalogs.

Channel-test and Azure request handling

Layer / File(s) Summary
Token parameter selection
controller/channel-test.go
Uses max_completion_tokens for reasoning, GPT-5, and selected Azure models. Preserves Gemini’s 3000-token max_tokens value and other default limits.
Azure AI Foundry URL routing
relay/channel/openai/adaptor.go
Routes Azure paths beginning with /v1 through /openai/v1 without deployment names or API-version parameters. Existing deployment routing remains available.

Container image publishing

Layer / File(s) Summary
Multi-architecture GHCR workflow
.github/workflows/docker-ghcr.yml
Builds amd64 and arm64 images, pushes architecture-specific tags, and publishes branch, versioned, and latest manifests.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant ChannelController
  participant BaichuanAPI
  participant ModelList
  ChannelController->>BaichuanAPI: Request upstream models
  BaichuanAPI-->>ChannelController: Return data[].model response
  ChannelController->>ModelList: Normalize and return model names
Loading

Poem

A rabbit maps channel sixty-one,
Baichuan models join the run.
Tokens choose the proper way,
Azure paths take a newer way.
Docker builds hop to GHCR today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the three main changes: Baichuan support, token parameter updates, and Azure AI Foundry routing.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@relay/common/relay_info.go`:
- Line 351: Update openai.Adaptor.ConvertOpenAIRequest to preserve StreamOptions
for ChannelTypeBaichuan, matching its SupportStreamOptions configuration instead
of clearing the field for non-OpenAI/non-Azure channels. Add a conversion test
covering a Baichuan streaming request and verify stream_options.include_usage
remains present.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro Plus

Run ID: dffcd8e6-640b-4575-ab7a-9a4135a768af

📥 Commits

Reviewing files that changed from the base of the PR and between 0ab0202 and c386058.

📒 Files selected for processing (15)
  • common/api_type.go
  • constant/api_type.go
  • constant/channel.go
  • controller/channel_upstream_update.go
  • relay/common/relay_info.go
  • relay/relay_adaptor.go
  • web/src/features/channels/constants.ts
  • web/src/features/channels/lib/channel-utils.ts
  • web/src/i18n/locales/en.json
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/ja.json
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/zh.json

constant.ChannelTypeSub2API: true,
constant.ChannelTypeNewAPI: true,
constant.ChannelTypeTencent: true,
constant.ChannelTypeBaichuan: true,

Copy link
Copy Markdown
Contributor

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
set -euo pipefail

# Expect the StreamOptions clearing logic to honor SupportStreamOptions
# or explicitly allow ChannelTypeBaichuan.
rg -n -C 8 \
  'request\.StreamOptions = nil|SupportStreamOptions|ChannelTypeBaichuan' \
  --glob '*.go' .

Repository: QuantumNous/new-api

Length of output: 15042


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '== relay_info init/StreamOptions section ==\n'
sed -n '200,245p' relay/common/relay_info.go
printf '\n== streamSupportedChannels section ==\n'
sed -n '330,355p' relay/common/relay_info.go

printf '\n== relay adaptor routing around ChannelTypeBaichuan ==\n'
sed -n '110,150p' relay/relay_adaptor.go

printf '\n== relevant OpenAI adaptor snippets ==\n'
sed -n '60,95p' relay/channel/openai/adaptor.go
sed -n '244,252p' relay/channel/openai/adaptor.go

printf '\n== channel adapter ConvertStreamOpenAIRequest references ==\n'
rg -n -C 5 'ConvertStreamOpenAIRequest|ConvertOpenAIRequest|SupportStreamOptions|StreamOptions' relay/channel --glob '*.go'

Repository: QuantumNous/new-api

Length of output: 50375


Preserve stream_options through the OpenAI adaptor.

ChannelTypeBaichuan is routed to openai.Adaptor, and SupportStreamOptions is set to true, but openai.Adaptor.ConvertOpenAIRequest still clears request.StreamOptions for non-OpenAI/non-Azure channels. Baichuan streaming requests lose stream_options before the upstream call. Add ChannelTypeBaichuan to the OpenAI adaptor’s allow-list, or have ConvertOpenAIRequest preserve stream options when info.SupportStreamOptions == true. Add a conversion test that checks Baichuan streaming requests keep stream_options.include_usage.

Suggested fix in the OpenAI adaptor
-	if info.ChannelType != constant.ChannelTypeOpenAI && info.ChannelType != constant.ChannelTypeAzure {
+	if !info.SupportStreamOptions &&
+		info.ChannelType != constant.ChannelTypeOpenAI &&
+		info.ChannelType != constant.ChannelTypeAzure {
		request.StreamOptions = 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 `@relay/common/relay_info.go` at line 351, Update
openai.Adaptor.ConvertOpenAIRequest to preserve StreamOptions for
ChannelTypeBaichuan, matching its SupportStreamOptions configuration instead of
clearing the field for non-OpenAI/non-Azure channels. Add a conversion test
covering a Baichuan streaming request and verify stream_options.include_usage
remains present.

Source: Coding guidelines

…ax_tokens

The channel test request builder hard-coded max_tokens=16 for the default
chat completion probe. Azure OpenAI (and OpenAI's reasoning models) reject
max_tokens and require max_completion_tokens instead, so batch-testing
gpt-4o / gpt-5.x deployments on Azure returned HTTP 400:

  Unsupported parameter: 'max_tokens' is not supported with this model.
  Use 'max_completion_tokens' instead.

The relay path already converts max_tokens to max_completion_tokens for
o-series and gpt-5-series models (relay/channel/openai/adaptor.go), but
the test path only special-cased o-series and missed gpt-5-series, and did
not account for Azure additionally rejecting max_tokens on the gpt-4o /
gpt-4.1 family.

Centralize the rule in useMaxCompletionTokens() and apply it in both the
auto-detected and explicit-endpoint branches of buildTestRequest so the
test request shape stays aligned with what the relay actually sends.
@aiastia aiastia changed the title feat(channel): add dedicated Baichuan channel type feat(channel): add Baichuan type + fix max_tokens in channel test Aug 2, 2026
The Azure channel adapter always built the classic deployment-scoped URL
(/openai/deployments/{model}/{task}?api-version=...). New Azure AI
Foundry resources (endpoint host *.services.ai.azure.com, base URL ending
/openai/v1) expose the standard OpenAI path /openai/v1/chat/completions
instead, with the model passed in the request body and no api-version
query parameter. Routing these resources through the classic deployment
path returns HTTP 404 DeploymentNotFound.

Mirror the behavior already present in one-hub: when the incoming request
path starts with /v1, build /openai{path} (no api-version) instead of the
deployment-scoped URL. Classic Azure OpenAI resources keep using the
deployment path since their requests do not start with /v1.

This lets users keep the Azure channel type (and its api-key header) for
new AI Foundry resources instead of having to switch to a Custom channel.
@aiastia aiastia changed the title feat(channel): add Baichuan type + fix max_tokens in channel test feat(channel): add Baichuan type + fix max_tokens & Azure AI Foundry /openai/v1 Aug 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@relay/channel/openai/adaptor.go`:
- Around line 161-167: Update the Azure URL-selection logic around the current
strings.HasPrefix(info.RequestURLPath, "/v1") branch to use an explicit
channel-configuration discriminator for Azure AI Foundry endpoints rather than
the request path alone. Exclude RelayModeRealtime from this Foundry branch
unless its deployment-specific routing is deliberately preserved, and normalize
the path by removing query parameters before rebuilding ClaudeConvertInfo.task,
requiring a strict /v1/ boundary; retain classic Azure deployment handling,
api-version propagation, and realtime routing.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro Plus

Run ID: a4e2a864-e0b4-4e2d-a6ed-30c691cde247

📥 Commits

Reviewing files that changed from the base of the PR and between a4c4068 and 30c696c.

📒 Files selected for processing (1)
  • relay/channel/openai/adaptor.go

Comment thread relay/channel/openai/adaptor.go Outdated
aiastia added 4 commits August 2, 2026 13:22
Add a GitHub Actions workflow that builds a multi-arch (amd64 + arm64)
Docker image on push to main and publishes it to GitHub Container
Registry at ghcr.io/aiastia/new-api. Uses the built-in GITHUB_TOKEN for
GHCR auth (packages: write), so no Docker Hub secrets are needed.

This is a fork-local CI addition for self-hosting; not intended for the
upstream PR branch.
Reuse the official multi-arch build matrix (native amd64 + arm64 runners,
then manifest merge) with verified action SHAs. Only the registry target
changes: GHCR via GITHUB_TOKEN instead of Docker Hub, image name becomes
ghcr.io/<owner>/<repo>. Triggers on push to main. Drops cosign signing
(not needed for fork self-hosting).
When the request path starts with /v1 (new AI Foundry resources), the
previous fix prepended /openai to the full /v1/chat/completions path,
yielding /openai/v1/chat/completions. That is correct only when the base
URL is the bare hostname. But if the base URL already ends with
/openai/v1 (as the Azure portal suggests), the final URL becomes
.../openai/v1/openai/v1/chat/completions -> 404.

Document the expected base URL shape (hostname only, no /openai/v1
suffix) and keep building /openai + RequestURLPath. This matches the
classic Azure flow where base URL is also just the hostname.
The previous /v1-request-path check was wrong: it fired for BOTH classic
and new Azure resources, because every client reaches new-api via
/v1/chat/completions regardless of upstream type. That would have routed
classic cognitiveservices.azure.com users into the /openai/v1 branch and
broken them.

Switch the discriminator to the base URL host instead:
- *.services.ai.azure.com (AI Foundry) -> /openai/v1/... (model in body)
- everything else -> classic /openai/deployments/{model}/... path

This is the only reliable signal, and it matches how the official
adapter already special-cases cognitiveservices.azure.com above.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 @.github/workflows/docker-ghcr.yml:
- Around line 37-41: Disable persisted checkout credentials by adding
persist-credentials: false to the actions/checkout steps at
.github/workflows/docker-ghcr.yml lines 37-41 and 84-88; apply the same change
to both checkout sites.
- Around line 162-167: Restrict the “Create & push manifest (latest)” step to
runs where needs.prepare.outputs.branch equals main by adding the workflow
condition at the step level. Keep the existing manifest creation command
unchanged for main-branch runs.
- Around line 10-19: Add a workflow-level concurrency group in the Docker GHCR
workflow using the resolved build branch, so runs targeting the same branch
serialize and prevent older publications from overwriting newer main/latest
manifests. Preserve the existing push and workflow_dispatch behavior.
🪄 Autofix (Beta)

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: CHILL

Plan: Pro Plus

Run ID: 4b04210c-f862-4c2a-b66e-e94b55d7596c

📥 Commits

Reviewing files that changed from the base of the PR and between 30c696c and eacc213.

📒 Files selected for processing (2)
  • .github/workflows/docker-ghcr.yml
  • relay/channel/openai/adaptor.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • relay/channel/openai/adaptor.go

Comment on lines +10 to +19
on:
push:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: "Branch name to build (默认 main)"
required: false
default: main
type: string

Copy link
Copy Markdown
Contributor

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

Serialize publications of mutable tags.

Two main runs can complete out of order. The older run can then overwrite the newer main and latest manifests.

Add a workflow-level concurrency group that uses the resolved build branch.

Proposed fix
 on:
   push:
     branches: [main]
   workflow_dispatch:
     inputs:
       branch:
         description: "Branch name to build (默认 main)"
         required: false
         default: main
         type: string

+concurrency:
+  group: ghcr-${{ github.repository }}-${{ inputs.branch || github.ref_name }}
+  cancel-in-progress: true
+
 env:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
push:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: "Branch name to build (默认 main)"
required: false
default: main
type: string
on:
push:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: "Branch name to build (默认 main)"
required: false
default: main
type: string
concurrency:
group: ghcr-${{ github.repository }}-${{ inputs.branch || github.ref_name }}
cancel-in-progress: true
env:
🤖 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 @.github/workflows/docker-ghcr.yml around lines 10 - 19, Add a workflow-level
concurrency group in the Docker GHCR workflow using the resolved build branch,
so runs targeting the same branch serialize and prevent older publications from
overwriting newer main/latest manifests. Preserve the existing push and
workflow_dispatch behavior.

Comment on lines +37 to +41
- name: Check out branch
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 1
ref: ${{ inputs.branch || github.ref }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable persisted checkout credentials.

actions/checkout persists its token in the workspace by default. The build job later supplies that workspace as the Docker build context. Disable credential persistence because the shown commands do not need Git authentication after checkout.

  • .github/workflows/docker-ghcr.yml#L37-L41: add persist-credentials: false.
  • .github/workflows/docker-ghcr.yml#L84-L88: add persist-credentials: false.
🧰 Tools
🪛 zizmor (1.28.0)

[warning] 37-41: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

📍 Affects 1 file
  • .github/workflows/docker-ghcr.yml#L37-L41 (this comment)
  • .github/workflows/docker-ghcr.yml#L84-L88
🤖 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 @.github/workflows/docker-ghcr.yml around lines 37 - 41, Disable persisted
checkout credentials by adding persist-credentials: false to the
actions/checkout steps at .github/workflows/docker-ghcr.yml lines 37-41 and
84-88; apply the same change to both checkout sites.

Source: Linters/SAST tools

Comment on lines +162 to +167
- name: Create & push manifest (latest)
run: |
docker buildx imagetools create \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64

Copy link
Copy Markdown
Contributor

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

Publish latest only from main.

A manual run can select a non-main branch. This step still overwrites :latest with that branch image.

Add a condition that permits this manifest only when needs.prepare.outputs.branch is main.

Proposed fix
       - name: Create & push manifest (latest)
+        if: needs.prepare.outputs.branch == 'main'
         run: |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Create & push manifest (latest)
run: |
docker buildx imagetools create \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64
- name: Create & push manifest (latest)
if: needs.prepare.outputs.branch == 'main'
run: |
docker buildx imagetools create \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-amd64 \
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.tag_prefix }}-arm64
🧰 Tools
🪛 zizmor (1.28.0)

[warning] 165-165: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 166-166: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 166-166: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[warning] 167-167: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 167-167: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 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 @.github/workflows/docker-ghcr.yml around lines 162 - 167, Restrict the
“Create & push manifest (latest)” step to runs where
needs.prepare.outputs.branch equals main by adding the workflow condition at the
step level. Keep the existing manifest creation command unchanged for
main-branch runs.

Instead of hard-coding host detection (services.ai.azure.com), let the
user signal the new AI Foundry endpoint by including /openai at the end
of the base URL. This mirrors how the Azure portal presents the endpoint
(https://xxx.services.ai.azure.com/openai) and avoids fragile host
matching.

- base URL ending in /openai  -> append /v1/chat/completions (AI Foundry)
- base URL without /openai     -> classic /openai/deployments/{model}/... path

Trim trailing slash so "host/openai/" and "host/openai" both work.
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