@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.
Files changed (103) hide show
  1. package/LICENSE +40 -0
  2. package/README.md +163 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +117 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/config.d.ts +4 -0
  8. package/dist/core/config.d.ts.map +1 -0
  9. package/dist/core/config.js +128 -0
  10. package/dist/core/config.js.map +1 -0
  11. package/dist/core/diff-analyzer.d.ts +3 -0
  12. package/dist/core/diff-analyzer.d.ts.map +1 -0
  13. package/dist/core/diff-analyzer.js +194 -0
  14. package/dist/core/diff-analyzer.js.map +1 -0
  15. package/dist/core/discover.d.ts +3 -0
  16. package/dist/core/discover.d.ts.map +1 -0
  17. package/dist/core/discover.js +51 -0
  18. package/dist/core/discover.js.map +1 -0
  19. package/dist/core/license.d.ts +13 -0
  20. package/dist/core/license.d.ts.map +1 -0
  21. package/dist/core/license.js +132 -0
  22. package/dist/core/license.js.map +1 -0
  23. package/dist/core/report.d.ts +4 -0
  24. package/dist/core/report.d.ts.map +1 -0
  25. package/dist/core/report.js +95 -0
  26. package/dist/core/report.js.map +1 -0
  27. package/dist/core/runner.d.ts +3 -0
  28. package/dist/core/runner.d.ts.map +1 -0
  29. package/dist/core/runner.js +136 -0
  30. package/dist/core/runner.js.map +1 -0
  31. package/dist/core/test-planner.d.ts +3 -0
  32. package/dist/core/test-planner.d.ts.map +1 -0
  33. package/dist/core/test-planner.js +107 -0
  34. package/dist/core/test-planner.js.map +1 -0
  35. package/dist/integrations/cursor-rule.d.ts +2 -0
  36. package/dist/integrations/cursor-rule.d.ts.map +1 -0
  37. package/dist/integrations/cursor-rule.js +46 -0
  38. package/dist/integrations/cursor-rule.js.map +1 -0
  39. package/dist/integrations/mcp-server.d.ts +67 -0
  40. package/dist/integrations/mcp-server.d.ts.map +1 -0
  41. package/dist/integrations/mcp-server.js +61 -0
  42. package/dist/integrations/mcp-server.js.map +1 -0
  43. package/dist/runners/api/api-runner.d.ts +3 -0
  44. package/dist/runners/api/api-runner.d.ts.map +1 -0
  45. package/dist/runners/api/api-runner.js +258 -0
  46. package/dist/runners/api/api-runner.js.map +1 -0
  47. package/dist/runners/api/endpoint-discovery.d.ts +3 -0
  48. package/dist/runners/api/endpoint-discovery.d.ts.map +1 -0
  49. package/dist/runners/api/endpoint-discovery.js +106 -0
  50. package/dist/runners/api/endpoint-discovery.js.map +1 -0
  51. package/dist/runners/e2e/playwright-runner.d.ts +3 -0
  52. package/dist/runners/e2e/playwright-runner.d.ts.map +1 -0
  53. package/dist/runners/e2e/playwright-runner.js +309 -0
  54. package/dist/runners/e2e/playwright-runner.js.map +1 -0
  55. package/dist/runners/security/dynamic-checker.d.ts +3 -0
  56. package/dist/runners/security/dynamic-checker.d.ts.map +1 -0
  57. package/dist/runners/security/dynamic-checker.js +136 -0
  58. package/dist/runners/security/dynamic-checker.js.map +1 -0
  59. package/dist/runners/security/rules/auth-middleware.d.ts +13 -0
  60. package/dist/runners/security/rules/auth-middleware.d.ts.map +1 -0
  61. package/dist/runners/security/rules/auth-middleware.js +94 -0
  62. package/dist/runners/security/rules/auth-middleware.js.map +1 -0
  63. package/dist/runners/security/rules/config-audit.d.ts +14 -0
  64. package/dist/runners/security/rules/config-audit.d.ts.map +1 -0
  65. package/dist/runners/security/rules/config-audit.js +91 -0
  66. package/dist/runners/security/rules/config-audit.js.map +1 -0
  67. package/dist/runners/security/rules/dep-audit.d.ts +7 -0
  68. package/dist/runners/security/rules/dep-audit.d.ts.map +1 -0
  69. package/dist/runners/security/rules/dep-audit.js +82 -0
  70. package/dist/runners/security/rules/dep-audit.js.map +1 -0
  71. package/dist/runners/security/rules/input-sanitization.d.ts +12 -0
  72. package/dist/runners/security/rules/input-sanitization.d.ts.map +1 -0
  73. package/dist/runners/security/rules/input-sanitization.js +64 -0
  74. package/dist/runners/security/rules/input-sanitization.js.map +1 -0
  75. package/dist/runners/security/rules/rate-limit-audit.d.ts +11 -0
  76. package/dist/runners/security/rules/rate-limit-audit.d.ts.map +1 -0
  77. package/dist/runners/security/rules/rate-limit-audit.js +51 -0
  78. package/dist/runners/security/rules/rate-limit-audit.js.map +1 -0
  79. package/dist/runners/security/rules/secrets-scan.d.ts +4 -0
  80. package/dist/runners/security/rules/secrets-scan.d.ts.map +1 -0
  81. package/dist/runners/security/rules/secrets-scan.js +129 -0
  82. package/dist/runners/security/rules/secrets-scan.js.map +1 -0
  83. package/dist/runners/security/rules/xss-vectors.d.ts +13 -0
  84. package/dist/runners/security/rules/xss-vectors.d.ts.map +1 -0
  85. package/dist/runners/security/rules/xss-vectors.js +76 -0
  86. package/dist/runners/security/rules/xss-vectors.js.map +1 -0
  87. package/dist/runners/security/static-analyzer.d.ts +7 -0
  88. package/dist/runners/security/static-analyzer.d.ts.map +1 -0
  89. package/dist/runners/security/static-analyzer.js +87 -0
  90. package/dist/runners/security/static-analyzer.js.map +1 -0
  91. package/dist/runners/unit/unit-runner.d.ts +3 -0
  92. package/dist/runners/unit/unit-runner.d.ts.map +1 -0
  93. package/dist/runners/unit/unit-runner.js +157 -0
  94. package/dist/runners/unit/unit-runner.js.map +1 -0
  95. package/dist/types.d.ts +153 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +2 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/util/glob.d.ts +2 -0
  100. package/dist/util/glob.d.ts.map +1 -0
  101. package/dist/util/glob.js +32 -0
  102. package/dist/util/glob.js.map +1 -0
  103. 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,3 @@
1
+ import type { QassConfig } from "../types.js";
2
+ export declare function discover(config: QassConfig, projectPath: string): Promise<void>;
3
+ //# sourceMappingURL=discover.d.ts.map
@@ -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,3 @@
1
+ import type { QassConfig, QassReport } from "../types.js";
2
+ export declare function runTests(config: QassConfig, projectPath: string, diffRef: string, type: string, fullScan?: boolean): Promise<QassReport>;
3
+ //# sourceMappingURL=runner.d.ts.map
@@ -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,3 @@
1
+ import type { QassConfig, DiffAnalysis, TestPlan } from "../types.js";
2
+ export declare function createTestPlan(config: QassConfig, projectPath: string, diff: DiffAnalysis): Promise<TestPlan>;
3
+ //# sourceMappingURL=test-planner.d.ts.map
@@ -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