surfpr
v0.1.1
Published
Contract Surface Protocol reference implementation - catches breaking changes and security issues
Maintainers
Readme
surfpr
surf (surface) + pr (protocol / pull request)
Reference implementation of the Contract Surface Protocol (CSP).
A CLI tool that detects breaking changes and security issues in your code contracts.
What is Contract Surface Protocol?
CSP is an open standard for defining and protecting code contracts. It provides:
- Surface definitions - Declare which parts of your code are contracts
- Breaking change categories - Standard rules for what constitutes a breaking change
- Violation reporting - Machine-readable format for CI/CD integration
- Confidence scoring - How certain we are about each violation
surfpr is the reference implementation. Other tools can implement CSP for different languages and ecosystems.
Features
- Breaking Change Detection - Detects removed fields, type narrowing, and API surface changes
- Secret Detection - Identifies hardcoded secrets, API keys, and credentials
- Confidence Scoring - Each violation includes a confidence score with explainable factors
- Zero Infrastructure - Runs anywhere: CLI, CI, GitHub Actions
- CSP Compliant - Follows the Contract Surface Protocol specification
Installation
npm install -g surfpr
# or
npx surfprQuick Start
# Initialize .surfaces.yml configuration
surfpr init
# Check for violations
surfpr check
# Check specific files
surfpr check src/api/*.ts
# Check a diff (CI mode)
git diff main | surfpr check --stdinConfiguration
Create a .surfaces.yml in your project root:
version: 1
surfaces:
# API contracts - detect breaking changes
- path: src/api/**/*.ts
type: api
rules:
- no-field-removal
- no-type-narrowing
- backward-compatible
# Secret detection - all files
- path: "**/*"
type: secrets
rules:
- no-hardcoded-secrets
# Files to ignore
ignore:
- "**/node_modules/**"
- "**/*.test.ts"Rules
| Rule | Severity | Description |
|------|----------|-------------|
| no-field-removal | critical | Detect removed exports/fields from interfaces |
| no-type-narrowing | major | Detect type changes that narrow valid values |
| no-hardcoded-secrets | critical | Detect exposed secrets and credentials |
| backward-compatible | critical | Combined breaking change checks |
What is a "Breaking Change"?
A breaking change is any modification that would cause existing consumers to fail:
| Change Type | Example | Why Breaking |
|-------------|---------|--------------|
| Field removal | User.email deleted | Consumers reading email will crash |
| Type narrowing | string → 'a' \| 'b' | Valid strings now rejected |
| Optional → Required | name?: → name: | Missing fields now error |
| Export removal | export interface User deleted | Import statements fail |
Confidence Scoring
Each violation includes a confidence score (0-100%) based on heuristic analysis:
surfpr
✗ 1 violation(s) found
src/config.ts
[critical] no-hardcoded-secrets (line 3) [91%]
Potential Stripe Secret Key detected
Confidence factors:
+40% Known secret prefix: sk_live_
+15% High entropy (4.23) suggests real secret
+10% Long value more likely to be real secretFactors that affect confidence:
- Known secret prefixes (AWS, GitHub, Stripe, etc.)
- Shannon entropy (randomness of the value)
- File path patterns (test vs production)
- Placeholder text detection
- API type naming conventions
GitHub Action
name: Contract Surface Check
on:
pull_request:
branches: [main]
jobs:
surfpr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install surfpr
run: npm install -g surfpr
- name: Check for breaking changes
run: git diff origin/main | surfpr check --stdin --format githubCLI Reference
Usage: surfpr <command> [options]
Commands:
init Create .surfaces.yml configuration
check [files...] Check files for violations
Check Options:
-c, --config <path> Path to config file (default: .surfaces.yml)
-f, --format <format> Output format: text, json, github
--stdin Read unified diff from stdin
-v, --verbose Verbose output (show confidence factors)
-q, --quiet Only output on violations
-h, --help Display helpExit Codes
| Code | Meaning | |------|---------| | 0 | No violations found | | 1 | Violations found | | 2 | Configuration error | | 3 | Runtime error |
Output Formats
Text (default)
surfpr
✗ 1 violation(s) found
src/api/users.ts
[critical] no-field-removal (line 15) [85%]
Field 'email' was removed from interface 'User'JSON
{
"version": "1.0.0",
"violations": [{
"id": "...",
"rule": "no-field-removal",
"severity": "critical",
"confidence": 0.85,
"confidenceFactors": [
{ "factor": "exported", "impact": 0.15, "reason": "Interface is exported (public API)" }
],
"location": { "file": "src/api/users.ts", "line": 15 },
"message": "Field 'email' was removed from interface 'User'"
}]
}GitHub Annotations
::error file=src/api/users.ts,line=15,title=no-field-removal::[85% confidence] Field 'email' was removed from interface 'User'Related
License
MIT
