Commit Graph
27 Commits
Author SHA1 Message Date
Martin Vogel 5f9da0ee4a Fix 3 CI failures: Windows .exe path, tre ssize_t, UI archive name
1. Windows install/update: append .exe to binary path on _WIN32
   (was writing empty command to .claude.json)
2. Vendored tre: add ssize_t typedef for Windows (basetsd.h SSIZE_T)
3. Smoke server: copy UI archive under standard name too, so
   install.sh and update --standard work in UI variant smoke tests
2026-03-25 21:33:01 +01:00
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 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 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 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
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 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
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
Martin Vogel 63e6141ac6 Add OpenClaw + VS Code agent detection (10 agents total)
- OpenClaw: detect ~/.openclaw/, write MCP config to openclaw.json
- VS Code was already wired in PR #79 but not counted in README
- Agent struct initializer uses memset instead of counting booleans
- README updated: 8 → 10 agents
2026-03-21 01:43:41 +01:00
Martin Vogel e09f27130e Fix Windows bulk test + dual MCP config location + CONTRIBUTING.md
- Bulk test: use cbm_tmpdir() instead of hardcoded /tmp/ (fixes
  Windows/MSYS2 where /tmp/ doesn't resolve for SQLite)
- Install: write MCP config to both ~/.claude/.mcp.json (Claude Code
  <=2.1.x) and ~/.claude.json (Claude Code >=2.1.80). Fixes #69.
- Uninstall: remove from both locations
- CONTRIBUTING.md: rewrite for pure C project (was still describing Go,
  causing contributors to submit Go PRs)
- Fix clang-format in mcp.c protocol version negotiation (PR #79 merge)
2026-03-20 20:32:38 +01:00
Martin Vogel 92275ffa95 Merge PR #79: Fix VS Code compatibility (schema, install, protocol negotiation) 2026-03-20 19:52:59 +01:00
Martin Vogel cd1417427c Add 8-layer security test suite + hardening
Code-level defenses:
- cbm_validate_shell_arg(): reject shell metacharacters before popen/system
- SQLite authorizer: block ATTACH/DETACH at engine level
- CORS localhost-only origin reflection (replaces wildcard *)
- Path containment: realpath() check in get_code_snippet
- process-kill restricted to server-spawned PIDs
- SHA256 checksum verification in update command

Security audit scripts (8 layers):
- L1: Static allow-list for dangerous calls + URLs
- L2: Binary string audit (URLs, payloads, credentials)
- L3: Network egress monitoring via strace (Linux)
- L4: Install output path + content validation
- L5: Smoke test hardening (clean shutdown, residual procs)
- L6: Graph UI audit (external domains, CORS, binding)
- L7: MCP robustness (23 adversarial JSON-RPC payloads)
- L8: Vendored integrity (checksums + dangerous call scan)

CI: parallel security-static job (no build needed), binary
layers in smoke jobs per-platform. Cleanup of test fixture
dirs in clean.sh + .gitignore.
2026-03-20 18:19:15 +01:00
Martin VogelandJay Sync c66d88745d Fix Swift call extraction: 0 CALLS edges (#43)
Swift tree-sitter grammar uses positional children (not named fields) for
call_expression, so extract_callee_name() returned NULL for every call.

- extract_calls.c: Swift-specific callee extraction via first named child
  for call_expression and constructor_expression nodes
- lang_specs.c: add constructor_expression to swift_call_types
- 4 new C tests: simple calls, method calls, constructors, chained calls

Co-Authored-By: Jay Sync <63868998+jay-sync@users.noreply.github.com>
2026-03-20 14:46:46 +01:00
Bing Ho 02575fb307 Add VS Code detection and MCP registration to install/uninstall
The install command detected many editors (Cursor, Zed, Gemini, etc.)
but not VS Code, even though cbm_install_vscode_mcp() already existed.
Add VS Code User config dir detection and wire it into both install
and uninstall flows, writing to ~/.config/Code/User/mcp.json (Linux)
or ~/Library/Application Support/Code/User/mcp.json (macOS).
2026-03-20 08:37:44 -05:00
Martin Vogel 7629940dca Restore session auto-detect + auto-index + config CLI from Go
- Config store: persistent SQLite key-value in _config.db (get/set/delete/bool/int)
- Config CLI: codebase-memory-mcp config list|get|set|reset
  Keys: auto_index (default false), auto_index_limit (default 50000)
- Session detection: detect project root from CWD on MCP initialize
- Auto-index: if auto_index=true and project not yet indexed, background pipeline
- Watcher hookup: after index completes, register project for ongoing git polling
- 6 new config store tests (open/close, get/set, bool, int, delete, persistence)

Enable auto-indexing:
  codebase-memory-mcp config set auto_index true
2026-03-19 20:13:17 +01:00
442cb958f0 Add KiloCode support, fix Zed JSONC parsing (#24, #53)
- KiloCode: detect globalStorage dir, upsert mcp_settings.json, install
  global rules at ~/.kilocode/rules/codebase-memory-mcp.md
- Zed: parse JSONC (comments + trailing commas) in existing settings.json
  — fixes "Invalid JSON" error on install with existing Zed config
- 2 new tests: KiloCode detection, Zed JSONC settings parsing
- Now supports 8 agents: Claude Code, Codex, Gemini, Zed, OpenCode,
  Antigravity, Aider, KiloCode

Co-Authored-By: David34920 <179368816+David34920@users.noreply.github.com>
Co-Authored-By: Paul Cohen <200370+sonicviz@users.noreply.github.com>
Co-Authored-By: Chitral Verma <11135032+chitralverma@users.noreply.github.com>
Co-Authored-By: Noel Kurian <1851449+noelkurian@users.noreply.github.com>
Co-Authored-By: José Almeida <57680069+zeval@users.noreply.github.com>
Co-Authored-By: Vasani Harshil <147682127+harshil480@users.noreply.github.com>
2026-03-19 18:56:16 +01:00
Martin Vogel 159378ad8e Multi-agent install: auto-detect 7 coding agents, upsert configs + hooks + instructions
- Detect Claude Code, Codex CLI, Gemini CLI, Zed, OpenCode, Antigravity, Aider
- Per-agent MCP config upsert: Codex TOML, OpenCode JSON, Antigravity JSON
- Instruction file upsert with marker-based sections (no duplicates on re-install)
- Claude Code PreToolUse hook (Grep|Glob|Read -> MCP reminder)
- Gemini CLI BeforeTool hook (grep_search|read_file -> MCP reminder)
- Fix Zed MCP config: args:[""] instead of broken source:"custom" (#24)
- Rewrite skill descriptions to directive pattern (100% auto-activation)
- Keyword-rich MCP tool descriptions for Tool Search discovery
- 35 new tests (agent detection, config upsert, instructions, hooks)
- All platforms green: macOS 2022, Linux 2004+18skip, Windows cross-compile OK
2026-03-19 16:08:43 +01:00
Martin Vogel 18fa9979ee Replace vmem with mimalloc global allocator, add extraction-phase prescan, fix __init__.py QN collision
Memory management:
- Vendor mimalloc v2.1.9 as global allocator (MI_OVERRIDE=1 in prod)
- New mem.h/mem.c: RSS-based budget tracking via mi_process_info()
- Remove vmem.c/vmem.h (mmap-based budget tracking)
- Remove slab tier2 bump allocator (~300 LOC); >64B goes to mimalloc
- Slab tier1 pages from malloc (= mimalloc) instead of vmem
- Arena blocks from malloc instead of vmem
- Budget raised from 35% to 50% RAM (no more untracked C++ heap)

Extraction-phase prescan (eliminates disk re-reads):
- HTTP call sites: keyword check + URL extraction during extraction
- HTTP routes: decorator + source-based extraction during extraction
- Config file refs: regex scan during extraction
- httplinks: 41.8s → 13ms on Linux kernel (3,212x faster)
- configlink: 41.4s → 0.8s on Linux kernel (54x faster)
- Linux kernel fast-mode total: 2m38s → 1m18s

Bug fixes:
- __init__.py Module QN no longer collides with Folder QN
- index.ts same fix for JS/TS packages
- 13 regression tests for QN collision at FQN + extraction layers
- search_graph/search_code default limit raised from 10 to 500k
- Resolve all clang-tidy, cppcheck, and clang-format warnings

Repo cleanup:
- tree-sitter-form, tree-sitter-magma moved to tools/
- .gitignore: build/, node_modules/, graph-ui/dist/, TEST_PLAN.md
2026-03-17 22:05:57 +01:00
Martin Vogel 0d216c7936 Resolve all clang-tidy, cppcheck, and clang-format warnings across 94 files
Enforce WarningsAsErrors: '*' with zero suppressions of entire check categories.
All non-FP warnings fixed at source; true false positives get per-instance NOLINT
with reasoning. Fixes include: braces around statements (1679), isolate declarations
(75), explicit casts for multilevel pointer conversions, missing includes, function
parameter documentation via NOLINT, and proper NOLINTBEGIN/NOLINTEND nesting.
2026-03-15 22:37:34 +01:00
Martin Vogel 94a9a92f83 Add C-native pipeline with blocking clang-tidy, cppcheck, clang-format linting
Complete C implementation of the indexing pipeline (src/), parallel worker
pool, graph buffer with merge support, SQLite writer, and 1893-test suite.

Linter setup: zero warnings from clang-tidy (all checks enabled, no NOLINT
suppressions), cppcheck, and clang-format. All issues fixed at source —
proper headers for external linkage, GROW_ARRAY macro restructured to
eliminate type parameter, null-deref paths guarded, named intermediates
for suspicious-argument checks.
2026-03-15 19:26:12 +01:00