claude-mpm 4.17.0__py3-none-any.whl → 4.18.3__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +48 -17
- claude_mpm/agents/agent_loader.py +4 -4
- claude_mpm/agents/templates/engineer.json +5 -1
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/core/config.py +42 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/auto_config_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/cli/session_manager.py +87 -0
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/mcp_config_manager.py +2 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/unified/deployment_strategies/local.py +1 -1
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/METADATA +68 -1
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/RECORD +52 -29
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.17.0.dist-info → claude_mpm-4.18.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_id: refactoring-patterns
|
|
3
|
+
skill_version: 0.1.0
|
|
4
|
+
description: Common refactoring techniques to improve code quality without changing behavior.
|
|
5
|
+
updated_at: 2025-10-30T17:00:00Z
|
|
6
|
+
tags: [refactoring, code-quality, patterns, maintainability]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Refactoring Patterns
|
|
10
|
+
|
|
11
|
+
Common refactoring techniques to improve code quality without changing behavior.
|
|
12
|
+
|
|
13
|
+
## Extract Method
|
|
14
|
+
```python
|
|
15
|
+
# Before: Long method doing multiple things
|
|
16
|
+
def process_order(order):
|
|
17
|
+
# Validate
|
|
18
|
+
if not order.items:
|
|
19
|
+
raise ValueError("Empty order")
|
|
20
|
+
# Calculate
|
|
21
|
+
total = sum(item.price for item in order.items)
|
|
22
|
+
tax = total * 0.1
|
|
23
|
+
# Save
|
|
24
|
+
db.save(order)
|
|
25
|
+
return total + tax
|
|
26
|
+
|
|
27
|
+
# After: Extracted into focused methods
|
|
28
|
+
def process_order(order):
|
|
29
|
+
validate_order(order)
|
|
30
|
+
total = calculate_total(order)
|
|
31
|
+
save_order(order)
|
|
32
|
+
return total
|
|
33
|
+
|
|
34
|
+
def validate_order(order):
|
|
35
|
+
if not order.items:
|
|
36
|
+
raise ValueError("Empty order")
|
|
37
|
+
|
|
38
|
+
def calculate_total(order):
|
|
39
|
+
subtotal = sum(item.price for item in order.items)
|
|
40
|
+
tax = subtotal * 0.1
|
|
41
|
+
return subtotal + tax
|
|
42
|
+
|
|
43
|
+
def save_order(order):
|
|
44
|
+
db.save(order)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Extract Variable
|
|
48
|
+
```python
|
|
49
|
+
# Before: Complex expression
|
|
50
|
+
if (user.age >= 18 and user.has_license and
|
|
51
|
+
user.insurance_valid and not user.suspended):
|
|
52
|
+
allow_driving()
|
|
53
|
+
|
|
54
|
+
# After: Named variable
|
|
55
|
+
is_eligible_driver = (
|
|
56
|
+
user.age >= 18 and
|
|
57
|
+
user.has_license and
|
|
58
|
+
user.insurance_valid and
|
|
59
|
+
not user.suspended
|
|
60
|
+
)
|
|
61
|
+
if is_eligible_driver:
|
|
62
|
+
allow_driving()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Replace Magic Number
|
|
66
|
+
```python
|
|
67
|
+
# Before
|
|
68
|
+
if response.status == 200:
|
|
69
|
+
process()
|
|
70
|
+
|
|
71
|
+
# After
|
|
72
|
+
HTTP_OK = 200
|
|
73
|
+
if response.status == HTTP_OK:
|
|
74
|
+
process()
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Replace Conditional with Polymorphism
|
|
78
|
+
```python
|
|
79
|
+
# Before
|
|
80
|
+
class Animal:
|
|
81
|
+
def make_sound(self):
|
|
82
|
+
if self.type == "dog":
|
|
83
|
+
return "Woof"
|
|
84
|
+
elif self.type == "cat":
|
|
85
|
+
return "Meow"
|
|
86
|
+
|
|
87
|
+
# After
|
|
88
|
+
class Dog(Animal):
|
|
89
|
+
def make_sound(self):
|
|
90
|
+
return "Woof"
|
|
91
|
+
|
|
92
|
+
class Cat(Animal):
|
|
93
|
+
def make_sound(self):
|
|
94
|
+
return "Meow"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Extract Class
|
|
98
|
+
```python
|
|
99
|
+
# Before: God class doing too much
|
|
100
|
+
class User:
|
|
101
|
+
def __init__(self):
|
|
102
|
+
self.name = ""
|
|
103
|
+
self.email = ""
|
|
104
|
+
self.street = ""
|
|
105
|
+
self.city = ""
|
|
106
|
+
self.zip = ""
|
|
107
|
+
|
|
108
|
+
def format_address(self):
|
|
109
|
+
return f"{self.street}, {self.city} {self.zip}"
|
|
110
|
+
|
|
111
|
+
# After: Separate concerns
|
|
112
|
+
class Address:
|
|
113
|
+
def __init__(self, street, city, zip_code):
|
|
114
|
+
self.street = street
|
|
115
|
+
self.city = city
|
|
116
|
+
self.zip = zip_code
|
|
117
|
+
|
|
118
|
+
def format(self):
|
|
119
|
+
return f"{self.street}, {self.city} {self.zip}"
|
|
120
|
+
|
|
121
|
+
class User:
|
|
122
|
+
def __init__(self, name, email, address):
|
|
123
|
+
self.name = name
|
|
124
|
+
self.email = email
|
|
125
|
+
self.address = address
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Introduce Parameter Object
|
|
129
|
+
```python
|
|
130
|
+
# Before: Too many parameters
|
|
131
|
+
def create_user(name, email, street, city, zip_code, phone):
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
# After: Group related parameters
|
|
135
|
+
@dataclass
|
|
136
|
+
class UserData:
|
|
137
|
+
name: str
|
|
138
|
+
email: str
|
|
139
|
+
address: Address
|
|
140
|
+
phone: str
|
|
141
|
+
|
|
142
|
+
def create_user(user_data: UserData):
|
|
143
|
+
pass
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Replace Loop with Pipeline
|
|
147
|
+
```python
|
|
148
|
+
# Before: Imperative loop
|
|
149
|
+
result = []
|
|
150
|
+
for item in items:
|
|
151
|
+
if item.active:
|
|
152
|
+
processed = process(item)
|
|
153
|
+
result.append(processed)
|
|
154
|
+
|
|
155
|
+
# After: Functional pipeline
|
|
156
|
+
result = [
|
|
157
|
+
process(item)
|
|
158
|
+
for item in items
|
|
159
|
+
if item.active
|
|
160
|
+
]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## When to Refactor
|
|
164
|
+
- Before adding new feature (make room)
|
|
165
|
+
- During code review (improve quality)
|
|
166
|
+
- When fixing bugs (prevent recurrence)
|
|
167
|
+
- When code smells emerge (tech debt)
|
|
168
|
+
|
|
169
|
+
## Refactoring Safety
|
|
170
|
+
1. Have tests in place
|
|
171
|
+
2. Make small changes
|
|
172
|
+
3. Test after each change
|
|
173
|
+
4. Commit frequently
|
|
174
|
+
5. Use IDE refactoring tools
|
|
175
|
+
|
|
176
|
+
## Remember
|
|
177
|
+
- Refactor or add feature, never both
|
|
178
|
+
- Tests must pass before and after
|
|
179
|
+
- Small steps are safer than big rewrites
|
|
180
|
+
- Leave code better than you found it
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
---
|
|
2
|
+
skill_id: security-scanning
|
|
3
|
+
skill_version: 0.1.0
|
|
4
|
+
description: Identify and fix common security vulnerabilities in code, eliminating redundant security guidance per agent.
|
|
5
|
+
updated_at: 2025-10-30T17:00:00Z
|
|
6
|
+
tags: [security, vulnerability, scanning, code-analysis]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Security Scanning
|
|
10
|
+
|
|
11
|
+
Identify and fix common security vulnerabilities in code. Eliminates ~150-200 lines of redundant security guidance per agent.
|
|
12
|
+
|
|
13
|
+
## Core Security Principles
|
|
14
|
+
|
|
15
|
+
1. **Never trust user input** - Validate and sanitize everything
|
|
16
|
+
2. **Least privilege** - Grant minimum necessary permissions
|
|
17
|
+
3. **Defense in depth** - Multiple layers of security
|
|
18
|
+
4. **Fail securely** - Errors shouldn't expose sensitive data
|
|
19
|
+
5. **Keep secrets secret** - Never commit credentials
|
|
20
|
+
|
|
21
|
+
## Common Vulnerabilities (OWASP Top 10)
|
|
22
|
+
|
|
23
|
+
### 1. Injection Attacks
|
|
24
|
+
|
|
25
|
+
**SQL Injection:**
|
|
26
|
+
```python
|
|
27
|
+
# ❌ Vulnerable
|
|
28
|
+
query = f"SELECT * FROM users WHERE email = '{user_email}'"
|
|
29
|
+
# Attacker input: ' OR '1'='1
|
|
30
|
+
|
|
31
|
+
# ✅ Safe: Use parameterized queries
|
|
32
|
+
query = "SELECT * FROM users WHERE email = %s"
|
|
33
|
+
cursor.execute(query, (user_email,))
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Command Injection:**
|
|
37
|
+
```python
|
|
38
|
+
# ❌ Vulnerable
|
|
39
|
+
os.system(f"ping {user_input}")
|
|
40
|
+
|
|
41
|
+
# ✅ Safe: Use subprocess with list
|
|
42
|
+
subprocess.run(["ping", "-c", "1", user_input])
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Authentication/Authorization
|
|
46
|
+
|
|
47
|
+
**Weak Password Storage:**
|
|
48
|
+
```python
|
|
49
|
+
# ❌ Vulnerable
|
|
50
|
+
password = user_input # Plain text!
|
|
51
|
+
|
|
52
|
+
# ✅ Safe: Use strong hashing
|
|
53
|
+
from werkzeug.security import generate_password_hash
|
|
54
|
+
password_hash = generate_password_hash(user_input)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Missing Authorization Checks:**
|
|
58
|
+
```python
|
|
59
|
+
# ❌ Vulnerable
|
|
60
|
+
def delete_user(user_id):
|
|
61
|
+
User.delete(user_id) # Anyone can delete!
|
|
62
|
+
|
|
63
|
+
# ✅ Safe: Check permissions
|
|
64
|
+
def delete_user(user_id, current_user):
|
|
65
|
+
if not current_user.is_admin:
|
|
66
|
+
raise PermissionError()
|
|
67
|
+
User.delete(user_id)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. Sensitive Data Exposure
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
# ❌ Vulnerable: Logging sensitive data
|
|
74
|
+
logger.info(f"User logged in: {email}, password: {password}")
|
|
75
|
+
|
|
76
|
+
# ✅ Safe: Never log secrets
|
|
77
|
+
logger.info(f"User logged in: {email}")
|
|
78
|
+
|
|
79
|
+
# ❌ Vulnerable: Committing secrets
|
|
80
|
+
API_KEY = "sk-1234567890abcdef" # In code! # pragma: allowlist secret
|
|
81
|
+
|
|
82
|
+
# ✅ Safe: Use environment variables
|
|
83
|
+
API_KEY = os.getenv("API_KEY")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 4. XML External Entities (XXE)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# ❌ Vulnerable
|
|
90
|
+
import xml.etree.ElementTree as ET
|
|
91
|
+
tree = ET.parse(user_supplied_xml) # Can read local files!
|
|
92
|
+
|
|
93
|
+
# ✅ Safe: Disable external entities
|
|
94
|
+
import defusedxml.ElementTree as ET
|
|
95
|
+
tree = ET.parse(user_supplied_xml)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 5. Broken Access Control
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// ❌ Vulnerable: Client-side only check
|
|
102
|
+
if (user.isAdmin) {
|
|
103
|
+
showAdminPanel();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ✅ Safe: Server-side verification
|
|
107
|
+
fetch('/admin/data', {
|
|
108
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
109
|
+
}).then(response => {
|
|
110
|
+
// Server validates token and permissions
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 6. Security Misconfiguration
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# ❌ Vulnerable: Debug mode in production
|
|
118
|
+
DEBUG = True # Exposes stack traces!
|
|
119
|
+
|
|
120
|
+
# ✅ Safe: Disable debug in production
|
|
121
|
+
DEBUG = os.getenv("ENV") != "production"
|
|
122
|
+
|
|
123
|
+
# ❌ Vulnerable: Default credentials
|
|
124
|
+
DB_PASSWORD = "admin123" # pragma: allowlist secret
|
|
125
|
+
|
|
126
|
+
# ✅ Safe: Strong, unique credentials
|
|
127
|
+
DB_PASSWORD = os.getenv("DB_PASSWORD")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 7. Cross-Site Scripting (XSS)
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// ❌ Vulnerable: Unescaped user content
|
|
134
|
+
element.innerHTML = userInput; // XSS attack!
|
|
135
|
+
|
|
136
|
+
// ✅ Safe: Escape or use textContent
|
|
137
|
+
element.textContent = userInput;
|
|
138
|
+
|
|
139
|
+
// Or use framework's safe rendering
|
|
140
|
+
<div>{{ userInput }}</div> {/* React/Vue auto-escape */}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 8. Insecure Deserialization
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
# ❌ Vulnerable: Deserializing untrusted data
|
|
147
|
+
import pickle
|
|
148
|
+
data = pickle.loads(user_data) # Can execute arbitrary code!
|
|
149
|
+
|
|
150
|
+
# ✅ Safe: Use JSON or validated formats
|
|
151
|
+
import json
|
|
152
|
+
data = json.loads(user_data)
|
|
153
|
+
validate_schema(data)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 9. Using Components with Known Vulnerabilities
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Check for vulnerable dependencies
|
|
160
|
+
npm audit
|
|
161
|
+
pip check
|
|
162
|
+
cargo audit
|
|
163
|
+
|
|
164
|
+
# Update regularly
|
|
165
|
+
npm update
|
|
166
|
+
pip install --upgrade
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 10. Insufficient Logging & Monitoring
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
# ✅ Log security events
|
|
173
|
+
logger.warning(f"Failed login attempt for user: {email} from IP: {ip}")
|
|
174
|
+
logger.error(f"Unauthorized access attempt to {resource} by {user}")
|
|
175
|
+
|
|
176
|
+
# Monitor for patterns
|
|
177
|
+
if failed_login_count > 5:
|
|
178
|
+
alert_security_team()
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Security Scanning Tools
|
|
182
|
+
|
|
183
|
+
### Python
|
|
184
|
+
```bash
|
|
185
|
+
# Bandit: Find common security issues
|
|
186
|
+
bandit -r src/
|
|
187
|
+
|
|
188
|
+
# Safety: Check for vulnerable dependencies
|
|
189
|
+
safety check
|
|
190
|
+
|
|
191
|
+
# Semgrep: Pattern-based scanning
|
|
192
|
+
semgrep --config=auto .
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### JavaScript
|
|
196
|
+
```bash
|
|
197
|
+
# npm audit: Check dependencies
|
|
198
|
+
npm audit
|
|
199
|
+
npm audit fix
|
|
200
|
+
|
|
201
|
+
# ESLint security plugin
|
|
202
|
+
npm install --save-dev eslint-plugin-security
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Go
|
|
206
|
+
```bash
|
|
207
|
+
# gosec: Security scanner
|
|
208
|
+
gosec ./...
|
|
209
|
+
|
|
210
|
+
# govulncheck: Known vulnerabilities
|
|
211
|
+
govulncheck ./...
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Rust
|
|
215
|
+
```bash
|
|
216
|
+
# cargo-audit: Check dependencies
|
|
217
|
+
cargo audit
|
|
218
|
+
|
|
219
|
+
# cargo-deny: Policy enforcement
|
|
220
|
+
cargo deny check
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Input Validation
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
# Always validate user input
|
|
227
|
+
from pydantic import BaseModel, EmailStr, conint
|
|
228
|
+
|
|
229
|
+
class UserInput(BaseModel):
|
|
230
|
+
email: EmailStr # Validates email format
|
|
231
|
+
age: conint(ge=0, le=150) # Constrained integer
|
|
232
|
+
username: str = Field(regex=r'^[a-zA-Z0-9_]+$') # Alphanumeric only
|
|
233
|
+
|
|
234
|
+
# Use the validator
|
|
235
|
+
try:
|
|
236
|
+
validated = UserInput(**user_data)
|
|
237
|
+
except ValidationError as e:
|
|
238
|
+
return {"error": "Invalid input"}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Secure API Design
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
# Rate limiting
|
|
245
|
+
from flask_limiter import Limiter
|
|
246
|
+
|
|
247
|
+
limiter = Limiter(app, key_func=get_remote_address)
|
|
248
|
+
|
|
249
|
+
@app.route("/api/login")
|
|
250
|
+
@limiter.limit("5 per minute") # Prevent brute force
|
|
251
|
+
def login():
|
|
252
|
+
pass
|
|
253
|
+
|
|
254
|
+
# CORS configuration
|
|
255
|
+
from flask_cors import CORS
|
|
256
|
+
|
|
257
|
+
CORS(app, origins=["https://trusted-domain.com"]) # Don't use *
|
|
258
|
+
|
|
259
|
+
# HTTPS only
|
|
260
|
+
if not request.is_secure and app.env == "production":
|
|
261
|
+
return redirect(request.url.replace("http://", "https://"))
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Cryptography Best Practices
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
# ❌ Don't roll your own crypto
|
|
268
|
+
def my_encryption(data, key):
|
|
269
|
+
return xor(data, key) # Insecure!
|
|
270
|
+
|
|
271
|
+
# ✅ Use established libraries
|
|
272
|
+
from cryptography.fernet import Fernet
|
|
273
|
+
|
|
274
|
+
key = Fernet.generate_key()
|
|
275
|
+
cipher = Fernet(key)
|
|
276
|
+
encrypted = cipher.encrypt(data.encode())
|
|
277
|
+
decrypted = cipher.decrypt(encrypted).decode()
|
|
278
|
+
|
|
279
|
+
# ✅ Use strong random numbers
|
|
280
|
+
import secrets
|
|
281
|
+
token = secrets.token_urlsafe(32) # Not random.randint()!
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Security Checklist
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
Authentication & Authorization:
|
|
288
|
+
□ Passwords are hashed (bcrypt, argon2)
|
|
289
|
+
□ MFA is supported
|
|
290
|
+
□ Session tokens are secure and expire
|
|
291
|
+
□ Authorization checks on all sensitive operations
|
|
292
|
+
□ Role-based access control implemented
|
|
293
|
+
|
|
294
|
+
Input Validation:
|
|
295
|
+
□ All user input is validated
|
|
296
|
+
□ SQL uses parameterized queries
|
|
297
|
+
□ XSS protection (output escaping)
|
|
298
|
+
□ CSRF tokens on state-changing operations
|
|
299
|
+
□ File uploads are validated and isolated
|
|
300
|
+
|
|
301
|
+
Data Protection:
|
|
302
|
+
□ Sensitive data is encrypted at rest
|
|
303
|
+
□ TLS/HTTPS for data in transit
|
|
304
|
+
□ Secrets are in environment variables
|
|
305
|
+
□ No secrets in version control
|
|
306
|
+
□ PII handling complies with regulations
|
|
307
|
+
|
|
308
|
+
Dependencies:
|
|
309
|
+
□ All dependencies are up to date
|
|
310
|
+
□ Security scanning in CI/CD
|
|
311
|
+
□ No known vulnerabilities
|
|
312
|
+
□ Minimal dependency footprint
|
|
313
|
+
|
|
314
|
+
Logging & Monitoring:
|
|
315
|
+
□ Security events are logged
|
|
316
|
+
□ Sensitive data not in logs
|
|
317
|
+
□ Anomaly detection in place
|
|
318
|
+
□ Incident response plan exists
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Remember
|
|
322
|
+
|
|
323
|
+
- **Security is ongoing** - Not a one-time fix
|
|
324
|
+
- **Assume breach** - Plan for when (not if) attacks happen
|
|
325
|
+
- **Update regularly** - Vulnerabilities are discovered constantly
|
|
326
|
+
- **Scan automatically** - Integrate security checks in CI/CD
|
|
327
|
+
- **Least surprise** - Secure defaults, explicit insecure options
|