@massu/core 0.4.2 → 0.6.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 +40 -0
- package/agents/massu-architecture-reviewer.md +104 -0
- package/agents/massu-blast-radius-analyzer.md +84 -0
- package/agents/massu-competitive-scorer.md +126 -0
- package/agents/massu-help-sync.md +73 -0
- package/agents/massu-migration-writer.md +94 -0
- package/agents/massu-output-scorer.md +87 -0
- package/agents/massu-pattern-reviewer.md +84 -0
- package/agents/massu-plan-auditor.md +170 -0
- package/agents/massu-schema-sync-verifier.md +70 -0
- package/agents/massu-security-reviewer.md +98 -0
- package/agents/massu-ux-reviewer.md +106 -0
- package/commands/_shared-preamble.md +53 -23
- package/commands/_shared-references/auto-learning-protocol.md +71 -0
- package/commands/_shared-references/blast-radius-protocol.md +76 -0
- package/commands/_shared-references/security-pre-screen.md +64 -0
- package/commands/_shared-references/test-first-protocol.md +87 -0
- package/commands/_shared-references/verification-table.md +52 -0
- package/commands/massu-article-review.md +343 -0
- package/commands/massu-autoresearch/references/eval-runner.md +84 -0
- package/commands/massu-autoresearch/references/safety-rails.md +125 -0
- package/commands/massu-autoresearch/references/scoring-protocol.md +151 -0
- package/commands/massu-autoresearch.md +258 -0
- package/commands/massu-batch.md +44 -12
- package/commands/massu-bearings.md +42 -8
- package/commands/massu-checkpoint.md +588 -0
- package/commands/massu-ci-fix.md +2 -2
- package/commands/massu-command-health.md +132 -0
- package/commands/massu-command-improve.md +232 -0
- package/commands/massu-commit.md +205 -44
- package/commands/massu-create-plan.md +239 -57
- package/commands/massu-data/references/common-queries.md +79 -0
- package/commands/massu-data/references/table-guide.md +50 -0
- package/commands/massu-data.md +66 -0
- package/commands/massu-dead-code.md +29 -34
- package/commands/massu-debug/references/auto-learning.md +61 -0
- package/commands/massu-debug/references/codegraph-tracing.md +80 -0
- package/commands/massu-debug/references/common-shortcuts.md +98 -0
- package/commands/massu-debug/references/investigation-phases.md +294 -0
- package/commands/massu-debug/references/report-format.md +107 -0
- package/commands/massu-debug.md +105 -386
- package/commands/massu-docs.md +1 -1
- package/commands/massu-full-audit.md +61 -0
- package/commands/massu-gap-enhancement-analyzer.md +276 -16
- package/commands/massu-golden-path/references/approval-points.md +216 -0
- package/commands/massu-golden-path/references/competitive-mode.md +273 -0
- package/commands/massu-golden-path/references/error-handling.md +121 -0
- package/commands/massu-golden-path/references/phase-0-requirements.md +53 -0
- package/commands/massu-golden-path/references/phase-1-plan-creation.md +168 -0
- package/commands/massu-golden-path/references/phase-2-implementation.md +397 -0
- package/commands/massu-golden-path/references/phase-2.5-gap-analyzer.md +156 -0
- package/commands/massu-golden-path/references/phase-3-simplify.md +40 -0
- package/commands/massu-golden-path/references/phase-4-commit.md +94 -0
- package/commands/massu-golden-path/references/phase-5-push.md +116 -0
- package/commands/massu-golden-path/references/phase-5.5-production-verify.md +170 -0
- package/commands/massu-golden-path/references/phase-6-completion.md +113 -0
- package/commands/massu-golden-path/references/qa-evaluator-spec.md +137 -0
- package/commands/massu-golden-path/references/sprint-contract-protocol.md +117 -0
- package/commands/massu-golden-path/references/vr-visual-calibration.md +73 -0
- package/commands/massu-golden-path.md +114 -848
- package/commands/massu-guide.md +72 -69
- package/commands/massu-hooks.md +27 -12
- package/commands/massu-hotfix.md +221 -144
- package/commands/massu-incident.md +49 -20
- package/commands/massu-infra-audit.md +187 -0
- package/commands/massu-learning-audit.md +211 -0
- package/commands/massu-loop/references/auto-learning.md +49 -0
- package/commands/massu-loop/references/checkpoint-audit.md +40 -0
- package/commands/massu-loop/references/guardrails.md +17 -0
- package/commands/massu-loop/references/iteration-structure.md +115 -0
- package/commands/massu-loop/references/loop-controller.md +188 -0
- package/commands/massu-loop/references/plan-extraction.md +78 -0
- package/commands/massu-loop/references/vr-plan-spec.md +140 -0
- package/commands/massu-loop-playwright.md +9 -9
- package/commands/massu-loop.md +115 -670
- package/commands/massu-new-pattern.md +423 -0
- package/commands/massu-perf.md +422 -0
- package/commands/massu-plan-audit.md +1 -1
- package/commands/massu-plan.md +389 -122
- package/commands/massu-production-verify.md +433 -0
- package/commands/massu-push.md +62 -378
- package/commands/massu-recap.md +29 -3
- package/commands/massu-rollback.md +613 -0
- package/commands/massu-scaffold-hook.md +2 -4
- package/commands/massu-scaffold-page.md +2 -3
- package/commands/massu-scaffold-router.md +1 -2
- package/commands/massu-security.md +619 -0
- package/commands/massu-simplify.md +115 -85
- package/commands/massu-squirrels.md +2 -2
- package/commands/massu-tdd.md +38 -22
- package/commands/massu-test.md +3 -3
- package/commands/massu-type-mismatch-audit.md +469 -0
- package/commands/massu-ui-audit.md +587 -0
- package/commands/massu-verify-playwright.md +287 -32
- package/commands/massu-verify.md +150 -46
- package/dist/cli.js +1451 -1047
- package/dist/hooks/post-tool-use.js +75 -6
- package/dist/hooks/user-prompt.js +16 -0
- package/package.json +6 -2
- package/patterns/build-patterns.md +302 -0
- package/patterns/component-patterns.md +246 -0
- package/patterns/display-patterns.md +185 -0
- package/patterns/form-patterns.md +890 -0
- package/patterns/integration-testing-checklist.md +445 -0
- package/patterns/security-patterns.md +219 -0
- package/patterns/testing-patterns.md +569 -0
- package/patterns/tool-routing.md +81 -0
- package/patterns/ui-patterns.md +371 -0
- package/protocols/plan-implementation.md +267 -0
- package/protocols/recovery.md +225 -0
- package/protocols/verification.md +404 -0
- package/reference/command-taxonomy.md +178 -0
- package/reference/cr-rules-reference.md +76 -0
- package/reference/hook-execution-order.md +148 -0
- package/reference/lessons-learned.md +175 -0
- package/reference/patterns-quickref.md +208 -0
- package/reference/standards.md +135 -0
- package/reference/subagents-reference.md +17 -0
- package/reference/vr-verification-reference.md +867 -0
- package/src/commands/init.ts +27 -0
- package/src/commands/install-commands.ts +149 -53
- package/src/hooks/post-tool-use.ts +17 -0
- package/src/hooks/user-prompt.ts +21 -0
- package/src/memory-file-ingest.ts +127 -0
- package/src/memory-tools.ts +34 -1
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
# Integration Testing Checklist
|
|
2
|
+
|
|
3
|
+
**Purpose**: Router contract verification, pre-test writing steps, test templates, common anti-patterns, prevention system.
|
|
4
|
+
|
|
5
|
+
**When to Read**: Before writing integration tests.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## CRITICAL: Router Contract Verification Required
|
|
10
|
+
|
|
11
|
+
**Why**: Writing tests for non-existent router methods wastes time and resources. Tests will always fail with "No procedure found" errors.
|
|
12
|
+
|
|
13
|
+
**Prevention**: Always verify router methods exist BEFORE writing integration tests.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Pre-Test Writing Checklist
|
|
18
|
+
|
|
19
|
+
### [x] Step 1: Read the Actual Router File
|
|
20
|
+
|
|
21
|
+
**DO NOT SKIP THIS STEP**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Example: Verify workflow engine router methods
|
|
25
|
+
cat src/server/api/routers/workflow-engine.ts | grep -A2 "export const"
|
|
26
|
+
|
|
27
|
+
# Look for the router definition:
|
|
28
|
+
# export const workflowEngineRouter = createTRPCRouter({
|
|
29
|
+
# methodName: protectedProcedure...
|
|
30
|
+
# })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Common Mistake**: Assuming methods exist based on naming conventions
|
|
34
|
+
**Correct Approach**: Read the actual file to see what's implemented
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
### [x] Step 2: List Available Methods in Test Header
|
|
39
|
+
|
|
40
|
+
Document the router's API contract at the top of your test file:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
/**
|
|
44
|
+
* Integration Tests: Workflow Engine Router
|
|
45
|
+
*
|
|
46
|
+
* ========================================
|
|
47
|
+
* ROUTER METHODS VERIFIED ({Date})
|
|
48
|
+
* ========================================
|
|
49
|
+
* Source: src/server/api/routers/workflow-engine.ts
|
|
50
|
+
*
|
|
51
|
+
* Available Methods:
|
|
52
|
+
* - executeWorkflow(workflowId, context?) - Execute a workflow with optional context
|
|
53
|
+
* - getExecutionStatus(executionId) - Get the status of a workflow execution
|
|
54
|
+
* - pauseExecution(executionId) - Pause a running workflow
|
|
55
|
+
* - resumeExecution(executionId) - Resume a paused workflow
|
|
56
|
+
*
|
|
57
|
+
* Methods NOT Available:
|
|
58
|
+
* - create() - Does NOT exist (use workflows.create() instead)
|
|
59
|
+
* - update() - Does NOT exist (workflows are immutable)
|
|
60
|
+
* - delete() - Does NOT exist (workflows are immutable)
|
|
61
|
+
*
|
|
62
|
+
* Input Schemas:
|
|
63
|
+
* - executeWorkflow: { workflowId: string (UUID), context?: Record<string, any> }
|
|
64
|
+
* - getExecutionStatus: { executionId: string (UUID) }
|
|
65
|
+
* - pauseExecution: { executionId: string (UUID) }
|
|
66
|
+
* - resumeExecution: { executionId: string (UUID) }
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
70
|
+
import { createCaller } from '../helpers/trpc';
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Why**: This documentation serves as a contract. When the router changes, you can immediately see what needs updating in tests.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### [x] Step 3: Verify Input Schemas
|
|
78
|
+
|
|
79
|
+
Check the Zod schema for each method you'll be testing:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// From router file:
|
|
83
|
+
executeWorkflow: protectedProcedure
|
|
84
|
+
.input(z.object({
|
|
85
|
+
workflowId: z.string().uuid(), // <- Required, must be UUID
|
|
86
|
+
context: z.record(z.any()).optional(), // <- Optional, any object
|
|
87
|
+
}))
|
|
88
|
+
.mutation(async ({ ctx, input }) => {
|
|
89
|
+
// Implementation...
|
|
90
|
+
}),
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Document in Test**:
|
|
94
|
+
```typescript
|
|
95
|
+
// Test using correct input structure
|
|
96
|
+
const result = await caller.workflowEngine.executeWorkflow({
|
|
97
|
+
workflowId: testWorkflowId, // [x] Matches schema: string UUID
|
|
98
|
+
context: { userId: 'test' } // [x] Matches schema: optional Record
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Common Mistakes**:
|
|
103
|
+
- [X] Passing `{ name, trigger_type, workflow_definition }` to `executeWorkflow` (wrong schema)
|
|
104
|
+
- [X] Calling `create()` when only `executeWorkflow()` exists (method doesn't exist)
|
|
105
|
+
- [X] Missing required fields (Zod will error at runtime)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### [x] Step 4: Run Router Contract Validation
|
|
110
|
+
|
|
111
|
+
**BEFORE COMMITTING**, run the validation script:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npm run validate:router-contracts
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Expected Output (Success)**:
|
|
118
|
+
```
|
|
119
|
+
=== API Contract Validation ===
|
|
120
|
+
Scanning integration test files...
|
|
121
|
+
Found 21 test files
|
|
122
|
+
|
|
123
|
+
Extracting router method calls...
|
|
124
|
+
Found 125 router method calls
|
|
125
|
+
|
|
126
|
+
Building router contract map...
|
|
127
|
+
Found 174 routers with 1497 total procedures
|
|
128
|
+
|
|
129
|
+
[x] SUCCESS: All 125 router method calls are valid!
|
|
130
|
+
No API contract violations found.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**If Failures Found**:
|
|
134
|
+
```
|
|
135
|
+
[X] FAILURE: Found 5 invalid router method calls
|
|
136
|
+
|
|
137
|
+
Router: workflowEngine
|
|
138
|
+
[x] Router exists
|
|
139
|
+
Available methods: executeWorkflow, getExecutionStatus, pauseExecution, resumeExecution
|
|
140
|
+
|
|
141
|
+
[X] create()
|
|
142
|
+
File: tests/integration/critical-flows/workflow-lifecycle.test.ts:165
|
|
143
|
+
Code: const workflow = await caller.workflowEngine.create({
|
|
144
|
+
Method 'create' does not exist in workflowEngine router
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Action**: Fix the test BEFORE committing. Update method calls to use actual router methods.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### [x] Step 5: Commit Tests Immediately
|
|
152
|
+
|
|
153
|
+
**DO NOT** leave integration tests as untracked files.
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Stage your test files
|
|
157
|
+
git add tests/integration/critical-flows/my-new-test.test.ts
|
|
158
|
+
|
|
159
|
+
# Commit immediately
|
|
160
|
+
git commit -m "test(integration): add workflow engine lifecycle tests"
|
|
161
|
+
|
|
162
|
+
# Push to trigger CI/CD
|
|
163
|
+
git push
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Why**: Uncommitted tests don't run in CI/CD. Issues won't be caught until you commit them, wasting time.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Test Writing Pattern
|
|
171
|
+
|
|
172
|
+
### Template for New Integration Tests
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
/**
|
|
176
|
+
* Integration Tests: {Router Name} Router
|
|
177
|
+
*
|
|
178
|
+
* ========================================
|
|
179
|
+
* ROUTER METHODS VERIFIED ({Date})
|
|
180
|
+
* ========================================
|
|
181
|
+
* Source: src/server/api/routers/{router-file}.ts
|
|
182
|
+
*
|
|
183
|
+
* Available Methods:
|
|
184
|
+
* - method1(params) - Description
|
|
185
|
+
* - method2(params) - Description
|
|
186
|
+
*
|
|
187
|
+
* Methods NOT Available:
|
|
188
|
+
* - methodX() - Does NOT exist (reason/alternative)
|
|
189
|
+
*
|
|
190
|
+
* Input Schemas:
|
|
191
|
+
* - method1: { field: type, ... }
|
|
192
|
+
* - method2: { field: type, ... }
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
196
|
+
import { createCaller } from '../helpers/trpc';
|
|
197
|
+
import { PrismaClient } from '@prisma/client';
|
|
198
|
+
|
|
199
|
+
const prisma = new PrismaClient();
|
|
200
|
+
|
|
201
|
+
describe('Integration: {Router Name} Router', () => {
|
|
202
|
+
let caller: ReturnType<typeof createCaller>;
|
|
203
|
+
|
|
204
|
+
beforeAll(async () => {
|
|
205
|
+
// Setup test data
|
|
206
|
+
caller = createCaller({ userId: 'test-user-id' });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
afterAll(async () => {
|
|
210
|
+
// Cleanup test data
|
|
211
|
+
await prisma.$disconnect();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('method1', () => {
|
|
215
|
+
it('should do X when Y', async () => {
|
|
216
|
+
// Test using VERIFIED router method
|
|
217
|
+
const result = await caller.routerName.method1({
|
|
218
|
+
field1: 'value', // [x] Matches input schema
|
|
219
|
+
field2: 123 // [x] Matches input schema
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
expect(result).toBeDefined();
|
|
223
|
+
expect(result.field).toBe('expected-value');
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Common Anti-Patterns to Avoid
|
|
232
|
+
|
|
233
|
+
### [X] Anti-Pattern 1: Assuming Method Names
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// [X] WRONG: Assuming create() exists because it's common
|
|
237
|
+
const workflow = await caller.workflowEngine.create({
|
|
238
|
+
name: 'Test Workflow',
|
|
239
|
+
trigger_type: 'manual'
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Why Wrong**: Method doesn't exist. Should check router first.
|
|
244
|
+
|
|
245
|
+
**Correct Approach**:
|
|
246
|
+
```typescript
|
|
247
|
+
// [x] CORRECT: Verified executeWorkflow() exists
|
|
248
|
+
const execution = await caller.workflowEngine.executeWorkflow({
|
|
249
|
+
workflowId: existingWorkflowId,
|
|
250
|
+
context: { trigger: 'manual' }
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### [X] Anti-Pattern 2: Testing Non-Existent Features
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
// [X] WRONG: Writing tests for features that don't exist yet
|
|
260
|
+
describe('Workflow Templates', () => {
|
|
261
|
+
it('should clone template', async () => {
|
|
262
|
+
await caller.workflowEngine.cloneTemplate({ templateId: 'test' });
|
|
263
|
+
// ^^^^^^^^^^^^^^^ Method doesn't exist
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Why Wrong**: Test will always fail. Wastes time debugging "missing method" instead of actual bugs.
|
|
269
|
+
|
|
270
|
+
**Correct Approach**:
|
|
271
|
+
```typescript
|
|
272
|
+
// [x] CORRECT: Only test methods that exist
|
|
273
|
+
describe('Workflow Execution', () => {
|
|
274
|
+
it('should execute workflow', async () => {
|
|
275
|
+
// [x] executeWorkflow() verified to exist
|
|
276
|
+
await caller.workflowEngine.executeWorkflow({
|
|
277
|
+
workflowId: 'test-id'
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// [x] OR: Skip test until feature implemented
|
|
283
|
+
describe.skip('Workflow Templates (NOT IMPLEMENTED)', () => {
|
|
284
|
+
it('should clone template - PENDING IMPLEMENTATION', async () => {
|
|
285
|
+
// TODO: Implement cloneTemplate() method first
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### [X] Anti-Pattern 3: Wrong Input Schema
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// [X] WRONG: Passing data that doesn't match Zod schema
|
|
296
|
+
const result = await caller.workflowEngine.executeWorkflow({
|
|
297
|
+
name: 'Test', // [X] Not in schema
|
|
298
|
+
trigger_type: 'manual', // [X] Not in schema
|
|
299
|
+
workflow_definition: {} // [X] Not in schema
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Why Wrong**: Zod validation will fail at runtime with confusing error messages.
|
|
304
|
+
|
|
305
|
+
**Correct Approach**:
|
|
306
|
+
```typescript
|
|
307
|
+
// [x] CORRECT: Match the actual input schema
|
|
308
|
+
const result = await caller.workflowEngine.executeWorkflow({
|
|
309
|
+
workflowId: 'uuid-here', // [x] Required field in schema
|
|
310
|
+
context: { // [x] Optional field in schema
|
|
311
|
+
userId: 'test',
|
|
312
|
+
trigger: 'manual'
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Troubleshooting
|
|
320
|
+
|
|
321
|
+
### Error: "No procedure found on path 'router,method'"
|
|
322
|
+
|
|
323
|
+
**Cause**: Test calls a router method that doesn't exist
|
|
324
|
+
|
|
325
|
+
**Solution**:
|
|
326
|
+
1. Run `npm run validate:router-contracts` to see all violations
|
|
327
|
+
2. Read the actual router file to see available methods
|
|
328
|
+
3. Update test to use correct method name
|
|
329
|
+
4. Re-run validation to confirm fix
|
|
330
|
+
|
|
331
|
+
### Error: Zod validation error with input schema
|
|
332
|
+
|
|
333
|
+
**Cause**: Test passes data that doesn't match the router's Zod input schema
|
|
334
|
+
|
|
335
|
+
**Solution**:
|
|
336
|
+
1. Open router file and find the method's `.input()` definition
|
|
337
|
+
2. Read the Zod schema to understand required/optional fields
|
|
338
|
+
3. Update test data to match schema exactly
|
|
339
|
+
4. Document input schema in test file header
|
|
340
|
+
|
|
341
|
+
### Error: Test files not running in CI/CD
|
|
342
|
+
|
|
343
|
+
**Cause**: Tests are uncommitted (untracked files)
|
|
344
|
+
|
|
345
|
+
**Solution**:
|
|
346
|
+
1. Check `git status` - are test files listed as "Untracked"?
|
|
347
|
+
2. Add files: `git add tests/integration/`
|
|
348
|
+
3. Commit: `git commit -m "test: add integration tests"`
|
|
349
|
+
4. Push: `git push`
|
|
350
|
+
5. Verify CI/CD runs: Check GitHub Actions
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Prevention System
|
|
355
|
+
|
|
356
|
+
### Layer 1: Local Pre-Commit Hook
|
|
357
|
+
|
|
358
|
+
Automatically blocks commits with router contract violations:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
# Triggered automatically on git commit
|
|
362
|
+
[6/6] Router Contract Validation...
|
|
363
|
+
[X] Router contract violations detected
|
|
364
|
+
Tests call router methods that don't exist
|
|
365
|
+
Run: npm run validate:router-contracts
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**How to Fix**: Run validation script, fix violations, then retry commit.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### Layer 2: GitHub Actions CI/CD
|
|
373
|
+
|
|
374
|
+
Fails CI if router contract violations detected:
|
|
375
|
+
|
|
376
|
+
```yaml
|
|
377
|
+
- name: Validate Router Contracts
|
|
378
|
+
run: npm run validate:router-contracts
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Impact**: Pull requests cannot be merged if tests call non-existent methods.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
### Layer 3: Documentation
|
|
386
|
+
|
|
387
|
+
This checklist enforces router verification as part of the test writing process.
|
|
388
|
+
|
|
389
|
+
**Required Reading**: Before writing integration tests, review this checklist.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Success Metrics
|
|
394
|
+
|
|
395
|
+
You're following the checklist correctly when:
|
|
396
|
+
|
|
397
|
+
- [x] Test file header lists all router methods being tested
|
|
398
|
+
- [x] `npm run validate:router-contracts` returns SUCCESS
|
|
399
|
+
- [x] Tests are committed immediately after writing
|
|
400
|
+
- [x] CI/CD passes without router contract violations
|
|
401
|
+
- [x] No "No procedure found" errors in test output
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Real-World Example
|
|
406
|
+
|
|
407
|
+
**Problem**: 17/18 tests failed with "No procedure found on path 'workflowEngine,create'". Tests called `create()` but router only had `executeWorkflow()`. Wasted 2+ hours debugging test failures. Root cause: Tests written without verifying router methods.
|
|
408
|
+
|
|
409
|
+
**Solution Applied**:
|
|
410
|
+
1. Created router contract validation script
|
|
411
|
+
2. Added pre-commit hooks to block violations
|
|
412
|
+
3. Added CI/CD validation step
|
|
413
|
+
4. Created this checklist
|
|
414
|
+
5. Documented required process
|
|
415
|
+
|
|
416
|
+
**Result**: API contract mismatches now caught in <2 seconds, not 2+ hours.
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Quick Reference
|
|
421
|
+
|
|
422
|
+
**Before writing tests**:
|
|
423
|
+
```bash
|
|
424
|
+
# 1. Read router file
|
|
425
|
+
cat src/server/api/routers/my-router.ts
|
|
426
|
+
|
|
427
|
+
# 2. List methods in test header (see template above)
|
|
428
|
+
|
|
429
|
+
# 3. Write tests using VERIFIED methods
|
|
430
|
+
|
|
431
|
+
# 4. Validate contracts
|
|
432
|
+
npm run validate:router-contracts
|
|
433
|
+
|
|
434
|
+
# 5. Commit immediately
|
|
435
|
+
git add tests/integration/
|
|
436
|
+
git commit -m "test: add integration tests"
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Prevention is imperative**: These steps prevent wasting time on tests that will always fail.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
**Document Status**: ACTIVE
|
|
444
|
+
**Enforcement**: Pre-commit hooks + GitHub Actions
|
|
445
|
+
**Compliance**: Mandatory for all integration tests
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Security Patterns
|
|
2
|
+
|
|
3
|
+
**Purpose**: Security patterns for credential management, authentication, and code safety.
|
|
4
|
+
|
|
5
|
+
**When to Read**: Before handling secrets, authentication, or security-sensitive code.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Credential Management (CR-5)
|
|
10
|
+
|
|
11
|
+
### The Rule
|
|
12
|
+
|
|
13
|
+
ALL secrets MUST use a credential provider (e.g., AWS Secrets Manager). Environment variables are acceptable ONLY as a development fallback.
|
|
14
|
+
|
|
15
|
+
### Credential Access Pattern
|
|
16
|
+
|
|
17
|
+
**WRONG (env-first anti-pattern):**
|
|
18
|
+
```typescript
|
|
19
|
+
const apiKey = process.env.SERVICE_API_KEY;
|
|
20
|
+
if (!apiKey) throw new Error('Missing API key');
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**CORRECT (credential-provider-first):**
|
|
24
|
+
```typescript
|
|
25
|
+
import { getServiceCredentials } from '@/lib/credentials/provider';
|
|
26
|
+
|
|
27
|
+
let apiKey: string | undefined;
|
|
28
|
+
// CR-5: Credential provider first
|
|
29
|
+
try {
|
|
30
|
+
const creds = await getServiceCredentials();
|
|
31
|
+
if (creds.apiKey) apiKey = creds.apiKey;
|
|
32
|
+
} catch {
|
|
33
|
+
log.debug('[Service] Credential provider unavailable, falling back to env var');
|
|
34
|
+
}
|
|
35
|
+
// Dev-only fallback
|
|
36
|
+
if (!apiKey) apiKey = process.env.SERVICE_API_KEY;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Path Convention
|
|
40
|
+
|
|
41
|
+
Store secrets with a structured path convention:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
{project}/api-credentials/{environment}/{service-name}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Example paths:
|
|
48
|
+
- `my-app/api-credentials/production/stripe`
|
|
49
|
+
- `my-app/api-credentials/development/anthropic`
|
|
50
|
+
- `my-app/api-credentials/production/sendgrid`
|
|
51
|
+
|
|
52
|
+
### Credential Loader Template
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// src/lib/credentials/{service}-credentials.ts
|
|
56
|
+
import { getCredentials } from '@/lib/credentials/provider';
|
|
57
|
+
|
|
58
|
+
interface ServiceCredentials {
|
|
59
|
+
apiKey: string;
|
|
60
|
+
apiSecret?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let cachedCredentials: ServiceCredentials | null = null;
|
|
64
|
+
let loadPromise: Promise<ServiceCredentials> | null = null;
|
|
65
|
+
|
|
66
|
+
export async function getServiceCredentials(): Promise<ServiceCredentials> {
|
|
67
|
+
if (cachedCredentials) return cachedCredentials;
|
|
68
|
+
if (loadPromise) return loadPromise;
|
|
69
|
+
|
|
70
|
+
loadPromise = (async () => {
|
|
71
|
+
const raw = await getCredentials('my-app/api-credentials/production/service-name');
|
|
72
|
+
cachedCredentials = {
|
|
73
|
+
apiKey: raw.api_key,
|
|
74
|
+
apiSecret: raw.api_secret,
|
|
75
|
+
};
|
|
76
|
+
return cachedCredentials;
|
|
77
|
+
})();
|
|
78
|
+
|
|
79
|
+
return loadPromise;
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Key patterns:**
|
|
84
|
+
- Lazy initialization (load on first use)
|
|
85
|
+
- Promise deduplication (prevent parallel loads)
|
|
86
|
+
- Typed return values (no raw strings)
|
|
87
|
+
|
|
88
|
+
### Service Templates
|
|
89
|
+
|
|
90
|
+
| Service | Credential Fields | Environment Variable Fallback |
|
|
91
|
+
|---------|------------------|------------------------------|
|
|
92
|
+
| Stripe | `secret_key`, `publishable_key`, `webhook_secret` | `STRIPE_SECRET_KEY` |
|
|
93
|
+
| Twilio | `account_sid`, `auth_token` | `TWILIO_AUTH_TOKEN` |
|
|
94
|
+
| SendGrid | `api_key` | `SENDGRID_API_KEY` |
|
|
95
|
+
| Anthropic | `api_key` | `ANTHROPIC_API_KEY` |
|
|
96
|
+
| OpenAI | `api_key` | `OPENAI_API_KEY` |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Authentication Patterns
|
|
101
|
+
|
|
102
|
+
### Protected Procedures
|
|
103
|
+
|
|
104
|
+
ALL mutations MUST use `protectedProcedure`:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// CORRECT
|
|
108
|
+
export const myRouter = createTRPCRouter({
|
|
109
|
+
create: protectedProcedure
|
|
110
|
+
.input(z.object({ name: z.string() }))
|
|
111
|
+
.mutation(async ({ ctx, input }) => {
|
|
112
|
+
// ctx.user is guaranteed to exist
|
|
113
|
+
return ctx.db.items.create({ data: input });
|
|
114
|
+
}),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// WRONG - Security vulnerability
|
|
118
|
+
export const myRouter = createTRPCRouter({
|
|
119
|
+
create: publicProcedure // NEVER use publicProcedure for mutations
|
|
120
|
+
.mutation(async ({ input }) => { ... }),
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Input Validation
|
|
125
|
+
|
|
126
|
+
ALL inputs MUST be validated with Zod:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { z } from 'zod';
|
|
130
|
+
|
|
131
|
+
// Define strict schemas
|
|
132
|
+
const createItemSchema = z.object({
|
|
133
|
+
name: z.string().min(1).max(255),
|
|
134
|
+
email: z.string().email(),
|
|
135
|
+
amount: z.number().positive().max(1000000),
|
|
136
|
+
status: z.enum(['draft', 'active', 'archived']),
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Code Safety Patterns
|
|
143
|
+
|
|
144
|
+
### SuperJSON Key Safety
|
|
145
|
+
|
|
146
|
+
NEVER use these as object keys — causes prototype pollution:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// WRONG - Prototype pollution vulnerability
|
|
150
|
+
const data = {
|
|
151
|
+
prototype: { ... }, // DANGEROUS
|
|
152
|
+
__proto__: { ... }, // DANGEROUS
|
|
153
|
+
constructor: { ... }, // DANGEROUS
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// CORRECT - Use safe key names
|
|
157
|
+
const data = {
|
|
158
|
+
prototypeData: { ... },
|
|
159
|
+
config: { ... },
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Service Worker Safety
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// WRONG - Causes infinite refresh loop
|
|
167
|
+
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
168
|
+
window.location.reload();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// CORRECT - Only reload once
|
|
172
|
+
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
173
|
+
window.location.reload();
|
|
174
|
+
}, { once: true });
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Pre-Commit Security Checks
|
|
180
|
+
|
|
181
|
+
Before committing, verify no secrets are staged:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Check for env files
|
|
185
|
+
git diff --cached --name-only | grep -E '\.(env|pem|key|secret)'
|
|
186
|
+
# Expected: 0 matches
|
|
187
|
+
|
|
188
|
+
# Check for API key patterns
|
|
189
|
+
git diff --cached | grep -E 'sk-[a-zA-Z0-9]{20,}|api_key.*=.*[a-zA-Z0-9]{20,}'
|
|
190
|
+
# Expected: 0 matches
|
|
191
|
+
|
|
192
|
+
# Check for common secret patterns
|
|
193
|
+
git diff --cached | grep -iE 'password\s*=\s*["\x27][^"\x27]+["\x27]|secret\s*=\s*["\x27][^"\x27]+["\x27]'
|
|
194
|
+
# Expected: 0 matches
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Security Verification Commands
|
|
200
|
+
|
|
201
|
+
| Check | Command | Expected |
|
|
202
|
+
|-------|---------|----------|
|
|
203
|
+
| No secrets staged | `git diff --cached \| grep -E 'sk-\|api_key'` | 0 matches |
|
|
204
|
+
| Protected procedures | `grep -rn "publicProcedure.mutation" src/` | 0 matches |
|
|
205
|
+
| Zod validation | `grep -rn "\.input(z\." src/server/api/routers/` | Match on all mutations |
|
|
206
|
+
| No prototype keys | `grep -rn "prototype:" src/ \| grep -v test` | 0 matches |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Related Documentation
|
|
211
|
+
|
|
212
|
+
- **Build Patterns**: `patterns/build-patterns.md` (Edge Runtime restrictions)
|
|
213
|
+
- **Testing Patterns**: `patterns/testing-patterns.md` (security testing)
|
|
214
|
+
- **Standards**: `reference/standards.md` (security standards)
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
**Document Status**: ACTIVE
|
|
219
|
+
**Compliance**: Mandatory — all credential access must follow provider-first pattern
|