0
# Security Testing Framework
1
2
The Metlo testing framework provides comprehensive security test generation, execution, and management capabilities with support for OWASP Top 10 vulnerabilities and custom security test scenarios.
3
4
## Capabilities
5
6
### Test Configuration Management
7
8
#### Load Test Configuration
9
10
Load and validate test configuration from YAML files.
11
12
```typescript { .api }
13
/**
14
* Load and validate test configuration from YAML file
15
* @param path - Path to the YAML test file
16
* @returns Parsed and validated test configuration
17
* @throws Error if configuration is invalid
18
*/
19
function loadTestConfig(path: string): TestConfig;
20
```
21
22
**Usage Examples:**
23
24
```typescript
25
import { loadTestConfig } from "@metlo/testing";
26
27
// Load test from file
28
const testConfig = loadTestConfig("./tests/auth-test.yaml");
29
30
// Error handling
31
try {
32
const testConfig = loadTestConfig("./tests/invalid-test.yaml");
33
} catch (error) {
34
console.error("Test configuration invalid:", error.message);
35
}
36
```
37
38
#### Dump Test Configuration
39
40
Serialize test configuration to YAML format with proper ordering.
41
42
```typescript { .api }
43
/**
44
* Serialize test configuration to YAML format
45
* @param config - Test configuration object
46
* @returns YAML string representation
47
*/
48
function dumpTestConfig(config: TestConfig): string;
49
```
50
51
**Usage Examples:**
52
53
```typescript
54
import { dumpTestConfig, TestBuilder } from "@metlo/testing";
55
56
// Create test and serialize to YAML
57
const testConfig = new TestBuilder("auth-test")
58
.setMeta({ name: "Authentication Test", severity: "CRITICAL" })
59
.addStep({
60
request: { method: "GET", url: "https://api.example.com/profile" },
61
assert: [{ key: "resp.status", value: 200 }]
62
})
63
.build();
64
65
const yamlContent = dumpTestConfig(testConfig);
66
console.log(yamlContent);
67
```
68
69
### Test Execution
70
71
#### Run Test
72
73
Execute a security test configuration and return detailed results.
74
75
```typescript { .api }
76
/**
77
* Execute a security test configuration
78
* @param config - Test configuration to execute
79
* @param context - Optional execution context
80
* @returns Promise resolving to test results
81
*/
82
function runTest(config: TestConfig, context?: any): Promise<TestResult>;
83
```
84
85
**Usage Examples:**
86
87
```typescript
88
import { runTest, loadTestConfig } from "@metlo/testing";
89
90
// Run test from configuration
91
const testConfig = loadTestConfig("./tests/sqli-test.yaml");
92
const result = await runTest(testConfig);
93
94
if (result.success) {
95
console.log("Test passed!");
96
} else {
97
console.log("Test failed:", result.errors);
98
}
99
100
// Run with custom context
101
const result = await runTest(testConfig, {
102
baseUrl: "https://staging.api.com",
103
timeout: 10000
104
});
105
```
106
107
#### Estimate Test Duration
108
109
Estimate the execution time for a test configuration.
110
111
```typescript { .api }
112
/**
113
* Estimate test execution time in milliseconds
114
* @param config - Test configuration to analyze
115
* @returns Promise resolving to estimated duration in ms
116
*/
117
function estimateTest(config: TestConfig): Promise<number>;
118
```
119
120
**Usage Examples:**
121
122
```typescript
123
import { estimateTest, loadTestConfig } from "@metlo/testing";
124
125
const testConfig = loadTestConfig("./tests/comprehensive-test.yaml");
126
const estimatedMs = await estimateTest(testConfig);
127
console.log(`Test will take approximately ${estimatedMs}ms to run`);
128
```
129
130
### Test Building
131
132
#### TestBuilder Class
133
134
Main class for building complete test configurations programmatically.
135
136
```typescript { .api }
137
/**
138
* Builder class for creating test configurations
139
*/
140
class TestBuilder {
141
/**
142
* Create a new test builder
143
* @param id - Unique test identifier
144
*/
145
constructor(id: string);
146
147
/**
148
* Set test metadata
149
* @param meta - Test metadata including name, severity, tags
150
* @returns TestBuilder instance for chaining
151
*/
152
setMeta(meta: TestMeta): TestBuilder;
153
154
/**
155
* Add a test step
156
* @param step - Test step configuration
157
* @returns TestBuilder instance for chaining
158
*/
159
addStep(step: TestStep): TestBuilder;
160
161
/**
162
* Set test execution options
163
* @param options - Test options like stopOnFailure
164
* @returns TestBuilder instance for chaining
165
*/
166
setOptions(options: TestOptions): TestBuilder;
167
168
/**
169
* Add environment variables
170
* @param items - Environment variable key-value pairs
171
* @returns TestBuilder instance for chaining
172
*/
173
addEnv(...items: KeyValType[]): TestBuilder;
174
175
/**
176
* Build the final test configuration
177
* @returns Complete test configuration
178
*/
179
build(): TestConfig;
180
}
181
```
182
183
**Usage Examples:**
184
185
```typescript
186
import { TestBuilder, TestStepBuilder } from "@metlo/testing";
187
188
// Build comprehensive authentication test
189
const testConfig = new TestBuilder("auth-comprehensive")
190
.setMeta({
191
name: "Comprehensive Authentication Test",
192
severity: "CRITICAL",
193
tags: ["BROKEN_AUTHENTICATION", "OWASP_TOP_10"]
194
})
195
.setOptions({
196
stopOnFailure: false
197
})
198
.addEnv(
199
{ name: "BASE_URL", value: "https://api.example.com" },
200
{ name: "TEST_USER", value: "testuser@example.com" }
201
)
202
.addStep({
203
request: {
204
method: "POST",
205
url: "{{BASE_URL}}/auth/login",
206
headers: [{ name: "Content-Type", value: "application/json" }],
207
data: JSON.stringify({ email: "{{TEST_USER}}", password: "password123" })
208
},
209
extract: [
210
{ name: "auth_token", type: "VALUE", value: "resp.body.token" }
211
],
212
assert: [
213
{ key: "resp.status", value: 200 },
214
{ key: "resp.body.token", value: "exists" }
215
]
216
})
217
.addStep({
218
request: {
219
method: "GET",
220
url: "{{BASE_URL}}/profile",
221
headers: [
222
{ name: "Authorization", value: "Bearer {{auth_token}}" }
223
]
224
},
225
assert: [
226
{ key: "resp.status", value: 200 }
227
]
228
})
229
.build();
230
```
231
232
#### TestStepBuilder Class
233
234
Builder class for creating individual test steps with request/response validation.
235
236
```typescript { .api }
237
/**
238
* Builder class for creating individual test steps
239
*/
240
class TestStepBuilder {
241
/**
242
* Create a new test step builder
243
* @param request - HTTP request configuration
244
*/
245
constructor(request: TestRequest);
246
247
/**
248
* Create sample request for endpoint (with authentication)
249
* @param endpoint - Target endpoint metadata
250
* @param config - Template configuration
251
* @param name - Optional name prefix for variables
252
* @returns TestStepBuilder instance
253
*/
254
static sampleRequest(
255
endpoint: GenTestEndpoint,
256
config: TemplateConfig,
257
name?: string
258
): TestStepBuilder;
259
260
/**
261
* Create sample request for endpoint (without authentication)
262
* @param endpoint - Target endpoint metadata
263
* @param config - Template configuration
264
* @param name - Optional name prefix for variables
265
* @returns TestStepBuilder instance
266
*/
267
static sampleRequestWithoutAuth(
268
endpoint: GenTestEndpoint,
269
config: TemplateConfig,
270
name?: string
271
): TestStepBuilder;
272
273
/**
274
* Add authentication to the request
275
* @param endpoint - Endpoint metadata for auth context
276
* @param name - Optional name prefix for variables
277
* @returns TestStepBuilder instance for chaining
278
*/
279
addAuth(endpoint: GenTestEndpoint, name?: string): TestStepBuilder;
280
281
/**
282
* Set the request configuration
283
* @param request - HTTP request details
284
* @returns TestStepBuilder instance for chaining
285
*/
286
setRequest(request: TestRequest): TestStepBuilder;
287
288
/**
289
* Modify the current request
290
* @param f - Function to transform the request
291
* @returns TestStepBuilder instance for chaining
292
*/
293
modifyRequest(f: (old: TestRequest) => TestRequest): TestStepBuilder;
294
295
/**
296
* Add response assertion
297
* @param assertion - Assertion to validate response
298
* @returns TestStepBuilder instance for chaining
299
*/
300
assert(assertion: Assertion): TestStepBuilder;
301
302
/**
303
* Add payload to request
304
* @param payload - Payload configuration
305
* @returns TestStepBuilder instance for chaining
306
*/
307
addPayloads(payload: PayloadType): TestStepBuilder;
308
309
/**
310
* Extract value from response
311
* @param item - Extraction configuration
312
* @returns TestStepBuilder instance for chaining
313
*/
314
extract(item: Extractor): TestStepBuilder;
315
316
/**
317
* Add environment variables to step
318
* @param items - Environment variable key-value pairs
319
* @returns TestStepBuilder instance for chaining
320
*/
321
addToEnv(...items: KeyValType[]): TestStepBuilder;
322
323
/**
324
* Build the test step
325
* @returns Complete test step configuration
326
*/
327
getStep(): TestStep;
328
}
329
```
330
331
**Usage Examples:**
332
333
```typescript
334
import { TestStepBuilder, AssertionType, ExtractorType } from "@metlo/testing";
335
336
// Build authentication test step
337
const loginStep = new TestStepBuilder({
338
method: "POST",
339
url: "https://api.example.com/auth/login",
340
headers: [{ name: "Content-Type", value: "application/json" }],
341
data: JSON.stringify({ email: "test@example.com", password: "password" })
342
})
343
.extract({
344
name: "access_token",
345
type: ExtractorType.enum.VALUE,
346
value: "resp.body.access_token"
347
})
348
.assert({
349
type: AssertionType.enum.EQ,
350
key: "resp.status",
351
value: 200
352
})
353
.assert({
354
type: AssertionType.enum.EXISTS,
355
key: "resp.body.access_token"
356
})
357
.addToEnv({ name: "USER_TOKEN", value: "{{access_token}}" });
358
359
// Build unauthorized access test step
360
const unauthorizedStep = TestStepBuilder.sampleRequestWithoutAuth(endpoint, config)
361
.assert({
362
type: AssertionType.enum.IN,
363
key: "resp.status",
364
value: [401, 403]
365
});
366
367
const testStep = loginStep.getStep();
368
```
369
370
### Test Generation
371
372
#### Generate Authentication Tests
373
374
Generate comprehensive authentication security tests for endpoints.
375
376
```typescript { .api }
377
/**
378
* Generate authentication security tests for an endpoint
379
* @param endpoint - Target endpoint metadata
380
* @param config - Template configuration for test generation
381
* @returns Array of generated test configurations
382
*/
383
function generateAuthTests(endpoint: GenTestEndpoint, config: TemplateConfig): TestConfig[];
384
```
385
386
**Usage Examples:**
387
388
```typescript
389
import { generateAuthTests } from "@metlo/testing";
390
391
const endpoint = {
392
host: "api.example.com",
393
path: "/api/users/profile",
394
method: "GET",
395
// ... other endpoint metadata
396
};
397
398
const config = {
399
// Template configuration
400
authConfig: {
401
type: "bearer",
402
headerName: "Authorization"
403
}
404
};
405
406
const authTests = generateAuthTests(endpoint, config);
407
console.log(`Generated ${authTests.length} authentication tests`);
408
409
// Run all generated tests
410
for (const testConfig of authTests) {
411
const result = await runTest(testConfig);
412
console.log(`Test ${testConfig.id}: ${result.success ? 'PASS' : 'FAIL'}`);
413
}
414
```
415
416
#### Find Endpoint Permissions
417
418
Analyze endpoint to determine required resource permissions.
419
420
```typescript { .api }
421
/**
422
* Analyze endpoint to determine required resource permissions
423
* @param endpoint - Target endpoint metadata
424
* @returns Array of required permission strings
425
*/
426
function findEndpointResourcePermissions(endpoint: GenTestEndpoint): string[];
427
```
428
429
**Usage Examples:**
430
431
```typescript
432
import { findEndpointResourcePermissions } from "@metlo/testing";
433
434
const endpoint = {
435
path: "/api/users/:id/profile",
436
method: "GET",
437
// ... other metadata
438
};
439
440
const permissions = findEndpointResourcePermissions(endpoint);
441
console.log("Required permissions:", permissions);
442
// Output: ["read:user", "read:profile"]
443
```
444
445
### Result Analysis
446
447
#### Get Failed Assertions
448
449
Extract detailed information about failed assertions from test results.
450
451
```typescript { .api }
452
/**
453
* Extract failed assertions from test results
454
* @param res - Test execution results
455
* @returns Array of failed assertion details
456
*/
457
function getFailedAssertions(res: TestResult): FailedAssertion[];
458
```
459
460
**Usage Examples:**
461
462
```typescript
463
import { getFailedAssertions, runTest } from "@metlo/testing";
464
465
const result = await runTest(testConfig);
466
467
if (!result.success) {
468
const failedAssertions = getFailedAssertions(result);
469
470
failedAssertions.forEach((failure, index) => {
471
console.log(`Failed Assertion ${index + 1}:`);
472
console.log(` Step: ${failure.stepIdx}`);
473
console.log(` Expected: ${failure.assertion.value}`);
474
console.log(` Actual: ${failure.res.body}`);
475
});
476
}
477
```
478
479
#### Get Failed Requests
480
481
Extract information about requests that failed to execute.
482
483
```typescript { .api }
484
/**
485
* Extract failed requests from test results
486
* @param res - Test execution results
487
* @returns Array of failed request details
488
*/
489
function getFailedRequests(res: TestResult): FailedRequest[];
490
```
491
492
**Usage Examples:**
493
494
```typescript
495
import { getFailedRequests, runTest } from "@metlo/testing";
496
497
const result = await runTest(testConfig);
498
499
if (!result.success) {
500
const failedRequests = getFailedRequests(result);
501
502
failedRequests.forEach((failure, index) => {
503
console.log(`Failed Request ${index + 1}:`);
504
console.log(` URL: ${failure.req.url}`);
505
console.log(` Method: ${failure.req.method}`);
506
console.log(` Error: ${failure.err}`);
507
});
508
}
509
```
510
511
### Resource Configuration
512
513
#### Parse Resource Configuration
514
515
Parse resource configuration strings into structured format.
516
517
```typescript { .api }
518
/**
519
* Parse resource configuration string
520
* @param config - Resource configuration string
521
* @returns Parsed resource configuration
522
*/
523
function parseResourceConfig(config: string): ResourceConfigParseRes;
524
```
525
526
#### Process Resource Configuration
527
528
Process parsed resource configuration into template configuration.
529
530
```typescript { .api }
531
/**
532
* Process parsed resource configuration into template configuration
533
* @param config - Parsed resource configuration
534
* @returns Template configuration for test generation
535
*/
536
function processResourceConfig(config: ResourceConfigParseRes): TemplateConfig;
537
```
538
539
## Type Definitions
540
541
### Core Test Types
542
543
```typescript { .api }
544
interface TestConfig {
545
id: string;
546
meta?: TestMeta;
547
env?: KeyValType[];
548
test: TestStep[];
549
options?: TestOptions;
550
}
551
552
interface TestMeta {
553
name?: string;
554
severity?: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
555
tags?: string[];
556
}
557
558
interface TestStep {
559
request: TestRequest;
560
extract?: Extractor[];
561
assert?: Assertion[];
562
payload?: PayloadType[];
563
}
564
565
interface TestRequest {
566
method: string;
567
url: string;
568
headers?: KeyValType[];
569
query?: KeyValType[];
570
form?: KeyValType[];
571
data?: string;
572
graphql?: string;
573
}
574
575
interface TestOptions {
576
stopOnFailure?: boolean;
577
}
578
579
interface KeyValType {
580
name: string;
581
value: string;
582
}
583
```
584
585
### Assertion and Extraction Types
586
587
```typescript { .api }
588
enum AssertionType {
589
EQ = "EQ",
590
NEQ = "NEQ",
591
GT = "GT",
592
LT = "LT",
593
GTE = "GTE",
594
LTE = "LTE",
595
IN = "IN",
596
NOT_IN = "NOT_IN",
597
EXISTS = "EXISTS",
598
NOT_EXISTS = "NOT_EXISTS",
599
CONTAINS = "CONTAINS",
600
NOT_CONTAINS = "NOT_CONTAINS",
601
REGEX = "REGEX"
602
}
603
604
enum ExtractorType {
605
VALUE = "VALUE",
606
HEADER = "HEADER",
607
COOKIE = "COOKIE"
608
}
609
610
interface Assertion {
611
description?: string;
612
type?: AssertionType;
613
key?: string;
614
value: string | number | boolean | Array<string | number | boolean>;
615
}
616
617
interface Extractor {
618
name: string;
619
type: ExtractorType;
620
value: string;
621
}
622
623
interface PayloadType {
624
key: string;
625
value: string;
626
}
627
```
628
629
### Result Types
630
631
```typescript { .api }
632
interface TestResult {
633
success: boolean;
634
test?: TestConfig;
635
results: TestStepResult[][];
636
errors?: string[];
637
}
638
639
interface TestStepResult {
640
success: boolean;
641
ctx: Record<string, any>;
642
req: StepRequest;
643
res?: StepResponse;
644
err?: string;
645
assertions: boolean[];
646
}
647
648
interface FailedAssertion {
649
stepIdx: number;
650
stepRunIdx: number;
651
assertionIdx: number;
652
ctx: Record<string, any>;
653
stepReq: StepRequest;
654
assertion: Assertion;
655
res: StepResponse;
656
}
657
658
interface FailedRequest {
659
stepIdx: number;
660
stepRunIdx: number;
661
stepReq: StepRequest;
662
req: TestRequest;
663
ctx: Record<string, any>;
664
err: string;
665
}
666
```
667
668
### Generation Types
669
670
```typescript { .api }
671
interface GenTestEndpoint {
672
host: string;
673
path: string;
674
method: string;
675
// Additional endpoint metadata
676
}
677
678
interface GenTestContext {
679
endpoint: GenTestEndpoint;
680
prefix?: string;
681
entityMap: Record<string, any>;
682
}
683
684
interface TemplateConfig {
685
authConfig?: {
686
type: "bearer" | "basic" | "apikey";
687
headerName?: string;
688
queryParam?: string;
689
};
690
// Additional template configuration
691
}
692
```