mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-02 23:56:24 +08:00
Bumps the actions group with 5 updates in the / directory: | Package | From | To | | --- | --- | --- | | [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) | `1.0.183` | `1.0.208` | | [actions/setup-node](https://github.com/actions/setup-node) | `4.0.2` | `7.0.0` | | [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) | `e18b497796c12c097a38f9edb9d0641fb99eee32` | `f0d9c3887740aee45f6153b24b3a6b815192ec16` | | [docker/login-action](https://github.com/docker/login-action) | `4.5.2` | `4.6.0` | | [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `4.2.0` | `4.3.0` | Updates `anthropics/claude-code-action` from 1.0.183 to 1.0.208 - [Release notes](https://github.com/anthropics/claude-code-action/releases) - [Commits](be7b93b190...e8c2d7c16c) Updates `actions/setup-node` from 4.0.2 to 7.0.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4.0.2...v7) Updates `Swatinem/rust-cache` from e18b497796c12c097a38f9edb9d0641fb99eee32 to f0d9c3887740aee45f6153b24b3a6b815192ec16 - [Release notes](https://github.com/swatinem/rust-cache/releases) - [Changelog](https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md) - [Commits](e18b497796...f0d9c38877) Updates `docker/login-action` from 4.5.2 to 4.6.0 - [Release notes](https://github.com/docker/login-action/releases) - [Commits](371161bbe7...dbcb813823) Updates `docker/setup-buildx-action` from 4.2.0 to 4.3.0 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](bb05f3f551...37fe631027) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: anthropics/claude-code-action dependency-version: 1.0.198 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: docker/login-action dependency-version: 4.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: docker/setup-buildx-action dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: Swatinem/rust-cache dependency-version: f0d9c3887740aee45f6153b24b3a6b815192ec16 dependency-type: direct:production dependency-group: actions ... Signed-off-by: dependabot[bot] <support@github.com>
585 lines
25 KiB
YAML
585 lines
25 KiB
YAML
name: Platform & Compat
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
ref:
|
|
description: Commit SHA or ref to test
|
|
required: false
|
|
type: string
|
|
include_docker:
|
|
description: Include Docker image build in this reusable test run
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
deep:
|
|
description: >-
|
|
Marker that this run is a reusable deep-CI invocation. Callers never
|
|
need to set it: the default makes `inputs.deep` true exactly when
|
|
this workflow runs via workflow_call, and the empty inputs context
|
|
makes it falsy on direct triggers. Job conditions must use this
|
|
instead of `github.event_name == 'workflow_call'` — in a reusable
|
|
workflow, github.event_name reflects the CALLER's event (e.g.
|
|
`schedule` under Nightly Deep CI), so that comparison never matches
|
|
and the gated jobs silently skip.
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
merge_group:
|
|
branches:
|
|
- main
|
|
types:
|
|
- checks_requested
|
|
push:
|
|
branches:
|
|
- main
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: platform-and-compat-${{ github.event_name }}-${{ github.head_ref || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
# Tests must never touch the real OS keychain (macOS Keychain auth dialog /
|
|
# Linux Secret Service). Guarded by
|
|
# crates/substrates/ironclaw_secrets/src/keychain.rs::os_keychain_suppressed:
|
|
# cfg!(test) covers unit tests; this covers integration/e2e that link the
|
|
# non-cfg(test) library.
|
|
IRONCLAW_DISABLE_OS_KEYCHAIN: "1"
|
|
# Pin wall-clock rendering inputs so a test cannot pass or fail on the
|
|
# runner's locale. Reborn renders model-visible time slices, and date/number
|
|
# formatting differs by locale, so an unpinned runner turns a formatting
|
|
# regression into an unreproducible flake. UTC also keeps recorded fixtures
|
|
# comparable with what a developer sees locally.
|
|
TZ: "UTC"
|
|
LANG: "C.UTF-8"
|
|
|
|
jobs:
|
|
changes:
|
|
name: Detect code changes
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
outputs:
|
|
docs_only: ${{ steps.non_diff.outputs.docs_only || steps.diff.outputs.docs_only }}
|
|
has_core_code: ${{ steps.non_diff.outputs.has_core_code || steps.diff.outputs.has_core_code }}
|
|
has_direct_wasm_abi_risk: ${{ steps.non_diff.outputs.has_direct_wasm_abi_risk || steps.diff.outputs.has_direct_wasm_abi_risk }}
|
|
has_wasm_abi_risk: ${{ steps.non_diff.outputs.has_wasm_abi_risk || steps.diff.outputs.has_wasm_abi_risk }}
|
|
has_legacy_tests: ${{ steps.non_diff.outputs.has_legacy_tests || steps.diff.outputs.has_legacy_tests }}
|
|
has_docker_risk: ${{ steps.non_diff.outputs.has_docker_risk || steps.diff.outputs.has_docker_risk }}
|
|
steps:
|
|
- id: non_diff
|
|
if: github.event_name != 'pull_request' && github.event_name != 'merge_group'
|
|
run: |
|
|
echo "docs_only=false" >> "$GITHUB_OUTPUT"
|
|
echo "has_core_code=true" >> "$GITHUB_OUTPUT"
|
|
echo "has_legacy_tests=true" >> "$GITHUB_OUTPUT"
|
|
echo "has_direct_wasm_abi_risk=true" >> "$GITHUB_OUTPUT"
|
|
echo "has_wasm_abi_risk=true" >> "$GITHUB_OUTPUT"
|
|
echo "has_docker_risk=true" >> "$GITHUB_OUTPUT"
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
|
|
with:
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- id: diff
|
|
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
|
|
env:
|
|
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
|
|
HEAD_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
|
run: |
|
|
CHANGED_FILES="$(git diff --name-only "$BASE_SHA"..."$HEAD_SHA")"
|
|
|
|
echo "Changed files:"
|
|
if [ -n "$CHANGED_FILES" ]; then
|
|
printf '%s\n' "$CHANGED_FILES"
|
|
else
|
|
echo "<none>"
|
|
fi
|
|
|
|
has_match() {
|
|
printf '%s\n' "$CHANGED_FILES" | grep -Eq "$1"
|
|
}
|
|
|
|
printf '%s\n' "$CHANGED_FILES" | scripts/ci/classify-test-scope.sh >> "$GITHUB_OUTPUT"
|
|
|
|
has_direct_wasm_abi_risk=false
|
|
# Crate scopes are matched by NAME at any depth: `crates/([^/]+/)*<name>/`
|
|
# keeps matching once crates move into family directories
|
|
# (crates/<family>/ironclaw_*, PROPOSAL §5). A flat `crates/<name>/`
|
|
# prefix stops matching there, `has_direct_wasm_abi_risk` goes false,
|
|
# and every WASM ABI check silently skips — the WS10 failure mode
|
|
# (#6963). `crates/ironclaw_wasm_product_adapters/` was also dropped:
|
|
# that crate no longer exists, so the alternative had been matching
|
|
# nothing. The bare `wit/` alternative went the same way when the WIT
|
|
# directory moved inside its owning crate (CHECKLIST WS4): the ABI
|
|
# files are `crates/lanes/ironclaw_wasm/wit/*.wit` now, already in scope via
|
|
# the `ironclaw_wasm` crate alternative, which unlike a repo-root
|
|
# prefix survives the WS7 family move too.
|
|
# scripts/ci/ws12_workflow_contracts.py pins this regex
|
|
# against the real crate inventory and against a real first-party
|
|
# extension manifest path, so a renamed, moved or deleted crate fails
|
|
# loudly here instead of quietly falling out of scope.
|
|
if has_match '^(crates/([^/]+/)*ironclaw_common/|crates/([^/]+/)*ironclaw_wasm/|crates/([^/]+/)*packages/[^/]+/(manifest\.toml|wasm-src/)|registry/|scripts/build-wasm-extensions\.sh$|scripts/check-version-bumps\.sh$|\.github/workflows/(platform-and-compat|nightly-deep-ci)\.yml$)'; then
|
|
has_direct_wasm_abi_risk=true
|
|
fi
|
|
echo "has_direct_wasm_abi_risk=$has_direct_wasm_abi_risk" >> "$GITHUB_OUTPUT"
|
|
|
|
if [ "$has_direct_wasm_abi_risk" = true ] || has_match '^(Cargo\.toml|Cargo\.lock)$'; then
|
|
echo "has_wasm_abi_risk=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "has_wasm_abi_risk=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
if has_match '^(Dockerfile|\.dockerignore$|docker/reborn/(entrypoint|start-sshd)\.sh$|\.github/workflows/platform-and-compat\.yml$)'; then
|
|
echo "has_docker_risk=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "has_docker_risk=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
hooks-parity-tests:
|
|
name: Hooks Predicate-Backend Parity Tests
|
|
needs: changes
|
|
if: needs.changes.outputs.docs_only != 'true' && needs.changes.outputs.has_legacy_tests == 'true' && needs.changes.outputs.has_core_code == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
services:
|
|
postgres:
|
|
image: pgvector/pgvector:pg16
|
|
env:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: ironclaw_test
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd "pg_isready -U postgres"
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
env:
|
|
DATABASE_URL: postgres://postgres:postgres@localhost/ironclaw_test
|
|
# Turn a missing/unreachable Postgres into a HARD failure so the full
|
|
# cross-backend matrix (in-memory + libSQL + Postgres) cannot skip-pass.
|
|
IRONCLAW_REQUIRE_POSTGRES: "1"
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
- name: Install Rust
|
|
uses: ./.github/actions/setup-rust
|
|
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
with:
|
|
key: hooks-parity
|
|
# Keep saves to protected-branch and merge_group runs so the ~10 GB
|
|
# repo cache LRU is seeded by shared states, not arbitrary PR branches.
|
|
save-if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'merge_group' }}
|
|
# Full parity matrix across all three backends. Backend implementations
|
|
# always compile; --features integration adds the multi-host adversarial
|
|
# suite, and IRONCLAW_REQUIRE_POSTGRES=1 (set above) makes the Postgres
|
|
# leg mandatory. The libSQL leg always runs (embedded temp-file).
|
|
- name: Run hooks parity matrix + multi-host adversarial suite (all backends)
|
|
run: |
|
|
timeout --signal=INT --kill-after=30s 15m \
|
|
cargo test -p ironclaw_hooks \
|
|
--features integration,test-support \
|
|
--test parity_matrix \
|
|
--test multi_host_adversarial \
|
|
--test predicate_state_postgres_contract \
|
|
--test predicate_state_postgres_adversarial \
|
|
--test predicate_state_libsql_contract \
|
|
-- --nocapture
|
|
|
|
windows-build:
|
|
name: Windows Build (${{ matrix.name }})
|
|
needs: changes
|
|
if: needs.changes.outputs.docs_only != 'true' && needs.changes.outputs.has_legacy_tests == 'true' && (github.event_name == 'push' || inputs.deep == true)
|
|
runs-on: windows-latest
|
|
timeout-minutes: 60
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# This job only runs on push / workflow_call (never on PR or
|
|
# merge_group), so it always builds the full feature matrix — no
|
|
# event-conditional SLIM/FULL indirection. Feature permutations are
|
|
# workspace-wide now that the v1 root package (and its
|
|
# html-to-markdown/bedrock/import features) is gone: `--all-features`
|
|
# enables every workspace member's features (including the heavy
|
|
# `bedrock` AWS lane), `default` builds the default set.
|
|
include:
|
|
- name: all-features
|
|
flags: "--all-features"
|
|
- name: default
|
|
flags: ""
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
- name: Install Rust
|
|
uses: ./.github/actions/setup-rust
|
|
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
with:
|
|
key: windows-${{ matrix.name }}
|
|
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
- name: Check compilation
|
|
run: cargo check --all --benches --tests --examples ${{ matrix.flags }}
|
|
|
|
wasm-wit-compat:
|
|
name: WASM WIT Compatibility
|
|
needs: changes
|
|
# WIT and registry paths are outside the shared legacy-test classifier;
|
|
# the event-specific WASM risk outputs are authoritative for this job.
|
|
if: >
|
|
needs.changes.outputs.docs_only != 'true' &&
|
|
(github.event_name == 'push' ||
|
|
inputs.deep == true ||
|
|
(github.event_name == 'merge_group' && needs.changes.outputs.has_wasm_abi_risk == 'true') ||
|
|
(github.event_name == 'pull_request' && needs.changes.outputs.has_direct_wasm_abi_risk == 'true'))
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
- name: Free disk space
|
|
run: |
|
|
df -h /
|
|
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
|
df -h /
|
|
- name: Install Rust
|
|
uses: ./.github/actions/setup-rust
|
|
with:
|
|
targets: wasm32-wasip2
|
|
- name: Enable pnpm for setup-node cache
|
|
run: corepack enable pnpm
|
|
- name: Install Node.js for WebUI bundle builds
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v4
|
|
with:
|
|
node-version: "22"
|
|
cache: "pnpm"
|
|
cache-dependency-path: |
|
|
crates/product/ironclaw_webui/frontend/pnpm-lock.yaml
|
|
crates/*/*/ironclaw_webui/frontend/pnpm-lock.yaml
|
|
- name: Enable pnpm
|
|
run: corepack enable pnpm
|
|
- name: Install WebUI frontend dependencies
|
|
run: |
|
|
set -euo pipefail
|
|
webui_dir="$(bash scripts/ci/crate-dir.sh ironclaw_webui)"
|
|
cd "${webui_dir}/frontend"
|
|
pnpm install --frozen-lockfile
|
|
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
with:
|
|
key: wasm-extensions
|
|
# Keep saves to protected-branch and merge_group runs so the ~10 GB
|
|
# repo cache LRU is seeded by shared states, not arbitrary PR branches.
|
|
save-if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event_name == 'merge_group' }}
|
|
- name: Install cargo-component
|
|
uses: ./.github/actions/install-cargo-component
|
|
- name: Build all WASM extensions against current WIT
|
|
run: ./scripts/build-wasm-extensions.sh
|
|
- name: Instantiation test (host linker compatibility)
|
|
run: |
|
|
timeout --signal=INT --kill-after=30s 20m \
|
|
cargo test -p ironclaw_wasm --test wit_tool_runtime_contract -- --nocapture
|
|
|
|
bench-compile:
|
|
name: Benchmark Compilation
|
|
needs: changes
|
|
if: >
|
|
needs.changes.outputs.docs_only != 'true' &&
|
|
needs.changes.outputs.has_legacy_tests == 'true' &&
|
|
(github.event_name == 'push' || inputs.deep == true) &&
|
|
needs.changes.outputs.has_core_code == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
- name: Install Rust
|
|
uses: ./.github/actions/setup-rust
|
|
- name: Enable pnpm for setup-node cache
|
|
run: corepack enable pnpm
|
|
- name: Install Node.js for WebUI bundle builds
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v4
|
|
with:
|
|
node-version: "22"
|
|
cache: "pnpm"
|
|
cache-dependency-path: |
|
|
crates/product/ironclaw_webui/frontend/pnpm-lock.yaml
|
|
crates/*/*/ironclaw_webui/frontend/pnpm-lock.yaml
|
|
- name: Enable pnpm
|
|
run: corepack enable pnpm
|
|
- name: Install WebUI frontend dependencies
|
|
run: |
|
|
set -euo pipefail
|
|
webui_dir="$(bash scripts/ci/crate-dir.sh ironclaw_webui)"
|
|
cd "${webui_dir}/frontend"
|
|
pnpm install --frozen-lockfile
|
|
- uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
|
|
with:
|
|
key: bench
|
|
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
- name: Compile benchmarks
|
|
run: cargo bench --all-features --no-run
|
|
|
|
docker-build:
|
|
name: Docker Build
|
|
needs: changes
|
|
# Dockerfile changes must not be a main-only failure: the merge queue
|
|
# builds the image when the merge group actually touches Docker inputs.
|
|
# The merge_group arm deliberately does not require has_legacy_tests —
|
|
# the scope classifier matches Docker inputs directly, so a merge group
|
|
# changing only .dockerignore or a Reborn startup script reports
|
|
# has_legacy_tests=false while has_docker_risk=true.
|
|
if: >
|
|
needs.changes.outputs.docs_only != 'true' &&
|
|
((needs.changes.outputs.has_legacy_tests == 'true' &&
|
|
(github.event_name == 'push' ||
|
|
(inputs.deep == true && inputs.include_docker))) ||
|
|
(github.event_name == 'merge_group' && needs.changes.outputs.has_docker_risk == 'true'))
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
- name: Build Docker image
|
|
run: docker build --target runtime -t ironclaw-reborn-test:ci .
|
|
- name: Verify in-worker SSH
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
test "$(docker image inspect --format '{{.Config.User}}' ironclaw-reborn-test:ci)" = "root"
|
|
docker image inspect --format '{{json .Config.ExposedPorts}}' ironclaw-reborn-test:ci \
|
|
| grep -q '"2222/tcp"'
|
|
|
|
ssh_work="$(mktemp -d)"
|
|
container_name="ironclaw-reborn-ssh-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
paste_container_name="${container_name}-paste"
|
|
cleanup() {
|
|
docker rm --force "$container_name" >/dev/null 2>&1 || true
|
|
docker rm --force "$paste_container_name" >/dev/null 2>&1 || true
|
|
rm -rf "$ssh_work"
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
ssh-keygen -q -t ed25519 -N '' -f "$ssh_work/id_ed25519"
|
|
docker run --detach \
|
|
--name "$container_name" \
|
|
--publish 127.0.0.1::2222 \
|
|
--env IRONCLAW_REBORN_WEBUI_TOKEN=ssh-ci-webui-token-0123456789abcdef0123456789abcdef \
|
|
--env "IRONCLAW_REBORN_SSH_PUBLIC_KEY=$(cat "$ssh_work/id_ed25519.pub")" \
|
|
ironclaw-reborn-test:ci
|
|
|
|
ssh_port="$(docker port "$container_name" 2222/tcp | awk -F: 'NR == 1 { print $NF }')"
|
|
ssh_ready=false
|
|
for _ in $(seq 1 30); do
|
|
if ssh \
|
|
-i "$ssh_work/id_ed25519" \
|
|
-p "$ssh_port" \
|
|
-o BatchMode=yes \
|
|
-o ConnectTimeout=1 \
|
|
-o IdentitiesOnly=yes \
|
|
-o StrictHostKeyChecking=no \
|
|
-o UserKnownHostsFile=/dev/null \
|
|
agent@127.0.0.1 \
|
|
'test "$USER" = agent && test "$HOME" = /workspace && test "$PWD" = /workspace'
|
|
then
|
|
ssh_ready=true
|
|
break
|
|
fi
|
|
if [ "$(docker inspect --format '{{.State.Running}}' "$container_name")" != "true" ]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [ "$ssh_ready" != "true" ]; then
|
|
docker logs "$container_name"
|
|
echo "Reborn runtime did not accept an SSH session as agent" >&2
|
|
exit 1
|
|
fi
|
|
|
|
paste_key="$(cat "$ssh_work/id_ed25519.pub")"$'\n'
|
|
# The key almost always arrives via `cat id_ed25519.pub`, so the value
|
|
# carries a trailing newline. start-sshd must tolerate that: it runs
|
|
# under the entrypoint's `set -e`, so rejecting a usable key does not
|
|
# merely disable SSH, it aborts the whole container boot. Reuses the
|
|
# image already built above -- no second build.
|
|
docker run --detach \
|
|
--name "$paste_container_name" \
|
|
--publish 127.0.0.1::2222 \
|
|
--env IRONCLAW_REBORN_WEBUI_TOKEN=ssh-ci-webui-token-0123456789abcdef0123456789abcdef \
|
|
--env "IRONCLAW_REBORN_SSH_PUBLIC_KEY=${paste_key}" \
|
|
ironclaw-reborn-test:ci
|
|
|
|
paste_port="$(docker port "$paste_container_name" 2222/tcp | awk -F: 'NR == 1 { print $NF }')"
|
|
paste_ready=false
|
|
for _ in $(seq 1 30); do
|
|
if ssh \
|
|
-i "$ssh_work/id_ed25519" \
|
|
-p "$paste_port" \
|
|
-o BatchMode=yes \
|
|
-o ConnectTimeout=1 \
|
|
-o IdentitiesOnly=yes \
|
|
-o StrictHostKeyChecking=no \
|
|
-o UserKnownHostsFile=/dev/null \
|
|
agent@127.0.0.1 'test "$USER" = agent'
|
|
then
|
|
paste_ready=true
|
|
break
|
|
fi
|
|
if [ "$(docker inspect --format '{{.State.Running}}' "$paste_container_name")" != "true" ]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [ "$paste_ready" != "true" ]; then
|
|
docker logs "$paste_container_name"
|
|
echo "A public key with a trailing newline must still be accepted; rejecting it aborts container boot" >&2
|
|
exit 1
|
|
fi
|
|
|
|
version-check:
|
|
name: Version Bump Check
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
needs: changes
|
|
if: >
|
|
(github.event_name == 'pull_request' || github.event_name == 'merge_group') &&
|
|
needs.changes.outputs.docs_only != 'true' &&
|
|
needs.changes.outputs.has_legacy_tests == 'true'
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
issues: read
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
ref: ${{ inputs.ref || github.sha }}
|
|
persist-credentials: false
|
|
fetch-depth: 0
|
|
- name: Resolve version-check skip labels
|
|
id: skip_labels
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
REPO: ${{ github.repository }}
|
|
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
|
|
HEAD_SHA: ${{ inputs.ref || github.sha }}
|
|
PR_LABELS: ${{ github.event_name == 'pull_request' && join(github.event.pull_request.labels.*.name, ',') || '' }}
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
echo "labels=${PR_LABELS}" >> "$GITHUB_OUTPUT"
|
|
echo "allow_skip=true" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
COMPARE_JSON="$(gh api "repos/${REPO}/compare/${BASE_SHA}...${HEAD_SHA}")"
|
|
PR_NUMBERS="$(
|
|
printf '%s' "$COMPARE_JSON" | jq -r '.commits[].sha' \
|
|
| while read -r sha; do
|
|
[ -n "$sha" ] || continue
|
|
gh api "repos/${REPO}/commits/${sha}/pulls" \
|
|
-H "Accept: application/vnd.github+json" \
|
|
--jq '.[].number' 2>/dev/null || true
|
|
done \
|
|
| awk 'NF && !seen[$0]++'
|
|
)"
|
|
|
|
PR_COUNT="$(printf '%s\n' "$PR_NUMBERS" | awk 'NF' | wc -l | tr -d ' ')"
|
|
if [ "${PR_COUNT}" != "1" ]; then
|
|
echo "labels=" >> "$GITHUB_OUTPUT"
|
|
echo "allow_skip=false" >> "$GITHUB_OUTPUT"
|
|
exit 0
|
|
fi
|
|
|
|
LABELS="$(
|
|
printf '%s\n' "$PR_NUMBERS" \
|
|
| while read -r pr; do
|
|
[ -n "$pr" ] || continue
|
|
gh api "repos/${REPO}/issues/${pr}" --jq '.labels[].name' 2>/dev/null || true
|
|
done \
|
|
| awk 'NF && !seen[$0]++'
|
|
)"
|
|
|
|
if [ -n "$LABELS" ]; then
|
|
echo "labels=$(printf '%s\n' "$LABELS" | paste -sd, -)" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "labels=" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
echo "allow_skip=true" >> "$GITHUB_OUTPUT"
|
|
- name: Check version bumps for changed extensions
|
|
env:
|
|
PR_LABELS: ${{ steps.skip_labels.outputs.labels }}
|
|
GITHUB_BASE_REF: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.ref || github.event_name == 'merge_group' && github.event.merge_group.base_ref || '' }}
|
|
ALLOW_SKIP_VERSION_CHECK: ${{ steps.skip_labels.outputs.allow_skip }}
|
|
run: ./scripts/check-version-bumps.sh
|
|
|
|
platform-compat:
|
|
name: Platform & Compat
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
if: always()
|
|
needs:
|
|
- changes
|
|
- hooks-parity-tests
|
|
- windows-build
|
|
- wasm-wit-compat
|
|
- bench-compile
|
|
- docker-build
|
|
- version-check
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
persist-credentials: false
|
|
- name: Check Platform & Compat jobs
|
|
run: |
|
|
# shellcheck disable=SC1091
|
|
if ! source .github/scripts/ci-job-result-ok.sh; then
|
|
echo "Unable to source .github/scripts/ci-job-result-ok.sh"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${{ needs.changes.result }}" != "success" ]]; then
|
|
echo "changes (scope detection) failed: ${{ needs.changes.result }}"
|
|
exit 1
|
|
fi
|
|
|
|
# Every job in this workflow is conditionally gated (by event or by
|
|
# detected scope), so "skipped" is a legitimate pass; anything that
|
|
# actually ran must have succeeded. This roll-up gives the workflow
|
|
# one stable check name that branch rulesets can require.
|
|
for job_result in \
|
|
"hooks-parity-tests=${{ needs.hooks-parity-tests.result }}" \
|
|
"windows-build=${{ needs.windows-build.result }}" \
|
|
"wasm-wit-compat=${{ needs.wasm-wit-compat.result }}" \
|
|
"bench-compile=${{ needs.bench-compile.result }}" \
|
|
"docker-build=${{ needs.docker-build.result }}" \
|
|
"version-check=${{ needs.version-check.result }}"; do
|
|
name="${job_result%%=*}"
|
|
result="${job_result##*=}"
|
|
if ! job_result_ok "$name" "$result" true "allow"; then
|
|
echo "$name failed: $result"
|
|
exit 1
|
|
fi
|
|
done
|