tewip-ai 0.18.1 → 0.18.3

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.
@@ -116,6 +116,9 @@ function junitCases(root, workspace) {
116
116
  }
117
117
  out.push({ testId, file: file || (testcase.attrs.classname ?? '').trim(), duration: Number.isFinite(seconds) ? Math.round(seconds * 1000) : 0, attempts });
118
118
  };
119
+ // <testrun> is the root Eclipse's JUnit runner and Ant write; everything inside it is ordinary
120
+ // JUnit XML. A real report in that shape was rejected outright as "no test report Tewip can
121
+ // read", which is a poor answer to a file holding 36 perfectly readable results.
119
122
  walk(root, root.name === 'testsuite' ? root : undefined);
120
123
  // Attempts whose error the runner did not record borrow the final one's, when there is one.
121
124
  for (const c of out) {
@@ -249,7 +252,7 @@ export function importJunit(path, meta) {
249
252
  if (start && (!startedAt || start < startedAt))
250
253
  startedAt = start;
251
254
  }
252
- else if (root.name === 'testsuites' || root.name === 'testsuite') {
255
+ else if (root.name === 'testsuites' || root.name === 'testsuite' || root.name === 'testrun') {
253
256
  cases = junitCases(root, meta.workspace);
254
257
  const stamp = root.attrs.timestamp ?? root.children.find((c) => c.name === 'testsuite')?.attrs.timestamp;
255
258
  if (stamp && (!startedAt || stamp < startedAt))
@@ -317,7 +320,7 @@ export function importJunit(path, meta) {
317
320
  if (unread.length > 0) {
318
321
  const list = unread.slice(0, 5).join(', ');
319
322
  if (parsedFiles === 0) {
320
- throw new Error(`no test report Tewip can read in ${path}: ${list}. It reads JUnit XML (<testsuites>/<testsuite>), NUnit 3 (<test-run>), .NET TRX (<TestRun>), ` +
323
+ throw new Error(`no test report Tewip can read in ${path}: ${list}. It reads JUnit XML (<testsuites>/<testsuite>/<testrun>), NUnit 3 (<test-run>), .NET TRX (<TestRun>), ` +
321
324
  'Robot Framework output.xml (<robot>), JMeter .jtl (<testResults>) and a k6 summary (--summary-export). ' +
322
325
  'Most runners can write JUnit XML; for TestNG use the Surefire report, and for NUnit use --result=x.xml.');
323
326
  }
@@ -54,18 +54,26 @@ export function entropyOf(value) {
54
54
  const PLACEHOLDER_WORDS = /example|placeholder|dummy|sample|changeme|your[-_ ]?(?:key|token|secret|api)|xxxx|redacted|fake|notreal|test[-_]?key|<[^>]+>|\$\{|\{\{/i;
55
55
  /** Files whose whole purpose is to show the shape of a secret, not to hold one. */
56
56
  const DOC_FILE = /(?:^|[\\/])(?:\.env\.example|\.env\.sample|\.env\.template|[^\\/]*\.(?:md|rst|txt|adoc)|[^\\/]*example[^\\/]*|[^\\/]*sample[^\\/]*)$/i;
57
- /** Why this match is probably not a live credential, or null when nothing says so. */
57
+ /**
58
+ * Why this match is probably not a live credential, or null when nothing says so.
59
+ *
60
+ * The file's name is deliberately not enough on its own any more. A realistic AWS key placed in
61
+ * `src/config-sample.js` was dismissed as noise - "nothing: this is not a credential" - while the
62
+ * identical key in `src/settings.js` was reported as critical. A filename is the weakest evidence
63
+ * there is, and a key pasted into an example file by accident is one of the commonest ways
64
+ * credentials leak. That case is now shown as a template finding instead of being dismissed.
65
+ */
58
66
  export function looksPlanted(value, line, file) {
59
67
  if (PLACEHOLDER_WORDS.test(value))
60
68
  return 'the value itself says it is an example';
61
69
  if (PLACEHOLDER_WORDS.test(line))
62
70
  return 'the line around it says it is an example';
63
- if (DOC_FILE.test(file))
64
- return 'it is in a documentation or example file';
65
71
  if (/(.)\1{5,}/.test(value))
66
72
  return 'the value repeats one character, so it is a stand-in';
67
73
  return null;
68
74
  }
75
+ /** True when only the file's name suggests a template, whatever the value itself looks like. */
76
+ export const inATemplate = (file) => DOC_FILE.test(file);
69
77
  const SKIP_DIR = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'coverage', 'target', 'vendor', '__pycache__', '.venv', 'venv', '.tewip', '.next', '.cache']);
70
78
  const BINARY = /\.(?:png|jpe?g|gif|webp|ico|svg|pdf|zip|gz|tar|exe|dll|so|dylib|woff2?|ttf|eot|mp4|mp3|wav|class|jar|pyc|lock)$/i;
71
79
  const MAX_FILE_BYTES = 2 * 1024 * 1024;
@@ -150,6 +158,7 @@ export function scanSecrets(root, files = sourceFiles(root)) {
150
158
  evidence: redact(lines[line - 1] ?? '', value),
151
159
  entropy: Number(entropy.toFixed(2)),
152
160
  placeholder: looksPlanted(value, lines[line - 1] ?? '', rel),
161
+ template: inATemplate(rel),
153
162
  });
154
163
  }
155
164
  }
@@ -60,6 +60,18 @@ export function triageSecret(finding, root, accepted) {
60
60
  if (finding.placeholder) {
61
61
  return { ...base, verdict: 'noise', severity: 'low', why: `${finding.placeholder}: ${finding.evidence}`, next: 'nothing: this is not a credential' };
62
62
  }
63
+ if (finding.template) {
64
+ // Only the file's name says this is a template; the value itself looks like a real credential.
65
+ // Dismissing it would hide the commonest accident there is - a working key pasted into an
66
+ // example file - so it is shown, below the ones that need acting on now.
67
+ return {
68
+ ...base,
69
+ verdict: 'not-reachable',
70
+ severity: 'medium',
71
+ why: `${finding.evidence} - the file is a template or documentation, but the value itself does not say it is an example`,
72
+ next: 'check whether this was ever a working credential; if it was, rotate it and replace it here with an obvious placeholder',
73
+ };
74
+ }
63
75
  const tracked = isTracked(root, finding.file);
64
76
  if (!tracked) {
65
77
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tewip-ai",
3
- "version": "0.18.1",
3
+ "version": "0.18.3",
4
4
  "description": "Tewip finds why each failing test failed - real bug, flaky test, environment, test data or changed selector - for any stack, from the command line, CI, or your editor.",
5
5
  "keywords": [
6
6
  "test-failures",