@musashishao/agent-kit 1.8.1 → 1.9.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/.agent/agents/ai-architect.md +39 -0
- package/.agent/agents/cloud-engineer.md +39 -0
- package/.agent/agents/game-asset-curator.md +317 -0
- package/.agent/agents/game-developer.md +190 -89
- package/.agent/agents/game-narrative-designer.md +310 -0
- package/.agent/agents/game-qa-agent.md +441 -0
- package/.agent/agents/marketing-specialist.md +41 -0
- package/.agent/agents/penetration-tester.md +15 -1
- package/.agent/rules/CODEX.md +26 -2
- package/.agent/rules/GEMINI.md +7 -5
- package/.agent/rules/REFERENCE.md +92 -2
- package/.agent/scripts/ak_cli.py +1 -1
- package/.agent/scripts/localize_workflows.py +54 -0
- package/.agent/scripts/memory_manager.py +24 -1
- package/.agent/skills/3d-web-experience/SKILL.md +386 -0
- package/.agent/skills/DEPENDENCIES.md +54 -0
- package/.agent/skills/ab-test-setup/SKILL.md +77 -0
- package/.agent/skills/active-directory-attacks/SKILL.md +59 -0
- package/.agent/skills/agent-evaluation/SKILL.md +430 -0
- package/.agent/skills/agent-memory-systems/SKILL.md +426 -0
- package/.agent/skills/agent-tool-builder/SKILL.md +139 -0
- package/.agent/skills/ai-agents-architect/SKILL.md +115 -0
- package/.agent/skills/ai-product/SKILL.md +86 -0
- package/.agent/skills/ai-wrapper-product/SKILL.md +90 -0
- package/.agent/skills/analytics-tracking/SKILL.md +88 -0
- package/.agent/skills/api-fuzzing-bug-bounty/SKILL.md +66 -0
- package/.agent/skills/app-store-optimization/SKILL.md +66 -0
- package/.agent/skills/autonomous-agent-patterns/SKILL.md +414 -0
- package/.agent/skills/aws-penetration-testing/SKILL.md +50 -0
- package/.agent/skills/aws-serverless/SKILL.md +327 -0
- package/.agent/skills/azure-functions/SKILL.md +340 -0
- package/.agent/skills/broken-authentication/SKILL.md +53 -0
- package/.agent/skills/browser-automation/SKILL.md +408 -0
- package/.agent/skills/browser-extension-builder/SKILL.md +422 -0
- package/.agent/skills/bullmq-specialist/SKILL.md +424 -0
- package/.agent/skills/bun-development/SKILL.md +386 -0
- package/.agent/skills/burp-suite-testing/SKILL.md +60 -0
- package/.agent/skills/clerk-auth/SKILL.md +432 -0
- package/.agent/skills/cloud-penetration-testing/SKILL.md +51 -0
- package/.agent/skills/copywriting/SKILL.md +66 -0
- package/.agent/skills/crewai/SKILL.md +470 -0
- package/.agent/skills/discord-bot-architect/SKILL.md +447 -0
- package/.agent/skills/email-sequence/SKILL.md +73 -0
- package/.agent/skills/ethical-hacking-methodology/SKILL.md +67 -0
- package/.agent/skills/firebase/SKILL.md +377 -0
- package/.agent/skills/game-development/godot-expert/SKILL.md +462 -0
- package/.agent/skills/game-development/npc-ai-integration/SKILL.md +110 -0
- package/.agent/skills/game-development/procedural-generation/SKILL.md +168 -0
- package/.agent/skills/game-development/unity-integration/SKILL.md +358 -0
- package/.agent/skills/game-development/webgpu-shading/SKILL.md +209 -0
- package/.agent/skills/gcp-cloud-run/SKILL.md +358 -0
- package/.agent/skills/graphql/SKILL.md +492 -0
- package/.agent/skills/idor-testing/SKILL.md +64 -0
- package/.agent/skills/inngest/SKILL.md +128 -0
- package/.agent/skills/langfuse/SKILL.md +415 -0
- package/.agent/skills/langgraph/SKILL.md +360 -0
- package/.agent/skills/launch-strategy/SKILL.md +68 -0
- package/.agent/skills/linux-privilege-escalation/SKILL.md +62 -0
- package/.agent/skills/llm-app-patterns/SKILL.md +367 -0
- package/.agent/skills/marketing-ideas/SKILL.md +66 -0
- package/.agent/skills/metasploit-framework/SKILL.md +60 -0
- package/.agent/skills/micro-saas-launcher/SKILL.md +93 -0
- package/.agent/skills/neon-postgres/SKILL.md +339 -0
- package/.agent/skills/paid-ads/SKILL.md +64 -0
- package/.agent/skills/supabase-integration/SKILL.md +411 -0
- package/.agent/workflows/ai-agent.md +36 -0
- package/.agent/workflows/autofix.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/context.md +1 -0
- package/.agent/workflows/create.md +1 -0
- package/.agent/workflows/dashboard.md +1 -0
- package/.agent/workflows/debug.md +1 -0
- package/.agent/workflows/deploy.md +1 -0
- package/.agent/workflows/enhance.md +1 -0
- package/.agent/workflows/game-prototype.md +154 -0
- package/.agent/workflows/marketing.md +37 -0
- package/.agent/workflows/next.md +1 -0
- package/.agent/workflows/orchestrate.md +1 -0
- package/.agent/workflows/pentest.md +37 -0
- package/.agent/workflows/plan.md +1 -0
- package/.agent/workflows/preview.md +2 -1
- package/.agent/workflows/quality.md +1 -0
- package/.agent/workflows/saas.md +36 -0
- package/.agent/workflows/spec.md +1 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/test.md +1 -0
- package/.agent/workflows/ui-ux-pro-max.md +1 -0
- package/README.md +52 -24
- package/bin/cli.js +68 -3
- package/docs/CHANGELOG_AI_INFRA.md +30 -0
- package/docs/MIGRATION_GUIDE_V1.9.md +55 -0
- package/package.json +1 -1
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: aws-serverless
|
|
3
|
+
description: "Production-ready serverless applications on AWS. Covers Lambda functions, API Gateway, DynamoDB, SQS/SNS event-driven patterns, SAM/CDK deployment, and cold start optimization."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
source: "antigravity-awesome-skills (adapted)"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# ☁️ AWS Serverless
|
|
9
|
+
|
|
10
|
+
You are an AWS serverless expert who has built production applications handling millions of requests. You understand Lambda's execution model, cold starts, and cost optimization strategies.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## When to Use This Skill
|
|
15
|
+
|
|
16
|
+
- Building serverless APIs with Lambda + API Gateway
|
|
17
|
+
- Event-driven architectures with SQS/SNS/EventBridge
|
|
18
|
+
- DynamoDB data modeling and access patterns
|
|
19
|
+
- SAM or CDK infrastructure as code
|
|
20
|
+
- Cold start optimization for latency-sensitive apps
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Capabilities
|
|
25
|
+
|
|
26
|
+
- `aws-lambda`
|
|
27
|
+
- `api-gateway`
|
|
28
|
+
- `dynamodb`
|
|
29
|
+
- `sqs-sns`
|
|
30
|
+
- `eventbridge`
|
|
31
|
+
- `sam-cdk`
|
|
32
|
+
- `step-functions`
|
|
33
|
+
- `s3-events`
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. Lambda Handler Patterns
|
|
38
|
+
|
|
39
|
+
### Node.js Handler
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
// handler.js
|
|
43
|
+
// Initialize OUTSIDE handler (reused across invocations)
|
|
44
|
+
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
|
|
45
|
+
const { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');
|
|
46
|
+
|
|
47
|
+
const client = new DynamoDBClient({});
|
|
48
|
+
const docClient = DynamoDBDocumentClient.from(client);
|
|
49
|
+
|
|
50
|
+
exports.handler = async (event, context) => {
|
|
51
|
+
// Don't wait for event loop to clear
|
|
52
|
+
context.callbackWaitsForEmptyEventLoop = false;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const body = typeof event.body === 'string'
|
|
56
|
+
? JSON.parse(event.body)
|
|
57
|
+
: event.body;
|
|
58
|
+
|
|
59
|
+
const result = await processRequest(body);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
statusCode: 200,
|
|
63
|
+
headers: {
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
'Access-Control-Allow-Origin': '*'
|
|
66
|
+
},
|
|
67
|
+
body: JSON.stringify(result)
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Error:', JSON.stringify({
|
|
71
|
+
error: error.message,
|
|
72
|
+
stack: error.stack,
|
|
73
|
+
requestId: context.awsRequestId
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
statusCode: error.statusCode || 500,
|
|
78
|
+
headers: { 'Content-Type': 'application/json' },
|
|
79
|
+
body: JSON.stringify({ error: error.message })
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Python Handler
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
# handler.py
|
|
89
|
+
import json
|
|
90
|
+
import os
|
|
91
|
+
import logging
|
|
92
|
+
import boto3
|
|
93
|
+
|
|
94
|
+
# Initialize OUTSIDE handler (reused across invocations)
|
|
95
|
+
logger = logging.getLogger()
|
|
96
|
+
logger.setLevel(logging.INFO)
|
|
97
|
+
|
|
98
|
+
dynamodb = boto3.resource('dynamodb')
|
|
99
|
+
table = dynamodb.Table(os.environ['TABLE_NAME'])
|
|
100
|
+
|
|
101
|
+
def handler(event, context):
|
|
102
|
+
try:
|
|
103
|
+
body = json.loads(event.get('body', '{}'))
|
|
104
|
+
result = table.get_item(Key={'id': body['id']})
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
'statusCode': 200,
|
|
108
|
+
'headers': {'Content-Type': 'application/json'},
|
|
109
|
+
'body': json.dumps(result.get('Item', {}))
|
|
110
|
+
}
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"Error: {str(e)}")
|
|
113
|
+
return {
|
|
114
|
+
'statusCode': 500,
|
|
115
|
+
'body': json.dumps({'error': str(e)})
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 2. SAM Template Pattern
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
# template.yaml
|
|
125
|
+
AWSTemplateFormatVersion: '2010-09-09'
|
|
126
|
+
Transform: AWS::Serverless-2016-10-31
|
|
127
|
+
|
|
128
|
+
Globals:
|
|
129
|
+
Function:
|
|
130
|
+
Runtime: nodejs20.x
|
|
131
|
+
Timeout: 30
|
|
132
|
+
MemorySize: 256
|
|
133
|
+
Environment:
|
|
134
|
+
Variables:
|
|
135
|
+
TABLE_NAME: !Ref ItemsTable
|
|
136
|
+
|
|
137
|
+
Resources:
|
|
138
|
+
# HTTP API (recommended)
|
|
139
|
+
HttpApi:
|
|
140
|
+
Type: AWS::Serverless::HttpApi
|
|
141
|
+
Properties:
|
|
142
|
+
StageName: prod
|
|
143
|
+
CorsConfiguration:
|
|
144
|
+
AllowOrigins: ["*"]
|
|
145
|
+
AllowMethods: [GET, POST, DELETE]
|
|
146
|
+
AllowHeaders: ["*"]
|
|
147
|
+
|
|
148
|
+
# Lambda Functions
|
|
149
|
+
GetItemFunction:
|
|
150
|
+
Type: AWS::Serverless::Function
|
|
151
|
+
Properties:
|
|
152
|
+
Handler: src/handlers/get.handler
|
|
153
|
+
Events:
|
|
154
|
+
GetItem:
|
|
155
|
+
Type: HttpApi
|
|
156
|
+
Properties:
|
|
157
|
+
ApiId: !Ref HttpApi
|
|
158
|
+
Path: /items/{id}
|
|
159
|
+
Method: GET
|
|
160
|
+
Policies:
|
|
161
|
+
- DynamoDBReadPolicy:
|
|
162
|
+
TableName: !Ref ItemsTable
|
|
163
|
+
|
|
164
|
+
# DynamoDB Table
|
|
165
|
+
ItemsTable:
|
|
166
|
+
Type: AWS::DynamoDB::Table
|
|
167
|
+
Properties:
|
|
168
|
+
AttributeDefinitions:
|
|
169
|
+
- AttributeName: id
|
|
170
|
+
AttributeType: S
|
|
171
|
+
KeySchema:
|
|
172
|
+
- AttributeName: id
|
|
173
|
+
KeyType: HASH
|
|
174
|
+
BillingMode: PAY_PER_REQUEST
|
|
175
|
+
|
|
176
|
+
Outputs:
|
|
177
|
+
ApiUrl:
|
|
178
|
+
Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com/prod"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 3. Event-Driven Patterns
|
|
184
|
+
|
|
185
|
+
### SQS Processing
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
// sqs-handler.js
|
|
189
|
+
exports.handler = async (event) => {
|
|
190
|
+
const failedRecords = [];
|
|
191
|
+
|
|
192
|
+
for (const record of event.Records) {
|
|
193
|
+
try {
|
|
194
|
+
const body = JSON.parse(record.body);
|
|
195
|
+
await processMessage(body);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
console.error(`Failed: ${record.messageId}`, error);
|
|
198
|
+
failedRecords.push({ itemIdentifier: record.messageId });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Partial batch response
|
|
203
|
+
return {
|
|
204
|
+
batchItemFailures: failedRecords
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### EventBridge Rule
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
# SAM template
|
|
213
|
+
ProcessOrderRule:
|
|
214
|
+
Type: AWS::Events::Rule
|
|
215
|
+
Properties:
|
|
216
|
+
EventPattern:
|
|
217
|
+
source: ["orders"]
|
|
218
|
+
detail-type: ["OrderCreated"]
|
|
219
|
+
Targets:
|
|
220
|
+
- Id: ProcessOrderLambda
|
|
221
|
+
Arn: !GetAtt ProcessOrderFunction.Arn
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 4. DynamoDB Patterns
|
|
227
|
+
|
|
228
|
+
### Single Table Design
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Access patterns in one table
|
|
232
|
+
const patterns = {
|
|
233
|
+
// Get user by ID
|
|
234
|
+
getUser: { PK: 'USER#123', SK: 'PROFILE' },
|
|
235
|
+
|
|
236
|
+
// Get user's orders
|
|
237
|
+
getUserOrders: {
|
|
238
|
+
PK: 'USER#123',
|
|
239
|
+
SK: { begins_with: 'ORDER#' }
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
// Get order by ID (GSI)
|
|
243
|
+
getOrder: {
|
|
244
|
+
GSI1PK: 'ORDER#456',
|
|
245
|
+
GSI1SK: 'ORDER#456'
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Access Pattern Matrix
|
|
251
|
+
|
|
252
|
+
| Access Pattern | PK | SK | Index |
|
|
253
|
+
|----------------|----|----|-------|
|
|
254
|
+
| Get user | USER#{id} | PROFILE | - |
|
|
255
|
+
| User's orders | USER#{id} | ORDER#{date} | - |
|
|
256
|
+
| Order by ID | - | - | GSI1 |
|
|
257
|
+
| Orders by date | - | - | GSI2 |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 5. Cold Start Optimization
|
|
262
|
+
|
|
263
|
+
| Strategy | Impact | Implementation |
|
|
264
|
+
|----------|--------|----------------|
|
|
265
|
+
| **Provisioned Concurrency** | Best | Keep instances warm |
|
|
266
|
+
| **Smaller packages** | High | Tree-shake, omit dev deps |
|
|
267
|
+
| **ARM64 (Graviton)** | Medium | Faster boot, lower cost |
|
|
268
|
+
| **Connection pooling** | Medium | Initialize outside handler |
|
|
269
|
+
| **Lambda SnapStart** | High | Java only, snapshot restore |
|
|
270
|
+
|
|
271
|
+
```yaml
|
|
272
|
+
# Provisioned concurrency
|
|
273
|
+
MyFunction:
|
|
274
|
+
Type: AWS::Serverless::Function
|
|
275
|
+
Properties:
|
|
276
|
+
AutoPublishAlias: live
|
|
277
|
+
ProvisionedConcurrencyConfig:
|
|
278
|
+
ProvisionedConcurrentExecutions: 5
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 6. Anti-Patterns
|
|
284
|
+
|
|
285
|
+
### ❌ Initialize Inside Handler
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
// WRONG
|
|
289
|
+
exports.handler = async (event) => {
|
|
290
|
+
const dynamodb = new DynamoDB(); // Cold on every call!
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// CORRECT
|
|
294
|
+
const dynamodb = new DynamoDB(); // Reused!
|
|
295
|
+
exports.handler = async (event) => {};
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### ❌ Synchronous Everything
|
|
299
|
+
|
|
300
|
+
```javascript
|
|
301
|
+
// WRONG: Wait for each
|
|
302
|
+
for (const item of items) {
|
|
303
|
+
await processItem(item);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// CORRECT: Parallel
|
|
307
|
+
await Promise.all(items.map(processItem));
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### ❌ No Dead Letter Queue
|
|
311
|
+
|
|
312
|
+
```yaml
|
|
313
|
+
# CORRECT: Always add DLQ
|
|
314
|
+
MyFunction:
|
|
315
|
+
Properties:
|
|
316
|
+
DeadLetterQueue:
|
|
317
|
+
Type: SQS
|
|
318
|
+
TargetArn: !GetAtt DLQ.Arn
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Related Skills
|
|
324
|
+
|
|
325
|
+
- `database-design` - DynamoDB modeling
|
|
326
|
+
- `api-patterns` - REST/GraphQL design
|
|
327
|
+
- `deployment-procedures` - CI/CD for serverless
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: azure-functions
|
|
3
|
+
description: "Azure Functions serverless patterns. Covers HTTP triggers, queue triggers, timer triggers, Durable Functions orchestration, and deployment with Azure CLI/Bicep."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# ☁️ Azure Functions
|
|
8
|
+
|
|
9
|
+
You are an Azure Functions expert who has built event-driven applications at scale. You understand the Azure serverless ecosystem, consumption vs premium plans, and Durable Functions for complex workflows.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## When to Use This Skill
|
|
14
|
+
|
|
15
|
+
- Building serverless APIs on Azure
|
|
16
|
+
- Event-driven processing with queues and blobs
|
|
17
|
+
- Complex workflows with Durable Functions
|
|
18
|
+
- Timer-based scheduled tasks
|
|
19
|
+
- Integration with Azure services
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Capabilities
|
|
24
|
+
|
|
25
|
+
- `azure-functions`
|
|
26
|
+
- `http-trigger`
|
|
27
|
+
- `queue-trigger`
|
|
28
|
+
- `timer-trigger`
|
|
29
|
+
- `durable-functions`
|
|
30
|
+
- `blob-trigger`
|
|
31
|
+
- `cosmosdb-trigger`
|
|
32
|
+
- `bicep-deployment`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 1. HTTP Trigger Pattern
|
|
37
|
+
|
|
38
|
+
### TypeScript Function
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
// src/functions/httpTrigger.ts
|
|
42
|
+
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
|
|
43
|
+
|
|
44
|
+
export async function httpTrigger(
|
|
45
|
+
request: HttpRequest,
|
|
46
|
+
context: InvocationContext
|
|
47
|
+
): Promise<HttpResponseInit> {
|
|
48
|
+
context.log(`HTTP function processed request for url "${request.url}"`);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const body = await request.json() as { name?: string };
|
|
52
|
+
const name = body.name || request.query.get('name') || 'World';
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
status: 200,
|
|
56
|
+
jsonBody: { message: `Hello, ${name}!` }
|
|
57
|
+
};
|
|
58
|
+
} catch (error) {
|
|
59
|
+
context.error('Error processing request:', error);
|
|
60
|
+
return {
|
|
61
|
+
status: 500,
|
|
62
|
+
jsonBody: { error: 'Internal server error' }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
app.http('httpTrigger', {
|
|
68
|
+
methods: ['GET', 'POST'],
|
|
69
|
+
authLevel: 'function',
|
|
70
|
+
handler: httpTrigger
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### JavaScript Function (v4 Model)
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
// src/functions/getUser.js
|
|
78
|
+
const { app } = require('@azure/functions');
|
|
79
|
+
const { CosmosClient } = require('@azure/cosmos');
|
|
80
|
+
|
|
81
|
+
// Initialize outside handler
|
|
82
|
+
const client = new CosmosClient(process.env.COSMOS_CONNECTION);
|
|
83
|
+
const container = client.database('mydb').container('users');
|
|
84
|
+
|
|
85
|
+
app.http('getUser', {
|
|
86
|
+
methods: ['GET'],
|
|
87
|
+
authLevel: 'anonymous',
|
|
88
|
+
route: 'users/{id}',
|
|
89
|
+
handler: async (request, context) => {
|
|
90
|
+
const id = request.params.id;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const { resource } = await container.item(id, id).read();
|
|
94
|
+
|
|
95
|
+
if (!resource) {
|
|
96
|
+
return { status: 404, jsonBody: { error: 'User not found' } };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { jsonBody: resource };
|
|
100
|
+
} catch (error) {
|
|
101
|
+
context.error('Error:', error);
|
|
102
|
+
return { status: 500, jsonBody: { error: error.message } };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 2. Queue Trigger Pattern
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// src/functions/queueTrigger.ts
|
|
114
|
+
import { app, InvocationContext } from "@azure/functions";
|
|
115
|
+
|
|
116
|
+
interface QueueMessage {
|
|
117
|
+
orderId: string;
|
|
118
|
+
customerId: string;
|
|
119
|
+
items: Array<{ id: string; quantity: number }>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function processOrder(
|
|
123
|
+
message: QueueMessage,
|
|
124
|
+
context: InvocationContext
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
context.log(`Processing order: ${message.orderId}`);
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
// Process the order
|
|
130
|
+
await processOrderItems(message.items);
|
|
131
|
+
|
|
132
|
+
// Output to another queue
|
|
133
|
+
context.extraOutputs.set('notification', {
|
|
134
|
+
type: 'order_processed',
|
|
135
|
+
orderId: message.orderId
|
|
136
|
+
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
context.error(`Failed to process order ${message.orderId}:`, error);
|
|
139
|
+
throw error; // Will move to poison queue after retries
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
app.storageQueue('processOrder', {
|
|
144
|
+
queueName: 'orders',
|
|
145
|
+
connection: 'AzureWebJobsStorage',
|
|
146
|
+
handler: processOrder,
|
|
147
|
+
extraOutputs: [
|
|
148
|
+
{ type: 'storageQueue', queueName: 'notifications', connection: 'AzureWebJobsStorage' }
|
|
149
|
+
]
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 3. Timer Trigger Pattern
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// src/functions/dailyCleanup.ts
|
|
159
|
+
import { app, InvocationContext, Timer } from "@azure/functions";
|
|
160
|
+
|
|
161
|
+
export async function dailyCleanup(
|
|
162
|
+
timer: Timer,
|
|
163
|
+
context: InvocationContext
|
|
164
|
+
): Promise<void> {
|
|
165
|
+
context.log('Daily cleanup started at:', new Date().toISOString());
|
|
166
|
+
|
|
167
|
+
if (timer.isPastDue) {
|
|
168
|
+
context.log('Timer is running late!');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Cleanup logic
|
|
172
|
+
await cleanupOldRecords();
|
|
173
|
+
await archiveCompletedOrders();
|
|
174
|
+
|
|
175
|
+
context.log('Daily cleanup completed');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
app.timer('dailyCleanup', {
|
|
179
|
+
// Every day at 2 AM UTC
|
|
180
|
+
schedule: '0 0 2 * * *',
|
|
181
|
+
handler: dailyCleanup
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 4. Durable Functions Pattern
|
|
188
|
+
|
|
189
|
+
Orchestrate complex workflows with automatic checkpointing.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// src/functions/orderOrchestrator.ts
|
|
193
|
+
import * as df from "durable-functions";
|
|
194
|
+
import { app, HttpRequest, HttpResponseInit, InvocationContext } from "@azure/functions";
|
|
195
|
+
|
|
196
|
+
// Orchestrator function
|
|
197
|
+
df.app.orchestration('orderWorkflow', function* (context) {
|
|
198
|
+
const orderId = context.df.getInput<string>();
|
|
199
|
+
|
|
200
|
+
// Step 1: Validate order
|
|
201
|
+
const isValid = yield context.df.callActivity('validateOrder', orderId);
|
|
202
|
+
if (!isValid) {
|
|
203
|
+
return { status: 'rejected', reason: 'Invalid order' };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Step 2: Reserve inventory (with retry)
|
|
207
|
+
const retryOptions = new df.RetryOptions(5000, 3);
|
|
208
|
+
const reserved = yield context.df.callActivityWithRetry(
|
|
209
|
+
'reserveInventory',
|
|
210
|
+
retryOptions,
|
|
211
|
+
orderId
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
// Step 3: Process payment
|
|
215
|
+
const payment = yield context.df.callActivity('processPayment', orderId);
|
|
216
|
+
|
|
217
|
+
// Step 4: Ship order (async, wait for external event)
|
|
218
|
+
const shippingTask = context.df.waitForExternalEvent('shippingConfirmed');
|
|
219
|
+
const timeoutTask = context.df.createTimer(
|
|
220
|
+
new Date(context.df.currentUtcDateTime.getTime() + 24 * 60 * 60 * 1000)
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const winner = yield context.df.Task.any([shippingTask, timeoutTask]);
|
|
224
|
+
|
|
225
|
+
if (winner === timeoutTask) {
|
|
226
|
+
return { status: 'failed', reason: 'Shipping timeout' };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { status: 'completed', orderId };
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Activity functions
|
|
233
|
+
df.app.activity('validateOrder', { handler: async (orderId: string) => true });
|
|
234
|
+
df.app.activity('reserveInventory', { handler: async (orderId: string) => true });
|
|
235
|
+
df.app.activity('processPayment', { handler: async (orderId: string) => ({ success: true }) });
|
|
236
|
+
|
|
237
|
+
// HTTP starter
|
|
238
|
+
app.http('startOrder', {
|
|
239
|
+
methods: ['POST'],
|
|
240
|
+
route: 'orders/start',
|
|
241
|
+
extraInputs: [df.input.durableClient()],
|
|
242
|
+
handler: async (request: HttpRequest, context: InvocationContext) => {
|
|
243
|
+
const client = df.getClient(context);
|
|
244
|
+
const body = await request.json() as { orderId: string };
|
|
245
|
+
|
|
246
|
+
const instanceId = await client.startNew('orderWorkflow', {
|
|
247
|
+
input: body.orderId
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
return client.createCheckStatusResponse(request, instanceId);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 5. Deployment Pattern (Bicep)
|
|
258
|
+
|
|
259
|
+
```bicep
|
|
260
|
+
// main.bicep
|
|
261
|
+
param location string = resourceGroup().location
|
|
262
|
+
param functionAppName string
|
|
263
|
+
|
|
264
|
+
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-02-01' = {
|
|
265
|
+
name: '${functionAppName}storage'
|
|
266
|
+
location: location
|
|
267
|
+
sku: { name: 'Standard_LRS' }
|
|
268
|
+
kind: 'StorageV2'
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
resource hostingPlan 'Microsoft.Web/serverfarms@2021-02-01' = {
|
|
272
|
+
name: '${functionAppName}-plan'
|
|
273
|
+
location: location
|
|
274
|
+
sku: {
|
|
275
|
+
name: 'Y1'
|
|
276
|
+
tier: 'Dynamic'
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
resource functionApp 'Microsoft.Web/sites@2021-02-01' = {
|
|
281
|
+
name: functionAppName
|
|
282
|
+
location: location
|
|
283
|
+
kind: 'functionapp'
|
|
284
|
+
properties: {
|
|
285
|
+
serverFarmId: hostingPlan.id
|
|
286
|
+
siteConfig: {
|
|
287
|
+
appSettings: [
|
|
288
|
+
{ name: 'AzureWebJobsStorage', value: storageAccount.properties.primaryEndpoints.blob }
|
|
289
|
+
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
|
|
290
|
+
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 6. Anti-Patterns
|
|
300
|
+
|
|
301
|
+
### ❌ Long-Running HTTP Functions
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
// WRONG: HTTP function running > 230 seconds
|
|
305
|
+
app.http('longProcess', {
|
|
306
|
+
handler: async (req) => {
|
|
307
|
+
await processFor10Minutes(); // Will timeout!
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// CORRECT: Use Durable Functions for long processes
|
|
312
|
+
app.http('startLongProcess', {
|
|
313
|
+
handler: async (req, context) => {
|
|
314
|
+
const client = df.getClient(context);
|
|
315
|
+
const instanceId = await client.startNew('longWorkflow');
|
|
316
|
+
return client.createCheckStatusResponse(req, instanceId);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### ❌ Cold Start Heavy
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
// WRONG: Heavy initialization in handler
|
|
325
|
+
export async function handler(req, context) {
|
|
326
|
+
const client = new HeavyClient(); // Cold every time!
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// CORRECT: Initialize outside
|
|
330
|
+
const client = new HeavyClient();
|
|
331
|
+
export async function handler(req, context) {}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Related Skills
|
|
337
|
+
|
|
338
|
+
- `aws-serverless` - Compare with AWS patterns
|
|
339
|
+
- `database-design` - CosmosDB patterns
|
|
340
|
+
- `api-patterns` - API design
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: broken-authentication
|
|
3
|
+
description: "Techniques for attacking authentication mechanisms: JWT bypass, Multi-Factor Authentication (MFA) bypass, OAuth flaws, and Session hijacking."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 🔓 Broken Authentication
|
|
8
|
+
|
|
9
|
+
You are an authentication security expert. You know that login is the most sensitive gate in an app, and developers often take shortcuts in its implementation.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Key Attack Vectors
|
|
14
|
+
|
|
15
|
+
### 1. JWT (JSON Web Token) Bypasses
|
|
16
|
+
- **None Algorithm**: Change `alg` in header to `None` and remove signature.
|
|
17
|
+
- **Key Confusion**: Use the Public Key to sign as if it were a Private Key (HMAC vs RSA).
|
|
18
|
+
- **Weak Secret**: Brute forcing the JWT secret using `hashcat`.
|
|
19
|
+
|
|
20
|
+
### 2. MFA Bypass
|
|
21
|
+
- **Response Manipulation**: Change `{"mfa": "required"}` to `{"mfa": "success"}` in the intercepting proxy.
|
|
22
|
+
- **Broken Logic**: Check if you can access `/dashboard` directly after entering the password but *before* the MFA code.
|
|
23
|
+
- **Rate Limit**: Brute force the 4-6 digit MFA code if no lockout is present.
|
|
24
|
+
|
|
25
|
+
### 3. OAuth 2.0 Flaws
|
|
26
|
+
- **Redirect URI Hijacking**: Changing the `redirect_uri` to a malicious site to steal the code/token.
|
|
27
|
+
- **CSRF via Lack of `state`**: If the `state` parameter is missing or static, you can link a victim's account to your identity.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Session Management Flaws
|
|
32
|
+
| Flaw | Description | Impact |
|
|
33
|
+
|------|-------------|--------|
|
|
34
|
+
| **Fixed Session** | Session ID doesn't change after login. | Session Fixation attack. |
|
|
35
|
+
| **No Secure/HttpOnly** | Cookies accessible via JS. | XSS can steal the session. |
|
|
36
|
+
| **Long Persistence** | Sessions never expire. | Long-term account hijack. |
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Checklist for Auth Audit
|
|
41
|
+
- [ ] Is password complexity enforced?
|
|
42
|
+
- [ ] Are brute force attacks possible (no rate limit/lockout)?
|
|
43
|
+
- [ ] Does the session die upon Logout?
|
|
44
|
+
- [ ] Are JWTs signed with a strong, rotated key?
|
|
45
|
+
- [ ] Is MFA truly required for all sensitive actions?
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Related Skills
|
|
50
|
+
|
|
51
|
+
- `burp-suite-testing` - Intercepting auth traffic
|
|
52
|
+
- `ethical-hacking-methodology` - "Gaining Access" phase
|
|
53
|
+
- `idor-testing` - Related authorization flaws
|