Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions .github/actions/curation-audit/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: 'Curation Audit'
description: 'On install failure, run a JFrog curation audit against just the packages yarn actually 403d, for a clear policy reason instead of a raw 403'

inputs:
install-log:
description: 'Path to the captured yarn install output'
required: true

runs:
using: 'composite'
steps:
- name: Extract 403d packages from the install log
shell: bash
id: extract
env:
INSTALL_LOG: ${{ inputs.install-log }}
run: |
set -euo pipefail
WORKDIR=$(mktemp -d)
echo "AUDIT_WORKDIR=$WORKDIR" >> "$GITHUB_ENV"

# yarn logs each curation 403 as three lines, and prints the same
# failure twice: once in the resolution tree (with a │/└ prefix) and
# once more in the final summary (no prefix) - the prefix is
# optional here so both forms normalize to the same name@version
# and collapse into one entry via sort -u below.
# ➤ YN0035: │ <name>@npm:<version>: The remote server failed to provide...
# ➤ YN0035: │ Response Code: 403 (Forbidden)
sed -E 's/\x1b\[[0-9;]*m//g' "$INSTALL_LOG" \
| grep "npm:.*: The remote server failed" \
| sed -E 's/.*YN0035: ([│└] )?//' \
| sed -E 's/(@npm:[^:]+): The remote.*/\1/' \
| sed -E 's/@npm:/@/' \
| sort -u > "$WORKDIR/packages.txt" || true

count=$(wc -l < "$WORKDIR/packages.txt" | tr -d ' ')
echo "count=$count" >> "$GITHUB_OUTPUT"
echo "Found $count curation-blocked package(s):"
cat "$WORKDIR/packages.txt"

host=$(echo "${ARTIFACTORY_URL}" | sed -E 's#https?://##')
cat > "$WORKDIR/base.npmrc" <<EOF
registry=${ARTIFACTORY_URL}/artifactory/api/npm/virtual-npm-thirdparty/
//${host}/artifactory/api/npm/virtual-npm-thirdparty/:_authToken=${YARN_NPM_AUTH_TOKEN}
EOF

cat > "$WORKDIR/check_one.sh" <<'SCRIPT'
#!/usr/bin/env bash
set -uo pipefail

pkg="$1"
name="${pkg%@*}"
version="${pkg##*@}"

tmpdir=$(mktemp -d)
cp "${AUDIT_WORKDIR}/base.npmrc" "$tmpdir/.npmrc"
python3 -c '
import json, sys
name, version, out = sys.argv[1], sys.argv[2], sys.argv[3]
json.dump({"name": "curation-audit-synthetic", "version": "1.0.0", "private": True, "dependencies": {name: version}}, open(out, "w"))
' "$name" "$version" "$tmpdir/package.json"

out=$(cd "$tmpdir" && jf ca --run-native --legacy-peer-deps --format=table 2>&1)
exit_status=$?
rm -rf "$tmpdir"

# jf's own exit code doesn't distinguish a real curation block from noise
# (e.g. npm ls ELSPROBLEMS when a package's own peer deps aren't declared
# in this single-package synthetic project) - only treat it as a real
# block when the output actually says so.
if echo "$out" | grep -qE "download blocking policy|Found [1-9][0-9]* blocked packages?"; then
echo "::group::BLOCKED: $pkg"
echo "$out"
echo "::endgroup::"
exit 1
elif [ $exit_status -ne 0 ]; then
echo "::group::Audit inconclusive for $pkg (non-curation resolution error, ignoring)"
echo "$out"
echo "::endgroup::"
fi
exit 0
SCRIPT
chmod +x "$WORKDIR/check_one.sh"

- name: Install jf CLI
if: steps.extract.outputs.count != '0'
shell: bash
run: |
curl -fkL https://getcli.jfrog.io/v2-jf | sh
sudo mv jf /usr/local/bin/jf

- name: Configure jf against the SDK build lane
if: steps.extract.outputs.count != '0'
shell: bash
run: |
jf c add curation-audit-server \
--url="${ARTIFACTORY_URL}" \
--access-token="${YARN_NPM_AUTH_TOKEN}" \
--interactive=false \
--overwrite
jf c use curation-audit-server

- name: Curation audit each blocked package
if: steps.extract.outputs.count != '0'
shell: bash
run: |
set -uo pipefail
xargs -P 8 -n 1 "${AUDIT_WORKDIR}/check_one.sh" < "${AUDIT_WORKDIR}/packages.txt"
exit_status=$?
if [ $exit_status -ne 0 ]; then
echo "::error::Curation blocked one or more packages - see the BLOCKED groups above for the policy reason on each."
exit 1
fi
22 changes: 18 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ env:
jobs:
ci:
name: Lint + Build + Test
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
permissions:
contents: read
id-token: write
Expand All @@ -29,7 +29,14 @@ jobs:
node-version: 22
- run: corepack enable
- name: Install dependencies
run: yarn install --immutable
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log
- name: Lint (eslint)
run: yarn lint
- name: Lint (formatting)
Expand All @@ -44,7 +51,7 @@ jobs:
commitlint:
name: Commitlint
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
permissions:
contents: read
id-token: write
Expand All @@ -57,7 +64,14 @@ jobs:
node-version: 22
- run: corepack enable
- name: Install dependencies
run: yarn install --immutable
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log
- name: Validate PR title
run: echo "$PR_TITLE" | yarn commitlint
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
e2e-tests:
# Skip on fork PRs and Dependabot PRs where repo secrets aren't available
if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }}
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large

steps:
- name: Checkout SDK
Expand Down
50 changes: 42 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ env:
jobs:
ci:
name: Lint + Build + Test
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
permissions:
contents: read
id-token: write
Expand All @@ -35,7 +35,14 @@ jobs:
node-version: 22
- run: corepack enable
- name: Install dependencies
run: yarn install --immutable
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log
- name: Lint (eslint)
run: yarn lint
- name: Lint (formatting)
Expand All @@ -51,7 +58,7 @@ jobs:
name: Release (dry-run)
if: inputs.type == 'dry-run'
needs: [ci]
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
permissions:
contents: write
issues: write
Expand All @@ -71,9 +78,18 @@ jobs:
node-version: 22
- run: corepack enable

- name: Install dependencies
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log

- name: Release (dry-run)
run: |
yarn install --immutable
yarn build
yarn multi-semantic-release --dry-run
env:
Expand All @@ -83,7 +99,7 @@ jobs:
name: Release (beta)
if: inputs.type == 'beta'
needs: [ci]
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
environment: Publish-Beta
permissions:
contents: write
Expand All @@ -104,9 +120,18 @@ jobs:
node-version: 22
- run: corepack enable

- name: Install dependencies
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log

- name: Release (beta)
run: |
yarn install --immutable
yarn build
yarn release
env:
Expand All @@ -118,7 +143,7 @@ jobs:
name: Release (production)
if: inputs.type == 'production'
needs: [ci]
runs-on: ubuntu-latest
runs-on: ubuntu-latest-large
environment: Publish
permissions:
contents: write
Expand All @@ -139,9 +164,18 @@ jobs:
node-version: 22
- run: corepack enable

- name: Install dependencies
run: |
set -o pipefail
yarn install --immutable 2>&1 | tee /tmp/yarn-install.log
- name: Curation Audit (on install failure)
if: failure()
uses: ./.github/actions/curation-audit
with:
install-log: /tmp/yarn-install.log

- name: Release (production)
run: |
yarn install --immutable
yarn build
yarn release
env:
Expand Down
44 changes: 43 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,47 @@
"ts-jest": "^29.1.1",
"typescript": "^5.2.2"
},
"packageManager": "yarn@4.1.0"
"packageManager": "yarn@4.1.0",
"resolutions": {
"flatted@^3.2.9": "^3.4.2",
"ip@^2.0.0": "^2.0.1",
"lodash-es@^4.17.21": "^4.18.0",
"@babel/plugin-transform-modules-systemjs@^7.23.9": "^7.29.4",
"@grpc/grpc-js@~1.9.0": "~1.9.16",
"diff@^5.1.0": "^5.2.2",
"fast-xml-parser@^4.0.12": "^4.5.5",
"glob@^10.2.2": "^10.5.0",
"glob@^10.3.10": "^10.5.0",
"glob@^10.3.7": "^10.5.0",
"image-size@^1.0.2": "^1.2.1",
"protobufjs@^7.2.5": "^7.6.5",
"shell-quote@1.8.0": "^1.9.0",
"shell-quote@^1.7.2": "^1.9.0",
"sigstore@^4.0.0": "^4.1.1",
"minimatch@^9.0.0": "^9.0.4",
"minimatch@^9.0.1": "^9.0.4",
"minimatch@^9.0.3": "^9.0.4",
"@semantic-release/npm@npm:^11.0.0": "^13.1.5",
"npm@^10.0.0": "10.9.0",
"npm@^11.6.2": "11.18.0",
"pacote@^17.0.0": "^17.0.7",
"pacote@^17.0.4": "^17.0.7",
"pacote@^17.0.6": "^17.0.7",
"pacote@^21.0.0": "^21.4.1",
"pacote@^21.0.2": "^21.4.1",
"pacote@^21.4.0": "^21.4.1",
"sigstore@^2.2.0": "^2.2.1",
"ws@^6.2.2": "6.2.4",
"ws@^7": "7.5.11",
"ws@^7.0.0": "7.5.11",
"ws@^7.5.1": "7.5.11",
"undici@^6.23.0": "^6.27.0",
"node-gyp@^12.4.0": "^13.0.1",
"node-gyp@latest": "^13.0.1",
"browserslist@^4.20.4": "^4.24.0",
"browserslist@^4.22.2": "^4.24.0",
"tar": "7.5.20",
"baseline-browser-mapping": "2.10.43",
"electron-to-chromium": "1.5.393"
}
}
Loading
Loading