start-vibing-stacks 2.6.0 → 2.7.3

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.
Files changed (80) hide show
  1. package/README.md +83 -135
  2. package/dist/index.js +16 -2
  3. package/dist/migrate.d.ts +27 -0
  4. package/dist/migrate.js +217 -0
  5. package/dist/setup.js +10 -0
  6. package/package.json +1 -1
  7. package/stacks/_shared/agents/claude-md-compactor.md +1 -0
  8. package/stacks/_shared/agents/commit-manager.md +1 -0
  9. package/stacks/_shared/agents/documenter.md +1 -0
  10. package/stacks/_shared/agents/domain-updater.md +1 -0
  11. package/stacks/_shared/agents/research-web.md +1 -0
  12. package/stacks/_shared/agents/security-auditor.md +168 -0
  13. package/stacks/_shared/agents/tester.md +1 -0
  14. package/stacks/_shared/hooks/final-check.ts +205 -0
  15. package/stacks/_shared/hooks/stop-validator.ts +77 -1
  16. package/stacks/_shared/skills/accessibility-wcag22/SKILL.md +284 -0
  17. package/stacks/_shared/skills/ci-pipelines/SKILL.md +166 -0
  18. package/stacks/_shared/skills/codebase-knowledge/SKILL.md +5 -0
  19. package/stacks/_shared/skills/database-migrations/SKILL.md +256 -0
  20. package/stacks/_shared/skills/debugging-patterns/SKILL.md +5 -0
  21. package/stacks/_shared/skills/docker-patterns/SKILL.md +5 -0
  22. package/stacks/_shared/skills/docs-tracker/SKILL.md +5 -0
  23. package/stacks/_shared/skills/error-handling/SKILL.md +335 -0
  24. package/stacks/_shared/skills/final-check/SKILL.md +74 -37
  25. package/stacks/_shared/skills/git-workflow/SKILL.md +5 -0
  26. package/stacks/_shared/skills/hook-development/SKILL.md +5 -0
  27. package/stacks/_shared/skills/observability/SKILL.md +351 -0
  28. package/stacks/_shared/skills/performance-patterns/SKILL.md +5 -0
  29. package/stacks/_shared/skills/playwright-automation/SKILL.md +5 -0
  30. package/stacks/_shared/skills/quality-gate/SKILL.md +5 -0
  31. package/stacks/_shared/skills/research-cache/SKILL.md +5 -0
  32. package/stacks/_shared/skills/secrets-management/SKILL.md +245 -0
  33. package/stacks/_shared/skills/security-baseline/SKILL.md +202 -0
  34. package/stacks/_shared/skills/test-coverage/SKILL.md +5 -0
  35. package/stacks/_shared/skills/ui-ux-audit/SKILL.md +5 -0
  36. package/stacks/frontend/react/skills/preline-ui/SKILL.md +5 -0
  37. package/stacks/frontend/react/skills/react-patterns/SKILL.md +5 -0
  38. package/stacks/frontend/react/skills/react-standards/SKILL.md +5 -0
  39. package/stacks/frontend/react/skills/react-ui-patterns/SKILL.md +5 -0
  40. package/stacks/frontend/react/skills/shadcn-ui/SKILL.md +5 -0
  41. package/stacks/frontend/react/skills/tailwind-patterns/SKILL.md +5 -0
  42. package/stacks/frontend/react/skills/zod-validation/SKILL.md +5 -0
  43. package/stacks/frontend/react-inertia/skills/inertia-react/SKILL.md +5 -0
  44. package/stacks/frontend/react-inertia/skills/react-standards/SKILL.md +5 -0
  45. package/stacks/nodejs/skills/api-security-node/SKILL.md +275 -0
  46. package/stacks/nodejs/skills/bun-runtime/SKILL.md +5 -0
  47. package/stacks/nodejs/skills/mongoose-patterns/SKILL.md +5 -0
  48. package/stacks/nodejs/skills/nextjs-app-router/SKILL.md +5 -0
  49. package/stacks/nodejs/skills/trpc-api/SKILL.md +5 -0
  50. package/stacks/nodejs/skills/typescript-strict/SKILL.md +5 -0
  51. package/stacks/nodejs/stack.json +2 -1
  52. package/stacks/nodejs/workflows/ci.yml +90 -0
  53. package/stacks/nodejs/workflows/security.yml +45 -0
  54. package/stacks/php/skills/api-design/SKILL.md +5 -0
  55. package/stacks/php/skills/api-security/SKILL.md +5 -0
  56. package/stacks/php/skills/composer-workflow/SKILL.md +5 -0
  57. package/stacks/php/skills/external-api-patterns/SKILL.md +5 -0
  58. package/stacks/php/skills/inertia-react/SKILL.md +5 -0
  59. package/stacks/php/skills/laravel-inertia-i18n/SKILL.md +5 -0
  60. package/stacks/php/skills/laravel-octane/SKILL.md +5 -0
  61. package/stacks/php/skills/laravel-patterns/SKILL.md +5 -0
  62. package/stacks/php/skills/mariadb-octane/SKILL.md +5 -0
  63. package/stacks/php/skills/php-patterns/SKILL.md +5 -0
  64. package/stacks/php/skills/phpstan-analysis/SKILL.md +5 -0
  65. package/stacks/php/skills/phpunit-testing/SKILL.md +5 -0
  66. package/stacks/php/skills/security-scan-php/SKILL.md +5 -0
  67. package/stacks/php/workflows/ci.yml +106 -0
  68. package/stacks/php/workflows/security.yml +36 -0
  69. package/stacks/python/skills/api-security-python/SKILL.md +312 -0
  70. package/stacks/python/skills/async-patterns/SKILL.md +5 -0
  71. package/stacks/python/skills/django-patterns/SKILL.md +5 -0
  72. package/stacks/python/skills/fastapi-patterns/SKILL.md +5 -0
  73. package/stacks/python/skills/pydantic-validation/SKILL.md +5 -0
  74. package/stacks/python/skills/pytest-testing/SKILL.md +5 -0
  75. package/stacks/python/skills/python-patterns/SKILL.md +5 -0
  76. package/stacks/python/skills/python-performance/SKILL.md +5 -0
  77. package/stacks/python/skills/scripting-automation/SKILL.md +5 -0
  78. package/stacks/python/stack.json +2 -1
  79. package/stacks/python/workflows/ci.yml +76 -0
  80. package/stacks/python/workflows/security.yml +56 -0
@@ -0,0 +1,106 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ ci:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ services:
20
+ mariadb:
21
+ image: mariadb:11
22
+ env:
23
+ MARIADB_ROOT_PASSWORD: root
24
+ MARIADB_DATABASE: testing
25
+ ports: ['3306:3306']
26
+ options: >-
27
+ --health-cmd "healthcheck.sh --connect --innodb_initialized"
28
+ --health-interval 10s --health-timeout 5s --health-retries 5
29
+ redis:
30
+ image: redis:7-alpine
31
+ ports: ['6379:6379']
32
+ options: >-
33
+ --health-cmd "redis-cli ping"
34
+ --health-interval 10s --health-timeout 5s --health-retries 5
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+
38
+ - uses: shivammathur/setup-php@v2
39
+ with:
40
+ php-version: '8.3'
41
+ extensions: mbstring, pdo_mysql, redis, swoole, intl, bcmath, zip
42
+ coverage: pcov
43
+ tools: composer:v2
44
+
45
+ - name: Cache composer
46
+ uses: actions/cache@v4
47
+ with:
48
+ path: vendor
49
+ key: composer-${{ hashFiles('composer.lock') }}
50
+
51
+ - name: Install dependencies
52
+ run: composer install --no-interaction --prefer-dist --optimize-autoloader
53
+
54
+ - name: Copy env
55
+ run: cp .env.example .env && php artisan key:generate
56
+
57
+ - name: PHPStan
58
+ run: vendor/bin/phpstan analyse --no-progress --memory-limit=512M
59
+
60
+ - name: Pint (code style)
61
+ run: vendor/bin/pint --test
62
+
63
+ - name: Migrate
64
+ env:
65
+ DB_CONNECTION: mariadb
66
+ DB_HOST: 127.0.0.1
67
+ DB_PORT: 3306
68
+ DB_DATABASE: testing
69
+ DB_USERNAME: root
70
+ DB_PASSWORD: root
71
+ run: php artisan migrate --force
72
+
73
+ - name: PHPUnit / Pest
74
+ env:
75
+ DB_CONNECTION: mariadb
76
+ DB_HOST: 127.0.0.1
77
+ DB_PORT: 3306
78
+ DB_DATABASE: testing
79
+ DB_USERNAME: root
80
+ DB_PASSWORD: root
81
+ REDIS_HOST: 127.0.0.1
82
+ run: vendor/bin/pest --coverage --min=70
83
+
84
+ security:
85
+ runs-on: ubuntu-latest
86
+ timeout-minutes: 10
87
+ steps:
88
+ - uses: actions/checkout@v4
89
+ with:
90
+ fetch-depth: 0
91
+
92
+ - uses: shivammathur/setup-php@v2
93
+ with:
94
+ php-version: '8.3'
95
+ tools: composer:v2
96
+
97
+ - name: Install dependencies
98
+ run: composer install --no-interaction --prefer-dist
99
+
100
+ - name: Composer audit
101
+ run: composer audit
102
+
103
+ - name: Gitleaks (secret scan)
104
+ uses: gitleaks/gitleaks-action@v2
105
+ env:
106
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,36 @@
1
+ name: Security
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 4 * * 1'
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+ security-events: write
13
+
14
+ jobs:
15
+ audit:
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 10
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: shivammathur/setup-php@v2
21
+ with:
22
+ php-version: '8.3'
23
+ tools: composer:v2
24
+ - run: composer install --no-interaction --prefer-dist
25
+ - run: composer audit
26
+
27
+ gitleaks:
28
+ runs-on: ubuntu-latest
29
+ timeout-minutes: 5
30
+ steps:
31
+ - uses: actions/checkout@v4
32
+ with:
33
+ fetch-depth: 0
34
+ - uses: gitleaks/gitleaks-action@v2
35
+ env:
36
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,312 @@
1
+ ---
2
+ name: api-security-python
3
+ version: 1.0.0
4
+ description: Production-grade API hardening for Python (FastAPI, Django, Flask). Rate limit, CORS, JWT, secure cookies, CSRF, OAuth2.
5
+ ---
6
+
7
+ # API Security — Python
8
+
9
+ **ALWAYS invoke when building API endpoints, auth flows, or admin actions.**
10
+
11
+ > Pair this with `security-baseline` for OWASP Top 10. This skill is stack-specific hardening.
12
+
13
+ ## Layered Defense
14
+
15
+ ```
16
+ Edge (CDN/WAF) → Rate Limit → CORS → Headers → Auth → Authz → Validate → Logic → Encode → Audit
17
+ ```
18
+
19
+ ---
20
+
21
+ ## 1. Security Headers
22
+
23
+ ### FastAPI — middleware
24
+ ```python
25
+ from fastapi import FastAPI
26
+ from starlette.middleware.base import BaseHTTPMiddleware
27
+
28
+ class SecurityHeaders(BaseHTTPMiddleware):
29
+ async def dispatch(self, request, call_next):
30
+ response = await call_next(request)
31
+ response.headers["Strict-Transport-Security"] = "max-age=63072000; includeSubDomains; preload"
32
+ response.headers["X-Content-Type-Options"] = "nosniff"
33
+ response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
34
+ response.headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()"
35
+ response.headers["X-Frame-Options"] = "DENY"
36
+ response.headers["Content-Security-Policy"] = (
37
+ "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; "
38
+ "img-src 'self' data: https:; frame-ancestors 'none'"
39
+ )
40
+ return response
41
+
42
+ app = FastAPI()
43
+ app.add_middleware(SecurityHeaders)
44
+ ```
45
+
46
+ ### Django — `settings.py`
47
+ ```python
48
+ SECURE_HSTS_SECONDS = 63072000
49
+ SECURE_HSTS_INCLUDE_SUBDOMAINS = True
50
+ SECURE_HSTS_PRELOAD = True
51
+ SECURE_CONTENT_TYPE_NOSNIFF = True
52
+ SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
53
+ SECURE_SSL_REDIRECT = True
54
+ SESSION_COOKIE_SECURE = True
55
+ SESSION_COOKIE_HTTPONLY = True
56
+ SESSION_COOKIE_SAMESITE = "Lax"
57
+ CSRF_COOKIE_SECURE = True
58
+ CSRF_COOKIE_HTTPONLY = True
59
+ X_FRAME_OPTIONS = "DENY"
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 2. CORS — Strict Allowlist
65
+
66
+ ```python
67
+ from fastapi.middleware.cors import CORSMiddleware
68
+ import os
69
+
70
+ ALLOW = [o.strip() for o in os.getenv("CORS_ORIGINS", "").split(",") if o]
71
+
72
+ app.add_middleware(
73
+ CORSMiddleware,
74
+ allow_origins=ALLOW, # explicit list, NEVER ["*"] with credentials
75
+ allow_credentials=True,
76
+ allow_methods=["GET", "POST", "PATCH", "DELETE"],
77
+ allow_headers=["Authorization", "Content-Type", "X-CSRF-Token"],
78
+ max_age=600,
79
+ )
80
+ ```
81
+
82
+ **Never** `allow_origins=["*"]` with `allow_credentials=True` — browsers reject and auth silently breaks.
83
+
84
+ ---
85
+
86
+ ## 3. Rate Limiting
87
+
88
+ ### FastAPI — `slowapi`
89
+ ```python
90
+ from slowapi import Limiter, _rate_limit_exceeded_handler
91
+ from slowapi.util import get_remote_address
92
+ from slowapi.errors import RateLimitExceeded
93
+
94
+ limiter = Limiter(key_func=get_remote_address, storage_uri="redis://localhost:6379")
95
+ app.state.limiter = limiter
96
+ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
97
+
98
+ @app.post("/auth/login")
99
+ @limiter.limit("5/15minutes")
100
+ async def login(request: Request, body: LoginIn):
101
+ ...
102
+ ```
103
+
104
+ ### Django — `django-ratelimit`
105
+ ```python
106
+ from django_ratelimit.decorators import ratelimit
107
+
108
+ @ratelimit(key='ip', rate='5/15m', block=True)
109
+ def login_view(request):
110
+ ...
111
+ ```
112
+
113
+ **Limits to set:** auth (5/15min), password reset (3/hour), signup (3/hour/IP), generic write (60/min/user).
114
+
115
+ ---
116
+
117
+ ## 4. Cookies
118
+
119
+ ### FastAPI
120
+ ```python
121
+ from fastapi import Response
122
+
123
+ response.set_cookie(
124
+ key="session",
125
+ value=token,
126
+ httponly=True, # JS cannot read
127
+ secure=True, # HTTPS only
128
+ samesite="lax", # 'strict' if no cross-site flows
129
+ max_age=60 * 60 * 24 * 7, # 7d
130
+ path="/",
131
+ domain=os.getenv("COOKIE_DOMAIN"),
132
+ )
133
+ ```
134
+
135
+ ---
136
+
137
+ ## 5. JWT / OAuth2 — FastAPI
138
+
139
+ ```python
140
+ from datetime import datetime, timedelta, timezone
141
+ from jose import jwt, JWTError
142
+ import os, uuid
143
+
144
+ SECRET = os.environ["JWT_SECRET"]
145
+ ALG = "HS256"
146
+
147
+ def issue_access_token(user_id: str, role: str) -> str:
148
+ now = datetime.now(timezone.utc)
149
+ return jwt.encode(
150
+ {
151
+ "sub": user_id,
152
+ "role": role,
153
+ "iat": now,
154
+ "exp": now + timedelta(minutes=15),
155
+ "jti": str(uuid.uuid4()),
156
+ },
157
+ SECRET,
158
+ algorithm=ALG,
159
+ )
160
+
161
+ async def current_user(token: str = Depends(oauth2_scheme)) -> User:
162
+ try:
163
+ payload = jwt.decode(token, SECRET, algorithms=[ALG]) # pin algorithm
164
+ except JWTError:
165
+ raise HTTPException(401, "Invalid token")
166
+ user = await User.get_or_none(id=payload["sub"])
167
+ if not user:
168
+ raise HTTPException(401, "User not found")
169
+ return user
170
+ ```
171
+
172
+ Rules:
173
+ - Access tokens: ≤ 15 min. Refresh tokens: rotate on use, store hash in DB, revocable.
174
+ - Pin `algorithms=[ALG]`. Never accept `alg: none`.
175
+ - Include `jti` for revocation lists.
176
+
177
+ ---
178
+
179
+ ## 6. CSRF
180
+
181
+ ### Django
182
+ Built-in: `django.middleware.csrf.CsrfViewMiddleware`. Always enabled — never disable globally.
183
+ For DRF + SessionAuth, use `@ensure_csrf_cookie` on the view that bootstraps the SPA.
184
+
185
+ ### FastAPI — double-submit cookie
186
+ ```python
187
+ import secrets
188
+ from fastapi import Request, HTTPException
189
+
190
+ CSRF_COOKIE = "csrf-token"
191
+ CSRF_HEADER = "x-csrf-token"
192
+ UNSAFE = {"POST", "PUT", "PATCH", "DELETE"}
193
+
194
+ @app.middleware("http")
195
+ async def csrf(request: Request, call_next):
196
+ if request.method in UNSAFE:
197
+ cookie = request.cookies.get(CSRF_COOKIE)
198
+ header = request.headers.get(CSRF_HEADER)
199
+ if not cookie or cookie != header:
200
+ raise HTTPException(403, "CSRF")
201
+ response = await call_next(request)
202
+ if not request.cookies.get(CSRF_COOKIE):
203
+ response.set_cookie(CSRF_COOKIE, secrets.token_urlsafe(32),
204
+ secure=True, samesite="lax", path="/")
205
+ return response
206
+ ```
207
+
208
+ ---
209
+
210
+ ## 7. Input Validation Boundary (Pydantic)
211
+
212
+ ```python
213
+ from pydantic import BaseModel, EmailStr, Field, ConfigDict
214
+
215
+ class CreateUser(BaseModel):
216
+ model_config = ConfigDict(extra="forbid") # rejects unknown keys → blocks mass assignment
217
+ email: EmailStr = Field(max_length=254)
218
+ age: int = Field(ge=13, le=120)
219
+
220
+ @app.post("/users")
221
+ async def create(body: CreateUser): # FastAPI validates automatically; 422 on failure
222
+ ...
223
+ ```
224
+
225
+ ---
226
+
227
+ ## 8. File Upload
228
+
229
+ ```python
230
+ import magic # python-magic — reads magic bytes
231
+ ALLOWED = {"image/jpeg", "image/png", "image/webp"}
232
+
233
+ async def upload(file: UploadFile = File(...)):
234
+ if file.size and file.size > 10 * 1024 * 1024:
235
+ raise HTTPException(413, "Too large")
236
+ head = await file.read(2048)
237
+ mime = magic.from_buffer(head, mime=True)
238
+ if mime not in ALLOWED:
239
+ raise HTTPException(415, "Unsupported type")
240
+ await file.seek(0)
241
+ # Save with UUID name, outside webroot
242
+ ```
243
+
244
+ ---
245
+
246
+ ## 9. Password Hashing
247
+
248
+ ```python
249
+ from argon2 import PasswordHasher
250
+ ph = PasswordHasher(memory_cost=19_456, time_cost=2, parallelism=1)
251
+
252
+ hashed = ph.hash(password)
253
+ try:
254
+ ph.verify(hashed, attempt)
255
+ except argon2.exceptions.VerifyMismatchError:
256
+ raise HTTPException(401, "Invalid credentials")
257
+
258
+ if ph.check_needs_rehash(hashed): # transparent upgrade
259
+ user.password = ph.hash(attempt)
260
+ ```
261
+
262
+ Argon2id is the modern default. Avoid bare `hashlib`. For Django, the framework handles this — don't reinvent it.
263
+
264
+ ---
265
+
266
+ ## 10. SQL Injection — Use ORM Bindings
267
+
268
+ ```python
269
+ # WRONG — string interpolation
270
+ cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
271
+
272
+ # CORRECT — parameterized
273
+ cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])
274
+
275
+ # CORRECT — ORM
276
+ user = await User.get(id=user_id) # Tortoise / SQLAlchemy / Django ORM
277
+ ```
278
+
279
+ `SQLAlchemy.text()` with `:param` bindings is also safe. Raw f-strings are not.
280
+
281
+ ---
282
+
283
+ ## Endpoint Checklist
284
+
285
+ - [ ] `Depends(current_user)` for protected routes
286
+ - [ ] User ID from `current_user`, **never** from body
287
+ - [ ] Pydantic model with `extra="forbid"`
288
+ - [ ] Authz check on the resource (object-level)
289
+ - [ ] Rate limit applied to auth + writes
290
+ - [ ] No PII in logs
291
+ - [ ] Errors: `HTTPException` with generic detail; full info to logs only
292
+
293
+ ## FORBIDDEN Patterns
294
+
295
+ | Anti-pattern | Reason |
296
+ |---|---|
297
+ | `allow_origins=["*"]` with credentials | Browsers reject; auth breaks |
298
+ | Calling `jwt.decode` without `algorithms=` | `alg: none` and confusion attacks |
299
+ | Storing JWT in `localStorage` | XSS exfiltration |
300
+ | Disabling Django `CsrfViewMiddleware` globally | CSRF wide open |
301
+ | f-string interpolation in SQL | SQL injection |
302
+ | Deserializing untrusted bytes (pickle, marshal, shelve) | RCE via gadget chains — use JSON |
303
+ | `eval` / `exec` on user input | RCE |
304
+ | Logging request body or headers raw | Leaks passwords, cookies, tokens |
305
+ | Shell-mode subprocess with user input | Command injection — use list args, no shell |
306
+
307
+ ## See Also
308
+
309
+ - `security-baseline` — OWASP Top 10
310
+ - `secrets-management` — env vars, rotation
311
+ - `pydantic-validation` — schema patterns
312
+ - `observability` — structured logs without PII
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: async-patterns
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Async Python Patterns — Concurrency & Performance
2
7
 
3
8
  **ALWAYS invoke when writing async/await code or concurrent operations.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: django-patterns
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Django Patterns — Full-Stack Python (Django 5+)
2
7
 
3
8
  **ALWAYS invoke when writing Django models, views, or serializers.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: fastapi-patterns
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # FastAPI Patterns — High-Performance Async APIs
2
7
 
3
8
  **ALWAYS invoke when writing FastAPI routes, dependencies, or middleware.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: pydantic-validation
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Pydantic Validation — Runtime Type Safety for Python
2
7
 
3
8
  **ALWAYS use Pydantic for API schemas, config, and data boundaries.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: pytest-testing
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Pytest Testing — Python Testing Patterns
2
7
 
3
8
  **ALWAYS invoke AFTER implementing any feature.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: python-patterns
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Python Patterns — Architecture & Decision-Making
2
7
 
3
8
  **ALWAYS invoke when making Python architecture decisions.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: python-performance
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Python Performance — Profiling & Optimization
2
7
 
3
8
  **ALWAYS invoke when optimizing slow Python code.**
@@ -1,3 +1,8 @@
1
+ ---
2
+ name: scripting-automation
3
+ version: 1.0.0
4
+ ---
5
+
1
6
  # Local Scripts & Automation — Python 3.12+
2
7
 
3
8
  **ALWAYS invoke when building local scripts, CLI tools, or automation tasks.**
@@ -69,7 +69,8 @@
69
69
  "python-patterns",
70
70
  "pydantic-validation",
71
71
  "pytest-testing",
72
- "python-performance"
72
+ "python-performance",
73
+ "api-security-python"
73
74
  ],
74
75
  "requirements": [
75
76
  {
@@ -0,0 +1,76 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ ci:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ strategy:
20
+ matrix:
21
+ python: ['3.12']
22
+ fail-fast: false
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+
26
+ - uses: actions/setup-python@v5
27
+ with:
28
+ python-version: ${{ matrix.python }}
29
+ cache: pip
30
+
31
+ - name: Install uv
32
+ run: curl -LsSf https://astral.sh/uv/install.sh | sh
33
+
34
+ - name: Install dependencies
35
+ run: uv sync --frozen
36
+
37
+ - name: Typecheck (mypy)
38
+ run: uv run mypy .
39
+
40
+ - name: Lint (ruff)
41
+ run: uv run ruff check .
42
+
43
+ - name: Format check (ruff)
44
+ run: uv run ruff format --check .
45
+
46
+ - name: Tests (pytest)
47
+ run: uv run pytest --tb=short --cov --cov-report=xml
48
+
49
+ - uses: codecov/codecov-action@v4
50
+ if: always()
51
+ with:
52
+ token: ${{ secrets.CODECOV_TOKEN }}
53
+ fail_ci_if_error: false
54
+
55
+ security:
56
+ runs-on: ubuntu-latest
57
+ timeout-minutes: 10
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ with:
61
+ fetch-depth: 0
62
+
63
+ - uses: actions/setup-python@v5
64
+ with:
65
+ python-version: '3.12'
66
+
67
+ - name: Install pip-audit
68
+ run: pip install pip-audit
69
+
70
+ - name: Audit dependencies
71
+ run: pip-audit --strict --vulnerability-service osv
72
+
73
+ - name: Gitleaks (secret scan)
74
+ uses: gitleaks/gitleaks-action@v2
75
+ env:
76
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,56 @@
1
+ name: Security
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 4 * * 1'
6
+ push:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: read
12
+ security-events: write
13
+
14
+ jobs:
15
+ audit:
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 10
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: '3.12'
23
+ - run: pip install pip-audit
24
+ - run: pip-audit --strict
25
+
26
+ bandit:
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 10
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: '3.12'
34
+ - run: pip install bandit[toml]
35
+ - run: bandit -r . -ll -ii --exclude tests,test
36
+
37
+ gitleaks:
38
+ runs-on: ubuntu-latest
39
+ timeout-minutes: 5
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ with:
43
+ fetch-depth: 0
44
+ - uses: gitleaks/gitleaks-action@v2
45
+ env:
46
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
47
+
48
+ codeql:
49
+ runs-on: ubuntu-latest
50
+ timeout-minutes: 20
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+ - uses: github/codeql-action/init@v3
54
+ with:
55
+ languages: python
56
+ - uses: github/codeql-action/analyze@v3