Merge pull request #26 from AikidoSec/npm-workspace-multiple-packages

Setup npm workspace to support multiple packages
This commit is contained in:
willem-delbare 2025-09-05 15:05:29 +02:00 committed by GitHub
commit 471b3efe4a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
74 changed files with 156 additions and 64 deletions

11
.github/CONTRIBUTING vendored
View file

@ -21,15 +21,20 @@ Report issues on our [GitHub Issues page](https://github.com/AikidoSec/safe-chai
## Development
**Workspace Structure:**
- `packages/safe-chain/` - Main CLI package
- `test/e2e/` - End-to-end tests
**Setup:**
```bash
npm install
npm install # Installs dependencies for all workspaces
```
**Commands:**
- `npm test` - Run tests
- `npm run test:watch` - Watch mode
- `npm test` - Run unit tests
- `npm run test:e2e` - Run end-to-end tests
- `npm run lint` - Check code style
- `npm run test --workspace=packages/safe-chain` - Test specific workspace
**Requirements:**
- Node.js 18+

View file

@ -27,15 +27,24 @@ jobs:
version="${{ github.ref_name }}"
echo "tag=$version" >> $GITHUB_OUTPUT
- name: Set the version
run: npm --no-git-tag-version version ${{ steps.get_version.outputs.tag }}
- name: Set the version in safe-chain package
run: npm --no-git-tag-version version ${{ steps.get_version.outputs.tag }} --workspace=packages/safe-chain
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm run test
- name: Copy documentation files to package
run: |
cp README.md packages/safe-chain/
cp LICENSE packages/safe-chain/
cp -r docs packages/safe-chain/
- name: Publish to npm
run: |
echo "Publishing version ${{ steps.get_version.outputs.tag }} to NPM"
npm publish --access public
npm publish --workspace=packages/safe-chain --access public
env:
NPM_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

View file

@ -29,13 +29,19 @@ jobs:
- name: Run ESLint
run: npm run lint
- name: Create package tarball
run: npm pack --workspace=packages/safe-chain
- name: Upload package tarball
uses: actions/upload-artifact@v4
with:
name: safe-chain-package
path: aikidosec-safe-chain-*.tgz
e2e-tests:
name: Run E2E tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: "test/e2e"
steps:
- name: Checkout code
@ -46,11 +52,11 @@ jobs:
with:
node-version: "lts/*"
- name: Install dependencies
- name: Install dependencies (root)
run: npm ci
- name: Run unit tests
run: npm test
- name: Run E2E tests
run: npm run test:e2e
- name: Clean up Docker resources
if: always()

5
.gitignore vendored
View file

@ -139,3 +139,8 @@ dist
# Vite logs files
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# AI
Claude.md
.claude
.reference

View file

@ -22,5 +22,5 @@ export default defineConfig([
},
rules: {},
},
globalIgnores(['test/e2e']),
globalIgnores(['test/e2e', 'node_modules']),
]);

78
package-lock.json generated
View file

@ -1,29 +1,16 @@
{
"name": "@aikidosec/safe-chain",
"name": "aikido-safe-chain-workspace",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@aikidosec/safe-chain",
"version": "1.0.0",
"name": "aikido-safe-chain-workspace",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@inquirer/prompts": "^7.4.1",
"abbrev": "^3.0.1",
"chalk": "^5.4.1",
"npm-registry-fetch": "^18.0.2",
"ora": "^8.2.0",
"semver": "^7.7.2"
},
"bin": {
"aikido-npm": "bin/aikido-npm.js",
"aikido-npx": "bin/aikido-npx.js",
"aikido-pnpm": "bin/aikido-pnpm.js",
"aikido-pnpx": "bin/aikido-pnpx.js",
"aikido-yarn": "bin/aikido-yarn.js",
"safe-chain": "bin/safe-chain.js"
},
"workspaces": [
"packages/*",
"test/e2e"
],
"devDependencies": {
"@eslint/js": "^9.26.0",
"eslint": "^9.26.0",
@ -32,6 +19,14 @@
"typescript-eslint": "^8.32.0"
}
},
"node_modules/@aikidosec/safe-chain": {
"resolved": "packages/safe-chain",
"link": true
},
"node_modules/@aikidosec/safe-chain-e2e-tests": {
"resolved": "test/e2e",
"link": true
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
@ -3876,6 +3871,12 @@
"node": "^18.17.0 || >=20.5.0"
}
},
"node_modules/nan": {
"version": "2.23.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz",
"integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==",
"license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@ -3892,6 +3893,16 @@
"node": ">= 0.6"
}
},
"node_modules/node-pty": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.0.0.tgz",
"integrity": "sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"nan": "^2.17.0"
}
},
"node_modules/npm-package-arg": {
"version": "12.0.2",
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-12.0.2.tgz",
@ -5764,6 +5775,35 @@
"peerDependencies": {
"zod": "^3.24.1"
}
},
"packages/safe-chain": {
"name": "@aikidosec/safe-chain",
"version": "1.0.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@inquirer/prompts": "^7.4.1",
"abbrev": "^3.0.1",
"chalk": "^5.4.1",
"npm-registry-fetch": "^18.0.2",
"ora": "^8.2.0",
"semver": "^7.7.2"
},
"bin": {
"aikido-npm": "bin/aikido-npm.js",
"aikido-npx": "bin/aikido-npx.js",
"aikido-pnpm": "bin/aikido-pnpm.js",
"aikido-pnpx": "bin/aikido-pnpx.js",
"aikido-yarn": "bin/aikido-yarn.js",
"safe-chain": "bin/safe-chain.js"
}
},
"test/e2e": {
"name": "@aikidosec/safe-chain-e2e-tests",
"version": "1.0.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"node-pty": "^1.0.0"
}
}
}
}

View file

@ -1,36 +1,22 @@
{
"name": "@aikidosec/safe-chain",
"version": "1.0.0",
"name": "aikido-safe-chain-workspace",
"private": true,
"type": "module",
"workspaces": [
"packages/*",
"test/e2e"
],
"scripts": {
"test": "node --test --experimental-test-module-mocks 'src/**/*.spec.js'",
"test:watch": "node --test --watch --experimental-test-module-mocks 'src/**/*.spec.js'",
"lint": "eslint ."
"test": "npm run test --workspace=packages/safe-chain",
"test:e2e": "npm run test --workspace=test/e2e",
"lint": "npm run lint --workspace=packages/safe-chain"
},
"repository": {
"type": "git",
"url": "git+https://github.com/AikidoSec/safe-chain.git"
},
"bin": {
"aikido-npm": "bin/aikido-npm.js",
"aikido-npx": "bin/aikido-npx.js",
"aikido-yarn": "bin/aikido-yarn.js",
"aikido-pnpm": "bin/aikido-pnpm.js",
"aikido-pnpx": "bin/aikido-pnpx.js",
"safe-chain": "bin/safe-chain.js"
},
"type": "module",
"keywords": [],
"author": "Aikido Security",
"license": "AGPL-3.0-or-later",
"description": "The Aikido Safe Chain wraps around the [npm cli](https://github.com/npm/cli), [npx](https://github.com/npm/cli/blob/latest/docs/content/commands/npx.md), [yarn](https://yarnpkg.com/), [pnpm](https://pnpm.io/), and [pnpx](https://pnpm.io/cli/dlx) to provide extra checks before installing new packages. This tool will detect when a package contains malware and prompt you to exit, preventing npm, npx, yarn, pnpm, or pnpx from downloading or running the malware.",
"dependencies": {
"@inquirer/prompts": "^7.4.1",
"abbrev": "^3.0.1",
"chalk": "^5.4.1",
"npm-registry-fetch": "^18.0.2",
"ora": "^8.2.0",
"semver": "^7.7.2"
},
"devDependencies": {
"@eslint/js": "^9.26.0",
"eslint": "^9.26.0",
@ -38,11 +24,6 @@
"globals": "^16.1.0",
"typescript-eslint": "^8.32.0"
},
"main": "eslint.config.js",
"bugs": {
"url": "https://github.com/AikidoSec/safe-chain/issues"
},
"homepage": "https://github.com/AikidoSec/safe-chain#readme",
"overrides": {
"brace-expansion@<=2.0.2": "2.0.2"
}

View file

@ -0,0 +1,5 @@
# Test files
src/**/*.spec.js
# Package files
*.tgz

View file

@ -0,0 +1,40 @@
{
"name": "@aikidosec/safe-chain",
"version": "1.0.0",
"scripts": {
"test": "node --test --experimental-test-module-mocks 'src/**/*.spec.js'",
"test:watch": "node --test --watch --experimental-test-module-mocks 'src/**/*.spec.js'",
"lint": "eslint ."
},
"bin": {
"aikido-npm": "bin/aikido-npm.js",
"aikido-npx": "bin/aikido-npx.js",
"aikido-yarn": "bin/aikido-yarn.js",
"aikido-pnpm": "bin/aikido-pnpm.js",
"aikido-pnpx": "bin/aikido-pnpx.js",
"safe-chain": "bin/safe-chain.js"
},
"type": "module",
"keywords": [],
"author": "Aikido Security",
"license": "AGPL-3.0-or-later",
"description": "The Aikido Safe Chain wraps around the [npm cli](https://github.com/npm/cli), [npx](https://github.com/npm/cli/blob/latest/docs/content/commands/npx.md), [yarn](https://yarnpkg.com/), [pnpm](https://pnpm.io/), and [pnpx](https://pnpm.io/cli/dlx) to provide extra checks before installing new packages. This tool will detect when a package contains malware and prompt you to exit, preventing npm, npx, yarn, pnpm, or pnpx from downloading or running the malware.",
"dependencies": {
"@inquirer/prompts": "^7.4.1",
"abbrev": "^3.0.1",
"chalk": "^5.4.1",
"npm-registry-fetch": "^18.0.2",
"ora": "^8.2.0",
"semver": "^7.7.2"
},
"main": "src/main.js",
"bugs": {
"url": "https://github.com/AikidoSec/safe-chain/issues"
},
"homepage": "https://github.com/AikidoSec/safe-chain#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/AikidoSec/safe-chain.git",
"directory": "packages/safe-chain"
}
}

View file

@ -6,13 +6,13 @@ ENV CI=true
WORKDIR /app
# Copy package files first for better caching
COPY package*.json ./
COPY packages/safe-chain/package*.json ./
# Install dependencies
RUN npm install
# Copy the rest of the application
COPY . .
COPY packages/safe-chain ./
# Build the application
RUN npm --no-git-tag-version version 1.0.0 --allow-same-version

View file

@ -1,5 +1,6 @@
{
"name": "@aikidosec/safe-chain-e2e-tests",
"private": true,
"version": "1.0.0",
"description": "End-to-end tests for the Aikido Safe Chain",
"scripts": {