Skip to content

fix(mobile): address F-Droid review — forky node, module subdir, drop… #194

fix(mobile): address F-Droid review — forky node, module subdir, drop…

fix(mobile): address F-Droid review — forky node, module subdir, drop… #194

Workflow file for this run

# .github/workflows/guardian.yml
#
# Sidecoin Monorepo CI Suite
# Runs on every push/PR to master across all packages.
#
# IMPORTANT: All cargo commands use --locked to ensure deterministic
# builds from the committed Cargo.lock. Without --locked, Cargo may
# resolve newer transitive dependencies (e.g. tauri-runtime) that
# introduce breaking trait changes and fail compilation.
name: Sidecoin CI Suite
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Force any remaining JavaScript actions onto the Node.js 24 runtime.
# After replacing pnpm/action-setup (corepack) and wrangler-action
# (npx wrangler) below, the only Node-20 action left is the transitive
# actions/github-script pulled in by codecov-action — which we cannot
# version-pin directly. This flag keeps it running on Node 24 so it does
# not break after the Sept 16 2026 Node-20 removal. Drop once codecov
# ships a Node 24 release.
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
guardian:
name: desktop-client (${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
env:
WEBVIEW2_LINK_STATIC: "1"
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt, llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ runner.os }}-v2
workspaces: "./apps/desktop/src-tauri -> target"
- name: Install Linux dependencies
if: matrix.platform == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf \
xvfb \
webkit2gtk-driver
cargo install tauri-driver
- name: Install Frontend dependencies
run: pnpm install --frozen-lockfile
# ── Shared ──────────────────────────────────────────────
- name: Type-check Shared
run: pnpm --filter @sidecoin/shared build
# ── Desktop — Placeholder Dist ──────────────────────────
#
# Tauri's generate_context!() proc macro validates that
# frontendDist ("../dist") exists at compile time. This
# placeholder must exist BEFORE any cargo command that
# compiles the Tauri app (clippy, build, llvm-cov, etc.).
# It is replaced by the real frontend build later.
# ────────────────────────────────────────────────────────
- name: Create Placeholder Dist
shell: bash
run: mkdir -p apps/desktop/dist && touch apps/desktop/dist/index.html
# ── Desktop — Rust Quality Gates ────────────────────────
- name: Check Rust Formatting
working-directory: apps/desktop/src-tauri
run: cargo fmt --all -- --check
- name: Clippy Lint
working-directory: apps/desktop/src-tauri
run: cargo clippy --locked --all-features --lib -- -D warnings
# ── Desktop — Build ─────────────────────────────────────
- name: Generate Types (Specta)
shell: bash
working-directory: apps/desktop/src-tauri
run: |
cargo run --locked --bin export_types
node -e "
const fs = require('fs');
const path = require('path');
const f = path.join('..', 'src', 'bindings.ts');
if (fs.existsSync(f)) {
const content = fs.readFileSync(f, 'utf8');
if (!content.startsWith('//@ts-nocheck')) {
fs.writeFileSync(f, '//@ts-nocheck\n' + content);
}
}
"
- name: Build Desktop Frontend
run: pnpm --filter @sidecoin/desktop exec vite build
- name: Build Tauri App
working-directory: apps/desktop/src-tauri
run: cargo build --locked
# ── Desktop — Tests ─────────────────────────────────────
- name: Run Rust Unit Tests (with coverage)
if: matrix.platform != 'windows-latest'
working-directory: apps/desktop/src-tauri
shell: bash
run: cargo llvm-cov --locked --all-features --lib --lcov --output-path lcov-rust.info
- name: Run Desktop Frontend Tests
run: pnpm --filter @sidecoin/desktop test
- name: Run Desktop Type Check
run: pnpm --filter @sidecoin/desktop exec vue-tsc --noEmit --skipLibCheck
# ── Desktop — E2E ───────────────────────────────────────
- name: Run E2E Tests
if: matrix.platform == 'ubuntu-latest'
continue-on-error: true
env:
CI: true
GDK_BACKEND: x11
WEBKIT_DISABLE_COMPOSITING_MODE: "1"
shell: bash
run: xvfb-run --auto-servernum pnpm --filter @sidecoin/desktop test:e2e
# ── Coverage Upload ─────────────────────────────────────
- name: Verify coverage file exists
if: matrix.platform == 'ubuntu-latest'
working-directory: apps/desktop/src-tauri
shell: bash
run: |
if [ -f lcov-rust.info ]; then
echo "✅ Coverage file found ($(wc -l < lcov-rust.info) lines)"
head -5 lcov-rust.info
else
echo "❌ Coverage file NOT found"
ls -la
exit 1
fi
- name: Upload Rust Coverage
if: matrix.platform == 'ubuntu-latest'
uses: codecov/codecov-action@v5
with:
files: apps/desktop/src-tauri/lcov-rust.info
flags: rust
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload Desktop Frontend Coverage
if: matrix.platform == 'ubuntu-latest'
uses: codecov/codecov-action@v5
with:
files: apps/desktop/coverage/lcov.info
flags: desktop-frontend
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── Wallet (standalone, labeled job) ─────────────────────
#
# Pure TS/Vite — runs once on ubuntu (no Rust/matrix needed).
# Appears as its own "wallet" entry in the Actions sidebar so
# a failure here is immediately distinguishable from the
# desktop/web/mobile/api legs. Builds @sidecoin/shared first
# (wallet depends on it). deploy-wallet gates on this job.
#
# Test runs with --coverage.reporter=lcov so the v8 provider
# emits coverage/lcov.info for the Codecov upload below. lcov
# is NOT a default vitest reporter, so it must be requested
# explicitly on the CLI (keeps local `pnpm test` coverage-free).
# The `--` separator forwards the flags to vitest rather than
# letting pnpm try to parse them as its own options.
# ─────────────────────────────────────────────────────────
wallet:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Wallet
run: pnpm --filter @sidecoin/wallet build
- name: Test Wallet
run: pnpm --filter @sidecoin/wallet test -- --coverage --coverage.reporter=lcov
- name: Type-check Wallet
run: pnpm --filter @sidecoin/wallet type-check
- name: Upload Wallet Coverage
uses: codecov/codecov-action@v5
with:
files: apps/wallet/coverage/lcov.info
flags: wallet
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── Mobile (standalone, labeled job) ─────────────────────
#
# React Native / Jest — runs once on ubuntu (no Rust/matrix
# needed). Appears as its own "mobile" entry in the Actions
# sidebar so a failure here is immediately distinguishable
# from the desktop/web/api legs.
#
# Builds @sidecoin/shared first: the App test imports
# @sidecoin/shared/chain and @sidecoin/shared/sidechains.
# ─────────────────────────────────────────────────────────
mobile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Test Mobile
run: pnpm --filter @sidecoin/mobile test
# ── Web — Landing Site (standalone, labeled job) ─────────
#
# Pure TS/Vite — runs once on ubuntu. Appears as its own
# "web" entry in the Actions sidebar. Builds @sidecoin/shared
# first (web depends on it), then builds + tests the site.
# deploy-web gates on this job.
# ─────────────────────────────────────────────────────────
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Web
run: pnpm --filter @sidecoin/web build
- name: Test Web
run: pnpm --filter @sidecoin/web test
# ── Explorer — Chain-aware Block Explorer (standalone, labeled job) ──
#
# Pure TS/Vite/Vue — runs once on ubuntu. Appears as its own
# "explorer" entry in the Actions sidebar so explorer regressions
# are immediately distinguishable from wallet/web/api failures.
# Builds @sidecoin/shared first for consistency with other frontend
# packages, then builds + tests + type-checks the explorer app.
# Deployment is intentionally added in a separate commit.
# ─────────────────────────────────────────────────────────
explorer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Explorer
run: pnpm --filter @sidecoin/explorer build
- name: Test Explorer
run: pnpm --filter @sidecoin/explorer test -- --coverage --coverage.reporter=lcov
- name: Type-check Explorer
run: pnpm --filter @sidecoin/explorer type-check
- name: Upload Explorer Coverage
uses: codecov/codecov-action@v5
with:
files: apps/explorer/coverage/lcov.info
flags: explorer
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── Smart Hub — Secure Portal Challenge (standalone, labeled job) ──
#
# Pure TS/Vite/Vue — runs once on ubuntu. Appears as its own
# "smarthub" entry in the Actions sidebar so portal regressions
# are immediately distinguishable from wallet/web/explorer/api failures.
# Builds + tests + type-checks the Smart Hub landing page.
# deploy-smarthub gates on this job.
# ─────────────────────────────────────────────────────────
smarthub:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Smart Hub
run: pnpm --filter @sidecoin/smarthub build
- name: Test Smart Hub
run: pnpm --filter @sidecoin/smarthub test -- --coverage --coverage.reporter=lcov
- name: Type-check Smart Hub
run: pnpm --filter @sidecoin/smarthub type-check
- name: Upload Smart Hub Coverage
uses: codecov/codecov-action@v5
with:
files: apps/smarthub/coverage/lcov.info
flags: smarthub
fail_ci_if_error: false
verbose: true
token: ${{ secrets.CODECOV_TOKEN }}
# ── API client (standalone, labeled job) ─────────────────
#
# Pure TS — runs once on ubuntu (no Rust/matrix needed).
# Appears as its own "api" entry in the Actions sidebar so
# a failure here is immediately distinguishable from the
# desktop/web/wallet legs. Each named step (Test/Type-check)
# pinpoints exactly which check broke.
#
# NOTE: the API adapter (formerly @sidecoin/api, the Cloudflare
# Worker) has been extracted to its own repository:
# https://github.com/APECSdev/sidecoin-api — it is no longer
# built or deployed from this monorepo. This job now covers only
# the @sidecoin/api-client package that remains here.
# ─────────────────────────────────────────────────────────
api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Test API client
run: pnpm --filter @sidecoin/api-client test
- name: Type-check API client
run: pnpm --filter @sidecoin/api-client typecheck
# ── Cloudflare Pages — Landing Site ──────────────────────
#
# Deploys on every push to master after all CI jobs pass.
# PRs do NOT deploy — only merged commits to master.
# ─────────────────────────────────────────────────────────
deploy-web:
needs: web
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment:
name: production-web
url: https://sidecoin.app
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Web
run: pnpm --filter @sidecoin/web build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy apps/web/dist --project-name=sidecoin --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# ── Cloudflare Pages — Wallet App ────────────────────────
deploy-wallet:
needs: wallet
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment:
name: production-wallet
url: https://wallet.sidecoin.app
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Wallet
run: pnpm --filter @sidecoin/wallet build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy apps/wallet/dist --project-name=sidecoin-wallet --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# ── Cloudflare Pages — Explorer App ──────────────────────
deploy-explorer:
needs: explorer
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment:
name: production-explorer
url: https://explorer.sidecoin.app
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Shared
run: pnpm --filter @sidecoin/shared build
- name: Build Explorer
run: pnpm --filter @sidecoin/explorer build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy apps/explorer/dist --project-name=sidecoin-explorer --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# ── Cloudflare Pages — Smart Hub ─────────────────────────
deploy-smarthub:
needs: smarthub
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment:
name: production-smarthub
url: https://hub.sidecoin.app
steps:
- uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: "22"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Smart Hub
run: pnpm --filter @sidecoin/smarthub build
- name: Deploy to Cloudflare Pages
run: npx wrangler pages deploy apps/smarthub/dist --project-name=sidecoin-hub --commit-dirty=true
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}