@qasshq/qass 0.1.2
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 +40 -0
- package/README.md +163 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +117 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +128 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/diff-analyzer.d.ts +3 -0
- package/dist/core/diff-analyzer.d.ts.map +1 -0
- package/dist/core/diff-analyzer.js +194 -0
- package/dist/core/diff-analyzer.js.map +1 -0
- package/dist/core/discover.d.ts +3 -0
- package/dist/core/discover.d.ts.map +1 -0
- package/dist/core/discover.js +51 -0
- package/dist/core/discover.js.map +1 -0
- package/dist/core/license.d.ts +13 -0
- package/dist/core/license.d.ts.map +1 -0
- package/dist/core/license.js +132 -0
- package/dist/core/license.js.map +1 -0
- package/dist/core/report.d.ts +4 -0
- package/dist/core/report.d.ts.map +1 -0
- package/dist/core/report.js +95 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/runner.d.ts +3 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +136 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/test-planner.d.ts +3 -0
- package/dist/core/test-planner.d.ts.map +1 -0
- package/dist/core/test-planner.js +107 -0
- package/dist/core/test-planner.js.map +1 -0
- package/dist/integrations/cursor-rule.d.ts +2 -0
- package/dist/integrations/cursor-rule.d.ts.map +1 -0
- package/dist/integrations/cursor-rule.js +46 -0
- package/dist/integrations/cursor-rule.js.map +1 -0
- package/dist/integrations/mcp-server.d.ts +67 -0
- package/dist/integrations/mcp-server.d.ts.map +1 -0
- package/dist/integrations/mcp-server.js +61 -0
- package/dist/integrations/mcp-server.js.map +1 -0
- package/dist/runners/api/api-runner.d.ts +3 -0
- package/dist/runners/api/api-runner.d.ts.map +1 -0
- package/dist/runners/api/api-runner.js +258 -0
- package/dist/runners/api/api-runner.js.map +1 -0
- package/dist/runners/api/endpoint-discovery.d.ts +3 -0
- package/dist/runners/api/endpoint-discovery.d.ts.map +1 -0
- package/dist/runners/api/endpoint-discovery.js +106 -0
- package/dist/runners/api/endpoint-discovery.js.map +1 -0
- package/dist/runners/e2e/playwright-runner.d.ts +3 -0
- package/dist/runners/e2e/playwright-runner.d.ts.map +1 -0
- package/dist/runners/e2e/playwright-runner.js +309 -0
- package/dist/runners/e2e/playwright-runner.js.map +1 -0
- package/dist/runners/security/dynamic-checker.d.ts +3 -0
- package/dist/runners/security/dynamic-checker.d.ts.map +1 -0
- package/dist/runners/security/dynamic-checker.js +136 -0
- package/dist/runners/security/dynamic-checker.js.map +1 -0
- package/dist/runners/security/rules/auth-middleware.d.ts +13 -0
- package/dist/runners/security/rules/auth-middleware.d.ts.map +1 -0
- package/dist/runners/security/rules/auth-middleware.js +94 -0
- package/dist/runners/security/rules/auth-middleware.js.map +1 -0
- package/dist/runners/security/rules/config-audit.d.ts +14 -0
- package/dist/runners/security/rules/config-audit.d.ts.map +1 -0
- package/dist/runners/security/rules/config-audit.js +91 -0
- package/dist/runners/security/rules/config-audit.js.map +1 -0
- package/dist/runners/security/rules/dep-audit.d.ts +7 -0
- package/dist/runners/security/rules/dep-audit.d.ts.map +1 -0
- package/dist/runners/security/rules/dep-audit.js +82 -0
- package/dist/runners/security/rules/dep-audit.js.map +1 -0
- package/dist/runners/security/rules/input-sanitization.d.ts +12 -0
- package/dist/runners/security/rules/input-sanitization.d.ts.map +1 -0
- package/dist/runners/security/rules/input-sanitization.js +64 -0
- package/dist/runners/security/rules/input-sanitization.js.map +1 -0
- package/dist/runners/security/rules/rate-limit-audit.d.ts +11 -0
- package/dist/runners/security/rules/rate-limit-audit.d.ts.map +1 -0
- package/dist/runners/security/rules/rate-limit-audit.js +51 -0
- package/dist/runners/security/rules/rate-limit-audit.js.map +1 -0
- package/dist/runners/security/rules/secrets-scan.d.ts +4 -0
- package/dist/runners/security/rules/secrets-scan.d.ts.map +1 -0
- package/dist/runners/security/rules/secrets-scan.js +129 -0
- package/dist/runners/security/rules/secrets-scan.js.map +1 -0
- package/dist/runners/security/rules/xss-vectors.d.ts +13 -0
- package/dist/runners/security/rules/xss-vectors.d.ts.map +1 -0
- package/dist/runners/security/rules/xss-vectors.js +76 -0
- package/dist/runners/security/rules/xss-vectors.js.map +1 -0
- package/dist/runners/security/static-analyzer.d.ts +7 -0
- package/dist/runners/security/static-analyzer.d.ts.map +1 -0
- package/dist/runners/security/static-analyzer.js +87 -0
- package/dist/runners/security/static-analyzer.js.map +1 -0
- package/dist/runners/unit/unit-runner.d.ts +3 -0
- package/dist/runners/unit/unit-runner.d.ts.map +1 -0
- package/dist/runners/unit/unit-runner.js +157 -0
- package/dist/runners/unit/unit-runner.js.map +1 -0
- package/dist/types.d.ts +153 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/util/glob.d.ts +2 -0
- package/dist/util/glob.d.ts.map +1 -0
- package/dist/util/glob.js +32 -0
- package/dist/util/glob.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-analyzer.js","sourceRoot":"","sources":["../../src/core/diff-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/core/discover.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAsDf"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { glob } from "../util/glob.js";
|
|
4
|
+
import { discoverEndpoints } from "../runners/api/endpoint-discovery.js";
|
|
5
|
+
export async function discover(config, projectPath) {
|
|
6
|
+
const root = resolve(projectPath, config.project.root);
|
|
7
|
+
if (config.paths?.api_routes) {
|
|
8
|
+
console.log(chalk.blue("\n▸ API Endpoints"));
|
|
9
|
+
const endpoints = await discoverEndpoints(config, projectPath);
|
|
10
|
+
if (endpoints.length === 0) {
|
|
11
|
+
console.log(chalk.dim(" No endpoints discovered"));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
for (const ep of endpoints) {
|
|
15
|
+
const method = ep.method.padEnd(7);
|
|
16
|
+
const auth = ep.requiresAuth ? chalk.green("auth") : chalk.red("public");
|
|
17
|
+
const role = ep.requiredRole ? chalk.yellow(ep.requiredRole) : "";
|
|
18
|
+
const gate = ep.planGate ? chalk.magenta(ep.planGate) : "";
|
|
19
|
+
console.log(` ${chalk.cyan(method)} ${ep.fullPath} ${auth} ${role} ${gate}`.trimEnd());
|
|
20
|
+
}
|
|
21
|
+
console.log(chalk.dim(`\n ${endpoints.length} endpoints discovered`));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (config.paths?.frontend_pages) {
|
|
25
|
+
console.log(chalk.blue("\n▸ Frontend Pages"));
|
|
26
|
+
const pages = await glob(config.paths.frontend_pages, root);
|
|
27
|
+
if (pages.length === 0) {
|
|
28
|
+
console.log(chalk.dim(" No pages found"));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
for (const p of pages) {
|
|
32
|
+
console.log(` ${chalk.cyan(p)}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(chalk.dim(`\n ${pages.length} pages found`));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (config.test_accounts && config.test_accounts.length > 0) {
|
|
38
|
+
console.log(chalk.blue("\n▸ Test Accounts"));
|
|
39
|
+
for (const account of config.test_accounts) {
|
|
40
|
+
console.log(` ${chalk.cyan(account.role)} ${chalk.dim(`(${account.email})`)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (config.feature_matrix) {
|
|
44
|
+
console.log(chalk.blue("\n▸ Feature Matrix"));
|
|
45
|
+
for (const [feature, roles] of Object.entries(config.feature_matrix)) {
|
|
46
|
+
console.log(` ${chalk.cyan(feature)} ${chalk.dim(`→ ${roles.join(", ")}`)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
console.log("");
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/core/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Plan = "free" | "pro" | "team";
|
|
2
|
+
interface LicenseStatus {
|
|
3
|
+
plan: Plan;
|
|
4
|
+
valid: boolean;
|
|
5
|
+
key?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function activateLicense(key: string): Promise<boolean>;
|
|
8
|
+
export declare function deactivateLicense(): Promise<void>;
|
|
9
|
+
export declare function checkLicense(): Promise<LicenseStatus>;
|
|
10
|
+
export declare function showStatus(): Promise<void>;
|
|
11
|
+
export declare function requirePlan(current: Plan, minimum: Plan): boolean;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=license.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../../src/core/license.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAS3C,UAAU,aAAa;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAsBD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqCnE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BvD;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAoC3D;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAahD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,GAAG,OAAO,CAGjE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, unlink } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
const LICENSE_DIR = join(homedir(), ".qass");
|
|
6
|
+
const LICENSE_FILE = join(LICENSE_DIR, "license.json");
|
|
7
|
+
const REVALIDATE_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
8
|
+
const LEMON_SQUEEZY_API = "https://api.lemonsqueezy.com/v1";
|
|
9
|
+
async function readLicenseFile() {
|
|
10
|
+
try {
|
|
11
|
+
const raw = await readFile(LICENSE_FILE, "utf-8");
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function writeLicenseFile(data) {
|
|
19
|
+
await mkdir(LICENSE_DIR, { recursive: true });
|
|
20
|
+
await writeFile(LICENSE_FILE, JSON.stringify(data, null, 2));
|
|
21
|
+
}
|
|
22
|
+
export async function activateLicense(key) {
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(`${LEMON_SQUEEZY_API}/licenses/activate`, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({
|
|
28
|
+
license_key: key,
|
|
29
|
+
instance_name: `qass-${homedir()}`,
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok) {
|
|
33
|
+
const body = await res.json().catch(() => ({}));
|
|
34
|
+
const msg = body?.error ?? `HTTP ${res.status}`;
|
|
35
|
+
console.log(chalk.red(` Activation failed: ${msg}`));
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const body = (await res.json());
|
|
39
|
+
const variant = body.meta?.variant_name?.toLowerCase() ?? "";
|
|
40
|
+
const plan = variant.includes("team") ? "team" : "pro";
|
|
41
|
+
await writeLicenseFile({
|
|
42
|
+
key,
|
|
43
|
+
plan,
|
|
44
|
+
validatedAt: new Date().toISOString(),
|
|
45
|
+
instanceId: body.activated?.id ?? body.instance?.id ?? "local",
|
|
46
|
+
});
|
|
47
|
+
console.log(chalk.green(` License activated. Plan: ${plan}`));
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
console.log(chalk.red(` Activation failed: ${err instanceof Error ? err.message : "network error"}`));
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function deactivateLicense() {
|
|
56
|
+
const data = await readLicenseFile();
|
|
57
|
+
if (!data) {
|
|
58
|
+
console.log(chalk.dim(" No license found."));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
await fetch(`${LEMON_SQUEEZY_API}/licenses/deactivate`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
headers: { "Content-Type": "application/json" },
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
license_key: data.key,
|
|
67
|
+
instance_id: data.instanceId,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// best-effort remote deactivation
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await unlink(LICENSE_FILE);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// file may not exist
|
|
79
|
+
}
|
|
80
|
+
console.log(chalk.dim(" License deactivated."));
|
|
81
|
+
}
|
|
82
|
+
export async function checkLicense() {
|
|
83
|
+
const data = await readLicenseFile();
|
|
84
|
+
if (!data) {
|
|
85
|
+
return { plan: "free", valid: true };
|
|
86
|
+
}
|
|
87
|
+
const age = Date.now() - new Date(data.validatedAt).getTime();
|
|
88
|
+
if (age < REVALIDATE_INTERVAL_MS) {
|
|
89
|
+
return { plan: data.plan, valid: true, key: data.key };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const res = await fetch(`${LEMON_SQUEEZY_API}/licenses/validate`, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "Content-Type": "application/json" },
|
|
95
|
+
body: JSON.stringify({
|
|
96
|
+
license_key: data.key,
|
|
97
|
+
instance_id: data.instanceId,
|
|
98
|
+
}),
|
|
99
|
+
signal: AbortSignal.timeout(5000),
|
|
100
|
+
});
|
|
101
|
+
if (res.ok) {
|
|
102
|
+
const body = (await res.json());
|
|
103
|
+
if (body.valid) {
|
|
104
|
+
await writeLicenseFile({ ...data, validatedAt: new Date().toISOString() });
|
|
105
|
+
return { plan: data.plan, valid: true, key: data.key };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { plan: "free", valid: false, key: data.key };
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Network error -- allow cached license to work offline
|
|
112
|
+
return { plan: data.plan, valid: true, key: data.key };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function showStatus() {
|
|
116
|
+
const status = await checkLicense();
|
|
117
|
+
console.log("");
|
|
118
|
+
console.log(chalk.bold(" QASS License Status"));
|
|
119
|
+
console.log(chalk.dim(" ─────────────────────"));
|
|
120
|
+
console.log(` Plan: ${chalk.bold(status.plan.toUpperCase())}`);
|
|
121
|
+
console.log(` Valid: ${status.valid ? chalk.green("yes") : chalk.red("expired")}`);
|
|
122
|
+
if (status.key) {
|
|
123
|
+
const masked = status.key.slice(0, 8) + "••••••••";
|
|
124
|
+
console.log(` Key: ${chalk.dim(masked)}`);
|
|
125
|
+
}
|
|
126
|
+
console.log("");
|
|
127
|
+
}
|
|
128
|
+
export function requirePlan(current, minimum) {
|
|
129
|
+
const rank = { free: 0, pro: 1, team: 2 };
|
|
130
|
+
return rank[current] >= rank[minimum];
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/core/license.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DiffAnalysis, TestResult, SecurityFinding, QassReport } from "../types.js";
|
|
2
|
+
export declare function generateReport(diff: DiffAnalysis, results: TestResult[], findings: SecurityFinding[]): QassReport;
|
|
3
|
+
export declare function writeReport(projectPath: string, report: QassReport): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,eAAe,EACf,UAAU,EACX,MAAM,aAAa,CAAC;AAErB,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,UAAU,EAAE,EACrB,QAAQ,EAAE,eAAe,EAAE,GAC1B,UAAU,CAiBZ;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { resolve, join } from "node:path";
|
|
3
|
+
export function generateReport(diff, results, findings) {
|
|
4
|
+
return {
|
|
5
|
+
timestamp: new Date().toISOString(),
|
|
6
|
+
scope: {
|
|
7
|
+
filesChanged: diff.changedFiles.length,
|
|
8
|
+
featuresAffected: diff.affectedFeatures,
|
|
9
|
+
},
|
|
10
|
+
summary: {
|
|
11
|
+
total: results.length,
|
|
12
|
+
passed: results.filter((r) => r.status === "passed").length,
|
|
13
|
+
failed: results.filter((r) => r.status === "failed").length,
|
|
14
|
+
skipped: results.filter((r) => r.status === "skipped").length,
|
|
15
|
+
securityFindings: findings.length,
|
|
16
|
+
},
|
|
17
|
+
results,
|
|
18
|
+
securityFindings: findings,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function writeReport(projectPath, report) {
|
|
22
|
+
const dir = resolve(projectPath, ".qass", "results");
|
|
23
|
+
await mkdir(dir, { recursive: true });
|
|
24
|
+
await writeFile(join(dir, "latest.json"), JSON.stringify(report, null, 2), "utf-8");
|
|
25
|
+
const md = renderMarkdown(report);
|
|
26
|
+
await writeFile(join(dir, "latest.md"), md, "utf-8");
|
|
27
|
+
}
|
|
28
|
+
function renderMarkdown(report) {
|
|
29
|
+
const lines = [];
|
|
30
|
+
lines.push("## QASS Report");
|
|
31
|
+
lines.push(`- **Time**: ${report.timestamp}`);
|
|
32
|
+
lines.push(`- **Scope**: ${report.scope.filesChanged} file${report.scope.filesChanged !== 1 ? "s" : ""} changed`);
|
|
33
|
+
if (report.scope.featuresAffected.length > 0) {
|
|
34
|
+
lines.push(`- **Features affected**: ${report.scope.featuresAffected.join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push(`- **Results**: ${report.summary.passed} passed, ${report.summary.failed} failed, ${report.summary.skipped} skipped`);
|
|
37
|
+
if (report.summary.securityFindings > 0) {
|
|
38
|
+
const high = report.securityFindings.filter((f) => f.severity === "HIGH").length;
|
|
39
|
+
const med = report.securityFindings.filter((f) => f.severity === "MEDIUM").length;
|
|
40
|
+
const low = report.securityFindings.filter((f) => f.severity === "LOW").length;
|
|
41
|
+
lines.push(`- **Security**: ${report.summary.securityFindings} findings (${high} HIGH, ${med} MEDIUM, ${low} LOW)`);
|
|
42
|
+
}
|
|
43
|
+
lines.push("");
|
|
44
|
+
if (report.securityFindings.length > 0) {
|
|
45
|
+
lines.push("### Security Findings");
|
|
46
|
+
lines.push("");
|
|
47
|
+
for (const f of report.securityFindings) {
|
|
48
|
+
lines.push(`#### ${f.severity}: ${f.rule} — ${f.file}${f.line ? `:${f.line}` : ""}`);
|
|
49
|
+
lines.push(`**Issue**: ${f.description}`);
|
|
50
|
+
lines.push(`**Fix**: ${f.fix}`);
|
|
51
|
+
lines.push("");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const failed = report.results.filter((r) => r.status === "failed");
|
|
55
|
+
if (failed.length > 0) {
|
|
56
|
+
lines.push("### Test Failures");
|
|
57
|
+
lines.push("");
|
|
58
|
+
for (const r of failed) {
|
|
59
|
+
lines.push(`#### ${r.type.toUpperCase()} FAILED: ${r.name}`);
|
|
60
|
+
if (r.file)
|
|
61
|
+
lines.push(`**File**: ${r.file}${r.line ? `:${r.line}` : ""}`);
|
|
62
|
+
if (r.error)
|
|
63
|
+
lines.push(`**Error**: ${r.error}`);
|
|
64
|
+
if (r.fix)
|
|
65
|
+
lines.push(`**Fix**: ${r.fix}`);
|
|
66
|
+
if (r.screenshot)
|
|
67
|
+
lines.push(`**Screenshot**: ${r.screenshot}`);
|
|
68
|
+
lines.push("");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const passed = report.results.filter((r) => r.status === "passed");
|
|
72
|
+
if (passed.length > 0) {
|
|
73
|
+
lines.push("### Passed Tests");
|
|
74
|
+
lines.push("");
|
|
75
|
+
const byType = groupBy(passed, (r) => r.type);
|
|
76
|
+
for (const [type, tests] of Object.entries(byType)) {
|
|
77
|
+
lines.push(`- **${type.toUpperCase()}**: ${tests.length} passed`);
|
|
78
|
+
}
|
|
79
|
+
lines.push("");
|
|
80
|
+
}
|
|
81
|
+
if (report.summary.failed === 0 && report.securityFindings.length === 0) {
|
|
82
|
+
lines.push("---");
|
|
83
|
+
lines.push("**All clear. Safe to ship.**");
|
|
84
|
+
}
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
function groupBy(arr, fn) {
|
|
88
|
+
const groups = {};
|
|
89
|
+
for (const item of arr) {
|
|
90
|
+
const key = fn(item);
|
|
91
|
+
(groups[key] ??= []).push(item);
|
|
92
|
+
}
|
|
93
|
+
return groups;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAA+B,MAAM,aAAa,CAAC;AAMvF,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,UAAQ,GACf,OAAO,CAAC,UAAU,CAAC,CAuKrB"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { analyzeDiff } from "./diff-analyzer.js";
|
|
3
|
+
import { generateReport, writeReport } from "./report.js";
|
|
4
|
+
import { checkLicense, requirePlan } from "./license.js";
|
|
5
|
+
export async function runTests(config, projectPath, diffRef, type, fullScan = false) {
|
|
6
|
+
const startTime = Date.now();
|
|
7
|
+
const results = [];
|
|
8
|
+
const findings = [];
|
|
9
|
+
const license = await checkLicense();
|
|
10
|
+
const plan = license.plan;
|
|
11
|
+
const diffAnalysis = await analyzeDiff(projectPath, diffRef, config);
|
|
12
|
+
if (diffAnalysis.changedFiles.length === 0 && !fullScan) {
|
|
13
|
+
console.log(chalk.yellow("No changes detected. Nothing to test."));
|
|
14
|
+
const report = generateReport(diffAnalysis, results, findings);
|
|
15
|
+
await writeReport(projectPath, report);
|
|
16
|
+
return report;
|
|
17
|
+
}
|
|
18
|
+
if (fullScan) {
|
|
19
|
+
console.log(chalk.dim(" Full scan mode — analyzing all files"));
|
|
20
|
+
}
|
|
21
|
+
const fileCount = diffAnalysis.changedFiles.length;
|
|
22
|
+
const categories = [...new Set(diffAnalysis.changeCategories)];
|
|
23
|
+
console.log(chalk.dim(` ${fileCount} file${fileCount !== 1 ? "s" : ""} changed [${categories.join(", ")}]`));
|
|
24
|
+
if (diffAnalysis.affectedFeatures.length > 0) {
|
|
25
|
+
console.log(chalk.dim(` Affected features: ${diffAnalysis.affectedFeatures.join(", ")}`));
|
|
26
|
+
}
|
|
27
|
+
const shouldRun = (t) => type === "all" || type === t;
|
|
28
|
+
if (shouldRun("security")) {
|
|
29
|
+
console.log(chalk.blue("\n▸ Security Scan"));
|
|
30
|
+
try {
|
|
31
|
+
const { runStaticAnalysis } = await import("../runners/security/static-analyzer.js");
|
|
32
|
+
const diffForScan = fullScan ? undefined : diffAnalysis;
|
|
33
|
+
const staticFindings = await runStaticAnalysis(config, projectPath, diffForScan);
|
|
34
|
+
findings.push(...staticFindings);
|
|
35
|
+
const high = staticFindings.filter((f) => f.severity === "HIGH").length;
|
|
36
|
+
const med = staticFindings.filter((f) => f.severity === "MEDIUM").length;
|
|
37
|
+
const low = staticFindings.filter((f) => f.severity === "LOW").length;
|
|
38
|
+
console.log(` Static: ${chalk.red(`${high} HIGH`)} ${chalk.yellow(`${med} MEDIUM`)} ${chalk.dim(`${low} LOW`)}`);
|
|
39
|
+
if (config.security?.dynamic_checks !== false && requirePlan(plan, "pro")) {
|
|
40
|
+
try {
|
|
41
|
+
const { runDynamicSecurityChecks } = await import("../runners/security/dynamic-checker.js");
|
|
42
|
+
const dynamicFindings = await runDynamicSecurityChecks(config, projectPath);
|
|
43
|
+
findings.push(...dynamicFindings);
|
|
44
|
+
if (dynamicFindings.length > 0) {
|
|
45
|
+
const dHigh = dynamicFindings.filter((f) => f.severity === "HIGH").length;
|
|
46
|
+
const dMed = dynamicFindings.filter((f) => f.severity === "MEDIUM").length;
|
|
47
|
+
console.log(` Dynamic: ${chalk.red(`${dHigh} HIGH`)} ${chalk.yellow(`${dMed} MEDIUM`)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// dynamic checks skipped
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else if (config.security?.dynamic_checks !== false && !requirePlan(plan, "pro")) {
|
|
55
|
+
console.log(chalk.dim(" Dynamic checks require Pro plan"));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.log(chalk.red(" Security scan failed:"), e instanceof Error ? e.message : "unknown error");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (shouldRun("api")) {
|
|
63
|
+
if (requirePlan(plan, "pro")) {
|
|
64
|
+
console.log(chalk.blue("\n▸ API Tests"));
|
|
65
|
+
try {
|
|
66
|
+
const { runApiTests } = await import("../runners/api/api-runner.js");
|
|
67
|
+
const apiResults = await runApiTests(config, projectPath, diffAnalysis);
|
|
68
|
+
results.push(...apiResults);
|
|
69
|
+
printResultsSummary(apiResults);
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
console.log(chalk.red(" API tests failed:"), e instanceof Error ? e.message : "unknown error");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(chalk.blue("\n▸ API Tests") + chalk.dim(" (Pro plan required)"));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (shouldRun("e2e") || shouldRun("smoke")) {
|
|
80
|
+
console.log(chalk.blue("\n▸ E2E Tests"));
|
|
81
|
+
try {
|
|
82
|
+
const { runE2ETests } = await import("../runners/e2e/playwright-runner.js");
|
|
83
|
+
const smokeOnly = type === "smoke";
|
|
84
|
+
const e2eResults = await runE2ETests(config, projectPath, diffAnalysis, smokeOnly);
|
|
85
|
+
results.push(...e2eResults);
|
|
86
|
+
printResultsSummary(e2eResults);
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
console.log(chalk.red(" E2E tests failed:"), e instanceof Error ? e.message : "unknown error");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (shouldRun("unit")) {
|
|
93
|
+
console.log(chalk.blue("\n▸ Unit Tests"));
|
|
94
|
+
try {
|
|
95
|
+
const { runUnitTests } = await import("../runners/unit/unit-runner.js");
|
|
96
|
+
const unitResults = await runUnitTests(config, projectPath, diffAnalysis);
|
|
97
|
+
results.push(...unitResults);
|
|
98
|
+
printResultsSummary(unitResults);
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
console.log(chalk.red(" Unit tests failed:"), e instanceof Error ? e.message : "unknown error");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
105
|
+
const report = generateReport(diffAnalysis, results, findings);
|
|
106
|
+
await writeReport(projectPath, report);
|
|
107
|
+
console.log(chalk.blue(`\n━━━ QASS Report ━━━`));
|
|
108
|
+
const passed = results.filter((r) => r.status === "passed").length;
|
|
109
|
+
const failed = results.filter((r) => r.status === "failed").length;
|
|
110
|
+
const secHigh = findings.filter((f) => f.severity === "HIGH").length;
|
|
111
|
+
if (failed === 0 && secHigh === 0) {
|
|
112
|
+
console.log(chalk.green(` ✓ All clear — ${passed} passed, ${findings.length} findings`));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
if (failed > 0)
|
|
116
|
+
console.log(chalk.red(` ✗ ${failed} test${failed !== 1 ? "s" : ""} failed`));
|
|
117
|
+
if (secHigh > 0)
|
|
118
|
+
console.log(chalk.red(` ✗ ${secHigh} HIGH severity finding${secHigh !== 1 ? "s" : ""}`));
|
|
119
|
+
}
|
|
120
|
+
console.log(chalk.dim(` ${elapsed}s | Report: .qass/results/latest.md\n`));
|
|
121
|
+
return report;
|
|
122
|
+
}
|
|
123
|
+
function printResultsSummary(results) {
|
|
124
|
+
const passed = results.filter((r) => r.status === "passed").length;
|
|
125
|
+
const failed = results.filter((r) => r.status === "failed").length;
|
|
126
|
+
const skipped = results.filter((r) => r.status === "skipped").length;
|
|
127
|
+
const parts = [];
|
|
128
|
+
if (passed > 0)
|
|
129
|
+
parts.push(chalk.green(`${passed} passed`));
|
|
130
|
+
if (failed > 0)
|
|
131
|
+
parts.push(chalk.red(`${failed} failed`));
|
|
132
|
+
if (skipped > 0)
|
|
133
|
+
parts.push(chalk.dim(`${skipped} skipped`));
|
|
134
|
+
console.log(` ${parts.join(", ")}`);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-planner.d.ts","sourceRoot":"","sources":["../../src/core/test-planner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EAGT,MAAM,aAAa,CAAC;AAGrB,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,QAAQ,CAAC,CA2GnB"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { discoverEndpoints } from "../runners/api/endpoint-discovery.js";
|
|
2
|
+
export async function createTestPlan(config, projectPath, diff) {
|
|
3
|
+
const endpoints = await discoverEndpoints(config, projectPath);
|
|
4
|
+
const accounts = selectAccounts(config, diff);
|
|
5
|
+
const categories = new Set(diff.changeCategories);
|
|
6
|
+
const plan = {
|
|
7
|
+
apiTests: { endpoints: [], accounts: [] },
|
|
8
|
+
e2eTests: { pages: [], accounts: [], flows: [] },
|
|
9
|
+
unitTests: { files: [] },
|
|
10
|
+
securityScan: { files: [], dynamicChecks: false },
|
|
11
|
+
};
|
|
12
|
+
plan.securityScan.files = diff.changedFiles
|
|
13
|
+
.filter((f) => f.status !== "deleted")
|
|
14
|
+
.map((f) => f.path);
|
|
15
|
+
if (categories.has("api_route")) {
|
|
16
|
+
const changedRouteFiles = diff.changedFiles
|
|
17
|
+
.filter((f) => f.category === "api_route")
|
|
18
|
+
.map((f) => f.path);
|
|
19
|
+
plan.apiTests.endpoints = endpoints.filter((ep) => changedRouteFiles.some((f) => ep.routeFile.includes(f) || f.includes(ep.routeFile)));
|
|
20
|
+
plan.apiTests.accounts = accounts;
|
|
21
|
+
plan.securityScan.dynamicChecks = true;
|
|
22
|
+
}
|
|
23
|
+
if (categories.has("middleware")) {
|
|
24
|
+
const changedMiddleware = diff.changedFiles
|
|
25
|
+
.filter((f) => f.category === "middleware")
|
|
26
|
+
.map((f) => f.path);
|
|
27
|
+
const affectsAuth = changedMiddleware.some((f) => /auth|planGate|requireCourier|requireAdmin/i.test(f));
|
|
28
|
+
if (affectsAuth) {
|
|
29
|
+
plan.apiTests.endpoints = endpoints;
|
|
30
|
+
plan.apiTests.accounts = accounts;
|
|
31
|
+
}
|
|
32
|
+
plan.securityScan.dynamicChecks = true;
|
|
33
|
+
}
|
|
34
|
+
if (categories.has("frontend_page")) {
|
|
35
|
+
plan.e2eTests.pages = diff.changedFiles
|
|
36
|
+
.filter((f) => f.category === "frontend_page")
|
|
37
|
+
.map((f) => filePathToRoute(f.path));
|
|
38
|
+
plan.e2eTests.accounts = accounts;
|
|
39
|
+
}
|
|
40
|
+
if (categories.has("component")) {
|
|
41
|
+
const changedComponents = diff.changedFiles
|
|
42
|
+
.filter((f) => f.category === "component")
|
|
43
|
+
.map((f) => f.path);
|
|
44
|
+
plan.unitTests.files.push(...changedComponents);
|
|
45
|
+
plan.e2eTests.pages = [
|
|
46
|
+
...new Set([
|
|
47
|
+
...plan.e2eTests.pages,
|
|
48
|
+
...findPagesUsingComponents(changedComponents, config),
|
|
49
|
+
]),
|
|
50
|
+
];
|
|
51
|
+
plan.e2eTests.accounts = accounts;
|
|
52
|
+
}
|
|
53
|
+
if (categories.has("shared_lib")) {
|
|
54
|
+
plan.apiTests.endpoints = endpoints;
|
|
55
|
+
plan.apiTests.accounts = accounts;
|
|
56
|
+
plan.unitTests.files.push(...diff.changedFiles
|
|
57
|
+
.filter((f) => f.category === "shared_lib")
|
|
58
|
+
.map((f) => f.path));
|
|
59
|
+
plan.securityScan.dynamicChecks = true;
|
|
60
|
+
}
|
|
61
|
+
if (categories.has("migration")) {
|
|
62
|
+
plan.apiTests.endpoints = endpoints;
|
|
63
|
+
plan.apiTests.accounts = accounts;
|
|
64
|
+
plan.securityScan.dynamicChecks = true;
|
|
65
|
+
}
|
|
66
|
+
if (categories.has("config")) {
|
|
67
|
+
plan.securityScan.dynamicChecks = true;
|
|
68
|
+
}
|
|
69
|
+
if (config.flows) {
|
|
70
|
+
const affectedFlows = [];
|
|
71
|
+
for (const [name, flow] of Object.entries(config.flows)) {
|
|
72
|
+
const flowPages = flow.steps
|
|
73
|
+
.filter((s) => "goto" in s)
|
|
74
|
+
.map((s) => s.goto);
|
|
75
|
+
const overlaps = plan.e2eTests.pages.some((p) => flowPages.some((fp) => p.includes(fp) || fp.includes(p)));
|
|
76
|
+
if (overlaps)
|
|
77
|
+
affectedFlows.push(name);
|
|
78
|
+
}
|
|
79
|
+
plan.e2eTests.flows = affectedFlows;
|
|
80
|
+
}
|
|
81
|
+
return plan;
|
|
82
|
+
}
|
|
83
|
+
function selectAccounts(config, diff) {
|
|
84
|
+
const allAccounts = config.test_accounts ?? [];
|
|
85
|
+
if (allAccounts.length === 0)
|
|
86
|
+
return [];
|
|
87
|
+
const neededRoles = new Set(diff.affectedRoles);
|
|
88
|
+
if (neededRoles.size === 0)
|
|
89
|
+
return allAccounts;
|
|
90
|
+
const selected = allAccounts.filter((a) => neededRoles.has(a.role));
|
|
91
|
+
const demoAccount = allAccounts.find((a) => a.role === "demo");
|
|
92
|
+
if (demoAccount && !selected.includes(demoAccount)) {
|
|
93
|
+
selected.push(demoAccount);
|
|
94
|
+
}
|
|
95
|
+
return selected.length > 0 ? selected : allAccounts;
|
|
96
|
+
}
|
|
97
|
+
function filePathToRoute(filePath) {
|
|
98
|
+
return filePath
|
|
99
|
+
.replace(/.*app\//, "/")
|
|
100
|
+
.replace(/\/page\.(tsx|jsx|ts|js)$/, "")
|
|
101
|
+
.replace(/\[([^\]]+)\]/g, "test-$1") || "/";
|
|
102
|
+
}
|
|
103
|
+
function findPagesUsingComponents(_componentPaths, _config) {
|
|
104
|
+
// TODO: static import analysis to find pages that import changed components
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=test-planner.js.map
|