Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/memory-core-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ src/git/git_context.c 18
src/main.c 32
src/mcp/compact_out.c 39
src/mcp/index_supervisor.c 8
src/mcp/mcp.c 814
src/mcp/mcp.c 785
src/pipeline/artifact.c 38
src/pipeline/fqn.c 23
src/pipeline/lsp_resolve.h 4
Expand Down
57 changes: 22 additions & 35 deletions src/mcp/mcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -11062,6 +11062,16 @@ static bool project_db_is_servable(const char *project, const char *db_path) {
return servable;
}

/* The three heap strings handle_index_repository owns from
* cbm_mcp_get_string_arg / resolved_repo_path_from_project_arg. One release
* point keeps the dozen early-return paths in step; free(NULL) is a no-op, so
* a path may pass NULL for an argument it never obtained. */
static void index_args_free(char *repo_path, char *mode_str, char *name_override) {
free(repo_path);
free(mode_str);
free(name_override);
}

static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
char *repo_path = cbm_mcp_get_string_arg(args, "repo_path");
char *mode_str = cbm_mcp_get_string_arg(args, "mode");
Expand All @@ -11074,15 +11084,12 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
}

if (!repo_path) {
free(mode_str);
free(name_override);
index_args_free(NULL, mode_str, name_override);
return cbm_mcp_text_result("repo_path is required", true);
}

if (!resolve_session_repo_path(srv, &repo_path)) {
free(mode_str);
free(name_override);
free(repo_path);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result("failed to resolve repo_path", true);
}

Expand All @@ -11102,26 +11109,20 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
if (repo_path && repo_path[0] &&
!cbm_workspace_root_allowed(repo_path, cbm_workspace_home_dir(), cbm_workspace_cache_dir(),
allowed_root, boundary_err, sizeof(boundary_err))) {
free(mode_str);
free(name_override);
free(repo_path);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result(boundary_err, true);
}

if (mode_str && strcmp(mode_str, "cross-repo-intelligence") == 0) {
free(mode_str);
char *result = handle_cross_repo_mode(srv, repo_path, name_override, args);
free(name_override);
free(repo_path);
index_args_free(repo_path, mode_str, name_override);
return result;
}

cbm_index_resource_policy_t resource_policy;
char policy_error[CBM_SZ_256] = {0};
if (!load_index_policy(srv, args, &resource_policy, policy_error, sizeof(policy_error))) {
free(mode_str);
free(name_override);
free(repo_path);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result(policy_error, true);
}

Expand All @@ -11133,9 +11134,7 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
worker_args ? srv->index_executor(srv->index_executor_context, repo_path, worker_args)
: NULL;
free(worker_args);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return coordinated ? coordinated
: cbm_mcp_text_result(
"daemon index coordinator could not start the operation", true);
Expand All @@ -11148,9 +11147,7 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
char *mutation_project =
cbm_project_name_from_path(name_override && name_override[0] ? name_override : repo_path);
if (!mutation_project) {
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result("could not resolve index project name", true);
}

Expand All @@ -11163,24 +11160,18 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {
char *worker_args = index_args_with_repo_path(args, repo_path, &resource_policy);
if (!worker_args) {
free(mutation_project);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result("failed to prepare supervised index request", true);
}
char *supervised = index_run_supervised(srv, worker_args);
free(worker_args);
if (supervised) {
free(mutation_project);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return supervised;
}
free(mutation_project);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result(
"index supervision failed before a contained worker could start; no "
"in-process fallback was attempted",
Expand All @@ -11189,18 +11180,14 @@ static char *handle_index_repository(cbm_mcp_server_t *srv, const char *args) {

if (!mcp_project_mutation_begin(srv, mutation_project)) {
free(mutation_project);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result("index operation blocked by another mutation for this project",
true);
}
if (mcp_request_cancelled(srv)) {
mcp_project_mutation_end(srv, mutation_project);
free(mutation_project);
free(repo_path);
free(mode_str);
free(name_override);
index_args_free(repo_path, mode_str, name_override);
return cbm_mcp_text_result("index operation cancelled for this request", true);
}

Expand Down
11 changes: 9 additions & 2 deletions tests/test_worker_session_scope.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,15 @@ run_worker() {
--response-out "${response}" >"${out}" 2>"${err}"
}

# A worker never reads the resource policy from config or environment: the
# supervisor resolves it and sends it inside the request, and a request
# without one is refused ("missing or incomplete trusted worker policy").
# This script plays the supervisor, so it sends what the supervisor sends --
# both limits off, the default.
policy='"_cbm_index_policy":{"index_max_files":"off","index_max_source_mb":"off"}'

response="${tmpdir}/scoped.response"
if ! run_worker "{\"repo_path\":\"${repo}\",\"mode\":\"fast\"}" "${response}" \
if ! run_worker "{\"repo_path\":\"${repo}\",\"mode\":\"fast\",${policy}}" "${response}" \
"${tmpdir}/scoped.out" "${tmpdir}/scoped.err"; then
echo "worker exited nonzero for an admitted request" >&2
cat "${tmpdir}/scoped.err" >&2
Expand All @@ -94,7 +101,7 @@ fi

# Fail closed: no repo_path means no request scope, so no indexing at all.
unscoped="${tmpdir}/unscoped.response"
if run_worker '{"mode":"fast"}' "${unscoped}" "${tmpdir}/unscoped.out" "${tmpdir}/unscoped.err"; then
if run_worker "{\"mode\":\"fast\",${policy}}" "${unscoped}" "${tmpdir}/unscoped.out" "${tmpdir}/unscoped.err"; then
echo "worker ran without a request workspace scope" >&2
exit 1
fi
Expand Down
Loading