Skip to content

ci(cpp): job 超时 15→30 分钟——vcpkg 重装+新增测试逼近原预算 #2048

ci(cpp): job 超时 15→30 分钟——vcpkg 重装+新增测试逼近原预算

ci(cpp): job 超时 15→30 分钟——vcpkg 重装+新增测试逼近原预算 #2048

Workflow file for this run

name: Docker
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
workflow_dispatch:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
packages: write
jobs:
build-server:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- timeout-minutes: 3
uses: actions/checkout@v7
with:
submodules: false
- name: Set up Docker Buildx
timeout-minutes: 5
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
if: github.event_name != 'pull_request'
timeout-minutes: 3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
timeout-minutes: 3
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository_owner }}/croupier-server
- name: Build and push Docker image
timeout-minutes: 15
uses: docker/build-push-action@v7
with:
context: .
file: ./docker/Dockerfile.server
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# IP 属地数据源(可选):在仓库 secrets 配置 IP2LOCATION_BIN_URL
# (从 https://lite.ip2location.com 账号下载页复制的完整链接),
# 镜像内置 BIN 后审计日志即可展示 IP 属地;未配置则跳过下载。
build-args: |
IP2LOCATION_BIN_URL=${{ secrets.IP2LOCATION_BIN_URL }}
- name: Make GHCR package public (server)
if: github.event_name != 'pull_request'
timeout-minutes: 3
env:
GH_OWNER: ${{ github.repository_owner }}
GH_OWNER_SCOPE: ${{ github.event.repository.owner.type == 'Organization' && 'orgs' || 'users' }}
# Prefer a PAT if provided; fall back to GITHUB_TOKEN (may lack perms to change visibility)
TOKEN: ${{ secrets.GHCR_TOKEN != '' && secrets.GHCR_TOKEN || github.token }}
PKG: croupier-server
continue-on-error: true
run: |
set -euo pipefail
echo "Ensuring GHCR package visibility: ghcr.io/${GH_OWNER}/${PKG} -> public"
scope="${GH_OWNER_SCOPE}/${GH_OWNER}"
# Wait for package to exist (up to ~60s)
for i in $(seq 1 12); do
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer ${TOKEN}" -H "Accept: application/vnd.github+json" "https://api.github.com/${scope}/packages/container/${PKG}" || true)
echo "Probe ${scope}/packages/container/${PKG} -> $code"
[ "$code" = "200" ] && break
sleep 5
done
# Attempt to set visibility
code=$(curl -s -o /dev/null -w "%{http_code}" -L -X PUT \
-H "Authorization: Bearer ${TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/${scope}/packages/container/${PKG}/visibility" \
-d '{"visibility":"public"}' || true)
if [ "$code" = "204" ] || [ "$code" = "200" ]; then
echo "Package ${PKG} set to public via ${scope}"
else
echo "Skipping GHCR visibility update for ${PKG} (HTTP $code)"
fi
build-agent:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- timeout-minutes: 3
uses: actions/checkout@v7
with:
submodules: false
- name: Set up Docker Buildx
timeout-minutes: 5
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
if: github.event_name != 'pull_request'
timeout-minutes: 3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
timeout-minutes: 3
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository_owner }}/croupier-agent
- name: Build and push Docker image
timeout-minutes: 15
uses: docker/build-push-action@v7
with:
context: .
file: ./docker/Dockerfile.agent
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Make GHCR package public (agent)
if: github.event_name != 'pull_request'
timeout-minutes: 3
env:
GH_OWNER: ${{ github.repository_owner }}
GH_OWNER_SCOPE: ${{ github.event.repository.owner.type == 'Organization' && 'orgs' || 'users' }}
TOKEN: ${{ secrets.GHCR_TOKEN != '' && secrets.GHCR_TOKEN || github.token }}
PKG: croupier-agent
continue-on-error: true
run: |
set -euo pipefail
echo "Ensuring GHCR package visibility: ghcr.io/${GH_OWNER}/${PKG} -> public"
scope="${GH_OWNER_SCOPE}/${GH_OWNER}"
for i in $(seq 1 12); do
code=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer ${TOKEN}" -H "Accept: application/vnd.github+json" "https://api.github.com/${scope}/packages/container/${PKG}" || true)
echo "Probe ${scope}/packages/container/${PKG} -> $code"
[ "$code" = "200" ] && break
sleep 5
done
code=$(curl -s -o /dev/null -w "%{http_code}" -L -X PUT \
-H "Authorization: Bearer ${TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/${scope}/packages/container/${PKG}/visibility" \
-d '{"visibility":"public"}' || true)
if [ "$code" = "204" ] || [ "$code" = "200" ]; then
echo "Package ${PKG} set to public via ${scope}"
else
echo "Skipping GHCR visibility update for ${PKG} (HTTP $code)"
fi
build-ingest:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- timeout-minutes: 3
uses: actions/checkout@v7
with:
submodules: false
- name: Set up Docker Buildx
timeout-minutes: 5
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
if: github.event_name != 'pull_request'
timeout-minutes: 3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
timeout-minutes: 3
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository_owner }}/croupier-ingest
- name: Build and push Docker image
timeout-minutes: 15
uses: docker/build-push-action@v7
with:
context: .
file: ./docker/Dockerfile.ingest
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=ingest
cache-to: type=gha,scope=ingest,mode=max
build-analytics-worker:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- timeout-minutes: 3
uses: actions/checkout@v7
with:
submodules: false
- name: Set up Docker Buildx
timeout-minutes: 5
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
if: github.event_name != 'pull_request'
timeout-minutes: 3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
timeout-minutes: 3
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository_owner }}/croupier-analytics-worker
- name: Build and push Docker image
timeout-minutes: 15
uses: docker/build-push-action@v7
with:
context: .
file: ./docker/Dockerfile.analytics-worker
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=analytics-worker
cache-to: type=gha,scope=analytics-worker,mode=max
# 供应链安全:镜像漏洞扫描(trivy)+ SBOM 归档 + cosign keyless 签名。
# 仅在镜像实际推送后执行(PR 构建不 push)。
supply-chain:
runs-on: ubuntu-latest
timeout-minutes: 20
needs: [build-server, build-agent, build-ingest, build-analytics-worker]
if: github.event_name != 'pull_request'
strategy:
matrix:
image:
[
croupier-server,
croupier-agent,
croupier-ingest,
croupier-analytics-worker,
]
permissions:
contents: read
# cosign 签名是向包仓库写签名层( attest/blobs upload),需要 write。
packages: write
# cosign keyless 签名需要 id-token。
id-token: write
# 扫描结果上传 SARIF。
security-events: write
env:
IMAGE: ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}
steps:
- name: Login to GHCR
timeout-minutes: 3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Resolve pushed tag
id: tag
timeout-minutes: 2
run: |
set -euo pipefail
# 与 metadata-action 的 tag 策略对齐:tag 触发 → 版本 tag;
# 分支推送(main)→ 分支名 tag(metadata-action 默认仅生成分支 tag)。
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
echo "tag=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
elif [[ "$GITHUB_REF" == refs/heads/* ]]; then
echo "tag=${GITHUB_REF#refs/heads/}" >> "$GITHUB_OUTPUT"
else
echo "tag=main" >> "$GITHUB_OUTPUT"
fi
- name: Trivy vulnerability scan
timeout-minutes: 10
uses: aquasecurity/trivy-action@0.35.0
with:
image-ref: ${{ env.IMAGE }}:${{ steps.tag.outputs.tag }}
format: sarif
output: trivy-${{ matrix.image }}.sarif
severity: HIGH,CRITICAL
exit-code: "0" # 发现不阻断(先观察基线);收紧为 1 可做门禁
ignore-unfixed: true
- name: Upload Trivy results to GitHub Security
timeout-minutes: 3
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: trivy-${{ matrix.image }}.sarif
category: trivy-${{ matrix.image }}
- name: Generate SBOM (SPDX)
timeout-minutes: 10
uses: aquasecurity/trivy-action@0.35.0
with:
image-ref: ${{ env.IMAGE }}:${{ steps.tag.outputs.tag }}
format: spdx-json
output: sbom-${{ matrix.image }}.spdx.json
- name: Upload SBOM artifact
timeout-minutes: 3
uses: actions/upload-artifact@v4
with:
name: sbom-${{ matrix.image }}-${{ steps.tag.outputs.tag }}
path: sbom-${{ matrix.image }}.spdx.json
retention-days: 90
- name: Sign image with cosign (keyless OIDC)
timeout-minutes: 5
uses: sigstore/cosign-installer@v4.1.2
- name: cosign sign
timeout-minutes: 5
run: |
set -euo pipefail
# 凭据沿用本 job 第一步的 docker login(GITHUB_TOKEN + job 声明的
# packages:write)。禁止再用 PAT 二次 login 覆盖——历史 GHCR_TOKEN
# secret 无效时会把好凭据换坏(403)。keyless 身份来自 id-token。
DIGEST="$(docker buildx imagetools inspect "${IMAGE}:${{ steps.tag.outputs.tag }}" --format '{{.Manifest.Digest}}')"
if [ -z "${DIGEST}" ]; then
echo "::error::empty digest for ${IMAGE}:${{ steps.tag.outputs.tag }}"
exit 1
fi
echo "Signing ${IMAGE}@${DIGEST}"
cosign sign --yes "${IMAGE}@${DIGEST}"