@@ -1207,6 +1207,100 @@ TEST(contract_edge_imports_alias_resolves_real_file_issue767) {
12071207 PASS ();
12081208}
12091209
1210+ /* #999: URLs in CI/tooling configs (.pre-commit-config.yaml, .github/
1211+ * workflows) are repository references for TOOLING, not endpoints this
1212+ * service exposes. They must not mint __route__infra__ Route nodes — the
1213+ * route matcher's root-service heuristic otherwise attaches every handler
1214+ * of an ambiguous "/" route to each junk URL (HANDLES churn on plain
1215+ * pallets/flask). */
1216+ static int count_infra_routes_matching (cbm_store_t * store , const char * project ,
1217+ const char * substr ) {
1218+ cbm_node_t * nodes = NULL ;
1219+ int count = 0 ;
1220+ if (cbm_store_find_nodes_by_label (store , project , "Route" , & nodes , & count ) != CBM_STORE_OK )
1221+ return -1 ;
1222+ int hits = 0 ;
1223+ for (int i = 0 ; i < count ; i ++ ) {
1224+ const char * qn = nodes [i ].qualified_name ;
1225+ if (qn && strncmp (qn , "__route__infra__" , (sizeof ("__route__infra__" ) - 1 )) == 0 &&
1226+ strstr (qn , substr ))
1227+ hits ++ ;
1228+ }
1229+ cbm_store_free_nodes (nodes , count );
1230+ return hits ;
1231+ }
1232+
1233+ TEST (contract_edge_no_infra_routes_from_ci_configs_issue999 ) {
1234+ LangProj lp ;
1235+ static const LangFile f [] = {
1236+ {"app.py" , "from flask import Flask\n"
1237+ "app = Flask(__name__)\n"
1238+ "\n"
1239+ "@app.route(\"/\")\n"
1240+ "def index():\n"
1241+ " return \"hi\"\n"
1242+ "\n"
1243+ "@app.route(\"/auth/login\")\n"
1244+ "def login():\n"
1245+ " return \"login\"\n" },
1246+ {".pre-commit-config.yaml" , "repos:\n"
1247+ " - repo: https://github.com/astral-sh/ruff-pre-commit\n"
1248+ " rev: v0.1.0\n"
1249+ " hooks:\n"
1250+ " - id: ruff\n"
1251+ " - repo: https://github.com/pre-commit/pre-commit-hooks\n"
1252+ " rev: v4.5.0\n"
1253+ " hooks:\n"
1254+ " - id: trailing-whitespace\n" },
1255+ {".github/workflows/ci.yml" , "name: CI\n"
1256+ "on: [push]\n"
1257+ "jobs:\n"
1258+ " build:\n"
1259+ " runs-on: ubuntu-latest\n"
1260+ " steps:\n"
1261+ " - uses: actions/checkout@v4\n"
1262+ " - run: curl https://coverage.example.io/upload\n" }};
1263+ cbm_store_t * store = lang_index_files (& lp , f , 3 );
1264+ ASSERT_NOT_NULL (store );
1265+ /* No tooling URL may materialize as an infra Route node. */
1266+ int gh_routes = count_infra_routes_matching (store , lp .project , "github.com" );
1267+ int wf_routes = count_infra_routes_matching (store , lp .project , "coverage.example.io" );
1268+ if (gh_routes != 0 || wf_routes != 0 ) {
1269+ fprintf (stderr ,
1270+ " [999] FAIL infra routes from CI configs: github.com=%d workflows=%d "
1271+ "(expected 0/0)\n" ,
1272+ gh_routes , wf_routes );
1273+ }
1274+ ASSERT_EQ (gh_routes , 0 );
1275+ ASSERT_EQ (wf_routes , 0 );
1276+ lang_cleanup (& lp , store );
1277+ PASS ();
1278+ }
1279+
1280+ /* #999 inverse guard: genuine infra endpoint URLs (Cloud Scheduler push
1281+ * targets and similar deployment configs) must STILL mint infra Route
1282+ * nodes — the CI/tooling deny must be file-scoped, not a blanket URL kill. */
1283+ TEST (contract_edge_infra_routes_from_deploy_configs_still_minted ) {
1284+ LangProj lp ;
1285+ static const LangFile f [] = {
1286+ {"scheduler.yaml" ,
1287+ "jobs:\n"
1288+ " - name: nightly-sync\n"
1289+ " schedule: \"0 3 * * *\"\n"
1290+ " push_endpoint: https://sync.internal.example/api/v1/sync\n" }};
1291+ cbm_store_t * store = lang_index_files (& lp , f , 1 );
1292+ ASSERT_NOT_NULL (store );
1293+ int routes = count_infra_routes_matching (store , lp .project , "sync.internal.example" );
1294+ if (routes < 1 ) {
1295+ fprintf (stderr , " [999] FAIL deploy-config endpoint minted %d infra routes "
1296+ "(expected >=1)\n" ,
1297+ routes );
1298+ }
1299+ ASSERT_TRUE (routes >= 1 );
1300+ lang_cleanup (& lp , store );
1301+ PASS ();
1302+ }
1303+
12101304/* True if some CALLS edge's TARGET node carries `label` and a QN ending with
12111305 * `qn_suffix` — i.e. the call resolved to that specific definition. */
12121306static int calls_edge_targets (cbm_store_t * store , const char * project , const char * label ,
@@ -1478,6 +1572,8 @@ SUITE(lang_contract) {
14781572 RUN_TEST (contract_edge_workspaces_imports_issue408 );
14791573 RUN_TEST (contract_edge_imports_alias_no_phantom_folder_edge_issue767 );
14801574 RUN_TEST (contract_edge_imports_alias_resolves_real_file_issue767 );
1575+ RUN_TEST (contract_edge_no_infra_routes_from_ci_configs_issue999 );
1576+ RUN_TEST (contract_edge_infra_routes_from_deploy_configs_still_minted );
14811577 RUN_TEST (contract_edge_commonjs_require_call_resolves_issue871 );
14821578 RUN_TEST (contract_edge_depends_on );
14831579 RUN_TEST (contract_edge_parallel_service_edges );
0 commit comments