qa-engineer 0.9.0 → 0.9.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/COMPATIBILITY.md +25 -15
- package/LICENSE +1 -1
- package/README.md +22 -4
- package/package.json +4 -3
- package/packages/installer/README.md +1 -1
- package/packages/installer/lib/agents/registry.mjs +46 -0
- package/packages/installer/lib/commands/doctor.mjs +6 -6
- package/packages/installer/lib/commands/install.mjs +32 -5
- package/packages/installer/lib/commands/onboard.mjs +2 -2
- package/packages/installer/lib/core/config.mjs +1 -1
- package/packages/installer/lib/core/lockfile.mjs +1 -1
- package/packages/installer/lib/core/manifest.mjs +3 -0
- package/packages/installer/lib/core/wrappers.mjs +4 -4
- package/packages/installer/lib/ui/theme.mjs +1 -1
- package/packages/installer/package.json +1 -1
- package/packages/installer/schemas/qa-lock.schema.json +1 -1
- package/packages/installer/schemas/qa.config.schema.json +1 -1
- package/shared/analysis/lib/qa_analysis/branding.json +1 -1
- package/shared/analysis/lib/qa_analysis/cli.py +15 -0
- package/shared/analysis/lib/qa_analysis/har.py +32 -3
- package/shared/analysis/lib/qa_analysis/junit.py +25 -1
- package/shared/analysis/lib/qa_analysis/redaction.py +10 -2
- package/shared/analysis/lib/qa_analysis/report_html.py +781 -0
- package/skills/qa/README.md +1 -1
- package/skills/qa/SKILL.md +1 -1
- package/skills/qa-api/references/deterministic-tooling.md +2 -0
- package/skills/qa-api/references/evidence-and-reporting.md +29 -4
- package/skills/qa-audit/references/deterministic-tooling.md +2 -0
- package/skills/qa-audit/references/evidence-and-reporting.md +29 -4
- package/skills/qa-debug/references/deterministic-tooling.md +2 -0
- package/skills/qa-debug/references/evidence-and-reporting.md +29 -4
- package/skills/qa-example/SKILL.md +1 -1
- package/skills/qa-example/contracts/self-check-report.schema.json +1 -1
- package/skills/qa-explore/SKILL.md +22 -5
- package/skills/qa-explore/contracts/explore-result.schema.json +26 -2
- package/skills/qa-explore/references/deterministic-tooling.md +130 -0
- package/skills/qa-explore/references/evidence-and-reporting.md +29 -4
- package/skills/qa-explore/references/report-pipeline.md +89 -8
- package/skills/qa-fix/references/deterministic-tooling.md +2 -0
- package/skills/qa-fix/references/evidence-and-reporting.md +29 -4
- package/skills/qa-flaky/references/deterministic-tooling.md +2 -0
- package/skills/qa-flaky/references/evidence-and-reporting.md +29 -4
- package/skills/qa-generate/references/evidence-and-reporting.md +29 -4
- package/skills/qa-init/references/deterministic-tooling.md +2 -0
- package/skills/qa-init/references/evidence-and-reporting.md +29 -4
- package/skills/qa-report/SKILL.md +3 -2
- package/skills/qa-report/references/deterministic-tooling.md +2 -0
- package/skills/qa-report/references/evidence-and-reporting.md +29 -4
- package/skills/qa-review/references/evidence-and-reporting.md +29 -4
- package/skills/qa-run/references/deterministic-tooling.md +2 -0
- package/skills/qa-run/references/evidence-and-reporting.md +29 -4
- package/packages/installer/lib/core/schema-validate.mjs +0 -142
|
@@ -24,6 +24,30 @@ def _int(value, default=0):
|
|
|
24
24
|
return default
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def _duration_ms(raw, path):
|
|
28
|
+
"""`time` in seconds as whole milliseconds.
|
|
29
|
+
|
|
30
|
+
An absent or empty attribute is zero — plenty of runners omit it. A value
|
|
31
|
+
that is present but not a finite number means the document is not what it
|
|
32
|
+
claims to be, so it raises: found by the Node port's parity corpus, where
|
|
33
|
+
`time="not-a-number"` escaped as a bare ValueError and `time="nan"` as
|
|
34
|
+
"cannot convert float NaN to integer". Both reached the caller as a traceback
|
|
35
|
+
and exit 1, while the CLI's documented failure mode is exit 2 with
|
|
36
|
+
{error, detail}.
|
|
37
|
+
"""
|
|
38
|
+
if raw is None or raw == "":
|
|
39
|
+
return 0
|
|
40
|
+
try:
|
|
41
|
+
seconds = float(raw)
|
|
42
|
+
except (TypeError, ValueError):
|
|
43
|
+
raise MalformedArtifact(
|
|
44
|
+
f"testcase time={raw!r} is not a number at {path}"
|
|
45
|
+
) from None
|
|
46
|
+
if seconds != seconds or seconds in (float("inf"), float("-inf")):
|
|
47
|
+
raise MalformedArtifact(f"testcase time={raw!r} is not a finite number at {path}")
|
|
48
|
+
return int(round(seconds * 1000))
|
|
49
|
+
|
|
50
|
+
|
|
27
51
|
def parse_junit(path):
|
|
28
52
|
"""Parse a JUnit XML file into a normalized result.
|
|
29
53
|
|
|
@@ -65,7 +89,7 @@ def parse_junit(path):
|
|
|
65
89
|
"title": case.get("name", ""),
|
|
66
90
|
"file": case.get("classname", ""),
|
|
67
91
|
"status": status,
|
|
68
|
-
"durationMs":
|
|
92
|
+
"durationMs": _duration_ms(case.get("time"), path),
|
|
69
93
|
}
|
|
70
94
|
if message:
|
|
71
95
|
entry["message"] = message
|
|
@@ -18,8 +18,16 @@ _RULES = [
|
|
|
18
18
|
("openai-key", re.compile(r"sk-[A-Za-z0-9]{20,}")),
|
|
19
19
|
("bearer", re.compile(r"(?i)\bBearer\s+[A-Za-z0-9._~+/-]+=*")),
|
|
20
20
|
# Sensitive header lines: keep the header name, mask the value.
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
#
|
|
22
|
+
# The value is `[^\r\n]+` rather than `.+$`, and the indent is `[ \t]*` rather
|
|
23
|
+
# than `\s*`, for one reason: on CRLF text, `.+` swallows the carriage return
|
|
24
|
+
# and `$` matches before the newline, so redacting a header silently rewrote
|
|
25
|
+
# the line ending to LF and corrupted the rest of the document's endings.
|
|
26
|
+
# Horizontal whitespace is also what a header indent actually is. Found by the
|
|
27
|
+
# Node port's parity corpus, where the two languages disagreed here and
|
|
28
|
+
# JavaScript was right.
|
|
29
|
+
("auth-header", re.compile(r"(?im)^([ \t]*(?:authorization|proxy-authorization)[ \t]*[:=][ \t]*)[^\r\n]+")),
|
|
30
|
+
("cookie-header", re.compile(r"(?im)^([ \t]*(?:set-cookie|cookie)[ \t]*[:=][ \t]*)[^\r\n]+")),
|
|
23
31
|
# Secret-like assignments: key=value / "key": "value".
|
|
24
32
|
("assigned-secret", re.compile(
|
|
25
33
|
r'(?i)(\b(?:password|passwd|pwd|secret|token|api[_-]?key|access[_-]?key|client[_-]?secret)\b\s*[:=]\s*["\']?)'
|