build(deps): bump axios from 1.15.2 to 1.16.0 (#7672) #74
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Debian package | |
| on: | |
| push: | |
| tags: | |
| # Actions tag filters are globs, not regex. Mirrors handleRelease.yml. | |
| - 'v*.*.*' | |
| - 'v*.*.*-*' | |
| branches: [develop] | |
| paths: | |
| - 'packaging/**' | |
| - '.github/workflows/deb-package.yml' | |
| - 'src/package.json' | |
| - 'pnpm-lock.yaml' | |
| - 'src/node/server.ts' | |
| - 'src/node/utils/run_cmd.ts' | |
| - 'src/static/js/pluginfw/**' | |
| - 'settings.json.template' | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: 'Git ref to package (defaults to current)' | |
| required: false | |
| # Default to read-only for the workflow; the release job opts in to | |
| # `contents: write` for itself only. Build jobs (which run on every PR) | |
| # don't need write and shouldn't have it. | |
| permissions: | |
| contents: read | |
| env: | |
| NFPM_VERSION: v2.43.0 | |
| jobs: | |
| build: | |
| name: Build .deb (${{ matrix.arch }}) | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - arch: amd64 | |
| runner: ubuntu-latest | |
| - arch: arm64 | |
| runner: ubuntu-24.04-arm | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.ref || github.ref }} | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| version: 10 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: pnpm | |
| - name: Resolve version | |
| id: v | |
| # Runs after setup-node so `node` is guaranteed available on | |
| # any runner image (some don't ship it preinstalled). | |
| run: | | |
| if [ "${GITHUB_REF_TYPE}" = "tag" ]; then | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| else | |
| VERSION="$(node -p "require('./package.json').version")" | |
| fi | |
| echo "version=${VERSION}" >>"$GITHUB_OUTPUT" | |
| echo "Packaging version: ${VERSION}" | |
| - name: Install dependencies | |
| run: pnpm install --frozen-lockfile | |
| - name: Build UI + admin | |
| run: pnpm run build:etherpad | |
| - name: Install nfpm | |
| run: | | |
| set -euo pipefail | |
| NFPM_ARCH=amd64 | |
| [ "${{ matrix.arch }}" = "arm64" ] && NFPM_ARCH=arm64 | |
| NFPM_DEB="nfpm_${NFPM_VERSION#v}_${NFPM_ARCH}.deb" | |
| BASE="https://github.com/goreleaser/nfpm/releases/download/${NFPM_VERSION}" | |
| curl -fsSL -o "/tmp/${NFPM_DEB}" "${BASE}/${NFPM_DEB}" | |
| curl -fsSL -o /tmp/nfpm-checksums.txt "${BASE}/checksums.txt" | |
| # Verify upstream artifact before sudo dpkg -i (defense in depth | |
| # against a tampered release asset). | |
| ( cd /tmp && grep " ${NFPM_DEB}\$" nfpm-checksums.txt | sha256sum -c - ) | |
| sudo dpkg -i "/tmp/${NFPM_DEB}" | |
| - name: Stage tree for packaging | |
| run: | | |
| set -eux | |
| STAGE=staging/opt/etherpad | |
| mkdir -p "${STAGE}" | |
| # Production footprint = src/ + bin/ + node_modules/ + metadata. | |
| cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE \ | |
| node_modules "${STAGE}/" | |
| # Make pnpm-workspace.yaml production-only (same trick Dockerfile uses). | |
| printf 'packages:\n - src\n - bin\n' > "${STAGE}/pnpm-workspace.yaml" | |
| mkdir -p packaging/etc | |
| cp settings.json.template packaging/etc/settings.json.dist | |
| # Purge test fixtures and dev caches from node_modules to shrink size. | |
| find "${STAGE}/node_modules" -type d \ | |
| \( -name test -o -name tests -o -name '__tests__' \ | |
| -o -name example -o -name examples -o -name docs \) \ | |
| -prune -exec rm -rf {} + 2>/dev/null || true | |
| find "${STAGE}/node_modules" -type f \ | |
| \( -name '*.md' -o -name '*.ts.map' -o -name '*.map' \ | |
| -o -name 'CHANGELOG*' -o -name 'HISTORY*' \) \ | |
| -delete 2>/dev/null || true | |
| - name: Build .deb | |
| env: | |
| VERSION: ${{ steps.v.outputs.version }} | |
| ARCH: ${{ matrix.arch }} | |
| run: | | |
| mkdir -p dist | |
| nfpm package --packager deb -f packaging/nfpm.yaml --target dist/ | |
| - name: Smoke-test the package (amd64 only) | |
| if: matrix.arch == 'amd64' | |
| run: | | |
| set -eux | |
| # Ubuntu's default apt nodejs is 18 — too old for our | |
| # `Depends: nodejs (>= 22)`. Add NodeSource's apt repo | |
| # explicitly (key + sources.list) instead of `curl | sudo bash` | |
| # so we don't execute network-fetched code as root. | |
| NODE_MAJOR=24 | |
| # GitHub runner images often ship a NodeSource node_20.x list | |
| # preinstalled (sometimes as a .sources deb822 file). Wipe any | |
| # existing nodesource entries so the only Node candidate apt sees | |
| # is our node_24.x repo. Otherwise `apt-get install -y nodejs` | |
| # picks the higher-version 20.x build that's already cached and | |
| # `dpkg -i` then fails on `Depends: nodejs (>= 22)`. | |
| sudo rm -f /etc/apt/sources.list.d/nodesource.list \ | |
| /etc/apt/sources.list.d/nodesource.sources \ | |
| /etc/apt/preferences.d/nodesource \ | |
| /etc/apt/preferences.d/nodesource.pref | |
| KEYRING=/usr/share/keyrings/nodesource.gpg | |
| curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ | |
| | sudo gpg --dearmor --yes -o "${KEYRING}" | |
| echo "deb [signed-by=${KEYRING}] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \ | |
| | sudo tee /etc/apt/sources.list.d/nodesource.list | |
| # Pin nodejs to the 24.x line so neither Ubuntu's noble-updates | |
| # 20.x nor any leftover NodeSource cache can win the resolver. | |
| printf 'Package: nodejs\nPin: version %s.*\nPin-Priority: 1001\n' "${NODE_MAJOR}" \ | |
| | sudo tee /etc/apt/preferences.d/nodesource >/dev/null | |
| sudo apt-get update | |
| # Pin the major explicitly on the install line as a belt-and- | |
| # suspenders guard against any preference file being ignored. | |
| sudo apt-get install -y "nodejs=${NODE_MAJOR}.*" | |
| # Sanity check before invoking dpkg so the failure mode is obvious | |
| # if pinning ever regresses again. | |
| installed_major=$(dpkg-query -W -f='${Version}' nodejs | cut -d. -f1) | |
| if [ "${installed_major}" != "${NODE_MAJOR}" ]; then | |
| echo "::error::Expected nodejs major ${NODE_MAJOR}, got ${installed_major}" | |
| apt-cache policy nodejs || true | |
| exit 1 | |
| fi | |
| sudo dpkg -i dist/*.deb || sudo apt-get install -f -y | |
| # /etc/etherpad is mode 0750 root:etherpad on purpose (DB creds | |
| # live here) so the runner user can't read into it. Each check | |
| # that crosses /etc/etherpad or /var/lib/etherpad runs under sudo. | |
| sudo test -x /usr/bin/etherpad | |
| sudo test -f /etc/etherpad/settings.json | |
| sudo test -L /opt/etherpad/settings.json | |
| sudo test -L /opt/etherpad/var | |
| [ "$(sudo readlink /opt/etherpad/var)" = "/var/lib/etherpad/var" ] | |
| sudo test -L /opt/etherpad/src/plugin_packages | |
| [ "$(sudo readlink /opt/etherpad/src/plugin_packages)" = "/var/lib/etherpad/plugin_packages" ] | |
| sudo test -d /var/lib/etherpad/plugin_packages | |
| [ "$(sudo stat -c '%U' /var/lib/etherpad/plugin_packages)" = "etherpad" ] | |
| [ "$(stat -c '%G' /opt/etherpad/src/node_modules)" = "etherpad" ] | |
| sudo test -f /var/lib/etherpad/var/installed_plugins.json | |
| sudo grep -q '"ep_etherpad-lite"' /var/lib/etherpad/var/installed_plugins.json | |
| sudo grep -q '"dbType": "sqlite"' /etc/etherpad/settings.json | |
| id etherpad | |
| systemctl cat etherpad.service | |
| sudo systemctl start etherpad | |
| ok= | |
| for i in $(seq 1 30); do | |
| if curl -fsS http://127.0.0.1:9001/health; then | |
| ok=1 | |
| break | |
| fi | |
| sleep 2 | |
| done | |
| if [ -z "${ok}" ]; then | |
| # Attach logs so the failing run is diagnosable. | |
| sudo journalctl -u etherpad --no-pager -n 200 || true | |
| exit 1 | |
| fi | |
| sudo systemctl stop etherpad | |
| sudo dpkg --purge etherpad | |
| ! id etherpad 2>/dev/null | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: etherpad-${{ steps.v.outputs.version }}-${{ matrix.arch }}-deb | |
| path: dist/*.deb | |
| if-no-files-found: error | |
| release: | |
| name: Attach to GitHub Release | |
| needs: build | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| pattern: etherpad-*-deb | |
| merge-multiple: true | |
| - name: Create stable "latest" aliases | |
| run: | | |
| set -euo pipefail | |
| # Publish stable filenames alongside the versioned ones so users | |
| # can curl https://github.com/.../releases/latest/download/etherpad-latest_amd64.deb | |
| # without knowing the version. | |
| for f in dist/etherpad_*_amd64.deb; do | |
| [ -e "$f" ] && cp "$f" dist/etherpad-latest_amd64.deb | |
| done | |
| for f in dist/etherpad_*_arm64.deb; do | |
| [ -e "$f" ] && cp "$f" dist/etherpad-latest_arm64.deb | |
| done | |
| ls -la dist/ | |
| - name: Attach .deb files to release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| files: dist/*.deb | |
| fail_on_unmatched_files: true | |
| apt-publish: | |
| # Generates a signed apt repository (Packages.gz + Release/InRelease) | |
| # from the .deb artefacts and cross-pushes it into ether/ether.github.com | |
| # under public/apt/. The Next.js site that powers etherpad.org serves | |
| # public/ verbatim, so the repo lands at: | |
| # | |
| # https://etherpad.org/apt/ (apt repo root) | |
| # https://etherpad.org/key.asc (public key for `apt-key`/keyring) | |
| # | |
| # Tag pushes go into the `stable` suite. Required secrets: | |
| # APT_SIGNING_KEY ASCII-armoured private key for the Etherpad APT | |
| # Repository keypair (fingerprint | |
| # 6953FA0C6431F30347D65B03AF0CD687D51A6E63). | |
| # SITE_DEPLOY_KEY SSH private key matching a deploy key with write | |
| # access on ether/ether.github.com. The site repo | |
| # holds the public half. | |
| name: Publish apt repository to etherpad.org | |
| needs: release | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout etherpad source (for packaging/apt/key.asc) | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Configure deploy key for ether/ether.github.com | |
| env: | |
| SITE_DEPLOY_KEY: ${{ secrets.SITE_DEPLOY_KEY }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${SITE_DEPLOY_KEY:-}" ]; then | |
| echo "::error::SITE_DEPLOY_KEY secret is not set on ether/etherpad." | |
| echo "::error::Add an SSH deploy key with write access on ether/ether.github.com and store the private key here." | |
| exit 1 | |
| fi | |
| mkdir -p ~/.ssh | |
| chmod 700 ~/.ssh | |
| printf '%s\n' "${SITE_DEPLOY_KEY}" > ~/.ssh/id_deploy | |
| chmod 600 ~/.ssh/id_deploy | |
| ssh-keyscan -t ed25519,rsa github.com >> ~/.ssh/known_hosts 2>/dev/null | |
| cat > ~/.ssh/config <<'CFG' | |
| Host github.com | |
| HostName github.com | |
| User git | |
| IdentityFile ~/.ssh/id_deploy | |
| IdentitiesOnly yes | |
| CFG | |
| chmod 600 ~/.ssh/config | |
| - name: Clone ether/ether.github.com | |
| run: git clone --depth 1 git@github.com:ether/ether.github.com.git site | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| pattern: etherpad-*-deb | |
| merge-multiple: true | |
| - name: Install apt-utils + gpg | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y -qq apt-utils gnupg | |
| - name: Import signing key | |
| env: | |
| APT_SIGNING_KEY: ${{ secrets.APT_SIGNING_KEY }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${APT_SIGNING_KEY:-}" ]; then | |
| echo "::error::APT_SIGNING_KEY secret is not set; cannot sign Release file." | |
| exit 1 | |
| fi | |
| export GNUPGHOME="$(mktemp -d)" | |
| chmod 700 "${GNUPGHOME}" | |
| echo "GNUPGHOME=${GNUPGHOME}" >>"${GITHUB_ENV}" | |
| printf '%s' "${APT_SIGNING_KEY}" | gpg --batch --import | |
| # Sanity check: expected long key id. | |
| gpg --list-secret-keys --keyid-format=long | grep -q AF0CD687D51A6E63 | |
| - name: Generate apt repo metadata | |
| run: | | |
| set -euo pipefail | |
| REPO=site/public/apt | |
| SUITE=stable | |
| COMP=main | |
| # Wipe any previous repo state so removed versions don't linger | |
| # in pool/. Packages.gz is regenerated from whatever is in pool/ | |
| # right now, so this is the simplest correct option — alternative | |
| # is per-version diffing which is fragile. | |
| rm -rf "${REPO}" | |
| # We ship one architecture-agnostic suite with per-arch pools. | |
| # Layout: apt/dists/<suite>/main/binary-{amd64,arm64}/ | |
| for arch in amd64 arm64; do | |
| mkdir -p "${REPO}/pool/main/e/etherpad" "${REPO}/dists/${SUITE}/${COMP}/binary-${arch}" | |
| done | |
| # Drop the .debs into pool/. The leading-digit pattern | |
| # excludes the etherpad-latest_*.deb filename aliases the | |
| # release job stages — apt resolves by package name + version, | |
| # not filename, so including the alias would create duplicate | |
| # Packages entries. (Also defends against any future alias that | |
| # accidentally lands on dist/etherpad_<word>_<arch>.deb.) | |
| shopt -s nullglob | |
| DEBS=(dist/etherpad_[0-9]*_amd64.deb dist/etherpad_[0-9]*_arm64.deb) | |
| shopt -u nullglob | |
| # Refuse to publish nothing. Without this, a missing or renamed | |
| # build artefact would wipe site/public/apt and push an empty, | |
| # signed apt repo — breaking `apt update` for every existing | |
| # subscriber until the next successful release. | |
| if [ ${#DEBS[@]} -lt 2 ]; then | |
| echo "::error::Expected per-arch .deb artifacts in dist/, found ${#DEBS[@]}: ${DEBS[*]:-<none>}" | |
| echo "::error::Refusing to publish a partial / empty apt repository." | |
| exit 1 | |
| fi | |
| cp "${DEBS[@]}" "${REPO}/pool/main/e/etherpad/" | |
| # Generate per-arch Packages files. | |
| ( | |
| cd "${REPO}" | |
| for arch in amd64 arm64; do | |
| apt-ftparchive --arch "${arch}" packages pool/main \ | |
| > "dists/${SUITE}/${COMP}/binary-${arch}/Packages" | |
| gzip -kf "dists/${SUITE}/${COMP}/binary-${arch}/Packages" | |
| done | |
| # Generate the suite's Release file. The heredoc lines | |
| # MUST start at column 1 — apt parsers reject leading | |
| # whitespace on header fields (RFC 822 / Debian control). | |
| # printf is used over a heredoc to make that contract | |
| # impossible to lose to a future re-indent. | |
| printf '%s\n' \ | |
| "Origin: Etherpad" \ | |
| "Label: Etherpad" \ | |
| "Suite: ${SUITE}" \ | |
| "Codename: ${SUITE}" \ | |
| "Architectures: amd64 arm64" \ | |
| "Components: ${COMP}" \ | |
| "Description: Etherpad official apt repository (${SUITE} channel)" \ | |
| "Date: $(date -Ru)" \ | |
| > "dists/${SUITE}/Release" | |
| # apt-ftparchive appends checksums. | |
| apt-ftparchive release "dists/${SUITE}" >> "dists/${SUITE}/Release" | |
| # Sign it (clear-signed InRelease + detached Release.gpg). | |
| gpg --default-key AF0CD687D51A6E63 --batch --yes \ | |
| --clearsign -o "dists/${SUITE}/InRelease" "dists/${SUITE}/Release" | |
| gpg --default-key AF0CD687D51A6E63 --batch --yes \ | |
| -abs -o "dists/${SUITE}/Release.gpg" "dists/${SUITE}/Release" | |
| ) | |
| - name: Stage public key alongside the site | |
| run: | | |
| # Users curl this to add our key to their keyring before apt update. | |
| cp packaging/apt/key.asc site/public/key.asc | |
| - name: Commit + push to ether/ether.github.com | |
| env: | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| cd site | |
| git -c user.email=actions@github.com -c user.name='github-actions[bot]' \ | |
| add public/apt public/key.asc | |
| if git diff --cached --quiet; then | |
| echo "No apt-repo changes to publish." | |
| exit 0 | |
| fi | |
| git -c user.email=actions@github.com -c user.name='github-actions[bot]' \ | |
| commit -m "apt: publish Etherpad ${TAG}" | |
| git push origin HEAD:master |