@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,87 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { glob } from "../../util/glob.js";
|
|
4
|
+
import { runAuthMiddlewareRule } from "./rules/auth-middleware.js";
|
|
5
|
+
import { runInputSanitizationRule } from "./rules/input-sanitization.js";
|
|
6
|
+
import { runSecretsScanRule } from "./rules/secrets-scan.js";
|
|
7
|
+
import { runXssVectorsRule } from "./rules/xss-vectors.js";
|
|
8
|
+
import { runConfigAuditRule } from "./rules/config-audit.js";
|
|
9
|
+
import { runRateLimitAuditRule } from "./rules/rate-limit-audit.js";
|
|
10
|
+
import { runDepAuditRule } from "./rules/dep-audit.js";
|
|
11
|
+
const RULES = [
|
|
12
|
+
{ name: "auth-middleware", run: runAuthMiddlewareRule },
|
|
13
|
+
{ name: "input-sanitization", run: runInputSanitizationRule },
|
|
14
|
+
{ name: "secrets-scan", run: runSecretsScanRule },
|
|
15
|
+
{ name: "xss-vectors", run: runXssVectorsRule },
|
|
16
|
+
{ name: "config-audit", run: runConfigAuditRule },
|
|
17
|
+
{ name: "rate-limit-audit", run: runRateLimitAuditRule },
|
|
18
|
+
{ name: "dep-audit", run: runDepAuditRule },
|
|
19
|
+
];
|
|
20
|
+
export async function runStaticAnalysis(config, projectPath, diff) {
|
|
21
|
+
const enabledRules = config.security?.static_rules ?? RULES.map((r) => r.name);
|
|
22
|
+
const threshold = config.security?.severity_threshold ?? "LOW";
|
|
23
|
+
const defaultIgnore = [
|
|
24
|
+
"**/*.test.*",
|
|
25
|
+
"**/*.spec.*",
|
|
26
|
+
"**/node_modules/**",
|
|
27
|
+
"**/runners/security/rules/**",
|
|
28
|
+
"**/runners/security/dynamic-checker.*",
|
|
29
|
+
];
|
|
30
|
+
const ignorePatterns = config.security?.ignore_paths
|
|
31
|
+
? [...config.security.ignore_paths, ...defaultIgnore]
|
|
32
|
+
: defaultIgnore;
|
|
33
|
+
const filesToScan = await getFilesToScan(projectPath, config, diff, ignorePatterns);
|
|
34
|
+
if (filesToScan.length === 0) {
|
|
35
|
+
console.log(chalk.dim(" No files to scan"));
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
console.log(chalk.dim(` Scanning ${filesToScan.length} files...`));
|
|
39
|
+
const findings = [];
|
|
40
|
+
for (const rule of RULES) {
|
|
41
|
+
if (!enabledRules.includes(rule.name))
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
const ruleFindings = await rule.run(filesToScan, config, projectPath);
|
|
45
|
+
findings.push(...ruleFindings);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.log(chalk.dim(` Rule ${rule.name} failed: ${e instanceof Error ? e.message : "unknown"}`));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return findings.filter((f) => severityRank(f.severity) >= severityRank(threshold));
|
|
52
|
+
}
|
|
53
|
+
async function getFilesToScan(projectPath, config, diff, ignorePatterns) {
|
|
54
|
+
const { readFile } = await import("node:fs/promises");
|
|
55
|
+
const { minimatch } = await import("minimatch");
|
|
56
|
+
let filePaths;
|
|
57
|
+
if (diff) {
|
|
58
|
+
filePaths = diff.changedFiles
|
|
59
|
+
.filter((f) => f.status !== "deleted")
|
|
60
|
+
.map((f) => f.path);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
filePaths = await glob("**/*.{ts,tsx,js,jsx,json,yaml,yml}", resolve(projectPath));
|
|
64
|
+
}
|
|
65
|
+
const filtered = filePaths.filter((f) => !ignorePatterns.some((pattern) => minimatch(f, pattern)));
|
|
66
|
+
const files = [];
|
|
67
|
+
for (const fp of filtered) {
|
|
68
|
+
try {
|
|
69
|
+
const content = await readFile(resolve(projectPath, fp), "utf-8");
|
|
70
|
+
files.push({ path: fp, content });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// skip unreadable files
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return files;
|
|
77
|
+
}
|
|
78
|
+
function severityRank(s) {
|
|
79
|
+
const ranks = {
|
|
80
|
+
INFO: 0,
|
|
81
|
+
LOW: 1,
|
|
82
|
+
MEDIUM: 2,
|
|
83
|
+
HIGH: 3,
|
|
84
|
+
};
|
|
85
|
+
return ranks[s] ?? 0;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=static-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-analyzer.js","sourceRoot":"","sources":["../../../src/runners/security/static-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-runner.d.ts","sourceRoot":"","sources":["../../../src/runners/unit/unit-runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI3E,wBAAsB,YAAY,CAChC,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CAkGvB"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { resolve, join, basename } from "node:path";
|
|
3
|
+
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
|
4
|
+
import { execFile } from "node:child_process";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
const exec = promisify(execFile);
|
|
7
|
+
export async function runUnitTests(config, projectPath, diff) {
|
|
8
|
+
const results = [];
|
|
9
|
+
const testableFiles = diff.changedFiles.filter((f) => f.status !== "deleted" &&
|
|
10
|
+
/\.(ts|tsx|js|jsx)$/.test(f.path) &&
|
|
11
|
+
!f.path.includes(".test.") &&
|
|
12
|
+
!f.path.includes(".spec.") &&
|
|
13
|
+
!f.path.includes("node_modules"));
|
|
14
|
+
if (testableFiles.length === 0) {
|
|
15
|
+
console.log(chalk.dim(" No testable files changed"));
|
|
16
|
+
return results;
|
|
17
|
+
}
|
|
18
|
+
const testDir = resolve(projectPath, ".qass", "tests", "unit");
|
|
19
|
+
await mkdir(testDir, { recursive: true });
|
|
20
|
+
let generatedCount = 0;
|
|
21
|
+
for (const file of testableFiles) {
|
|
22
|
+
try {
|
|
23
|
+
const content = await readFile(resolve(projectPath, file.path), "utf-8");
|
|
24
|
+
const testCode = generateTestForFile(file.path, content);
|
|
25
|
+
if (testCode) {
|
|
26
|
+
const testFileName = basename(file.path).replace(/\.(ts|tsx|js|jsx)$/, ".test.ts");
|
|
27
|
+
await writeFile(join(testDir, testFileName), testCode, "utf-8");
|
|
28
|
+
generatedCount++;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// skip files we can't read/generate for
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (generatedCount === 0) {
|
|
36
|
+
console.log(chalk.dim(" No tests generated"));
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
console.log(chalk.dim(` Generated ${generatedCount} test file(s)`));
|
|
40
|
+
try {
|
|
41
|
+
const { stdout, stderr } = await exec("npx", ["vitest", "run", "--reporter=json", testDir], {
|
|
42
|
+
cwd: projectPath,
|
|
43
|
+
timeout: 60000,
|
|
44
|
+
env: { ...process.env, NODE_ENV: "test" },
|
|
45
|
+
});
|
|
46
|
+
const output = stdout || stderr;
|
|
47
|
+
try {
|
|
48
|
+
const vitestResult = JSON.parse(output);
|
|
49
|
+
if (vitestResult.testResults) {
|
|
50
|
+
for (const suite of vitestResult.testResults) {
|
|
51
|
+
for (const test of suite.assertionResults ?? []) {
|
|
52
|
+
results.push({
|
|
53
|
+
name: test.fullName ?? test.title ?? "unknown test",
|
|
54
|
+
type: "unit",
|
|
55
|
+
status: test.status === "passed" ? "passed" : "failed",
|
|
56
|
+
duration: test.duration,
|
|
57
|
+
error: test.failureMessages?.join("\n"),
|
|
58
|
+
file: suite.name,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
results.push({
|
|
66
|
+
name: "Unit test suite",
|
|
67
|
+
type: "unit",
|
|
68
|
+
status: generatedCount > 0 ? "passed" : "skipped",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
const errMsg = e instanceof Error ? e.message : "unknown";
|
|
74
|
+
if (/vitest.*not found|Cannot find/i.test(errMsg)) {
|
|
75
|
+
console.log(chalk.yellow(" Vitest not installed. Run: npm i -D vitest"));
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
results.push({
|
|
79
|
+
name: "Unit test suite",
|
|
80
|
+
type: "unit",
|
|
81
|
+
status: "failed",
|
|
82
|
+
error: errMsg,
|
|
83
|
+
fix: "Check the generated tests in .qass/tests/unit/ for issues.",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return results;
|
|
88
|
+
}
|
|
89
|
+
function generateTestForFile(filePath, content) {
|
|
90
|
+
const exports = extractExports(content);
|
|
91
|
+
if (exports.length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
const isReactComponent = /\b(React|jsx|tsx)\b/.test(content) ||
|
|
94
|
+
/export\s+(?:default\s+)?function\s+\w+.*\(/.test(content) && /</.test(content);
|
|
95
|
+
const lines = [];
|
|
96
|
+
const modulePath = filePath.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
97
|
+
lines.push(`import { describe, it, expect } from "vitest";`);
|
|
98
|
+
if (isReactComponent) {
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push(`describe("${basename(filePath)}", () => {`);
|
|
101
|
+
lines.push(` it("module is importable", async () => {`);
|
|
102
|
+
lines.push(` const mod = await import("${modulePath}").catch(e => e);`);
|
|
103
|
+
lines.push(` expect(mod).toBeDefined();`);
|
|
104
|
+
lines.push(` });`);
|
|
105
|
+
lines.push(`});`);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
lines.push("");
|
|
109
|
+
lines.push(`describe("${basename(filePath)}", () => {`);
|
|
110
|
+
for (const exp of exports) {
|
|
111
|
+
if (exp.type === "function") {
|
|
112
|
+
lines.push(` describe("${exp.name}", () => {`);
|
|
113
|
+
lines.push(` it("is a function", async () => {`);
|
|
114
|
+
lines.push(` const mod = await import("${modulePath}");`);
|
|
115
|
+
lines.push(` expect(typeof mod.${exp.name}).toBe("function");`);
|
|
116
|
+
lines.push(` });`);
|
|
117
|
+
if (exp.params.length === 0) {
|
|
118
|
+
lines.push(` it("runs without errors when called with no args", async () => {`);
|
|
119
|
+
lines.push(` const mod = await import("${modulePath}");`);
|
|
120
|
+
lines.push(` expect(() => mod.${exp.name}()).not.toThrow();`);
|
|
121
|
+
lines.push(` });`);
|
|
122
|
+
}
|
|
123
|
+
lines.push(` });`);
|
|
124
|
+
lines.push("");
|
|
125
|
+
}
|
|
126
|
+
else if (exp.type === "const") {
|
|
127
|
+
lines.push(` it("exports ${exp.name}", async () => {`);
|
|
128
|
+
lines.push(` const mod = await import("${modulePath}");`);
|
|
129
|
+
lines.push(` expect(mod.${exp.name}).toBeDefined();`);
|
|
130
|
+
lines.push(` });`);
|
|
131
|
+
lines.push("");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
lines.push(`});`);
|
|
135
|
+
}
|
|
136
|
+
return lines.join("\n");
|
|
137
|
+
}
|
|
138
|
+
function extractExports(content) {
|
|
139
|
+
const exports = [];
|
|
140
|
+
const funcMatches = content.matchAll(/export\s+(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g);
|
|
141
|
+
for (const m of funcMatches) {
|
|
142
|
+
exports.push({
|
|
143
|
+
name: m[1],
|
|
144
|
+
type: "function",
|
|
145
|
+
params: m[2]
|
|
146
|
+
.split(",")
|
|
147
|
+
.map((p) => p.trim())
|
|
148
|
+
.filter(Boolean),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const constMatches = content.matchAll(/export\s+const\s+(\w+)\s*[=:]/g);
|
|
152
|
+
for (const m of constMatches) {
|
|
153
|
+
exports.push({ name: m[1], type: "const", params: [] });
|
|
154
|
+
}
|
|
155
|
+
return exports;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=unit-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-runner.js","sourceRoot":"","sources":["../../../src/runners/unit/unit-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
export interface QassConfig {
|
|
2
|
+
project: {
|
|
3
|
+
name: string;
|
|
4
|
+
root: string;
|
|
5
|
+
type?: "monorepo" | "standalone";
|
|
6
|
+
};
|
|
7
|
+
services?: Record<string, {
|
|
8
|
+
start: string;
|
|
9
|
+
port: number;
|
|
10
|
+
health?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
}>;
|
|
13
|
+
auth?: {
|
|
14
|
+
provider: "supabase";
|
|
15
|
+
supabase_url: string;
|
|
16
|
+
supabase_anon_key: string;
|
|
17
|
+
};
|
|
18
|
+
test_accounts?: TestAccount[];
|
|
19
|
+
paths?: Record<string, string>;
|
|
20
|
+
route_mounting?: Record<string, string>;
|
|
21
|
+
feature_matrix?: Record<string, string[]>;
|
|
22
|
+
plan_error_codes?: string[];
|
|
23
|
+
security?: SecurityConfig;
|
|
24
|
+
e2e?: E2EConfig;
|
|
25
|
+
flows?: Record<string, FlowDefinition>;
|
|
26
|
+
}
|
|
27
|
+
export interface TestAccount {
|
|
28
|
+
email: string;
|
|
29
|
+
password: string;
|
|
30
|
+
role: string;
|
|
31
|
+
}
|
|
32
|
+
export interface SecurityConfig {
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
severity_threshold?: Severity;
|
|
35
|
+
static_rules?: string[];
|
|
36
|
+
dynamic_checks?: boolean;
|
|
37
|
+
ignore_paths?: string[];
|
|
38
|
+
secrets_allowlist?: string[];
|
|
39
|
+
required_headers?: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface E2EConfig {
|
|
42
|
+
viewports?: Viewport[];
|
|
43
|
+
smoke_crawl?: boolean;
|
|
44
|
+
visual_regression?: boolean;
|
|
45
|
+
visual_threshold?: number;
|
|
46
|
+
mask_selectors?: string[];
|
|
47
|
+
stuck_timeout?: number;
|
|
48
|
+
slow_response?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface Viewport {
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
name: string;
|
|
54
|
+
}
|
|
55
|
+
export interface FlowDefinition {
|
|
56
|
+
as: string;
|
|
57
|
+
steps: FlowStep[];
|
|
58
|
+
}
|
|
59
|
+
export type FlowStep = {
|
|
60
|
+
goto: string;
|
|
61
|
+
} | {
|
|
62
|
+
fill: string;
|
|
63
|
+
} | {
|
|
64
|
+
click: string;
|
|
65
|
+
} | {
|
|
66
|
+
wait: string;
|
|
67
|
+
} | {
|
|
68
|
+
wait_url: string;
|
|
69
|
+
} | {
|
|
70
|
+
assert_visible: string;
|
|
71
|
+
} | {
|
|
72
|
+
assert_hidden: string;
|
|
73
|
+
} | {
|
|
74
|
+
assert_url: string;
|
|
75
|
+
};
|
|
76
|
+
export type Severity = "HIGH" | "MEDIUM" | "LOW" | "INFO";
|
|
77
|
+
export interface FileChange {
|
|
78
|
+
path: string;
|
|
79
|
+
status: "added" | "modified" | "deleted" | "renamed";
|
|
80
|
+
category: FileCategory;
|
|
81
|
+
diff?: string;
|
|
82
|
+
}
|
|
83
|
+
export type FileCategory = "api_route" | "middleware" | "frontend_page" | "component" | "shared_lib" | "migration" | "config" | "other";
|
|
84
|
+
export interface DiffAnalysis {
|
|
85
|
+
changedFiles: FileChange[];
|
|
86
|
+
affectedFeatures: string[];
|
|
87
|
+
affectedRoles: string[];
|
|
88
|
+
changeCategories: FileCategory[];
|
|
89
|
+
}
|
|
90
|
+
export interface Endpoint {
|
|
91
|
+
method: string;
|
|
92
|
+
path: string;
|
|
93
|
+
fullPath: string;
|
|
94
|
+
requiresAuth: boolean;
|
|
95
|
+
requiredRole?: string;
|
|
96
|
+
planGate?: string;
|
|
97
|
+
middlewareChain: string[];
|
|
98
|
+
routeFile: string;
|
|
99
|
+
}
|
|
100
|
+
export interface TestResult {
|
|
101
|
+
name: string;
|
|
102
|
+
type: "api" | "e2e" | "unit" | "security";
|
|
103
|
+
status: "passed" | "failed" | "skipped";
|
|
104
|
+
duration?: number;
|
|
105
|
+
error?: string;
|
|
106
|
+
file?: string;
|
|
107
|
+
line?: number;
|
|
108
|
+
screenshot?: string;
|
|
109
|
+
fix?: string;
|
|
110
|
+
}
|
|
111
|
+
export interface SecurityFinding {
|
|
112
|
+
rule: string;
|
|
113
|
+
severity: Severity;
|
|
114
|
+
file: string;
|
|
115
|
+
line?: number;
|
|
116
|
+
description: string;
|
|
117
|
+
fix: string;
|
|
118
|
+
}
|
|
119
|
+
export interface QassReport {
|
|
120
|
+
timestamp: string;
|
|
121
|
+
scope: {
|
|
122
|
+
filesChanged: number;
|
|
123
|
+
featuresAffected: string[];
|
|
124
|
+
};
|
|
125
|
+
summary: {
|
|
126
|
+
total: number;
|
|
127
|
+
passed: number;
|
|
128
|
+
failed: number;
|
|
129
|
+
skipped: number;
|
|
130
|
+
securityFindings: number;
|
|
131
|
+
};
|
|
132
|
+
results: TestResult[];
|
|
133
|
+
securityFindings: SecurityFinding[];
|
|
134
|
+
}
|
|
135
|
+
export interface TestPlan {
|
|
136
|
+
apiTests: {
|
|
137
|
+
endpoints: Endpoint[];
|
|
138
|
+
accounts: TestAccount[];
|
|
139
|
+
};
|
|
140
|
+
e2eTests: {
|
|
141
|
+
pages: string[];
|
|
142
|
+
accounts: TestAccount[];
|
|
143
|
+
flows: string[];
|
|
144
|
+
};
|
|
145
|
+
unitTests: {
|
|
146
|
+
files: string[];
|
|
147
|
+
};
|
|
148
|
+
securityScan: {
|
|
149
|
+
files: string[];
|
|
150
|
+
dynamicChecks: boolean;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CACf,MAAM,EACN;QACE,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CACF,CAAC;IACF,IAAI,CAAC,EAAE;QACL,QAAQ,EAAE,UAAU,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,aAAa,CAAC,EAAE,WAAW,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kBAAkB,CAAC,EAAE,QAAQ,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GACpB;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAC1B;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3B,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IACrD,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,YAAY,GACZ,eAAe,GACf,WAAW,GACX,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,OAAO,CAAC;AAEZ,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,YAAY,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1C,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;IACF,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE;QAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAC7D,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACxE,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC/B,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3D"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/util/glob.ts"],"names":[],"mappings":"AAIA,wBAAsB,IAAI,CACxB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { minimatch } from "minimatch";
|
|
4
|
+
export async function glob(pattern, rootDir) {
|
|
5
|
+
const matches = [];
|
|
6
|
+
await walkDir(rootDir, rootDir, pattern, matches);
|
|
7
|
+
return matches.sort();
|
|
8
|
+
}
|
|
9
|
+
async function walkDir(dir, rootDir, pattern, matches) {
|
|
10
|
+
try {
|
|
11
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
12
|
+
for (const entry of entries) {
|
|
13
|
+
const fullPath = join(dir, entry.name);
|
|
14
|
+
if (entry.isDirectory()) {
|
|
15
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === "dist") {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
await walkDir(fullPath, rootDir, pattern, matches);
|
|
19
|
+
}
|
|
20
|
+
else if (entry.isFile()) {
|
|
21
|
+
const relPath = relative(rootDir, fullPath).replace(/\\/g, "/");
|
|
22
|
+
if (minimatch(relPath, pattern)) {
|
|
23
|
+
matches.push(relPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// skip inaccessible directories
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/util/glob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,OAAe,EACf,OAAe;IAEf,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,GAAW,EACX,OAAe,EACf,OAAe,EACf,OAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACpF,SAAS;gBACX,CAAC;gBACD,MAAM,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACrD,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAChE,IAAI,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;oBAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qasshq/qass",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "QA + Security Scanner for vibe-coded applications. Your AI writes code. QASS catches what it got wrong.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"qass": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "tsx src/cli.ts",
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"start": "node dist/cli.js",
|
|
18
|
+
"test": "vitest run"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"qa",
|
|
22
|
+
"security",
|
|
23
|
+
"scanner",
|
|
24
|
+
"testing",
|
|
25
|
+
"vibe-coding",
|
|
26
|
+
"ai",
|
|
27
|
+
"cursor",
|
|
28
|
+
"windsurf",
|
|
29
|
+
"copilot",
|
|
30
|
+
"playwright"
|
|
31
|
+
],
|
|
32
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/Dujaun-Paul/QASS.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/Dujaun-Paul/QASS",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/Dujaun-Paul/QASS/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20.11.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"chalk": "^5.4.1",
|
|
46
|
+
"commander": "^13.1.0",
|
|
47
|
+
"minimatch": "^10.0.1",
|
|
48
|
+
"yaml": "^2.7.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^22.13.4",
|
|
52
|
+
"tsx": "^4.19.3",
|
|
53
|
+
"typescript": "^5.7.3",
|
|
54
|
+
"vitest": "^4.0.18"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"playwright": ">=1.40.0",
|
|
58
|
+
"vitest": ">=1.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"playwright": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"vitest": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|