Commit Graph
98 Commits
Author SHA1 Message Date
Martin Vogel b7e076c5d5 Fix Linux build: guard cbm_macos_adhoc_sign with #ifdef __APPLE__ 2026-03-25 00:12:10 +01:00
Martin Vogel fa97ea5b09 Fix CodeQL TOCTOU: use fchmod before fclose on gate script
CodeQL cpp/toctou-race-condition #32: fopen then chmod on the same
path allows a race where the file could be swapped between write
and chmod. Fix: use fchmod(fileno(f)) before fclose on POSIX.
Windows falls back to chmod (no fchmod).
2026-03-25 00:04:28 +01:00
Martin Vogel 7f579f91ad Add 480+ tests, fix 3 bugs discovered by new test coverage
New tests (6481 lines across 23 files):
- Arena: reset invariants, growth, sized init, destroy safety
- Dynamic array: capacity, remove, clear, grow patterns
- FQN: module/package/class name computation (592 lines)
- Graph buffer: node/edge CRUD, dedup, merge, concurrent access
- Hash table: collision, resize, iteration, edge cases
- MCP: tool dispatch, argument parsing, error handling
- Memory: allocation tracking, collection, limits
- Pipeline: test detection (path + func name patterns)
- Store: node/edge CRUD, search, batch ops, persistence
- String: intern dedup, util edge cases, YAML parsing (1105 lines)
- Traces: ingestion, dedup, query
- Watcher: baseline, polling, change detection
- Worker pool: task distribution, completion

Bugs found and fixed:
1. Arena reset overflow: block_size not reset to block_sizes[0]
   after growth — subsequent allocations could overflow blocks[0]
2. Test path detection: missing __tests__/, tests/, spec/ directory
   patterns and _spec.rb suffix
3. Test func detection: "Testable" falsely matched as Go test —
   now requires uppercase or end-of-string after "Test" prefix
2026-03-24 23:48:23 +01:00
Martin Vogel cbac7be1e0 Fix #139 #133 #137: thread stack, Windows paths, detect_changes
#139 Stack overflow in autoindex: all threads now get 8MB stack
by default (CBM_DEFAULT_STACK_SIZE). macOS ARM64 default was
512KB, too small for deep pipeline passes like configlink.

#133 search_code rejects Windows backslash paths: allow backslash
in cbm_validate_shell_arg on _WIN32 builds.

#137 detect_changes fails on paths with spaces: replace cd with
git -C flag, use double quotes on Windows.

Also fix arena test: allocations must exceed 64KB block size to
force multiple blocks (test was always wrong, never caught because
it wasn't in the test suite until now).
2026-03-24 23:14:33 +01:00
Martin Vogel eaf9c83066 Eliminate rename() — reindex deletes old DB, index writes directly
Architecture change to prevent concurrent write corruption:

  Indexing (new project): cbm_write_db writes project.db directly
  Reindexing (existing): delete project.db, then index as new
  Incremental: upsert changes into existing project.db (unchanged)

Root cause: rename(project.db.tmp, project.db) while watcher/MCP
had the old file open via SQLite caused WAL corruption — stale
connections wrote to deleted inodes.

Changes:
- cbm_gbuf_dump_to_sqlite: write to final path, no .tmp + rename
- pipeline.c: if DB exists but not eligible for incremental, delete
  it before proceeding with full index (reindex = delete + index)
- Pipeline lock (atomic spinlock) serializes concurrent runs:
  MCP/autoindex block, watcher skips if busy
- delete_project acquires pipeline lock before unlinking
- BEGIN IMMEDIATE for all write transactions (respects busy_timeout)
- cbm_store_check_integrity: detects corrupt DBs (>5 project rows
  or invalid root_path), auto-deletes with ERROR log
- cbm_store_get_db accessor for test corruption simulation

Tests: 5 integrity tests + 4 concurrency lock tests
2026-03-24 23:14:33 +01:00
Martin Vogel 68cc19ebf2 Auto-detect and clean corrupt index databases
Add cbm_store_check_integrity() that validates:
- projects table has <= 5 rows (1 project per .db file)
- root_path starts with / or drive letter (not numeric garbage)

Wire into resolve_store (MCP queries) and pipeline routing:
- MCP: corrupt DB auto-deleted with ERROR log, returns "not indexed"
- Pipeline: corrupt DB deleted, falls through to full reindex

Root cause: user-reported corrupt DBs had 48K rows in projects table
with node IDs in text columns. Exact write path TBD, but detection
+ auto-clean prevents the symptom from persisting.

5 unit tests: clean DB, empty DB, bad path, too many rows, NULL.
2026-03-24 23:14:33 +01:00
Martin Vogel abe319b46c Real E2E update/uninstall + CBM_DOWNLOAD_URL support
Add CBM_DOWNLOAD_URL env var to cbm_cmd_update and checksum
verification — allows E2E testing against local HTTP server.

Phase 14: runs actual update --standard -y against local server,
verifies binary replaced, agent configs refreshed (stale path
updated), then real uninstall -y verifies binary removed and
configs cleaned.

Phase 13: add PATH setup verification. Non-interactive stdin:
isatty() prevents silent hangs.
2026-03-24 23:14:33 +01:00
Martin Vogel da7638c651 Prevent silent hangs on non-interactive stdin
Add isatty() checks to prompt_yn() and update variant chooser.
When stdin is not a terminal and no -y/-n or --standard/--ui flag
is provided, print a clear error and exit instead of hanging on
fgets(). Prevents agents from silently blocking when running
install/update programmatically.

Add smoke test 9b-9: verify non-interactive update fails cleanly.
2026-03-24 23:14:33 +01:00
Martin Vogel 8951647d3e Fix remaining install/update gaps + in-memory zip extraction
Install command:
- Add cbm_kill_other_instances() to kill stale MCP servers
- Add cbm_macos_adhoc_sign() to sign binary if placed unsigned

Update command:
- Replace skills-only reinstall with full cbm_install_agent_configs()
- Replace external unzip with cbm_extract_binary_from_zip() via zlib

Refactor: extract 10-agent config loop into cbm_install_agent_configs()
called by both install and update.

New: cbm_extract_binary_from_zip() — in-memory zip extraction with
stored + deflate support, path traversal rejection, bounds checks.
4 unit tests. Smoke: add install.ps1 E2E for Windows.
2026-03-24 23:14:33 +01:00
Martin Vogel 006e6dbf20 Add install scripts, CI pre-signing, download E2E smoke tests
install.sh: one-liner for macOS/Linux — detects OS/arch (Rosetta-
aware), downloads release, verifies checksum, extracts, signs on
macOS, runs install -y for all 10 agents. Supports --ui flag and
CBM_DOWNLOAD_URL env var for testing.

install.ps1: one-liner for Windows — Invoke-WebRequest + Expand-
Archive + Unblock-File (strips MOTW), installs to %LOCALAPPDATA%,
adds to user PATH via [Environment]::SetEnvironmentVariable.

CI pre-signing: add codesign --sign - step for macOS builds in
both dry-run.yml and release.yml, before archiving. Release
binaries now ship pre-signed.

Phase 12 smoke tests: real HTTP download via local artifact server,
checksum verification, archive extraction, binary verification.
Runs only when SMOKE_DOWNLOAD_URL is set (CI provides it).

Phase 13 smoke tests: install.sh E2E — runs full script with local
URL + isolated HOME, verifies binary placed, signed, runs, and
agent configs created.

CI HTTP server: smoke jobs start python3 HTTP server serving the
built binary as a tar.gz/zip archive + checksums.txt. Enables
Phases 12-13 in CI on all platforms.

Update security allowlist: remove system() entry (eliminated),
add cbm_popen for pgrep. Update README with one-liner Quick Start.
2026-03-24 23:14:33 +01:00
Martin Vogel d2451c4fd6 Add comprehensive E2E smoke tests for install/update/uninstall
Phase 8: Agent config install E2E — creates stub environment with
all 10 agent detection dirs, runs install -y with isolated HOME,
verifies exact JSON structure, TOML content, hook format, skills,
and merge-not-overwrite behavior for every agent config.

Phase 9: Agent config uninstall E2E — verifies complete removal of
all MCP entries, hooks, instructions while preserving user's existing
config keys. Adversarial tests: idempotent double install, uninstall
without prior install, corrupt JSON/TOML handling, double uninstall.

Phase 10: Platform binary security — macOS: codesign verify, strip
signature, SIGKILL on unsigned arm64 (exit 137), re-sign + verify.
Linux/Windows: verify unsigned binary runs without signing.

Phase 11: Process kill — start MCP server, verify running, kill,
verify gone.

Phase 14: Update flow — binary replacement with signing, read-only
binary edge case, platform-specific verification.

Fix cbm_find_cli: add S_IXUSR check for hardcoded path search
(was missing, only checked for PATH-based search).
2026-03-24 23:14:33 +01:00
Martin Vogel d612dc415a Fix update command: replace system(), add macOS signing, kill stale servers
Replace system("curl ...") with cbm_exec_no_shell in both download
call sites (archive + checksums.txt) to eliminate shell injection risk.

Add cbm_macos_adhoc_sign() that removes quarantine xattr and ad-hoc
signs the binary after replacement — fixes SIGKILL (exit 137) on
macOS arm64 where unsigned binaries are killed by the kernel.

Add cbm_kill_other_instances() that finds and terminates running MCP
server processes before binary replacement, so stale servers don't
continue serving old code. Uses pgrep on POSIX, taskkill on Windows.
Skips own PID to avoid self-termination.
2026-03-24 23:14:33 +01:00
Martin Vogel c00723e5c8 Require project param on all MCP tool calls
Make project a required parameter for all query tools (search_graph,
query_graph, trace_call_path, get_code_snippet, get_graph_schema,
get_architecture, search_code, index_status, detect_changes,
manage_adr, ingest_traces). Removes implicit fallback to session
project or last-opened store.

When project is missing or not found, return error with list of
available indexed projects so agents can self-correct.

Rename delete_project param from project_name to project for
consistency. Fix smoke test trace_call_path depth param name
(max_depth -> depth).
2026-03-24 13:38:25 +01:00
Martin Vogel 20814e8b27 Add smoke tests to Docker test infra + CI pipeline
Expand smoke-test.sh with Phase 5 (MCP stdio transport), Phase 6
(CLI subcommands: install/uninstall/update --dry-run), and Phase 7
(MCP advanced tool calls: search_code v2, get_code_snippet).

Add smoke/smoke-amd64 services to Docker compose that build then
run all 7 smoke test phases. Include in run.sh full/all flows.

Add python3-minimal to Dockerfile for smoke test JSON parsing.
Fix Phase 4a shutdown test to use portable background+kill pattern
instead of `timeout` (not available on macOS).

Add --dry-run, --standard, --ui flags to update command. Fix
clang-tidy readability-implicit-bool-conversion in dry_run ternary.
2026-03-23 21:56:33 +01:00
Martin Vogel 7d6b3af341 Fix memory leak in resolve_store + Windows setenv build error
- resolve_store: verify project exists in database after opening;
  close store immediately if project is absent (prevents SQLite
  connection leak when querying deleted/empty projects)
- test_userconfig.c: use cbm_setenv/cbm_unsetenv instead of raw
  POSIX setenv/unsetenv (fixes Windows build)
2026-03-23 17:37:21 +01:00
Martin Vogel 8fc19497e7 Add cbm_replace_binary: unlink-before-write for update command
TDD: two tests (overwrite read-only file, create new file) written
first, then cbm_replace_binary() implemented and wired into update.

The update command failed when the existing binary had no write
permission (e.g., 0500). unlink() only requires write permission on
the parent directory, not the file itself, so removing first then
creating with O_CREAT | 0755 handles all permission combinations.

Fixes #114.
2026-03-23 15:47:05 +01:00
Martin Vogel 7e78e302f2 Fix Windows UI zip filename + clang-format store.c
- release.yml: UI zip now contains codebase-memory-mcp.exe (not -ui.exe),
  matching the Unix tar.gz convention (Fixes #110)
- store.c: clang-format fix from PR #124 merge
2026-03-23 15:33:35 +01:00
Martin Vogel 8f59934fcf Merge branch 'main' into fix/manage-adr-use-after-free 2026-03-23 15:13:27 +01:00
Martin Vogel 2d20996139 Merge branch 'main' into fix/security-sql-argument-injection 2026-03-23 15:04:42 +01:00
Martin Vogel 4788b0d396 Fix session project name mismatch with indexed project name
detect_session used a two-component path algorithm (e.g. "project_dir-
codebase-memory-mcp") while the pipeline used cbm_project_name_from_path
with the full absolute path (e.g. "Users-martinvogel-project_dir-
codebase-memory-mcp"). This caused session queries to look for a .db
file that didn't match the indexed name, silently returning empty results.

Fix: use cbm_project_name_from_path in detect_session so both paths
produce the same project name. Update integration test to accept guard
error after project deletion (correct new behavior from PR #120).
2026-03-23 14:53:27 +01:00
Martin Vogel c788469722 Merge branch 'main' into fix/store-open-create-guards 2026-03-23 14:39:16 +01:00
Martin Vogel b4a951219a Merge branch 'main' into fix/wal-busy-timeout-ordering 2026-03-23 14:34:11 +01:00
Shane McCarronandClaude Sonnet 4.6 822a56f0df fix(mcp): fix use-after-free in handle_manage_adr get path
yyjson_mut_obj_add_str stores the raw pointer without copying. Freeing
buf before yy_doc_to_str serializes the document causes yyjson to read
freed heap memory, producing garbage JSON. cbm_jsonrpc_format_response
then fails to parse the result field (res_doc == NULL), so "result" is
omitted from the JSON-RPC response and the MCP client hangs indefinitely.

Fix: hoist adr_buf to function scope (initialized NULL), remove the
premature free, and free it after yy_doc_to_str has serialized the doc.

Adds regression test tool_manage_adr_get_with_existing_adr that FAILS
before this fix and PASSES after it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:25:42 -05:00
Martin Vogel de322d98a3 Merge branch 'main' into fix/mcp-stdio-buffering 2026-03-23 14:20:15 +01:00
Bing Ho 3658588051 fix(platform): fall back to USERPROFILE when HOME is unset
Add cbm_get_home_dir() in platform.c: tries HOME first, then
USERPROFILE (Windows). Replace all 17 raw getenv("HOME") callsites.
Fallback from "/tmp" to cbm_tmpdir() for cross-platform temp dir.

Cherry-picked from PR #88 by @bingh0. Fixes #77.
2026-03-23 14:08:09 +01:00
Martin Vogel 296a97a337 Merge branch 'main' into fix/libgit2-diff-options-init 2026-03-23 13:30:46 +01:00
Martin Vogel fad0ff7f90 Merge PR #87: feat(k8s) — Kubernetes and Kustomize indexing (66 languages)
Adds first-class indexing for K8s manifests and Kustomize overlays:
- Resource nodes for K8s kinds (Deployment/my-app, Service/my-svc)
- Module nodes for Kustomize overlays with IMPORTS edges
- Detection via name (kustomization.yaml) and content (apiVersion:)
- Reuses vendored YAML grammar — no new tree-sitter grammar needed

Fix lint: clang-format, implicit bool conversion, magic number.
Resolve CONTRIBUTING.md conflict. Update language count 64 → 66.
Add infrastructure indexing to README features.

Closes #86. Thanks @halindrome!
2026-03-23 13:06:37 +01:00
Martin Vogel 7f33e8b49b Fix lint issues in userconfig + add custom extensions docs to README
- clang-format: fix alignment in userconfig.c and userconfig.h
- Magic number 1280 → PATH_BUF_SZ named constant
- Remove dead g-- before break in dedup loop (cppcheck)
- Add "Custom File Extensions" section to README documenting
  .codebase-memory.json and global config
2026-03-23 11:52:39 +01:00
Martin Vogel 556ccefd25 Merge branch 'main' into feat/c-user-extension-config 2026-03-23 11:41:27 +01:00
Martin Vogel cd3b9fdd93 search_code v2: graph-augmented code search with modes + path_filter
Rewrites search_code from a raw grep wrapper into a 4-phase pipeline:
grep scan → graph block expansion → batch degree ranking → context assembly.

- Scoped grep: queries indexed file paths from graph, passes to xargs
  grep — eliminates scanning vendored/generated code (Fixes #102)
- Graph dedup: grep matches grouped into containing functions with
  in_degree, out_degree, qualified_name, label
- Three output modes: compact (default, metadata only — token efficient),
  full (with function source), files (just file paths)
- path_filter: regex on file paths (e.g. "^src/") to scope results
- context: N lines around each match (like grep -C) in compact mode
- directories: summary showing match distribution by top-level directory
- Ranking: project source first, vendored demoted, tests penalized
- Batch degree query via cbm_store_batch_count_degrees (2 SQL queries
  instead of 52 individual ones)
- Fix yyjson pointer bugs: use strcpy variants for heap/stack strings
- Add cbm_store_list_files() for indexed file enumeration
- Code discovery gate hook: per-session block (PPID-keyed) nudging
  Claude toward codebase-memory-mcp tools before grep fallback
2026-03-23 10:57:18 +01:00
map588 6a6127c17a Fix SQL injection in store search/BFS and argument injection in HTTP server
- cbm_store_search(): exclude_labels were interpolated as '%s' literals
  into SQL. Replaced with ?N parameterized placeholders via BIND_TEXT().
- cbm_store_bfs(): edge_types IN clause used '%s' interpolation. Replaced
  with ?N placeholders and bind_text() for both the CTE query and the
  follow-up edge collection query.
- index_thread_fn(): root_path was embedded raw into a JSON string for the
  indexer subprocess. Added JSON escaping for " and \ before interpolation.
2026-03-22 20:30:43 -04:00
Shane McCarronandClaude Sonnet 4.6 a3f11bd7fa fix(mcp,store): address QA round 2
- Fix handle_get_code_snippet inline store-NULL check to return the same
  JSON error format as REQUIRE_STORE and the other inline checks:
  {"error":"no project loaded"} instead of a plain string
- Fix smoke_guard.sh query_graph invocation: pass "query" parameter
  (not "cypher") to match what handle_query_graph actually reads; the
  wrong key caused the handler to early-return before reaching the guard
- Remove extra blank line in handle_get_graph_schema guard block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:33:10 -05:00
Shane McCarronandClaude Sonnet 4.6 2791d0d8af fix(mcp,store): address QA round 1
- Update stale comment in verify_project_indexed: resolve_store now uses
  cbm_store_open_path_query (no SQLITE_OPEN_CREATE), so store is NULL for
  missing files; the helper catches the empty-but-present .db case
- Guard state updates in resolve_store behind successful open check: only
  set owns_store=true and update current_project when store is non-NULL,
  preventing misleading state when an unknown project is queried
- Expand smoke_guard.sh to test all 5 guarded handlers (search_graph,
  query_graph, get_graph_schema, trace_call_path, get_code_snippet) instead
  of search_graph only; each checks both the guard error and no-ghost-file
  invariant

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:28:27 -05:00
Shane McCarronandClaude Sonnet 4.6 a109e9753e fix(store,mcp): prevent ghost .db file creation for unknown projects
- Add cbm_store_open_path_query() that opens with SQLITE_OPEN_READWRITE
  only (no SQLITE_OPEN_CREATE); returns NULL when file is absent
- Declare cbm_store_open_path_query() in store.h
- Change resolve_store() in mcp.c to call cbm_store_open_path_query
  so querying a nonexistent project never creates a ghost .db file
- Indexing path (cbm_store_open_path) retains SQLITE_OPEN_CREATE

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:18:21 -05:00
Shane McCarronandClaude Sonnet 4.6 172d3a658a fix(mcp): extend project-not-indexed guard to all query handlers
- Add static helper verify_project_indexed() before handle_get_graph_schema
- Replace inline guard in handle_get_architecture with helper call
- Apply guard to handle_search_graph, handle_get_graph_schema,
  handle_trace_call_path, handle_get_code_snippet, handle_query_graph
- All five query handlers now return {"error":"project not indexed —
  run index_repository first"} instead of silently returning empty results

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:18:21 -05:00
Shane McCarronandClaude Sonnet 4.6 804d680c0d fix(store): set busy_timeout before journal_mode=WAL to prevent immediate SQLITE_BUSY on lock contention
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 14:42:03 -05:00
Martin Vogel 0888726073 Add security defense tests + eliminate system() command injection
TDD: 31 security tests covering shell injection prevention, SQLite
authorizer (ATTACH/DETACH blocked), SQL injection via Cypher, path
containment, and shell-free subprocess execution.

- Add cbm_exec_no_shell() in compat_fs: fork+execvp (POSIX), _spawnvp
  (Windows) — executes commands without shell interpretation
- Replace system() with cbm_exec_no_shell() for unzip extraction and
  version verification in update command — eliminates CodeQL
  command-line-injection alerts
- CodeQL: switch to build-mode manual for 100% source file coverage
- CodeQL gate: fix race condition between scan completion and alert API
  propagation (60s settle + double-check polling)
- Dismiss TOCTOU in pass_envscan.c (benign read-only directory walk)
2026-03-21 23:02:34 +01:00
Martin Vogel aa2b60be7d Fix 29 CodeQL alerts: command injection, snprintf overflow, TOCTOU races
- Command injection (CRITICAL): validate shell args before system() in
  update command's unzip and version-check calls
- TOCTOU cli.c: use open(O_CREAT, 0755) + fdopen() to set permissions
  atomically instead of fopen() + chmod() after close
- TOCTOU pass_envscan.c: open file first, then fstat() on fd to check
  size, eliminating stat-then-open race window
- Overflowing snprintf (11 locations): clamp offset after each append
  to prevent unsigned underflow on truncation in cypher.c, store.c,
  http_server.c, test_c_lsp.c
- Add CBM_SNPRINTF_APPEND macro in str_util.h for future safe appends
- CodeQL: remove pull_request trigger (only scan push to main)
- CodeQL gate: increase timeout from 30 to 45 minutes
- Add fuzz testing script (random JSON-RPC + Cypher mutations)
- 12 Scorecard governance alerts dismissed (not code vulnerabilities)
2026-03-21 22:18:31 +01:00
Shane McCarronandClaude Sonnet 4.6 1a7c6ae8d2 fix(k8s): add k8s pass to parallel pipeline path
The parallel execution path (used for repos above MIN_FILES_FOR_PARALLEL)
was missing the cbm_pipeline_pass_k8s() call. The pass existed only in
the sequential fallback path, so any repo large enough to trigger parallel
indexing produced zero k8s Resource and kustomize Module nodes.

Discovered via live testing against a 954-file gitops repo: the parallel
path was taken, k8s pass was silently skipped, and search_graph returned
0 Resource nodes despite 213 kustomize overlays and hundreds of manifests.

Add the pass after cbm_parallel_resolve() in the parallel branch, matching
the same pattern (fail-open, cancel check, timing log) as the sequential path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 15:08:42 -05:00
Shane McCarronandClaude Sonnet 4.6 94882c26f9 fix(k8s): address QA round 3 findings
- Check return value of cbm_pipeline_pass_k8s() in incremental path;
  log warning on failure (fail-open, matches full pipeline behaviour)
- Add comment documenting pass ordering and the two known structural
  limitations: File→Resource DEFINES edges and cross-file kustomize
  IMPORTS edges are not emitted in incremental (gbuf only contains
  nodes for changed files; File nodes from pass_structure are absent)
- Fix clang-format violation in incremental_kustomize_module_indexed
  test (single-line if condition)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 14:59:12 -05:00
Shane McCarronandClaude Sonnet 4.6 a90ab5d37b fix(k8s): add k8s pass to incremental pipeline
cbm_pipeline_pass_k8s() was called in the full pipeline (pipeline.c)
but absent from pipeline_incremental.c. This meant k8s Resource nodes
and kustomize Module nodes were never created or updated during
incremental re-indexing — only after a fresh full index.

Add the pass after the semantic pass, following the same timing-log
pattern as the other incremental passes. Pass changed_files (not the
full file list) so only modified/added YAML files are re-processed.

Add two regression tests:
- incremental_k8s_manifest_indexed: full index + add manifest via
  incremental, verifies Resource node appears in the DB
- incremental_kustomize_module_indexed: same for kustomization.yaml
  Module node

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 14:38:41 -05:00
Shane McCarronandClaude Sonnet 4.6 5b534ce465 fix(mcp): address QA round 2 findings
- Add explicit fallback path when fcntl(F_GETFL) fails: skip the FILE*
  peek and fall through directly to blocking poll so idle eviction still
  fires on timeout (Finding 1)
- Strengthen C unit test: verify id:1 (initialize) and id:2 (tools/list)
  response IDs are both present, not just a substring match on "tools"
  (Finding 2)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 12:47:11 -05:00
Shane McCarronandClaude Sonnet 4.6 5ca5f3291f fix(mcp): address QA round 1 findings
- Use O_NONBLOCK + clearerr() in Phase 2 fgetc probe to preserve the
  60s idle eviction timeout when both kernel fd and FILE* buffer are
  empty (fgetc on a blocking fd would otherwise block indefinitely,
  bypassing Phase 3 poll timeout and preventing cbm_mcp_server_evict_idle)
- Add #include <fcntl.h> for fcntl()/O_NONBLOCK
- Fix comment: "two-phase" → "three-phase" (implementation has 3 phases)
- Improve Python integration test: verify id:1 (initialize) and id:2
  (tools/list) response IDs are both present, not just "tools" substring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 12:37:28 -05:00
Shane McCarron b8b2dd356b fix(mcp): resolve poll/getline FILE* buffering mismatch causing tools/list hang 2026-03-21 12:00:41 -05:00
Juha SyrjäläandClaude Opus 4.6 feeb0b1602 Fix build error with libgit2 -Wmissing-field-initializers
Build fails at pass_githistory.c:171 with:

  error: missing field 'interhunk_lines' initializer
         [-Werror,-Wmissing-field-initializers]
    git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;

codebase-memory-mcp at 75b5dcb has this issue. The GIT_DIFF_OPTIONS_INIT
macro does not list all struct fields, which clang flags as an error
under -Werror.

Replace the macro with the runtime git_diff_options_init() API, which
properly initializes all fields. Available since libgit2 0.28.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:11:48 +02:00
Shane McCarronandClaude Sonnet 4.6 340862c619 fix(k8s): address QA round 2 findings
- CONTRIBUTING.md: fix CBMLanguage enum file reference from
  non-existent cbm_language.h to internal/cbm/cbm.h
- CONTRIBUTING.md: rephrase "do not use tree-sitter grammars" to
  "do not require a new tree-sitter grammar", clarifying they reuse
  the existing YAML grammar
- pass_k8s.c: correct header comment from "per top-level resource
  document" to "first document only — multi-document YAML is not
  yet supported"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:29:22 -05:00
Shane McCarronandClaude Sonnet 4.6 94841e0542 fix(k8s): address QA round 1 findings
- [Major 1+2] pass_k8s: always re-extract K8s manifests with CBM_LANG_K8S,
  discarding any cached YAML result; pass already-read source buffer to
  handle_k8s_manifest to eliminate the double file read
- [Minor 3] CONTRIBUTING.md: fix extractor path to internal/cbm/extract_k8s.c
  and clarify tree-sitter YAML grammar usage
- [Minor 4] language.c: add comment documenting intentional case-sensitive
  FILENAME_TABLE and case-insensitive cbm_is_kustomize_file() split behaviour
- [Minor 5] test_pipeline.c: add k8s_extract_manifest_multidoc test pinning
  single-document-per-file extraction behaviour
- [Minor 6] pass_infrascan: replace strlen with strnlen(content, 4096) in
  cbm_is_k8s_manifest to bound the scan
- [Minor 7] extract_k8s: add "crds" to is_kustomize_list_key
- [Nit 8] extract_k8s: remove dead second block_node unwrap in
  extract_k8s_scalars metadata descent
- [Nit 10] extract_k8s: use cbm_arena_strdup for def.label "Resource"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:29:22 -05:00
Shane McCarronandClaude Sonnet 4.6 e696fcdf80 style(k8s): apply clang-format to k8s and infra-pass source files
- Fix alignment violations in extract_k8s.c, pass_k8s.c, pass_infrascan.c
- Fix spacing in language.c filename table rows (kustomization.yml entry)
- Fix alignment in cbm.h CBMLanguage enum comments
- Fix pipeline.c empty-body brace style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:29:22 -05:00
Shane McCarronandClaude Sonnet 4.6 337694dc65 test(k8s): tests for detection helpers, extractors, and pipeline pass
- Add TEST(infra_is_kustomize_file): positive/negative/NULL cases
- Add TEST(infra_is_k8s_manifest): apiVersion present/absent, kustomize
  file returns false, NULL guards
- Add TEST(k8s_extract_kustomize): asserts 2 imports (deployment.yaml,
  service.yaml) from Kustomization resources list
- Add TEST(k8s_extract_manifest): asserts Resource def with label
  "Resource" and name containing "Deployment"
- Add TEST(k8s_extract_manifest_no_name): no crash, has_error==false
- Fix extract_k8s.c get_scalar_text() to unwrap flow_node wrappers
  (tree-sitter YAML grammar wraps plain_scalar in flow_node)
- Fix pass_k8s.c missing #include "foundation/compat.h" for CBM_TLS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:29:22 -05:00
Shane McCarronandClaude Sonnet 4.6 bf3af55bf2 feat(k8s): pipeline pass for k8s manifest parsing and graph node emission
- Add pass_k8s.c: cbm_pipeline_pass_k8s() iterates files, classifies
  kustomize overlays via cbm_is_kustomize_file() and k8s manifests via
  cbm_is_k8s_manifest(), emits Module/Resource nodes and IMPORTS/DEFINES edges
- Kustomize files emit Module node (cbm_infra_qn) + IMPORTS edges per resources entry
- K8s manifest files emit Resource nodes per top-level document with DEFINES edge
- Falls back to file re-read + re-extraction when result_cache is unavailable
- Declare cbm_pipeline_pass_k8s() prototype in pipeline_internal.h
- Add pass_k8s.c to PIPELINE_SRCS in Makefile.cbm
- Call pass after definitions pass in pipeline.c sequential path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:29:22 -05:00