Skip to content

chore(deps-dev): bump eslint from 9.39.5 to 10.7.0 in /ui #219

chore(deps-dev): bump eslint from 9.39.5 to 10.7.0 in /ui

chore(deps-dev): bump eslint from 9.39.5 to 10.7.0 in /ui #219

Workflow file for this run

name: ci
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
server:
# Self-hosted watcher-runners (meshed) so the cargo build uses the shared
# in-cluster sccache redis. The runners now carry a postgres sidecar (cluster
# repo: charts/actions/runners/values-watcher.yaml) reachable at localhost:5432,
# so the ARC-can't-run-a-service-container reason for staying hosted is gone.
runs-on: watcher-runners
env:
DATABASE_URL: postgres://watcher:watcher@localhost:5432/watcher
# sccache → shared in-cluster redis (cluster repo: charts/sccache). Reachable
# only through Linkerd mTLS (the watcher runner identity is admitted); it
# carries no credentials, so it lives here rather than a secret.
# CARGO_INCREMENTAL=0 — sccache can't cache incremental artefacts.
RUSTC_WRAPPER: sccache
SCCACHE_REDIS: redis://sccache-redis.dev.svc.cluster.local:6379
CARGO_INCREMENTAL: "0"
defaults:
run:
working-directory: server
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
cache-targets: false
workspaces: server
# Stable key shared across branches/PRs (not the per-branch default), so a
# PR's first run restores main's warm target/ instead of compiling cold.
shared-key: watcher-server
- name: Install sccache
# --force: rust-cache restores cargo's "already installed" metadata on a warm
# cache, but not the binary, so a plain binstall skips and sccache is absent
# from PATH (RUSTC_WRAPPER then fails). Force a real install every run.
run: cargo binstall --no-confirm --force sccache
# The postgres sidecar boots in parallel with the runner container; block until
# it accepts TCP before building/testing. bash /dev/tcp avoids needing a client.
- name: Wait for postgres sidecar
run: |
for i in $(seq 1 60); do
(echo > /dev/tcp/127.0.0.1/5432) >/dev/null 2>&1 && { echo "postgres up after ${i}s"; exit 0; }
sleep 1
done
echo "postgres sidecar never came up" >&2; exit 1
- run: cargo fmt --check
# clippy replaces a standalone `cargo build`: it's check-speed (no codegen) and
# gates the compile too, while `cargo test` below does the actual codegen. Only
# the workspace crate runs through clippy-driver; deps still compile via sccache.
# -D warnings matches the repo's warnings-as-errors policy.
- run: cargo clippy --locked --all-targets -- -D warnings
- run: cargo test --locked # ingest->query integration test against the sidecar DB
- name: sccache stats
if: always()
run: sccache --show-stats
ui:
runs-on: watcher-runners
defaults:
run:
working-directory: ui
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
cache-dependency-path: ui/package-lock.json
- run: npm ci
# Accessibility floor (JEF-431): eslint-plugin-jsx-a11y gates keyboard-
# operable rows, labeled charts, and no silent-live tables from regressing.
- run: npm run lint
# Runtime a11y route-smoke (JEF-442) runs inside `npm test`: each top-level
# route is mounted (jsdom, API mocked) and scanned by axe-core, failing on
# serious/critical structural violations. Complements the static lint above —
# it catches ARIA that only resolves against the rendered tree.
- run: npm test
- run: npm run build
# One image now: the server builds the UI and embeds it (rust-embed), so there
# is no separate watcher-ui image. Build context is the repo root.
#
# Native per-arch on the self-hosted runner (watcher-runners), offloading to the
# two in-cluster BuildKit builders — amd64 on `buildkit` (node-3), arm64 on
# `buildkit-arm64` (an arm64 Pi) — each building NATIVELY, no QEMU. BuildKit
# enforces mTLS, so we point the remote driver at the client cert the runner
# already mounts (BUILDKIT_TLS_DIR) and verify each endpoint against its
# servername; without the cert the gRPC handshake is rejected. The build also pushes a layer cache to GHA
# (cache-from/to type=gha): paired with cargo-chef in the Dockerfile, the dep
# compile becomes a portable layer any node can pull — unlike the per-node
# BuildKit daemon cache, which a cold node can't reach.
image:
needs: [server, ui]
if: github.ref == 'refs/heads/main'
runs-on: watcher-runners
permissions:
contents: read
packages: write
id-token: write # keyless cosign signing (OIDC token -> Sigstore Fulcio)
steps:
- uses: actions/checkout@v7
- name: Connect to BuildKit (mTLS, native per-arch)
# Two native builders share one CA (cluster: charts/actions/buildkit +
# values-arm64.yaml): amd64 on `buildkit` (node-3), arm64 on `buildkit-arm64`
# (an arm64 Pi). buildx --append joins them into one builder so each platform
# builds NATIVELY and buildx merges the manifest — no QEMU (arm64 Rust under
# QEMU ran for hours). The runner's existing client cert (BUILDKIT_TLS_DIR)
# authenticates to both; each endpoint verifies its own server SAN via servername.
env:
BUILDKIT_ARM64_HOST: tcp://buildkit-arm64.dev.svc.cluster.local:1234
BUILDKIT_ARM64_TLS_SERVER_NAME: buildkit-arm64.dev.svc.cluster.local
run: |
for i in 1 2 3 4 5; do
docker buildx rm watcher-remote >/dev/null 2>&1 || true
if docker buildx create --name watcher-remote --use \
--driver remote --platform linux/amd64 \
--driver-opt cacert="$BUILDKIT_TLS_DIR/ca.crt",cert="$BUILDKIT_TLS_DIR/tls.crt",key="$BUILDKIT_TLS_DIR/tls.key",servername="$BUILDKIT_TLS_SERVER_NAME" \
"$BUILDKIT_HOST" \
&& docker buildx create --name watcher-remote --append \
--driver remote --platform linux/arm64 \
--driver-opt cacert="$BUILDKIT_TLS_DIR/ca.crt",cert="$BUILDKIT_TLS_DIR/tls.crt",key="$BUILDKIT_TLS_DIR/tls.key",servername="$BUILDKIT_ARM64_TLS_SERVER_NAME" \
"$BUILDKIT_ARM64_HOST" \
&& timeout 90 docker buildx inspect --bootstrap; then
echo "connected to buildkit (amd64 + arm64, native)"; exit 0
fi
echo "buildkit connect failed (attempt $i/5), retrying…"; sleep 10
done
echo "could not reach buildkit"; exit 1
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v6
id: meta
with:
images: ghcr.io/${{ github.repository_owner }}/watcher-server
tags: |
type=raw,value=latest
type=sha
- uses: docker/build-push-action@v7
id: build
with:
context: .
file: server/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Portable layer cache on GitHub's Actions Cache (~10GB/repo, free). With
# cargo-chef the dep-compile layer cache-hits here until Cargo.lock moves,
# so a cold node skips it. mode=max also caches intermediate (build-stage)
# layers, which is what carries the cook layer — at the cost of a larger
# WAN transfer (see JEF-87 / measure in JEF-82).
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: true
- uses: sigstore/cosign-installer@v3
- name: Sign the image (keyless)
# Sign by immutable digest, not tag. Keyless: GitHub's OIDC token is
# exchanged for a short-lived Fulcio cert and the signature is recorded in
# the Rekor transparency log — no private key to store. cosign reuses the
# docker login above to push the signature to GHCR.
env:
DIGEST: ${{ steps.build.outputs.digest }}
run: cosign sign --yes "ghcr.io/${{ github.repository_owner }}/watcher-server@${DIGEST}"