brainblast 0.5.0 → 0.5.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.
@@ -662,6 +662,44 @@ var taintToSink = (c, p) => {
662
662
  return { result: "pass", detail: "No tracked source value flows to a sink within the analyzed call graph." };
663
663
  };
664
664
 
665
+ // src/checkers/literalMultiplierWrongConstant.ts
666
+ import { SyntaxKind as SyntaxKind8 } from "ts-morph";
667
+ function callName4(call) {
668
+ const exp = call.getExpression();
669
+ if (exp.getKind() === SyntaxKind8.Identifier) return exp.getText();
670
+ if (exp.getKind() === SyntaxKind8.PropertyAccessExpression) {
671
+ return exp.asKind(SyntaxKind8.PropertyAccessExpression).getName();
672
+ }
673
+ return "";
674
+ }
675
+ function containsIdentifier(node, name) {
676
+ if (node.getKind() === SyntaxKind8.Identifier && node.getText() === name) return true;
677
+ return node.getDescendantsOfKind(SyntaxKind8.Identifier).some((id) => id.getText() === name);
678
+ }
679
+ var literalMultiplierWrongConstant = (c, p) => {
680
+ const calls = c.fn.getDescendantsOfKind(SyntaxKind8.CallExpression).filter((x) => callName4(x) === p.call);
681
+ if (calls.length === 0) {
682
+ return { result: "cant_tell", detail: p.absentCallDetail };
683
+ }
684
+ const arg = calls[0].getArguments()[p.argIndex];
685
+ if (!arg) {
686
+ return { result: "cant_tell", detail: p.absentCallDetail };
687
+ }
688
+ const forbidden = Array.isArray(p.forbiddenIdentifiers) ? p.forbiddenIdentifiers : [];
689
+ for (const name of forbidden) {
690
+ if (containsIdentifier(arg, name)) {
691
+ return { result: "fail", detail: String(p.failDetail).replace("{got}", name) };
692
+ }
693
+ }
694
+ const expected = Array.isArray(p.expectedIdentifiers) ? p.expectedIdentifiers : [];
695
+ for (const name of expected) {
696
+ if (containsIdentifier(arg, name)) {
697
+ return { result: "pass", detail: String(p.passDetail) };
698
+ }
699
+ }
700
+ return { result: "cant_tell", detail: p.cantTellDetail };
701
+ };
702
+
665
703
  // src/checkers/index.ts
666
704
  var registry = {
667
705
  "positional-arg-identity": positionalArgIdentity,
@@ -671,7 +709,8 @@ var registry = {
671
709
  "object-arg-property-literal-equals": objectArgPropertyLiteralEquals,
672
710
  "anchor-init-if-needed-guarded": anchorInitIfNeededGuarded,
673
711
  "env-secrets-committed": envSecretsCommitted,
674
- "taint-to-sink": taintToSink
712
+ "taint-to-sink": taintToSink,
713
+ "literal-multiplier-wrong-constant": literalMultiplierWrongConstant
675
714
  };
676
715
  function runChecker(kind, c, params) {
677
716
  const fn = registry[kind];
@@ -887,7 +926,7 @@ function findRustCandidates(targetDir, rule) {
887
926
  }
888
927
 
889
928
  // src/fixers/positionalArgIdentity.ts
890
- import { SyntaxKind as SyntaxKind8 } from "ts-morph";
929
+ import { SyntaxKind as SyntaxKind9 } from "ts-morph";
891
930
 
892
931
  // src/fixers/diffUtil.ts
893
932
  function buildDiff(node, replacement) {
@@ -912,9 +951,9 @@ function buildDiff(node, replacement) {
912
951
  // src/fixers/positionalArgIdentity.ts
913
952
  var fixPositionalArgIdentity = (c, p, outcome) => {
914
953
  if (outcome.result !== "fail") return void 0;
915
- const calls = c.fn.getDescendantsOfKind(SyntaxKind8.CallExpression).filter((call) => {
954
+ const calls = c.fn.getDescendantsOfKind(SyntaxKind9.CallExpression).filter((call) => {
916
955
  const exp = call.getExpression();
917
- return exp.getKind() === SyntaxKind8.PropertyAccessExpression && exp.asKind(SyntaxKind8.PropertyAccessExpression).getName() === p.call;
956
+ return exp.getKind() === SyntaxKind9.PropertyAccessExpression && exp.asKind(SyntaxKind9.PropertyAccessExpression).getName() === p.call;
918
957
  });
919
958
  if (calls.length === 0) {
920
959
  const wantParam2 = c.params[p.paramIndex] ?? "<rawBodyParam>";
@@ -929,7 +968,7 @@ Do not call JSON.parse() on the body before this verification step.`
929
968
  }
930
969
  const arg = calls[0].getArguments()[p.argIndex];
931
970
  const wantParam = c.params[p.paramIndex];
932
- if (arg && wantParam && arg.getKind() === SyntaxKind8.CallExpression) {
971
+ if (arg && wantParam && arg.getKind() === SyntaxKind9.CallExpression) {
933
972
  return {
934
973
  summary: `Pass the raw body parameter '${wantParam}' to ${p.call} instead of a parsed value`,
935
974
  diff: buildDiff(arg, wantParam)
@@ -939,12 +978,12 @@ Do not call JSON.parse() on the body before this verification step.`
939
978
  };
940
979
 
941
980
  // src/fixers/requiredCallWithOptions.ts
942
- import { SyntaxKind as SyntaxKind9 } from "ts-morph";
943
- function callName4(call) {
981
+ import { SyntaxKind as SyntaxKind10 } from "ts-morph";
982
+ function callName5(call) {
944
983
  const exp = call.getExpression();
945
- if (exp.getKind() === SyntaxKind9.Identifier) return exp.getText();
946
- if (exp.getKind() === SyntaxKind9.PropertyAccessExpression) {
947
- return exp.asKind(SyntaxKind9.PropertyAccessExpression).getName();
984
+ if (exp.getKind() === SyntaxKind10.Identifier) return exp.getText();
985
+ if (exp.getKind() === SyntaxKind10.PropertyAccessExpression) {
986
+ return exp.asKind(SyntaxKind10.PropertyAccessExpression).getName();
948
987
  }
949
988
  return "";
950
989
  }
@@ -962,15 +1001,15 @@ function placeholderFor(propName) {
962
1001
  }
963
1002
  var fixRequiredCallWithOptions = (c, p, outcome) => {
964
1003
  if (outcome.result !== "fail") return void 0;
965
- const calls = c.fn.getDescendantsOfKind(SyntaxKind9.CallExpression);
966
- const verify = calls.filter((x) => p.verifyCalls.includes(callName4(x)));
1004
+ const calls = c.fn.getDescendantsOfKind(SyntaxKind10.CallExpression);
1005
+ const verify = calls.filter((x) => p.verifyCalls.includes(callName5(x)));
967
1006
  if (verify.length > 0) {
968
1007
  const call = verify[0];
969
1008
  const args = call.getArguments();
970
1009
  const lastArg = args[args.length - 1];
971
- const obj = lastArg?.asKind(SyntaxKind9.ObjectLiteralExpression);
1010
+ const obj = lastArg?.asKind(SyntaxKind10.ObjectLiteralExpression);
972
1011
  const presentNames = obj ? obj.getProperties().map((pr) => {
973
- const pa = pr.asKind(SyntaxKind9.PropertyAssignment) ?? pr.asKind(SyntaxKind9.ShorthandPropertyAssignment);
1012
+ const pa = pr.asKind(SyntaxKind10.PropertyAssignment) ?? pr.asKind(SyntaxKind10.ShorthandPropertyAssignment);
974
1013
  return pa?.getName() ?? "";
975
1014
  }) : [];
976
1015
  const missingGroups = p.requiredProps.filter(
@@ -978,7 +1017,7 @@ var fixRequiredCallWithOptions = (c, p, outcome) => {
978
1017
  );
979
1018
  if (missingGroups.length === 0) return void 0;
980
1019
  const newProps = missingGroups.map((g) => placeholderFor(g[0])).join(", ");
981
- const summary = `Add ${missingGroups.map((g) => g[0]).join(" and ")} to the ${callName4(call)} call`;
1020
+ const summary = `Add ${missingGroups.map((g) => g[0]).join(" and ")} to the ${callName5(call)} call`;
982
1021
  if (obj) {
983
1022
  const inner = obj.getText().slice(1, -1).trim();
984
1023
  const newText = inner.length > 0 ? `{ ${inner}, ${newProps} }` : `{ ${newProps} }`;
@@ -990,7 +1029,7 @@ var fixRequiredCallWithOptions = (c, p, outcome) => {
990
1029
  }
991
1030
  return {
992
1031
  summary,
993
- suggestion: `Add an options object ({ ${newProps} }) as an argument to ${callName4(call)}.`
1032
+ suggestion: `Add an options object ({ ${newProps} }) as an argument to ${callName5(call)}.`
994
1033
  };
995
1034
  }
996
1035
  return {
@@ -1956,7 +1995,7 @@ function renderTrustGraphMd(g) {
1956
1995
  }
1957
1996
 
1958
1997
  // src/costAnalysis.ts
1959
- import { Project as Project2, SyntaxKind as SyntaxKind10 } from "ts-morph";
1998
+ import { Project as Project2, SyntaxKind as SyntaxKind11 } from "ts-morph";
1960
1999
  var LAMPORTS_PER_BYTE_YEAR = 3480;
1961
2000
  var EXEMPTION_THRESHOLD = 2;
1962
2001
  var OVERHEAD_BYTES = 128;
@@ -2037,11 +2076,11 @@ var KNOWN_FLOWS = [
2037
2076
  }
2038
2077
  ];
2039
2078
  var LOOP_NODE_KINDS = /* @__PURE__ */ new Set([
2040
- SyntaxKind10.ForStatement,
2041
- SyntaxKind10.ForOfStatement,
2042
- SyntaxKind10.ForInStatement,
2043
- SyntaxKind10.WhileStatement,
2044
- SyntaxKind10.DoStatement
2079
+ SyntaxKind11.ForStatement,
2080
+ SyntaxKind11.ForOfStatement,
2081
+ SyntaxKind11.ForInStatement,
2082
+ SyntaxKind11.WhileStatement,
2083
+ SyntaxKind11.DoStatement
2045
2084
  ]);
2046
2085
  var ARRAY_METHOD_LOOPS = /* @__PURE__ */ new Set(["map", "forEach", "flatMap", "reduce", "filter"]);
2047
2086
  function isInsideLoop(node) {
@@ -2049,12 +2088,12 @@ function isInsideLoop(node) {
2049
2088
  while (cur) {
2050
2089
  const k = cur.getKind?.();
2051
2090
  if (k !== void 0 && LOOP_NODE_KINDS.has(k)) {
2052
- return { scalable: true, note: `call is inside a ${SyntaxKind10[k]} \u2014 cost scales with loop iterations` };
2091
+ return { scalable: true, note: `call is inside a ${SyntaxKind11[k]} \u2014 cost scales with loop iterations` };
2053
2092
  }
2054
- if (k === SyntaxKind10.CallExpression) {
2093
+ if (k === SyntaxKind11.CallExpression) {
2055
2094
  const expr = cur.getExpression?.();
2056
- if (expr?.getKind?.() === SyntaxKind10.PropertyAccessExpression) {
2057
- const name = expr.asKind?.(SyntaxKind10.PropertyAccessExpression)?.getName?.();
2095
+ if (expr?.getKind?.() === SyntaxKind11.PropertyAccessExpression) {
2096
+ const name = expr.asKind?.(SyntaxKind11.PropertyAccessExpression)?.getName?.();
2058
2097
  if (name && ARRAY_METHOD_LOOPS.has(name)) {
2059
2098
  return { scalable: true, note: `call is inside .${name}() \u2014 cost scales with array length` };
2060
2099
  }
@@ -2068,7 +2107,7 @@ function detectPriorityFee(targetDir) {
2068
2107
  const project = new Project2({ skipAddingFilesFromTsConfig: true });
2069
2108
  for (const file of walk(targetDir)) {
2070
2109
  const sf = project.addSourceFileAtPath(file);
2071
- const calls = sf.getDescendantsOfKind(SyntaxKind10.CallExpression);
2110
+ const calls = sf.getDescendantsOfKind(SyntaxKind11.CallExpression);
2072
2111
  for (const ce of calls) {
2073
2112
  const expr = ce.getExpression();
2074
2113
  const text = expr.getText();
@@ -2096,22 +2135,22 @@ function detectAccountFlows(targetDir) {
2096
2135
  const importedModules = new Set(
2097
2136
  sf.getImportDeclarations().map((d) => d.getModuleSpecifierValue())
2098
2137
  );
2099
- for (const ce of sf.getDescendantsOfKind(SyntaxKind10.CallExpression)) {
2138
+ for (const ce of sf.getDescendantsOfKind(SyntaxKind11.CallExpression)) {
2100
2139
  const expr = ce.getExpression();
2101
- let callName5 = null;
2102
- if (expr.getKind() === SyntaxKind10.Identifier) {
2103
- callName5 = expr.getText();
2104
- } else if (expr.getKind() === SyntaxKind10.PropertyAccessExpression) {
2105
- callName5 = expr.asKind(SyntaxKind10.PropertyAccessExpression).getName();
2140
+ let callName6 = null;
2141
+ if (expr.getKind() === SyntaxKind11.Identifier) {
2142
+ callName6 = expr.getText();
2143
+ } else if (expr.getKind() === SyntaxKind11.PropertyAccessExpression) {
2144
+ callName6 = expr.asKind(SyntaxKind11.PropertyAccessExpression).getName();
2106
2145
  }
2107
- if (!callName5) continue;
2108
- const known = callIndex.get(callName5);
2146
+ if (!callName6) continue;
2147
+ const known = callIndex.get(callName6);
2109
2148
  if (!known) continue;
2110
2149
  if (!importedModules.has(known.module)) continue;
2111
2150
  const lamports = rentExemptMinimum(known.dataLen);
2112
2151
  const { scalable, note } = isInsideLoop(ce);
2113
2152
  flows.push({
2114
- call: callName5,
2153
+ call: callName6,
2115
2154
  module: known.module,
2116
2155
  accountType: known.accountType,
2117
2156
  file,
package/dist/cli.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  submitTelemetry,
21
21
  telemetryFilePath,
22
22
  validatePack
23
- } from "./chunk-5LJXC66F.js";
23
+ } from "./chunk-LOPYKIXE.js";
24
24
 
25
25
  // src/cli.ts
26
26
  import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
package/dist/index.js CHANGED
@@ -50,7 +50,7 @@ import {
50
50
  testKinds,
51
51
  validatePack,
52
52
  validatePackManifest
53
- } from "./chunk-5LJXC66F.js";
53
+ } from "./chunk-LOPYKIXE.js";
54
54
 
55
55
  // src/generate.ts
56
56
  import { writeFileSync, mkdirSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainblast",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "description": "Deterministic auditor for catastrophic AI-integration bugs: scan a repo, find the silent money/auth traps, and generate the behavioral test that proves they're fixed.",
6
6
  "keywords": [