@smicolon/ai-kit 0.1.0 → 0.1.1
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.
- package/.claude-plugin/CLAUDE.md +7 -0
- package/.claude-plugin/marketplace.json +373 -0
- package/package.json +4 -3
- package/packs/architect/CHANGELOG.md +17 -0
- package/packs/architect/README.md +58 -0
- package/packs/architect/agents/system-architect.md +768 -0
- package/packs/architect/commands/diagram-create.md +300 -0
- package/packs/better-auth/.claude-plugin/plugin.json +14 -0
- package/packs/better-auth/.mcp.json +14 -0
- package/packs/better-auth/CHANGELOG.md +26 -0
- package/packs/better-auth/README.md +125 -0
- package/packs/better-auth/agents/auth-architect.md +278 -0
- package/packs/better-auth/commands/auth-provider-add.md +265 -0
- package/packs/better-auth/commands/auth-setup.md +298 -0
- package/packs/better-auth/skills/auth-security/SKILL.md +425 -0
- package/packs/better-auth/skills/better-auth-patterns/SKILL.md +455 -0
- package/packs/dev-loop/.claude-plugin/plugin.json +10 -0
- package/packs/dev-loop/CHANGELOG.md +69 -0
- package/packs/dev-loop/README.md +155 -0
- package/packs/dev-loop/commands/cancel-dev.md +21 -0
- package/packs/dev-loop/commands/dev-loop.md +72 -0
- package/packs/dev-loop/commands/dev-plan.md +351 -0
- package/packs/dev-loop/hooks/hooks.json +15 -0
- package/packs/dev-loop/hooks/stop-hook.sh +178 -0
- package/packs/dev-loop/scripts/setup-dev-loop.sh +194 -0
- package/packs/dev-loop/skills/tdd-planner/SKILL.md +249 -0
- package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +874 -0
- package/packs/dev-loop/skills/tdd-planner/references/good-example.md +260 -0
- package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +275 -0
- package/packs/django/CHANGELOG.md +39 -0
- package/packs/django/README.md +92 -0
- package/packs/django/agents/django-architect.md +182 -0
- package/packs/django/agents/django-builder.md +250 -0
- package/packs/django/agents/django-feature-based.md +420 -0
- package/packs/django/agents/django-reviewer.md +253 -0
- package/packs/django/agents/django-tester.md +230 -0
- package/packs/django/commands/api-endpoint.md +285 -0
- package/packs/django/commands/model-create.md +178 -0
- package/packs/django/commands/test-generate.md +325 -0
- package/packs/django/rules/migrations.md +138 -0
- package/packs/django/rules/models.md +167 -0
- package/packs/django/rules/serializers.md +126 -0
- package/packs/django/rules/services.md +131 -0
- package/packs/django/rules/tests.md +140 -0
- package/packs/django/rules/views.md +102 -0
- package/packs/django/skills/import-convention-enforcer/SKILL.md +226 -0
- package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +343 -0
- package/packs/django/skills/migration-safety-checker/SKILL.md +375 -0
- package/packs/django/skills/model-entity-validator/SKILL.md +298 -0
- package/packs/django/skills/performance-optimizer/SKILL.md +447 -0
- package/packs/django/skills/red-phase-verifier/SKILL.md +180 -0
- package/packs/django/skills/security-first-validator/SKILL.md +435 -0
- package/packs/django/skills/test-coverage-advisor/SKILL.md +394 -0
- package/packs/django/skills/test-validity-checker/SKILL.md +194 -0
- package/packs/failure-log/.claude-plugin/plugin.json +14 -0
- package/packs/failure-log/CHANGELOG.md +20 -0
- package/packs/failure-log/README.md +168 -0
- package/packs/failure-log/commands/failure-add.md +106 -0
- package/packs/failure-log/commands/failure-list.md +89 -0
- package/packs/failure-log/hooks/hooks.json +16 -0
- package/packs/failure-log/hooks/scripts/inject-failures.sh +64 -0
- package/packs/failure-log/skills/failure-log-manager/SKILL.md +164 -0
- package/packs/flutter/.claude-plugin/plugin.json +10 -0
- package/packs/flutter/CHANGELOG.md +19 -0
- package/packs/flutter/README.md +170 -0
- package/packs/flutter/agents/flutter-architect.md +166 -0
- package/packs/flutter/agents/flutter-builder.md +303 -0
- package/packs/flutter/agents/release-manager.md +355 -0
- package/packs/flutter/commands/fastlane-setup.md +188 -0
- package/packs/flutter/commands/flutter-build.md +90 -0
- package/packs/flutter/commands/flutter-deploy.md +133 -0
- package/packs/flutter/commands/flutter-test.md +117 -0
- package/packs/flutter/commands/signing-setup.md +209 -0
- package/packs/flutter/hooks/hooks.json +17 -0
- package/packs/flutter/skills/fastlane-knowledge/SKILL.md +193 -0
- package/packs/flutter/skills/flutter-architecture/SKILL.md +127 -0
- package/packs/flutter/skills/store-publishing/SKILL.md +163 -0
- package/packs/hono/.claude-plugin/plugin.json +19 -0
- package/packs/hono/CHANGELOG.md +19 -0
- package/packs/hono/README.md +143 -0
- package/packs/hono/agents/hono-architect.md +240 -0
- package/packs/hono/agents/hono-builder.md +285 -0
- package/packs/hono/agents/hono-reviewer.md +279 -0
- package/packs/hono/agents/hono-tester.md +346 -0
- package/packs/hono/commands/middleware-create.md +223 -0
- package/packs/hono/commands/project-init.md +306 -0
- package/packs/hono/commands/route-create.md +153 -0
- package/packs/hono/commands/rpc-client.md +263 -0
- package/packs/hono/hooks/hooks.json +4 -0
- package/packs/hono/skills/cloudflare-bindings/SKILL.md +408 -0
- package/packs/hono/skills/hono-patterns/SKILL.md +309 -0
- package/packs/hono/skills/rpc-typesafe/SKILL.md +388 -0
- package/packs/hono/skills/zod-validation/SKILL.md +332 -0
- package/packs/nestjs/CHANGELOG.md +29 -0
- package/packs/nestjs/README.md +75 -0
- package/packs/nestjs/agents/nestjs-architect.md +402 -0
- package/packs/nestjs/agents/nestjs-builder.md +301 -0
- package/packs/nestjs/agents/nestjs-tester.md +437 -0
- package/packs/nestjs/commands/module-create.md +369 -0
- package/packs/nestjs/rules/controllers.md +92 -0
- package/packs/nestjs/rules/dto.md +124 -0
- package/packs/nestjs/rules/entities.md +102 -0
- package/packs/nestjs/rules/services.md +106 -0
- package/packs/nestjs/skills/barrel-export-manager/SKILL.md +389 -0
- package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +365 -0
- package/packs/nextjs/CHANGELOG.md +36 -0
- package/packs/nextjs/README.md +76 -0
- package/packs/nextjs/agents/frontend-tester.md +680 -0
- package/packs/nextjs/agents/frontend-visual.md +820 -0
- package/packs/nextjs/agents/nextjs-architect.md +331 -0
- package/packs/nextjs/agents/nextjs-modular.md +433 -0
- package/packs/nextjs/commands/component-create.md +398 -0
- package/packs/nextjs/rules/api-routes.md +129 -0
- package/packs/nextjs/rules/components.md +106 -0
- package/packs/nextjs/rules/hooks.md +132 -0
- package/packs/nextjs/skills/accessibility-validator/SKILL.md +445 -0
- package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +399 -0
- package/packs/nextjs/skills/react-form-validator/SKILL.md +569 -0
- package/packs/nuxtjs/CHANGELOG.md +30 -0
- package/packs/nuxtjs/README.md +56 -0
- package/packs/nuxtjs/agents/frontend-tester.md +680 -0
- package/packs/nuxtjs/agents/frontend-visual.md +820 -0
- package/packs/nuxtjs/agents/nuxtjs-architect.md +537 -0
- package/packs/nuxtjs/commands/component-create.md +223 -0
- package/packs/nuxtjs/rules/components.md +101 -0
- package/packs/nuxtjs/rules/composables.md +118 -0
- package/packs/nuxtjs/rules/server-routes.md +127 -0
- package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +183 -0
- package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +196 -0
- package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +190 -0
- package/packs/onboard/CHANGELOG.md +22 -0
- package/packs/onboard/README.md +103 -0
- package/packs/onboard/agents/onboard-guide.md +118 -0
- package/packs/onboard/commands/onboard.md +313 -0
- package/packs/onboard/skills/onboard-context-provider/SKILL.md +98 -0
- package/packs/tanstack-router/.claude-plugin/plugin.json +14 -0
- package/packs/tanstack-router/CHANGELOG.md +30 -0
- package/packs/tanstack-router/README.md +113 -0
- package/packs/tanstack-router/agents/tanstack-architect.md +173 -0
- package/packs/tanstack-router/agents/tanstack-builder.md +360 -0
- package/packs/tanstack-router/agents/tanstack-tester.md +454 -0
- package/packs/tanstack-router/commands/form-create.md +313 -0
- package/packs/tanstack-router/commands/query-create.md +263 -0
- package/packs/tanstack-router/commands/route-create.md +190 -0
- package/packs/tanstack-router/commands/table-create.md +413 -0
- package/packs/tanstack-router/skills/ai-patterns/SKILL.md +370 -0
- package/packs/tanstack-router/skills/db-patterns/SKILL.md +346 -0
- package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +415 -0
- package/packs/tanstack-router/skills/form-patterns/SKILL.md +425 -0
- package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +341 -0
- package/packs/tanstack-router/skills/query-patterns/SKILL.md +359 -0
- package/packs/tanstack-router/skills/router-patterns/SKILL.md +285 -0
- package/packs/tanstack-router/skills/store-patterns/SKILL.md +351 -0
- package/packs/tanstack-router/skills/table-patterns/SKILL.md +531 -0
- package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +428 -0
- package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +490 -0
- package/packs/worktree/.claude-plugin/plugin.json +19 -0
- package/packs/worktree/CHANGELOG.md +24 -0
- package/packs/worktree/README.md +110 -0
- package/packs/worktree/commands/wt.md +73 -0
- package/packs/worktree/scripts/wt.sh +396 -0
- package/packs/worktree/skills/worktree-manager/SKILL.md +68 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-first-validator
|
|
3
|
+
description: This skill should be used when the user asks to "create an API endpoint", "add a view", "write a viewset", "create a serializer", or when writing Django REST Framework code. Enforces security requirements (permissions, authentication, rate limiting).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Security-First Validator
|
|
7
|
+
|
|
8
|
+
Enforces security requirements for all Django REST Framework API endpoints.
|
|
9
|
+
|
|
10
|
+
## Activation Triggers
|
|
11
|
+
|
|
12
|
+
This skill activates when:
|
|
13
|
+
- Creating API views or viewsets
|
|
14
|
+
- Creating serializers
|
|
15
|
+
- Mentioning "endpoint", "API", "view", "route"
|
|
16
|
+
- Writing DRF classes (APIView, ViewSet, Serializer)
|
|
17
|
+
- Creating URL patterns for APIs
|
|
18
|
+
- Discussing authentication or permissions
|
|
19
|
+
|
|
20
|
+
## Security Requirements (MANDATORY)
|
|
21
|
+
|
|
22
|
+
Every API endpoint MUST have:
|
|
23
|
+
|
|
24
|
+
### 1. Permission Classes (REQUIRED)
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from rest_framework import viewsets
|
|
28
|
+
from rest_framework.permissions import IsAuthenticated
|
|
29
|
+
|
|
30
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
31
|
+
permission_classes = [IsAuthenticated] # ✅ REQUIRED
|
|
32
|
+
# ...
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Serializer Validation (REQUIRED)
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from rest_framework import serializers
|
|
39
|
+
|
|
40
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
41
|
+
class Meta:
|
|
42
|
+
model = User
|
|
43
|
+
fields = ['id', 'email', 'first_name']
|
|
44
|
+
# NO sensitive fields exposed ✅
|
|
45
|
+
|
|
46
|
+
def validate_email(self, value):
|
|
47
|
+
# Custom validation ✅
|
|
48
|
+
if not value.endswith('@company.com'):
|
|
49
|
+
raise serializers.ValidationError("Must use company email")
|
|
50
|
+
return value
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. No Raw SQL (REQUIRED)
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# ❌ DANGEROUS
|
|
57
|
+
User.objects.raw(f"SELECT * FROM users WHERE id = {user_id}")
|
|
58
|
+
|
|
59
|
+
# ✅ SAFE
|
|
60
|
+
User.objects.filter(id=user_id)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. Rate Limiting (REQUIRED for sensitive endpoints)
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from rest_framework.throttling import UserRateThrottle
|
|
67
|
+
|
|
68
|
+
class LoginView(APIView):
|
|
69
|
+
throttle_classes = [UserRateThrottle] # ✅ REQUIRED for auth
|
|
70
|
+
# ...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Validation Process
|
|
74
|
+
|
|
75
|
+
### Step 1: Detect New API Endpoint
|
|
76
|
+
|
|
77
|
+
When API code is being written:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
81
|
+
queryset = User.objects.all()
|
|
82
|
+
serializer_class = UserSerializer
|
|
83
|
+
# Missing security! ❌
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Step 2: Run Security Checklist
|
|
87
|
+
|
|
88
|
+
Verify:
|
|
89
|
+
1. ✅ Permission classes defined
|
|
90
|
+
2. ✅ Serializer has proper validation
|
|
91
|
+
3. ✅ No raw SQL queries
|
|
92
|
+
4. ✅ Rate limiting on sensitive endpoints
|
|
93
|
+
5. ✅ No password/token fields in serializer
|
|
94
|
+
6. ✅ Proper CORS configuration
|
|
95
|
+
|
|
96
|
+
### Step 3: Auto-Add Security Requirements
|
|
97
|
+
|
|
98
|
+
**Before (Insecure):**
|
|
99
|
+
```python
|
|
100
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
101
|
+
queryset = User.objects.all()
|
|
102
|
+
serializer_class = UserSerializer
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**After (Secure):**
|
|
106
|
+
```python
|
|
107
|
+
from rest_framework import viewsets
|
|
108
|
+
from rest_framework.permissions import IsAuthenticated
|
|
109
|
+
|
|
110
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
111
|
+
"""User management endpoints."""
|
|
112
|
+
|
|
113
|
+
queryset = User.objects.all()
|
|
114
|
+
serializer_class = UserSerializer
|
|
115
|
+
permission_classes = [IsAuthenticated] # ✅ Added
|
|
116
|
+
|
|
117
|
+
def get_queryset(self):
|
|
118
|
+
"""Filter queryset to exclude soft-deleted records."""
|
|
119
|
+
return super().get_queryset().filter(is_deleted=False)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Step 4: Validate Serializer Security
|
|
123
|
+
|
|
124
|
+
**Check for exposed sensitive fields:**
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# ❌ DANGEROUS - Exposes password!
|
|
128
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
129
|
+
class Meta:
|
|
130
|
+
model = User
|
|
131
|
+
fields = '__all__' # Never use __all__!
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Auto-fix to:**
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# ✅ SAFE - Explicit field list
|
|
138
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
139
|
+
class Meta:
|
|
140
|
+
model = User
|
|
141
|
+
fields = ['id', 'email', 'first_name', 'last_name']
|
|
142
|
+
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
143
|
+
# Password excluded ✅
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 5: Report Security Issues
|
|
147
|
+
|
|
148
|
+
Report to developer:
|
|
149
|
+
|
|
150
|
+
> **Security Issues Detected and Fixed**
|
|
151
|
+
>
|
|
152
|
+
> **Fixed:**
|
|
153
|
+
> 1. ✅ Added `permission_classes = [IsAuthenticated]` to UserViewSet
|
|
154
|
+
> 2. ✅ Changed serializer from `fields = '__all__'` to explicit field list
|
|
155
|
+
> 3. ✅ Excluded sensitive fields (password, tokens)
|
|
156
|
+
> 4. ✅ Added `read_only_fields` for audit fields
|
|
157
|
+
>
|
|
158
|
+
> **Why:**
|
|
159
|
+
> - Permission classes prevent unauthorized access
|
|
160
|
+
> - Explicit fields prevent accidental data exposure
|
|
161
|
+
> - Read-only fields prevent tampering with audit trail
|
|
162
|
+
|
|
163
|
+
## Complete Secure Endpoint Example
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import users.models as _users_models
|
|
167
|
+
import users.serializers as _users_serializers
|
|
168
|
+
|
|
169
|
+
from rest_framework import viewsets, status
|
|
170
|
+
from rest_framework.decorators import action
|
|
171
|
+
from rest_framework.permissions import IsAuthenticated
|
|
172
|
+
from rest_framework.response import Response
|
|
173
|
+
from rest_framework.throttling import UserRateThrottle
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class UserViewSet(viewsets.ModelViewSet):
|
|
177
|
+
"""
|
|
178
|
+
User management API.
|
|
179
|
+
|
|
180
|
+
Security:
|
|
181
|
+
- Requires authentication
|
|
182
|
+
- Users can only access their own data (see get_queryset)
|
|
183
|
+
- Rate limited for sensitive actions
|
|
184
|
+
- Input validation via serializer
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
queryset = _users_models.User.objects.all()
|
|
188
|
+
serializer_class = _users_serializers.UserSerializer
|
|
189
|
+
permission_classes = [IsAuthenticated] # ✅ Authentication required
|
|
190
|
+
|
|
191
|
+
def get_queryset(self):
|
|
192
|
+
"""Users can only see active, non-deleted records."""
|
|
193
|
+
qs = super().get_queryset().filter(is_deleted=False)
|
|
194
|
+
|
|
195
|
+
# Users see only their own data unless admin
|
|
196
|
+
if not self.request.user.is_staff:
|
|
197
|
+
qs = qs.filter(id=self.request.user.id)
|
|
198
|
+
|
|
199
|
+
return qs
|
|
200
|
+
|
|
201
|
+
def perform_create(self, serializer):
|
|
202
|
+
"""Auto-set created_by on creation."""
|
|
203
|
+
serializer.save(created_by=self.request.user)
|
|
204
|
+
|
|
205
|
+
@action(
|
|
206
|
+
detail=False,
|
|
207
|
+
methods=['post'],
|
|
208
|
+
throttle_classes=[UserRateThrottle], # ✅ Rate limiting
|
|
209
|
+
permission_classes=[IsAuthenticated]
|
|
210
|
+
)
|
|
211
|
+
def change_password(self, request):
|
|
212
|
+
"""Change user password (rate limited)."""
|
|
213
|
+
serializer = _serializers.ChangePasswordSerializer(data=request.data)
|
|
214
|
+
serializer.is_valid(raise_exception=True) # ✅ Validation
|
|
215
|
+
|
|
216
|
+
user = request.user
|
|
217
|
+
user.set_password(serializer.validated_data['new_password'])
|
|
218
|
+
user.save()
|
|
219
|
+
|
|
220
|
+
return Response({'status': 'password changed'})
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Security Checklist by Endpoint Type
|
|
224
|
+
|
|
225
|
+
### Read-Only Endpoints (GET)
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
class PublicArticleViewSet(viewsets.ReadOnlyModelViewSet):
|
|
229
|
+
"""Public articles (read-only)."""
|
|
230
|
+
|
|
231
|
+
queryset = Article.objects.filter(is_published=True, is_deleted=False)
|
|
232
|
+
serializer_class = ArticleSerializer
|
|
233
|
+
permission_classes = [AllowAny] # ✅ Explicit - public endpoint
|
|
234
|
+
|
|
235
|
+
# Still apply rate limiting to prevent scraping
|
|
236
|
+
throttle_classes = [AnonRateThrottle]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Create Endpoints (POST)
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
class UserCreateView(generics.CreateAPIView):
|
|
243
|
+
"""User registration (public)."""
|
|
244
|
+
|
|
245
|
+
serializer_class = UserCreateSerializer
|
|
246
|
+
permission_classes = [AllowAny] # ✅ Public registration
|
|
247
|
+
throttle_classes = [AnonRateThrottle] # ✅ Prevent abuse
|
|
248
|
+
|
|
249
|
+
def perform_create(self, serializer):
|
|
250
|
+
"""
|
|
251
|
+
Create user and send verification email.
|
|
252
|
+
|
|
253
|
+
Security: Rate limited, email validation in serializer.
|
|
254
|
+
"""
|
|
255
|
+
user = serializer.save()
|
|
256
|
+
send_verification_email(user)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Update Endpoints (PUT/PATCH)
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
class UserUpdateView(generics.UpdateAPIView):
|
|
263
|
+
"""Update user profile."""
|
|
264
|
+
|
|
265
|
+
serializer_class = UserUpdateSerializer
|
|
266
|
+
permission_classes = [IsAuthenticated, IsOwner] # ✅ Auth + ownership
|
|
267
|
+
|
|
268
|
+
def get_object(self):
|
|
269
|
+
"""Users can only update their own profile."""
|
|
270
|
+
return self.request.user
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Delete Endpoints (DELETE)
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
class UserDestroyView(generics.DestroyAPIView):
|
|
277
|
+
"""Soft delete user account."""
|
|
278
|
+
|
|
279
|
+
permission_classes = [IsAuthenticated, IsOwner] # ✅ Auth + ownership
|
|
280
|
+
|
|
281
|
+
def perform_destroy(self, instance):
|
|
282
|
+
"""Soft delete instead of hard delete."""
|
|
283
|
+
instance.is_deleted = True
|
|
284
|
+
instance.save(update_fields=['is_deleted', 'updated_at'])
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Common Security Violations
|
|
288
|
+
|
|
289
|
+
### Violation 1: No Permission Classes
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
# ❌ DANGEROUS - Anyone can access!
|
|
293
|
+
class AdminViewSet(viewsets.ModelViewSet):
|
|
294
|
+
queryset = User.objects.all()
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**Auto-fix:**
|
|
298
|
+
```python
|
|
299
|
+
# ✅ SECURE
|
|
300
|
+
class AdminViewSet(viewsets.ModelViewSet):
|
|
301
|
+
queryset = User.objects.all()
|
|
302
|
+
permission_classes = [IsAuthenticated, IsAdminUser] # Added!
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Violation 2: Serializer Exposes Sensitive Data
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
# ❌ DANGEROUS - Exposes password!
|
|
309
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
310
|
+
class Meta:
|
|
311
|
+
model = User
|
|
312
|
+
fields = '__all__'
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**I auto-fix:**
|
|
316
|
+
```python
|
|
317
|
+
# ✅ SECURE
|
|
318
|
+
class UserSerializer(serializers.ModelSerializer):
|
|
319
|
+
class Meta:
|
|
320
|
+
model = User
|
|
321
|
+
fields = ['id', 'email', 'first_name', 'last_name', 'created_at']
|
|
322
|
+
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
323
|
+
# password, tokens excluded!
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Violation 3: Raw SQL Injection Risk
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
# ❌ DANGEROUS - SQL injection!
|
|
330
|
+
def get_user(user_id):
|
|
331
|
+
query = f"SELECT * FROM users WHERE id = {user_id}"
|
|
332
|
+
return User.objects.raw(query)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**I auto-fix:**
|
|
336
|
+
```python
|
|
337
|
+
# ✅ SECURE
|
|
338
|
+
def get_user(user_id):
|
|
339
|
+
return User.objects.filter(id=user_id).first()
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Violation 4: No Rate Limiting on Auth
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
# ❌ DANGEROUS - Brute force attacks possible!
|
|
346
|
+
class LoginView(APIView):
|
|
347
|
+
def post(self, request):
|
|
348
|
+
# Login logic
|
|
349
|
+
pass
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
**I auto-fix:**
|
|
353
|
+
```python
|
|
354
|
+
# ✅ SECURE
|
|
355
|
+
from rest_framework.throttling import AnonRateThrottle
|
|
356
|
+
|
|
357
|
+
class LoginView(APIView):
|
|
358
|
+
throttle_classes = [AnonRateThrottle] # Added!
|
|
359
|
+
|
|
360
|
+
def post(self, request):
|
|
361
|
+
# Login logic
|
|
362
|
+
pass
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## OWASP Top 10 Coverage
|
|
366
|
+
|
|
367
|
+
Automatically check for:
|
|
368
|
+
|
|
369
|
+
1. **Broken Access Control** → Permission classes required
|
|
370
|
+
2. **Cryptographic Failures** → No sensitive fields in serializers
|
|
371
|
+
3. **Injection** → No raw SQL, use ORM
|
|
372
|
+
4. **Insecure Design** → Enforce secure-by-default patterns
|
|
373
|
+
5. **Security Misconfiguration** → CORS, HTTPS, rate limiting
|
|
374
|
+
6. **Vulnerable Components** → (Check in CI/CD)
|
|
375
|
+
7. **Authentication Failures** → Throttling on auth endpoints
|
|
376
|
+
8. **Data Integrity Failures** → Serializer validation required
|
|
377
|
+
9. **Logging Failures** → (Suggest logging for sensitive ops)
|
|
378
|
+
10. **SSRF** → Validate URLs in serializers
|
|
379
|
+
|
|
380
|
+
## Custom Permission Classes
|
|
381
|
+
|
|
382
|
+
Recognize and allow custom permissions:
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
from rest_framework.permissions import BasePermission
|
|
386
|
+
|
|
387
|
+
class IsOwner(BasePermission):
|
|
388
|
+
"""User can only access their own objects."""
|
|
389
|
+
|
|
390
|
+
def has_object_permission(self, request, view, obj):
|
|
391
|
+
return obj.user == request.user
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
# Usage ✅ VALID
|
|
395
|
+
class ProfileViewSet(viewsets.ModelViewSet):
|
|
396
|
+
permission_classes = [IsAuthenticated, IsOwner]
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Integration with Other Skills
|
|
400
|
+
|
|
401
|
+
Works together with:
|
|
402
|
+
- **model-entity-validator**: Ensures models don't expose sensitive fields
|
|
403
|
+
- **test-coverage-advisor**: Suggests security tests
|
|
404
|
+
- **django-reviewer**: Full security audit during review
|
|
405
|
+
|
|
406
|
+
## Success Criteria
|
|
407
|
+
|
|
408
|
+
✅ ALL endpoints have permission classes
|
|
409
|
+
✅ ALL serializers use explicit field lists
|
|
410
|
+
✅ NO raw SQL queries
|
|
411
|
+
✅ Rate limiting on sensitive endpoints
|
|
412
|
+
✅ NO sensitive fields exposed
|
|
413
|
+
✅ Input validation on all write operations
|
|
414
|
+
✅ Developer understands OWASP risks
|
|
415
|
+
|
|
416
|
+
## Behavior
|
|
417
|
+
|
|
418
|
+
**Proactive enforcement:**
|
|
419
|
+
- Check security without being asked
|
|
420
|
+
- Add permission classes automatically
|
|
421
|
+
- Fix serializer field exposure immediately
|
|
422
|
+
- Explain WHY each security measure is critical
|
|
423
|
+
- Reference OWASP categories
|
|
424
|
+
|
|
425
|
+
**Never:**
|
|
426
|
+
- Require explicit "check security" request
|
|
427
|
+
- Wait for pen test results
|
|
428
|
+
- Just warn without fixing
|
|
429
|
+
- Allow endpoints without security
|
|
430
|
+
|
|
431
|
+
**Block completion if:**
|
|
432
|
+
- No permission classes defined
|
|
433
|
+
- Serializer uses `fields = '__all__'`
|
|
434
|
+
- Raw SQL detected
|
|
435
|
+
- Sensitive endpoints lack rate limiting
|