mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
feat: migrate pmg to nx based release automation (#293)
* feat: Migrate release system to Nx with platform-specific npm packages * add go.work.sum * fix: CI deprecations, stale action pins, and signal propagation * fix: update e2e workflows to pnpm 11 and latest action SHAs * fix: update pmg-e2e.yml to Node 24 with Go and pnpm caching * fix: resolve E2E failures, remove goreleaser-test, update action SHAs * fix: restore goreleaser-test (required check) * fix: escape pnpm workspace detection for yarn/pnpx tests, update action versions
This commit is contained in:
@@ -26,8 +26,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
- uses: ./
|
||||
@@ -65,8 +65,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Write custom PMG config
|
||||
@@ -106,8 +106,8 @@ jobs:
|
||||
matrix:
|
||||
driver: [landlock, bubblewrap]
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 24
|
||||
- uses: ./
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Action must exit non-zero
|
||||
id: run
|
||||
continue-on-error: true
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
@@ -71,15 +71,13 @@ jobs:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Build Binary
|
||||
run: make
|
||||
@@ -93,7 +91,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
@@ -101,7 +99,7 @@ jobs:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Run Goreleaser
|
||||
uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
|
||||
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
||||
with:
|
||||
distribution: goreleaser
|
||||
version: "~> v2"
|
||||
@@ -112,7 +110,7 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||
@@ -124,3 +122,39 @@ jobs:
|
||||
run: |
|
||||
docker buildx build --platform linux/amd64 --load \
|
||||
-t build-container-test:latest .
|
||||
|
||||
release-preflight:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: "24"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
||||
with:
|
||||
install-only: true
|
||||
version: "~> v2"
|
||||
|
||||
- name: Release preflight
|
||||
run: pnpm nx run pmg:release-preflight
|
||||
|
||||
@@ -11,21 +11,17 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
release:
|
||||
timeout-minutes: 60
|
||||
environment: npm-release
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
permissions:
|
||||
contents: write # for goreleaser/goreleaser-action to create a GitHub release
|
||||
packages: write # for goreleaser/goreleaser-action to publish docker images
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# Required for buildx on docker 19.x
|
||||
DOCKER_CLI_EXPERIMENTAL: "enabled"
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -33,39 +29,80 @@ jobs:
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Run GoReleaser
|
||||
id: run-goreleaser
|
||||
uses: goreleaser/goreleaser-action@1a80836c5c9d9e5755a25cb59ec6f45a3b5f41a8 # v7
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
distribution: goreleaser
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Extract version
|
||||
id: version
|
||||
shell: bash
|
||||
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install GoReleaser
|
||||
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
|
||||
with:
|
||||
install-only: true
|
||||
version: "~> v2"
|
||||
args: release --clean
|
||||
|
||||
- name: Build release (goreleaser via Nx)
|
||||
run: pnpm nx run pmg:build-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
|
||||
|
||||
- name: Upload dist Folder
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: dist-artifacts
|
||||
path: dist/
|
||||
|
||||
provenance:
|
||||
needs: [goreleaser]
|
||||
permissions:
|
||||
actions: read # To read the workflow path.
|
||||
id-token: write # To sign the provenance.
|
||||
attestations: write # To write attestations
|
||||
artifact-metadata: write # To write artifact metadata
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download dist folder
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
|
||||
with:
|
||||
name: dist-artifacts
|
||||
path: dist/
|
||||
|
||||
- name: Attest build provenance (checksums)
|
||||
uses: actions/attest-build-provenance@b3e506e8c389afc651c5bacf2b8f2a1ea0557215 # v4
|
||||
- name: Attest Go binary provenance
|
||||
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
|
||||
with:
|
||||
subject-checksums: dist/checksums.txt
|
||||
|
||||
- name: Publish npm packages (sync + build + publish via Nx)
|
||||
run: pnpm nx run pmg:publish-npm
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
test-installation:
|
||||
needs: release
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
node: ["18", "20", "22", "24"]
|
||||
steps:
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
|
||||
- name: Extract version
|
||||
id: version
|
||||
shell: bash
|
||||
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Wait for package on registry
|
||||
shell: bash
|
||||
run: |
|
||||
for i in $(seq 1 20); do
|
||||
npm view "@safedep/pmg@${{ steps.version.outputs.version }}" version > /dev/null 2>&1 && break
|
||||
echo "Waiting... ($i/20)"
|
||||
sleep 30
|
||||
[ "$i" -eq 20 ] && echo "Package not available after 10 minutes" && exit 1
|
||||
done
|
||||
|
||||
- name: Install
|
||||
run: npm install -g "@safedep/pmg@${{ steps.version.outputs.version }}"
|
||||
|
||||
- name: Smoke test
|
||||
run: pmg version
|
||||
|
||||
@@ -31,26 +31,27 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
node-version: "24"
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
@@ -60,7 +61,7 @@ jobs:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Setup uv
|
||||
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39
|
||||
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
||||
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a
|
||||
@@ -224,7 +225,7 @@ jobs:
|
||||
- name: Test PNPM - Single Package & Manifest
|
||||
run: |
|
||||
echo "Testing PNPM single package installation..."
|
||||
mkdir pnpm-test && cd pnpm-test
|
||||
PNPM_TESTDIR=$(mktemp -d) && cd "$PNPM_TESTDIR"
|
||||
pmg --proxy-mode=false pnpm init
|
||||
pmg --proxy-mode=false pnpm add express@5.2.1
|
||||
pmg --proxy-mode=false pnpm add lodash@4.17.21
|
||||
@@ -242,7 +243,7 @@ jobs:
|
||||
test -f pnpm-lock.yaml
|
||||
test -d node_modules/express
|
||||
test -d node_modules/lodash
|
||||
cd .. && rm -rf pnpm-test
|
||||
cd - && rm -rf "$PNPM_TESTDIR"
|
||||
|
||||
- name: Test Bun - Single Package & Manifest
|
||||
run: |
|
||||
@@ -283,7 +284,7 @@ jobs:
|
||||
npm install -g yarn@1.22.22
|
||||
yarn --version
|
||||
|
||||
mkdir yarn-test && cd yarn-test
|
||||
YARN_TESTDIR=$(mktemp -d) && cd "$YARN_TESTDIR"
|
||||
pmg --proxy-mode=false yarn init -y
|
||||
pmg --proxy-mode=false yarn add express@5.2.1
|
||||
pmg --proxy-mode=false yarn add lodash@4.17.21
|
||||
@@ -301,7 +302,7 @@ jobs:
|
||||
test -f yarn.lock
|
||||
test -d node_modules/express
|
||||
test -d node_modules/lodash
|
||||
cd .. && rm -rf yarn-test
|
||||
cd - && rm -rf "$YARN_TESTDIR"
|
||||
|
||||
- name: Test NPX - Package Execution
|
||||
run: |
|
||||
@@ -331,7 +332,7 @@ jobs:
|
||||
- name: Test PNPX - Package Execution
|
||||
run: |
|
||||
echo "Testing PNPX package execution..."
|
||||
mkdir pnpx-test && cd pnpx-test
|
||||
PNPX_TESTDIR=$(mktemp -d) && cd "$PNPX_TESTDIR"
|
||||
|
||||
echo "Testing pnpx with a simple package..."
|
||||
pmg --proxy-mode=false pnpx cowsay@1.6.0 "Hello from pmg pnpx" | tee pnpx-output.txt
|
||||
@@ -351,7 +352,7 @@ jobs:
|
||||
# Verification: dry-run should NOT produce cowsay ASCII art (cow face ^__^ should not appear)
|
||||
! grep -q '\^__\^' pnpx-dry-output.txt
|
||||
|
||||
cd .. && rm -rf pnpx-test
|
||||
cd - && rm -rf "$PNPX_TESTDIR"
|
||||
|
||||
- name: Test Pip - Single Package & Manifest
|
||||
run: |
|
||||
@@ -516,23 +517,24 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
node-version: "24"
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Build PMG
|
||||
run: make
|
||||
@@ -571,23 +573,24 @@ jobs:
|
||||
PMG_SANDBOX_DRIVER: bubblewrap
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
node-version: "24"
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Install Bubblewrap
|
||||
run: sudo apt-get update && sudo apt-get install -y bubblewrap
|
||||
@@ -646,23 +649,24 @@ jobs:
|
||||
npm_config_cache: /tmp/npm-cache
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: true
|
||||
|
||||
- name: Enable corepack
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
node-version: "24"
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Build PMG
|
||||
run: make
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
name: Publish NPM Package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v[0-9]+.[0-9]+.[0-9]+"
|
||||
|
||||
jobs:
|
||||
publish-npm:
|
||||
runs-on: ubuntu-latest
|
||||
environment: npm-release
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
node-version: "24"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: |
|
||||
echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Wait for GitHub release
|
||||
run: |
|
||||
echo "Waiting for GitHub release v${{ steps.version.outputs.version }}..."
|
||||
i=1
|
||||
while [ $i -le 30 ]; do
|
||||
if curl -s -f "https://api.github.com/repos/safedep/pmg/releases/tags/v${{ steps.version.outputs.version }}" > /dev/null; then
|
||||
echo "Release found!"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 30 ]; then
|
||||
echo "Release not found after 10 minutes"
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting... ($i/30)"
|
||||
sleep 20
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
- name: Prepare package
|
||||
run: |
|
||||
cd publish/npm
|
||||
npm version ${{ steps.version.outputs.version }} --no-git-tag-version
|
||||
|
||||
- name: Publish to npm
|
||||
run: |
|
||||
cd publish/npm
|
||||
npm publish --provenance
|
||||
|
||||
test-installation:
|
||||
needs: publish-npm
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
node-version: ["16", "18", "20"]
|
||||
|
||||
steps:
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Wait for npm package
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Waiting for npm package..."
|
||||
i=1
|
||||
while [ $i -le 20 ]; do
|
||||
if npm view @safedep/pmg@${{ steps.version.outputs.version }} > /dev/null 2>&1; then
|
||||
echo "Package available!"
|
||||
break
|
||||
fi
|
||||
if [ $i -eq 20 ]; then
|
||||
echo "Package not available after 10 minutes"
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting... ($i/20)"
|
||||
sleep 30
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
- name: Test installation
|
||||
run: |
|
||||
npm install -g @safedep/pmg@${{ steps.version.outputs.version }}
|
||||
pmg version
|
||||
pmg --help || true
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Enable Cloud Mode
|
||||
run: echo "SAFEDEP_CLOUD_MODE=true" >> $GITHUB_ENV
|
||||
|
||||
+11
-3
@@ -17,9 +17,6 @@
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
bin/
|
||||
|
||||
# env file
|
||||
@@ -27,3 +24,14 @@ bin/
|
||||
|
||||
dist/
|
||||
.DS_Store
|
||||
|
||||
# Nx
|
||||
.nx/
|
||||
node_modules/
|
||||
|
||||
# Platform package binaries (populated by sync-binaries at build time)
|
||||
packages/*/bin/
|
||||
|
||||
# Build artifacts in wrapper package
|
||||
packages/pmg/dist/
|
||||
packages/pmg/README.md
|
||||
|
||||
+22
-1
@@ -11,6 +11,16 @@ builds:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
ignore:
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
ldflags:
|
||||
- -s -w
|
||||
- -X github.com/safedep/pmg/internal/version.Version={{.Version}}
|
||||
- -X github.com/safedep/pmg/internal/version.Commit={{.Commit}}
|
||||
|
||||
archives:
|
||||
- formats: [tar.gz]
|
||||
@@ -39,11 +49,22 @@ checksum:
|
||||
universal_binaries:
|
||||
- replace: true
|
||||
|
||||
brews:
|
||||
homebrew_casks:
|
||||
- name: pmg
|
||||
directory: Casks
|
||||
homepage: https://github.com/safedep/pmg
|
||||
description: "PMG protects developers from malicious packages"
|
||||
license: "Apache-2.0"
|
||||
binaries:
|
||||
- pmg
|
||||
url:
|
||||
verified: github.com/safedep/pmg
|
||||
hooks:
|
||||
post:
|
||||
install: |
|
||||
if OS.mac?
|
||||
system_command "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "#{staged_path}/pmg"]
|
||||
end
|
||||
repository:
|
||||
owner: safedep
|
||||
name: homebrew-tap
|
||||
|
||||
@@ -44,13 +44,13 @@ require (
|
||||
github.com/denisbrodbeck/machineid v1.0.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.14.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.30.2 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
@@ -81,10 +81,10 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/mod v0.33.0 // indirect
|
||||
golang.org/x/net v0.50.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/net v0.51.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
||||
@@ -58,8 +58,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
|
||||
@@ -78,8 +78,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
|
||||
github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
@@ -174,8 +174,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safedep/dry v0.0.0-20260513152148-f809919cc4ce h1:0FxzXTmSrMWse6u0Wv2CbZOjXB1EFZE1qjhF4vB9NOg=
|
||||
github.com/safedep/dry v0.0.0-20260513152148-f809919cc4ce/go.mod h1:tKhOr0osgpefdBbxG8n4H5gYH1GLXidKS+hzNbRQ9LQ=
|
||||
github.com/safedep/dry v0.0.0-20260524092302-4815730a17cf h1:1PorZhAZWANkKup1Ao4kS8s+L6a+dmR+G0waIQonjdY=
|
||||
github.com/safedep/dry v0.0.0-20260524092302-4815730a17cf/go.mod h1:tKhOr0osgpefdBbxG8n4H5gYH1GLXidKS+hzNbRQ9LQ=
|
||||
github.com/safedep/ptyx v0.2.1-0.20260119085117-f667570c2d12 h1:NzARvPtncPbVI8a8Z0JKpJ7XJCSPpsRstV7wAgEtmOU=
|
||||
@@ -243,8 +241,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@@ -262,8 +260,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -285,8 +283,8 @@ golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
|
||||
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
buf.build/gen/go/bufbuild/protovalidate/grpc/go v1.6.1-20240508200655-46a4cf4ba109.1/go.mod h1:12iIaR0LjReZQXXxBXMzWTMUIN6n4Y3HuSTwPpUQYSg=
|
||||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cloud.google.com/go v0.121.2/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/profiler v0.4.3/go.mod h1:3xFodugWfPIQZWFcXdUmfa+yTiiyQ8fWrdT+d2Sg4J0=
|
||||
cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY=
|
||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
deps.dev/api/v3 v3.0.0-20250307021655-d811e36f9cad/go.mod h1:o6PwfRErnKxbT8Sdij64ZMiTqMNxPsYwfymiyjXPh7A=
|
||||
deps.dev/api/v3alpha v0.0.0-20250429014815-ac0aa6a085fa/go.mod h1:qL3BV/n9j5WptUB9hWZrWM6yISapPTUYIQmHMWrGEmk=
|
||||
deps.dev/util/maven v0.0.0-20250307021655-d811e36f9cad/go.mod h1:eGrXziwI7scSGrwIj+5EBHtTeSxAZD/yi8Hb3nFXesA=
|
||||
deps.dev/util/pypi v0.0.0-20250307021655-d811e36f9cad/go.mod h1:qmA0z/Lsfa1FMtuLd9JmVZLMHR3GBX/EmbM6z1X3EDU=
|
||||
deps.dev/util/resolve v0.0.0-20250310223405-f4cf91c9e684/go.mod h1:y8YIleznCUaoZGI9XKQrVNrNd8gcVuPzvAJ7BBcJo5Q=
|
||||
deps.dev/util/semver v0.0.0-20250307021655-d811e36f9cad/go.mod h1:jjJweVqtuMQ7Q4zlTQ/kCHpboojkRvpMYlhy/c93DVU=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/ClickHouse/ch-go v0.66.0/go.mod h1:noiHWyLMJAZ5wYuq3R/K0TcRhrNA8h7o1AqHX0klEhM=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.35.0/go.mod h1:O2FFT/rugdpGEW2VKyEGyMUWyQU0ahmenY9/emxLPxs=
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.0/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
|
||||
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5/go.mod h1:exZ0C/1emQJAw5tHOaUDyY1ycttqBAPcxuzf7QbY6ec=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.52.0/go.mod h1:ayYHuYU7iNcNtEs1K9k6D/Bju7u1VEHMQm5qQ1n3GtM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.52.0/go.mod h1:gdIm9TxRk5soClCwuB0FtdXsbqtw0aqPwBEurK9tPkw=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/Microsoft/hcsshim v0.11.7/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/anchore/go-struct-converter v0.0.0-20230627203149-c72ef8859ca9/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA=
|
||||
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.8/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.15/go.mod h1:yLJzL0IkI9+4BwjPSOueyHzppJj3t0dhK5tbmmcFk5Q=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI=
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/transfermanager v0.1.16/go.mod h1:Iu9wL4lqscFF6ByhqyDO8mgvCUwGn5bqWr7fuOgUjTA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.22/go.mod h1:zd/JsJ4P7oGfUhXn1VyLqaRZwPmZwg44Jf2dS84Dm3Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.13/go.mod h1:CEuVn5WqOMilYl+tbccq8+N2ieCy0gVn3OtRb0vBNNM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.21/go.mod h1:cv3TNhVrssKR0O/xxLJVRfd2oazSnZnkUeTf6ctUwfQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0/go.mod h1:uoA43SdFwacedBfSgfFSjjCvYe8aYBS7EnU5GZ/YKMM=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw=
|
||||
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/brunoga/deep v1.2.4/go.mod h1:GDV6dnXqn80ezsLSZ5Wlv1PdKAWAO4L5PnKYtv2dgaI=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k=
|
||||
github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
|
||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||
github.com/charmbracelet/x/ansi v0.11.5/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY=
|
||||
github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cloudwego/eino v0.7.13/go.mod h1:nA8Vacmuqv3pqKBQbTWENBLQ8MmGmPt/WqiyLeB8ohQ=
|
||||
github.com/cloudwego/eino-ext/components/model/claude v0.1.17/go.mod h1:2sGGgwpR60LW+RdG/hcjdGBVEVEJ6EkKxlva8mju9BI=
|
||||
github.com/cloudwego/eino-ext/components/model/gemini v0.1.5/go.mod h1:yWVzN9Y5TU9MERRStVnfa28uXQbbAk+z/2SCi+G32Vc=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
|
||||
github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc=
|
||||
github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
|
||||
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
|
||||
github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v25.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
|
||||
github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/erikvarga/go-rpmdb v0.0.0-20240208180226-b97e041ef9af/go.mod h1:MiEorPk0IChAoCwpg2FXyqVgbNvOlPWZAYHqqIoDNoY=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/goark/errs v1.3.2/go.mod h1:ZsQucxaDFVfSB8I99j4bxkDRfNOrlKINwg72QMuRWKw=
|
||||
github.com/goark/go-cvss v1.6.7/go.mod h1:qsmYCGTQnQqW/Lq1Z3lRCEarKD++nx7C+KgsG05MhDA=
|
||||
github.com/gohugoio/hashstructure v0.5.0/go.mod h1:Ser0TniXuu/eauYmrwM4o64EBvySxNzITEOLlm4igec=
|
||||
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
|
||||
github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932/go.mod h1:cC6EdPbj/17GFCPDK39NRarlMI+kt+O60S12cNB5J9Y=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w=
|
||||
github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/groob/plist v0.1.1/go.mod h1:itkABA+w2cw7x5nYUS/pLRef6ludkZKOigbROmCTaFw=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY=
|
||||
github.com/knadh/koanf/providers/env v1.0.0/go.mod h1:mzFyRZueYhb37oPmC1HAv/oGEEuyvJDA98r3XAa8Gak=
|
||||
github.com/knadh/koanf/providers/file v1.1.2/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
|
||||
github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0=
|
||||
github.com/knadh/koanf/providers/structs v0.1.0/go.mod h1:sw2YZ3txUcqA3Z27gPlmmBzWn1h8Nt9O6EP/91MkcWE=
|
||||
github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/labstack/echo-contrib v0.17.4/go.mod h1:9O7ZPAHUeMGTOAfg80YqQduHzt0CzLak36PZRldYrZ0=
|
||||
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
|
||||
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/michaelkedar/xml v0.0.0-20250310223042-5d14c9302b17/go.mod h1:KUAB0Nhc2O/lzyPLuWF6Jm/HVC4GIRHWpxTWpy14WHM=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
|
||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
|
||||
github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
|
||||
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
|
||||
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
|
||||
github.com/ossf/osv-schema/bindings/go v0.0.0-20250210065807-ab8a4f6e6389/go.mod h1:lILztSxHU7VsdlYqCnwgxSDBhbXMf7iEQWtldJCDXPo=
|
||||
github.com/pandatix/go-cvss v0.6.2/go.mod h1:jDXYlQBZrc8nvrMUVVvTG8PhmuShOnKrxP53nOFkt8Q=
|
||||
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||
github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
|
||||
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c/go.mod h1:kwM/7r/rVluTE8qJbHAffduuqmSv4knVQT2IajGvSiA=
|
||||
github.com/s2-streamstore/s2-sdk-go v0.14.0/go.mod h1:1a+v2sGqU+s5neI8XwqRJz78ktStkR+mZH/JEi9HNSo=
|
||||
github.com/saferwall/pe v1.5.6/go.mod h1:mJx+PuptmNpoPFBNhWs/uDMFL/kTHVZIkg0d4OUJFbQ=
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d/go.mod h1:PegD7EVqlN88z7TpCqH92hHP+GBpfomGCCnw1PFtNOA=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
|
||||
github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f/go.mod h1:JqzWyvTuI2X4+9wOHmKSQCYxybB/8j6Ko43qVmXDuZg=
|
||||
github.com/spdx/gordf v0.0.0-20221230105357-b735bd5aac89/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||
github.com/spdx/tools-golang v0.5.3/go.mod h1:/ETOahiAo96Ob0/RAIBmFZw6XN0yTnyr/uFZm2NTMhI=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
|
||||
github.com/vektra/mockery/v3 v3.3.2/go.mod h1:erK6TiB02iqKYIvBtegmiz9k/pQUQzE0RwMIb1Y/510=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.61.0/go.mod h1:/V0rmKWoHzXI2ROCfKE2PKPoo6hdlU1GRtzwzuO/3jc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/vuln v1.0.4/go.mod h1:NbJdUQhX8jY++FtuhrXs2Eyx0yePo9pF7nPlIjo9aaQ=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg=
|
||||
google.golang.org/genai v1.21.0/go.mod h1:QPj5NGJw+3wEOHg+PrsWwJKvG6UC84ex5FR7qAYsN/M=
|
||||
google.golang.org/genproto v0.0.0-20250528174236-200df99c418a h1:KXuwdBmgjb4T3l4ZzXhP6HxxFKXD9FcK5/8qfJI4WwU=
|
||||
google.golang.org/genproto v0.0.0-20250528174236-200df99c418a/go.mod h1:Nlk93rrS2X7rV8hiC2gh2A/AJspZhElz9Oh2KGsjLEY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:p3MLuOwURrGBRoEyFHBT3GjUwaCQVKeNqqWxlcISGdw=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gorm.io/driver/clickhouse v0.7.0/go.mod h1:TmNo0wcVTsD4BBObiRnCahUgHJHjBIwuRejHwYt3JRs=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
|
||||
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
||||
gorm.io/plugin/opentelemetry v0.1.14/go.mod h1:ZAp4v5vU1CCcK9Oo8/va5rl6NStrzpSU+a70evd+W/g=
|
||||
gorm.io/plugin/prometheus v0.1.0/go.mod h1:5nrc/JrWCUNoDXCY4eOae/FK/J5WjQ0axXuFusCzdTc=
|
||||
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||
www.velocidex.com/golang/regparser v0.0.0-20240404115756-2169ac0e3c09/go.mod h1:pxSECT5mWM3goJ4sxB4HCJNKnKqiAlpyT8XnvBwkLGU=
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
||||
"defaultBase": "main",
|
||||
"analytics": false,
|
||||
"namedInputs": {
|
||||
"goWorkspaceSources": [
|
||||
"{workspaceRoot}/**/*.go",
|
||||
"{workspaceRoot}/go.mod",
|
||||
"{workspaceRoot}/go.sum",
|
||||
"{workspaceRoot}/.goreleaser.yaml",
|
||||
"!{workspaceRoot}/packages/**",
|
||||
"!{workspaceRoot}/scripts/**",
|
||||
"!{workspaceRoot}/dist/**",
|
||||
"!{workspaceRoot}/bin/**",
|
||||
"!{workspaceRoot}/node_modules/**"
|
||||
],
|
||||
"goSyncSources": [
|
||||
"{workspaceRoot}/scripts/sync-binaries/**/*.go",
|
||||
"{workspaceRoot}/scripts/go.mod",
|
||||
"{workspaceRoot}/scripts/go.sum"
|
||||
],
|
||||
"tsPackageSources": [
|
||||
"{projectRoot}/src/**",
|
||||
"{projectRoot}/tsconfig.json"
|
||||
]
|
||||
},
|
||||
"targetDefaults": {
|
||||
"build": { "cache": true },
|
||||
"build-snapshot": { "cache": true },
|
||||
"run": { "cache": true },
|
||||
"typecheck": { "cache": true }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "pmg-workspace",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/node": "20.19.41",
|
||||
"nx": "23.0.0-beta.11"
|
||||
},
|
||||
"packageManager": "pnpm@11.1.3+sha512.c85357fe17ca12dd23dd7071822666dfd7e3cb76fe214e3370b5ea2fb34f2a231185509b63e717f3cd0acb38dd3f8d82bcd5e8172400ae678b70ea4fbed0896d"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@safedep/pmg-darwin-arm64",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"files": [
|
||||
"bin/**"
|
||||
],
|
||||
"bin": {
|
||||
"pmg": "bin/pmg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@safedep/pmg-darwin-x64",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"files": [
|
||||
"bin/**"
|
||||
],
|
||||
"bin": {
|
||||
"pmg": "bin/pmg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@safedep/pmg-linux-arm64",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"files": [
|
||||
"bin/**"
|
||||
],
|
||||
"bin": {
|
||||
"pmg": "bin/pmg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@safedep/pmg-linux-x64",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"files": [
|
||||
"bin/**"
|
||||
],
|
||||
"bin": {
|
||||
"pmg": "bin/pmg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@safedep/pmg-win32-x64",
|
||||
"version": "0.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"files": [
|
||||
"bin/**"
|
||||
],
|
||||
"bin": {
|
||||
"pmg": "bin/pmg.exe"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@safedep/pmg",
|
||||
"version": "0.0.0",
|
||||
"description": "PMG - Package Manager Guard: protect developers from malicious packages",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": ["security", "supply-chain", "packages", "safedep", "pmg"],
|
||||
"engines": { "node": ">=18" },
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"homepage": "https://safedep.io",
|
||||
"bugs": { "url": "https://github.com/safedep/pmg/issues" },
|
||||
"publishConfig": { "access": "public" },
|
||||
"type": "module",
|
||||
"bin": {
|
||||
"pmg": "dist/bin.cjs"
|
||||
},
|
||||
"files": [
|
||||
"dist/**"
|
||||
],
|
||||
"optionalDependencies": {
|
||||
"@safedep/pmg-linux-x64": "workspace:*",
|
||||
"@safedep/pmg-linux-arm64": "workspace:*",
|
||||
"@safedep/pmg-darwin-x64": "workspace:*",
|
||||
"@safedep/pmg-darwin-arm64": "workspace:*",
|
||||
"@safedep/pmg-win32-x64": "workspace:*"
|
||||
},
|
||||
"scripts": {
|
||||
"prepack": "cp ../../README.md README.md",
|
||||
"build": "tsdown",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "25.9.1",
|
||||
"tsdown": "0.22.0",
|
||||
"typescript": "6.0.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "@safedep/pmg",
|
||||
"root": "packages/pmg",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "sync-binaries", "target": "run"}],
|
||||
"options": {
|
||||
"command": "pnpm run build",
|
||||
"cwd": "{projectRoot}"
|
||||
},
|
||||
"inputs": ["tsPackageSources", "{projectRoot}/tsdown.config.ts"],
|
||||
"outputs": ["{projectRoot}/dist"]
|
||||
},
|
||||
"build-release": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "sync-binaries", "target": "run-release"}],
|
||||
"options": {
|
||||
"command": "pnpm run build",
|
||||
"cwd": "{projectRoot}"
|
||||
},
|
||||
"inputs": ["tsPackageSources", "{projectRoot}/tsdown.config.ts"],
|
||||
"outputs": ["{projectRoot}/dist"],
|
||||
"cache": false
|
||||
},
|
||||
"typecheck": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "pnpm run typecheck",
|
||||
"cwd": "{projectRoot}"
|
||||
},
|
||||
"inputs": ["tsPackageSources"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env node
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, join } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
function pkgNameForHost(): string {
|
||||
const platform = process.platform; // linux | darwin | win32
|
||||
const arch = process.arch; // x64 | arm64
|
||||
return `@safedep/pmg-${platform}-${arch}`;
|
||||
}
|
||||
|
||||
function findBinaryPath(pkgName: string): string {
|
||||
const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
|
||||
const pkgRoot = dirname(pkgJsonPath);
|
||||
const exe = process.platform === "win32" ? "pmg.exe" : "pmg";
|
||||
const p = join(pkgRoot, "bin", exe);
|
||||
if (!existsSync(p)) {
|
||||
throw new Error(
|
||||
`Binary not found at ${p}. The platform package "${pkgName}" is installed but does not contain bin/${exe}.`
|
||||
);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
function main() {
|
||||
const pkgName = pkgNameForHost();
|
||||
let binPath: string;
|
||||
try {
|
||||
binPath = findBinaryPath(pkgName);
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
console.error(
|
||||
[
|
||||
"Failed to locate the platform binary.",
|
||||
`Host: ${process.platform}/${process.arch}`,
|
||||
`Expected platform package: ${pkgName}`,
|
||||
msg,
|
||||
"",
|
||||
"Common causes:",
|
||||
"- optionalDependencies were omitted during install",
|
||||
"- this platform/arch is not published yet",
|
||||
"- the platform package was published without the binary in bin/",
|
||||
].join("\n")
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
|
||||
|
||||
child.on("exit", (code: number | null, signal: string | null) => {
|
||||
if (signal) {
|
||||
process.kill(process.pid, signal as NodeJS.Signals);
|
||||
return;
|
||||
}
|
||||
process.exit(code ?? 1);
|
||||
});
|
||||
child.on("error", (error: Error) => {
|
||||
console.error(`Failed to spawn the binary: ${error}`);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "tsdown";
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/bin.ts"],
|
||||
format: ["cjs"],
|
||||
clean: true,
|
||||
minify: true,
|
||||
});
|
||||
Generated
+1681
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
packages:
|
||||
- 'packages/*'
|
||||
|
||||
allowBuilds:
|
||||
nx: true
|
||||
|
||||
dedupePeers: true
|
||||
minimumReleaseAge: 4320
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "pmg",
|
||||
"root": ".",
|
||||
"targets": {
|
||||
"build-snapshot": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "goreleaser build --clean --snapshot",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"inputs": ["goWorkspaceSources"],
|
||||
"outputs": ["{workspaceRoot}/dist"]
|
||||
},
|
||||
"build-release": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "goreleaser release --clean",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"inputs": ["goWorkspaceSources"],
|
||||
"outputs": ["{workspaceRoot}/dist"],
|
||||
"cache": false
|
||||
},
|
||||
"build-dev": {
|
||||
"executor": "nx:noop",
|
||||
"dependsOn": [{"projects": "@safedep/pmg", "target": "build"}]
|
||||
},
|
||||
"verify": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "pmg", "target": "build-dev"}],
|
||||
"options": {
|
||||
"command": "node packages/pmg/dist/bin.cjs version",
|
||||
"cwd": "{workspaceRoot}"
|
||||
}
|
||||
},
|
||||
"publish-npm": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "@safedep/pmg", "target": "build-release"}],
|
||||
"options": {
|
||||
"command": "pnpm publish -r --provenance --no-git-checks --access public",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"cache": false
|
||||
},
|
||||
"release-preflight": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "pmg", "target": "verify"}],
|
||||
"options": {
|
||||
"command": "pnpm publish -r --dry-run --no-git-checks",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"cache": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
# Exclude the actual binary (but keep the wrapper script)
|
||||
bin/pmg
|
||||
bin/pmg.exe
|
||||
|
||||
# Exclude temp files and directories
|
||||
temp/
|
||||
.temp/
|
||||
|
||||
# Exclude development files
|
||||
node_modules/
|
||||
.git/
|
||||
.gitignore
|
||||
*.log
|
||||
.DS_Store
|
||||
|
||||
# Keep only the wrapper script in bin/
|
||||
!bin/pmg.js
|
||||
@@ -1,66 +0,0 @@
|
||||
<div align="center">
|
||||
<img src="https://raw.githubusercontent.com/safedep/pmg/main/docs/assets/pmg-banner.png" alt="PMG banner">
|
||||
</div>
|
||||
|
||||
# Package Manager Guard (PMG)
|
||||
|
||||
PMG intercepts package installs and checks them for malware before code executes. Install it once, and your usual package manager workflows can stay the same.
|
||||
|
||||
This package is the npm distribution of PMG. The main project README at [`github.com/safedep/pmg`](https://github.com/safedep/pmg) is the source of truth for full documentation.
|
||||
|
||||
## Why PMG?
|
||||
|
||||
- Protects developers and AI coding agents from malicious packages
|
||||
- Wraps tools like `npm`, `pnpm`, `yarn`, `pip`, `poetry`, and `uv`
|
||||
- Adds sandboxing and install-time security checks with minimal workflow changes
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install -g @safedep/pmg
|
||||
```
|
||||
|
||||
You can also install PMG with Homebrew:
|
||||
|
||||
```bash
|
||||
brew install safedep/tap/pmg
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
Set up PMG so your normal package manager commands are protected automatically:
|
||||
|
||||
```bash
|
||||
pmg setup install
|
||||
```
|
||||
|
||||
After setup, restart your terminal and keep using your tools as usual:
|
||||
|
||||
```bash
|
||||
npm install express
|
||||
pnpm add react
|
||||
pip install requests
|
||||
```
|
||||
|
||||
If you prefer, you can also run package manager commands through PMG directly:
|
||||
|
||||
```bash
|
||||
pmg npm install express
|
||||
pmg pnpm add react
|
||||
pmg pip install requests
|
||||
```
|
||||
|
||||
## Platform Support
|
||||
|
||||
- macOS
|
||||
- Linux
|
||||
- Windows
|
||||
|
||||
Requires Node.js 14 or higher.
|
||||
|
||||
## Learn More
|
||||
|
||||
For complete documentation, installation options, troubleshooting, and project updates, see:
|
||||
|
||||
- [Main README](https://github.com/safedep/pmg)
|
||||
- [Quickstart Docs](https://docs.safedep.io/pmg/quickstart)
|
||||
@@ -1,76 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { spawn } = require("child_process");
|
||||
const { ORG_NAME, PACKAGE_NAME, BINARY_NAME } = require("../config");
|
||||
|
||||
const BINARY_NAME_WITH_EXT =
|
||||
process.platform === "win32" ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
||||
const BINARY_PATH = path.join(__dirname, BINARY_NAME_WITH_EXT);
|
||||
|
||||
function main() {
|
||||
// Check if binary exists
|
||||
if (!fs.existsSync(BINARY_PATH)) {
|
||||
console.error(`❌ ${BINARY_NAME_WITH_EXT} binary not found`);
|
||||
console.error(
|
||||
`Try reinstalling: npm install -g ${ORG_NAME}/${PACKAGE_NAME}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Verify binary is executable
|
||||
try {
|
||||
fs.accessSync(BINARY_PATH, fs.constants.F_OK | fs.constants.X_OK);
|
||||
} catch (error) {
|
||||
console.error(`❌ ${BINARY_NAME_WITH_EXT} is not executable`);
|
||||
console.error(
|
||||
`Try reinstalling: npm install -g ${ORG_NAME}/${PACKAGE_NAME}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Pass all arguments to the binary
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
// Spawn the binary with inherited stdio for proper terminal interaction
|
||||
const child = spawn(BINARY_PATH, args, {
|
||||
stdio: "inherit",
|
||||
windowsHide: false,
|
||||
});
|
||||
|
||||
// Handle process termination
|
||||
child.on("error", (error) => {
|
||||
console.error(
|
||||
`❌ Failed to execute ${BINARY_NAME_WITH_EXT}: ${error.message}`,
|
||||
);
|
||||
console.error(
|
||||
`Try reinstalling: npm install -g ${ORG_NAME}/${PACKAGE_NAME}`,
|
||||
);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Exit with the same code as the child process
|
||||
child.on("exit", (code, signal) => {
|
||||
if (signal) {
|
||||
process.kill(process.pid, signal);
|
||||
} else {
|
||||
process.exit(code || 0);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle termination signals
|
||||
process.on("SIGTERM", () => {
|
||||
child.kill("SIGTERM");
|
||||
});
|
||||
|
||||
process.on("SIGINT", () => {
|
||||
child.kill("SIGINT");
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
module.exports = { main };
|
||||
@@ -1,34 +0,0 @@
|
||||
// Configuration for npm binary wrapper
|
||||
|
||||
const ORG_NAME = "@safedep";
|
||||
const PACKAGE_NAME = "pmg";
|
||||
const BINARY_NAME = "pmg";
|
||||
|
||||
// GitHub repository information for releases
|
||||
const REPO_OWNER = "safedep";
|
||||
const REPO_NAME = "pmg";
|
||||
|
||||
// GitHub releases base URL (constructed from repo info)
|
||||
const GITHUB_RELEASES_BASE = `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download`;
|
||||
|
||||
// Platform-specific binary filename patterns (GoReleaser format)
|
||||
const BINARY_PATTERNS = {
|
||||
"darwin-x64": `${BINARY_NAME}_Darwin_all.tar.gz`,
|
||||
"darwin-arm64": `${BINARY_NAME}_Darwin_all.tar.gz`,
|
||||
"linux-x64": `${BINARY_NAME}_Linux_x86_64.tar.gz`,
|
||||
"linux-arm64": `${BINARY_NAME}_Linux_arm64.tar.gz`,
|
||||
"linux-ia32": `${BINARY_NAME}_Linux_i386.tar.gz`,
|
||||
"win32-x64": `${BINARY_NAME}_Windows_x86_64.zip`,
|
||||
"win32-arm64": `${BINARY_NAME}_Windows_arm64.zip`,
|
||||
"win32-ia32": `${BINARY_NAME}_Windows_i386.zip`,
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
ORG_NAME,
|
||||
PACKAGE_NAME,
|
||||
BINARY_NAME,
|
||||
REPO_OWNER,
|
||||
REPO_NAME,
|
||||
GITHUB_RELEASES_BASE,
|
||||
BINARY_PATTERNS,
|
||||
};
|
||||
@@ -1,243 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
const https = require("https");
|
||||
const crypto = require("crypto");
|
||||
const { execSync } = require("child_process");
|
||||
const {
|
||||
BINARY_NAME,
|
||||
REPO_OWNER,
|
||||
REPO_NAME,
|
||||
GITHUB_RELEASES_BASE,
|
||||
BINARY_PATTERNS,
|
||||
} = require("./config");
|
||||
|
||||
// Read version from package.json with strict validation
|
||||
function getValidatedVersion() {
|
||||
try {
|
||||
const packageJson = JSON.parse(
|
||||
fs.readFileSync(path.join(__dirname, "package.json"), "utf8"),
|
||||
);
|
||||
|
||||
const version = packageJson.version;
|
||||
|
||||
// Strict validation: must be valid semver (x.y.z)
|
||||
if (!/^\d+\.\d+\.\d+$/.test(version)) {
|
||||
throw new Error(`Invalid version format: ${version}`);
|
||||
}
|
||||
|
||||
return `v${version}`;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to read valid version: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const RELEASE_VERSION = getValidatedVersion();
|
||||
const BASE_URL = `${GITHUB_RELEASES_BASE}/${RELEASE_VERSION}`;
|
||||
|
||||
// Platform-specific binary URLs (constructed from config)
|
||||
const BINARY_URLS = {};
|
||||
Object.keys(BINARY_PATTERNS).forEach((platform) => {
|
||||
BINARY_URLS[platform] = `${BASE_URL}/${BINARY_PATTERNS[platform]}`;
|
||||
});
|
||||
|
||||
const CHECKSUMS_URL = `${BASE_URL}/checksums.txt`;
|
||||
|
||||
function getPlatformKey() {
|
||||
const platform = process.platform;
|
||||
const arch = process.arch;
|
||||
return `${platform}-${arch}`;
|
||||
}
|
||||
|
||||
function downloadFile(url, dest, maxRedirects = 5) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (maxRedirects < 0) {
|
||||
reject(new Error("Too many redirects"));
|
||||
return;
|
||||
}
|
||||
|
||||
const file = fs.createWriteStream(dest);
|
||||
|
||||
https
|
||||
.get(url, (response) => {
|
||||
if (response.statusCode === 302 || response.statusCode === 301) {
|
||||
file.close();
|
||||
fs.unlink(dest, () => {});
|
||||
return downloadFile(response.headers.location, dest, maxRedirects - 1)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
file.close();
|
||||
fs.unlink(dest, () => {});
|
||||
reject(new Error(`Download failed: ${response.statusCode}`));
|
||||
return;
|
||||
}
|
||||
|
||||
response.pipe(file);
|
||||
|
||||
file.on("finish", () => {
|
||||
file.close();
|
||||
resolve();
|
||||
});
|
||||
|
||||
file.on("error", (err) => {
|
||||
fs.unlink(dest, () => {});
|
||||
reject(err);
|
||||
});
|
||||
})
|
||||
.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
function calculateChecksum(filePath) {
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
const hashSum = crypto.createHash("sha256");
|
||||
hashSum.update(fileBuffer);
|
||||
return hashSum.digest("hex");
|
||||
}
|
||||
|
||||
function validateChecksum(filePath, expectedChecksum) {
|
||||
const actualChecksum = calculateChecksum(filePath);
|
||||
return actualChecksum === expectedChecksum;
|
||||
}
|
||||
|
||||
function extractArchive(archivePath, extractDir) {
|
||||
const isZip = archivePath.endsWith(".zip");
|
||||
|
||||
if (isZip) {
|
||||
if (process.platform === "win32") {
|
||||
execSync(
|
||||
`powershell -NoProfile -Command "Expand-Archive -Force -Path '${archivePath}' -DestinationPath '${extractDir}'"`,
|
||||
{ stdio: "pipe" },
|
||||
);
|
||||
} else {
|
||||
execSync(`unzip -o "${archivePath}" -d "${extractDir}"`, {
|
||||
stdio: "pipe",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
execSync(`tar -xzf "${archivePath}" -C "${extractDir}"`, { stdio: "pipe" });
|
||||
}
|
||||
}
|
||||
|
||||
async function install() {
|
||||
let tempWorkspace;
|
||||
|
||||
try {
|
||||
console.log("📦 Installing PMG binary...");
|
||||
|
||||
// Get platform-specific URL
|
||||
const platformKey = getPlatformKey();
|
||||
const binaryUrl = BINARY_URLS[platformKey];
|
||||
|
||||
if (!binaryUrl) {
|
||||
throw new Error(`Unsupported platform: ${platformKey}`);
|
||||
}
|
||||
|
||||
console.log(`🔍 Platform: ${platformKey}`);
|
||||
console.log(`📡 Version: ${RELEASE_VERSION}`);
|
||||
|
||||
// Create directories
|
||||
const binDir = path.join(__dirname, "bin");
|
||||
tempWorkspace = fs.mkdtempSync(path.join(os.tmpdir(), "pmg-install-"));
|
||||
|
||||
fs.mkdirSync(binDir, { recursive: true });
|
||||
|
||||
// Download binary archive
|
||||
const archiveFilename = path.basename(binaryUrl);
|
||||
const archivePath = path.join(tempWorkspace, archiveFilename);
|
||||
|
||||
console.log(`⬇️ Downloading binary...`);
|
||||
await downloadFile(binaryUrl, archivePath);
|
||||
|
||||
// Download checksums
|
||||
const checksumsPath = path.join(tempWorkspace, "checksums.txt");
|
||||
console.log(`⬇️ Downloading checksums...`);
|
||||
await downloadFile(CHECKSUMS_URL, checksumsPath);
|
||||
|
||||
// Parse checksums file
|
||||
const checksumsContent = fs.readFileSync(checksumsPath, "utf8");
|
||||
const checksumLines = checksumsContent.split("\n");
|
||||
|
||||
let expectedChecksum = null;
|
||||
for (const line of checksumLines) {
|
||||
if (line.includes(archiveFilename)) {
|
||||
expectedChecksum = line.split(/\s+/)[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!expectedChecksum) {
|
||||
throw new Error(`Checksum not found for ${archiveFilename}`);
|
||||
}
|
||||
|
||||
// Validate checksum
|
||||
console.log(`🔐 Validating checksum...`);
|
||||
if (!validateChecksum(archivePath, expectedChecksum)) {
|
||||
throw new Error(
|
||||
"Checksum validation failed - binary may be corrupted or tampered",
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`✅ Checksum validated`);
|
||||
|
||||
// Extract archive
|
||||
console.log(`📂 Extracting binary...`);
|
||||
extractArchive(archivePath, tempWorkspace);
|
||||
|
||||
// Find and move binary
|
||||
const binaryName =
|
||||
process.platform === "win32" ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
||||
const extractedBinaryPath = path.join(tempWorkspace, binaryName);
|
||||
const finalBinaryPath = path.join(binDir, binaryName);
|
||||
|
||||
if (!fs.existsSync(extractedBinaryPath)) {
|
||||
throw new Error(
|
||||
`Binary not found at expected location: ${extractedBinaryPath}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Move binary to final location (handle cross-device links)
|
||||
try {
|
||||
fs.renameSync(extractedBinaryPath, finalBinaryPath);
|
||||
} catch (error) {
|
||||
if (error.code === "EXDEV") {
|
||||
// Cross-device link not permitted, copy and delete instead
|
||||
fs.copyFileSync(extractedBinaryPath, finalBinaryPath);
|
||||
fs.unlinkSync(extractedBinaryPath);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Make executable on Unix systems
|
||||
if (process.platform !== "win32") {
|
||||
fs.chmodSync(finalBinaryPath, "755");
|
||||
}
|
||||
|
||||
// Clean up
|
||||
fs.rmSync(tempWorkspace, { recursive: true, force: true });
|
||||
|
||||
console.log("✅ PMG binary installed successfully!");
|
||||
} catch (error) {
|
||||
console.error("❌ Installation failed:", error.message);
|
||||
|
||||
// Clean up on failure
|
||||
try {
|
||||
if (tempWorkspace && fs.existsSync(tempWorkspace)) {
|
||||
fs.rmSync(tempWorkspace, { recursive: true, force: true });
|
||||
}
|
||||
} catch (cleanupError) {
|
||||
console.warn("⚠️ Failed to clean up:", cleanupError.message);
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run installation
|
||||
install();
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
"name": "@safedep/pmg",
|
||||
"description": "PMG protects developers from getting compromised by malicious packages",
|
||||
"main": "bin/pmg.js",
|
||||
"bin": {
|
||||
"pmg": "bin/pmg.js"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "echo \"Installing PMG binary for your platform...\"",
|
||||
"postinstall": "node install.js"
|
||||
},
|
||||
"keywords": [
|
||||
"security",
|
||||
"package-manager",
|
||||
"malicious-packages",
|
||||
"npm",
|
||||
"cli",
|
||||
"vulnerability",
|
||||
"dependency-security",
|
||||
"safedep"
|
||||
],
|
||||
"author": "SafeDep <devops@safedep.io>",
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://github.com/safedep/pmg#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/safedep/pmg.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/safedep/pmg/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"os": [
|
||||
"darwin",
|
||||
"linux",
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64",
|
||||
"arm64",
|
||||
"ia32"
|
||||
],
|
||||
"files": [
|
||||
"bin/pmg.js",
|
||||
"install.js",
|
||||
"config.js",
|
||||
"test.js",
|
||||
"README.md",
|
||||
".npmignore"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
module github.com/safedep/pmg/scripts
|
||||
|
||||
go 1.25.1
|
||||
|
||||
require (
|
||||
github.com/go-playground/validator/v10 v10.30.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
golang.org/x/crypto v0.49.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.35.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
|
||||
github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,4 @@
|
||||
# sync-binaries
|
||||
|
||||
Copies GoReleaser build artifacts into the npm platform packages under `packages/`.
|
||||
Run via Nx: `pnpm nx run sync-binaries:run` (snapshot) or `pnpm nx run sync-binaries:run-release` (release).
|
||||
@@ -0,0 +1,169 @@
|
||||
// Sync binaries to packages directory from goreleaser's dist/ directory.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type GoreleaserArtifact struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Goos string `json:"goos" validate:"required"`
|
||||
Goarch string `json:"goarch"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
}
|
||||
|
||||
var goArchToNodeArchMap = map[string]string{
|
||||
"amd64": "x64",
|
||||
"386": "x86",
|
||||
"arm64": "arm64",
|
||||
}
|
||||
|
||||
var goOsToNodeOsMap = map[string]string{
|
||||
"windows": "win32",
|
||||
}
|
||||
|
||||
func main() {
|
||||
artifactsPath := flag.String("artifacts-path", "dist/artifacts.json", "Path to goreleaser artifacts.json")
|
||||
packagesPath := flag.String("packages-path", "./packages", "Path to the npm packages directory")
|
||||
strict := flag.Bool("strict", true, "Fail if a package directory does not exist for a built artifact")
|
||||
setVersion := flag.String("set-version", "", "Semver x.y.z to write into all non-private package.json files under packages-path")
|
||||
verifyBins := flag.Bool("verify-bins", false, "Verify that each platform package has a non-empty bin/ directory after sync")
|
||||
flag.Parse()
|
||||
|
||||
artifactsBytes, err := os.ReadFile(*artifactsPath)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read artifacts.json (did you run goreleaser build?): %v", err)
|
||||
}
|
||||
|
||||
var artifacts []GoreleaserArtifact
|
||||
if err := json.Unmarshal(artifactsBytes, &artifacts); err != nil {
|
||||
log.Fatalf("failed to parse artifacts.json: %v", err)
|
||||
}
|
||||
|
||||
validate := validator.New(validator.WithRequiredStructEnabled())
|
||||
|
||||
for _, artifact := range artifacts {
|
||||
switch artifact.Type {
|
||||
case "Binary":
|
||||
if err := validate.Struct(artifact); err != nil {
|
||||
log.Printf("skipping invalid artifact: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// goreleaser v2 emits a universal macOS binary as type "Binary"
|
||||
// with goarch "all" when universal_binaries.replace is true.
|
||||
// Copy it to both darwin platform packages.
|
||||
if artifact.Goos == "darwin" && artifact.Goarch == "all" {
|
||||
for _, nodeArch := range []string{"x64", "arm64"} {
|
||||
packagePath := filepath.Join(*packagesPath, fmt.Sprintf("pmg-darwin-%s", nodeArch))
|
||||
if err := copyToBin(artifact.Path, packagePath, "pmg", *strict); err != nil {
|
||||
log.Fatalf("sync darwin universal -> %s: %v", nodeArch, err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err := syncBinary(artifact, *packagesPath, *strict); err != nil {
|
||||
log.Fatalf("sync: %v", err)
|
||||
}
|
||||
|
||||
case "Universal Binary":
|
||||
// Retained for compatibility with older goreleaser versions that
|
||||
// emitted a distinct type for universal binaries.
|
||||
if artifact.Goos != "darwin" {
|
||||
log.Printf("unexpected universal binary for goos=%s, skipping", artifact.Goos)
|
||||
continue
|
||||
}
|
||||
for _, nodeArch := range []string{"x64", "arm64"} {
|
||||
packagePath := filepath.Join(*packagesPath, fmt.Sprintf("pmg-darwin-%s", nodeArch))
|
||||
if err := copyToBin(artifact.Path, packagePath, "pmg", *strict); err != nil {
|
||||
log.Fatalf("sync darwin universal -> %s: %v", nodeArch, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if *setVersion != "" {
|
||||
if err := setPackageVersions(*packagesPath, *setVersion); err != nil {
|
||||
log.Fatalf("set-version: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if *verifyBins {
|
||||
if err := verifyPackageBins(*packagesPath); err != nil {
|
||||
log.Fatalf("verify-bins: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncBinary(artifact GoreleaserArtifact, packagesPath string, strict bool) error {
|
||||
nodeArch, ok := goArchToNodeArchMap[artifact.Goarch]
|
||||
if !ok {
|
||||
nodeArch = artifact.Goarch
|
||||
}
|
||||
nodeOs, ok := goOsToNodeOsMap[artifact.Goos]
|
||||
if !ok {
|
||||
nodeOs = artifact.Goos
|
||||
}
|
||||
|
||||
packagePath := filepath.Join(packagesPath, fmt.Sprintf("pmg-%s-%s", nodeOs, nodeArch))
|
||||
binName := "pmg"
|
||||
if artifact.Goos == "windows" {
|
||||
binName = "pmg.exe"
|
||||
}
|
||||
return copyToBin(artifact.Path, packagePath, binName, strict)
|
||||
}
|
||||
|
||||
func copyToBin(src, packagePath, binName string, strict bool) error {
|
||||
if _, err := os.Stat(packagePath); os.IsNotExist(err) {
|
||||
if strict {
|
||||
return fmt.Errorf("package directory %s does not exist (add the platform package or remove the goreleaser target)", packagePath)
|
||||
}
|
||||
log.Printf("package directory %s does not exist, skipping", packagePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
binDir := filepath.Join(packagePath, "bin")
|
||||
if err := os.MkdirAll(binDir, 0o755); err != nil { //nolint:gosec // bin/ needs execute permission
|
||||
return fmt.Errorf("create bin dir %s: %w", binDir, err)
|
||||
}
|
||||
|
||||
dst := filepath.Join(binDir, binName)
|
||||
log.Printf("copying %s -> %s", src, dst)
|
||||
return copyFile(src, dst)
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open source: %w", err)
|
||||
}
|
||||
defer srcFile.Close() //nolint:errcheck // read-only; close error is negligible
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create destination: %w", err)
|
||||
}
|
||||
defer dstFile.Close() //nolint:errcheck // Sync() is called explicitly before return; deferred close is best-effort
|
||||
|
||||
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
||||
return fmt.Errorf("copy: %w", err)
|
||||
}
|
||||
if err := dstFile.Sync(); err != nil {
|
||||
return fmt.Errorf("sync: %w", err)
|
||||
}
|
||||
|
||||
srcInfo, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stat source: %w", err)
|
||||
}
|
||||
return os.Chmod(dst, srcInfo.Mode())
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "sync-binaries",
|
||||
"root": "scripts/sync-binaries",
|
||||
"targets": {
|
||||
"run": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [{"projects": "pmg", "target": "build-snapshot"}],
|
||||
"options": {
|
||||
"command": "go run ./scripts/sync-binaries/ --strict --verify-bins --artifacts-path dist/artifacts.json --packages-path ./packages",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"inputs": ["goSyncSources", "{workspaceRoot}/dist/artifacts.json"],
|
||||
"outputs": [
|
||||
"{workspaceRoot}/packages/pmg-linux-x64/bin",
|
||||
"{workspaceRoot}/packages/pmg-linux-arm64/bin",
|
||||
"{workspaceRoot}/packages/pmg-darwin-x64/bin",
|
||||
"{workspaceRoot}/packages/pmg-darwin-arm64/bin",
|
||||
"{workspaceRoot}/packages/pmg-win32-x64/bin"
|
||||
]
|
||||
},
|
||||
"run-release": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "go run ./scripts/sync-binaries/ --strict --verify-bins --artifacts-path dist/artifacts.json --packages-path ./packages --set-version $VERSION",
|
||||
"cwd": "{workspaceRoot}"
|
||||
},
|
||||
"inputs": ["goSyncSources", "{workspaceRoot}/dist/artifacts.json"],
|
||||
"outputs": [
|
||||
"{workspaceRoot}/packages/pmg-linux-x64/bin",
|
||||
"{workspaceRoot}/packages/pmg-linux-arm64/bin",
|
||||
"{workspaceRoot}/packages/pmg-darwin-x64/bin",
|
||||
"{workspaceRoot}/packages/pmg-darwin-arm64/bin",
|
||||
"{workspaceRoot}/packages/pmg-win32-x64/bin"
|
||||
],
|
||||
"cache": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var semverRe = regexp.MustCompile(`^\d+\.\d+\.\d+$`)
|
||||
|
||||
// packageMeta holds the fields from package.json that drive sync decisions.
|
||||
// Only the fields we actually branch on are declared; json.Unmarshal ignores
|
||||
// the rest, so the full file content is never disturbed.
|
||||
type packageMeta struct {
|
||||
Private bool `json:"private"`
|
||||
OS []string `json:"os"`
|
||||
}
|
||||
|
||||
func readPackageMeta(path string) (*packageMeta, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var meta packageMeta
|
||||
if err := json.Unmarshal(data, &meta); err != nil {
|
||||
return nil, fmt.Errorf("parse: %w", err)
|
||||
}
|
||||
return &meta, nil
|
||||
}
|
||||
|
||||
// setPackageVersions scans every immediate subdirectory of packagesPath for a
|
||||
// package.json, skips those with "private": true, and writes version to the
|
||||
// rest. Returns an error on the first failure.
|
||||
func setPackageVersions(packagesPath, version string) error {
|
||||
if !semverRe.MatchString(version) {
|
||||
return fmt.Errorf("invalid version %q: must be x.y.z", version)
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(packagesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read packages dir: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(packagesPath, entry.Name(), "package.json")
|
||||
if err := setVersionInPackageJSON(path, version); err != nil {
|
||||
return fmt.Errorf("package %s: %w", entry.Name(), err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// versionFieldRe is used to swap the "version" field in raw JSON bytes instead
|
||||
// of round-tripping through a Go struct, which would re-serialize arrays and
|
||||
// destroy inline formatting (e.g. "os": ["linux"] would expand to multi-line).
|
||||
// Anchoring to start-of-line prevents false matches inside string values of
|
||||
// other keys. Group 1 captures leading whitespace so indentation is unchanged.
|
||||
var versionFieldRe = regexp.MustCompile(`(?m)^(\s*)"version"\s*:\s*"[^"]*"`)
|
||||
|
||||
// setVersionInPackageJSON reads the file at path, sets "version" to version,
|
||||
// and writes it back. A missing file is silently skipped. Packages with
|
||||
// "private": true are skipped unchanged.
|
||||
//
|
||||
// The replacement is done on the raw bytes so all other formatting (key order,
|
||||
// inline arrays, whitespace) is preserved byte-for-byte.
|
||||
func setVersionInPackageJSON(path, version string) error {
|
||||
data, err := os.ReadFile(path)
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("read: %w", err)
|
||||
}
|
||||
|
||||
var meta packageMeta
|
||||
if err := json.Unmarshal(data, &meta); err != nil {
|
||||
return fmt.Errorf("parse: %w", err)
|
||||
}
|
||||
if meta.Private {
|
||||
return nil
|
||||
}
|
||||
|
||||
repl := fmt.Appendf(nil, "${1}\"version\": \"%s\"", version)
|
||||
updated := versionFieldRe.ReplaceAll(data, repl)
|
||||
|
||||
// 0o644: package.json must be world-readable for npm tooling.
|
||||
return os.WriteFile(path, updated, 0o644) //nolint:gosec
|
||||
}
|
||||
|
||||
// verifyPackageBins checks that every platform package under packagesPath has a
|
||||
// non-empty bin/ directory. Platform packages are identified by the presence of
|
||||
// an "os" field in their package.json; packages without that field (e.g. the
|
||||
// meta/shim package) and private packages are skipped.
|
||||
func verifyPackageBins(packagesPath string) error {
|
||||
entries, err := os.ReadDir(packagesPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read packages dir: %w", err)
|
||||
}
|
||||
|
||||
var missing []string
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
pkgJSONPath := filepath.Join(packagesPath, entry.Name(), "package.json")
|
||||
meta, err := readPackageMeta(pkgJSONPath)
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", entry.Name(), err)
|
||||
}
|
||||
|
||||
if meta.Private || len(meta.OS) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
binDir := filepath.Join(packagesPath, entry.Name(), "bin")
|
||||
binEntries, err := os.ReadDir(binDir)
|
||||
if err != nil || len(binEntries) == 0 {
|
||||
missing = append(missing, entry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return fmt.Errorf("platform packages missing bin/: %s", strings.Join(missing, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// makeDir creates a directory for test fixtures.
|
||||
// 0o755 is the conventional permission for directories that need traversal.
|
||||
func makeDir(t *testing.T, path string) {
|
||||
t.Helper()
|
||||
require.NoError(t, os.MkdirAll(path, 0o755)) //nolint:gosec
|
||||
}
|
||||
|
||||
// writeTestFile writes a file for test fixtures.
|
||||
// 0o644 is the conventional permission for config files like package.json.
|
||||
func writeTestFile(t *testing.T, path string, content []byte) {
|
||||
t.Helper()
|
||||
require.NoError(t, os.WriteFile(path, content, 0o644)) //nolint:gosec
|
||||
}
|
||||
|
||||
func writePkgJSON(t *testing.T, dir, name string, content map[string]any) string {
|
||||
t.Helper()
|
||||
pkgDir := filepath.Join(dir, name)
|
||||
makeDir(t, pkgDir)
|
||||
data, err := json.MarshalIndent(content, "", " ")
|
||||
require.NoError(t, err)
|
||||
path := filepath.Join(pkgDir, "package.json")
|
||||
writeTestFile(t, path, append(data, '\n'))
|
||||
return path
|
||||
}
|
||||
|
||||
func readVersion(t *testing.T, path string) string {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
var pkg map[string]any
|
||||
require.NoError(t, json.Unmarshal(data, &pkg))
|
||||
v, _ := pkg["version"].(string)
|
||||
return v
|
||||
}
|
||||
|
||||
func TestSetPackageVersions(t *testing.T) {
|
||||
t.Run("sets version in all non-private packages", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pathA := writePkgJSON(t, dir, "pkg-a", map[string]any{"name": "pkg-a", "version": "0.0.0"})
|
||||
pathB := writePkgJSON(t, dir, "pkg-b", map[string]any{"name": "pkg-b", "version": "0.0.0"})
|
||||
|
||||
require.NoError(t, setPackageVersions(dir, "1.2.3"))
|
||||
|
||||
assert.Equal(t, "1.2.3", readVersion(t, pathA))
|
||||
assert.Equal(t, "1.2.3", readVersion(t, pathB))
|
||||
})
|
||||
|
||||
t.Run("skips private packages", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
pathPriv := writePkgJSON(t, dir, "private-pkg", map[string]any{
|
||||
"name": "private-pkg",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
})
|
||||
pathPub := writePkgJSON(t, dir, "public-pkg", map[string]any{"name": "public-pkg", "version": "0.0.0"})
|
||||
|
||||
require.NoError(t, setPackageVersions(dir, "2.0.0"))
|
||||
|
||||
assert.Equal(t, "0.0.0", readVersion(t, pathPriv))
|
||||
assert.Equal(t, "2.0.0", readVersion(t, pathPub))
|
||||
})
|
||||
|
||||
t.Run("skips subdirectories without package.json", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
makeDir(t, filepath.Join(dir, "no-pkg-json"))
|
||||
pathA := writePkgJSON(t, dir, "pkg-a", map[string]any{"name": "pkg-a", "version": "0.0.0"})
|
||||
|
||||
require.NoError(t, setPackageVersions(dir, "3.0.0"))
|
||||
|
||||
assert.Equal(t, "3.0.0", readVersion(t, pathA))
|
||||
})
|
||||
|
||||
t.Run("rejects invalid semver", func(t *testing.T) {
|
||||
err := setPackageVersions(t.TempDir(), "not-a-version")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "invalid version")
|
||||
})
|
||||
|
||||
t.Run("returns error when packages dir is missing", func(t *testing.T) {
|
||||
err := setPackageVersions("/nonexistent/path", "1.0.0")
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func writeBinary(t *testing.T, dir, pkgName, binName string) {
|
||||
t.Helper()
|
||||
binDir := filepath.Join(dir, pkgName, "bin")
|
||||
makeDir(t, binDir)
|
||||
// 0o755: binary files need execute permission.
|
||||
require.NoError(t, os.WriteFile(filepath.Join(binDir, binName), []byte("binary"), 0o755)) //nolint:gosec
|
||||
}
|
||||
|
||||
func TestVerifyPackageBins(t *testing.T) {
|
||||
t.Run("passes when all platform packages have binaries", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli-linux-x64", map[string]any{
|
||||
"name": "cli-linux-x64", "version": "0.0.0", "os": []string{"linux"},
|
||||
})
|
||||
writeBinary(t, dir, "cli-linux-x64", "pmg")
|
||||
|
||||
writePkgJSON(t, dir, "cli-darwin-arm64", map[string]any{
|
||||
"name": "cli-darwin-arm64", "version": "0.0.0", "os": []string{"darwin"},
|
||||
})
|
||||
writeBinary(t, dir, "cli-darwin-arm64", "pmg")
|
||||
|
||||
require.NoError(t, verifyPackageBins(dir))
|
||||
})
|
||||
|
||||
t.Run("fails when a platform package has an empty bin/", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli-linux-x64", map[string]any{
|
||||
"name": "cli-linux-x64", "version": "0.0.0", "os": []string{"linux"},
|
||||
})
|
||||
makeDir(t, filepath.Join(dir, "cli-linux-x64", "bin"))
|
||||
|
||||
err := verifyPackageBins(dir)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cli-linux-x64")
|
||||
})
|
||||
|
||||
t.Run("fails when a platform package has no bin/ directory", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli-linux-x64", map[string]any{
|
||||
"name": "cli-linux-x64", "version": "0.0.0", "os": []string{"linux"},
|
||||
})
|
||||
|
||||
err := verifyPackageBins(dir)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cli-linux-x64")
|
||||
})
|
||||
|
||||
t.Run("skips meta packages without os field", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli", map[string]any{
|
||||
"name": "cli", "version": "0.0.0",
|
||||
})
|
||||
|
||||
require.NoError(t, verifyPackageBins(dir))
|
||||
})
|
||||
|
||||
t.Run("skips private packages", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli-private", map[string]any{
|
||||
"name": "cli-private", "version": "0.0.0", "os": []string{"linux"}, "private": true,
|
||||
})
|
||||
|
||||
require.NoError(t, verifyPackageBins(dir))
|
||||
})
|
||||
|
||||
t.Run("reports multiple missing packages", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writePkgJSON(t, dir, "cli-linux-x64", map[string]any{
|
||||
"name": "cli-linux-x64", "version": "0.0.0", "os": []string{"linux"},
|
||||
})
|
||||
writePkgJSON(t, dir, "cli-darwin-x64", map[string]any{
|
||||
"name": "cli-darwin-x64", "version": "0.0.0", "os": []string{"darwin"},
|
||||
})
|
||||
|
||||
err := verifyPackageBins(dir)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cli-linux-x64")
|
||||
assert.Contains(t, err.Error(), "cli-darwin-x64")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetVersionInPackageJSON(t *testing.T) {
|
||||
t.Run("writes version field", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := writePkgJSON(t, dir, "pkg", map[string]any{"name": "pkg", "version": "0.0.0"})
|
||||
|
||||
require.NoError(t, setVersionInPackageJSON(filepath.Join(dir, "pkg", "package.json"), "4.5.6"))
|
||||
|
||||
assert.Equal(t, "4.5.6", readVersion(t, path))
|
||||
})
|
||||
|
||||
t.Run("skips private package", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := writePkgJSON(t, dir, "pkg", map[string]any{"name": "pkg", "version": "0.0.0", "private": true})
|
||||
|
||||
require.NoError(t, setVersionInPackageJSON(filepath.Join(dir, "pkg", "package.json"), "4.5.6"))
|
||||
|
||||
assert.Equal(t, "0.0.0", readVersion(t, path))
|
||||
})
|
||||
|
||||
t.Run("missing file is a no-op", func(t *testing.T) {
|
||||
err := setVersionInPackageJSON("/nonexistent/package.json", "1.0.0")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("preserves inline array formatting", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "pkg", "package.json")
|
||||
makeDir(t, filepath.Dir(path))
|
||||
|
||||
original := `{
|
||||
"name": "pkg",
|
||||
"version": "0.0.0",
|
||||
"os": ["linux"],
|
||||
"cpu": ["x64"],
|
||||
"files": ["bin/**"]
|
||||
}
|
||||
`
|
||||
writeTestFile(t, path, []byte(original))
|
||||
|
||||
require.NoError(t, setVersionInPackageJSON(path, "1.2.3"))
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
content := string(data)
|
||||
|
||||
assert.Contains(t, content, `"version": "1.2.3"`)
|
||||
assert.Contains(t, content, `"os": ["linux"]`)
|
||||
assert.Contains(t, content, `"cpu": ["x64"]`)
|
||||
assert.Contains(t, content, `"files": ["bin/**"]`)
|
||||
})
|
||||
|
||||
t.Run("does not match version inside a string value", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "pkg", "package.json")
|
||||
makeDir(t, filepath.Dir(path))
|
||||
|
||||
original := "{\n \"name\": \"pkg\",\n \"version\": \"0.0.0\",\n \"description\": \"see \\\"version\\\": \\\"1.0.0\\\" in docs\"\n}\n"
|
||||
writeTestFile(t, path, []byte(original))
|
||||
|
||||
require.NoError(t, setVersionInPackageJSON(path, "2.0.0"))
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
content := string(data)
|
||||
|
||||
assert.Contains(t, content, `"version": "2.0.0"`)
|
||||
assert.Contains(t, content, "\"description\": \"see \\\"version\\\": \\\"1.0.0\\\" in docs\"")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user