aztrx-cli 0.4.1 → 0.4.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/dist/cli.js CHANGED
@@ -64,8 +64,15 @@ async function detectUrl(repoRoot) {
64
64
  function suggestNext(findings, opts) {
65
65
  if (opts.dryRun || opts.crashTest || findings.length === 0)
66
66
  return;
67
- const crashOrError = findings.some((f) => f.severity === "crash" || f.severity === "error");
68
67
  const alreadyFixing = opts.heal || opts.fix || opts.magicFix;
68
+ // Server-side 5xx → point at the server fuzzer. `--fix` patches frontend code,
69
+ // so it can't help with a 502/500 from the server.
70
+ const serverError = findings.some((f) => f.type === "network_5xx");
71
+ if (serverError && !opts.httpFuzz) {
72
+ console.log(pc.dim("Tip: these are server-side 5xx — run with --http-fuzz to map the server attack surface"));
73
+ return;
74
+ }
75
+ const crashOrError = findings.some((f) => f.severity === "crash" || f.severity === "error");
69
76
  if (crashOrError && !alreadyFixing) {
70
77
  if (opts.repro) {
71
78
  console.log(pc.dim("Tip: run with --fix to attempt a closed-loop fix"));
@@ -73,11 +80,6 @@ function suggestNext(findings, opts) {
73
80
  else {
74
81
  console.log(pc.dim("Tip: run with --repro to prove these with a runnable spec, or --fix to fix them end-to-end"));
75
82
  }
76
- return;
77
- }
78
- const serverError = findings.some((f) => f.type === "network_5xx");
79
- if (serverError && !opts.httpFuzz) {
80
- console.log(pc.dim("Tip: run with --http-fuzz to map the server-side attack surface"));
81
83
  }
82
84
  }
83
85
  program
@@ -227,15 +227,15 @@ export async function run(options) {
227
227
  // it in a sandboxed worktree, and verify the bug stops reproducing. Opt-in;
228
228
  // the patch is only ever handed to a human for review, never committed.
229
229
  if (options.heal) {
230
- const healTargets = findings.filter((f) => (f.severity === "crash" || f.severity === "error") &&
230
+ const reproducible = findings.filter((f) => (f.severity === "crash" || f.severity === "error") &&
231
231
  // A `network_5xx` finding heals only when its 500 body leaked a server
232
232
  // stack (→ an own-code source location); heal then boots the patched app
233
233
  // to verify. `network_timeout` stays excluded — it needs a time-based
234
234
  // repro first.
235
235
  f.type !== "network_timeout" &&
236
- f.mappedLocation?.isOwnCode &&
237
236
  f.repro &&
238
237
  f.repro.verdict !== "unreliable");
238
+ const healTargets = reproducible.filter((f) => f.mappedLocation?.isOwnCode);
239
239
  if (healTargets.length) {
240
240
  say(pc.cyan("— Closed-loop healing (redact → generate → gate → sandbox → test → verify) —"));
241
241
  emitPhase("heal");
@@ -295,6 +295,11 @@ export async function run(options) {
295
295
  }
296
296
  }
297
297
  }
298
+ else if (reproducible.length > 0) {
299
+ // Reproducible crashes, but none mapped to source (wrong --repo?) — tell the
300
+ // user rather than silently doing nothing.
301
+ say(pc.yellow(`Found ${reproducible.length} reproducible crash(es) but couldn't map them to source files. Run from your project root (or pass --repo <dir>) so --fix can read the code.`));
302
+ }
298
303
  }
299
304
  const reportPath = writeReport(repoRoot, url, findings);
300
305
  say(pc.dim(`Report: ${path.relative(repoRoot, reportPath)}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aztrx-cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "private": false,
5
5
  "description": "Aztrx AI — runtime stress-tester for web apps. Detect bugs, then prove them with an executable repro.",
6
6
  "license": "Apache-2.0",