Security Guide for OpenPets
Last Updated: 2025-11-25 Status: Production Ready
This guide outlines security best practices and tools for developing and publishing OpenPets packages.
🔐 Security Scanner
OpenPets includes a comprehensive security scanner that runs automatically before every publish to prevent accidental exposure of secrets and sensitive files.
Quick Start
# Scan entire project
npm run security:scan
# Scan with verbose output
npm run security:scan:verbose
# Scan specific directory
bun scripts/security-scan.ts --dir pets/maps
# Get JSON output (for CI/CD)
npm run security:scan:json
# Fail on any issue (strictest)
npm run security:check:allWhat It Detects
🔴 Critical Issues
Sensitive Files:
.env,.env.local,.env.productionprivate.key,*.pem,*.keycredentials.json,auth.jsonsecrets.*,*.pfx,*.p12.git-credentials,.npmrc
API Keys & Tokens:
- Google API Keys (
AIza...) - OpenAI API Keys (
sk-...,sk-proj-...) - GitHub Personal Access Tokens (
ghp_...) - NPM Access Tokens (
npm_...) - AWS Access Keys (
AKIA...) - Stripe Live Keys (
sk_live_...) - Bearer Tokens
- Private Keys (PEM format)
- Database connection strings with credentials
🟠 High Severity
- Generic API key patterns
- Configuration files with embedded secrets
- MongoDB/PostgreSQL connection strings
🟡 Medium Severity
- Hardcoded passwords
- NPM configuration files (may contain tokens)
Automatic Protection
The security scanner runs automatically in these scenarios:
- Before npm publish - via prepublish hooks
- During CI/CD - in GitHub Actions
- In publish scripts - integrated into
publish-pet.ts
The publish will fail if critical issues are detected, preventing accidental leaks.
🧱 Secure Subprocess Patterns (CLI)
When adding or updating CLI commands that call external tools (git, opencode, pets, etc.), use these rules:
- Prefer
spawn/spawnSyncorexecFileargument arrays over shell strings. - Never interpolate user-controlled values into shell commands.
- Pass dynamic values (branch names, queries, paths) as separate argv items.
- Normalize or validate command-specific inputs before invocation (for example branch names).
- Treat non-zero subprocess exit codes as failures and surface a clear message.
Example:
const result = spawnSync("git", ["checkout", "-b", branchName], { stdio: "inherit" })Avoid:
execSync(`git checkout -b "${branchName}"`, { stdio: "inherit" })📋 Publishing Security Checklist
Before publishing any package, ensure:
Pre-Publish
- [ ] Run security scan:
npm run security:check - [ ] Review
package.jsonfiles array - [ ] Check
.gitignoreincludes sensitive files - [ ] No
.envfiles in tracked directories - [ ] No hardcoded API keys in code
- [ ] Test installation with
--dry-run
NPM Account Security
- [ ] 2FA enabled on npm account
- [ ] Using granular access tokens (not classic tokens)
- [ ] Tokens restricted to
@openpetsscope only - [ ] Token permissions: Publish only (no admin)
- [ ] Tokens have expiration dates set
Package Configuration
- [ ]
publishConfig.access: "public"set - [ ]
filesarray explicitly whitelist files - [ ] Publish via
bun scripts/publish-pet.ts(handles security checks) - [ ] No sensitive files in
filesarray - [ ]
.npmignoreor.gitignoreproperly configured
🛠️ Security Scanner Configuration
Command Line Options
# Scan specific directory
bun scripts/security-scan.ts --dir pets/maps
# Verbose output (shows all severity levels)
bun scripts/security-scan.ts --verbose
# JSON output (for programmatic use)
bun scripts/security-scan.ts --json
# Fail on different severity levels
bun scripts/security-scan.ts --fail-on critical # Default
bun scripts/security-scan.ts --fail-on high
bun scripts/security-scan.ts --fail-on medium
bun scripts/security-scan.ts --fail-on low # StrictestIgnored Patterns
The scanner automatically ignores:
node_modules/dist/,build/,coverage/*.test.ts,*.spec.ts- Files containing
mock,fixture,example .env.example,.env.template- Binary files (images, fonts, videos, archives)
Exit Codes
0- Security scan passed1- Security issues found at or above fail threshold
🔧 Integration with Publish Workflow
Publish Scripts
The security scanner is integrated into scripts/publish-pet.ts:
// Enhanced security check runs before publish
try {
const srcPath = join(petPath, 'src')
if (await Bun.file(join(petPath, 'tsconfig.json')).exists()) {
const srcStat = await Bun.file(srcPath).exists()
if (srcStat) {
await checkSecurity(srcPath)
}
}
} catch (e) {
console.error("Security check failed:", e)
process.exit(1)
}What happens:
- Scanner checks the
src/directory - Scans all
.ts,.js,.jsonfiles - Checks for sensitive filenames
- Scans content for API key patterns
- Fails the publish if issues found
NPM Hooks
Package.json includes pre-publish hooks:
{
"scripts": {
"prepublish:core": "npm run security:check",
"prepublish:pet": "npm run security:check"
}
}🔐 NPM Provenance
Note: Provenance (
--provenance) is not currently used because the source repository is private. npm provenance requires a public source repository and GitHub-hosted runners. If the repository becomes public in the future, provenance can be re-enabled by adding--provenanceto the publish command inscripts/publish-pet.ts.
🔑 Token Management
Creating Granular Access Tokens
Recommended approach:
# 1. Login to npm
npm login
# 2. Create scoped token
npm token create \
--read-only=false \
--cidr-whitelist=0.0.0.0/0 \
--scope=@openpets \
--description="GitHub Actions Publisher" \
--expires=90dToken Permissions:
- ✅ Read and Publish
- ✅ Scoped to
@openpets/*only - ✅ No admin permissions
- ✅ Expires in 1 year
Environment Variables
For CI/CD:
# GitHub Actions Secrets
NPM_TOKEN=npm_xxxxxxxxxx...Never:
- ❌ Commit tokens to git
- ❌ Use classic tokens (legacy)
- ❌ Give tokens admin permissions
- ❌ Create tokens without expiration
🚨 Responding to Security Issues
If Scanner Detects Issues
- Review the findings - Check what was detected
- Remove sensitive files - Delete or move to gitignored location
- Replace hardcoded secrets - Use environment variables
- Run scanner again - Verify issues are resolved
- Commit changes - Update repository
If Secret Was Published
Immediate Actions:
Rotate the secret immediately
- Generate new API keys
- Update environment variables
- Revoke compromised keys
Unpublish if within 72 hours:
bashnpm unpublish openpets@1.0.xDeprecate if past 72 hours:
bashnpm deprecate openpets@1.0.x "Security issue - please upgrade"Publish fixed version:
bashnpm version patch npm publish --access publicNotify users via:
- GitHub Security Advisory
- npm deprecation message
- README update
📊 Security Audit Logs
Manual Audits
Run comprehensive security checks:
# Full project scan
npm run security:scan:verbose
# Check dependencies for vulnerabilities
npm audit
# Check for outdated packages
npm outdated
# Verify published packages
npm view openpets
npm view @openpets/mapsAutomated Audits
Set up GitHub Actions for automatic scanning:
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: npm run security:check:all
- run: npm audit --audit-level=moderate🎯 Security Best Practices
Code
- Use environment variables for all secrets
- Never hardcode API keys or passwords
- Use .env.example for documentation (without real values)
- Validate input from external sources
- Sanitize user input before processing
Configuration
Keep .gitignore up to date
.env .env.local .env.*.local *.pem *.key credentials.jsonWhitelist files explicitly in package.json
json{ "files": [ "*.ts", "*.js", "src/**/*", "!**/*.test.*" ] }Use .npmignore for additional exclusions
Publishing
- Use
bun scripts/publish-pet.ts --previewto test first - Test with --dry-run before manual publishes
- Review package contents with
npm pack - Enable 2FA on npm account
- Use granular tokens for automation
📚 Additional Resources
🆘 Support
Found a security issue?
Public issues: Open a GitHub issue Security vulnerabilities: Email security@raggle.co (private disclosure)
Response time: 24-48 hours for critical issues