@dailephd/my-dev-kit-lab 0.2.0 → 0.2.1
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/README.md +5 -3
- package/dist/scripts/security/resolveToolRoot.js +16 -0
- package/dist/scripts/security/runCodeql.js +2 -1
- package/dist/scripts/security/runDependencyChecks.js +2 -1
- package/dist/scripts/security/runPackageChecks.js +2 -1
- package/dist/scripts/security/runSemgrep.js +2 -1
- package/dist/scripts/security/validate.js +2 -1
- package/dist/src/core/localProjectTarget.js +4 -0
- package/dist/src/core/runMeasuredCommand.js +10 -6
- package/dist/src/securityValidation/report/renderSecurityReport.js +20 -1
- package/dist/src/securityValidation/validate/runCliSecuritySuiteCheck.js +124 -0
- package/dist/src/securityValidation/validate/runSecurityValidation.js +9 -40
- package/package.json +24 -20
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
my-dev-kit-lab is the experiment, evidence, reporting, and demo companion for [my-dev-kit](https://github.com/your-org/my-dev-kit). It runs reproducible experiments that test whether my-dev-kit's graph-guided retrieval helps coding-agent workflows, collects metrics, renders reports, generates plots, captures screenshots, and builds gallery outputs.
|
|
4
4
|
|
|
5
|
-
As of v0.2.
|
|
5
|
+
As of v0.2.1, my-dev-kit-lab also exposes a generic experiment-plugin framework for validating local developer tools, security checks, codebase workflows, retrieval strategies, and experiment outcomes. The first plugin is `context-strategy-comparison`, which preserves the existing raw-full-file vs my-dev-kit-guided workflow through the plugin runner.
|
|
6
6
|
|
|
7
7
|
**my-dev-kit** is the repo indexing and graph-guided retrieval engine.
|
|
8
8
|
**my-dev-kit-lab** is the separate lab layer that feeds it benchmark inputs and records evaluation outputs.
|
|
@@ -205,7 +205,7 @@ See [docs/METRICS.md](docs/METRICS.md) for full metric definitions.
|
|
|
205
205
|
|
|
206
206
|
## Current baseline release positioning
|
|
207
207
|
|
|
208
|
-
my-dev-kit-lab is at a working baseline. The raw-vs-indexed experiment pipeline is fully implemented and produces reproducible artifacts. Real-agent campaign support exists for Codex and Claude. v0.2.
|
|
208
|
+
my-dev-kit-lab is at a working baseline. The raw-vs-indexed experiment pipeline is fully implemented and produces reproducible artifacts. Real-agent campaign support exists for Codex and Claude. v0.2.1 keeps the generic experiment-plugin framework, preserves `context-strategy-comparison` as the first plugin, and fixes target-aware security validation so installed-package checks run `npm run test:security` in the external target project root.
|
|
209
209
|
|
|
210
210
|
---
|
|
211
211
|
|
|
@@ -239,7 +239,9 @@ The release gate is implemented as of v0.1.4. It combines static scans, dependen
|
|
|
239
239
|
|
|
240
240
|
CodeQL, Semgrep, and OSV-Scanner are optional. When unavailable locally, they are recorded as `skipped` in the report — not as failures — and the verdict is `ready except optional manual checks` rather than `not ready`.
|
|
241
241
|
|
|
242
|
-
Each security command can validate my-dev-kit-lab itself or another local project via `--target <path>`. When `--target` is omitted, the framework performs self-validation. Target projects are inspected in place: their source files are not modified, generated artifacts stay under `reports/security/`, and external-target reports identify
|
|
242
|
+
Each security command can validate my-dev-kit-lab itself or another local project via `--target <path>`. When `--target` is omitted, the framework performs self-validation. Target projects are inspected in place: their source files are not modified, generated artifacts stay under `reports/security/`, and external-target reports identify the tool root, target root, target package metadata, target git metadata, command cwd, exit code, and stdout/stderr summaries.
|
|
243
|
+
|
|
244
|
+
For external-target validation, `security:validate` reads the target `package.json`, detects `scripts.test:security`, and runs `npm run test:security` in the target project root when that script exists. This behavior is validated both from the source checkout and from an installed packed tarball because published-package execution differs from local source execution.
|
|
243
245
|
|
|
244
246
|
Generated security reports under `reports/security/` are excluded from git by default. They are produced locally or in CI as release-gate evidence and are not committed to the repository.
|
|
245
247
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export function resolveToolRoot(moduleUrl) {
|
|
5
|
+
let current = path.dirname(fileURLToPath(moduleUrl));
|
|
6
|
+
while (true) {
|
|
7
|
+
if (fs.existsSync(path.join(current, "package.json"))) {
|
|
8
|
+
return current;
|
|
9
|
+
}
|
|
10
|
+
const parent = path.dirname(current);
|
|
11
|
+
if (parent === current) {
|
|
12
|
+
return process.cwd();
|
|
13
|
+
}
|
|
14
|
+
current = parent;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { runCodeqlCheck } from "../../src/securityValidation/staticScans/codeql.js";
|
|
3
3
|
import { resolveValidationTarget } from "../../src/securityValidation/validate/resolveTarget.js";
|
|
4
|
+
import { resolveToolRoot } from "./resolveToolRoot.js";
|
|
4
5
|
const rawArgs = process.argv.slice(2);
|
|
5
6
|
const args = parseArgs(rawArgs);
|
|
6
|
-
const toolRoot =
|
|
7
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
7
8
|
let targetRoot;
|
|
8
9
|
try {
|
|
9
10
|
const target = resolveValidationTarget(args.target, toolRoot);
|
|
@@ -3,9 +3,10 @@ import path from "node:path";
|
|
|
3
3
|
import { runDependencyChecks } from "../../src/securityValidation/index.js";
|
|
4
4
|
import { DEFAULT_SECURITY_CONFIG } from "../../src/securityValidation/index.js";
|
|
5
5
|
import { resolveValidationTarget } from "../../src/securityValidation/validate/resolveTarget.js";
|
|
6
|
+
import { resolveToolRoot } from "./resolveToolRoot.js";
|
|
6
7
|
const rawArgs = process.argv.slice(2);
|
|
7
8
|
const args = parseArgs(rawArgs);
|
|
8
|
-
const toolRoot =
|
|
9
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
9
10
|
let targetRoot;
|
|
10
11
|
try {
|
|
11
12
|
const target = resolveValidationTarget(args.target, toolRoot);
|
|
@@ -3,9 +3,10 @@ import path from "node:path";
|
|
|
3
3
|
import { runPackageChecks } from "../../src/securityValidation/index.js";
|
|
4
4
|
import { DEFAULT_SECURITY_CONFIG } from "../../src/securityValidation/index.js";
|
|
5
5
|
import { resolveValidationTarget } from "../../src/securityValidation/validate/resolveTarget.js";
|
|
6
|
+
import { resolveToolRoot } from "./resolveToolRoot.js";
|
|
6
7
|
const rawArgs = process.argv.slice(2);
|
|
7
8
|
const args = parseArgs(rawArgs);
|
|
8
|
-
const toolRoot =
|
|
9
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
9
10
|
let targetRoot;
|
|
10
11
|
try {
|
|
11
12
|
const target = resolveValidationTarget(args.target, toolRoot);
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { runSemgrepCheck } from "../../src/securityValidation/staticScans/semgrep.js";
|
|
4
4
|
import { resolveValidationTarget } from "../../src/securityValidation/validate/resolveTarget.js";
|
|
5
|
+
import { resolveToolRoot } from "./resolveToolRoot.js";
|
|
5
6
|
const rawArgs = process.argv.slice(2);
|
|
6
7
|
const args = parseArgs(rawArgs);
|
|
7
|
-
const toolRoot =
|
|
8
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
8
9
|
let targetRoot;
|
|
9
10
|
try {
|
|
10
11
|
const target = resolveValidationTarget(args.target, toolRoot);
|
|
@@ -4,10 +4,11 @@ import fs from "node:fs";
|
|
|
4
4
|
import { runSecurityValidation } from "../../src/securityValidation/validate/runSecurityValidation.js";
|
|
5
5
|
import { resolveValidationTarget, reportFilenamePrefix } from "../../src/securityValidation/validate/resolveTarget.js";
|
|
6
6
|
import { renderTextReport, renderJsonReport } from "../../src/securityValidation/report/renderSecurityReport.js";
|
|
7
|
+
import { resolveToolRoot } from "./resolveToolRoot.js";
|
|
7
8
|
// Parse CLI arguments from process.argv (after the node/tsx and script path).
|
|
8
9
|
const rawArgs = process.argv.slice(2);
|
|
9
10
|
const args = parseArgs(rawArgs);
|
|
10
|
-
const toolRoot =
|
|
11
|
+
const toolRoot = resolveToolRoot(import.meta.url);
|
|
11
12
|
// Resolve and validate target early so we can fail fast with a clean error.
|
|
12
13
|
let target;
|
|
13
14
|
try {
|
|
@@ -27,6 +27,7 @@ export function resolveLocalProjectTarget(targetPathArg, toolRoot) {
|
|
|
27
27
|
packageName: packageMetadata.packageName,
|
|
28
28
|
packageVersion: packageMetadata.packageVersion,
|
|
29
29
|
hasPackageJson: packageMetadata.hasPackageJson,
|
|
30
|
+
hasSecurityTestScript: packageMetadata.hasSecurityTestScript,
|
|
30
31
|
hasLockfile: hasLockfile(resolvedTargetRoot),
|
|
31
32
|
...readGitMetadata(resolvedTargetRoot),
|
|
32
33
|
isSelf: resolvedTargetRoot === resolvedToolRoot,
|
|
@@ -36,10 +37,12 @@ function readPackageMetadata(targetRoot) {
|
|
|
36
37
|
try {
|
|
37
38
|
const pkgRaw = fs.readFileSync(path.join(targetRoot, "package.json"), "utf8");
|
|
38
39
|
const pkg = JSON.parse(pkgRaw);
|
|
40
|
+
const testSecurityScript = pkg.scripts && typeof pkg.scripts["test:security"] === "string";
|
|
39
41
|
return {
|
|
40
42
|
hasPackageJson: true,
|
|
41
43
|
packageName: typeof pkg.name === "string" ? pkg.name : null,
|
|
42
44
|
packageVersion: typeof pkg.version === "string" ? pkg.version : null,
|
|
45
|
+
hasSecurityTestScript: Boolean(testSecurityScript),
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
catch {
|
|
@@ -47,6 +50,7 @@ function readPackageMetadata(targetRoot) {
|
|
|
47
50
|
hasPackageJson: false,
|
|
48
51
|
packageName: null,
|
|
49
52
|
packageVersion: null,
|
|
53
|
+
hasSecurityTestScript: false,
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
}
|
|
@@ -70,9 +70,9 @@ export async function runMeasuredCommand(options) {
|
|
|
70
70
|
resolvedCommand: resolution
|
|
71
71
|
};
|
|
72
72
|
void Promise.all([
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
writeArtifact(stdoutPath, stdout),
|
|
74
|
+
writeArtifact(stderrPath, stderr),
|
|
75
|
+
writeArtifact(telemetryPath, JSON.stringify(measured, null, 2))
|
|
76
76
|
]).then(() => resolve(measured));
|
|
77
77
|
return;
|
|
78
78
|
}
|
|
@@ -98,8 +98,8 @@ export async function runMeasuredCommand(options) {
|
|
|
98
98
|
}
|
|
99
99
|
const endedAt = new Date().toISOString();
|
|
100
100
|
const durationMs = Date.now() - started;
|
|
101
|
-
await
|
|
102
|
-
await
|
|
101
|
+
await writeArtifact(stdoutPath, stdout);
|
|
102
|
+
await writeArtifact(stderrPath, stderr);
|
|
103
103
|
const measured = {
|
|
104
104
|
commandId: options.commandId,
|
|
105
105
|
commandString: options.commandString,
|
|
@@ -119,12 +119,16 @@ export async function runMeasuredCommand(options) {
|
|
|
119
119
|
error: spawnError,
|
|
120
120
|
resolvedCommand: resolution
|
|
121
121
|
};
|
|
122
|
-
await
|
|
122
|
+
await writeArtifact(telemetryPath, JSON.stringify(measured, null, 2));
|
|
123
123
|
resolve(measured);
|
|
124
124
|
});
|
|
125
125
|
});
|
|
126
126
|
return result;
|
|
127
127
|
}
|
|
128
|
+
async function writeArtifact(filePath, value) {
|
|
129
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
130
|
+
await writeFile(filePath, value, "utf8");
|
|
131
|
+
}
|
|
128
132
|
function killProcessTree(pid) {
|
|
129
133
|
if (!pid) {
|
|
130
134
|
return;
|
|
@@ -72,7 +72,7 @@ export function renderTextReport(report) {
|
|
|
72
72
|
{ num: 7, title: "npm audit Result", ids: ["npm-audit-full", "npm-audit-runtime"] },
|
|
73
73
|
{ num: 8, title: "OSV-Scanner Result", ids: ["osv-scanner"] },
|
|
74
74
|
{ num: 9, title: "Package Tarball Inspection", ids: ["npm-pack-dry-run"] },
|
|
75
|
-
{ num: 10, title: "File-System / Path Traversal Tests", ids: ["path-traversal-root", "path-traversal-out", "path-traversal-index", "absolute-path-escape", "path-harness-escape-detection"] },
|
|
75
|
+
{ num: 10, title: "CLI / File-System / Path Traversal Tests", ids: ["cli-adversarial-suite", "path-traversal-root", "path-traversal-out", "path-traversal-index", "absolute-path-escape", "path-harness-escape-detection"] },
|
|
76
76
|
{ num: 11, title: "Source Read-Only Boundary Tests", ids: ["source-files-not-modified", "writes-limited-to-output", "index-write-containment", "artifact-cleanup-safe"] },
|
|
77
77
|
{ num: 12, title: "Graphviz / Subprocess Safety Tests", ids: ["graphviz-label-escaping", "subprocess-no-shell-interpolation"] },
|
|
78
78
|
{ num: 13, title: "JSON stdout/stderr Safety Tests", ids: ["json-mode-parseable-output", "stderr-not-in-stdout", "json-failure-error-object", "progress-not-in-json-stdout"] },
|
|
@@ -144,6 +144,21 @@ export function renderTextReport(report) {
|
|
|
144
144
|
}
|
|
145
145
|
for (const check of sectionChecks) {
|
|
146
146
|
lines.push(`[${statusIcon(check.status)}] ${pad(check.name)} ${formatDuration(check.durationMs)}`);
|
|
147
|
+
if (check.command) {
|
|
148
|
+
lines.push(` Command: ${check.command}`);
|
|
149
|
+
}
|
|
150
|
+
if (check.commandCwd) {
|
|
151
|
+
lines.push(` Cwd: ${check.commandCwd}`);
|
|
152
|
+
}
|
|
153
|
+
if (check.exitCode !== undefined) {
|
|
154
|
+
lines.push(` Exit code: ${String(check.exitCode)}`);
|
|
155
|
+
}
|
|
156
|
+
if (check.stdoutSummary) {
|
|
157
|
+
lines.push(` Stdout: ${check.stdoutSummary.slice(0, 200)}`);
|
|
158
|
+
}
|
|
159
|
+
if (check.stderrSummary) {
|
|
160
|
+
lines.push(` Stderr: ${check.stderrSummary.slice(0, 200)}`);
|
|
161
|
+
}
|
|
147
162
|
if (check.status === "skipped" && check.skippedReason) {
|
|
148
163
|
lines.push(` Reason: ${check.skippedReason}`);
|
|
149
164
|
}
|
|
@@ -212,6 +227,10 @@ export function renderJsonReport(report) {
|
|
|
212
227
|
findingCount: c.findings.length,
|
|
213
228
|
skippedReason: c.skippedReason ?? null,
|
|
214
229
|
command: c.command ?? null,
|
|
230
|
+
commandCwd: c.commandCwd ?? null,
|
|
231
|
+
exitCode: c.exitCode ?? null,
|
|
232
|
+
stdoutSummary: c.stdoutSummary ?? null,
|
|
233
|
+
stderrSummary: c.stderrSummary ?? null,
|
|
215
234
|
}));
|
|
216
235
|
const sanitizedFindings = allFindings.map((f) => ({
|
|
217
236
|
id: f.id,
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { runSecurityCommand, resolveNpmCommand } from "../commandRunner.js";
|
|
2
|
+
export async function runCliSecuritySuiteCheck(options) {
|
|
3
|
+
const startedAt = new Date().toISOString();
|
|
4
|
+
if (!options.target.isSelf && !options.target.hasPackageJson) {
|
|
5
|
+
const finishedAt = new Date().toISOString();
|
|
6
|
+
return {
|
|
7
|
+
id: "cli-adversarial-suite",
|
|
8
|
+
name: "Target security test suite",
|
|
9
|
+
category: "cli-adversarial",
|
|
10
|
+
status: "failed",
|
|
11
|
+
severity: "major",
|
|
12
|
+
startedAt,
|
|
13
|
+
finishedAt,
|
|
14
|
+
durationMs: 0,
|
|
15
|
+
command: "npm run test:security",
|
|
16
|
+
commandCwd: options.target.targetRoot,
|
|
17
|
+
exitCode: null,
|
|
18
|
+
findings: [
|
|
19
|
+
{
|
|
20
|
+
id: "target-security-suite-missing-package-json",
|
|
21
|
+
title: "Target package.json is missing",
|
|
22
|
+
severity: "major",
|
|
23
|
+
category: "cli-adversarial",
|
|
24
|
+
description: "Target-aware security suite validation requires a package.json at the target root.",
|
|
25
|
+
recommendation: "Add a package.json with a test:security script or validate a package-based target.",
|
|
26
|
+
releaseImpact: "Should fix before release",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (!options.target.isSelf && !options.target.hasSecurityTestScript) {
|
|
32
|
+
const finishedAt = new Date().toISOString();
|
|
33
|
+
return {
|
|
34
|
+
id: "cli-adversarial-suite",
|
|
35
|
+
name: "Target security test suite",
|
|
36
|
+
category: "cli-adversarial",
|
|
37
|
+
status: "failed",
|
|
38
|
+
severity: "major",
|
|
39
|
+
startedAt,
|
|
40
|
+
finishedAt,
|
|
41
|
+
durationMs: 0,
|
|
42
|
+
command: "npm run test:security",
|
|
43
|
+
commandCwd: options.target.targetRoot,
|
|
44
|
+
exitCode: null,
|
|
45
|
+
findings: [
|
|
46
|
+
{
|
|
47
|
+
id: "target-security-suite-missing-script",
|
|
48
|
+
title: "Target test:security script is missing",
|
|
49
|
+
severity: "major",
|
|
50
|
+
category: "cli-adversarial",
|
|
51
|
+
description: "The target package.json does not define scripts.test:security, so the target security suite could not be validated.",
|
|
52
|
+
recommendation: "Add a target test:security script and rerun security:validate.",
|
|
53
|
+
releaseImpact: "Should fix before release",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const npm = resolveNpmCommand();
|
|
59
|
+
const isSelf = options.target.isSelf;
|
|
60
|
+
const commandCwd = isSelf ? options.toolRoot : options.target.targetRoot;
|
|
61
|
+
const cmd = await runSecurityCommand({
|
|
62
|
+
command: npm,
|
|
63
|
+
args: ["run", "test:security"],
|
|
64
|
+
cwd: commandCwd,
|
|
65
|
+
timeoutMs: Math.min(options.timeoutMs * 3, 180_000),
|
|
66
|
+
});
|
|
67
|
+
const finishedAt = new Date().toISOString();
|
|
68
|
+
const passed = cmd.exitCode === 0;
|
|
69
|
+
const name = isSelf
|
|
70
|
+
? "CLI adversarial test suite (tool self-tests)"
|
|
71
|
+
: "Target security test suite";
|
|
72
|
+
return {
|
|
73
|
+
id: "cli-adversarial-suite",
|
|
74
|
+
name,
|
|
75
|
+
category: "cli-adversarial",
|
|
76
|
+
status: passed ? "passed" : "failed",
|
|
77
|
+
severity: "major",
|
|
78
|
+
startedAt,
|
|
79
|
+
finishedAt,
|
|
80
|
+
durationMs: cmd.durationMs,
|
|
81
|
+
findings: passed
|
|
82
|
+
? []
|
|
83
|
+
: [
|
|
84
|
+
{
|
|
85
|
+
id: "cli-adversarial-suite-failed",
|
|
86
|
+
title: isSelf ? "CLI adversarial test suite had failures" : "Target test:security script failed",
|
|
87
|
+
severity: "major",
|
|
88
|
+
category: "cli-adversarial",
|
|
89
|
+
description: isSelf
|
|
90
|
+
? `Tool-root test:security exited with code ${String(cmd.exitCode)}.`
|
|
91
|
+
: `Target-root test:security exited with code ${String(cmd.exitCode)}.`,
|
|
92
|
+
evidence: buildEvidence(cmd),
|
|
93
|
+
recommendation: isSelf
|
|
94
|
+
? "Fix failing tool security tests before release."
|
|
95
|
+
: "Fix the target test:security failure and rerun security:validate.",
|
|
96
|
+
releaseImpact: "Should fix before release",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
command: `${npm} run test:security`,
|
|
100
|
+
commandCwd,
|
|
101
|
+
exitCode: cmd.exitCode,
|
|
102
|
+
stdoutSummary: summarizeOutput(cmd.stdout),
|
|
103
|
+
stderrSummary: summarizeOutput(cmd.stderr),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function summarizeOutput(value) {
|
|
107
|
+
const normalized = value.replace(/\r\n/g, "\n").trim();
|
|
108
|
+
if (!normalized) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
return normalized.slice(0, 500);
|
|
112
|
+
}
|
|
113
|
+
function buildEvidence(cmd) {
|
|
114
|
+
const parts = [`cwd=${cmd.cwd}`, `exitCode=${String(cmd.exitCode)}`];
|
|
115
|
+
const stdoutSummary = summarizeOutput(cmd.stdout);
|
|
116
|
+
const stderrSummary = summarizeOutput(cmd.stderr);
|
|
117
|
+
if (stdoutSummary) {
|
|
118
|
+
parts.push(`stdout=${stdoutSummary}`);
|
|
119
|
+
}
|
|
120
|
+
if (stderrSummary) {
|
|
121
|
+
parts.push(`stderr=${stderrSummary}`);
|
|
122
|
+
}
|
|
123
|
+
return parts.join(" | ");
|
|
124
|
+
}
|
|
@@ -6,10 +6,10 @@ import { runCodeqlCheck } from "../staticScans/codeql.js";
|
|
|
6
6
|
import { runSemgrepCheck } from "../staticScans/semgrep.js";
|
|
7
7
|
import { runAllFuzzTargets } from "../fuzz/fuzzHarness.js";
|
|
8
8
|
import { ALL_FUZZ_TARGETS } from "../fuzz/fuzzTargets.js";
|
|
9
|
-
import { runSecurityCommand, resolveNpmCommand } from "../commandRunner.js";
|
|
10
9
|
import { calculateVerdict } from "./verdict.js";
|
|
11
10
|
import { resolveValidationTarget, targetDescription as describeTarget } from "./resolveTarget.js";
|
|
12
11
|
import { DEFAULT_SECURITY_CONFIG } from "../config.js";
|
|
12
|
+
import { runCliSecuritySuiteCheck } from "./runCliSecuritySuiteCheck.js";
|
|
13
13
|
export async function runSecurityValidation(options) {
|
|
14
14
|
const toolRoot = options.cwd;
|
|
15
15
|
const config = {
|
|
@@ -68,45 +68,14 @@ export async function runSecurityValidation(options) {
|
|
|
68
68
|
catch (err) {
|
|
69
69
|
collect(errorCheck("semgrep-scan", "Semgrep static analysis", "static-scan", err));
|
|
70
70
|
}
|
|
71
|
-
// ---
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
args: ["run", "test:security", "--", "--reporter=json"],
|
|
80
|
-
cwd: toolRoot,
|
|
81
|
-
timeoutMs: Math.min(config.commandTimeoutMs * 3, 180_000),
|
|
82
|
-
});
|
|
83
|
-
const finishedAt2 = new Date().toISOString();
|
|
84
|
-
const passed = cmd.exitCode === 0;
|
|
85
|
-
collect({
|
|
86
|
-
id: "cli-adversarial-suite",
|
|
87
|
-
name: "CLI adversarial test suite (tool self-tests, not target-specific)",
|
|
88
|
-
category: "cli-adversarial",
|
|
89
|
-
status: passed ? "passed" : "failed",
|
|
90
|
-
severity: "major",
|
|
91
|
-
startedAt: startedAt2,
|
|
92
|
-
finishedAt: finishedAt2,
|
|
93
|
-
durationMs: cmd.durationMs,
|
|
94
|
-
findings: passed
|
|
95
|
-
? []
|
|
96
|
-
: [
|
|
97
|
-
{
|
|
98
|
-
id: "cli-adversarial-suite-failed",
|
|
99
|
-
title: "CLI adversarial test suite had failures",
|
|
100
|
-
severity: "major",
|
|
101
|
-
category: "cli-adversarial",
|
|
102
|
-
description: `test:security exited with code ${String(cmd.exitCode)}. Run 'npm run test:security' for details.`,
|
|
103
|
-
recommendation: "Fix failing adversarial tests before release.",
|
|
104
|
-
releaseImpact: "Should fix before release",
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
command: `${npm} run test:security`,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
71
|
+
// --- Security suite check ---
|
|
72
|
+
// Self-validation runs the lab's own test:security suite.
|
|
73
|
+
// External validation runs the target project's test:security script when present.
|
|
74
|
+
collect(await runCliSecuritySuiteCheck({
|
|
75
|
+
toolRoot,
|
|
76
|
+
target,
|
|
77
|
+
timeoutMs: config.commandTimeoutMs,
|
|
78
|
+
}));
|
|
110
79
|
// --- Fuzz smoke (always tool-internal; tests library parser/helper code) ---
|
|
111
80
|
try {
|
|
112
81
|
collect(await runAllFuzzTargets(ALL_FUZZ_TARGETS, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@dailephd/my-dev-kit-lab",
|
|
3
|
-
"version": "0.2.
|
|
2
|
+
"name": "@dailephd/my-dev-kit-lab",
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Evidence, benchmark, and evaluation companion for my-dev-kit.",
|
|
6
6
|
"bin": {
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"url": "git+https://github.com/dailephd/my-dev-kit-lab.git"
|
|
20
20
|
},
|
|
21
21
|
"homepage": "https://github.com/dailephd/my-dev-kit-lab#readme",
|
|
22
|
-
"bugs": {
|
|
23
|
-
"url": "https://github.com/dailephd/my-dev-kit-lab/issues"
|
|
24
|
-
},
|
|
25
|
-
"publishConfig": {
|
|
26
|
-
"access": "public"
|
|
27
|
-
},
|
|
28
|
-
"funding": [
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/dailephd/my-dev-kit-lab/issues"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
28
|
+
"funding": [
|
|
29
29
|
"https://github.com/sponsors/dailephd",
|
|
30
30
|
"https://paypal.me/daile88"
|
|
31
31
|
],
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"license": "UNLICENSED",
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.json",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
44
45
|
"test": "vitest run",
|
|
45
46
|
"test:benchmarks": "vitest run tests/benchmarks tests/scripts",
|
|
46
47
|
"test:report": "vitest run tests/report tests/commands",
|
|
@@ -78,14 +79,17 @@
|
|
|
78
79
|
"test:fuzz:smoke": "tsx scripts/security/runFuzzSmoke.ts",
|
|
79
80
|
"security:validate": "tsx scripts/security/validate.ts"
|
|
80
81
|
},
|
|
81
|
-
"devDependencies": {
|
|
82
|
-
"@types/node": "^24.0.0",
|
|
83
|
-
"playwright": "^1.54.1",
|
|
84
|
-
"tsx": "^4.20.3",
|
|
85
|
-
"typescript": "^5.8.3",
|
|
86
|
-
"vitest": "^3.2.4"
|
|
87
|
-
},
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
}
|
|
91
|
-
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"@types/node": "^24.0.0",
|
|
84
|
+
"playwright": "^1.54.1",
|
|
85
|
+
"tsx": "^4.20.3",
|
|
86
|
+
"typescript": "^5.8.3",
|
|
87
|
+
"vitest": "^3.2.4"
|
|
88
|
+
},
|
|
89
|
+
"overrides": {
|
|
90
|
+
"vite": "7.3.6"
|
|
91
|
+
},
|
|
92
|
+
"engines": {
|
|
93
|
+
"node": ">=20"
|
|
94
|
+
}
|
|
95
|
+
}
|