Skip to content

Changelog added, pkg version bumbed #7417

Changelog added, pkg version bumbed

Changelog added, pkg version bumbed #7417

name: PR Checks (SDK Pod)
on:
# Plain `pull_request` (NOT pull_request_target): fork PRs run with a
# read-only token and no secrets, so it is safe to check out and execute PR
# code (install/lint/build/test). These checks need no secrets, so the
# privileged context would buy nothing and only add "pwn request" risk.
#
# No trigger-level `paths:` filter on purpose: this workflow publishes the
# required "SDK Pod Checks" status, which must report on EVERY PR or GitHub
# blocks unrelated PRs ("waiting for status to be reported"). The single job
# below detects SDK pod changes itself and is a fast no-op when nothing
# relevant changed.
pull_request:
types:
- opened
- synchronize
- reopened
- labeled
branches:
- main
- release-*
- feature-*
- tmp-*
workflow_dispatch:
permissions:
contents: read
# Package config lives in .github/sdk-pod-checks.json
# Scripts (lint, build, test:unit) are auto-detected from each package's package.json
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
# ---------------------------------------------------------------------------
# Single required status check for SDK pod packages.
#
# Runs on every PR so the "SDK Pod Checks" context is always reported — a
# required check that is never reported blocks the PR forever. It is a fast
# no-op (detect step only) when no SDK pod files changed, so unrelated PRs are
# unaffected. Mark THIS job's name ("SDK Pod Checks") required in the ruleset.
#
# - no SDK pod files changed -> pass (no checks run)
# - changed + checks pass -> pass
# - changed + a check fails -> fail (blocks the merge)
# - changed + a check fails, but the 'skip-sdk-pod-checks' label is set
# -> pass (audited override for e.g. a
# confirmed false-positive test; the
# failure is still run and logged)
#
# The package config and the diff baseline are read from the trusted base
# commit (not the PR), so a PR cannot edit the config to skip its own checks.
# Packages are checked sequentially in this single job (instead of a parallel
# matrix) so that exactly one check appears on every PR.
# ---------------------------------------------------------------------------
sdk-pod-checks:
name: SDK Pod Checks
runs-on: ubuntu-latest
# Hard cap so a hung job can't hog runners or burn minutes. Slightly above
# the 30-min default because this rollup runs up to 6 packages sequentially
# (incl. the SDK build + bare/e2e tests and the two consumer installs).
timeout-minutes: 45
steps:
# Checkout the trusted base commit. The package config and the diff
# baseline are read from here — never from the PR — so a PR cannot edit
# the config to exclude itself from its own checks.
- name: Checkout base
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
ref: ${{ github.event.pull_request.base.sha || github.ref }}
fetch-depth: 0
- name: Detect changed SDK pod packages
id: detect
timeout-minutes: 5
shell: bash
env:
EVENT: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
run: |
# Fail closed: any error here (git fetch/diff, jq) fails the step and
# therefore the whole "SDK Pod Checks" job — never a silent green.
set -euo pipefail
# Default optional fields. `sources` is which SDK variants to test a
# package against: sdk_sources_release on release-* PRs (and dispatch),
# else sdk_sources. Both default to ["default"] — one leg, no prep.
ALL_PACKAGES=$(jq -c --arg event "$EVENT" --arg base "${BASE_REF:-}" '
[ .[]
| .pkg_manager //= "npm"
| .needs_bare //= false
| .tests_bare //= false
| .sdk_sources //= ["default"]
| .sdk_sources_release //= .sdk_sources
| .sources = (if ($event == "workflow_dispatch" or ($base | startswith("release-")))
then .sdk_sources_release else .sdk_sources end)
]' .github/sdk-pod-checks.json)
# Gates the bare-sdk dep-parity check to dep/version changes only.
sdk_pkgjson_changed="false"
if [ "$EVENT" = "workflow_dispatch" ]; then
# workflow_dispatch: run all packages
PACKAGES="$ALL_PACKAGES"
sdk_pkgjson_changed="true"
else
# Fetch PR head (available on the repo via pull refs)
git fetch origin "refs/pull/${PR_NUMBER}/head"
# Filter to only packages with changed files in this PR
CHANGED_FILES=$(git diff --name-only "$BASE_SHA"..."$HEAD_SHA")
PACKAGES=$(echo "$ALL_PACKAGES" | jq -c --arg files "$CHANGED_FILES" '[
.[] | select(.path as $p | $files | split("\n") | any(startswith($p + "/")))
]')
if echo "$CHANGED_FILES" | grep -qx "packages/sdk/package.json"; then
sdk_pkgjson_changed="true"
fi
fi
echo "packages=${PACKAGES}" >> "$GITHUB_OUTPUT"
echo "sdk_pkgjson_changed=${sdk_pkgjson_changed}" >> "$GITHUB_OUTPUT"
has_changes=$(echo "$PACKAGES" | jq -r 'if length > 0 then "true" else "false" end')
echo "has_changes=${has_changes}" >> "$GITHUB_OUTPUT"
if [ "$has_changes" = "true" ]; then
echo "::notice::SDK pod packages changed: $(echo "$PACKAGES" | jq -r '[.[].package] | join(", ")')"
else
echo "::notice::No SDK pod package files changed - gate passes."
fi
# ----- Everything below runs only when SDK pod files changed -----
# Safe under `pull_request`: fork PRs get a read-only token and no secrets,
# so checking out and executing PR code cannot exfiltrate anything.
- name: Checkout PR head
if: steps.detect.outputs.has_changes == 'true'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
with:
ref: ${{ github.event.pull_request.head.sha || github.ref }}
- name: Setup Bun
if: steps.detect.outputs.has_changes == 'true'
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # 2.2.0
with:
bun-version: latest
- name: Setup Node
if: steps.detect.outputs.has_changes == 'true'
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # 6.3.0
with:
node-version: 22
- name: Run SDK pod checks
if: steps.detect.outputs.has_changes == 'true'
timeout-minutes: 40
shell: bash
env:
PACKAGES: ${{ steps.detect.outputs.packages }}
SDK_PKGJSON_CHANGED: ${{ steps.detect.outputs.sdk_pkgjson_changed }}
# Maintainer escape hatch: when this label is present the gate still
# runs and logs failures, but reports success so an urgent fix can
# land over a confirmed false-positive check. Audited via the label
# and the warning below.
OVERRIDE: ${{ contains(github.event.pull_request.labels.*.name, 'skip-sdk-pod-checks') }}
run: |
set -uo pipefail
WS="$GITHUB_WORKSPACE"
fail=0
# Run a single check; record (don't abort on) failures so every check runs.
run() {
local label="$1"
shift
if "$@"; then
echo " ok [$PKG] $label"
else
echo "::error::[$PKG] $label failed"
fail=$((fail + 1))
fi
}
# Validates the SDK tarball installs cleanly for end consumers:
# 1. zero peer-dependency warnings on install
# 2. shared P2P packages resolve to a single copy
# 3. import('@qvac/sdk') resolves from a vanilla install
# Runs in a subshell so its directory changes do not leak.
consumer_install_check() (
set -eo pipefail
cd "$WS/packages/sdk"
# Pack the tarball produced by the preceding build step.
bun pm pack --destination dist/
tarball=$(ls dist/qvac-sdk-*.tgz | head -n1)
test -n "$tarball" || { echo "::error::No SDK tarball found after pack"; exit 1; }
tarball_abs="$(pwd)/$tarball"
check_consumer() {
local consumer="$1" label="$2"
cd "$consumer"
if grep -Eq "ERESOLVE|npm warn peer" install.log; then
echo "::error title=Peer dependency drift (${label})::SDK consumer install surfaced peer warnings"
grep -E "ERESOLVE|npm warn peer" install.log || true
return 1
fi
echo "::notice::[${label}] 0 peer warnings"
local f=0 tree copies
for pkg in corestore hyperswarm hyperdrive hyperdb hyperblobs hyperdht; do
tree=$(npm ls "$pkg" --all 2>&1)
copies=$(printf '%s\n' "$tree" | grep -E "[─ ]${pkg}@" | grep -vc "deduped" || true)
if [ "$copies" != "1" ]; then
echo "::error::[${label}] ${pkg} resolved to ${copies} copies (expected 1)"
printf '%s\n' "$tree"
f=1
else
echo " ok [${label}] ${pkg} = 1 copy"
fi
done
[ "$f" = "0" ] || return 1
echo "::notice::[${label}] Single-copy invariant holds for shared P2P packages"
node -e "import('@qvac/sdk').then(m => { if (Object.keys(m).length < 50) { console.error('FAIL: too few exports'); process.exit(1); } console.log('[${label}] import ok:', Object.keys(m).length, 'exports'); }).catch(e => { console.error('[${label}] FAIL:', e.message); process.exit(1); })"
}
# Scenario 1: default install (plug-n-play) - all optionalDependencies present.
consumer_default=$(mktemp -d)
cd "$consumer_default"
npm init -y > /dev/null
npm pkg set type=module > /dev/null
npm install --no-fund --no-audit --ignore-scripts --loglevel=info "$tarball_abs" 2>&1 | tee install.log
check_consumer "$consumer_default" "default"
# Scenario 2: lean backend install (--omit=optional) - no optionalDependencies.
consumer_lean=$(mktemp -d)
cd "$consumer_lean"
npm init -y > /dev/null
npm pkg set type=module > /dev/null
npm install --no-fund --no-audit --ignore-scripts --omit=optional --loglevel=info "$tarball_abs" 2>&1 | tee install.log
check_consumer "$consumer_lean" "lean (--omit=optional)"
)
# Install the Bare runtime once if any changed package needs it.
if echo "$PACKAGES" | jq -e 'any(.[]; .needs_bare == true)' > /dev/null; then
echo "::group::Install Bare runtime"
npm install -g --force bare
echo "::endgroup::"
fi
len=$(echo "$PACKAGES" | jq 'length')
i=0
while [ "$i" -lt "$len" ]; do
PKG=$(echo "$PACKAGES" | jq -r ".[$i].package")
P_PATH=$(echo "$PACKAGES" | jq -r ".[$i].path")
PM=$(echo "$PACKAGES" | jq -r ".[$i].pkg_manager")
TESTS_BARE=$(echo "$PACKAGES" | jq -r ".[$i].tests_bare")
SOURCES=$(echo "$PACKAGES" | jq -r ".[$i].sources[]")
i=$((i + 1))
echo "::group::SDK pod checks - $PKG"
cd "$WS/$P_PATH"
# Disallowed dependencies: no git URLs or dev/tmp versions. Checked on
# the committed manifest, before any per-source prep can rewrite it.
deps=$(jq -r '([.dependencies, .devDependencies] | map(select(type=="object")) | add // {}) | to_entries[] | .value' package.json)
if echo "$deps" | grep -Eq '^(git\+https:\/\/github.com|[0-9]+\.[0-9]+\.[0-9]+-(dev|tmp)[^"]*)$'; then
echo "::error::[$PKG] disallowed dependency detected (git URL or dev/tmp version)"
fail=$((fail + 1))
fi
# Run the checks once per declared SDK source. The optional
# sdk-source:<source> script does that source's setup (e.g. link the
# in-repo SDK); absent = plain install of the committed dependency.
src_idx=0
for SRC in $SOURCES; do
# Bracketed source shown after each check name, e.g. "build [workspace]".
# Empty for the lone "default" source (single-leg packages stay clean).
src=""
if [ "$SRC" != "default" ]; then src="[$SRC]"; fi
# Reset to the committed manifest. For the 2nd+ source also wipe
# node_modules + lockfile — a prior `npm install ../sdk` leaves a
# symlink npm would keep, leaking that source into this one.
git checkout HEAD -- package.json 2>/dev/null || true
if [ "$src_idx" -gt 0 ]; then
rm -rf node_modules package-lock.json
fi
# npm run --if-present reads package.json scripts and works regardless
# of the installer (bun lacks --if-present).
if [ "$PKG" = "sdk" ]; then
run "install $src" bun install
else
run "install $src" "$PM" install
fi
# Per-source setup (no-op if the script is absent).
run "sdk-source $src" npm run --if-present "sdk-source:$SRC"
run "lint $src" npm run --if-present lint
run "build:types $src" npm run --if-present build:types
run "build $src" npm run --if-present build
run "test:unit $src" npm run --if-present test:unit
if [ "$TESTS_BARE" = "true" ]; then
run "test:bare $src" npm run --if-present test:bare
fi
run "test:e2e $src" npm run --if-present test:e2e
src_idx=$((src_idx + 1))
done
# Back to the committed manifest for the sdk-only checks below.
git checkout HEAD -- package.json 2>/dev/null || true
if [ "$PKG" = "sdk" ]; then
# Assert bare-sdk stays in dep lockstep with sdk.
if [ "$SDK_PKGJSON_CHANGED" = "true" ]; then
run "bare-sdk deps parity" node "$WS/packages/bare-sdk/scripts/check-deps-vs-sdk.mjs"
fi
if consumer_install_check; then
echo " ok [$PKG] consumer install"
else
echo "::error::[$PKG] consumer install check failed"
fail=$((fail + 1))
fi
fi
cd "$WS"
echo "::endgroup::"
done
if [ "$fail" -gt 0 ]; then
if [ "$OVERRIDE" = "true" ]; then
echo "::warning::$fail SDK pod check(s) failed, but the 'skip-sdk-pod-checks' label is applied - overriding to allow this merge (e.g. a confirmed false-positive test). Fix the failing check in a follow-up."
exit 0
fi
echo "::error::There were $fail failed SDK pod check(s)"
exit 1
fi
echo "All SDK pod checks passed."