Files
pezkuwi-sdk/.gitlab-ci.yml
T
Kurdistan Tech Ministry 9d5b101fd7 fix(ci): fix check-zepter PATH and cargo-audit pipefail
check-zepter: CARGO_HOME=$CI_PROJECT_DIR/.cargo but export used $HOME/.cargo/bin;
switched to $CARGO_HOME/bin so installed zepter 1.82.1 takes precedence.

cargo-audit: set -o pipefail caused the pipe to fail with cargo-audit's exit
code (1 when vulns exist) even when python check passed; redirect to file first.
2026-04-22 06:39:22 +03:00

533 lines
19 KiB
YAML

# ============================================================================
# Pezkuwi SDK — GitLab CI/CD Pipeline
# Mirrors: checks-quick, checks, security-audit, tests, docs, release
#
# Same unified image as GitHub Actions — no apt-get overhead, sccache ready.
# ============================================================================
image: ghcr.io/pezkuwichain/ci-unified:bullseye-1.88.0-2025-06-27-v202511141243
stages:
- quick-checks
- checks
- security
- test
- docs
- build
- release
# ── Variables ─────────────────────────────────────────────────────────────────
variables:
CARGO_HOME: "$CI_PROJECT_DIR/.cargo"
CARGO_INCREMENTAL: "0"
CARGO_TERM_COLOR: "always"
RUST_BACKTRACE: "short"
RUSTFLAGS: "-D warnings"
# Disable forklift (GitHub-only sccache proxy not available on GitLab)
RUSTC_WRAPPER: ""
# Faster artifact transfer
FF_USE_FASTZIP: "true"
ARTIFACT_COMPRESSION_LEVEL: "fast"
CACHE_COMPRESSION_LEVEL: "fast"
# ── Workflow: avoid duplicate pipelines ───────────────────────────────────────
workflow:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
# ── Default ───────────────────────────────────────────────────────────────────
default:
before_script:
- rustup show
- rustc --version && cargo --version
cache:
key:
files:
- Cargo.lock
- rust-toolchain.toml
paths:
- .cargo/registry/
- .cargo/git/
policy: pull-push
interruptible: true
# ╔══════════════════════════════════════════════════════════════════════════════
# QUICK CHECKS — fast feedback on every push/MR (mirrors checks-quick.yml)
# ╚══════════════════════════════════════════════════════════════════════════════
fmt:
stage: quick-checks
script:
- cargo fmt --all -- --check
check-toml-format:
stage: quick-checks
variables:
CARGO_HOME: /root/.cargo
script:
- taplo format --check --config .config/taplo.toml
- echo "Run 'taplo format --config .config/taplo.toml' to fix TOML issues"
check-dependency-rules:
stage: quick-checks
script:
- cd bizinikiwi/ && ../.gitlab/ensure-deps.sh
check-fail-ci:
stage: quick-checks
script:
- |
if rg --line-number --hidden --type rust --glob '!{.git,target}' "FAIL-CI" .; then
echo "FAIL-CI marker found — remove before merging"
exit 1
fi
echo "✅ No FAIL-CI markers found"
check-workspace-integrity:
stage: quick-checks
variables:
CARGO_HOME: /root/.cargo
script:
- pip3 install toml "cargo-workspace>=1.2.6" --quiet
- |
python3 .github/scripts/check-workspace.py . \
--exclude "bizinikiwi/pezframe/contracts/fixtures/build" "bizinikiwi/pezframe/contracts/fixtures/contracts/common"
- python3 .github/scripts/deny-git-deps.py .
check-zepter:
stage: quick-checks
script:
- cargo metadata --format-version=1 --locked > /dev/null
- cargo install zepter@1.82.1 --force
- export PATH="$CARGO_HOME/bin:$PATH"
- zepter --version
- zepter run check
test-rust-features:
stage: quick-checks
script:
- bash .gitlab/rust-features.sh .
check-umbrella:
stage: quick-checks
allow_failure: true
script:
- pip3 install "cargo-workspace>=1.2.4" toml --quiet
- git config --global --add safe.directory '*'
- |
UMBRELLA_VERSION=$(cargo metadata --format-version=1 | \
python3 -c "import json,sys; pkgs=json.load(sys.stdin)['packages']; \
print(next(p['version'] for p in pkgs if p['manifest_path'].endswith('umbrella/Cargo.toml')))")
echo "Umbrella version: $UMBRELLA_VERSION"
python3 scripts/generate-umbrella.py --sdk . --version "$UMBRELLA_VERSION"
cargo +nightly fmt -p pezkuwi-sdk
- |
if [ -n "$(git status --porcelain)" ]; then
echo "❌ Umbrella crate is out of sync. Run: python3 scripts/generate-umbrella.py --sdk . --version <VERSION>"
git diff
exit 1
fi
echo "✅ Umbrella crate is up to date"
check-licenses-headers:
stage: quick-checks
script:
- |
FAIL=0
for dir in pezkuwi pezcumulus bizinikiwi; do
echo "Checking license headers in ./$dir..."
MISSING=""
while IFS= read -r f; do
head -20 "$f" | grep -qiE "(apache|gpl|mit|unlicense|copyright)" || MISSING="$MISSING\n$f"
done < <(find "./$dir" -name "*.rs" -type f | head -200)
if [ -n "$MISSING" ]; then
echo "⚠️ Files potentially missing license headers in $dir:"
printf "$MISSING\n" | head -20
FAIL=1
else
echo "✅ $dir: license headers OK (sampled)"
fi
done
exit $FAIL
# ╔══════════════════════════════════════════════════════════════════════════════
# CHECKS — deeper linting and feature checks (mirrors checks.yml)
# ╚══════════════════════════════════════════════════════════════════════════════
clippy:
stage: checks
needs: [fmt]
variables:
SKIP_WASM_BUILD: "1"
timeout: 90m
script:
- git config --global --add safe.directory '*'
- |
cargo clippy --all-targets --all-features --locked --workspace --quiet \
--exclude pezpallet-revive-eth-rpc \
--exclude pezkuwi-zombienet-sdk-tests \
-- -D warnings
check-try-runtime:
stage: checks
needs: [clippy]
variables:
SKIP_WASM_BUILD: "1"
timeout: 90m
script:
- git config --global --add safe.directory '*'
- cargo check --locked --all --features try-runtime --quiet
- cargo check --locked -p teyrchain-template-node --features try-runtime
- cargo check --locked --all --features try-runtime,experimental --quiet
check-core-crypto-features:
stage: checks
needs: [fmt]
script:
- rustup target add wasm32v1-none
- |
for pkg in core application-crypto keyring; do
echo "--- Checking bizinikiwi/primitives/$pkg ---"
(cd bizinikiwi/primitives/$pkg && ./check-features-variants.sh)
done
# ╔══════════════════════════════════════════════════════════════════════════════
# SECURITY — mirrors security-audit.yml (runs on push + schedule weekly Mon 06:00)
# ╚══════════════════════════════════════════════════════════════════════════════
cargo-deny-advisories:
stage: security
needs: []
before_script: []
script:
- cargo install cargo-deny --locked -q
- cargo deny check advisories --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-deny-licenses:
stage: security
needs: []
before_script: []
script:
- cargo install cargo-deny --locked -q
- cargo deny check licenses --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-deny-sources:
stage: security
needs: []
before_script: []
script:
- cargo install cargo-deny --locked -q
- cargo deny check sources --config deny.toml
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
- if: $CI_PIPELINE_SOURCE == "schedule"
cargo-audit:
stage: security
needs: []
before_script: []
script:
- cargo install cargo-audit --locked -q
- cargo audit --json 2>/dev/null > /tmp/audit.json || true
- python3 .gitlab/check-audit.py < /tmp/audit.json
allow_failure: false
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
# ╔══════════════════════════════════════════════════════════════════════════════
# TEST — mirrors tests-linux-stable.yml (manual-only on GitHub, schedule here)
# ╚══════════════════════════════════════════════════════════════════════════════
# Tests split into 3 partitions via cargo-nextest — mirrors GitHub matrix strategy
.test-base:
stage: test
needs: [clippy, check-try-runtime]
variables:
RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings"
WASM_BUILD_NO_COLOR: "1"
CARGO_INCREMENTAL: "0"
timeout: 90m
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
test-partition-1:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:1/3
artifacts:
when: always
paths: [test-results-1.xml]
reports:
junit: test-results-1.xml
expire_in: 7 days
test-partition-2:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:2/3
artifacts:
when: always
paths: [test-results-2.xml]
reports:
junit: test-results-2.xml
expire_in: 7 days
test-partition-3:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features try-runtime,experimental,ci-only-tests \
--partition count:3/3
# First partition also runs runtime-api tests
- cargo nextest run -p pezsp-api-test --features enable-pez-staging-api --cargo-quiet
artifacts:
when: always
paths: [test-results-3.xml]
reports:
junit: test-results-3.xml
expire_in: 7 days
test-no-try-runtime-1:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features experimental,ci-only-tests \
--partition count:1/2
test-no-try-runtime-2:
extends: .test-base
script:
- git config --global --add safe.directory '*'
- |
cargo nextest run \
--workspace --locked --release --no-fail-fast --cargo-quiet \
--features experimental,ci-only-tests \
--partition count:2/2
wasm-check:
stage: test
needs: [check-try-runtime]
script:
- rustup target add wasm32-unknown-unknown
- cargo check -p pezkuwichain-runtime --locked --target wasm32-unknown-unknown
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
# Runtime migration — disabled until try-runtime Zagros endpoints are live
# Enable by removing the `when: manual` rule and setting proper URIs
runtime-migration:
stage: test
needs: []
variables:
RUSTFLAGS: ""
script:
- |
echo "Runtime migration check — currently manual/disabled"
echo "Targets: zagros, asset-hub-zagros, collectives-zagros, coretime-zagros"
echo "Re-enable when wss://try-runtime-zagros.pezkuwichain.io is live"
rules:
- if: $CI_PIPELINE_SOURCE == "web"
when: manual
- if: $CI_PIPELINE_SOURCE == "schedule"
when: manual
allow_failure: true
# ╔══════════════════════════════════════════════════════════════════════════════
# DOCS — mirrors docs.yml
# ╚══════════════════════════════════════════════════════════════════════════════
test-doc:
stage: docs
needs: [clippy]
variables:
RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings"
SKIP_WASM_BUILD: "0"
timeout: 5h
script:
- rustup target add wasm32v1-none
- git config --global --add safe.directory '*'
- |
cargo test --doc --workspace --locked --all-features \
--exclude pezkuwi-zombienet-sdk-tests \
--exclude pezpallet-revive-eth-rpc
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
allow_failure: true
build-rustdoc:
stage: docs
needs: [test-doc]
variables:
SKIP_WASM_BUILD: "1"
RUSTDOCFLAGS: >-
-Dwarnings
--default-theme=ayu
--html-in-header ./docs/sdk/assets/header.html
--extend-css ./docs/sdk/assets/theme.css
--html-after-content ./docs/sdk/assets/after-content.html
timeout: 4h
script:
- git config --global --add safe.directory '*'
- |
cargo doc --all-features --workspace --no-deps --locked \
--exclude pezkuwi-zombienet-sdk-tests \
--exclude pezpallet-revive-eth-rpc
- rm -f target/doc/.lock
- mv target/doc ./crate-docs
- echo '<meta http-equiv=refresh content=0;url=pezkuwi_sdk_docs/index.html>' > ./crate-docs/index.html
- tar czf crate-docs.tar.gz crate-docs/
artifacts:
paths: [crate-docs.tar.gz]
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: true
build-implementers-guide:
stage: docs
needs: []
before_script: []
script:
- mdbook build ./pezkuwi/roadmap/implementers-guide
artifacts:
paths: [pezkuwi/roadmap/implementers-guide/book/]
expire_in: 1 day
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_MERGE_REQUEST_IID
allow_failure: true
# GitLab Pages — publish rustdocs to pages.gitlab.io
pages:
stage: docs
needs: [build-rustdoc, build-implementers-guide]
before_script: []
script:
- mkdir -p public
- tar xzf crate-docs.tar.gz -C public/ --strip-components=1 || true
- cp -r pezkuwi/roadmap/implementers-guide/book public/guide || true
artifacts:
paths: [public/]
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
allow_failure: true
# ╔══════════════════════════════════════════════════════════════════════════════
# BUILD — release binary (main branch + tags)
# ╚══════════════════════════════════════════════════════════════════════════════
build-release:
stage: build
needs: [clippy, wasm-check]
variables:
RUSTFLAGS: "-D warnings"
timeout: 4h
script:
- git config --global --add safe.directory '*'
- cargo build --release -p pezkuwi --locked
- |
echo "=== Build artifacts ==="
ls -lh target/release/pezkuwi \
target/release/pezkuwi-execute-worker \
target/release/pezkuwi-prepare-worker
echo ""
echo "=== SHA256 checksums ==="
sha256sum \
target/release/pezkuwi \
target/release/pezkuwi-execute-worker \
target/release/pezkuwi-prepare-worker | tee SHA256SUMS
artifacts:
name: "pezkuwi-$CI_COMMIT_REF_NAME"
paths:
- target/release/pezkuwi
- target/release/pezkuwi-execute-worker
- target/release/pezkuwi-prepare-worker
- SHA256SUMS
expire_in: 7 days
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
# ╔══════════════════════════════════════════════════════════════════════════════
# RELEASE — GitLab Release with assets (tags only)
# ╚══════════════════════════════════════════════════════════════════════════════
release:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
before_script: []
needs: [build-release]
script:
- echo "Creating GitLab Release for $CI_COMMIT_TAG"
release:
tag_name: "$CI_COMMIT_TAG"
name: "Pezkuwi SDK $CI_COMMIT_TAG"
description: |
## Pezkuwi SDK $CI_COMMIT_TAG
### Binaries (Linux x86_64)
| Binary | Description |
|--------|-------------|
| `pezkuwi` | Node binary |
| `pezkuwi-execute-worker` | WASM execution worker |
| `pezkuwi-prepare-worker` | WASM preparation worker |
SHA256 checksums in `SHA256SUMS`.
### Verify
```bash
sha256sum -c SHA256SUMS
```
assets:
links:
- name: "pezkuwi (node binary)"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi?job=build-release"
link_type: package
- name: "pezkuwi-execute-worker"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi-execute-worker?job=build-release"
link_type: package
- name: "pezkuwi-prepare-worker"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/pezkuwi-prepare-worker?job=build-release"
link_type: package
- name: "SHA256SUMS"
url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/SHA256SUMS?job=build-release"
link_type: other
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/