crucible-mcp 0.5.0__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crucible/cli.py +109 -2
- crucible/enforcement/bundled/error-handling.yaml +84 -0
- crucible/enforcement/bundled/security.yaml +123 -0
- crucible/enforcement/bundled/smart-contract.yaml +110 -0
- crucible/enforcement/compliance.py +9 -5
- crucible/hooks/claudecode.py +388 -0
- crucible/hooks/precommit.py +117 -25
- crucible/knowledge/loader.py +186 -0
- crucible/knowledge/principles/API_DESIGN.md +176 -0
- crucible/knowledge/principles/COMMITS.md +127 -0
- crucible/knowledge/principles/DATABASE.md +138 -0
- crucible/knowledge/principles/DOCUMENTATION.md +201 -0
- crucible/knowledge/principles/ERROR_HANDLING.md +157 -0
- crucible/knowledge/principles/FP.md +162 -0
- crucible/knowledge/principles/GITIGNORE.md +218 -0
- crucible/knowledge/principles/OBSERVABILITY.md +147 -0
- crucible/knowledge/principles/PRECOMMIT.md +201 -0
- crucible/knowledge/principles/SECURITY.md +136 -0
- crucible/knowledge/principles/SMART_CONTRACT.md +153 -0
- crucible/knowledge/principles/SYSTEM_DESIGN.md +153 -0
- crucible/knowledge/principles/TESTING.md +129 -0
- crucible/knowledge/principles/TYPE_SAFETY.md +170 -0
- crucible/skills/accessibility-engineer/SKILL.md +71 -0
- crucible/skills/backend-engineer/SKILL.md +69 -0
- crucible/skills/customer-success/SKILL.md +69 -0
- crucible/skills/data-engineer/SKILL.md +70 -0
- crucible/skills/devops-engineer/SKILL.md +69 -0
- crucible/skills/fde-engineer/SKILL.md +69 -0
- crucible/skills/formal-verification/SKILL.md +86 -0
- crucible/skills/gas-optimizer/SKILL.md +89 -0
- crucible/skills/incident-responder/SKILL.md +91 -0
- crucible/skills/mev-researcher/SKILL.md +87 -0
- crucible/skills/mobile-engineer/SKILL.md +70 -0
- crucible/skills/performance-engineer/SKILL.md +68 -0
- crucible/skills/product-engineer/SKILL.md +68 -0
- crucible/skills/protocol-architect/SKILL.md +83 -0
- crucible/skills/security-engineer/SKILL.md +63 -0
- crucible/skills/tech-lead/SKILL.md +92 -0
- crucible/skills/uiux-engineer/SKILL.md +70 -0
- crucible/skills/web3-engineer/SKILL.md +79 -0
- crucible_mcp-1.0.1.dist-info/METADATA +198 -0
- crucible_mcp-1.0.1.dist-info/RECORD +66 -0
- crucible_mcp-0.5.0.dist-info/METADATA +0 -161
- crucible_mcp-0.5.0.dist-info/RECORD +0 -30
- {crucible_mcp-0.5.0.dist-info → crucible_mcp-1.0.1.dist-info}/WHEEL +0 -0
- {crucible_mcp-0.5.0.dist-info → crucible_mcp-1.0.1.dist-info}/entry_points.txt +0 -0
- {crucible_mcp-0.5.0.dist-info → crucible_mcp-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Observability
|
|
3
|
+
description: Logging, metrics, tracing, alerting patterns
|
|
4
|
+
triggers: [logging, monitoring, metrics, tracing, observability]
|
|
5
|
+
type: pattern
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Observability Principles
|
|
9
|
+
|
|
10
|
+
Logs, metrics, traces, and alerting patterns.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The Triad
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Logs: What happened (events, errors)
|
|
18
|
+
Metrics: How much (counters, gauges, histograms)
|
|
19
|
+
Traces: Where (request flow across services)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Minimum Viable Observability
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
├── Structured logs (JSON, not strings)
|
|
28
|
+
├── Error tracking (Sentry)
|
|
29
|
+
├── Basic metrics (response times, error rates)
|
|
30
|
+
├── Health check endpoint
|
|
31
|
+
└── Alerts on SLOs
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Structured Logging
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// String concatenation (hard to parse)
|
|
40
|
+
console.log(`Created tip ${tipId} for page ${pageId}`);
|
|
41
|
+
|
|
42
|
+
// Structured (queryable, machine-readable)
|
|
43
|
+
log.info("Tip created", {
|
|
44
|
+
tipId,
|
|
45
|
+
pageId,
|
|
46
|
+
amountCents,
|
|
47
|
+
timestamp: new Date().toISOString(),
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Log Levels
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
ERROR → Something broke, needs attention
|
|
57
|
+
WARN → Something unexpected, may need attention
|
|
58
|
+
INFO → Normal operation, useful for debugging
|
|
59
|
+
DEBUG → Detailed info, usually disabled in prod
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Health Checks
|
|
65
|
+
|
|
66
|
+
Every service needs health endpoints:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Simple health check
|
|
70
|
+
GET /health
|
|
71
|
+
{ status: "ok" }
|
|
72
|
+
|
|
73
|
+
// Detailed health check
|
|
74
|
+
GET /health/ready
|
|
75
|
+
{
|
|
76
|
+
status: "ok",
|
|
77
|
+
checks: {
|
|
78
|
+
database: "ok",
|
|
79
|
+
redis: "ok",
|
|
80
|
+
externalApi: "degraded"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Metrics to Track
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
├── Request rate (requests/second)
|
|
91
|
+
├── Error rate (errors/requests)
|
|
92
|
+
├── Latency (p50, p95, p99)
|
|
93
|
+
├── Saturation (CPU, memory, connections)
|
|
94
|
+
└── Business metrics (signups, purchases)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Alerting
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
Alert on SLOs, not symptoms:
|
|
103
|
+
├── CPU > 80% (less useful)
|
|
104
|
+
├── Error rate > 1% for 5 minutes (actionable)
|
|
105
|
+
├── p99 latency > 500ms for 10 minutes (actionable)
|
|
106
|
+
|
|
107
|
+
Runnable alerts include:
|
|
108
|
+
├── What's broken?
|
|
109
|
+
├── How to verify?
|
|
110
|
+
├── How to fix?
|
|
111
|
+
├── Who to escalate to?
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Correlation IDs
|
|
117
|
+
|
|
118
|
+
Trace requests across services:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// Generate at edge
|
|
122
|
+
const correlationId = req.headers['x-correlation-id'] || uuid();
|
|
123
|
+
|
|
124
|
+
// Pass to all downstream calls
|
|
125
|
+
await fetch(url, {
|
|
126
|
+
headers: { 'x-correlation-id': correlationId }
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Include in all logs
|
|
130
|
+
log.info("Processing request", { correlationId, ... });
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Observability Budget
|
|
136
|
+
|
|
137
|
+
Plan observability for each feature:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
├── What metrics will you track?
|
|
141
|
+
├── What alerts will fire?
|
|
142
|
+
├── How will you debug in production?
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
*Template. Adapt to your needs.*
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Pre-commit Hooks
|
|
3
|
+
description: Automated checks before commits - linting, formatting, secrets
|
|
4
|
+
triggers: [precommit, hooks, linting, formatting]
|
|
5
|
+
type: pattern
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Pre-commit Hook Principles
|
|
9
|
+
|
|
10
|
+
Automated guardrails before code enters the repo.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install pre-commit
|
|
18
|
+
pre-commit install
|
|
19
|
+
pre-commit run --all-files # Initial scan
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Config: `.pre-commit-config.yaml`
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Secret Detection (Critical)
|
|
27
|
+
|
|
28
|
+
Layer multiple scanners for defense-in-depth:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
repos:
|
|
32
|
+
# Gitleaks - comprehensive secret scanner
|
|
33
|
+
- repo: https://github.com/gitleaks/gitleaks
|
|
34
|
+
rev: v8.18.1
|
|
35
|
+
hooks:
|
|
36
|
+
- id: gitleaks
|
|
37
|
+
|
|
38
|
+
# Detect-secrets by Yelp - another layer
|
|
39
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
40
|
+
rev: v1.4.0
|
|
41
|
+
hooks:
|
|
42
|
+
- id: detect-secrets
|
|
43
|
+
args: ['--baseline', '.secrets.baseline']
|
|
44
|
+
|
|
45
|
+
# Built-in checks
|
|
46
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
47
|
+
rev: v4.5.0
|
|
48
|
+
hooks:
|
|
49
|
+
- id: detect-private-key
|
|
50
|
+
- id: detect-aws-credentials
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Custom Secret Scanner
|
|
56
|
+
|
|
57
|
+
For high-confidence patterns:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
HIGH_CONFIDENCE_PATTERNS=(
|
|
61
|
+
# AWS
|
|
62
|
+
'AKIA[0-9A-Z]{16}'
|
|
63
|
+
|
|
64
|
+
# GitHub tokens
|
|
65
|
+
'ghp_[A-Za-z0-9]{36}'
|
|
66
|
+
'gho_[A-Za-z0-9]{36}'
|
|
67
|
+
|
|
68
|
+
# API keys
|
|
69
|
+
'sk-[A-Za-z0-9]{48}' # OpenAI
|
|
70
|
+
'sk-ant-[A-Za-z0-9\-]{80,}' # Anthropic
|
|
71
|
+
|
|
72
|
+
# Private keys
|
|
73
|
+
'-----BEGIN (RSA |EC )?PRIVATE KEY-----'
|
|
74
|
+
|
|
75
|
+
# Database URLs with passwords
|
|
76
|
+
'postgres://[^:]+:[^@]+@'
|
|
77
|
+
'mongodb://[^:]+:[^@]+@'
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Python Hooks
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
# Ruff - fast linter
|
|
87
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
88
|
+
rev: v0.3.0
|
|
89
|
+
hooks:
|
|
90
|
+
- id: ruff
|
|
91
|
+
args: [--fix]
|
|
92
|
+
- id: ruff-format
|
|
93
|
+
|
|
94
|
+
# MyPy - type checking
|
|
95
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
96
|
+
rev: v1.8.0
|
|
97
|
+
hooks:
|
|
98
|
+
- id: mypy
|
|
99
|
+
additional_dependencies: [types-all]
|
|
100
|
+
args: [--strict]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## File Hygiene
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
109
|
+
rev: v4.5.0
|
|
110
|
+
hooks:
|
|
111
|
+
- id: trailing-whitespace
|
|
112
|
+
- id: end-of-file-fixer
|
|
113
|
+
- id: check-yaml
|
|
114
|
+
- id: check-json
|
|
115
|
+
- id: check-toml
|
|
116
|
+
- id: check-added-large-files
|
|
117
|
+
args: ['--maxkb=500']
|
|
118
|
+
- id: check-merge-conflict
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Commit Message Validation
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
- repo: https://github.com/commitizen-tools/commitizen
|
|
127
|
+
rev: v3.13.0
|
|
128
|
+
hooks:
|
|
129
|
+
- id: commitizen
|
|
130
|
+
stages: [commit-msg]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Enforces semantic commit format: `(type): description`
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## CI Integration
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
ci:
|
|
141
|
+
autofix_commit_msg: |
|
|
142
|
+
[pre-commit.ci] auto fixes from hooks
|
|
143
|
+
autofix_prs: true
|
|
144
|
+
autoupdate_schedule: weekly
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Skip Patterns
|
|
150
|
+
|
|
151
|
+
Files to exclude from scanning:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
SKIP_PATTERNS=(
|
|
155
|
+
'\.lock$'
|
|
156
|
+
'package-lock\.json$'
|
|
157
|
+
'\.min\.js$'
|
|
158
|
+
'vendor/'
|
|
159
|
+
'node_modules/'
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Blocked Commit Response
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
============================================================
|
|
169
|
+
COMMIT BLOCKED: Potential secrets detected!
|
|
170
|
+
============================================================
|
|
171
|
+
|
|
172
|
+
If these are false positives, you can:
|
|
173
|
+
1. Add patterns to .gitignore
|
|
174
|
+
2. Use 'git commit --no-verify' (NOT RECOMMENDED)
|
|
175
|
+
3. Add file to hooks/secrets-allowlist.txt
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Anti-patterns
|
|
181
|
+
|
|
182
|
+
```yaml
|
|
183
|
+
# Bad: no secret detection
|
|
184
|
+
repos:
|
|
185
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
186
|
+
hooks:
|
|
187
|
+
- id: trailing-whitespace
|
|
188
|
+
|
|
189
|
+
# Bad: single layer of detection
|
|
190
|
+
# (one tool might miss what another catches)
|
|
191
|
+
|
|
192
|
+
# Bad: skipping hooks in CI
|
|
193
|
+
skip: [gitleaks, detect-secrets]
|
|
194
|
+
|
|
195
|
+
# Bad: loose file size limits
|
|
196
|
+
args: ['--maxkb=10000']
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
*Pair with comprehensive .gitignore for defense-in-depth.*
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Security Principles
|
|
3
|
+
description: Core security principles - input validation, secrets, injection prevention
|
|
4
|
+
triggers: [security, auth, crypto, api, secrets, injection]
|
|
5
|
+
type: principle
|
|
6
|
+
assertions: security.yaml
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Security Principles
|
|
10
|
+
|
|
11
|
+
Quick reference for secure code patterns.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Review Checklist
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
[ ] Dependencies updated (npm audit, pip audit)
|
|
19
|
+
[ ] No secrets in code or logs
|
|
20
|
+
[ ] Input validation on all endpoints
|
|
21
|
+
[ ] Rate limiting on sensitive routes
|
|
22
|
+
[ ] HTTPS everywhere
|
|
23
|
+
[ ] Auth on protected routes
|
|
24
|
+
[ ] CORS configured correctly
|
|
25
|
+
[ ] CSP headers set
|
|
26
|
+
[ ] SQL injection impossible (ORM/parameterized)
|
|
27
|
+
[ ] XSS prevented (escaped output)
|
|
28
|
+
[ ] CSRF tokens on forms
|
|
29
|
+
[ ] Audit logging for sensitive operations
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Input Validation
|
|
35
|
+
|
|
36
|
+
Validate at every trust boundary.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const handler = (req: Request) => {
|
|
40
|
+
const result = InputSchema.safeParse(req.body);
|
|
41
|
+
if (!result.success) {
|
|
42
|
+
return Response.json({ error: 'Invalid input' }, { status: 400 });
|
|
43
|
+
}
|
|
44
|
+
// Proceed with validated data
|
|
45
|
+
};
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Query Safety
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
// SQL injection risk
|
|
54
|
+
const query = `SELECT * FROM users WHERE id = '${userId}'`;
|
|
55
|
+
|
|
56
|
+
// Parameterized (ORMs do this automatically)
|
|
57
|
+
const user = await prisma.user.findUnique({ where: { id: userId } });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Secrets Management
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
├── Env vars, not in code
|
|
66
|
+
├── Rotate on any suspected leak
|
|
67
|
+
├── Mask secrets in logs
|
|
68
|
+
├── Different secrets per environment
|
|
69
|
+
└── Use secret managers in production
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Defense in Depth
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
┌─────────────────────────────────────────────────────────┐
|
|
78
|
+
│ PREVENTION │
|
|
79
|
+
│ Input validation, auth checks, rate limiting │
|
|
80
|
+
└───────────────────────────┬─────────────────────────────┘
|
|
81
|
+
│ if prevention fails
|
|
82
|
+
▼
|
|
83
|
+
┌─────────────────────────────────────────────────────────┐
|
|
84
|
+
│ DETECTION │
|
|
85
|
+
│ Logging, monitoring, alerts, anomaly detection │
|
|
86
|
+
└───────────────────────────┬─────────────────────────────┘
|
|
87
|
+
│ when detected
|
|
88
|
+
▼
|
|
89
|
+
┌─────────────────────────────────────────────────────────┐
|
|
90
|
+
│ RESPONSE │
|
|
91
|
+
│ Incident runbook, secret rotation, access revocation │
|
|
92
|
+
└───────────────────────────┬─────────────────────────────┘
|
|
93
|
+
│ after response
|
|
94
|
+
▼
|
|
95
|
+
┌─────────────────────────────────────────────────────────┐
|
|
96
|
+
│ RECOVERY │
|
|
97
|
+
│ Backups, audit trail, rollback, post-mortem │
|
|
98
|
+
└─────────────────────────────────────────────────────────┘
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Deserialization Safety
|
|
104
|
+
|
|
105
|
+
Do not deserialize untrusted data into objects that can execute code.
|
|
106
|
+
|
|
107
|
+
| Library | Dangerous | Safe Alternative |
|
|
108
|
+
|---------|-----------|------------------|
|
|
109
|
+
| Python | `pickle.load()`, `eval()` | `json.load()` |
|
|
110
|
+
| PyYAML | `yaml.load()` | `yaml.safe_load()` |
|
|
111
|
+
| subprocess | `shell=True` + user input | `shell=False`, explicit args |
|
|
112
|
+
|
|
113
|
+
**Principle:** If it can reconstruct arbitrary objects, it can execute arbitrary code.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Risk Surface Mapping
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
Step 1: Map Data Flows
|
|
121
|
+
├── Where does data come from?
|
|
122
|
+
├── Where does it go?
|
|
123
|
+
├── Who can access it?
|
|
124
|
+
└── What's the impact if wrong/leaked/lost?
|
|
125
|
+
|
|
126
|
+
Step 2: Categorize Risks
|
|
127
|
+
├── Data Integrity → Wrong data stored
|
|
128
|
+
├── Confidentiality → Sensitive data exposed
|
|
129
|
+
├── Auth Bypass → Unauthorized access
|
|
130
|
+
├── Injection → SQL, XSS, command injection
|
|
131
|
+
└── Denial of Service → Resource exhaustion
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
*Template. Adapt to your needs.*
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Smart Contract Principles
|
|
3
|
+
description: EVM patterns - reentrancy, CEI, gas optimization, upgrade safety
|
|
4
|
+
triggers: [solidity, smart-contract, web3, evm, ethereum, blockchain]
|
|
5
|
+
type: principle
|
|
6
|
+
assertions: smart-contract.yaml
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Smart Contract Principles
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The EVM Cost Model
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
TRADITIONAL BACKEND: SMART CONTRACTS:
|
|
17
|
+
├── State is cheap State costs ~20k gas/32 bytes
|
|
18
|
+
├── Computation is cheap Computation costs gas
|
|
19
|
+
├── Side effects are "free" Side effects cost gas + risk
|
|
20
|
+
├── Bugs are fixable Deployed code is immutable
|
|
21
|
+
└── Complexity is manageable Complexity increases attack surface
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Review Checklist
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
[ ] CEI pattern followed (Checks-Effects-Interactions)
|
|
30
|
+
[ ] Reentrancy guards on external call + value functions
|
|
31
|
+
[ ] No tx.origin for authentication
|
|
32
|
+
[ ] Address zero checks on critical params
|
|
33
|
+
[ ] Slither clean (or findings documented)
|
|
34
|
+
[ ] Access control on privileged functions
|
|
35
|
+
[ ] Events emitted for state changes
|
|
36
|
+
[ ] No hardcoded addresses (use immutable/constructor)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## CEI Pattern
|
|
42
|
+
|
|
43
|
+
Checks-Effects-Interactions:
|
|
44
|
+
|
|
45
|
+
```solidity
|
|
46
|
+
// Safe: CEI pattern
|
|
47
|
+
function withdraw() external {
|
|
48
|
+
uint256 amount = balances[msg.sender]; // CHECK
|
|
49
|
+
balances[msg.sender] = 0; // EFFECT (state first)
|
|
50
|
+
(bool success, ) = msg.sender.call{value: amount}(""); // INTERACTION
|
|
51
|
+
require(success, "Transfer failed");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Unsafe: Interaction before effect = reentrancy
|
|
55
|
+
function withdraw() external {
|
|
56
|
+
uint256 amount = balances[msg.sender];
|
|
57
|
+
(bool success, ) = msg.sender.call{value: amount}(""); // INTERACTION
|
|
58
|
+
balances[msg.sender] = 0; // EFFECT after = vulnerable
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## State Optimization
|
|
65
|
+
|
|
66
|
+
```solidity
|
|
67
|
+
// Constant: Compile-time, zero gas to read
|
|
68
|
+
uint256 public constant MAX_FEE = 1000;
|
|
69
|
+
|
|
70
|
+
// Immutable: Set once in constructor, cheaper reads
|
|
71
|
+
address public immutable owner;
|
|
72
|
+
|
|
73
|
+
// Storage: 20,000 gas to set, 2,100 gas to read
|
|
74
|
+
uint256 public mutableValue;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Common Vulnerabilities
|
|
80
|
+
|
|
81
|
+
### Reentrancy
|
|
82
|
+
```solidity
|
|
83
|
+
// Use ReentrancyGuard
|
|
84
|
+
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
|
|
85
|
+
|
|
86
|
+
function withdraw() external nonReentrant { ... }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### tx.origin
|
|
90
|
+
```solidity
|
|
91
|
+
// Vulnerable to phishing
|
|
92
|
+
require(tx.origin == owner);
|
|
93
|
+
|
|
94
|
+
// Use msg.sender
|
|
95
|
+
require(msg.sender == owner);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Unchecked Returns
|
|
99
|
+
```solidity
|
|
100
|
+
// Ignoring return value
|
|
101
|
+
token.transfer(to, amount);
|
|
102
|
+
|
|
103
|
+
// Using SafeERC20
|
|
104
|
+
using SafeERC20 for IERC20;
|
|
105
|
+
token.safeTransfer(to, amount);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Security Invariants
|
|
111
|
+
|
|
112
|
+
Properties that must hold:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
1. Conservation: sum(balances) == totalSupply
|
|
116
|
+
2. No over-withdrawal: user.withdrawn <= user.entitled
|
|
117
|
+
3. Monotonicity: Open → Settling → Closed (state transitions)
|
|
118
|
+
4. Access: only owner can call admin functions
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Test invariants with fuzzing (Foundry, Echidna).
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Gas Optimization
|
|
126
|
+
|
|
127
|
+
Cache values in hot paths:
|
|
128
|
+
|
|
129
|
+
```solidity
|
|
130
|
+
// Cache array length
|
|
131
|
+
uint256 len = values.length;
|
|
132
|
+
for (uint256 i; i < len; ) {
|
|
133
|
+
total += values[i];
|
|
134
|
+
unchecked { ++i; } // Safe when i < len
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Prioritize clarity for infrequent operations.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Anti-Patterns
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
- Premature upgradeability (adds complexity, admin risk)
|
|
146
|
+
- Deep inheritance (hard to audit)
|
|
147
|
+
- God contracts (too much in one place)
|
|
148
|
+
- Magic numbers (use constants)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
*Template. Adapt to your needs.*
|