A mock npm registry server for testing trust configurations with OTP (One-Time Password) authentication.
- Mock trust configuration endpoints (create, list, revoke)
- OTP authentication flow simulation
- Special test packages for error scenarios
- Persistent storage to JSON file
- Debug endpoints for testing
npm installnode index.jsThe server will start on http://localhost:3000
npm config set registry http://localhost:3000# Create a trust configuration
npm trust github mypackage --registry=http://localhost:3000 \
--repository=npm/cli \
--workflow-ref-file=publish.yml
# List trust configurations
npm trust list mypackage --registry=http://localhost:3000
# Revoke a trust configuration
npm trust revoke mypackage --id=<config-id> --registry=http://localhost:3000| Method | Endpoint | Description |
|---|---|---|
| POST | /-/package/:package/trust |
Create trust configuration(s) |
| GET | /-/package/:package/trust |
List trust configurations |
| DELETE | /-/package/:package/trust/:id |
Revoke a trust configuration |
| Method | Endpoint | Description |
|---|---|---|
| GET | /debug |
View current trust store state |
| DELETE | /debug/reset |
Reset all trust configurations |
| Method | Endpoint | Description |
|---|---|---|
| GET | /auth/:sessionId |
OTP authentication page (auto-sets OTP to 123456) |
| POST | /auth/:sessionId |
Submit OTP manually |
| GET | /done/:sessionId |
Poll for OTP completion |
The server supports special package names that trigger specific error scenarios for testing. Use these package names in any API endpoint (GET, POST, DELETE) to simulate different error conditions:
| Package Name | Status Code | Description |
|---|---|---|
not-found-package |
404 | The package doesn't exist in the registry |
invalid-private-package-access |
404 | The package is private and the user doesn't have access (obfuscated - returns 404 instead of 403 to hide the resource's existence) |
invalid-public-package-access |
403 | The package is public but the user doesn't have sufficient permissions to access it |
no-2fa-for-user |
401 | The user authentication is missing or invalid, preventing access to the resource that requires 2FA |
valid-private-package-access-readonly |
200 (GET) / 403 (POST, DELETE) | The package is private and the user has read-only access but not write access |
valid-public-package-access-readonly |
200 (GET) / 403 (POST, DELETE) | The package is public and the user has read-only access but not write access |
Note: All special test package responses include an npm-notice header with a descriptive message about the test scenario being triggered.
# Test package not found scenario
npm trust list not-found-package --registry=http://localhost:3000
# Test private package access denial (obfuscated as 404)
npm trust list invalid-private-package-access --registry=http://localhost:3000
# Test public package access denial
npm trust list invalid-public-package-access --registry=http://localhost:3000
# Test missing 2FA authentication
npm trust list no-2fa-for-user --registry=http://localhost:3000
# Test read-only access (GET works, POST/DELETE fail with 403)
npm trust list valid-private-package-access-readonly --registry=http://localhost:3000
npm trust github valid-private-package-access-readonly --repository=npm/cli --workflow-ref-file=publish.yml --registry=http://localhost:3000
# Test public read-only access
npm trust list valid-public-package-access-readonly --registry=http://localhost:3000
npm trust github valid-public-package-access-readonly --repository=npm/cli --workflow-ref-file=publish.yml --registry=http://localhost:3000All trust operations require OTP authentication. The flow works as follows:
- Request without OTP header returns 401 with
authUrlanddoneUrl - Client opens
authUrlin browser (automatically sets OTP to 123456) - Client polls
doneUrluntil OTP is ready - Client retries original request with
npm-otpheader
Example with curl:
# Initial request (will return 401 with OTP flow URLs)
curl -X POST http://localhost:3000/-/package/mypackage/trust \
-H "Content-Type: application/json" \
-d '[{"type":"github","claims":{"repository":"npm/cli","workflow_ref":{"file":"publish.yml"}}}]'
# After completing OTP flow, retry with OTP header
curl -X POST http://localhost:3000/-/package/mypackage/trust \
-H "Content-Type: application/json" \
-H "npm-otp: 123456" \
-d '[{"type":"github","claims":{"repository":"npm/cli","workflow_ref":{"file":"publish.yml"}}}]'{
"type": "github",
"claims": {
"repository": "npm/cli",
"workflow_ref": {
"file": "publish.yml"
}
},
"environment": "production"
}{
"type": "gitlab",
"claims": {
"project_path": "npm/cli",
"ci_config_ref_uri": {
"file": ".gitlab-ci.yml"
}
},
"environment": "production"
}Trust configurations are persisted to trust-store.json in the project directory. The file is automatically loaded on startup and saved after each modification.
The server exports the router as a function, allowing it to be integrated into other Express applications:
const createTrustRegistryRouter = require('npm-registry-mock-trust');
const express = require('express');
const app = express();
app.use('/custom-path', createTrustRegistryRouter());
app.listen(3000);ISC