Skip to content

fix(dev-tunnel): warn when the dev server can't be embedded by the host #452

fix(dev-tunnel): warn when the dev server can't be embedded by the host

fix(dev-tunnel): warn when the dev server can't be embedded by the host #452

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: go vet
run: go vet ./...
- name: gofmt
run: |
unformatted=$(gofmt -s -l .)
if [ -n "$unformatted" ]; then
echo "These files are not gofmt-ed:"
echo "$unformatted"
exit 1
fi
- name: test
run: go test ./...
- name: build
run: go build ./...
# Static-analysis gate: golangci-lint over the whole module using the curated
# linter set in .golangci.yml (staticcheck / govet / ineffassign / unused /
# misspell + gofmt). Runs on every PR. `make lint` mirrors this locally.
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: false # golangci-lint-action manages its own build/analysis cache
- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: v2.12.2
# Drift-guard: the vendored block-manifest schema (go:embed'd for offline
# `civitai app validate`) must stay identical to the canonical the platform
# publishes at civitai.com/schemas/app-block/v1.json (the single source of
# truth). Fails if a server-side contract change leaves the CLI stale.
schema-drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: check canonical schema
run: ./scripts/check-canonical-schema.sh
# Rot-guard: assert each scaffold template's `@civitai/*` pin still ADMITS the
# version npm currently publishes as `latest`. A pre-1.0 caret (`^0.24.0`)
# locks the minor, so a pin that falls behind npm silently ships apps that are
# born stale — and `npm install` won't catch it (it resolves the caret to the
# newest version the stale range still admits). This is the network half of
# the scaffold guard; it's env-gated so the default `go test ./...` stays
# offline, and it SKIPS (never false-fails) when npm is unreachable.
pins-vs-published:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: check scaffold pins vs npm latest
env:
CIVITAI_CHECK_PUBLISHED_PINS: "1"
run: go test ./internal/scaffold -run TestScaffoldPinsSatisfyPublished -v
# Rot-guard: scaffold the page-money template and run its JS toolchain against
# the PUBLISHED SDK (@civitai/blocks-react). Catches a template that renders
# but no longer installs / typechecks / tests / builds after an SDK bump — the
# out-of-the-box contract the template promises.
template-page-money:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: scaffold page-money
run: go run ./cmd/civitai app init "CI Money Block" --dir ./_ci-page-money --template page-money
- name: install
working-directory: ./_ci-page-money
run: npm install --no-audit --no-fund
- name: typecheck
working-directory: ./_ci-page-money
run: npm run typecheck
- name: test (node + dom suites)
working-directory: ./_ci-page-money
run: npm test
- name: build
working-directory: ./_ci-page-money
run: npm run build
- name: validate
working-directory: ./_ci-page-money
run: go run ../cmd/civitai app validate
# Scaffold-currency guard — the "born-broken app" gate. Two rot-classes that
# pins-vs-published + template-page-money both MISS:
#
# (a) ANTI-PATTERN gate — scaffold the SDK template, then scan the generated
# source for a curated denylist of dead/superseded platform surfaces
# (the REMOVED /api/v1/blocks/buzz route, the superseded shared-storage
# REST route, the deprecated @civitai/blocks-cli). A scaffold can compile
# and pass the pins guard yet still fetch a route that 404s at runtime —
# exactly how playable-collections shipped 3 broken features. The denylist
# is precise: it does NOT flag legitimately-REST unbridged endpoints
# (catalog /models, /images; the /me viewer read; the /dev-token mint).
# Logic + fixtures live in internal/antipattern (offline table test); this
# runs it against the real `civitai app init` output.
#
# (b) LATEST-SDK build — install the ACTUAL newest published @civitai/app-sdk
# + @civitai/blocks-react (not the pinned caret npm resolves to) and
# re-typecheck + re-build. pins-vs-published catches "the pin can't admit
# latest"; THIS catches "the template code breaks against latest" (a
# removed/renamed SDK export). Network-dependent, so it mirrors the
# pins-vs-published SKIP-on-unreachable contract: a reachability PROBE
# gates the install/typecheck/build steps — an npm outage (network / DNS /
# 5xx / 429) SKIPS them (job stays green, indistinguishable-from-real is
# avoided) while a reachable registry runs them and FAILS on a genuine
# code-breaks-against-latest signal. (A peer-dep incompat where the pin
# can't admit latest is already caught by pins-vs-published, so treating an
# install failure under a REACHABLE registry as real is correct.) The
# offline anti-pattern scan is hermetic and always runs.
scaffold-currency:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- uses: actions/setup-node@v4
with:
node-version: "22"
- name: scaffold page-money
run: go run ./cmd/civitai app init "CI Currency Block" --dir "$GITHUB_WORKSPACE/_ci-currency" --template page-money
# (a) Anti-pattern gate on the scaffolded app.
# CIVITAI_ANTIPATTERN_SCAN_DIR MUST be ABSOLUTE: `go test` runs the test
# binary with its CWD set to the package dir (internal/antipattern), not
# the repo root, so a relative `./_ci-currency` would resolve under the
# package dir and lstat-fail. github.workspace anchors it to where the
# scaffold step wrote the app.
- name: anti-pattern scan (scaffolded app)
env:
CIVITAI_ANTIPATTERN_SCAN_DIR: ${{ github.workspace }}/_ci-currency
run: go test ./internal/antipattern -run TestScanDirFromEnv -count=1 -v
# (b) Build against the LATEST published SDK, not just the pinned caret.
# Probe npm first; if the registry is unreachable (network/DNS/5xx/429)
# the build steps SKIP so a transient outage can't red the job (mirrors
# the pins-vs-published skip-on-unreachable contract). A 200 on the
# /latest metadata means "reachable" — a real SDK break then fails at
# typecheck/build, not here.
- name: probe npm reachability
id: npmprobe
run: |
code=$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 \
https://registry.npmjs.org/@civitai/app-sdk/latest 2>/dev/null) || code=000
[ -z "$code" ] && code=000
if [ "$code" = "200" ]; then
echo "reachable=true" >> "$GITHUB_OUTPUT"
echo "npm registry reachable (HTTP $code) — running the latest-SDK build check"
else
echo "reachable=false" >> "$GITHUB_OUTPUT"
echo "::notice title=scaffold-currency::skipped latest-SDK build check — npm registry unreachable (HTTP $code); not a real failure, re-run later"
fi
- name: install (pinned)
if: steps.npmprobe.outputs.reachable == 'true'
working-directory: ./_ci-currency
run: npm install --no-audit --no-fund
- name: install @latest SDK
if: steps.npmprobe.outputs.reachable == 'true'
working-directory: ./_ci-currency
run: npm install --no-audit --no-fund @civitai/app-sdk@latest @civitai/blocks-react@latest
- name: typecheck against latest SDK
if: steps.npmprobe.outputs.reachable == 'true'
working-directory: ./_ci-currency
run: npm run typecheck
- name: build against latest SDK
if: steps.npmprobe.outputs.reachable == 'true'
working-directory: ./_ci-currency
run: npm run build