build: bind candidate identity to images
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-08-26 06:57:12 +08:00
parent 29bdf4900f
commit e8a6122bd6
8 changed files with 71 additions and 22 deletions
+3
View File
@@ -2,6 +2,9 @@
# 敏感配置同时支持NAME_FILE=/容器内绝对路径;NAME与NAME_FILE只能设置一个。 # 敏感配置同时支持NAME_FILE=/容器内绝对路径;NAME与NAME_FILE只能设置一个。
APP_ENV=local APP_ENV=local
LOG_LEVEL=debug LOG_LEVEL=debug
PLATFORM_BUILD_VERSION=dev
PLATFORM_BUILD_COMMIT=unknown
PLATFORM_BUILD_TIME=unknown
HTTP_ADDR=0.0.0.0:58080 HTTP_ADDR=0.0.0.0:58080
API_PORT=58080 API_PORT=58080
CALLBACKS_PORT=58081 CALLBACKS_PORT=58081
+32 -3
View File
@@ -42,10 +42,27 @@ jobs:
npm run build npm run build
- name: Validate compose - name: Validate compose
run: docker compose config --quiet run: docker compose config --quiet
- name: Resolve immutable build identity
run: |
openapi_version="$(awk '/^ version:/{print $2; exit}' openapi/openapi.yaml)"
test -n "$openapi_version"
echo "PLATFORM_BUILD_VERSION=${openapi_version}-ci.${GITHUB_RUN_NUMBER}" >> "$GITHUB_ENV"
echo "PLATFORM_BUILD_COMMIT=${GITHUB_SHA}" >> "$GITHUB_ENV"
echo "PLATFORM_BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_ENV"
- name: Build backend image - name: Build backend image
run: docker build -f deploy/backend.Dockerfile -t data-terminal-cloud-backend:test . run: >-
docker build -f deploy/backend.Dockerfile
--build-arg VERSION="$PLATFORM_BUILD_VERSION"
--build-arg COMMIT="$PLATFORM_BUILD_COMMIT"
--build-arg BUILD_TIME="$PLATFORM_BUILD_TIME"
-t data-terminal-cloud-backend:test .
- name: Build web image - name: Build web image
run: docker build -f deploy/web.Dockerfile -t data-terminal-cloud-web:test . run: >-
docker build -f deploy/web.Dockerfile
--build-arg VERSION="$PLATFORM_BUILD_VERSION"
--build-arg COMMIT="$PLATFORM_BUILD_COMMIT"
--build-arg BUILD_TIME="$PLATFORM_BUILD_TIME"
-t data-terminal-cloud-web:test .
- name: Go vulnerability and license policy - name: Go vulnerability and license policy
run: | run: |
go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
@@ -79,7 +96,19 @@ jobs:
run: | run: |
backend_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-backend:test)" backend_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-backend:test)"
web_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-web:test)" web_digest="$(docker image inspect --format='{{.Id}}' data-terminal-cloud-web:test)"
jq -n --arg source_commit "$GITHUB_SHA" --arg run_id "$GITHUB_RUN_ID" --arg run_attempt "$GITHUB_RUN_ATTEMPT" --arg backend_digest "$backend_digest" --arg web_digest "$web_digest" '{source_commit:$source_commit,run_id:$run_id,run_attempt:$run_attempt,backend_image_digest:$backend_digest,web_image_digest:$web_digest}' > artifacts/build-metadata.json backend_version="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' data-terminal-cloud-backend:test)"
backend_commit="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' data-terminal-cloud-backend:test)"
backend_time="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.created"}}' data-terminal-cloud-backend:test)"
web_version="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.version"}}' data-terminal-cloud-web:test)"
web_commit="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.revision"}}' data-terminal-cloud-web:test)"
web_time="$(docker image inspect --format='{{index .Config.Labels "org.opencontainers.image.created"}}' data-terminal-cloud-web:test)"
test "$backend_version" = "$PLATFORM_BUILD_VERSION"
test "$web_version" = "$PLATFORM_BUILD_VERSION"
test "$backend_commit" = "$GITHUB_SHA"
test "$web_commit" = "$GITHUB_SHA"
test "$backend_time" = "$PLATFORM_BUILD_TIME"
test "$web_time" = "$PLATFORM_BUILD_TIME"
jq -n --arg candidate_version "$PLATFORM_BUILD_VERSION" --arg source_commit "$GITHUB_SHA" --arg build_time "$PLATFORM_BUILD_TIME" --arg run_id "$GITHUB_RUN_ID" --arg run_attempt "$GITHUB_RUN_ATTEMPT" --arg backend_digest "$backend_digest" --arg web_digest "$web_digest" '{candidate_version:$candidate_version,source_commit:$source_commit,build_time:$build_time,run_id:$run_id,run_attempt:$run_attempt,backend_image_digest:$backend_digest,web_image_digest:$web_digest}' > artifacts/build-metadata.json
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: security-and-sbom name: security-and-sbom
+2
View File
@@ -87,6 +87,8 @@ Set-Location E:\Codex\story\platform
.\scripts\dev.ps1 .\scripts\dev.ps1
``` ```
默认本地镜像使用`dev/unknown/unknown`构建标识。需要冻结可追溯候选时,应在构建前设置`PLATFORM_BUILD_VERSION`、40位`PLATFORM_BUILD_COMMIT`和UTC RFC3339格式的`PLATFORM_BUILD_TIME`;Compose会把同一标识写入后端二进制和后端/Web镜像OCI标签,远程CI会根据OpenAPI版本、完整提交和运行时间自动设置并复核这些值。
启动成功后访问: 启动成功后访问:
- Web:<http://localhost:3100> - Web:<http://localhost:3100>
+18 -18
View File
@@ -66,6 +66,14 @@ x-backend-environment: &backend-environment
ARK_EMBEDDING_MODEL: ${ARK_EMBEDDING_MODEL:-} ARK_EMBEDDING_MODEL: ${ARK_EMBEDDING_MODEL:-}
ARK_REQUEST_TIMEOUT: ${ARK_REQUEST_TIMEOUT:-30s} ARK_REQUEST_TIMEOUT: ${ARK_REQUEST_TIMEOUT:-30s}
x-backend-build: &backend-build
context: .
dockerfile: deploy/backend.Dockerfile
args:
VERSION: ${PLATFORM_BUILD_VERSION:-dev}
COMMIT: ${PLATFORM_BUILD_COMMIT:-unknown}
BUILD_TIME: ${PLATFORM_BUILD_TIME:-unknown}
x-backend-dependencies: &backend-dependencies x-backend-dependencies: &backend-dependencies
postgres: postgres:
condition: service_healthy condition: service_healthy
@@ -194,9 +202,7 @@ services:
restart: "no" restart: "no"
api: api:
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/api"] entrypoint: ["/app/api"]
environment: environment:
<<: *backend-environment <<: *backend-environment
@@ -208,9 +214,7 @@ services:
depends_on: *backend-dependencies depends_on: *backend-dependencies
callbacks: callbacks:
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/callbacks"] entrypoint: ["/app/callbacks"]
environment: environment:
<<: *backend-environment <<: *backend-environment
@@ -223,9 +227,7 @@ services:
depends_on: *backend-dependencies depends_on: *backend-dependencies
worker: worker:
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/worker"] entrypoint: ["/app/worker"]
environment: environment:
<<: *backend-environment <<: *backend-environment
@@ -255,9 +257,7 @@ services:
condition: service_started condition: service_started
mock-provider: mock-provider:
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/mock-provider"] entrypoint: ["/app/mock-provider"]
environment: environment:
HTTP_ADDR: 0.0.0.0:8083 HTTP_ADDR: 0.0.0.0:8083
@@ -273,9 +273,7 @@ services:
condition: service_started condition: service_started
mock-alert-receiver: mock-alert-receiver:
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/mock-alert-receiver"] entrypoint: ["/app/mock-alert-receiver"]
environment: environment:
HTTP_ADDR: 0.0.0.0:8084 HTTP_ADDR: 0.0.0.0:8084
@@ -285,9 +283,7 @@ services:
sim-device: sim-device:
profiles: [simulation] profiles: [simulation]
build: build: *backend-build
context: .
dockerfile: deploy/backend.Dockerfile
entrypoint: ["/app/sim-device"] entrypoint: ["/app/sim-device"]
environment: environment:
SIM_API_URL: http://api:8080 SIM_API_URL: http://api:8080
@@ -301,6 +297,10 @@ services:
build: build:
context: . context: .
dockerfile: deploy/web.Dockerfile dockerfile: deploy/web.Dockerfile
args:
VERSION: ${PLATFORM_BUILD_VERSION:-dev}
COMMIT: ${PLATFORM_BUILD_COMMIT:-unknown}
BUILD_TIME: ${PLATFORM_BUILD_TIME:-unknown}
environment: environment:
WEB_OIDC_AUTHORITY: ${WEB_OIDC_AUTHORITY:-http://localhost:58180/realms/voice-local} WEB_OIDC_AUTHORITY: ${WEB_OIDC_AUTHORITY:-http://localhost:58180/realms/voice-local}
WEB_OIDC_CLIENT_ID: ${WEB_OIDC_CLIENT_ID:-voice-platform-web} WEB_OIDC_CLIENT_ID: ${WEB_OIDC_CLIENT_ID:-voice-platform-web}
+6
View File
@@ -33,6 +33,12 @@ RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w \
CGO_ENABLED=0 go build -trimpath -o /out/mock-alert-receiver ./cmd/mock-alert-receiver CGO_ENABLED=0 go build -trimpath -o /out/mock-alert-receiver ./cmd/mock-alert-receiver
FROM gcr.io/distroless/static-debian12:nonroot FROM gcr.io/distroless/static-debian12:nonroot
ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_TIME=unknown
LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${COMMIT}" \
org.opencontainers.image.created="${BUILD_TIME}"
WORKDIR /app WORKDIR /app
COPY --from=build /out/ /app/ COPY --from=build /out/ /app/
EXPOSE 8080 8081 8082 8083 8084 EXPOSE 8080 8081 8082 8083 8084
+6
View File
@@ -7,6 +7,12 @@ COPY web ./
RUN npm run generate:api && npm run build RUN npm run generate:api && npm run build
FROM nginxinc/nginx-unprivileged:1.30.4-alpine FROM nginxinc/nginx-unprivileged:1.30.4-alpine
ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_TIME=unknown
LABEL org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${COMMIT}" \
org.opencontainers.image.created="${BUILD_TIME}"
USER root USER root
RUN apk upgrade --no-cache RUN apk upgrade --no-cache
COPY --chown=101:101 deploy/web.nginx.conf /etc/nginx/conf.d/default.conf COPY --chown=101:101 deploy/web.nginx.conf /etc/nginx/conf.d/default.conf
+2 -1
View File
@@ -246,7 +246,8 @@
| 真实终端RTC/语音供应商精简矩阵与发布门禁 | 新增`real-device-rtc-capture-v1`、`real-device-rtc-conformance-report-v1`和`cmd/rtc-conformance`。真实报告以至少3台候选终端执行6通:`s2s_pure/s2s_hybrid/cascade`各正常完成1通,再覆盖凭证续签、网络切换恢复和受控停止;每通必须证明房间/用户/任务绑定、双向媒体、固定状态序列、供应商启停、最终字幕、用量、质量通过、任务去重和资源回收。协议模拟固定为`PROTOCOL_SIMULATION/external_validation_required=true`。v3证据包新增`real_device_rtc_validation`,该门禁不可豁免且首个文件必须为合格真实报告。按低强度策略执行采集器/证据包定向测试和一条协议结构工具链冒烟:1台模拟终端1通结构结果生成`PASS/PROTOCOL_SIMULATION`并继续外部待验;证据包保留真实报告、设备/通话数量、三方式和四场景共10项缺口,临时文件已清理。 | | 真实终端RTC/语音供应商精简矩阵与发布门禁 | 新增`real-device-rtc-capture-v1`、`real-device-rtc-conformance-report-v1`和`cmd/rtc-conformance`。真实报告以至少3台候选终端执行6通:`s2s_pure/s2s_hybrid/cascade`各正常完成1通,再覆盖凭证续签、网络切换恢复和受控停止;每通必须证明房间/用户/任务绑定、双向媒体、固定状态序列、供应商启停、最终字幕、用量、质量通过、任务去重和资源回收。协议模拟固定为`PROTOCOL_SIMULATION/external_validation_required=true`。v3证据包新增`real_device_rtc_validation`,该门禁不可豁免且首个文件必须为合格真实报告。按低强度策略执行采集器/证据包定向测试和一条协议结构工具链冒烟:1台模拟终端1通结构结果生成`PASS/PROTOCOL_SIMULATION`并继续外部待验;证据包保留真实报告、设备/通话数量、三方式和四场景共10项缺口,临时文件已清理。 |
| 真实Agent生成、Embedding和内容安全质量门禁 | 新增`real-agent-models-capture-v1`、`real-agent-models-conformance-report-v1`和`cmd/agent-models-conformance`。内容生成复用现有固定10类Agent评测,并使用评测集、脱敏观测和报告重新计算防篡改;Embedding按版本化阈值覆盖精确/改写召回、跨长者隔离、撤销/敏感排除和无匹配降级六类;内容安全覆盖验证码、金融账户、提示注入、敏感医疗、正常内容和模型输出六类。真实证据还必须绑定受控提供器、账号/区域、数据条款、额度和审计引用;本地生成器、哈希向量和规则固定为`LOCAL_AGENT_TOOLCHAIN/external_validation_required=true`。v3证据包新增`real_agent_models_validation`,该门禁不可豁免。按低强度策略执行聚合器/证据包定向测试和一条重算现有模拟报告的本地工具链冒烟:既有10类模拟报告重新计算一致,两组六类结构完整,输出`PASS/LOCAL_AGENT_TOOLCHAIN`并继续外部待验;证据包保留真实报告、三提供器和12类别共16项缺口,临时文件已清理。 | | 真实Agent生成、Embedding和内容安全质量门禁 | 新增`real-agent-models-capture-v1`、`real-agent-models-conformance-report-v1`和`cmd/agent-models-conformance`。内容生成复用现有固定10类Agent评测,并使用评测集、脱敏观测和报告重新计算防篡改;Embedding按版本化阈值覆盖精确/改写召回、跨长者隔离、撤销/敏感排除和无匹配降级六类;内容安全覆盖验证码、金融账户、提示注入、敏感医疗、正常内容和模型输出六类。真实证据还必须绑定受控提供器、账号/区域、数据条款、额度和审计引用;本地生成器、哈希向量和规则固定为`LOCAL_AGENT_TOOLCHAIN/external_validation_required=true`。v3证据包新增`real_agent_models_validation`,该门禁不可豁免。按低强度策略执行聚合器/证据包定向测试和一条重算现有模拟报告的本地工具链冒烟:既有10类模拟报告重新计算一致,两组六类结构完整,输出`PASS/LOCAL_AGENT_TOOLCHAIN`并继续外部待验;证据包保留真实报告、三提供器和12类别共16项缺口,临时文件已清理。 |
| 托管内容安全外部预检与告警 | OpenAPI 0.64.0把`content_safety_tls`纳入外部依赖查询和候选验收快照。生产Worker仅执行DNS、TCP和受信TLS握手,不发送待分类正文;结果复用依赖可用性指标、数据库脱敏状态和运营诊断页面,连续5分钟不可用进入统一CRITICAL告警,记录缺失/失败/过期均可阻断候选技术快照但不驱逐Pod。按低强度策略执行App/探针/诊断定向测试、前端类型生成/类型检查/生产构建和Prometheus规则校验。 | | 托管内容安全外部预检与告警 | OpenAPI 0.64.0把`content_safety_tls`纳入外部依赖查询和候选验收快照。生产Worker仅执行DNS、TCP和受信TLS握手,不发送待分类正文;结果复用依赖可用性指标、数据库脱敏状态和运营诊断页面,连续5分钟不可用进入统一CRITICAL告警,记录缺失/失败/过期均可阻断候选技术快照但不驱逐Pod。按低强度策略执行App/探针/诊断定向测试、前端类型生成/类型检查/生产构建和Prometheus规则校验。 |
| 阶段8外部执行轻量预检 | 新增`scripts/stage8-preflight.ps1`,以单一只读入口核对候选Git提交、远程仓库、Compose本地基线、外部配置变量名称和十类证据索引结构/状态;报告明确不读取密钥值,也不把环境变量或本地服务可用性当作验收证据。默认仅报告缺口,`-Strict`可供自动化阻断未就绪交接;当前实测本地运行基线就绪、索引结构有效,但无候选提交/远程仓库、构建摘要仍为占位值且十类证据均为`PENDING`。 | | 阶段8外部执行轻量预检 | 新增`scripts/stage8-preflight.ps1`,以单一只读入口核对候选Git提交、远程仓库、Compose本地基线、外部配置变量名称和十类证据索引结构/状态;报告明确不读取密钥值,也不把环境变量或本地服务可用性当作验收证据。默认仅报告缺口,`-Strict`可供自动化阻断未就绪交接;当前已建立本地`main`候选提交,本地运行基线就绪且索引结构有效,仍缺远程仓库,样例构建摘要为占位值,十类外部证据均为`PENDING`。 |
| 候选构建身份贯通 | Compose新增统一候选构建参数,后端二进制和后端/Web镜像OCI标签共享版本、完整Git提交及UTC构建时间;远程CI从OpenAPI版本和运行编号形成候选版本,构建后重新读取两个镜像标签并与`GITHUB_SHA`和构建时间逐项比对,再把候选版本、提交、时间和双镜像摘要写入构建元数据。修复了此前Dockerfile虽支持注入但Compose/CI未传参、运行版本仍为`dev/unknown`的问题。 |
## 下一开发批次 ## 下一开发批次
+2
View File
@@ -25,6 +25,8 @@
仓库CI会上传三份SBOM和`build-metadata.json`,其中记录完整提交、运行编号和两个本次构建镜像ID。正式发布若将镜像推入制品库,应以制品库返回的不可变清单摘要为准,并保证采集中的`build_digest`与证据包候选一致。 仓库CI会上传三份SBOM和`build-metadata.json`,其中记录完整提交、运行编号和两个本次构建镜像ID。正式发布若将镜像推入制品库,应以制品库返回的不可变清单摘要为准,并保证采集中的`build_digest`与证据包候选一致。
CI从OpenAPI版本生成候选版本,并把候选版本、`GITHUB_SHA`和UTC构建时间同时写入后端二进制及后端/Web镜像的OCI `version/revision/created`标签。生成`build-metadata.json`前会重新读取并逐项比对两个镜像标签;标签为空、提交不一致或构建时间漂移时,流水线直接失败,不能产出候选供应链证据。
下载运行日志、构建元数据、SBOM和制品库摘要后,按`remote-ci-supply-chain-capture-v1`整理采集,再执行: 下载运行日志、构建元数据、SBOM和制品库摘要后,按`remote-ci-supply-chain-capture-v1`整理采集,再执行:
```powershell ```powershell