or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analysis.mdbackend-api.mdcli.mdindex.mdingestors.mdintegration.mdtesting.mdtypes.md

testing.mddocs/

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

```