Skip to content

fix(web): require an available machine for SSH terminals #1639

fix(web): require an available machine for SSH terminals

fix(web): require an available machine for SSH terminals #1639

Workflow file for this run

name: Lint
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
# A superseded push must not keep CI busy: pushing three times to a PR used to
# queue three full sets of jobs, all but the last of them already irrelevant.
# release.yml deliberately does the OPPOSITE (`cancel-in-progress: false`) —
# cancelling a release mid-flight leaves a tag without a release — but CI has
# nothing to protect.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Linting
# Bare on the runner rather than in the builder image: this job needs only
# bun (via setup-bun below) and node, and a container would buy nothing —
# nothing root-owns the workspace, so there is nothing to un-root.
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.0
# tsdown/rolldown run under NODE, not bun — their bin shebang is
# `#!/usr/bin/env node` — so the repo has always had a Node requirement
# it never declared, and CI silently inherited whatever the host had.
# the fleet once shipped node 18.19 while ubuntu-latest shipped 20+; rolldown needs
# `styleText` from `node:util` (20.12+), so the build broke on the move.
#
# Pinned to the `engines.node` the root package.json now declares, NOT
# to rolldown's floor. A hosted runner image ships a node and floats it
# with each image refresh; the pinned version is the contract, so it
# comes from the workflow rather than from the image.
- name: Use Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
- name: Cache Bun install
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: ${{ runner.os }}-bun-
- name: Cache Turbo
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
# Turbo v2's local cache is .turbo/cache at the repo root
# (measured 2026-09-22 against turbo 2.10.11); the v1 path this
# previously named is never written, so the cache restored nothing.
path: .turbo
key: ${{ runner.os }}-turbo-${{ github.sha }}
restore-keys: ${{ runner.os }}-turbo-
- name: Install Dependencies
run: bun install --frozen-lockfile
- name: Build workspace packages
run: bun run build
- name: Run package checking
run: bun run lint:packages
# Bun records a version for each workspace in bun.lock and never resyncs
# it, and `--frozen-lockfile` exits 0 when it is stale — so the release
# flow silently drifted the lockfile a whole version behind before
# anyone noticed. This is the only check that sees it.
- name: Check the lockfile's workspace versions
run: bun run lint:lockfile
# Subshell is dual-licensed by path (apps/server/** is AGPL, the rest is
# Apache). A new or moved package declaring the wrong `license` — or none
# at all — is not a type error, a lint error or a test failure. This is
# the only thing that sees it.
- name: Check the per-path licence declarations
run: bun run lint:licenses
# The design system (docs/design-system.md): one type/colour vocabulary
# across four surfaces, asserted from the token files. A stray
# `text-[13px]`, `font-size: 14.5px` or `fontSize: 17` is not a type,
# lint or test failure — this is the only thing that sees it.
- name: Check the design tokens
run: bun run lint:design
# The voice rule (operator ruling 2026-09-25): no em dashes in authored
# prose. The docs site enforces this through its content test; this is
# the twin for the rest of the repository's prose (AGENTS.md files,
# docs/, rules, READMEs, pending changesets). A dash is not a type, lint
# or test failure, so this is the only thing that sees it.
- name: Check the prose (no em dashes)
run: bun run lint:prose
- name: Run type checking
run: bun run verify-types
# Read-only: `lint` writes fixes and would pass on unformatted code.
- name: Run linting
run: bun run lint:check
- name: "shellcheck (Proxmox helpers, image entrypoint, docker scenario)"
run: |
sudo apt-get update -q
sudo apt-get install -y -q shellcheck
shellcheck -S warning proxmox-server.sh proxmox-node.sh docker-entrypoint.sh scripts/cli-e2e/docker-image.sh
# Dependency advisories, gated. `bun audit` on its own is informational: it
# prints advisories and would have left this file green through every one of
# them. dep-audit requires the live advisory set to be a subset of
# scripts/dep-audit.ignore.json, so a NEW advisory fails the job naming its
# GHSA id, and an allowlisted entry that has since been fixed warns, which is
# what keeps the file recording reasons rather than history. A separate job
# rather than a step: the audit is a statement about the lockfile, and it
# fails for reasons no amount of linting fixes.
dep-audit:
name: Dependency audit
# Bare like the lint job above: bun and the lockfile are the whole input.
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.0
- name: Cache Bun install
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: ${{ runner.os }}-bun-
- name: Install Dependencies
run: bun install --frozen-lockfile
- name: Audit dependencies
run: bun run audit:deps
# The website's install column reads the root releases.json, and release.yml
# regenerates it after every cut. If that job's commit step ever breaks,
# main moves on with a stale manifest: drift is a CI failure, not a
# visitor's problem (spec 2026-09-23 §5). Bare on the runner like the Lint
# job above for the same reason: bun and the checkout are the whole need.
site-manifest-fresh:
name: releases.json matches the tags
# Push-only: tags land at cut START, PRs must not go red for a cut in flight; drift is caught "on the next push".
if: github.event_name == 'push'
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout Repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Use Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: 1.4.0
- name: Install Dependencies
run: bun install --frozen-lockfile
# ls-remote goes to the remote by protocol, so no fetch-depth: 0 here:
# the checkout supplies the script and the committed file it compares
# against, nothing more.
- name: Check
run: bun scripts/site-releases.ts --check