mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
fix(pipeline): stop CI/tooling config URLs from minting infra Route nodes
URLs in .pre-commit-config.yaml, .github/workflows and similar CI configs are repository/action/registry references for the development toolchain, never endpoints the indexed service exposes. They matched is_infra_file (.yaml) and passed the #521 value guards, so each minted a __route__infra__<url> Route node; the route matcher's root-service heuristic then attached every handler of an ambiguous '/' route to each junk URL - 6-7 junk HANDLES targets per handler on plain pallets/flask, with tie-break-dependent winners feeding HANDLES churn between builds. Deny by file identity (well-known CI/tooling basenames plus .github/, .gitlab/, .circleci/ trees) in cbm_pipeline_extract_infra_routes, not by URL shape: deployment configs (Cloud Scheduler push endpoints, compose) keep minting their genuine endpoints, guarded by an inverse test. Closes #999 Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
1 parent
8c9ac98e30
commit
f7b5a856f5
2 files changed
+139
-1
No files matched your search
+43
-1
@@ -613,6 +613,47 @@ static bool is_infra_file(const char *fp) {
|
||||
strstr(fp, ".tf") != NULL || strstr(fp, ".hcl") != NULL || strstr(fp, ".toml") != NULL);
|
||||
}
|
||||
|
||||
/* CI/tooling configs describe the development TOOLCHAIN — their URLs are
|
||||
* repository/action/registry references, never endpoints this service
|
||||
* exposes. Minting infra Route nodes from them lets the route matcher's
|
||||
* root-service heuristic attach every handler of an ambiguous "/" route to
|
||||
* each tooling URL (junk HANDLES churn on plain pallets/flask, #999).
|
||||
* Deny by file identity, not URL shape: deployment configs (Cloud
|
||||
* Scheduler, compose) keep minting their genuine endpoints. */
|
||||
static bool is_ci_tooling_config(const char *fp) {
|
||||
if (!fp) {
|
||||
return false;
|
||||
}
|
||||
if (strstr(fp, ".github/") != NULL || strstr(fp, ".gitlab/") != NULL ||
|
||||
strstr(fp, ".circleci/") != NULL) {
|
||||
return true;
|
||||
}
|
||||
const char *slash = strrchr(fp, '/');
|
||||
const char *base = slash ? slash + 1 : fp;
|
||||
static const char *const tooling[] = {".pre-commit-config.yaml",
|
||||
".pre-commit-hooks.yaml",
|
||||
".gitlab-ci.yml",
|
||||
".travis.yml",
|
||||
"azure-pipelines.yml",
|
||||
"appveyor.yml",
|
||||
"bitbucket-pipelines.yml",
|
||||
".readthedocs.yaml",
|
||||
".readthedocs.yml",
|
||||
"codecov.yml",
|
||||
".codecov.yml",
|
||||
".goreleaser.yaml",
|
||||
".goreleaser.yml",
|
||||
".golangci.yml",
|
||||
".golangci.yaml",
|
||||
NULL};
|
||||
for (int i = 0; tooling[i]; i++) {
|
||||
if (strcmp(base, tooling[i]) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* True when a YAML key path denotes an UPSTREAM dependency, CONFIG value, or
|
||||
* HEALTHCHECK target rather than an endpoint this service exposes. Such URLs
|
||||
* (auth JWKS, downstream service base URLs, package-registry URLs, healthcheck
|
||||
@@ -681,7 +722,8 @@ static void cbm_pipeline_extract_infra_routes(cbm_gbuf_t *gbuf, const cbm_file_i
|
||||
CBMHashTable *denied = cbm_ht_create(16);
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
for (int i = 0; i < file_count; i++) {
|
||||
if (!result_cache[i] || !is_infra_file(files[i].rel_path)) {
|
||||
if (!result_cache[i] || !is_infra_file(files[i].rel_path) ||
|
||||
is_ci_tooling_config(files[i].rel_path)) {
|
||||
continue;
|
||||
}
|
||||
for (int si = 0; si < result_cache[i]->string_refs.count; si++) {
|
||||
|
||||
@@ -1202,6 +1202,100 @@ TEST(contract_edge_imports_alias_resolves_real_file_issue767) {
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* #999: URLs in CI/tooling configs (.pre-commit-config.yaml, .github/
|
||||
* workflows) are repository references for TOOLING, not endpoints this
|
||||
* service exposes. They must not mint __route__infra__ Route nodes — the
|
||||
* route matcher's root-service heuristic otherwise attaches every handler
|
||||
* of an ambiguous "/" route to each junk URL (HANDLES churn on plain
|
||||
* pallets/flask). */
|
||||
static int count_infra_routes_matching(cbm_store_t *store, const char *project,
|
||||
const char *substr) {
|
||||
cbm_node_t *nodes = NULL;
|
||||
int count = 0;
|
||||
if (cbm_store_find_nodes_by_label(store, project, "Route", &nodes, &count) != CBM_STORE_OK)
|
||||
return -1;
|
||||
int hits = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
const char *qn = nodes[i].qualified_name;
|
||||
if (qn && strncmp(qn, "__route__infra__", (sizeof("__route__infra__") - 1)) == 0 &&
|
||||
strstr(qn, substr))
|
||||
hits++;
|
||||
}
|
||||
cbm_store_free_nodes(nodes, count);
|
||||
return hits;
|
||||
}
|
||||
|
||||
TEST(contract_edge_no_infra_routes_from_ci_configs_issue999) {
|
||||
LangProj lp;
|
||||
static const LangFile f[] = {
|
||||
{"app.py", "from flask import Flask\n"
|
||||
"app = Flask(__name__)\n"
|
||||
"\n"
|
||||
"@app.route(\"/\")\n"
|
||||
"def index():\n"
|
||||
" return \"hi\"\n"
|
||||
"\n"
|
||||
"@app.route(\"/auth/login\")\n"
|
||||
"def login():\n"
|
||||
" return \"login\"\n"},
|
||||
{".pre-commit-config.yaml", "repos:\n"
|
||||
" - repo: https://github.com/astral-sh/ruff-pre-commit\n"
|
||||
" rev: v0.1.0\n"
|
||||
" hooks:\n"
|
||||
" - id: ruff\n"
|
||||
" - repo: https://github.com/pre-commit/pre-commit-hooks\n"
|
||||
" rev: v4.5.0\n"
|
||||
" hooks:\n"
|
||||
" - id: trailing-whitespace\n"},
|
||||
{".github/workflows/ci.yml", "name: CI\n"
|
||||
"on: [push]\n"
|
||||
"jobs:\n"
|
||||
" build:\n"
|
||||
" runs-on: ubuntu-latest\n"
|
||||
" steps:\n"
|
||||
" - uses: actions/checkout@v4\n"
|
||||
" - run: curl https://coverage.example.io/upload\n"}};
|
||||
cbm_store_t *store = lang_index_files(&lp, f, 3);
|
||||
ASSERT_NOT_NULL(store);
|
||||
/* No tooling URL may materialize as an infra Route node. */
|
||||
int gh_routes = count_infra_routes_matching(store, lp.project, "github.com");
|
||||
int wf_routes = count_infra_routes_matching(store, lp.project, "coverage.example.io");
|
||||
if (gh_routes != 0 || wf_routes != 0) {
|
||||
fprintf(stderr,
|
||||
" [999] FAIL infra routes from CI configs: github.com=%d workflows=%d "
|
||||
"(expected 0/0)\n",
|
||||
gh_routes, wf_routes);
|
||||
}
|
||||
ASSERT_EQ(gh_routes, 0);
|
||||
ASSERT_EQ(wf_routes, 0);
|
||||
lang_cleanup(&lp, store);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* #999 inverse guard: genuine infra endpoint URLs (Cloud Scheduler push
|
||||
* targets and similar deployment configs) must STILL mint infra Route
|
||||
* nodes — the CI/tooling deny must be file-scoped, not a blanket URL kill. */
|
||||
TEST(contract_edge_infra_routes_from_deploy_configs_still_minted) {
|
||||
LangProj lp;
|
||||
static const LangFile f[] = {
|
||||
{"scheduler.yaml",
|
||||
"jobs:\n"
|
||||
" - name: nightly-sync\n"
|
||||
" schedule: \"0 3 * * *\"\n"
|
||||
" push_endpoint: https://sync.internal.example/api/v1/sync\n"}};
|
||||
cbm_store_t *store = lang_index_files(&lp, f, 1);
|
||||
ASSERT_NOT_NULL(store);
|
||||
int routes = count_infra_routes_matching(store, lp.project, "sync.internal.example");
|
||||
if (routes < 1) {
|
||||
fprintf(stderr, " [999] FAIL deploy-config endpoint minted %d infra routes "
|
||||
"(expected >=1)\n",
|
||||
routes);
|
||||
}
|
||||
ASSERT_TRUE(routes >= 1);
|
||||
lang_cleanup(&lp, store);
|
||||
PASS();
|
||||
}
|
||||
|
||||
/* DEPENDS_ON — Helm Chart.yaml `dependencies:` -> per-dependency Chart node.
|
||||
* Basename must be exactly "Chart.yaml"; pass_k8s runs in both pipeline paths. */
|
||||
TEST(contract_edge_depends_on) {
|
||||
@@ -1411,6 +1505,8 @@ SUITE(lang_contract) {
|
||||
RUN_TEST(contract_edge_workspaces_imports_issue408);
|
||||
RUN_TEST(contract_edge_imports_alias_no_phantom_folder_edge_issue767);
|
||||
RUN_TEST(contract_edge_imports_alias_resolves_real_file_issue767);
|
||||
RUN_TEST(contract_edge_no_infra_routes_from_ci_configs_issue999);
|
||||
RUN_TEST(contract_edge_infra_routes_from_deploy_configs_still_minted);
|
||||
RUN_TEST(contract_edge_depends_on);
|
||||
RUN_TEST(contract_edge_parallel_service_edges);
|
||||
RUN_TEST(contract_edge_file_changes_with);
|
||||
|
||||
Reference in new issue
Block a user