From f1960aafb727e135b96cbfd48d400a4ca89c998e Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 11:11:51 +0800 Subject: [PATCH 1/7] chore(tdx): drop setup-vendor-config, document PCCS_URL env var The pure-Rust `builtin-as-tdx-rust` verifier fetches TDX/SGX collateral directly over HTTPS and reads the PCCS endpoint from the `PCCS_URL` environment variable (default: Alibaba Cloud PCCS); it does not touch `/etc/sgx_default_qcnl.conf`. The `setup-vendor-config` tool only edited that conf file for the legacy FFI QPL, so it is dead weight for the default Rust backend. - Delete `scripts/setup-vendor-config` and `docs/setup-vendor-config.md`. - Drop the COPY/chmod of the tool from `Dockerfile` (keep `jq` install). - Remove the `setup-vendor-config` CI job from `shell-scripts.yml` (shellcheck on `scripts/` is retained). - Rewrite the Builtin AS note in `docs/configuration.md` and its Chinese counterpart to document `PCCS_URL` control (default, URL forms, Alibaba Cloud public/VPC endpoints) instead of pointing at the conf file. --- .github/workflows/shell-scripts.yml | 67 ------- Dockerfile | 5 - docs/configuration.md | 7 +- docs/configuration_zh.md | 7 +- docs/setup-vendor-config.md | 105 ---------- scripts/setup-vendor-config | 294 ---------------------------- 6 files changed, 10 insertions(+), 475 deletions(-) delete mode 100644 docs/setup-vendor-config.md delete mode 100755 scripts/setup-vendor-config diff --git a/.github/workflows/shell-scripts.yml b/.github/workflows/shell-scripts.yml index a905a11e..fc0ea589 100644 --- a/.github/workflows/shell-scripts.yml +++ b/.github/workflows/shell-scripts.yml @@ -30,70 +30,3 @@ jobs: echo "=== Checking $f ===" shellcheck "$f" done - - setup-vendor-config: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Run setup-vendor-config tests - run: | - set -e - SCRIPT="scripts/setup-vendor-config" - chmod +x "$SCRIPT" - - echo "=== Test: --help exits 0 ===" - "$SCRIPT" --help > /dev/null - - echo "=== Test: --list shows aliyun ===" - "$SCRIPT" --list | grep -q "aliyun" - - echo "=== Test: aliyun --dry-run exits 0 ===" - "$SCRIPT" aliyun --dry-run > /dev/null - - echo "=== Test: aliyun --region cn-beijing --dry-run ===" - output=$("$SCRIPT" aliyun --region cn-beijing --dry-run) - echo "$output" | grep -q "cn-beijing" - echo "$output" | grep -q "cn-beijing.aliyuncs.com" - - echo "=== Test: unknown vendor fails ===" - ! "$SCRIPT" unknown 2>/dev/null - - echo "=== Test: no args fails ===" - ! "$SCRIPT" 2>/dev/null - - echo "=== Test: unknown option fails ===" - ! "$SCRIPT" --foobar 2>/dev/null - - echo "=== Test: --region without value fails ===" - ! "$SCRIPT" aliyun --region 2>/dev/null - - echo "=== Test: --internal without --region fails ===" - ! "$SCRIPT" aliyun --internal 2>/dev/null - - echo "=== Test: --internal with --region uses VPC endpoint ===" - output=$("$SCRIPT" aliyun --internal --region cn-hangzhou --dry-run) - echo "$output" | grep -q "sgx-dcap-server-vpc.cn-hangzhou.aliyuncs.com" - echo "$output" | grep -q "internal (VPC)" - - echo "=== Test: public endpoint (default) ===" - output=$("$SCRIPT" aliyun --region cn-beijing --dry-run) - echo "$output" | grep -q "sgx-dcap-server.cn-beijing.aliyuncs.com" - echo "$output" | grep -q "Endpoint: public" - - echo "=== Test: apply and verify config ===" - # Create a temp config file for testing - tmp_conf=$(mktemp) - cat > "$tmp_conf" <<'EOF' - # PCCS server address - PCCS_URL=https://localhost:8081/sgx/certification/v4/ - USE_SECURE_CERT=TRUE - EOF - - # Use sed with a modified CONFIG_FILE via env override approach - # Since the script hardcodes CONFIG_FILE, we test via dry-run output instead - output=$("$SCRIPT" aliyun --region cn-hangzhou --dry-run) - echo "$output" | grep -q "cn-hangzhou.aliyuncs.com" - - echo "All tests passed!" diff --git a/Dockerfile b/Dockerfile index e2c364a9..b3231f90 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,11 +43,6 @@ COPY --from=builder /usr/local/cargo/bin/tng /usr/local/bin/tng RUN mkdir -p /usr/lib/tng/ COPY --from=builder /code/target/release/libtng_hook.so /usr/lib/tng/libtng_hook.so -# Install vendor config setup tool -COPY scripts/setup-vendor-config /usr/local/bin/setup-vendor-config -RUN chmod +x /usr/local/bin/setup-vendor-config - -# install jq for custome shell script RUN yum install -y jq CMD ["tng"] diff --git a/docs/configuration.md b/docs/configuration.md index 05861ac3..fd1751f1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1246,9 +1246,12 @@ The **Verifier** receives and verifies Evidence from the Attester, only recogniz When `as_type` = `"builtin"`, TNG uses the built-in AS to verify Evidence locally without connecting to an external AS. This is suitable for network-isolated, latency-sensitive, or simplified deployment scenarios. > [!NOTE] -> Builtin mode requires compiling with the corresponding TEE feature enabled (`builtin-as-tdx`, `builtin-as-sgx`, or `builtin-as-snp`). GitHub CI-built RPM packages and binary artifacts do not support this mode; only container images support it. +> To verify TDX Evidence, TNG fetches TDX/SGX collateral directly over HTTPS from a PCCS (Provisioning Certificate Caching Service). Set the `PCCS_URL` environment variable to your cloud provider's PCCS; if unset, it defaults to the Alibaba Cloud PCCS (`https://sgx-dcap-server.cn-beijing.aliyuncs.com`). Both bare-host (`https://sgx-dcap-server.cn-hangzhou.aliyuncs.com`) and path-suffixed (`https://sgx-dcap-server.cn-hangzhou.aliyuncs.com/sgx/certification/v4/`) forms are accepted — the backend normalizes the path. Common Alibaba Cloud endpoints: > -> For SGX/TDX builtin AS mode, you also need to configure the PCCS URL in `/etc/sgx_default_qcnl.conf` for your cloud provider. See the [Vendor Configuration Setup](setup-vendor-config.md) guide for details. +> | Endpoint | `PCCS_URL` | +> |---|---| +> | Public (region-specific) | `https://sgx-dcap-server..aliyuncs.com` | +> | VPC internal | `https://sgx-dcap-server-vpc..aliyuncs.com` | **PolicyConfig (OPA Policy):** diff --git a/docs/configuration_zh.md b/docs/configuration_zh.md index 83974aa4..f0adddf7 100644 --- a/docs/configuration_zh.md +++ b/docs/configuration_zh.md @@ -1256,9 +1256,12 @@ Passport 模式适用于网络隔离或性能要求较高的场景,因为它 `as_type` = `"builtin"` 时,TNG 使用内置 AS 在本地直接验证 Evidence,无需连接外部 AS。适用于网络隔离、延迟敏感或简化部署的场景。 > [!NOTE] -> Builtin 模式需在编译时启用对应 TEE 特性(`builtin-as-tdx`、`builtin-as-sgx` 或 `builtin-as-snp`)。GitHub CI 构建的 RPM 包和二进制产物不支持此模式,仅容器镜像支持。 +> 当验证TDX Evidence时,TNG会通过 HTTPS 直接从 PCCS(Provisioning Certificate Caching Service)拉取 TDX/SGX collateral。将 `PCCS_URL` 环境变量设为你的云服务商 PCCS;未设置时默认为阿里云 PCCS(`https://sgx-dcap-server.cn-beijing.aliyuncs.com`)。纯主机形式(`https://sgx-dcap-server.cn-hangzhou.aliyuncs.com`)和带路径后缀形式(`https://sgx-dcap-server.cn-hangzhou.aliyuncs.com/sgx/certification/v4/`)都接受——后端会规范化路径。阿里云常用端点: > -> 对于 SGX/TDX 内置 AS 模式,还需为云服务商配置 `/etc/sgx_default_qcnl.conf` 中的 PCCS URL。详见 [Vendor Configuration Setup](setup-vendor-config.md)。 +> | 端点类型 | `PCCS_URL` | +> |---|---| +> | 公网(按地域) | `https://sgx-dcap-server..aliyuncs.com` | +> | VPC 内网 | `https://sgx-dcap-server-vpc..aliyuncs.com` | **PolicyConfig(OPA 策略):** diff --git a/docs/setup-vendor-config.md b/docs/setup-vendor-config.md deleted file mode 100644 index 5b3f3666..00000000 --- a/docs/setup-vendor-config.md +++ /dev/null @@ -1,105 +0,0 @@ -# Vendor Configuration Setup - -This document describes how to configure cloud-provider-specific PCCS (Provisioning Certificate Caching Service) settings when using TNG's **builtin AS** mode. - -## Background - -When using builtin AS mode with **SGX or TDX** enclaves, the local quote verification process needs to fetch and verify provisioning certificates from a PCCS. The PCCS URL is configured in `/etc/sgx_default_qcnl.conf`. - -If the PCCS URL is not set correctly for your cloud provider, quote verification will fail with: - -``` -tee_verify_quote failed: 0xe019 -``` - -## The `setup-vendor-config` Tool - -TNG ships with a `setup-vendor-config` tool to automatically configure `/etc/sgx_default_qcnl.conf` for supported cloud providers. - -### Usage - -``` -setup-vendor-config [options] -``` - -| Option | Description | -|---|---| -| `` | Cloud provider name (required) | -| `--region REGION` | Cloud region ID (optional for some vendors) | -| `--internal` | Use VPC internal endpoint (requires `--region`) | -| `--dry-run` | Show what would be changed without applying | -| `--no-backup` | Skip creating a backup of the existing config | -| `--list` | List all supported vendors with details | -| `--help` | Show help message | - -### Supported Vendors - -| Vendor | Description | Default Region | -|---|---|---| -| `aliyun` | Alibaba Cloud SGX DCAP PCCS | `cn-hangzhou` | - -### Examples - -```sh -# Configure for Alibaba Cloud (uses default region cn-hangzhou) -setup-vendor-config aliyun - -# Configure for a specific region -setup-vendor-config aliyun --region cn-beijing - -# Use VPC internal endpoint (requires explicit --region) -setup-vendor-config aliyun --internal --region cn-hangzhou - -# Preview changes without applying -setup-vendor-config aliyun --region cn-shanghai --dry-run - -# List all supported vendors -setup-vendor-config --list -``` - -### Docker Usage - -Run the tool inside the container before `tng launch`: - -```sh -docker run -it --rm --privileged --network host --cgroupns=host \ - ghcr.io/inclavare-containers/tng:latest \ - sh -c 'setup-vendor-config aliyun && tng launch --config-content="..."' -``` - -> [!TIP] -> The `--region` flag is optional for Alibaba Cloud — `cn-hangzhou` works for all TDX instances. Use `--region` only if you need a different endpoint. - -### VPC Internal Endpoint - -> [!IMPORTANT] -> When `--internal` is specified, `--region` **must** be provided explicitly — the default region (`cn-hangzhou`) will not be used. - -The `--internal` flag switches the PCCS URL to the VPC internal endpoint (`sgx-dcap-server-vpc..aliyuncs.com`), which uses Alibaba Cloud's internal network instead of the public internet. This provides lower latency and avoids public bandwidth charges when running inside a VPC. - -```sh -# VPC internal endpoint for cn-hangzhou -setup-vendor-config aliyun --internal --region cn-hangzhou -``` - -## Manual Configuration - -If your provider is not yet supported by the tool, manually edit `/etc/sgx_default_qcnl.conf`: - -```sh -sudo sed -i.$(date "+%m%d%y") 's|PCCS_URL=.*|PCCS_URL=https://sgx-dcap-server../sgx/certification/v4/|' /etc/sgx_default_qcnl.conf -``` - -Replace `` and `` with your cloud provider's PCCS endpoint. Consult your provider's confidential computing documentation for the correct URL. - -## Adding a New Vendor - -To add support for a new vendor, edit `scripts/setup-vendor-config` and add three variables following the existing pattern: - -```bash -VENDOR_PCCS_URL_="https:///__REGION__/" -VENDOR_REQUIRES_REGION_="false" # or "true" if region is mandatory -VENDOR_DEFAULT_REGION_="" -``` - -Then add the vendor name to the `SUPPORTED_VENDORS` list. diff --git a/scripts/setup-vendor-config b/scripts/setup-vendor-config deleted file mode 100755 index aaec994a..00000000 --- a/scripts/setup-vendor-config +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env bash -# -# setup-vendor-config — Configure vendor-specific PCCS settings for TNG builtin AS mode. -# -# When using TNG's builtin attestation service (e.g., the Docker image built with -# the builtin-as-tdx-ffi feature), local quote verification requires a correctly -# configured PCCS (Provisioning Certificate Caching Service). If the PCCS_URL in -# /etc/sgx_default_qcnl.conf does not point to your cloud provider's service, -# quote verification will fail with: -# -# tee_verify_quote failed: 0xe019 -# -# This tool updates the configuration for supported vendors automatically. -# -# Usage: -# setup-vendor-config [options] -# -# Examples: -# setup-vendor-config aliyun -# setup-vendor-config aliyun --region cn-beijing -# setup-vendor-config aliyun --dry-run -# setup-vendor-config --list - -set -euo pipefail - -CONFIG_FILE="/etc/sgx_default_qcnl.conf" -# shellcheck disable=SC2034 -DEFAULT_QCNL_CONTENT='# PCCS server address -PCCS_URL=https://localhost:8081/sgx/certification/v4/ -USE_SECURE_CERT=TRUE -RETRY_TIMES=6 -RETRY_DELAY=10 -PCK_CACHE_EXPIRE_HOURS=168 -VERIFY_COLLATERAL_CACHE_EXPIRE_HOURS=168' - -# ============================================================================== -# Vendor definitions -# ============================================================================== -# Add a new vendor by defining: -# VENDOR_PCCS_URL_ — the PCCS URL template (use __REGION__ placeholder) -# VENDOR_REQUIRES_REGION_ — set to "true" if region is mandatory -# VENDOR_DEFAULT_REGION_ — default region if --region not specified - -# These variables are accessed via indirect expansion (${!var}) in main(). -# shellcheck disable=SC2034 -VENDOR_PCCS_URL_aliyun="https://sgx-dcap-server.__REGION__.aliyuncs.com/sgx/certification/v4/" -# shellcheck disable=SC2034 -VENDOR_PCCS_URL_INTERNAL_aliyun="https://sgx-dcap-server-vpc.__REGION__.aliyuncs.com/sgx/certification/v4/" -# shellcheck disable=SC2034 -VENDOR_REQUIRES_REGION_aliyun="false" -# shellcheck disable=SC2034 -VENDOR_DEFAULT_REGION_aliyun="cn-hangzhou" - -# ============================================================================== -# Supported vendors list (kebab-case names) -# ============================================================================== -SUPPORTED_VENDORS="aliyun" - -# ============================================================================== -# Usage / Help -# ============================================================================== -usage() { - cat <<'EOF' -Usage: setup-vendor-config [options] - -Setup vendor-specific PCCS configuration for TNG builtin AS mode. - -Arguments: - Cloud provider name to configure - -Options: - --region REGION Cloud region ID (optional for some vendors, see --list) - --internal Use VPC internal endpoint (requires --region) - --dry-run Show what would be changed without applying - --no-backup Skip creating a backup of the existing config - --list List all supported vendors with details - --help Show this help message - -Supported Vendors: - aliyun Alibaba Cloud SGX DCAP PCCS - Default region: cn-hangzhou (covers all TDX instances) - -Examples: - setup-vendor-config aliyun - setup-vendor-config aliyun --region cn-beijing - setup-vendor-config aliyun --internal --region cn-hangzhou - setup-vendor-config aliyun --region cn-shanghai --dry-run - setup-vendor-config --list - -For more information, see docs/configuration.md. -EOF -} - -list_vendors() { - echo "Supported vendors:" - echo "" - for vendor in $SUPPORTED_VENDORS; do - local url_var="VENDOR_PCCS_URL_${vendor}" - local requires_var="VENDOR_REQUIRES_REGION_${vendor}" - local default_var="VENDOR_DEFAULT_REGION_${vendor}" - local url="${!url_var}" - local requires="${!requires_var}" - local default_region="${!default_var}" - - echo " ${vendor}" - if [[ "$requires" == "true" ]]; then - echo " PCCS URL template: ${url}" - echo " Region: required (use --region)" - else - echo " PCCS URL template: ${url}" - echo " Default region: ${default_region}" - fi - echo "" - done -} - -# ============================================================================== -# Core logic -# ============================================================================== -main() { - local vendor="" - local region="" - local dry_run=false - local do_backup=true - local use_internal=false - - # Parse arguments - while [[ $# -gt 0 ]]; do - case "$1" in - --help|-h) - usage - exit 0 - ;; - --list) - list_vendors - exit 0 - ;; - --dry-run) - dry_run=true - shift - ;; - --no-backup) - do_backup=false - shift - ;; - --internal) - use_internal=true - shift - ;; - --region) - if [[ -z "${2:-}" ]]; then - echo "Error: --region requires a value" >&2 - exit 1 - fi - region="$2" - shift 2 - ;; - -*) - echo "Error: unknown option: $1" >&2 - usage >&2 - exit 1 - ;; - *) - if [[ -n "$vendor" ]]; then - echo "Error: unexpected argument: $1" >&2 - usage >&2 - exit 1 - fi - vendor="$1" - shift - ;; - esac - done - - if [[ -z "$vendor" ]]; then - echo "Error: vendor name is required" >&2 - usage >&2 - exit 1 - fi - - # Validate vendor - local supported=false - for v in $SUPPORTED_VENDORS; do - if [[ "$v" == "$vendor" ]]; then - supported=true - break - fi - done - if [[ "$supported" != "true" ]]; then - echo "Error: unsupported vendor '${vendor}'" >&2 - echo "Run '$0 --list' to see supported vendors." >&2 - exit 1 - fi - - # Resolve region - local requires_var="VENDOR_REQUIRES_REGION_${vendor}" - local default_var="VENDOR_DEFAULT_REGION_${vendor}" - local url_var="VENDOR_PCCS_URL_${vendor}" - local url_var_internal="VENDOR_PCCS_URL_INTERNAL_${vendor}" - local requires_region="${!requires_var}" - local default_region="${!default_var}" - local url_template="${!url_var}" - local url_template_internal="${!url_var_internal:-}" - - # --internal requires explicit region (no default fallback) - if [[ "$use_internal" == "true" && -z "$region" ]]; then - echo "Error: --internal requires --region to be specified explicitly" >&2 - exit 1 - fi - - if [[ -z "$region" ]]; then - if [[ "$requires_region" == "true" ]]; then - echo "Error: --region is required for vendor '${vendor}'" >&2 - exit 1 - fi - region="$default_region" - fi - - # Select the URL template (internal VPC or public) - if [[ "$use_internal" == "true" ]]; then - if [[ -z "$url_template_internal" ]]; then - echo "Error: vendor '${vendor}' does not support --internal" >&2 - exit 1 - fi - url_template="$url_template_internal" - fi - - # Build the final URL - local pccs_url="${url_template//__REGION__/$region}" - - # Show configuration - echo "Vendor: ${vendor}" - echo "Region: ${region}" - if [[ "$use_internal" == "true" ]]; then - echo "Endpoint: internal (VPC)" - else - echo "Endpoint: public" - fi - echo "PCCS URL: ${pccs_url}" - echo "Config file: ${CONFIG_FILE}" - echo "" - - # Dry run - if [[ "$dry_run" == "true" ]]; then - echo "[DRY RUN] The following changes would be made:" - echo "" - if [[ -f "$CONFIG_FILE" ]]; then - local current_url - current_url=$(grep '^PCCS_URL=' "$CONFIG_FILE" | head -1 | cut -d= -f2-) - echo " Current PCCS_URL: ${current_url}" - echo " New PCCS_URL: ${pccs_url}" - echo "" - echo "Backup: ${CONFIG_FILE}.$(date +%m%d%y) (would be created)" - else - echo " Config file does not exist — would be created with default content." - echo " Then PCCS_URL would be set to: ${pccs_url}" - fi - exit 0 - fi - - # Apply configuration - if [[ -f "$CONFIG_FILE" ]]; then - # Backup - if [[ "$do_backup" == "true" ]]; then - local backup_path - backup_path="${CONFIG_FILE}.$(date +%m%d%y)" - cp "$CONFIG_FILE" "$backup_path" - echo "Backup created: ${backup_path}" - fi - - # Update PCCS_URL - sed -i "s|^PCCS_URL=.*|PCCS_URL=${pccs_url}|" "$CONFIG_FILE" - echo "Updated PCCS_URL in ${CONFIG_FILE}" - else - echo "Config file not found — creating with vendor settings." - mkdir -p "$(dirname "$CONFIG_FILE")" - cat > "$CONFIG_FILE" < Date: Tue, 14 Jul 2026 14:09:35 +0800 Subject: [PATCH 2/7] fix(ci): install perl-IPC-Cmd for vendored OpenSSL build The builtin-as-tdx-rust (dcap-qvl) backend pulls in vendored openssl-sys, which builds OpenSSL from source; OpenSSL's Configure requires the IPC::Cmd Perl module that is missing from the minimal an8/alinux CI containers, causing `perl ./Configure` to abort with "Can't locate IPC/Cmd.pm" and failing the build / go-sdk-tests jobs. Install perl-IPC-Cmd (the standalone package providing IPC::Cmd on an8/al8; FindBin/File::Compare/File::Copy already ship with the base perl-interpreter) in: - go-sdk.yml (alinux3 container) - the RPM buildspec prepare phase (AnolisOS8) - the spec BuildRequires (covers test.yml's yum-builddep path) --- .github/workflows/go-sdk.yml | 9 ++++++++- .../trusted-network-gateway.an8.buildspec.yaml.template | 6 ++++++ trusted-network-gateway.spec | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go-sdk.yml b/.github/workflows/go-sdk.yml index 69897e45..0650cf87 100644 --- a/.github/workflows/go-sdk.yml +++ b/.github/workflows/go-sdk.yml @@ -39,7 +39,14 @@ jobs: set -x sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo sed -i -E 's|https?://mirrors.cloud.aliyuncs.com/|https://mirrors.aliyun.com/|g' /etc/yum.repos.d/*.repo - yum install -y git make tar clang protobuf-devel jq iptables + # openssl-sys builds OpenSSL from source (vendored) because the + # builtin-as-tdx-rust (dcap-qvl) backend pulls it in; OpenSSL's + # `Configure` requires the IPC::Cmd Perl module, which on alinux + # (an8-based) lives in its own `perl-IPC-Cmd` package (FindBin / + # File::Compare / File::Copy ship with the base perl-interpreter + # already present). Without this, `perl ./Configure` aborts with + # "Can't locate IPC/Cmd.pm". + yum install -y git make tar clang protobuf-devel jq iptables perl-IPC-Cmd - uses: dtolnay/rust-toolchain@1.89.0 diff --git a/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template b/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template index b5e35818..20cb5d1c 100644 --- a/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template +++ b/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template @@ -69,6 +69,12 @@ phases: - rustup default 1.91.1 # Change yum source from Anolis to Alinux - sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo + # openssl-sys builds OpenSSL from source (vendored); OpenSSL's `Configure` + # requires the IPC::Cmd Perl module, which on an8 lives in its own + # `perl-IPC-Cmd` package (FindBin/File::Compare/File::Copy ship with the + # base perl-interpreter already present). Without it, `perl ./Configure` + # aborts with "Can't locate IPC/Cmd.pm" and the rpmbuild %build fails. + - yum install -y perl-IPC-Cmd build: commands: - rpmbuild --define "_topdir /tmp/rpmbuild" -ba /tmp/rpmbuild/SPECS/trusted-network-gateway.spec --define 'with_rustup 1' diff --git a/trusted-network-gateway.spec b/trusted-network-gateway.spec index a6424282..bd34a562 100644 --- a/trusted-network-gateway.spec +++ b/trusted-network-gateway.spec @@ -31,6 +31,9 @@ BuildRequires: binutils-devel BuildRequires: protobuf-devel BuildRequires: clang BuildRequires: jq +# openssl-sys compiles OpenSSL from source (vendored); OpenSSL's `Configure` +# needs the IPC::Cmd Perl module, which on an8/al8 ships in perl-IPC-Cmd. +BuildRequires: perl(IPC::Cmd) %{!?with_rustup:%global use_system_rust 1} %if 0%{?use_system_rust} From d8a22de4b46aa97208b2525696aa6b0f0d265574 Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 14:24:00 +0800 Subject: [PATCH 3/7] fix(ci): align go-sdk.yml triggers with other workflows, drop paths filter go-sdk.yml was the only workflow with a `paths:` filter, gating the Go SDK tests on tng-go/**, tng/**, Cargo.toml, Cargo.lock, and the workflow file itself. That let regressions ship undetected: the Go SDK tests also run `cargo test --package tng-testsuite --features go-sdk`, so they transitively depend on tng-testsuite/, rats-cert/, and the tng binary, none of which were in the paths list. Align the `on:` block with the repo-wide convention (every other workflow triggers on push to master + tags v*.*.* and pull_request to master, no paths): remove the paths filter, drop the legacy sdk-go branch trigger (deleted on the remote), and add tags. Also add a CLAUDE.md section reminding contributors not to add `paths:` filters (or per-feature legacy branch triggers) to new workflows, with the rationale and the canonical `on:` block. --- .github/workflows/go-sdk.yml | 16 ++-------------- CLAUDE.md | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/go-sdk.yml b/.github/workflows/go-sdk.yml index 0650cf87..ed3b6f03 100644 --- a/.github/workflows/go-sdk.yml +++ b/.github/workflows/go-sdk.yml @@ -4,23 +4,11 @@ on: push: branches: - "master" - - "sdk-go" - paths: - - "tng-go/**" - - "tng/**" - - "Cargo.toml" - - "Cargo.lock" - - ".github/workflows/go-sdk.yml" + tags: + - "v*.*.*" pull_request: branches: - "master" - - "sdk-go" - paths: - - "tng-go/**" - - "tng/**" - - "Cargo.toml" - - "Cargo.lock" - - ".github/workflows/go-sdk.yml" jobs: go-sdk-tests: diff --git a/CLAUDE.md b/CLAUDE.md index 41c947c0..f427ff91 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -139,6 +139,27 @@ git filter-branch -f --msg-filter 'sed "/Co-Authored-By:/d"' --env-filter ' ``` +## GitHub Actions Workflow Triggers + +When creating or editing `.github/workflows/*.yml`, follow the repo-wide trigger convention: every workflow triggers on `push` to `master` (and tags `v*.*.*`) and on `pull_request` targeting `master` — **without** a `paths:` filter. + +**Never add a `paths:` filter** to gate a workflow on a subset of changed files. A `paths` filter silently skips the job when a change lands outside the listed globs — and because tests transitively depend on files outside their own directory (e.g. the Go SDK tests run `cargo test --package tng-testsuite --features go-sdk`, so they also depend on `tng-testsuite/`, `rats-cert/`, the `tng` binary, etc.), a `paths` filter limited to `tng-go/**` lets a real regression ship undetected. Triggering on every push/PR to `master` costs more CI minutes but closes that gap — the tradeoff is intentional. + +Do not add per-feature legacy branch triggers (e.g. `sdk-go`) either; `master` is the only branch these workflows target. The canonical `on:` block is: + +```yaml +on: + push: + branches: + - "master" + tags: + - "v*.*.*" + pull_request: + branches: + - "master" +``` + + ## API Compatibility When designing public APIs (REST endpoints, config fields, trait methods, public structs/traits), always design the full namespace structure upfront — do not defer naming decisions. Retrofitting a namespace layer later (e.g. inserting `/ohttp/` into an existing path like `/status/egress//keys` → `/status/egress//ohttp/keys`) breaks backward compatibility and is extremely costly. If a category of resources might grow multiple sub-resources in the future, include that category's namespace from day one. From d701f35f606347d0be9be3991104e52028054d35 Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 15:38:38 +0800 Subject: [PATCH 4/7] fix(rpm): install perl(Time::Piece) for vendored OpenSSL 3.5.x build openssl-sys compiles OpenSSL from source (vendored). OpenSSL 3.5.x's Configure/Makefile.in generation needs the Time::Piece Perl module in addition to IPC::Cmd; without it the build fails with 'Can't locate Time/Piece.pm in @INC'. Declare perl(Time::Piece) as a BuildRequires so yum-builddep installs perl-Time-Piece (an8/al8). --- trusted-network-gateway.spec | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/trusted-network-gateway.spec b/trusted-network-gateway.spec index bd34a562..b603b9ef 100644 --- a/trusted-network-gateway.spec +++ b/trusted-network-gateway.spec @@ -31,9 +31,11 @@ BuildRequires: binutils-devel BuildRequires: protobuf-devel BuildRequires: clang BuildRequires: jq -# openssl-sys compiles OpenSSL from source (vendored); OpenSSL's `Configure` -# needs the IPC::Cmd Perl module, which on an8/al8 ships in perl-IPC-Cmd. +# openssl-sys compiles OpenSSL from source (vendored); OpenSSL 3.5.x's build +# scripts need the IPC::Cmd and Time::Piece Perl modules, which on an8/al8 +# ship in perl-IPC-Cmd and perl-Time-Piece respectively. BuildRequires: perl(IPC::Cmd) +BuildRequires: perl(Time::Piece) %{!?with_rustup:%global use_system_rust 1} %if 0%{?use_system_rust} From 8ec583391260b222a0212a8f765426bb59d2d229 Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 15:38:39 +0800 Subject: [PATCH 5/7] fix(rpm): vendor trustee protos/ for attestation-service build.rs cargo vendor packages the trustee git dependency (attestation-service) as just its crate dir (vendor/attestation-service-0.1.0/). Its build.rs compiles ../protos/reference.proto, but protos/ lives outside the package in the trustee repo, so cargo vendor omits it and the offline vendored build fails with 'protoc failed: ../protos/reference.proto: No such file or directory'. Non-vendored builds work because the full git checkout keeps protos/ as a sibling. Extract protos/ at the exact rev pinned in Cargo.lock from cargo's trustee git db into vendor/protos/ during create-tarball, so ../protos/ resolves from the vendored crate dir. Fails loudly if the rev/protos cannot be located. --- Makefile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Makefile b/Makefile index 0dda9f86..b0276017 100644 --- a/Makefile +++ b/Makefile @@ -193,6 +193,27 @@ create-tarball: # copy untracked (new) files that are not ignored if [ -n "$$(git ls-files --others --exclude-standard)" ] ; then git ls-files --others --exclude-standard -z | xargs -0 tar -c -f - | tar -x -f - -C /tmp/trusted-network-gateway-tarball/trusted-network-gateway-${VERSION}/src/ ; fi + # attestation-service is a git dep (trustee) that `cargo vendor` packages as just + # its crate dir (vendor/attestation-service-0.1.0/). Its build.rs compiles + # ../protos/reference.proto, but protos/ lives outside the package in the trustee + # repo, so `cargo vendor` omits it and the offline (vendored) build then fails with + # "protoc failed: ../protos/reference.proto: No such file or directory". Extract + # protos/ at the exact rev pinned in Cargo.lock from cargo's trustee git db into + # the vendor dir, so ../protos/ resolves from the vendored crate dir. (Non-vendored + # builds work because the full git checkout keeps protos/ as a sibling.) + @TRUSTEE_REV=$$(sed -n 's|.*trustee/?rev=\([a-f0-9]\{40\}\).*|\1|p' Cargo.lock | head -1); \ + PROTOS_OK=0; \ + for db in $${CARGO_HOME:-$$HOME/.cargo}/git/db/trustee-*; do \ + [ -d "$$db" ] || continue; \ + if git --git-dir="$$db" cat-file -e "$$TRUSTEE_REV" 2>/dev/null; then \ + git --git-dir="$$db" archive "$$TRUSTEE_REV" protos \ + | tar -x -C /tmp/trusted-network-gateway-tarball/trusted-network-gateway-${VERSION}/vendor/ \ + && PROTOS_OK=1 && break; \ + fi; \ + done; \ + [ "$$PROTOS_OK" = 1 ] && [ -f /tmp/trusted-network-gateway-tarball/trusted-network-gateway-${VERSION}/vendor/protos/reference.proto ] \ + || { echo "ERROR: could not extract trustee protos/ for vendored attestation-service (rev $$TRUSTEE_REV)"; exit 1; } + # delete all checksum (this is required due to previous patch work) sed -i 's/checksum = ".*//g' /tmp/trusted-network-gateway-tarball/trusted-network-gateway-${VERSION}/src/Cargo.lock From e3f75cd2dc1dd8decd194378ae7caaef18f2914b Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 16:22:10 +0800 Subject: [PATCH 6/7] docs(claude): require Assisted-by trailer for AI-authored commits Add Assisted-by: convention to Git Commit Requirements, replacing the forbidden Co-Authored-By form as the only accepted AI attribution. Document the AGENT_NAME:MODEL_VERSION [TOOL] format and note that the pre-push filter-branch sed preserves Assisted-by while stripping Co-Authored-By. Assisted-by: Claude:claude-opus-4-8 --- CLAUDE.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index f427ff91..b0283681 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,6 +19,19 @@ When creating or amending commits: - **Author and committer** must always be taken from the local git config (`git config user.name` / `git config user.email`). Never use Claude's own identity. - **Never** add `Co-Authored-By:` trailers of any kind. +- **Always** add an `Assisted-by:` trailer to every commit message that Claude authored or co-authored. The trailer is the *only* accepted form of AI attribution. Format: + + ``` + Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2] ... + ``` + + Where `AGENT_NAME` is the AI tool name (e.g. `Claude`), `MODEL_VERSION` is the specific model version used (e.g. `claude-opus-4-8`), and the optional bracketed `[TOOL]` entries are specialized analysis tools employed in producing the change (e.g. `coccinelle`, `sparse`, `smatch`, `clang-tidy`). Basic development tools (`git`, `gcc`, `make`, editors) must **not** be listed. Place the trailer as the last line(s) of the commit message body, separated by a blank line from the rest of the message. Example: + + ``` + Assisted-by: Claude:claude-opus-4-8 clang-tidy + ``` + + Only one `Assisted-by:` trailer per commit. If no specialized tool was used, omit the bracketed list entirely (`Assisted-by: Claude:claude-opus-4-8`). - **Never** include any Claude session URLs, session IDs, or links to claude.ai in commit messages or PR descriptions. Commit messages should only describe the code changes. - **Never** include "🤖 Generated with [Claude Code](https://claude.com/claude-code)" or similar AI attribution footers in PR descriptions or commit messages. - **Always** use `--no-gpg-sign` to avoid GPG signing. @@ -138,6 +151,8 @@ git filter-branch -f --msg-filter 'sed "/Co-Authored-By:/d"' --env-filter ' ' ..HEAD ``` +This rewrites `Co-Authored-By` trailers (forbidden) but **preserves** `Assisted-by:` trailers (expected) — the `sed` only deletes `Co-Authored-By:` lines, so `Assisted-by:` survives untouched. After rewriting, confirm every AI-authored commit still carries its `Assisted-by:` trailer before pushing. + ## GitHub Actions Workflow Triggers From 0ace2383c527f4e9155eac29b1d5b718026e809c Mon Sep 17 00:00:00 2001 From: Kun Lai Date: Tue, 14 Jul 2026 16:25:41 +0800 Subject: [PATCH 7/7] fix(ci): install perl-Time-Piece for vendored OpenSSL 3.5.x in CI The earlier spec fix (BuildRequires perl(Time::Piece)) only covers paths that resolve deps via yum-builddep on the spec. Two CI paths install perl deps explicitly and still failed: - go-sdk.yml: 'cargo build' hits openssl-sys vendored Configure, which now needs Time::Piece in addition to IPC::Cmd -> 'Can't locate Time/Piece.pm'. - build-rpm.yml (GuanFu/an8 buildspec): rpmbuild's strict BuildRequires check rejects 'perl(Time::Piece) is needed by ...' before %build, since the prepare phase only installed perl-IPC-Cmd. Add perl-Time-Piece to both explicit install lists. clippy.yml is unaffected (it uses yum-builddep on the spec, which already resolves perl(Time::Piece)). --- .github/workflows/go-sdk.yml | 15 ++++++++------- ...ed-network-gateway.an8.buildspec.yaml.template | 15 +++++++++------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/go-sdk.yml b/.github/workflows/go-sdk.yml index ed3b6f03..a95d62fa 100644 --- a/.github/workflows/go-sdk.yml +++ b/.github/workflows/go-sdk.yml @@ -28,13 +28,14 @@ jobs: sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo sed -i -E 's|https?://mirrors.cloud.aliyuncs.com/|https://mirrors.aliyun.com/|g' /etc/yum.repos.d/*.repo # openssl-sys builds OpenSSL from source (vendored) because the - # builtin-as-tdx-rust (dcap-qvl) backend pulls it in; OpenSSL's - # `Configure` requires the IPC::Cmd Perl module, which on alinux - # (an8-based) lives in its own `perl-IPC-Cmd` package (FindBin / - # File::Compare / File::Copy ship with the base perl-interpreter - # already present). Without this, `perl ./Configure` aborts with - # "Can't locate IPC/Cmd.pm". - yum install -y git make tar clang protobuf-devel jq iptables perl-IPC-Cmd + # builtin-as-tdx-rust (dcap-qvl) backend pulls it in; OpenSSL 3.5.x's + # `Configure` requires the IPC::Cmd and Time::Piece Perl modules, + # which on alinux (an8-based) live in their own `perl-IPC-Cmd` and + # `perl-Time-Piece` packages (FindBin / File::Compare / File::Copy + # ship with the base perl-interpreter already present). Without these, + # `perl ./Configure` aborts with "Can't locate IPC/Cmd.pm" / + # "Can't locate Time/Piece.pm". + yum install -y git make tar clang protobuf-devel jq iptables perl-IPC-Cmd perl-Time-Piece - uses: dtolnay/rust-toolchain@1.89.0 diff --git a/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template b/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template index 20cb5d1c..650b8b4f 100644 --- a/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template +++ b/rpm/AnolisOS8/trusted-network-gateway.an8.buildspec.yaml.template @@ -69,12 +69,15 @@ phases: - rustup default 1.91.1 # Change yum source from Anolis to Alinux - sed -i -E 's|https?://mirrors.openanolis.cn/anolis/|https://mirrors.aliyun.com/anolis/|g' /etc/yum.repos.d/*.repo - # openssl-sys builds OpenSSL from source (vendored); OpenSSL's `Configure` - # requires the IPC::Cmd Perl module, which on an8 lives in its own - # `perl-IPC-Cmd` package (FindBin/File::Compare/File::Copy ship with the - # base perl-interpreter already present). Without it, `perl ./Configure` - # aborts with "Can't locate IPC/Cmd.pm" and the rpmbuild %build fails. - - yum install -y perl-IPC-Cmd + # openssl-sys builds OpenSSL from source (vendored); OpenSSL 3.5.x's + # `Configure` requires the IPC::Cmd and Time::Piece Perl modules, which + # on an8 live in their own `perl-IPC-Cmd` and `perl-Time-Piece` packages + # (FindBin/File::Compare/File::Copy ship with the base perl-interpreter + # already present). Without them, `perl ./Configure` aborts with + # "Can't locate IPC/Cmd.pm" / "Can't locate Time/Piece.pm" during + # rpmbuild %build, and rpmbuild's strict BuildRequires check rejects + # perl(IPC::Cmd) / perl(Time::Piece) before %build even runs. + - yum install -y perl-IPC-Cmd perl-Time-Piece build: commands: - rpmbuild --define "_topdir /tmp/rpmbuild" -ba /tmp/rpmbuild/SPECS/trusted-network-gateway.spec --define 'with_rustup 1'