diff --git a/.github/actions/setup-npm/action.yml b/.github/actions/setup-npm/action.yml index b8e997099..e76acd0a1 100644 --- a/.github/actions/setup-npm/action.yml +++ b/.github/actions/setup-npm/action.yml @@ -1,5 +1,5 @@ -name: 'Setup npm with Nexus' -description: 'Starts Nexus, publishes patched packages, then runs npm install' +name: 'Setup npm with local registry' +description: 'Starts Verdaccio, publishes patched packages, then runs npm install' inputs: node-version: @@ -15,47 +15,57 @@ runs: with: node-version: ${{ inputs.node-version }} - - name: Cache Nexus data - uses: actions/cache@v4 - with: - path: /tmp/nexus-data - key: nexus-data-v1-${{ hashFiles('deployment/npm-patches/**', 'deployment/nexus-init.sh') }} - restore-keys: | - nexus-data-v1- - - - name: Start Nexus + - name: Start Verdaccio and publish patched packages shell: bash run: | - docker run -d --name nexus \ - -p 8091:8081 \ - -v /tmp/nexus-data:/nexus-data \ - --platform linux/amd64 \ - sonatype/nexus3:3.75.0 - echo "Nexus starting..." + # Install and start Verdaccio (lightweight npm registry, ~2s startup) + npm install -g verdaccio@6 --silent - - name: Wait for Nexus - shell: bash - run: | - echo "Waiting for Nexus to be healthy (up to 3 minutes)..." - timeout 180 bash -c ' - until curl -sf http://localhost:8091/service/rest/v1/status -u admin:nexus >/dev/null 2>&1 || \ - curl -sf http://localhost:8091/service/rest/v1/status >/dev/null 2>&1; do - echo " still waiting..." - sleep 10 - done - ' - echo "Nexus is up" + mkdir -p /tmp/verdaccio-storage + cat > /tmp/verdaccio.yaml << 'VERDACCIO_EOF' + storage: /tmp/verdaccio-storage + uplinks: + npmjs: + url: https://registry.npmjs.org/ + timeout: 60s + max_fails: 3 + packages: + '@esbuild-kit/*': + access: $all + publish: $all + proxy: npmjs + '**': + access: $all + publish: $all + proxy: npmjs + server: + keepAliveTimeout: 60 + log: + type: stdout + format: pretty + level: warn + listen: 0.0.0.0:4873 + VERDACCIO_EOF - - name: Initialise Nexus (npm repos) - shell: bash - env: - NEXUS_URL: http://localhost:8091 - NEXUS_ADMIN_NEW_PASS: nexus - run: bash deployment/nexus-ci-init.sh + verdaccio --config /tmp/verdaccio.yaml & + VERDACCIO_PID=$! + echo "Verdaccio PID: $VERDACCIO_PID" - - name: Publish patched npm packages - shell: bash - run: bash deployment/publish-npm-patches.sh + # Wait for Verdaccio to be ready (usually <3s) + timeout 30 bash -c 'until curl -sf http://localhost:4873/-/ping >/dev/null 2>&1; do sleep 1; done' + echo "Verdaccio ready" + + # Publish all patched tarballs + PATCHES_DIR="deployment/npm-patches" + for tarball in "$PATCHES_DIR"/*.tgz; do + [ -f "$tarball" ] || continue + echo "Publishing $tarball..." + npm publish "$tarball" \ + --registry http://localhost:4873 \ + --tag patched \ + 2>&1 | grep -v "^npm notice" || true + done + echo "Patched packages published to Verdaccio" - name: Install npm dependencies shell: bash diff --git a/.npmrc b/.npmrc index 9ea09f42a..ad67b009e 100644 --- a/.npmrc +++ b/.npmrc @@ -42,8 +42,9 @@ workspaces-update=true # These are documented in package.json engines field # Current: Node 22.22.1, npm 11.11.0 -# SCOPED NEXUS REGISTRY - @esbuild-kit patched packages -# Local dev: cd deployment && docker compose -f docker-compose.nexus.yml up -d +# SCOPED VERDACCIO REGISTRY - @esbuild-kit patched packages +# Local dev: npx verdaccio --config deployment/verdaccio.yaml & +# bash deployment/publish-npm-patches.sh --verdaccio # CI: started automatically via .github/actions/setup-npm composite action -@esbuild-kit:registry=http://localhost:8091/repository/npm-group/ -//localhost:8091/repository/npm-group/:_auth=YWRtaW46bmV4dXM= +@esbuild-kit:registry=http://localhost:4873/ +//localhost:4873/:_authToken= diff --git a/deployment/publish-npm-patches.sh b/deployment/publish-npm-patches.sh index 063269454..49ad6577f 100755 --- a/deployment/publish-npm-patches.sh +++ b/deployment/publish-npm-patches.sh @@ -1,15 +1,17 @@ #!/usr/bin/env bash -# Publish patched npm packages to local Nexus registry. +# Publish patched npm packages to a local registry (Nexus or Verdaccio). # # These packages fix vulnerabilities in bundled transitive dependencies # that npm overrides cannot reach (e.g. minimatch/tar inside the npm package). # -# Prerequisites: -# - Nexus running: docker compose -f docker-compose.nexus.yml up -d -# - nexus-init completed (npm-hosted repo exists) +# Prerequisites (choose one): +# Nexus: docker compose -f docker-compose.nexus.yml up -d +# Verdaccio: npx verdaccio --config deployment/verdaccio.yaml & # # Usage: -# ./publish-npm-patches.sh +# ./publish-npm-patches.sh # auto-detect (Nexus first, Verdaccio fallback) +# ./publish-npm-patches.sh --verdaccio # force Verdaccio on :4873 +# ./publish-npm-patches.sh --nexus # force Nexus on :8091 set -euo pipefail @@ -18,10 +20,30 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' +# Parse flags +USE_VERDACCIO=false +USE_NEXUS=false +for arg in "$@"; do + case "$arg" in + --verdaccio) USE_VERDACCIO=true ;; + --nexus) USE_NEXUS=true ;; + esac +done + +# Auto-detect: try Nexus first, fall back to Verdaccio +if ! $USE_VERDACCIO && ! $USE_NEXUS; then + if curl -sf http://localhost:8091/service/rest/v1/status -u admin:nexus >/dev/null 2>&1; then + USE_NEXUS=true + else + USE_VERDACCIO=true + fi +fi + NEXUS_URL="${NEXUS_URL:-http://localhost:8091}" NEXUS_NPM_HOSTED="${NEXUS_URL}/repository/npm-hosted/" NEXUS_USER="${NEXUS_USER:-admin}" NEXUS_PASS="${NEXUS_PASS:-nexus}" +VERDACCIO_URL="${VERDACCIO_URL:-http://localhost:4873}" # Packages to patch — version must be the exact fixed version PATCHES=( @@ -42,20 +64,35 @@ log() { echo -e "${GREEN}[npm-patch]${NC} $*"; } warn() { echo -e "${YELLOW}[npm-patch]${NC} $*"; } fail() { echo -e "${RED}[npm-patch]${NC} $*"; exit 1; } -# Verify Nexus is reachable -log "Checking Nexus at $NEXUS_URL..." -HTTP=$(curl -s -o /dev/null -w "%{http_code}" "$NEXUS_URL/service/rest/v1/status" -u "$NEXUS_USER:$NEXUS_PASS") -if [ "$HTTP" != "200" ]; then - fail "Cannot reach Nexus (HTTP $HTTP). Is it running?" -fi -log "Nexus is up" - -# Configure npm auth for Nexus hosted repo -NEXUS_AUTH=$(echo -n "$NEXUS_USER:$NEXUS_PASS" | base64) NPM_RC="$WORK_DIR/.npmrc" -cat > "$NPM_RC" < "$NPM_RC" < "$NPM_RC" <&1 | grep -v "^npm notice"; then + log " ${GREEN}Published${NC} $pkg_name@$pkg_version" + ((published++)) || true + else + warn " $pkg_name@$pkg_version already exists or publish failed, skipping" ((skipped++)) || true - continue fi - - log " Publishing $tarball_name to Nexus..." - HTTP=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \ - -u "$NEXUS_USER:$NEXUS_PASS" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@$TARBALL" \ - "${NEXUS_NPM_HOSTED}${pkg_name}/-/${tarball_name}") - - case "$HTTP" in - 200|201) - log " ${GREEN}Published${NC} $pkg_name@$pkg_version" - ((published++)) || true - ;; - 400) - warn " $pkg_name@$pkg_version already exists (HTTP 400)" - ((skipped++)) || true - ;; - *) - fail " Failed to publish $pkg_name@$pkg_version (HTTP $HTTP)" - ;; - esac done for pkg_spec in "${PATCHES[@]}"; do @@ -122,42 +137,21 @@ for pkg_spec in "${PATCHES[@]}"; do log "Processing $pkg_name@$pkg_version..." # Check if already published to Nexus - CHECK_URL="${NEXUS_URL}/repository/npm-hosted/${pkg_name}/${pkg_version}" - HTTP=$(curl -s -o /dev/null -w "%{http_code}" "$CHECK_URL") - if [ "$HTTP" = "200" ]; then - warn " $pkg_name@$pkg_version already in Nexus, skipping" - ((skipped++)) || true - continue - fi - - # Download the tarball from npmjs.org + # Download from npmjs.org and publish to local registry cd "$WORK_DIR" TARBALL=$(npm pack "$pkg_spec" 2>/dev/null) if [ ! -f "$TARBALL" ]; then fail " Failed to download $pkg_spec" fi - # Publish to Nexus hosted repo - log " Publishing $TARBALL to Nexus..." - HTTP=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \ - -u "$NEXUS_USER:$NEXUS_PASS" \ - -H "Content-Type: application/octet-stream" \ - --data-binary "@$TARBALL" \ - "${NEXUS_NPM_HOSTED}${pkg_name}/-/${TARBALL}") - - case "$HTTP" in - 200|201) - log " ${GREEN}Published${NC} $pkg_name@$pkg_version" - ((published++)) || true - ;; - 400) - warn " $pkg_name@$pkg_version already exists (HTTP 400)" - ((skipped++)) || true - ;; - *) - fail " Failed to publish $pkg_name@$pkg_version (HTTP $HTTP)" - ;; - esac + log " Publishing $TARBALL..." + if npm publish "$TARBALL" $PUBLISH_ARGS --tag patched 2>&1 | grep -v "^npm notice"; then + log " ${GREEN}Published${NC} $pkg_name@$pkg_version" + ((published++)) || true + else + warn " $pkg_name@$pkg_version already exists or publish failed, skipping" + ((skipped++)) || true + fi rm -f "$TARBALL" done @@ -165,8 +159,8 @@ done echo "" log "Done. published=$published skipped=$skipped" echo "" -log "To use patched packages, add to .npmrc:" -log " registry=${NEXUS_URL}/repository/npm-group/" -echo "" -log "Or use scoped overrides in package.json:" -log ' "overrides": { "minimatch": "10.2.4", "tar": "7.5.11", "@esbuild-kit/core-utils": "3.3.3-metabuilder.0" }' +if $USE_NEXUS; then + log "Nexus npm-group: ${NEXUS_URL}/repository/npm-group/" +else + log "Verdaccio registry: $VERDACCIO_URL" +fi diff --git a/deployment/verdaccio.yaml b/deployment/verdaccio.yaml new file mode 100644 index 000000000..38bbbd202 --- /dev/null +++ b/deployment/verdaccio.yaml @@ -0,0 +1,31 @@ +# Verdaccio configuration for local npm patch registry +# Serves patched packages (e.g. @esbuild-kit/core-utils) and proxies everything +# else to npmjs.org. +# +# Usage: +# npx verdaccio --config deployment/verdaccio.yaml & +# bash deployment/publish-npm-patches.sh --verdaccio +# # .npmrc already points @esbuild-kit:registry to localhost:4873 + +storage: /tmp/verdaccio-storage +uplinks: + npmjs: + url: https://registry.npmjs.org/ + timeout: 60s + max_fails: 3 +packages: + '@esbuild-kit/*': + access: $all + publish: $all + proxy: npmjs + '**': + access: $all + publish: $all + proxy: npmjs +server: + keepAliveTimeout: 60 +log: + type: stdout + format: pretty + level: warn +listen: 0.0.0.0:4873