Files
OwnCord/.github/workflows/ci.yml
T
J3vbandClaude Fable 5 03fcb7d518 fix: execute the 2026-08-19 audit fix order (docs refresh + five FRAGILE fixes) (#1396)
* docs(plans): phased remediation plan for the 2026-08-19 audit

Executes the audit's §8 MUST-fix verdict and §9.1 fix order: one phase per
finding group, statuses updated in place as phases land.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* test(client): give the renderWindow-breaker test its own timeout (audit F-5)

30 synchronous 100-row jsdom rebuilds can exceed vitest's default 5s on a
loaded runner; the test timed out once under CI-like load and passes in
isolation, so it now carries an explicit 20s budget.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* docs: fix the ten wrong reference-doc statements from audit 2026-08-19 (B-01..B-10)

schema.md: migrations 030/031 documented, attachments ON DELETE SET NULL
(matching 030's rebuild), index inventory rewritten from cumulative migration
state, writer/reader pool split described, default-roles table made a
consistent post-migration snapshot, dbgen preamble updated.

protocol.md: DM chat events documented as sequenced/ring-buffered/replayable
(they are), plugin_broadcast seq flipped to Yes, retry_after claim removed
(no WS error carries it), the five enforced-but-documented-as-None rate
limits added (channel_focus, mark_read, call_decline, chat_command, ping),
E2EE announce/offer budgets corrected incl. the per-target inner cap,
BAD_PAYLOAD and NOT_KEY_HOLDER added to the error table, ready voice_states/
roles field lists completed, member_join top-level status documented.

api.md: diagnostics endpoint is ADMINISTRATOR-only (H-8) with a per-IP
limiter and host:port livekit_url, error-code table now matches emitted codes
(INTERNAL_ERROR, STORAGE_ERROR 507; oversize upload is 400), body-cap
exemptions listed, identity_public_key documented on PATCH /users/me, plugin
endpoints' plain-text errors + X-Plugin-Runtime header documented, /health
503 degraded state documented, metrics/LiveKit CIDR keys named, updates/apply
restart-conflict 409s added.

Also folds in the audit's D-04/D-05 comment and plan-header staleness fixes
(buildReady comment, e2e spec-count comments, logctx stray word, three plan
status headers).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* fix(server): log the five silently-discarded persistence errors (audit F-3/F-4/D-16)

Lockout Upsert/Delete/Cleanup failures (auth/ratelimit.go), the H-6
session-cap eviction failure in CreateSession (db/auth_queries.go), and the
channel_focus read-state write failure (service/channel.go) all discarded
their errors with no trace — a brute-force lockout could silently fail to
survive a restart. In-memory behavior is unchanged (warn-and-continue); the
lockout write paths are pinned by tests mirroring OC-0061's load-path test.
The session-cap and read-state sites are log-only additions on seams the
existing suites already exercise on the success path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* fix(dm): blocking a user evicts them from the pair's live 1:1 DM voice call (audit F-1)

The block gate ran only at voice_join and voluntary voice_token_refresh, so
a blocked user already in the shared 1:1 DM call kept their session
indefinitely — the same guard-asymmetry family as A-2026-08-03. handleBlockUser
now severs the call through the dmVoiceEvictor capability handleCloseDM
already exercises, using a new find-only FindDMChannelIDBetween lookup
(sqlc-generated; mirrors GetOrCreateDMChannel's is_group=0 clause so group
DM calls stay exempt, matching requireDMNotBlocked). Pinned by three handler
tests: shared-DM eviction, no-DM no-op, group-only no-op.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* fix(ws): close the role-reassignment/handshake race (audit F-2)

A role reassignment landing mid-handshake was invisible for the socket's
whole life: both handshake paths resolved permissions from the auth-time
c.user snapshot, revokeUnreadableChannels early-returns for a user not yet
in h.clients, and its Unsubscribe no-ops on the pubsub identity guard once a
reconnect replaced the client.

Three coordinated fixes: (1) refreshUserSnapshot re-reads the user row (and
role name) in reconnectPrecheck and handleFreshConnect, fail-closed; (2) the
resume-fallback path re-reads the role once more after registerNow and runs
the revocation pass when it moved, so the reassignment-vs-registration
orderings meet in the middle; (3) revokeUnreadableChannels re-resolves the
live client immediately before acting, mirroring RefreshChannelVisibility.
Pinned by four tests driving real WS handshakes through the existing race
hooks plus a new pre-register/pre-act hook pair; ws suite green under the
default and deadlock builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* refactor(client): remove the inert replay-dedup machinery (audit F-6)

The server writes auth_ok before the replay burst, so replayDedup — created
on socket-open and cleared when auth_ok is processed — could never be active
for a real replayed frame, and the dispatcher's isReplaying() unread gates
never fired. Their no-op behavior is the correct behavior (a buffer/db
resume has no ready payload, so replayed frames must count as unread), so
the machinery, the gates, and the misleading comments are removed rather
than repaired. The pinning tests injected replay frames in an order a
spec-compliant server never produces; they are replaced by a test pinning
the real contract (frames after auth_ok are dispatched verbatim; duplicate
handling belongs to the stores). Client suite green: 5036/5036.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* docs(plans): mark remediation phases 1-6 done

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

* fix(ws): nolint the context-less revoke call golangci-lint flags

revokeUnreadableChannels takes no context by design (admin HubBroadcaster
interface); annotate the one call site inside a ctx-taking function, matching
the RefreshChannelVisibility precedent. golangci-lint v2.11.3: 0 issues.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HtkxwdqE4pUv82GQPRsTeQ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-20 03:49:13 +02:00

511 lines
20 KiB
YAML

name: CI
on:
# dev is deliberately not a push trigger: while a dev -> main PR is open every
# push to dev already fires pull_request(synchronize), so listing it here ran
# the whole suite twice for one push. Use workflow_dispatch for a dev branch
# with no PR open yet.
push:
branches: [main]
pull_request:
branches: [main, dev]
workflow_dispatch:
# Cancel in-progress runs for the same branch/PR
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
server-build-test:
name: Server Build & Test (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
binary: chatserver.exe
- os: ubuntu-latest
binary: chatserver
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: Server/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: "1.26"
cache-dependency-path: Server/go.sum
- name: Build server
run: go build -o ${{ matrix.binary }} -ldflags "-s -w" .
# Phase B + C build-tag matrix. Each tag variant must compile so the
# tag boundaries don't drift.
- name: Build with -tags otel (Phase B Step 8)
run: go build -tags otel ./...
- name: Build with -tags wazero (Phase C Step 9)
run: go build -tags wazero ./...
- name: Build with -tags otel,wazero (full community-hub build)
run: go build -tags otel,wazero ./...
- name: Go vulnerability check
run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 && govulncheck ./...
# Generated sqlc output must never drift from db/queries/. One leg of
# the matrix is enough; make is not guaranteed on the Windows runner.
- name: Verify generated sqlc output (make sqlc-verify)
if: matrix.os == 'ubuntu-latest'
run: make sqlc-install sqlc-verify
# Protocol message-type constants (Go + TS) must never drift from
# docs/protocol-schema.json — the single source of truth.
- name: Verify generated protocol constants (make protocol-verify)
if: matrix.os == 'ubuntu-latest'
run: make protocol-verify
- name: Run tests with race detection and coverage
run: go test -race -timeout 20m ./... -coverprofile=coverage.out -cover
- name: Run tests with deadlock detection
run: go test -tags deadlock -count=1 ./...
# Tag-gated tests (DC-06 / T-2026-07-25-16). The build-tag matrix above
# only COMPILES the otel/wazero variants; the tests behind those tags
# (plugin/sandbox_wazero_test.go, telemetry/telemetry_otel_test.go) ran
# nowhere until this step. Scoped to the two packages that carry tagged
# files — every other package is tag-invariant and already covered by the
# race run above. One leg is enough; no -race (the runtime under the tag
# is the concern, not new concurrency).
- name: Run tag-gated tests (-tags wazero, -tags otel)
if: matrix.os == 'ubuntu-latest'
run: |
go test -tags wazero -count=1 ./plugin/...
go test -tags otel -count=1 ./telemetry/...
- name: Upload Go coverage
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: go-coverage-${{ matrix.os }}
path: Server/coverage.out
retention-days: 7
# verify: false — the action's default `config verify` pass fetches
# golangci-lint.run's JSONSchema over HTTPS before linting anything, so a
# timeout on that host fails a required job having run zero linters (it
# took main red on d352696). `golangci-lint run` rejects a bad config on
# its own; the schema pass only bought a prettier error message, priced
# at a third-party site inside the gate.
- name: Lint
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.11.3
working-directory: Server/
verify: false
# ubuntu-latest deliberately: the client TS code has zero win32-conditional
# paths (no process.platform / path.sep branches in src or the unit suites),
# prettier pins endOfLine: lf and .gitattributes forces eol=lf, so a Windows
# runner adds queue time without adding coverage. Windows-specific behavior
# is covered where it exists: rust-tests and the tauri-build matrix.
client-check:
name: Client Static Checks
runs-on: ubuntu-latest
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install npm dependencies
run: npm ci
# Scoped to shipped dependencies. The remaining high findings are all one
# advisory, brace-expansion <=5.0.7, reaching us only through dev tooling
# (eslint, @vitest/coverage-v8, stryker). Those are already on their
# latest versions, so no bump reaches the fix, and there is no patched
# release in the 1.x/2.x lines they pin. Forcing every copy to 5.0.9 via
# overrides was tried and broke the build: minimatch requires
# brace-expansion as CJS and v5 is not callable that way, which took out
# vitest's coverage provider. Nothing here ships to users; revisit when
# eslint and @vitest/coverage-v8 widen their minimatch ranges.
- name: Security audit (npm, shipped deps)
run: npm audit --omit=dev --audit-level=high
- name: Oxlint (fast correctness checks)
run: npx oxlint src/
- name: TypeScript check
run: npx tsc --noEmit
- name: TypeScript check (Playwright specs)
# The main tsconfig excludes tests/e2e from the app graph; this
# project typechecks every tests/e2e spec + fixtures + the
# playwright configs so type rot cannot hide there.
run: npx tsc -p tsconfig.e2e.json --noEmit
- name: ESLint (type-aware rules)
run: npx eslint src/
- name: Prettier format check
run: npx prettier --check "src/**/*.ts" "tests/**/*.ts"
- name: Knip (unused code & deps)
# Blocking since the 2026-08-04 remediation: the '|| true' era let a
# real unused-export finding sit invisible in every green run.
run: npx knip
# Unit tests live in their own job so a suite failure is visible as exactly one
# failing check instead of masking the static gates above. The suite is GREEN
# and must stay green — never "fix" a failing test by editing its assertions.
# ubuntu-latest for the same reason as client-check above: jsdom-only vitest
# with no platform-conditional code under test.
client-tests:
name: Client Unit Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install npm dependencies
run: npm ci
- name: Run unit tests with coverage
run: npx vitest run --coverage --reporter=default
- name: Upload client coverage
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: client-coverage
path: Client/tauri-client/coverage/
retention-days: 7
# Rust unit tests used to live inside tauri-build, which only runs on PRs to
# main — so #[cfg(test)] code never ran on pushes or on PRs to dev, and could
# rot for a whole release cycle. This job runs them on every event. Clippy is
# run with --all-targets here (tauri-build's lib-only clippy skips test code).
rust-tests:
name: Rust Unit Tests
runs-on: ubuntu-22.04
timeout-minutes: 30
defaults:
run:
working-directory: Client/tauri-client/src-tauri/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Install Linux system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
libsecret-1-dev \
libdbus-1-dev \
libasound2-dev \
libssl-dev \
librsvg2-dev
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- name: Rust cache
uses: swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: Client/tauri-client/src-tauri
- name: Clippy lint (including test targets)
run: cargo clippy --all-targets -- -D warnings
- name: Rust unit tests
run: cargo test --lib
# Playwright e2e against the mocked-Tauri dev server. Runaway protection
# lives in playwright.config.ts (maxFailures: 20 aborts a systemic cascade
# early; globalTimeout: 20 min self-terminates with a usable report) with
# timeout-minutes below as the outer backstop.
#
# BLOCKING since 2026-08-05 (DC-07): the post-repair soak recorded green
# full-suite runs at 270, 276 and 291 tests across the 08-04/08-05 audit
# branches, and the one hard CI failure in that window was a real spec bug
# (updater install-settle race), which a non-blocking job would have let
# rot. retries: 2 absorbs the known rare flake class (see E2E-ISSUES.md's
# flake accounting).
# See docs/audit-test-coverage-2026-07-25.md T-2026-07-25-21.
# The native config (playwright.config.native.ts) is deliberately not wired
# up — it needs a real server and a built desktop binary.
client-e2e:
name: Client E2E (Playwright)
runs-on: ubuntu-latest
timeout-minutes: 25
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install npm dependencies
run: npm ci
- name: Install Playwright browser
run: npx playwright install --with-deps chromium
- name: Run Playwright tests
run: npx playwright test --config=playwright.config.ts
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-report
path: |
Client/tauri-client/playwright-report/
Client/tauri-client/test-results/
retention-days: 7
# Admin-panel journey against a REAL server (no mocks): start-server.sh
# builds the Go binary and boots it with a fresh temp data dir, and the
# suite drives the embedded SPA through the first-run wizard, dashboard,
# channel CRUD, audit log and re-login — the one DC-04 surface the mocked
# suites cannot reach. Non-blocking while it earns its soak, same
# graduation convention client-e2e followed.
# GRADUATION CRITERION (recorded 2026-08-15): flip continue-on-error to
# false once the job has ~30 consecutive green runs on main with no
# infra-flake reruns — the same evidence bar client-e2e cleared (270+ green
# runs cited in docs/audit-2026-08-04-docs-and-coverage.md) scaled to this
# job's lower traffic. Check with: gh run list -w CI -b main --json
# conclusion | jq '[.[] | .conclusion] | index("failure")'.
admin-e2e:
name: Admin Panel E2E (real server, non-blocking)
runs-on: ubuntu-latest
continue-on-error: true
timeout-minutes: 20
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
with:
go-version: "1.26"
cache-dependency-path: Server/go.sum
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install npm dependencies
run: npm ci
- name: Install Playwright browser
run: npx playwright install --with-deps chromium
- name: Run admin-panel journey
run: npx playwright test --config=playwright.config.admin.ts
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: admin-e2e-report
path: |
Client/tauri-client/playwright-report/
Client/tauri-client/test-results/
retention-days: 7
# Blocking e2e subset: the parity-feature specs (tagged "@parity"), covering
# the wire paths added in v1.2.0 (mentions/badges, per-channel mute, NSFW
# gate, group DMs, role change, custom-emoji autocomplete, voice moderation).
# These are new and authored green, so unlike the full legacy suite above they
# gate PRs: a regression on one of these features must fail CI. Kept as its own
# job (not folded into the non-blocking suite) so the legacy suite can keep
# earning its "few green pushes" before it too graduates to blocking.
client-e2e-parity:
name: Client E2E (parity subset, blocking)
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install npm dependencies
run: npm ci
- name: Install Playwright browser
run: npx playwright install --with-deps chromium
- name: Run parity e2e specs
run: npx playwright test --config=playwright.config.ts --grep "@parity"
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-report-parity
path: |
Client/tauri-client/playwright-report/
Client/tauri-client/test-results/
retention-days: 7
# Image build is verification only, so it is skipped on dev to keep day-to-day
# work on the fast check suite. Runs for main pushes and PRs targeting main.
server-docker-build:
name: Server Docker Build (verify)
if: github.ref_name == 'main' || github.base_ref == 'main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Build image (no push)
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: Server/
push: false
load: true
tags: owncord-smoke:candidate
build-args: VERSION=ci
cache-from: type=gha
cache-to: type=gha,mode=max
# Same script release.yml runs before it signs or pushes anything. A
# boot regression — or a bug in the smoke harness itself, as happened on
# the first v1.2.0-alpha.3 release run — must fail here, not at tag time.
- name: Boot-smoke Docker image
run: bash Server/scripts/docker-smoke.sh owncord-smoke:candidate
# Full Tauri build only on PRs to main (expensive: ~15 min x2 multiplier).
#
# Skipped for Dependabot: its PRs run under the separate `dependabot` secrets
# scope, so TAURI_SIGNING_PRIVATE_KEY arrives empty and `npm run tauri build`
# always aborts with "failed to decode secret key" while signing the updater
# artifact — after a successful compile and bundle. That burned ~50 min of
# runner time per dependency PR to produce a red check that never carried any
# signal. Granting Dependabot the signing key would fix the symptom but hands
# a release key to workflows triggered by third-party dependency updates.
#
# What still covers Dependabot PRs: the required `rust-tests` job compiles the
# crate (cargo clippy --all-targets + cargo test --lib), so a dependency bump
# that breaks the Rust build is still caught.
# What this gives up on those PRs: bundling (NSIS/AppImage/deb), Windows and
# ARM-specific compilation, and the `cargo audit` step below — that last one
# overlaps with Dependabot's own cargo scanning, which is what opens these PRs
# in the first place.
tauri-build:
name: Tauri Full Build (${{ matrix.os }})
needs: client-check
if: >-
github.event_name == 'pull_request'
&& github.base_ref == 'main'
&& github.actor != 'dependabot[bot]'
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
- os: ubuntu-22.04
- os: ubuntu-22.04-arm
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: Client/tauri-client/
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20
cache: npm
cache-dependency-path: Client/tauri-client/package-lock.json
- name: Install Linux system dependencies
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
libsecret-1-dev \
libdbus-1-dev \
libasound2-dev \
libssl-dev \
patchelf \
librsvg2-dev \
xdg-utils
- name: Install Rust
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
with:
components: clippy
- name: Rust cache
uses: swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
workspaces: Client/tauri-client/src-tauri
- name: Install npm dependencies
run: npm ci
- name: Clippy lint (Rust)
working-directory: Client/tauri-client/src-tauri/
run: cargo clippy -- -D warnings
# Rust unit tests moved to the standalone `rust-tests` job so they run on
# every event, not just PRs to main.
- name: Security audit (Rust dependencies)
working-directory: Client/tauri-client/src-tauri/
run: |
cargo install cargo-audit@0.22.1 --quiet
cargo audit
- name: Build Tauri app
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: npm run tauri build