Skip to content

Commit 24bee57

Browse files
authored
Merge pull request #1437 from DeusData/fix/1425-no-corrupt-litter-on-invalid-name
fix(mcp): stop quarantining an anonymous temp db on invalid project names (#1425)
2 parents 5da4698 + 99dfc19 commit 24bee57

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

‎src/mcp/mcp.c‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,14 @@ static bool quarantine_corrupt_store(cbm_mcp_server_t *srv, const char *project,
20032003
char *backup_out, size_t backup_out_size) {
20042004
char backup[CBM_SZ_2K];
20052005
char pending[CBM_SZ_2K];
2006+
/* #1425 belt-and-braces: an empty store path would render the backup as a
2007+
* bare relative ".corrupt.<hex>" in the process cwd. There is nothing at
2008+
* such a path worth quarantining. */
2009+
if (!path || !path[0]) {
2010+
cbm_log_error("store.auto_clean_failed", "project", project, "path", "", "reason",
2011+
"empty store path");
2012+
return false;
2013+
}
20062014
if (!reserve_unique_corrupt_pending(path, pending, sizeof(pending), backup, sizeof(backup))) {
20072015
cbm_log_error("store.auto_clean_failed", "project", project, "path", path, "reason",
20082016
"cannot reserve unique backup");
@@ -2090,10 +2098,16 @@ static cbm_store_t *resolve_store_internal(cbm_mcp_server_t *srv, const char *pr
20902098
}
20912099

20922100
/* Open project's .db file — query-only open (no SQLITE_OPEN_CREATE) to
2093-
* prevent ghost .db file creation for unknown/unindexed projects. */
2101+
* prevent ghost .db file creation for unknown/unindexed projects.
2102+
* #1425: an invalid project name yields an empty path. SQLite opens ""
2103+
* as an anonymous temp db, which then fails the integrity check and
2104+
* quarantines a db that never existed — as a RELATIVE .corrupt.<hex>
2105+
* file in the daemon's cwd. Skip the direct open entirely; the fallback
2106+
* scan below still resolves legacy dbs whose internal name predates
2107+
* validation. */
20942108
char path[CBM_SZ_1K];
20952109
project_db_path(project, path, sizeof(path));
2096-
srv->store = cbm_store_open_path_query(path);
2110+
srv->store = path[0] ? cbm_store_open_path_query(path) : NULL;
20972111
if (srv->store) {
20982112
/* Check DB integrity — back up (never silently delete) a corrupt DB */
20992113
if (!cbm_store_check_integrity(srv->store)) {

‎tests/test_mcp.c‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2551,6 +2551,53 @@ TEST(tool_trace_call_path_not_found) {
25512551
PASS();
25522552
}
25532553

2554+
/* Regression for #1425: a project name that fails validation must produce a
2555+
* clean "not found" error and NOTHING else. project_db_path() yields "" for
2556+
* such names; SQLite opens "" as an anonymous temp db, its integrity check
2557+
* fails, and quarantine rendered "".corrupt.<hex> - a RELATIVE path dropped
2558+
* into the daemon's cwd on every such query. */
2559+
TEST(tool_call_invalid_project_name_leaves_no_corrupt_litter_issue1425) {
2560+
char tmpdir[256];
2561+
snprintf(tmpdir, sizeof(tmpdir), "/tmp/mcp-litter-XXXXXX");
2562+
if (!cbm_mkdtemp(tmpdir))
2563+
FAIL("cbm_mkdtemp failed");
2564+
char oldcwd[CBM_SZ_1K];
2565+
if (!cbm_getcwd(oldcwd, sizeof(oldcwd)))
2566+
FAIL("getcwd failed");
2567+
if (cbm_chdir(tmpdir) != 0)
2568+
FAIL("chdir failed");
2569+
2570+
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
2571+
char *resp =
2572+
cbm_mcp_server_handle(srv, "{\"jsonrpc\":\"2.0\",\"id\":30,\"method\":\"tools/call\","
2573+
"\"params\":{\"name\":\"search_graph\","
2574+
"\"arguments\":{\"name_pattern\":\"x\","
2575+
"\"project\":\"bad name\"}}}");
2576+
bool clean_error = resp && strstr(resp, "not found") != NULL;
2577+
free(resp);
2578+
cbm_mcp_server_free(srv);
2579+
2580+
int litter = 0;
2581+
cbm_dir_t *dir = cbm_opendir(tmpdir);
2582+
if (dir) {
2583+
cbm_dirent_t *entry;
2584+
while ((entry = cbm_readdir(dir)) != NULL) {
2585+
if (strstr(entry->name, ".corrupt.")) {
2586+
litter++;
2587+
}
2588+
}
2589+
cbm_closedir(dir);
2590+
}
2591+
if (cbm_chdir(oldcwd) != 0)
2592+
FAIL("chdir back failed");
2593+
th_rmtree(tmpdir);
2594+
if (!clean_error)
2595+
FAIL("invalid project name must produce a clean not-found error");
2596+
if (litter != 0)
2597+
FAIL("invalid project name must not quarantine an anonymous temp db into cwd (#1425)");
2598+
PASS();
2599+
}
2600+
25542601
TEST(tool_trace_missing_function_name) {
25552602
cbm_mcp_server_t *srv = cbm_mcp_server_new(NULL);
25562603

@@ -10352,6 +10399,7 @@ SUITE(mcp) {
1035210399

1035310400
/* Tool handlers with validation */
1035410401
RUN_TEST(tool_trace_call_path_not_found);
10402+
RUN_TEST(tool_call_invalid_project_name_leaves_no_corrupt_litter_issue1425);
1035510403
RUN_TEST(tool_trace_missing_function_name);
1035610404
RUN_TEST(tool_trace_call_path_ambiguous);
1035710405
RUN_TEST(tool_trace_union_records_min_hop_across_seeds);

0 commit comments

Comments
 (0)