Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 146 additions & 16 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,45 @@ name: Tests

on:
push:
branches: [ "**" ]
branches: ['**']
pull_request:
branches: [ "**" ]
branches: ['**']

jobs:
integration-tests:
name: Tests (${{ matrix.os }} / ${{ matrix.arch }})
build:
name: Build (shared)
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Build project
run: npm run build

- name: Build Node test bundle
run: npm run build:test-node

- name: Upload build artifacts
uses: actions/upload-artifact@v6
with:
name: build-artifacts
path: |
dist/
dist-test-node/
if-no-files-found: error

bun-tests:
name: Bun Tests (${{ matrix.os }} / ${{ matrix.arch }})
needs: build
runs-on: ${{ matrix.runner }}

strategy:
Expand All @@ -30,12 +62,12 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '18'
node-version: '20'

- name: Setup Bun
uses: oven-sh/setup-bun@v2
Expand Down Expand Up @@ -66,25 +98,123 @@ jobs:
brew install ripgrep zsh

- name: Install Node dependencies
run: npm install
run: npm ci

- name: Build project
run: npm run build
- name: Download build artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: .

- name: Run unit tests
- name: Run Bun unit tests
run: npm run test:unit

- name: Run Bun integration tests
run: npm run test:integration

- name: Upload test results
if: always()
uses: actions/upload-artifact@v6
with:
name: test-results-bun-${{ matrix.os }}-${{ matrix.arch }}
path: |
test-results/
*.log
if-no-files-found: ignore

node-tests:
name: Node ${{ matrix.node-version }} Tests (${{ matrix.os }} / ${{ matrix.arch }})
needs: build
runs-on: ${{ matrix.runner }}

strategy:
fail-fast: false
matrix:
include:
- arch: x86-64
runner: ubuntu-latest
os: linux
node-version: '18'
- arch: x86-64
runner: ubuntu-latest
os: linux
node-version: '20'
- arch: x86-64
runner: ubuntu-latest
os: linux
node-version: '22'
- arch: x86-64
runner: ubuntu-latest
os: linux
node-version: '24'
- arch: arm64
runner: ubuntu-24.04-arm
os: linux
node-version: '24'
- arch: x86-64
runner: macos-15-large
os: macos
node-version: '24'
- arch: arm64
runner: macos-14
os: macos
node-version: '24'

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}

- name: Install system dependencies (Linux)
if: matrix.os == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y bubblewrap libseccomp-dev gcc socat ripgrep apparmor-profiles zsh

- name: Enable unprivileged user namespaces (Linux)
if: matrix.os == 'linux'
run: |
# Ubuntu 24.04+ restricts unprivileged user namespaces by default
# Set setuid bit on bwrap to allow namespace creation
echo "Setting setuid bit on bwrap..."
sudo chmod u+s $(which bwrap)

# Verify bwrap can create namespaces
echo "Testing bwrap namespace creation..."
bwrap --ro-bind / / --unshare-net true && echo "✓ bwrap namespace creation works" || echo "✗ bwrap namespace creation still fails"

- name: Install system dependencies (macOS)
if: matrix.os == 'macos'
run: |
brew install ripgrep zsh

- name: Install Node dependencies
run: npm ci

- name: Download build artifacts
uses: actions/download-artifact@v7
with:
name: build-artifacts
path: .

- name: Run Node.js unit tests
run: node --test dist-test-node/config-validation.test.js dist-test-node/sandbox/seccomp-filter.test.js

- name: Run Node.js fallback tests
run: node test/utils/which-node-test.mjs
run: node test-node/utils/which-node-test.mjs

- name: Run integration tests
run: npm run test:integration
- name: Run Node.js integration tests
run: node --test dist-test-node/sandbox/integration.test.js

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: test-results-${{ matrix.os }}-${{ matrix.arch }}
name: test-results-node${{ matrix.node-version }}-${{ matrix.os }}-${{ matrix.arch }}
path: |
test-results/
*.log
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
environment: npm
environment:
name: npm
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 0

Expand All @@ -35,12 +36,12 @@ jobs:
exit 1
fi

- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'

- run: npm install
- run: npm ci
- run: npm run clean && npm run build

- name: Publish to npm
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
dist
dist-test-node
.claude
.DS_Store
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,10 @@ Uses an **allow-only pattern** - all network access is denied by default.

**Unix Socket Settings** (platform-specific behavior):

| Setting | macOS | Linux |
|---------|-------|-------|
| `allowUnixSockets: string[]` | Allowlist of socket paths | *Ignored* (seccomp can't filter by path) |
| `allowAllUnixSockets: boolean` | Allow all sockets | Disable seccomp blocking |
| Setting | macOS | Linux |
| ------------------------------ | ------------------------- | ---------------------------------------- |
| `allowUnixSockets: string[]` | Allowlist of socket paths | _Ignored_ (seccomp can't filter by path) |
| `allowAllUnixSockets: boolean` | Allow all sockets | Disable seccomp blocking |

Unix sockets are **blocked by default** on both platforms.

Expand Down Expand Up @@ -444,12 +444,15 @@ npm run build
# Build seccomp binaries (requires Docker)
npm run build:seccomp

# Run tests
# Run tests with Bun
npm test

# Run integration tests
npm run test:integration

# Run tests with Node.js (Node 18+)
npm run test:node
npm run test:unit:node
npm run test:integration:node

# Type checking
npm run typecheck

Expand Down Expand Up @@ -501,7 +504,6 @@ Filesystem restrictions are enforced at the OS level:
**Default filesystem permissions:**

- **Read** (deny-only): Allowed everywhere by default. You can deny specific paths.

- Example: `denyRead: ["~/.ssh"]` to block access to SSH keys
- Empty `denyRead: []` = full read access (nothing denied)

Expand Down
24 changes: 23 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ import prettierRecommended from 'eslint-plugin-prettier/recommended'

export default [
{
ignores: ['node_modules/', 'dist/', '**/*.d.ts'],
ignores: [
'node_modules/',
'dist/',
'dist-test-node/',
'**/*.d.ts',
'test-node/**/*.js',
'test-node/**/*.mjs',
],
},
{
files: ['**/*.{js,ts}'],
Expand All @@ -34,6 +41,15 @@ export default [
},
},
},
{
files: ['test-node/**/*.ts'],
languageOptions: {
parserOptions: {
project: './tsconfig.test-node.json',
projectService: false,
},
},
},
{
plugins: {
'eslint-plugin-n': pluginNode,
Expand Down Expand Up @@ -112,5 +128,11 @@ export default [
reportUnusedDisableDirectives: false,
},
},
{
files: ['test-node/**/*.ts'],
rules: {
'@typescript-eslint/no-floating-promises': 'off',
},
},
prettierRecommended,
]
Loading