@metlo/testing
Advanced tools
Comparing version 0.2.15 to 0.2.16
@@ -12,2 +12,2 @@ import { FailedAssertion, FailedRequest, TestConfig, TestResult } from "./types/test"; | ||
export { TestTemplate } from "./templates/types"; | ||
export { runTest } from "./runner"; | ||
export { runTest, estimateTest } from "./runner"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runTest = exports.TestStepBuilder = exports.TestBuilder = exports.TestConfigSchema = exports.ExtractorType = exports.AssertionType = exports.getFailedRequests = exports.getFailedAssertions = exports.loadTestConfig = exports.dumpTestConfig = void 0; | ||
exports.estimateTest = exports.runTest = exports.TestStepBuilder = exports.TestBuilder = exports.TestConfigSchema = exports.ExtractorType = exports.AssertionType = exports.getFailedRequests = exports.getFailedAssertions = exports.loadTestConfig = exports.dumpTestConfig = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -114,2 +114,3 @@ const chalk_1 = tslib_1.__importDefault(require("chalk")); | ||
Object.defineProperty(exports, "runTest", { enumerable: true, get: function () { return runner_1.runTest; } }); | ||
Object.defineProperty(exports, "estimateTest", { enumerable: true, get: function () { return runner_1.estimateTest; } }); | ||
//# sourceMappingURL=index.js.map |
import { TestConfig, TestResult } from "../types/test"; | ||
export declare const estimateTest: (test: TestConfig, env?: Record<string, string | object>) => number; | ||
export declare const runTest: (test: TestConfig, env?: Record<string, string | object>) => Promise<TestResult>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runTest = void 0; | ||
exports.runTest = exports.estimateTest = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -11,2 +11,21 @@ const step_1 = require("./step"); | ||
}); | ||
const estimateTest = (test, env) => { | ||
const context = { | ||
cookies: {}, | ||
envVars: env || {}, | ||
}; | ||
if (test.env) { | ||
context.envVars = Object.fromEntries(Object.entries(context.envVars).concat(test.env.map(e => [e.name, e.value]))); | ||
} | ||
const testStack = [...test.test]; | ||
if (testStack.length > 0) { | ||
const firstStep = testStack.shift(); | ||
const config = test.config; | ||
return (0, step_1.runStepComplexity)(0, firstStep, testStack, context, config); | ||
} | ||
else { | ||
throw new Error("No item to test in stack"); | ||
} | ||
}; | ||
exports.estimateTest = estimateTest; | ||
const runTest = (test, env) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
@@ -25,3 +44,4 @@ const context = { | ||
const firstStep = testStack.shift(); | ||
const resp = yield (0, step_1.runStep)(0, firstStep, testStack, context); | ||
const config = test.config || {}; | ||
const resp = yield (0, step_1.runStep)(0, firstStep, testStack, context, config); | ||
return { | ||
@@ -31,2 +51,3 @@ test, | ||
results: resp.results, | ||
abortedAt: resp.abortedAt, | ||
}; | ||
@@ -33,0 +54,0 @@ } |
@@ -5,3 +5,26 @@ "use strict"; | ||
exports.makeRequest = void 0; | ||
const tslib_1 = require("tslib"); | ||
const axios_1 = tslib_1.__importDefault(require("axios")); | ||
const utils_1 = require("../utils"); | ||
axios_1.default.interceptors.request.use(function (config) { | ||
// @ts-ignore | ||
config.metadata = { startTime: new Date() }; | ||
return config; | ||
}, function (error) { | ||
return Promise.reject(error); | ||
}); | ||
axios_1.default.interceptors.response.use(function (response) { | ||
// @ts-ignore | ||
response.config.metadata.endTime = new Date(); | ||
// @ts-ignore | ||
response.duration = | ||
// @ts-ignore | ||
response.config.metadata.endTime - response.config.metadata.startTime; | ||
return response; | ||
}, function (error) { | ||
error.config.metadata.endTime = new Date(); | ||
error.duration = | ||
error.config.metadata.endTime - error.config.metadata.startTime; | ||
return Promise.reject(error); | ||
}); | ||
const BLOCKED_HOSTS = new Set((_a = process.env.METLO_TEST_BLOCKED_HOSTS) === null || _a === void 0 ? void 0 : _a.split(",")); | ||
@@ -8,0 +31,0 @@ const makeRequest = (req, ctx) => { |
@@ -1,3 +0,4 @@ | ||
import { TestStep, TestResult } from "../types/test"; | ||
import { TestStep, TestResult, Config } from "../types/test"; | ||
import { Context } from "../types/context"; | ||
export declare const runStep: (idx: number, step: TestStep, nextSteps: TestStep[], ctx: Context) => Promise<TestResult>; | ||
export declare const runStep: (idx: number, step: TestStep, nextSteps: TestStep[], ctx: Context, config: Config) => Promise<TestResult>; | ||
export declare function runStepComplexity(idx: number, step: TestStep, nextSteps: TestStep[], ctx: Context, config: Config): number; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runStep = void 0; | ||
exports.runStepComplexity = exports.runStep = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -9,2 +9,4 @@ const axios_1 = tslib_1.__importDefault(require("axios")); | ||
const extractors_1 = require("./extractors"); | ||
const data_1 = require("../data"); | ||
const utils_1 = require("./utils"); | ||
const axiosRespToStepResponse = (res) => ({ | ||
@@ -28,7 +30,49 @@ data: res.data, | ||
}); | ||
const runStep = (idx, step, nextSteps, ctx) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
const runStepPayloads = (idx, step, nextSteps, ctx, config) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
const payloadValues = {}; | ||
step.payload = step.payload; | ||
step.payload.forEach(payloadEntry => { | ||
const payload = payloadEntry.value; | ||
if (payloadEntry.key in payloadValues) { | ||
payloadValues[payloadEntry.key].push(...(0, data_1.getValues)(payload)); | ||
} | ||
else { | ||
payloadValues[payloadEntry.key] = [...(0, data_1.getValues)(payload)]; | ||
} | ||
}); | ||
const results = yield Promise.all((0, utils_1.cartesian)(payloadValues).map(data => { | ||
const newCtx = Object.assign(Object.assign({}, ctx), { envVars: Object.assign(Object.assign({}, ctx.envVars), data) }); | ||
return (0, exports.runStep)(idx, { | ||
extract: step.extract, | ||
assert: step.assert, | ||
request: step.request, | ||
}, nextSteps, newCtx, config); | ||
})); | ||
const flatResults = results.map(e => e.results.flat()).flat(); | ||
const groupedResults = {}; | ||
flatResults.forEach(res => { | ||
if (res.idx in groupedResults) { | ||
groupedResults[res.idx].push(res); | ||
} | ||
else { | ||
groupedResults[res.idx] = [res]; | ||
} | ||
}); | ||
const combinedResults = Object.entries(groupedResults) | ||
.sort(([key1, res1], [key2, res2]) => (key1 < key2 ? 1 : -1)) | ||
.map(([key, res]) => res); | ||
return { | ||
success: results.every(e => e), | ||
results: combinedResults, | ||
}; | ||
}); | ||
const runStep = (idx, step, nextSteps, ctx, config) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { | ||
var _a; | ||
if (step.payload) { | ||
return runStepPayloads(idx, step, nextSteps, ctx, config); | ||
} | ||
let res = null; | ||
let err = undefined; | ||
let errStack = undefined; | ||
let abortedAt = undefined; | ||
const reqConfig = (0, request_1.makeRequest)(step.request, ctx); | ||
@@ -59,6 +103,16 @@ const stepRequest = { | ||
ctx.cookies[host] = currUrlCookies; | ||
let assertions = Array((step.assert || []).length).fill(false); | ||
for (const e of step.extract || []) { | ||
ctx = (0, extractors_1.runExtractor)(e, res, ctx); | ||
} | ||
let assertions = (step.assert || []).map(e => (0, assertions_1.runAssertion)(e, res, ctx)); | ||
let i = 0; | ||
for (const _step of step.assert || []) { | ||
const asserted = (0, assertions_1.runAssertion)(_step, res, ctx); | ||
assertions[i] = asserted; | ||
i++; | ||
if (config.stopOnFailedAssertion && !asserted) { | ||
abortedAt = i; | ||
break; | ||
} | ||
} | ||
stepResult = { | ||
@@ -85,6 +139,7 @@ idx, | ||
const nextStep = nextSteps.shift(); | ||
if (!nextStep) { | ||
if (!nextStep || abortedAt) { | ||
return { | ||
success: stepResult.success, | ||
results: [[stepResult]], | ||
abortedAt, | ||
}; | ||
@@ -96,9 +151,41 @@ } | ||
cookies: cookiesCopy, | ||
}); | ||
}, config); | ||
return { | ||
success: stepResult.success && nextRes.success, | ||
results: [[stepResult]].concat(nextRes.results), | ||
abortedAt: nextRes.abortedAt, | ||
}; | ||
}); | ||
exports.runStep = runStep; | ||
function runStepComplexity(idx, step, nextSteps, ctx, config) { | ||
if (step.payload) { | ||
const payloadValues = {}; | ||
step.payload.forEach(payloadEntry => { | ||
const payload = payloadEntry.value; | ||
if (payloadEntry.key in payloadValues) { | ||
payloadValues[payloadEntry.key].push(...(0, data_1.getValues)(payload)); | ||
} | ||
else { | ||
payloadValues[payloadEntry.key] = [...(0, data_1.getValues)(payload)]; | ||
} | ||
}); | ||
const results = (0, utils_1.cartesian)(payloadValues).map(data => { | ||
const newCtx = Object.assign(Object.assign({}, ctx), { envVars: Object.assign(Object.assign({}, ctx.envVars), data) }); | ||
return runStepComplexity(idx, { | ||
extract: step.extract, | ||
assert: step.assert, | ||
request: step.request, | ||
}, nextSteps, newCtx, config); | ||
}); | ||
return results.reduce((prev, curr) => prev + curr, 0); | ||
} | ||
else { | ||
const next = nextSteps.shift(); | ||
if (!next) { | ||
return 1; | ||
} | ||
return 1 + runStepComplexity(idx + 1, next, nextSteps, ctx, config); | ||
} | ||
} | ||
exports.runStepComplexity = runStepComplexity; | ||
//# sourceMappingURL=step.js.map |
import { AxiosResponse } from "axios"; | ||
import { Context } from "../types/context"; | ||
export declare const getKeyValue: (key: string, resp: AxiosResponse, ctx: Context) => any; | ||
export declare function cartesian(takeProductOf: { | ||
[k: string]: Array<string>; | ||
}): { | ||
[k: string]: string; | ||
}[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getKeyValue = void 0; | ||
exports.cartesian = exports.getKeyValue = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -12,2 +12,22 @@ const lodash_get_1 = tslib_1.__importDefault(require("lodash.get")); | ||
exports.getKeyValue = getKeyValue; | ||
function cartesian(takeProductOf) { | ||
const separatedKeys = Object.entries(takeProductOf).map(([key, entries]) => ({ | ||
[key]: entries, | ||
})); | ||
function cartesianInner(part, index) { | ||
var k = Object.keys(separatedKeys[index])[0]; | ||
separatedKeys[index][k].forEach(function (a) { | ||
var p = Object.assign({}, part, { [k]: a }); | ||
if (index + 1 === separatedKeys.length) { | ||
res.push(p); | ||
return; | ||
} | ||
cartesianInner(p, index + 1); | ||
}); | ||
} | ||
let res = []; | ||
cartesianInner({}, 0); | ||
return res; | ||
} | ||
exports.cartesian = cartesian; | ||
//# sourceMappingURL=utils.js.map |
@@ -6,1 +6,3 @@ import { z } from "zod"; | ||
export declare const ExtractorType: z.ZodEnum<["VALUE", "JS", "REGEXP", "HTML"]>; | ||
export declare const PredefinedPayloadTypeArray: [string, ...string[]]; | ||
export declare const PredefinedPayloadType: z.ZodEnum<[string, ...string[]]>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ExtractorType = exports.AssertionType = exports.Method = exports.Severity = void 0; | ||
exports.PredefinedPayloadType = exports.PredefinedPayloadTypeArray = exports.ExtractorType = exports.AssertionType = exports.Method = exports.Severity = void 0; | ||
const zod_1 = require("zod"); | ||
@@ -19,2 +19,9 @@ exports.Severity = zod_1.z.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]); | ||
exports.ExtractorType = zod_1.z.enum(["VALUE", "JS", "REGEXP", "HTML"]); | ||
exports.PredefinedPayloadTypeArray = [ | ||
"XSS", | ||
"SQLI", | ||
"SQLI_AUTH_BYPASS", | ||
"SQLI_TIME", | ||
]; | ||
exports.PredefinedPayloadType = zod_1.z.enum(exports.PredefinedPayloadTypeArray); | ||
//# sourceMappingURL=enums.js.map |
@@ -120,2 +120,12 @@ import { z } from "zod"; | ||
}>, z.ZodString]>; | ||
export declare const PayloadSchema: z.ZodArray<z.ZodObject<{ | ||
key: z.ZodString; | ||
value: z.ZodUnion<[z.ZodEnum<[string, ...string[]]>, z.ZodString]>; | ||
}, "strip", z.ZodTypeAny, { | ||
value: string; | ||
key: string; | ||
}, { | ||
value: string; | ||
key: string; | ||
}>, "many">; | ||
export declare const TestStepSchema: z.ZodObject<{ | ||
@@ -215,2 +225,12 @@ request: z.ZodObject<{ | ||
}>, z.ZodString]>, "many">>; | ||
payload: z.ZodOptional<z.ZodArray<z.ZodObject<{ | ||
key: z.ZodString; | ||
value: z.ZodUnion<[z.ZodEnum<[string, ...string[]]>, z.ZodString]>; | ||
}, "strip", z.ZodTypeAny, { | ||
value: string; | ||
key: string; | ||
}, { | ||
value: string; | ||
key: string; | ||
}>, "many">>; | ||
}, "strip", z.ZodTypeAny, { | ||
@@ -227,2 +247,6 @@ extract?: { | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -256,2 +280,6 @@ data?: string | undefined; | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -275,2 +303,9 @@ data?: string | undefined; | ||
}>; | ||
export declare const ConfigSchema: z.ZodObject<{ | ||
stopOnFailedAssertion: z.ZodOptional<z.ZodBoolean>; | ||
}, "strip", z.ZodTypeAny, { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
}, { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
}>; | ||
export declare const TestConfigSchema: z.ZodObject<{ | ||
@@ -395,2 +430,12 @@ id: z.ZodString; | ||
}>, z.ZodString]>, "many">>; | ||
payload: z.ZodOptional<z.ZodArray<z.ZodObject<{ | ||
key: z.ZodString; | ||
value: z.ZodUnion<[z.ZodEnum<[string, ...string[]]>, z.ZodString]>; | ||
}, "strip", z.ZodTypeAny, { | ||
value: string; | ||
key: string; | ||
}, { | ||
value: string; | ||
key: string; | ||
}>, "many">>; | ||
}, "strip", z.ZodTypeAny, { | ||
@@ -407,2 +452,6 @@ extract?: { | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -436,2 +485,6 @@ data?: string | undefined; | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -455,2 +508,9 @@ data?: string | undefined; | ||
}>, "many">; | ||
config: z.ZodOptional<z.ZodObject<{ | ||
stopOnFailedAssertion: z.ZodOptional<z.ZodBoolean>; | ||
}, "strip", z.ZodTypeAny, { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
}, { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
}>>; | ||
}, "strip", z.ZodTypeAny, { | ||
@@ -466,2 +526,5 @@ meta?: { | ||
}[] | undefined; | ||
config?: { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
} | undefined; | ||
id: string; | ||
@@ -479,2 +542,6 @@ test: { | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -508,2 +575,5 @@ data?: string | undefined; | ||
}[] | undefined; | ||
config?: { | ||
stopOnFailedAssertion?: boolean | undefined; | ||
} | undefined; | ||
id: string; | ||
@@ -521,2 +591,6 @@ test: { | ||
})[] | undefined; | ||
payload?: { | ||
value: string; | ||
key: string; | ||
}[] | undefined; | ||
request: { | ||
@@ -544,2 +618,3 @@ data?: string | undefined; | ||
export type Assertion = z.infer<typeof AssertionSchema>; | ||
export type PayloadType = z.infer<typeof PayloadSchema>; | ||
export type KeyValType = z.infer<typeof KeyValSchema>; | ||
@@ -549,2 +624,3 @@ export type TestRequest = z.infer<typeof RequestSchema>; | ||
export type TestConfig = z.infer<typeof TestConfigSchema>; | ||
export type Config = z.infer<typeof ConfigSchema>; | ||
export interface StepRequest { | ||
@@ -593,2 +669,3 @@ url: string; | ||
results: StepResult[][]; | ||
abortedAt?: number; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TestConfigSchema = exports.TestStepSchema = exports.AssertionSchema = exports.ExtractorSchema = exports.RequestSchema = exports.KeyValSchema = exports.MetaSchema = exports.PrimitiveValueSchema = void 0; | ||
exports.TestConfigSchema = exports.ConfigSchema = exports.TestStepSchema = exports.PayloadSchema = exports.AssertionSchema = exports.ExtractorSchema = exports.RequestSchema = exports.KeyValSchema = exports.MetaSchema = exports.PrimitiveValueSchema = void 0; | ||
const zod_1 = require("zod"); | ||
@@ -47,2 +47,8 @@ const enums_1 = require("./enums"); | ||
]); | ||
exports.PayloadSchema = zod_1.z | ||
.object({ | ||
key: zod_1.z.string(), | ||
value: zod_1.z.union([enums_1.PredefinedPayloadType, zod_1.z.string()]), | ||
}) | ||
.array(); | ||
exports.TestStepSchema = zod_1.z.object({ | ||
@@ -52,3 +58,7 @@ request: exports.RequestSchema, | ||
assert: exports.AssertionSchema.array().optional(), | ||
payload: exports.PayloadSchema.optional(), | ||
}); | ||
exports.ConfigSchema = zod_1.z.object({ | ||
stopOnFailedAssertion: zod_1.z.boolean().optional(), | ||
}); | ||
exports.TestConfigSchema = zod_1.z.object({ | ||
@@ -59,3 +69,4 @@ id: zod_1.z.string().regex(constants_1.IDRegex), | ||
test: exports.TestStepSchema.array(), | ||
config: exports.ConfigSchema.optional(), | ||
}); | ||
//# sourceMappingURL=test.js.map |
{ | ||
"name": "@metlo/testing", | ||
"version": "0.2.15", | ||
"version": "0.2.16", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
951487
85
9208
1