@homenshum/convex-mcp-nodebench 0.9.5 → 0.9.6

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/index.js CHANGED
@@ -79,7 +79,7 @@ for (const tool of ALL_TOOLS) {
79
79
  // ── Server setup ────────────────────────────────────────────────────
80
80
  const server = new Server({
81
81
  name: "convex-mcp-nodebench",
82
- version: "0.9.5",
82
+ version: "0.9.6",
83
83
  }, {
84
84
  capabilities: {
85
85
  tools: {},
@@ -81,12 +81,13 @@ function auditAuthorization(convexDir) {
81
81
  const identityAssign = body.match(/(?:const|let)\s+(\w+)\s*=\s*await\s+ctx\.auth\.getUserIdentity\s*\(\s*\)/);
82
82
  if (identityAssign) {
83
83
  const varName = identityAssign[1];
84
- // Recognize: if (!var), if (var === null), if (var), var &&, var ?, throw on !var
85
- const hasNullCheck = new RegExp(`if\\s*\\(\\s*!${varName}\\b|if\\s*\\(\\s*${varName}\\s*===?\\s*null|if\\s*\\(\\s*${varName}\\s*\\)|${varName}\\s*&&|${varName}\\s*\\?|throw.*!${varName}|${varName}\\s*!==?\\s*null`).test(body);
84
+ // Recognize: if (!var), if (var === null), if (var), var &&, var ?, throw on !var, comparisons
85
+ const hasNullCheck = new RegExp(`if\\s*\\(\\s*!${varName}\\b|if\\s*\\(\\s*${varName}\\s*===?\\s*null|if\\s*\\(\\s*${varName}\\s*\\)|${varName}\\s*&&|${varName}\\s*\\?|throw.*!${varName}|${varName}\\s*!==?\\s*null|===\\s*${varName}|!==\\s*${varName}`).test(body);
86
86
  if (!hasNullCheck) {
87
87
  uncheckedIdentity++;
88
+ // Queries can intentionally return different data for auth/unauth — warning not critical
88
89
  issues.push({
89
- severity: "critical",
90
+ severity: ft === "query" ? "warning" : "critical",
90
91
  location: `${relativePath}:${i + 1}`,
91
92
  functionName: funcName,
92
93
  message: `${ft} "${funcName}" calls getUserIdentity() but doesn't check for null. Unauthenticated users will get undefined identity.`,
@@ -98,12 +99,13 @@ function auditAuthorization(convexDir) {
98
99
  const authUserAssign = body.match(/(?:const|let)\s+(\w+)\s*=\s*await\s+getAuthUserId\s*\(/);
99
100
  if (authUserAssign) {
100
101
  const varName = authUserAssign[1];
101
- // Recognize: if (!var), if (var === null), if (var), var &&, var ?, throw on !var
102
- const hasNullCheck = new RegExp(`if\\s*\\(\\s*!${varName}\\b|if\\s*\\(\\s*${varName}\\s*===?\\s*null|if\\s*\\(\\s*${varName}\\s*\\)|${varName}\\s*&&|${varName}\\s*\\?|throw.*!${varName}|${varName}\\s*!==?\\s*null`).test(body);
102
+ // Recognize: if (!var), if (var === null), if (var), var &&, var ?, throw on !var, comparisons
103
+ const hasNullCheck = new RegExp(`if\\s*\\(\\s*!${varName}\\b|if\\s*\\(\\s*${varName}\\s*===?\\s*null|if\\s*\\(\\s*${varName}\\s*\\)|${varName}\\s*&&|${varName}\\s*\\?|throw.*!${varName}|${varName}\\s*!==?\\s*null|===\\s*${varName}|!==\\s*${varName}`).test(body);
103
104
  if (!hasNullCheck) {
104
105
  uncheckedIdentity++;
106
+ // Queries can intentionally return different data for auth/unauth — warning not critical
105
107
  issues.push({
106
- severity: "critical",
108
+ severity: ft === "query" ? "warning" : "critical",
107
109
  location: `${relativePath}:${i + 1}`,
108
110
  functionName: funcName,
109
111
  message: `${ft} "${funcName}" calls getAuthUserId() but doesn't check for null. Unauthenticated users will get null userId.`,
@@ -76,8 +76,11 @@ function auditFunctions(convexDir) {
76
76
  if (fn.type === "httpAction")
77
77
  continue; // httpActions don't have args/returns validators
78
78
  if (!fn.hasArgs) {
79
+ // Public mutations/actions without args validators are a security concern (unvalidated client input)
80
+ // Queries and internal functions: just a best-practice recommendation
81
+ const isSecurity = !fn.isInternal && (fn.type === "mutation" || fn.type === "action");
79
82
  issues.push({
80
- severity: "critical",
83
+ severity: isSecurity ? "critical" : "warning",
81
84
  location: `${fn.relativePath}:${fn.line}`,
82
85
  functionName: fn.name,
83
86
  message: `${fn.type} "${fn.name}" is missing args validator`,
@@ -94,8 +97,9 @@ function auditFunctions(convexDir) {
94
97
  });
95
98
  }
96
99
  if (!fn.hasHandler) {
100
+ // Old shorthand syntax (query(async (ctx) => {})) works fine — just a style recommendation
97
101
  issues.push({
98
- severity: "critical",
102
+ severity: "warning",
99
103
  location: `${fn.relativePath}:${fn.line}`,
100
104
  functionName: fn.name,
101
105
  message: `${fn.type} "${fn.name}" is missing handler property (may be using old syntax)`,
@@ -284,7 +288,7 @@ export const functionTools = [
284
288
  const functions = extractFunctions(convexDir);
285
289
  // Store audit result
286
290
  const db = getDb();
287
- db.prepare("INSERT INTO audit_results (id, project_dir, audit_type, issues_json, issue_count) VALUES (?, ?, ?, ?, ?)").run(genId("audit"), projectDir, "function_audit", JSON.stringify(issues), issues.length);
291
+ db.prepare("INSERT INTO audit_results (id, project_dir, audit_type, issues_json, issue_count) VALUES (?, ?, ?, ?, ?)").run(genId("audit"), projectDir, "functions", JSON.stringify(issues), issues.length);
288
292
  const critical = issues.filter((i) => i.severity === "critical");
289
293
  const warnings = issues.filter((i) => i.severity === "warning");
290
294
  // Aggregate issues by category for cleaner output
@@ -75,7 +75,7 @@ function buildSarif(projectDir, auditTypes, limit) {
75
75
  tool: {
76
76
  driver: {
77
77
  name: "convex-mcp-nodebench",
78
- version: "0.9.5",
78
+ version: "0.9.6",
79
79
  informationUri: "https://www.npmjs.com/package/@homenshum/convex-mcp-nodebench",
80
80
  rules: [...rulesMap.values()],
81
81
  },
@@ -133,7 +133,7 @@ export const storageAuditTools = [
133
133
  }
134
134
  const { issues, stats } = auditStorageUsage(convexDir);
135
135
  const db = getDb();
136
- db.prepare("INSERT INTO audit_results (id, project_dir, audit_type, issues_json, issue_count) VALUES (?, ?, ?, ?, ?)").run(genId("audit"), projectDir, "storage_usage", JSON.stringify(issues), issues.length);
136
+ db.prepare("INSERT INTO audit_results (id, project_dir, audit_type, issues_json, issue_count) VALUES (?, ?, ?, ?, ?)").run(genId("audit"), projectDir, "storage", JSON.stringify(issues), issues.length);
137
137
  return {
138
138
  summary: {
139
139
  ...stats,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homenshum/convex-mcp-nodebench",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "description": "Convex-specific MCP server applying NodeBench self-instruct diligence patterns to Convex development. Schema audit, function compliance, deployment gates, persistent gotcha DB, and methodology guidance. Complements Context7 (raw docs) and official Convex MCP (deployment introspection) with structured verification workflows.",
5
5
  "type": "module",
6
6
  "bin": {