antigravity-devkit 1.0.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/LICENSE +21 -0
- package/README.md +421 -0
- package/bin/cli.js +179 -0
- package/package.json +38 -0
- package/template/ARCHITECTURE.md +148 -0
- package/template/README.md +421 -0
- package/template/agents/backend-specialist.md +137 -0
- package/template/agents/database-architect.md +114 -0
- package/template/agents/debugger.md +108 -0
- package/template/agents/devops-engineer.md +125 -0
- package/template/agents/documentation-writer.md +109 -0
- package/template/agents/explorer-agent.md +107 -0
- package/template/agents/frontend-specialist.md +231 -0
- package/template/agents/orchestrator.md +100 -0
- package/template/agents/performance-optimizer.md +109 -0
- package/template/agents/project-planner.md +123 -0
- package/template/agents/security-auditor.md +107 -0
- package/template/agents/test-engineer.md +133 -0
- package/template/rules/GEMINI.md +180 -0
- package/template/scripts/checklist.py +170 -0
- package/template/scripts/verify_all.py +243 -0
- package/template/skills/api-patterns/SKILL.md +116 -0
- package/template/skills/architecture/SKILL.md +98 -0
- package/template/skills/aspnet-patterns/SKILL.md +120 -0
- package/template/skills/azure-aks/SKILL.md +136 -0
- package/template/skills/azure-devops/SKILL.md +123 -0
- package/template/skills/azure-keyvault/SKILL.md +100 -0
- package/template/skills/brainstorming/SKILL.md +96 -0
- package/template/skills/clean-code/SKILL.md +84 -0
- package/template/skills/csharp-patterns/SKILL.md +115 -0
- package/template/skills/documentation-templates/SKILL.md +127 -0
- package/template/skills/english-education/SKILL.md +116 -0
- package/template/skills/english-education/references/lesson-templates.md +151 -0
- package/template/skills/english-education/references/quiz-templates.md +177 -0
- package/template/skills/english-education/scripts/curriculum_validator.py +175 -0
- package/template/skills/frontend-design/SKILL.md +199 -0
- package/template/skills/frontend-design/animation-guide.md +217 -0
- package/template/skills/frontend-design/design-systems.md +230 -0
- package/template/skills/frontend-design/ux-psychology.md +128 -0
- package/template/skills/gitops-patterns/SKILL.md +105 -0
- package/template/skills/grafana-logging/SKILL.md +107 -0
- package/template/skills/intelligent-routing/SKILL.md +75 -0
- package/template/skills/plan-writing/SKILL.md +96 -0
- package/template/skills/sqlserver-design/SKILL.md +97 -0
- package/template/skills/systematic-debugging/SKILL.md +98 -0
- package/template/skills/testing-patterns/SKILL.md +102 -0
- package/template/skills/vitest-testing/SKILL.md +116 -0
- package/template/skills/vue3-patterns/SKILL.md +195 -0
- package/template/skills/vulnerability-scanner/SKILL.md +104 -0
- package/template/skills/xunit-testing/SKILL.md +127 -0
- package/template/workflows/brainstorm.md +69 -0
- package/template/workflows/code.md +82 -0
- package/template/workflows/create.md +79 -0
- package/template/workflows/debug.md +83 -0
- package/template/workflows/deploy.md +101 -0
- package/template/workflows/orchestrate.md +86 -0
- package/template/workflows/plan.md +79 -0
- package/template/workflows/review.md +85 -0
- package/template/workflows/status.md +90 -0
- package/template/workflows/test.md +89 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-patterns
|
|
3
|
+
description: Test strategies and patterns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing Patterns
|
|
7
|
+
|
|
8
|
+
> Test strategies for full-stack applications.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Test Pyramid
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/\
|
|
16
|
+
/E2E\ Few, slow, critical paths
|
|
17
|
+
/------\
|
|
18
|
+
/ Integ- \ Some, key integrations
|
|
19
|
+
/--ration--\
|
|
20
|
+
/ Unit \ Many, fast, isolated
|
|
21
|
+
/--------------\
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Type | Speed | Scope |
|
|
25
|
+
|------|-------|-------|
|
|
26
|
+
| Unit | Fast | Single function/class |
|
|
27
|
+
| Integration | Medium | Multiple components |
|
|
28
|
+
| E2E | Slow | Full user flow |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## AAA Pattern
|
|
33
|
+
|
|
34
|
+
```csharp
|
|
35
|
+
[Fact]
|
|
36
|
+
public void Method_Scenario_Expected()
|
|
37
|
+
{
|
|
38
|
+
// Arrange - Set up test data
|
|
39
|
+
var input = CreateInput();
|
|
40
|
+
|
|
41
|
+
// Act - Execute the code
|
|
42
|
+
var result = Process(input);
|
|
43
|
+
|
|
44
|
+
// Assert - Verify outcome
|
|
45
|
+
Assert.Equal(expected, result);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Test Naming
|
|
52
|
+
|
|
53
|
+
Format: `Method_Scenario_ExpectedResult`
|
|
54
|
+
|
|
55
|
+
| ❌ Bad | ✅ Good |
|
|
56
|
+
|--------|---------|
|
|
57
|
+
| TestAdd | Add_TwoPositive_ReturnsSum |
|
|
58
|
+
| Test1 | GetUser_InvalidId_ThrowsException |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## What to Test
|
|
63
|
+
|
|
64
|
+
| ✅ Test | ❌ Skip |
|
|
65
|
+
|---------|---------|
|
|
66
|
+
| Business logic | Framework code |
|
|
67
|
+
| Edge cases | Getters/setters |
|
|
68
|
+
| Error handling | Third-party libs |
|
|
69
|
+
| Public API | Implementation details |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Mocking Guidelines
|
|
74
|
+
|
|
75
|
+
| Mock | Don't Mock |
|
|
76
|
+
|------|------------|
|
|
77
|
+
| External APIs | The code under test |
|
|
78
|
+
| Database | Simple objects |
|
|
79
|
+
| File system | Pure functions |
|
|
80
|
+
| Time/Random | Business logic |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Code Coverage
|
|
85
|
+
|
|
86
|
+
| Metric | Target |
|
|
87
|
+
|--------|--------|
|
|
88
|
+
| Overall | 70-80% |
|
|
89
|
+
| Business logic | 90%+ |
|
|
90
|
+
| Controllers | 60%+ |
|
|
91
|
+
| Infrastructure | Lower priority |
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## DO / DON'T
|
|
96
|
+
|
|
97
|
+
| ✅ Do | ❌ Don't |
|
|
98
|
+
|-------|---------|
|
|
99
|
+
| One concept per test | Test multiple things |
|
|
100
|
+
| Descriptive names | Cryptic test names |
|
|
101
|
+
| Independent tests | Tests that depend on order |
|
|
102
|
+
| Test edge cases | Only happy path |
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vitest-testing
|
|
3
|
+
description: Vitest testing for Vue3 applications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Vitest Testing
|
|
7
|
+
|
|
8
|
+
> Unit and component testing for Vue3.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Basic Test
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { describe, it, expect } from 'vitest'
|
|
16
|
+
|
|
17
|
+
describe('Calculator', () => {
|
|
18
|
+
it('adds two numbers', () => {
|
|
19
|
+
expect(2 + 3).toBe(5)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Component Test
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { mount } from '@vue/test-utils'
|
|
30
|
+
import { describe, it, expect } from 'vitest'
|
|
31
|
+
import MyButton from './MyButton.vue'
|
|
32
|
+
|
|
33
|
+
describe('MyButton', () => {
|
|
34
|
+
it('renders label', () => {
|
|
35
|
+
const wrapper = mount(MyButton, {
|
|
36
|
+
props: { label: 'Click me' }
|
|
37
|
+
})
|
|
38
|
+
expect(wrapper.text()).toContain('Click me')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('emits click event', async () => {
|
|
42
|
+
const wrapper = mount(MyButton)
|
|
43
|
+
await wrapper.find('button').trigger('click')
|
|
44
|
+
expect(wrapper.emitted('click')).toBeTruthy()
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Testing Composables
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { describe, it, expect } from 'vitest'
|
|
55
|
+
import { useCounter } from './useCounter'
|
|
56
|
+
|
|
57
|
+
describe('useCounter', () => {
|
|
58
|
+
it('increments count', () => {
|
|
59
|
+
const { count, increment } = useCounter()
|
|
60
|
+
|
|
61
|
+
expect(count.value).toBe(0)
|
|
62
|
+
increment()
|
|
63
|
+
expect(count.value).toBe(1)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Mocking
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { vi, describe, it, expect } from 'vitest'
|
|
74
|
+
import { fetchUsers } from './api'
|
|
75
|
+
|
|
76
|
+
vi.mock('./api', () => ({
|
|
77
|
+
fetchUsers: vi.fn().mockResolvedValue([{ id: 1 }])
|
|
78
|
+
}))
|
|
79
|
+
|
|
80
|
+
describe('UserList', () => {
|
|
81
|
+
it('fetches users', async () => {
|
|
82
|
+
const users = await fetchUsers()
|
|
83
|
+
expect(users).toHaveLength(1)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Pinia Store Testing
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { setActivePinia, createPinia } from 'pinia'
|
|
94
|
+
import { useUserStore } from './userStore'
|
|
95
|
+
|
|
96
|
+
describe('User Store', () => {
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
setActivePinia(createPinia())
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('has initial state', () => {
|
|
102
|
+
const store = useUserStore()
|
|
103
|
+
expect(store.user).toBeNull()
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Run Tests
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm run test
|
|
114
|
+
npm run test -- --watch
|
|
115
|
+
npm run test -- --coverage
|
|
116
|
+
```
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vue3-patterns
|
|
3
|
+
description: Vue3 Composition API, Pinia, Vue Router, and Tailwind CSS patterns
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Vue3 Patterns
|
|
7
|
+
|
|
8
|
+
> Modern Vue3 with Composition API, TypeScript, Pinia, and **Tailwind CSS**.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Component Structure
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
// 1. Imports
|
|
17
|
+
import { ref, computed, onMounted } from 'vue'
|
|
18
|
+
|
|
19
|
+
// 2. Props & Emits
|
|
20
|
+
const props = defineProps<{ title: string }>()
|
|
21
|
+
const emit = defineEmits<{ (e: 'update', value: string): void }>()
|
|
22
|
+
|
|
23
|
+
// 3. Reactive State
|
|
24
|
+
const count = ref(0)
|
|
25
|
+
|
|
26
|
+
// 4. Computed
|
|
27
|
+
const doubled = computed(() => count.value * 2)
|
|
28
|
+
|
|
29
|
+
// 5. Methods
|
|
30
|
+
const increment = () => count.value++
|
|
31
|
+
|
|
32
|
+
// 6. Lifecycle
|
|
33
|
+
onMounted(() => console.log('Mounted'))
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<div class="p-4 rounded-lg bg-white shadow-md">
|
|
38
|
+
<h2 class="text-xl font-semibold">{{ title }}</h2>
|
|
39
|
+
<p class="mt-2 text-gray-600">Count: {{ count }}</p>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Tailwind CSS with Vue3
|
|
47
|
+
|
|
48
|
+
### Styling Approach
|
|
49
|
+
|
|
50
|
+
| Approach | When to Use |
|
|
51
|
+
|----------|-------------|
|
|
52
|
+
| **Utility classes** | Default - inline in template |
|
|
53
|
+
| **@apply in scoped** | Complex repeated patterns |
|
|
54
|
+
| **CSS variables** | Dynamic theming |
|
|
55
|
+
|
|
56
|
+
### Button with Tailwind
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<template>
|
|
60
|
+
<button class="
|
|
61
|
+
px-4 py-2 font-medium rounded-lg
|
|
62
|
+
bg-primary text-white
|
|
63
|
+
transition-all duration-200 ease-out
|
|
64
|
+
hover:-translate-y-0.5 hover:shadow-lg
|
|
65
|
+
active:scale-95
|
|
66
|
+
focus:outline-none focus:ring-2 focus:ring-primary/50
|
|
67
|
+
disabled:opacity-50 disabled:cursor-not-allowed
|
|
68
|
+
">
|
|
69
|
+
<slot />
|
|
70
|
+
</button>
|
|
71
|
+
</template>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Dynamic Classes
|
|
75
|
+
|
|
76
|
+
```vue
|
|
77
|
+
<template>
|
|
78
|
+
<div :class="[
|
|
79
|
+
'p-4 rounded-lg transition-colors',
|
|
80
|
+
isActive ? 'bg-primary text-white' : 'bg-gray-100',
|
|
81
|
+
{ 'opacity-50': disabled }
|
|
82
|
+
]">
|
|
83
|
+
Content
|
|
84
|
+
</div>
|
|
85
|
+
</template>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Vue Transitions with Tailwind
|
|
91
|
+
|
|
92
|
+
```vue
|
|
93
|
+
<template>
|
|
94
|
+
<Transition
|
|
95
|
+
enter-active-class="transition-all duration-300 ease-out"
|
|
96
|
+
enter-from-class="opacity-0 translate-y-4"
|
|
97
|
+
enter-to-class="opacity-100 translate-y-0"
|
|
98
|
+
leave-active-class="transition-all duration-200 ease-in"
|
|
99
|
+
leave-from-class="opacity-100"
|
|
100
|
+
leave-to-class="opacity-0 translate-y-4"
|
|
101
|
+
>
|
|
102
|
+
<div v-if="show" class="p-4 bg-white rounded-lg shadow">
|
|
103
|
+
Animated content
|
|
104
|
+
</div>
|
|
105
|
+
</Transition>
|
|
106
|
+
</template>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## State Management
|
|
112
|
+
|
|
113
|
+
| Scope | Solution |
|
|
114
|
+
|-------|----------|
|
|
115
|
+
| Component | `ref()`, `reactive()` |
|
|
116
|
+
| Parent-child | Props + Emits |
|
|
117
|
+
| Global | Pinia store |
|
|
118
|
+
|
|
119
|
+
### Pinia Store
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
export const useUserStore = defineStore('user', () => {
|
|
123
|
+
const user = ref<User | null>(null)
|
|
124
|
+
const isLoggedIn = computed(() => !!user.value)
|
|
125
|
+
|
|
126
|
+
async function login(credentials: Credentials) {
|
|
127
|
+
user.value = await api.login(credentials)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { user, isLoggedIn, login }
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Composables
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// composables/useCounter.ts
|
|
140
|
+
export function useCounter(initial = 0) {
|
|
141
|
+
const count = ref(initial)
|
|
142
|
+
const increment = () => count.value++
|
|
143
|
+
const decrement = () => count.value--
|
|
144
|
+
return { count, increment, decrement }
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Tailwind Config
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// tailwind.config.js
|
|
154
|
+
module.exports = {
|
|
155
|
+
content: [
|
|
156
|
+
'./index.html',
|
|
157
|
+
'./src/**/*.{vue,js,ts,jsx,tsx}',
|
|
158
|
+
],
|
|
159
|
+
theme: {
|
|
160
|
+
extend: {
|
|
161
|
+
colors: {
|
|
162
|
+
primary: '#0d9488',
|
|
163
|
+
accent: '#f59e0b',
|
|
164
|
+
},
|
|
165
|
+
fontFamily: {
|
|
166
|
+
sans: ['DM Sans', 'sans-serif'],
|
|
167
|
+
display: ['Space Grotesk', 'sans-serif'],
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## TypeScript
|
|
177
|
+
|
|
178
|
+
| Pattern | Example |
|
|
179
|
+
|---------|---------|
|
|
180
|
+
| Props | `defineProps<{ id: number }>()` |
|
|
181
|
+
| Emits | `defineEmits<{ (e: 'click'): void }>()` |
|
|
182
|
+
| Ref typing | `const user = ref<User \| null>(null)` |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## DO / DON'T
|
|
187
|
+
|
|
188
|
+
| Do | Don't |
|
|
189
|
+
|-------|---------|
|
|
190
|
+
| Composition API | Options API |
|
|
191
|
+
| TypeScript strict | `any` type |
|
|
192
|
+
| Pinia for global state | Vuex |
|
|
193
|
+
| Tailwind utilities | Inline styles |
|
|
194
|
+
| Custom Tailwind config | Default colors only |
|
|
195
|
+
| Small components | Giant components |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vulnerability-scanner
|
|
3
|
+
description: Security vulnerability scanning and OWASP guidelines
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Vulnerability Scanner
|
|
7
|
+
|
|
8
|
+
> Identify and fix security vulnerabilities.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## OWASP Top 10
|
|
13
|
+
|
|
14
|
+
| Risk | Prevention |
|
|
15
|
+
|------|------------|
|
|
16
|
+
| Injection | Parameterized queries |
|
|
17
|
+
| Broken Auth | Secure session management |
|
|
18
|
+
| Sensitive Data | Encryption, HTTPS |
|
|
19
|
+
| XXE | Disable external entities |
|
|
20
|
+
| Broken Access | RBAC, validate permissions |
|
|
21
|
+
| Security Misconfig | Security headers |
|
|
22
|
+
| XSS | Output encoding |
|
|
23
|
+
| Insecure Deserialization | Input validation |
|
|
24
|
+
| Vulnerable Components | Update dependencies |
|
|
25
|
+
| Insufficient Logging | Audit logs |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Security Checklist
|
|
30
|
+
|
|
31
|
+
### Authentication
|
|
32
|
+
- [ ] Passwords hashed (bcrypt/argon2)
|
|
33
|
+
- [ ] Session tokens secure
|
|
34
|
+
- [ ] Token expiration set
|
|
35
|
+
- [ ] Brute force protection
|
|
36
|
+
|
|
37
|
+
### Authorization
|
|
38
|
+
- [ ] RBAC implemented
|
|
39
|
+
- [ ] Resource-level checks
|
|
40
|
+
- [ ] API endpoints protected
|
|
41
|
+
|
|
42
|
+
### Data
|
|
43
|
+
- [ ] HTTPS enforced
|
|
44
|
+
- [ ] Sensitive data encrypted
|
|
45
|
+
- [ ] No secrets in code
|
|
46
|
+
- [ ] Input validated
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Code Patterns to Avoid
|
|
51
|
+
|
|
52
|
+
```csharp
|
|
53
|
+
// ❌ SQL Injection
|
|
54
|
+
$"SELECT * FROM Users WHERE Email = '{email}'"
|
|
55
|
+
|
|
56
|
+
// ✅ Parameterized
|
|
57
|
+
"SELECT * FROM Users WHERE Email = @Email"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```csharp
|
|
61
|
+
// ❌ Hardcoded secret
|
|
62
|
+
var secret = "my-secret-key";
|
|
63
|
+
|
|
64
|
+
// ✅ KeyVault
|
|
65
|
+
var secret = Configuration["SecretKey"];
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Security Headers
|
|
71
|
+
|
|
72
|
+
```csharp
|
|
73
|
+
// Add security headers
|
|
74
|
+
app.Use(async (context, next) =>
|
|
75
|
+
{
|
|
76
|
+
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
|
|
77
|
+
context.Response.Headers.Add("X-Frame-Options", "DENY");
|
|
78
|
+
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
|
|
79
|
+
await next();
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Dependency Scanning
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# .NET
|
|
89
|
+
dotnet list package --vulnerable
|
|
90
|
+
|
|
91
|
+
# npm
|
|
92
|
+
npm audit
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## DO / DON'T
|
|
98
|
+
|
|
99
|
+
| ✅ Do | ❌ Don't |
|
|
100
|
+
|-------|---------|
|
|
101
|
+
| Validate all input | Trust user data |
|
|
102
|
+
| Use KeyVault | Hardcode secrets |
|
|
103
|
+
| Hash passwords | Store plain text |
|
|
104
|
+
| Update dependencies | Ignore vulnerabilities |
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: xunit-testing
|
|
3
|
+
description: xUnit testing for .NET applications
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# xUnit Testing
|
|
7
|
+
|
|
8
|
+
> Unit and integration testing for C#/.NET.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Basic Test
|
|
13
|
+
|
|
14
|
+
```csharp
|
|
15
|
+
public class CalculatorTests
|
|
16
|
+
{
|
|
17
|
+
[Fact]
|
|
18
|
+
public void Add_TwoNumbers_ReturnsSum()
|
|
19
|
+
{
|
|
20
|
+
// Arrange
|
|
21
|
+
var calculator = new Calculator();
|
|
22
|
+
|
|
23
|
+
// Act
|
|
24
|
+
var result = calculator.Add(2, 3);
|
|
25
|
+
|
|
26
|
+
// Assert
|
|
27
|
+
Assert.Equal(5, result);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Theory with Data
|
|
35
|
+
|
|
36
|
+
```csharp
|
|
37
|
+
[Theory]
|
|
38
|
+
[InlineData(2, 3, 5)]
|
|
39
|
+
[InlineData(-1, 1, 0)]
|
|
40
|
+
[InlineData(0, 0, 0)]
|
|
41
|
+
public void Add_VariousInputs_ReturnsExpected(int a, int b, int expected)
|
|
42
|
+
{
|
|
43
|
+
var result = new Calculator().Add(a, b);
|
|
44
|
+
Assert.Equal(expected, result);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Async Tests
|
|
51
|
+
|
|
52
|
+
```csharp
|
|
53
|
+
[Fact]
|
|
54
|
+
public async Task GetUser_ValidId_ReturnsUser()
|
|
55
|
+
{
|
|
56
|
+
// Arrange
|
|
57
|
+
var service = CreateService();
|
|
58
|
+
|
|
59
|
+
// Act
|
|
60
|
+
var result = await service.GetByIdAsync(1);
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
Assert.NotNull(result);
|
|
64
|
+
Assert.Equal(1, result.Id);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Mocking with Moq
|
|
71
|
+
|
|
72
|
+
```csharp
|
|
73
|
+
[Fact]
|
|
74
|
+
public async Task GetUser_CallsRepository()
|
|
75
|
+
{
|
|
76
|
+
// Arrange
|
|
77
|
+
var mockRepo = new Mock<IUserRepository>();
|
|
78
|
+
mockRepo.Setup(r => r.GetByIdAsync(1))
|
|
79
|
+
.ReturnsAsync(new User { Id = 1 });
|
|
80
|
+
|
|
81
|
+
var service = new UserService(mockRepo.Object);
|
|
82
|
+
|
|
83
|
+
// Act
|
|
84
|
+
var result = await service.GetByIdAsync(1);
|
|
85
|
+
|
|
86
|
+
// Assert
|
|
87
|
+
mockRepo.Verify(r => r.GetByIdAsync(1), Times.Once);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Test Fixtures
|
|
94
|
+
|
|
95
|
+
```csharp
|
|
96
|
+
public class DatabaseFixture : IDisposable
|
|
97
|
+
{
|
|
98
|
+
public DbContext Context { get; }
|
|
99
|
+
|
|
100
|
+
public DatabaseFixture()
|
|
101
|
+
{
|
|
102
|
+
Context = CreateTestContext();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public void Dispose() => Context.Dispose();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public class UserTests : IClassFixture<DatabaseFixture>
|
|
109
|
+
{
|
|
110
|
+
private readonly DatabaseFixture _fixture;
|
|
111
|
+
|
|
112
|
+
public UserTests(DatabaseFixture fixture)
|
|
113
|
+
{
|
|
114
|
+
_fixture = fixture;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Run Tests
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
dotnet test
|
|
125
|
+
dotnet test --filter "FullyQualifiedName~UserTests"
|
|
126
|
+
dotnet test --collect:"XPlat Code Coverage"
|
|
127
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Socratic discovery for requirements clarification
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /brainstorm - Discovery Mode
|
|
6
|
+
|
|
7
|
+
$ARGUMENTS
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
|
|
13
|
+
Clarify requirements through Socratic questioning before implementation.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Protocol
|
|
18
|
+
|
|
19
|
+
### 1. Analyze Request
|
|
20
|
+
- What domain is this? (Frontend, Backend, Database, etc.)
|
|
21
|
+
- What's unclear or ambiguous?
|
|
22
|
+
|
|
23
|
+
### 2. Generate Questions (Minimum 3)
|
|
24
|
+
|
|
25
|
+
```markdown
|
|
26
|
+
🤔 **Before we proceed, let me understand better:**
|
|
27
|
+
|
|
28
|
+
1. [Scope question]
|
|
29
|
+
2. [User/audience question]
|
|
30
|
+
3. [Technical constraint question]
|
|
31
|
+
|
|
32
|
+
Please answer these so I can create the best solution.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 3. Wait for Answers
|
|
36
|
+
|
|
37
|
+
**DO NOT proceed until user responds.**
|
|
38
|
+
|
|
39
|
+
### 4. Summarize Understanding
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
✅ **Understood:**
|
|
43
|
+
- Goal: [summary]
|
|
44
|
+
- Users: [who]
|
|
45
|
+
- Scope: [what's included]
|
|
46
|
+
- Constraints: [limitations]
|
|
47
|
+
|
|
48
|
+
Ready to proceed with `/plan`?
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Question Categories
|
|
54
|
+
|
|
55
|
+
| Category | Example |
|
|
56
|
+
|----------|---------|
|
|
57
|
+
| Scope | What exactly needs to be built? |
|
|
58
|
+
| Users | Who will use this feature? |
|
|
59
|
+
| Data | What data flows in/out? |
|
|
60
|
+
| Integration | What existing systems are involved? |
|
|
61
|
+
| Priority | What's most important? |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## After Brainstorm
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Next: /plan [feature description]
|
|
69
|
+
```
|