@qazuor/claude-code-config 0.3.1 → 0.5.0
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/README.md +289 -9
- package/dist/bin.cjs +2247 -48
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2247 -48
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +282 -1
- package/dist/index.d.ts +282 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/templates/docs/_registry.json +54 -0
- package/templates/docs/standards/code-standards.md +20 -0
- package/templates/docs/standards/design-standards.md +13 -0
- package/templates/docs/standards/documentation-standards.md +13 -0
- package/templates/docs/standards/performance-standards.md +524 -0
- package/templates/docs/standards/security-standards.md +496 -0
- package/templates/docs/standards/testing-standards.md +15 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
# Security Standards
|
|
2
|
+
|
|
3
|
+
This document defines the security standards and practices for the project.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
<!-- markdownlint-disable MD051 -->
|
|
10
|
+
|
|
11
|
+
1. [Security Philosophy](#security-philosophy)
|
|
12
|
+
2. [Authentication](#authentication)
|
|
13
|
+
3. [Authorization](#authorization)
|
|
14
|
+
4. [Input Validation](#input-validation)
|
|
15
|
+
5. [CSRF Protection](#csrf-protection)
|
|
16
|
+
6. [Rate Limiting](#rate-limiting)
|
|
17
|
+
7. [Data Protection](#data-protection)
|
|
18
|
+
8. [API Security](#api-security)
|
|
19
|
+
9. [Dependency Security](#dependency-security)
|
|
20
|
+
10. [Security Headers](#security-headers)
|
|
21
|
+
|
|
22
|
+
<!-- markdownlint-enable MD051 -->
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
<!-- AUTO-GENERATED: Configured values -->
|
|
29
|
+
| Setting | Value |
|
|
30
|
+
|---------|-------|
|
|
31
|
+
| **Authentication Pattern** | {{AUTH_PATTERN}} |
|
|
32
|
+
| **Input Validation Library** | {{INPUT_VALIDATION}} |
|
|
33
|
+
| **CSRF Protection** | {{CSRF_PROTECTION}} |
|
|
34
|
+
| **Rate Limiting** | {{RATE_LIMITING}} |
|
|
35
|
+
<!-- END AUTO-GENERATED -->
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Security Philosophy
|
|
40
|
+
|
|
41
|
+
### Core Principles
|
|
42
|
+
|
|
43
|
+
**Defense in Depth:**
|
|
44
|
+
|
|
45
|
+
- Multiple layers of security
|
|
46
|
+
- No single point of failure
|
|
47
|
+
- Fail securely (deny by default)
|
|
48
|
+
|
|
49
|
+
**Principle of Least Privilege:**
|
|
50
|
+
|
|
51
|
+
- Users get minimum necessary permissions
|
|
52
|
+
- Services run with minimal privileges
|
|
53
|
+
- API tokens are scoped appropriately
|
|
54
|
+
|
|
55
|
+
**Secure by Default:**
|
|
56
|
+
|
|
57
|
+
- Security enabled out of the box
|
|
58
|
+
- Opt-out, not opt-in
|
|
59
|
+
- Safe defaults everywhere
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Authentication
|
|
64
|
+
|
|
65
|
+
### Authentication Pattern: {{AUTH_PATTERN}}
|
|
66
|
+
|
|
67
|
+
**Supported patterns:**
|
|
68
|
+
|
|
69
|
+
- **JWT** - Stateless JSON Web Tokens
|
|
70
|
+
- **Session** - Server-side session management
|
|
71
|
+
- **OAuth** - OAuth 2.0 / OpenID Connect
|
|
72
|
+
|
|
73
|
+
### JWT Implementation (if using JWT)
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Token structure
|
|
77
|
+
interface JWTPayload {
|
|
78
|
+
sub: string; // User ID
|
|
79
|
+
email: string; // User email
|
|
80
|
+
role: UserRole; // User role
|
|
81
|
+
iat: number; // Issued at
|
|
82
|
+
exp: number; // Expiration
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Token configuration
|
|
86
|
+
const JWT_CONFIG = {
|
|
87
|
+
algorithm: 'HS256',
|
|
88
|
+
accessTokenExpiry: '15m',
|
|
89
|
+
refreshTokenExpiry: '7d',
|
|
90
|
+
issuer: 'your-app-name',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Token generation
|
|
94
|
+
const generateToken = (user: User): string => {
|
|
95
|
+
return jwt.sign(
|
|
96
|
+
{ sub: user.id, email: user.email, role: user.role },
|
|
97
|
+
process.env.JWT_SECRET,
|
|
98
|
+
{ expiresIn: JWT_CONFIG.accessTokenExpiry }
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Session Implementation (if using sessions)
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// Session configuration
|
|
107
|
+
const SESSION_CONFIG = {
|
|
108
|
+
name: 'session_id',
|
|
109
|
+
secret: process.env.SESSION_SECRET,
|
|
110
|
+
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
111
|
+
httpOnly: true,
|
|
112
|
+
secure: process.env.NODE_ENV === 'production',
|
|
113
|
+
sameSite: 'strict' as const,
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Password Security
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Password requirements
|
|
121
|
+
const PASSWORD_REQUIREMENTS = {
|
|
122
|
+
minLength: 8,
|
|
123
|
+
maxLength: 128,
|
|
124
|
+
requireUppercase: true,
|
|
125
|
+
requireLowercase: true,
|
|
126
|
+
requireNumbers: true,
|
|
127
|
+
requireSpecialChars: false,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Password hashing
|
|
131
|
+
import { hash, verify } from '@node-rs/bcrypt';
|
|
132
|
+
|
|
133
|
+
const hashPassword = async (password: string): Promise<string> => {
|
|
134
|
+
return hash(password, 12); // Cost factor of 12
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const verifyPassword = async (password: string, hash: string): Promise<boolean> => {
|
|
138
|
+
return verify(password, hash);
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Authentication Best Practices
|
|
143
|
+
|
|
144
|
+
**DO:**
|
|
145
|
+
|
|
146
|
+
- Use secure, httpOnly cookies for tokens
|
|
147
|
+
- Implement token refresh mechanism
|
|
148
|
+
- Hash passwords with bcrypt (cost 12+)
|
|
149
|
+
- Use constant-time comparison for secrets
|
|
150
|
+
- Log authentication failures
|
|
151
|
+
|
|
152
|
+
**DON'T:**
|
|
153
|
+
|
|
154
|
+
- Store passwords in plain text
|
|
155
|
+
- Use MD5 or SHA1 for passwords
|
|
156
|
+
- Include sensitive data in JWT payload
|
|
157
|
+
- Use predictable session IDs
|
|
158
|
+
- Expose authentication errors
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Authorization
|
|
163
|
+
|
|
164
|
+
### Role-Based Access Control (RBAC)
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// Define roles
|
|
168
|
+
type UserRole = 'admin' | 'host' | 'guest';
|
|
169
|
+
|
|
170
|
+
// Define permissions
|
|
171
|
+
type Permission =
|
|
172
|
+
| 'user:read' | 'user:write' | 'user:delete'
|
|
173
|
+
| 'entity:read' | 'entity:write' | 'entity:delete'
|
|
174
|
+
| 'booking:read' | 'booking:write' | 'booking:delete';
|
|
175
|
+
|
|
176
|
+
// Role-permission mapping
|
|
177
|
+
const ROLE_PERMISSIONS: Record<UserRole, Permission[]> = {
|
|
178
|
+
admin: ['user:read', 'user:write', 'user:delete', 'entity:read', 'entity:write', 'entity:delete'],
|
|
179
|
+
host: ['entity:read', 'entity:write', 'booking:read'],
|
|
180
|
+
guest: ['entity:read', 'booking:read', 'booking:write'],
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// Authorization check
|
|
184
|
+
const hasPermission = (user: User, permission: Permission): boolean => {
|
|
185
|
+
return ROLE_PERMISSIONS[user.role]?.includes(permission) ?? false;
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Resource-Level Authorization
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Check ownership
|
|
193
|
+
const canModifyEntity = async (user: User, entityId: string): Promise<boolean> => {
|
|
194
|
+
if (user.role === 'admin') return true;
|
|
195
|
+
|
|
196
|
+
const entity = await db.query.entities.findFirst({
|
|
197
|
+
where: eq(entities.id, entityId),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return entity?.hostId === user.id;
|
|
201
|
+
};
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Input Validation
|
|
207
|
+
|
|
208
|
+
### Validation Library: {{INPUT_VALIDATION}}
|
|
209
|
+
|
|
210
|
+
**Using {{VALIDATION_LIBRARY}} for all input validation:**
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { z } from 'zod';
|
|
214
|
+
|
|
215
|
+
// Define schemas
|
|
216
|
+
const createUserSchema = z.object({
|
|
217
|
+
name: z.string()
|
|
218
|
+
.min(1, 'Name is required')
|
|
219
|
+
.max(200, 'Name too long')
|
|
220
|
+
.trim(),
|
|
221
|
+
email: z.string()
|
|
222
|
+
.email('Invalid email format')
|
|
223
|
+
.toLowerCase()
|
|
224
|
+
.trim(),
|
|
225
|
+
password: z.string()
|
|
226
|
+
.min(8, 'Password must be at least 8 characters')
|
|
227
|
+
.max(128, 'Password too long'),
|
|
228
|
+
role: z.enum(['admin', 'host', 'guest']),
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Validate in route
|
|
232
|
+
app.post('/users', zValidator('json', createUserSchema), async (c) => {
|
|
233
|
+
const input = c.req.valid('json'); // Type-safe and validated
|
|
234
|
+
// ...
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Validation Rules
|
|
239
|
+
|
|
240
|
+
**Always validate:**
|
|
241
|
+
|
|
242
|
+
- All user input (forms, query params, headers)
|
|
243
|
+
- File uploads (type, size, content)
|
|
244
|
+
- API request bodies
|
|
245
|
+
- URL parameters
|
|
246
|
+
- Webhook payloads
|
|
247
|
+
|
|
248
|
+
**Sanitization:**
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
// Sanitize HTML content
|
|
252
|
+
import DOMPurify from 'isomorphic-dompurify';
|
|
253
|
+
|
|
254
|
+
const sanitizeHtml = (dirty: string): string => {
|
|
255
|
+
return DOMPurify.sanitize(dirty, {
|
|
256
|
+
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'br'],
|
|
257
|
+
ALLOWED_ATTR: ['href'],
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
// Sanitize for SQL (use parameterized queries instead)
|
|
262
|
+
// NEVER do this:
|
|
263
|
+
// const query = `SELECT * FROM users WHERE id = '${userId}'`;
|
|
264
|
+
|
|
265
|
+
// ALWAYS use parameterized queries:
|
|
266
|
+
const result = await db.query.users.findFirst({
|
|
267
|
+
where: eq(users.id, userId),
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## CSRF Protection
|
|
274
|
+
|
|
275
|
+
### CSRF Protection: {{CSRF_PROTECTION}}
|
|
276
|
+
|
|
277
|
+
**Implementation:**
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
// Generate CSRF token
|
|
281
|
+
import { randomBytes } from 'crypto';
|
|
282
|
+
|
|
283
|
+
const generateCsrfToken = (): string => {
|
|
284
|
+
return randomBytes(32).toString('hex');
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Middleware
|
|
288
|
+
const csrfMiddleware = async (c: Context, next: Next) => {
|
|
289
|
+
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(c.req.method)) {
|
|
290
|
+
const token = c.req.header('X-CSRF-Token');
|
|
291
|
+
const sessionToken = getCookie(c, 'csrf_token');
|
|
292
|
+
|
|
293
|
+
if (!token || token !== sessionToken) {
|
|
294
|
+
return c.json({ error: 'Invalid CSRF token' }, 403);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
await next();
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// Set token in response
|
|
301
|
+
const setCsrfToken = (c: Context, token: string) => {
|
|
302
|
+
setCookie(c, 'csrf_token', token, {
|
|
303
|
+
httpOnly: true,
|
|
304
|
+
secure: true,
|
|
305
|
+
sameSite: 'Strict',
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Frontend integration:**
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Include token in requests
|
|
314
|
+
const api = axios.create({
|
|
315
|
+
headers: {
|
|
316
|
+
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')?.content,
|
|
317
|
+
},
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Rate Limiting
|
|
324
|
+
|
|
325
|
+
### Rate Limiting: {{RATE_LIMITING}}
|
|
326
|
+
|
|
327
|
+
**Implementation:**
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
import { Ratelimit } from '@upstash/ratelimit';
|
|
331
|
+
import { Redis } from '@upstash/redis';
|
|
332
|
+
|
|
333
|
+
const ratelimit = new Ratelimit({
|
|
334
|
+
redis: Redis.fromEnv(),
|
|
335
|
+
limiter: Ratelimit.slidingWindow(100, '1 m'), // 100 requests per minute
|
|
336
|
+
analytics: true,
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Middleware
|
|
340
|
+
const rateLimitMiddleware = async (c: Context, next: Next) => {
|
|
341
|
+
const ip = c.req.header('x-forwarded-for') ?? 'unknown';
|
|
342
|
+
const { success, limit, remaining, reset } = await ratelimit.limit(ip);
|
|
343
|
+
|
|
344
|
+
c.header('X-RateLimit-Limit', limit.toString());
|
|
345
|
+
c.header('X-RateLimit-Remaining', remaining.toString());
|
|
346
|
+
c.header('X-RateLimit-Reset', reset.toString());
|
|
347
|
+
|
|
348
|
+
if (!success) {
|
|
349
|
+
return c.json({ error: 'Too many requests' }, 429);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
await next();
|
|
353
|
+
};
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Rate limits by endpoint type:**
|
|
357
|
+
|
|
358
|
+
| Endpoint Type | Authenticated | Anonymous |
|
|
359
|
+
|---------------|---------------|-----------|
|
|
360
|
+
| Read (GET) | 200/min | 50/min |
|
|
361
|
+
| Write (POST/PUT/DELETE) | 100/min | 20/min |
|
|
362
|
+
| Auth (login/register) | 10/min | 5/min |
|
|
363
|
+
| Upload | 10/min | 2/min |
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Data Protection
|
|
368
|
+
|
|
369
|
+
### Sensitive Data Handling
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
// Never log sensitive data
|
|
373
|
+
const sanitizeForLogging = (data: unknown): unknown => {
|
|
374
|
+
if (typeof data !== 'object' || data === null) return data;
|
|
375
|
+
|
|
376
|
+
const sensitive = ['password', 'token', 'secret', 'apiKey', 'creditCard'];
|
|
377
|
+
const sanitized = { ...data };
|
|
378
|
+
|
|
379
|
+
for (const key of Object.keys(sanitized)) {
|
|
380
|
+
if (sensitive.some(s => key.toLowerCase().includes(s))) {
|
|
381
|
+
sanitized[key] = '[REDACTED]';
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return sanitized;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// Encrypt sensitive data at rest
|
|
389
|
+
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
|
|
390
|
+
|
|
391
|
+
const encrypt = (text: string, key: Buffer): string => {
|
|
392
|
+
const iv = randomBytes(16);
|
|
393
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
394
|
+
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
|
|
395
|
+
const authTag = cipher.getAuthTag();
|
|
396
|
+
return Buffer.concat([iv, authTag, encrypted]).toString('base64');
|
|
397
|
+
};
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### PII Protection
|
|
401
|
+
|
|
402
|
+
- Minimize collection of personal data
|
|
403
|
+
- Encrypt sensitive data at rest
|
|
404
|
+
- Implement data retention policies
|
|
405
|
+
- Support user data deletion requests
|
|
406
|
+
- Log access to sensitive data
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## API Security
|
|
411
|
+
|
|
412
|
+
### Security Headers
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
// Security headers middleware
|
|
416
|
+
const securityHeaders = async (c: Context, next: Next) => {
|
|
417
|
+
await next();
|
|
418
|
+
|
|
419
|
+
c.header('X-Content-Type-Options', 'nosniff');
|
|
420
|
+
c.header('X-Frame-Options', 'DENY');
|
|
421
|
+
c.header('X-XSS-Protection', '1; mode=block');
|
|
422
|
+
c.header('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
423
|
+
c.header('Permissions-Policy', 'geolocation=(), camera=(), microphone=()');
|
|
424
|
+
|
|
425
|
+
if (process.env.NODE_ENV === 'production') {
|
|
426
|
+
c.header(
|
|
427
|
+
'Strict-Transport-Security',
|
|
428
|
+
'max-age=31536000; includeSubDomains; preload'
|
|
429
|
+
);
|
|
430
|
+
c.header(
|
|
431
|
+
'Content-Security-Policy',
|
|
432
|
+
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### CORS Configuration
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
import { cors } from 'hono/cors';
|
|
442
|
+
|
|
443
|
+
app.use('*', cors({
|
|
444
|
+
origin: process.env.ALLOWED_ORIGINS?.split(',') ?? ['http://localhost:3000'],
|
|
445
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
446
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token'],
|
|
447
|
+
credentials: true,
|
|
448
|
+
maxAge: 86400,
|
|
449
|
+
}));
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Dependency Security
|
|
455
|
+
|
|
456
|
+
### Security Scanning
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
# Run security audit
|
|
460
|
+
pnpm audit
|
|
461
|
+
|
|
462
|
+
# Fix vulnerabilities
|
|
463
|
+
pnpm audit fix
|
|
464
|
+
|
|
465
|
+
# Check for outdated dependencies
|
|
466
|
+
pnpm outdated
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Dependency Management
|
|
470
|
+
|
|
471
|
+
- Review all new dependencies before adding
|
|
472
|
+
- Use lockfiles (pnpm-lock.yaml)
|
|
473
|
+
- Pin major versions
|
|
474
|
+
- Run security audits in CI/CD
|
|
475
|
+
- Subscribe to security advisories
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Security Checklist
|
|
480
|
+
|
|
481
|
+
Before deploying:
|
|
482
|
+
|
|
483
|
+
- [ ] All inputs validated and sanitized
|
|
484
|
+
- [ ] Authentication implemented correctly
|
|
485
|
+
- [ ] Authorization checks on all endpoints
|
|
486
|
+
- [ ] CSRF protection enabled
|
|
487
|
+
- [ ] Rate limiting configured
|
|
488
|
+
- [ ] Security headers set
|
|
489
|
+
- [ ] Sensitive data encrypted
|
|
490
|
+
- [ ] No secrets in code/logs
|
|
491
|
+
- [ ] Dependencies audited
|
|
492
|
+
- [ ] Error messages don't leak information
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
**Security is not optional. All code must follow these standards.**
|
|
@@ -4,6 +4,21 @@ This document defines the testing standards and practices.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Configuration
|
|
8
|
+
|
|
9
|
+
<!-- AUTO-GENERATED: Configured values -->
|
|
10
|
+
| Setting | Value |
|
|
11
|
+
|---------|-------|
|
|
12
|
+
| **Coverage Target** | {{COVERAGE_TARGET}}% |
|
|
13
|
+
| **TDD Required** | {{TDD_REQUIRED}} |
|
|
14
|
+
| **Test Pattern** | {{TEST_PATTERN}} |
|
|
15
|
+
| **Test Location** | {{TEST_LOCATION}} |
|
|
16
|
+
| **Unit Test Max** | {{UNIT_TEST_MAX_MS}}ms |
|
|
17
|
+
| **Integration Test Max** | {{INTEGRATION_TEST_MAX_MS}}ms |
|
|
18
|
+
<!-- END AUTO-GENERATED -->
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
7
22
|
## Table of Contents
|
|
8
23
|
|
|
9
24
|
<!-- markdownlint-disable MD051 -->
|