Skip to content

feat(swift-sdk): typed DPNS contested-name browsing for voters (#4328) #14706

feat(swift-sdk): typed DPNS contested-name browsing for voters (#4328)

feat(swift-sdk): typed DPNS contested-name browsing for voters (#4328) #14706

Workflow file for this run

name: Tests
on:
workflow_dispatch:
push:
branches:
- master
- "v*-dev"
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- master
- "v*-dev"
- "ci/*"
schedule:
- cron: "0 23 * * *"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check-secrets:
name: Check secret availability
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
outputs:
has_ecr: ${{ steps.check.outputs.has_ecr }}
steps:
- name: Check if ECR credentials are available
id: check
run: |
if [[ -n "${{ secrets.AWS_ACCESS_KEY_ID }}" && -n "${{ secrets.AWS_ACCOUNT_ID }}" ]]; then
echo "has_ecr=true" >> "$GITHUB_OUTPUT"
else
echo "has_ecr=false" >> "$GITHUB_OUTPUT"
echo "::notice::ECR credentials not available — Docker image builds and dependent tests will be skipped (expected for fork PRs)"
fi
changes:
name: Determine changed packages
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
outputs:
js-packages: ${{ steps.override.outputs.js-packages || steps.prune-pr-matrix.outputs.js-packages || steps.filter-js.outputs.changes }}
js-packages-direct: ${{ steps.override.outputs.js-packages-direct || steps.filter-js-direct.outputs.changes }}
rs-packages: ${{ steps.override.outputs.rs-packages || steps.filter-rs.outputs.changes }}
rs-workflows-changed: ${{ steps.filter-rs-workflows.outputs.rs-workflows }}
rs-scope: ${{ steps.rs-scope.outputs.scope }}
shielded-changed: ${{ steps.override.outputs.shielded-changed || steps.filter-shielded.outputs.shielded-changed }}
doctests-changed: ${{ steps.override.outputs.doctests-changed || steps.filter-doctests.outputs.doctests-changed }}
swift-sdk-changed: ${{ steps.override.outputs.swift-sdk-changed || steps.filter-swift-sdk.outputs.swift-sdk-changed }}
version-changed: ${{ steps.override.outputs.version-changed || steps.filter-version.outputs.version-changed }}
e2e-tests-changed: ${{ steps.override.outputs.e2e-tests-changed || steps.filter-e2e.outputs.e2e-tests-changed }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Verify self-hosted Swift runner policy
run: python3 .github/scripts/check-swift-self-hosted-runner.py
- uses: dorny/paths-filter@v4
id: filter-js
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
filters: .github/package-filters/js-packages-no-workflows.yml
- uses: dorny/paths-filter@v4
id: filter-js-direct
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
filters: .github/package-filters/js-packages-direct.yml
- uses: dorny/paths-filter@v4
id: filter-rs
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
filters: .github/package-filters/rs-packages-no-workflows.yml
- uses: dorny/paths-filter@v4
id: filter-rs-workflows
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
filters: |
rs-workflows:
- .github/workflows/tests-rs-workspace.yml
- .github/workflows/tests-rs-wallet.yml
- .github/workflows/tests.yml
- .github/scripts/check-wallet-closure.py
- uses: dorny/paths-filter@v4
id: filter-e2e
if: ${{ github.event_name != 'workflow_dispatch' }}
with:
filters: |
e2e-tests-changed:
- packages/platform-test-suite/**
- packages/dashmate/**
- packages/js-dapi-client/**
- packages/js-dash-sdk/**
- packages/wallet-lib/**
- packages/wasm-sdk/**
- packages/dapi/.env.example
- packages/rs-drive-abci/.env.local
- .github/actions/aws_ecr_login/**
- .github/actions/docker/**
- .github/actions/local-network/**
- .github/actions/nodejs/**
- .github/actions/rust/**
- .github/actions/sccache/**
- .github/workflows/tests.yml
- .github/workflows/tests-build-js.yml
- .github/workflows/tests-build-image.yml
- .github/workflows/tests-test-suite.yml
- .github/workflows/tests-packges-functional.yml
- .github/workflows/tests-dashmate.yml
- scripts/setup_local_network.sh
- scripts/configure_test_suite.sh
- scripts/configure_dotenv.sh
- scripts/dashmate/volumes/**
- name: Check for platform version change
id: filter-version
if: ${{ github.event_name != 'workflow_dispatch' }}
run: |
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before || 'HEAD~1' }}"
if git diff "$BASE_SHA"...HEAD -- Cargo.toml 2>/dev/null | grep -qE '^\+version\s*='; then
echo "version-changed=true" >> "$GITHUB_OUTPUT"
echo "Platform version changed — Docker builds and test suite will run"
else
echo "version-changed=false" >> "$GITHUB_OUTPUT"
echo "Platform version unchanged"
fi
- name: Check for doctest changes
id: filter-doctests
if: ${{ github.event_name != 'workflow_dispatch' }}
run: |
BASE_SHA="${{ github.event.pull_request.base.sha || github.event.before || 'HEAD~1' }}"
DIFF=$(git diff "$BASE_SHA"...HEAD -- '*.rs' 2>/dev/null || git diff HEAD~1 -- '*.rs')
# Look for added/removed lines in doc comments that contain code fences
if echo "$DIFF" | grep -qE '^[+-].*///.*```|^[+-].*//!.*```'; then
echo "doctests-changed=true" >> "$GITHUB_OUTPUT"
echo "Doc comments with code examples changed — doctests will run"
exit 0
fi
echo "doctests-changed=false" >> "$GITHUB_OUTPUT"
echo "No doctest changes — skipping doctests"
- name: Determine Rust test scope (wallet-only fast path)
id: rs-scope
if: ${{ github.event_name != 'workflow_dispatch' }}
run: |
# The fast path applies only to same-repo pull requests. Fork PRs
# must take the full workspace path (both Rust workflows skip fork
# PRs outright, since neither may run untrusted code on a persistent
# runner). Push and schedule runs have no reliable base SHA — scope
# computed from the last commit alone could silently downgrade the
# nightly / post-merge full runs.
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "scope=full" >> "$GITHUB_OUTPUT"
echo "Not a pull request — using full Rust workspace tests"
exit 0
fi
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ] \
&& [ "${{ github.event.pull_request.head.repo.owner.login }}" != "thepastaclaw" ]; then
echo "scope=full" >> "$GITHUB_OUTPUT"
echo "Fork pull request — using full Rust workspace tests"
exit 0
fi
# --no-renames: a file moved out of another crate into a wallet
# crate must still count as a change to the source crate.
if ! CHANGED=$(git diff --no-renames --name-only "${{ github.event.pull_request.base.sha }}"...HEAD); then
echo "scope=full" >> "$GITHUB_OUTPUT"
echo "Could not diff against the PR base — using full Rust workspace tests"
exit 0
fi
if [ -z "$CHANGED" ]; then
echo "scope=full" >> "$GITHUB_OUTPUT"
echo "No changed files detected — using full Rust workspace tests"
exit 0
fi
has_wallet=false
non_wallet=false
while IFS= read -r f; do
[ -z "$f" ] && continue
case "$f" in
packages/rs-platform-wallet/*|packages/rs-platform-wallet-ffi/*|packages/rs-platform-wallet-storage/*)
has_wallet=true ;;
packages/swift-sdk/*)
# Swift sources are not part of the Rust workspace and cannot
# affect `cargo test`, so they don't force the full suite.
: ;;
*)
# Anything else — another Rust crate, Cargo.lock, root config,
# docs, workflows — conservatively forces the full workspace run.
non_wallet=true ;;
esac
done <<< "$CHANGED"
if [ "$has_wallet" = true ] && [ "$non_wallet" = false ]; then
echo "scope=wallet" >> "$GITHUB_OUTPUT"
echo "Only wallet crates changed — using scoped Rust wallet tests"
else
echo "scope=full" >> "$GITHUB_OUTPUT"
echo "Non-wallet Rust changes present — using full Rust workspace tests"
fi
# Decide whether the shielded test phase of tests-rs-workspace.yml must
# run. This is a HEURISTIC, not a dependency-closure proof: shielded
# tests exercise shared consensus code (drive batch ops, state
# transition processing), so a PR touching only shared code could in
# principle break them while being classified "unrelated" here. The
# safety net is that every non-PR run (push to a dev branch after merge,
# the nightly schedule, manual dispatch) always runs the shielded suite,
# so an escape is caught minutes after merge and bisects to one PR.
#
# A PR counts as shielded-relevant if any of:
# - a changed file's path mentions shield/orchard/halo2 (all shielded
# modules live in *shield* directories, but keyword-match the whole
# path to be safe);
# - the diff content of any .rs or .proto file mentions those keywords
# (catches edits to shielded match arms, error variants, and test
# names in shared files outside the shielded directories, and
# shielded gRPC message changes that regenerate into dapi-grpc);
# - anything that changes how the shielded suite is built or selected:
# any Cargo.toml/Cargo.lock (feature unification, dep bumps),
# rust-toolchain.toml, the rust setup action, or the Rust test
# workflows themselves.
- name: Check for shielded-relevant changes
id: filter-shielded
if: ${{ github.event_name != 'workflow_dispatch' }}
run: |
# No pipefail: the detection pipelines end in `grep -q`, which exits
# on first match and SIGPIPEs the upstream git diff — with pipefail
# a *match* would read as pipeline failure and silently flip the
# answer to "unchanged".
set -eu
# Non-PR runs are the safety net: always run shielded tests (and
# refresh the shared shielded-coverage cache).
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Not a pull request — shielded tests always run"
exit 0
fi
# --no-renames: a shielded file moved elsewhere must still count as
# a shielded change on both sides of the move.
if ! CHANGED=$(git diff --no-renames --name-only "${{ github.event.pull_request.base.sha }}"...HEAD); then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Could not diff against the PR base — assuming shielded changes"
exit 0
fi
# Keep in sync with the shielded-source content hash computed in
# tests-rs-workspace.yml ("Compute shielded source content hash").
SHIELD_RE='shield|orchard|halo2'
if echo "$CHANGED" | grep -qiE "$SHIELD_RE"; then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Changed paths mention shielded modules — shielded tests will run"
exit 0
fi
if echo "$CHANGED" | grep -qE '(^|/)Cargo\.(toml|lock)$|^rust-toolchain\.toml$|^\.github/actions/rust/|^\.github/workflows/tests\.yml$|^\.github/workflows/tests-rs-workspace\.yml$'; then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Build configuration changed — shielded tests will run"
exit 0
fi
# Capture the diff first so a git failure here is distinguishable
# from "no keyword match" — inside the pipeline the final grep's
# non-match status would mask it and fail open to "unchanged".
CONTENT_DIFF=$(mktemp)
trap 'rm -f "$CONTENT_DIFF"' EXIT
if ! git diff --no-renames --unified=0 "${{ github.event.pull_request.base.sha }}"...HEAD -- '*.rs' '*.proto' > "$CONTENT_DIFF"; then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Could not inspect changed file contents — assuming shielded changes"
exit 0
fi
# grep -v filters the +++/--- file headers so only real content
# lines are keyword-matched.
if grep -E '^[+-]' "$CONTENT_DIFF" | grep -vE '^(\+\+\+|---)' | grep -qiE "$SHIELD_RE"; then
echo "shielded-changed=true" >> "$GITHUB_OUTPUT"
echo "Changed Rust/proto lines mention shielded identifiers — shielded tests will run"
exit 0
fi
echo "shielded-changed=false" >> "$GITHUB_OUTPUT"
echo "No shielded-relevant changes — shielded tests can reuse cached coverage"
- name: Check for Swift SDK changes
id: filter-swift-sdk
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: dorny/paths-filter@v4
with:
filters: |
swift-sdk-changed:
- .github/workflows/swift-sdk-build.yml
- packages/swift-sdk/**
- packages/dapi-grpc/**
- packages/dashpay-contract/**
- packages/data-contracts/**
- packages/document-history-contract/**
- packages/dpns-contract/**
- packages/keyword-search-contract/**
- packages/masternode-reward-shares-contract/**
- packages/rs-context-provider/**
- packages/rs-dapi-client/**
- packages/rs-dash-async/**
- packages/rs-dash-platform-macros/**
- packages/rs-dpp/**
- packages/rs-dpp-json-convertible-derive/**
- packages/rs-drive/**
- packages/rs-drive-proof-verifier/**
- packages/rs-json-schema-compatibility-validator/**
- packages/rs-platform-encryption/**
- packages/rs-platform-serialization/**
- packages/rs-platform-serialization-derive/**
- packages/rs-platform-value/**
- packages/rs-platform-value-convertible/**
- packages/rs-platform-version/**
- packages/rs-platform-versioning/**
- packages/rs-platform-wallet/**
- packages/rs-platform-wallet-ffi/**
- packages/rs-platform-wallet-storage/**
- packages/rs-sdk/**
- packages/rs-sdk-ffi/**
- packages/rs-sdk-trusted-context-provider/**
- packages/rs-unified-sdk-ffi/**
- packages/simple-signer/**
- packages/token-history-contract/**
- packages/wallet-utils-contract/**
- packages/withdrawals-contract/**
# Drop @dashevo/wasm-dpp from the JS test matrix on
# `pull_request` events so the heaviest entry in the matrix
# only runs on the nightly schedule + manual
# `workflow_dispatch`. @dashevo/wasm-dpp2 stays on the PR
# path — it's a separate, lighter package that should be
# exercised on every PR. Cascading consumers
# (`dapi-client`, `wallet-lib`, `dash`, `dashmate`,
# `platform-test-suite`, `evo-sdk`) also keep running on PRs:
# their JS test code exercises behavior on top of wasm-dpp's
# already-built artifact, and `tests-build-js.yml` runs
# `yarn build` across the whole workspace so the wasm-dpp
# output is still compiled and linkable for them — just not
# test-driven on the PR critical path. To force wasm-dpp
# tests on a specific PR, use the `Run workflow`
# (workflow_dispatch) button on the Actions tab — that path
# goes through the `override` step below and runs every JS
# package.
- name: Skip wasm-dpp tests on pull_request (nightly-only)
id: prune-pr-matrix
if: ${{ github.event_name == 'pull_request' }}
run: |
set -eo pipefail
raw='${{ steps.filter-js.outputs.changes }}'
pruned=$(echo "$raw" | jq -c 'map(select(. != "@dashevo/wasm-dpp"))')
echo "js-packages=$pruned" >> "$GITHUB_OUTPUT"
echo "Pruned wasm-dpp from PR matrix:"
echo " before: $raw"
echo " after: $pruned"
- name: Override all outputs for workflow_dispatch
id: override
if: ${{ github.event_name == 'workflow_dispatch' }}
run: |
set -eo pipefail
# Extract top-level keys from filter YAML files to build JSON arrays
to_json() { yq -o=json '[keys | .[] ]' "$1" | tr -d '\n'; }
echo "js-packages=$(to_json .github/package-filters/js-packages-no-workflows.yml)" >> "$GITHUB_OUTPUT"
echo "js-packages-direct=$(to_json .github/package-filters/js-packages-direct.yml)" >> "$GITHUB_OUTPUT"
echo "rs-packages=$(to_json .github/package-filters/rs-packages-no-workflows.yml)" >> "$GITHUB_OUTPUT"
echo 'doctests-changed=true' >> "$GITHUB_OUTPUT"
echo 'shielded-changed=true' >> "$GITHUB_OUTPUT"
echo 'swift-sdk-changed=true' >> "$GITHUB_OUTPUT"
echo 'version-changed=true' >> "$GITHUB_OUTPUT"
echo 'e2e-tests-changed=true' >> "$GITHUB_OUTPUT"
build-js:
name: Build JS packages
needs:
- changes
if: ${{ needs.changes.outputs.js-packages != '[]' || needs.changes.outputs.version-changed == 'true' || needs.changes.outputs.e2e-tests-changed == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
secrets: inherit
uses: ./.github/workflows/tests-build-js.yml
build-images:
name: Build Docker images
needs:
- check-secrets
- changes
# Build Docker images for platform E2E changes, version changes, nightly schedules, or manual dispatches
if: >-
needs.check-secrets.outputs.has_ecr == 'true' &&
(needs.changes.outputs.version-changed == 'true' || needs.changes.outputs.e2e-tests-changed == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
secrets: inherit
strategy:
fail-fast: false
matrix:
include:
- name: Drive
image_name: drive
target: drive-abci
build_args: |
SDK_TEST_DATA=true
- name: RS-DAPI
image_name: rs-dapi
target: rs-dapi
- name: Dashmate helper
image_name: dashmate-helper
target: dashmate-helper
uses: ./.github/workflows/tests-build-image.yml
with:
name: ${{ matrix.name }}
image_name: ${{ matrix.image_name }}
target: ${{ matrix.target }}
build_args: ${{ matrix.build_args }}
rs-workspace-tests:
name: Rust workspace tests
needs:
- changes
if: ${{ (needs.changes.outputs.rs-packages != '[]' || needs.changes.outputs.rs-workflows-changed == 'true') && needs.changes.outputs.rs-scope != 'wallet' }}
secrets: inherit
uses: ./.github/workflows/tests-rs-workspace.yml
with:
doctests-changed: ${{ needs.changes.outputs.doctests-changed == 'true' }}
# Anything other than an explicit 'false' (including an empty output
# from a skipped detector step) fails safe into running the suite.
shielded-changed: ${{ needs.changes.outputs.shielded-changed != 'false' }}
# Fast path: only wallet crates changed, so run the scoped wallet suite
# instead of the full workspace job above (the two are mutually exclusive
# via `rs-scope`).
rs-wallet-tests:
name: Rust wallet tests
needs:
- changes
if: ${{ needs.changes.outputs.rs-scope == 'wallet' }}
secrets: inherit
uses: ./.github/workflows/tests-rs-wallet.yml
with:
doctests-changed: ${{ needs.changes.outputs.doctests-changed == 'true' }}
swift-sdk-build:
name: Swift SDK build
needs:
- changes
- rs-workspace-tests
- rs-wallet-tests
# At most one of the two Rust jobs runs (none for e.g. Swift-only PRs);
# skipped jobs report result 'skipped', not 'failure', so this only
# blocks on a Rust job that actually ran and failed.
# Untrusted fork PRs must not reach the self-hosted Swift runner — same
# trusted-fork policy as the callee guard in swift-sdk-build.yml.
if: >-
${{ always()
&& (github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name == github.repository
|| github.event.pull_request.head.repo.owner.login == 'thepastaclaw')
&& needs.changes.outputs.swift-sdk-changed == 'true'
&& needs.changes.result != 'failure'
&& needs.rs-workspace-tests.result != 'failure'
&& needs.rs-wallet-tests.result != 'failure' }}
secrets: inherit
uses: ./.github/workflows/swift-sdk-build.yml
js-packages:
name: JS packages
needs:
- changes
- build-js
if: ${{ needs.changes.outputs.js-packages != '[]' }}
secrets: inherit
strategy:
fail-fast: false
matrix:
js-package: ${{ fromJson(needs.changes.outputs.js-packages) }}
uses: ./.github/workflows/tests-js-package.yml
with:
package: ${{ matrix.js-package }}
# The platform test suite's default command drives a live network, so it
# runs from the E2E jobs. Its unit tests need nothing and run here.
test-command: ${{ (matrix.js-package == 'dashmate' || contains(matrix.js-package, 'platform-test-suite')) && 'test:unit' || 'test' }}
direct-packages: ${{ needs.changes.outputs.js-packages-direct }}
js-deps-versions:
name: JS dependency versions check
if: ${{ github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' || !github.event.pull_request.draft }}
runs-on: ubuntu-24.04
steps:
- name: Check out repo
uses: actions/checkout@v4
- name: Setup Node.JS
uses: actions/setup-node@v4
with:
node-version: "24"
- name: Enable corepack
run: corepack enable
- name: Validate workspaces
run: yarn constraints
dashmate-e2e-tests:
name: Dashmate E2E tests
secrets: inherit
needs:
- changes
- build-js
- build-images
- check-secrets
strategy:
fail-fast: false
matrix:
include:
- name: Local network
test-pattern: test/e2e/localNetwork.spec.js
restore_local_network_data: true
- name: Testnet fullnode
test-pattern: test/e2e/testnetFullnode.spec.js
restore_local_network_data: false
- name: Testnet Evonode
test-pattern: test/e2e/testnetEvonode.spec.js
restore_local_network_data: false
uses: ./.github/workflows/tests-dashmate.yml
with:
name: ${{ matrix.name }}
test-pattern: ${{ matrix.test-pattern }}
restore_local_network_data: ${{ matrix.restore_local_network_data }}
if: >-
always() &&
needs.check-secrets.outputs.has_ecr == 'true' &&
needs.build-js.result == 'success' &&
needs.build-images.result == 'success' &&
(needs.changes.outputs.version-changed == 'true' || needs.changes.outputs.e2e-tests-changed == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
test-suite:
name: Test Suite
needs:
- changes
- build-js
- build-images
- check-secrets
secrets: inherit
if: >-
always() &&
needs.check-secrets.outputs.has_ecr == 'true' &&
needs.build-js.result == 'success' &&
needs.build-images.result == 'success' &&
(needs.changes.outputs.version-changed == 'true' || needs.changes.outputs.e2e-tests-changed == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
strategy:
fail-fast: false
matrix:
include:
- name: Test Suite
command: test:suite
batch_index: 0
batch_total: 0
- name: Test Suite in browser (1)
command: test:browsers
batch_index: 0
batch_total: 2
- name: Test Suite in browser (2)
command: test:browsers
batch_index: 1
batch_total: 2
uses: ./.github/workflows/tests-test-suite.yml
with:
name: ${{ matrix.name }}
command: ${{ matrix.command }}
batch_total: ${{ matrix.batch_total }}
batch_index: ${{ matrix.batch_index }}
test-functional:
name: Packages functional tests
needs:
- changes
- build-js
- build-images
- check-secrets
secrets: inherit
if: >-
always() &&
needs.check-secrets.outputs.has_ecr == 'true' &&
needs.build-js.result == 'success' &&
needs.build-images.result == 'success' &&
(needs.changes.outputs.version-changed == 'true' || needs.changes.outputs.e2e-tests-changed == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/tests-packges-functional.yml