Skip to content

Commit 006e6db

Browse files
committed
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.
1 parent d2451c4 commit 006e6db

8 files changed

Lines changed: 613 additions & 3 deletions

File tree

.github/workflows/dry-run.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ jobs:
249249
- name: Build standard binary
250250
run: scripts/build.sh CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
251251

252+
- name: Ad-hoc sign macOS binary
253+
if: startsWith(matrix.os, 'macos')
254+
run: codesign --sign - --force build/c/codebase-memory-mcp
255+
252256
- name: Archive standard binary
253257
run: |
254258
cp LICENSE build/c/
@@ -258,6 +262,10 @@ jobs:
258262
- name: Build UI binary
259263
run: scripts/build.sh --with-ui CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
260264

265+
- name: Ad-hoc sign macOS UI binary
266+
if: startsWith(matrix.os, 'macos')
267+
run: codesign --sign - --force build/c/codebase-memory-mcp
268+
261269
- name: Frontend integrity scan (post-build dist/)
262270
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
263271
run: scripts/security-ui.sh
@@ -358,8 +366,23 @@ jobs:
358366
tar -xzf codebase-memory-mcp${SUFFIX}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz
359367
chmod +x codebase-memory-mcp
360368
369+
- name: Start artifact server for E2E smoke tests
370+
run: |
371+
mkdir -p /tmp/smoke-server
372+
cp codebase-memory-mcp /tmp/smoke-server/
373+
OS=${{ matrix.goos }}
374+
ARCH=${{ matrix.goarch }}
375+
SUFFIX=${{ matrix.variant == 'ui' && '-ui' || '' }}
376+
tar -czf "/tmp/smoke-server/codebase-memory-mcp${SUFFIX}-${OS}-${ARCH}.tar.gz" \
377+
-C /tmp/smoke-server codebase-memory-mcp
378+
cd /tmp/smoke-server
379+
sha256sum *.tar.gz > checksums.txt 2>/dev/null || shasum -a 256 *.tar.gz > checksums.txt
380+
python3 -m http.server 18080 -d /tmp/smoke-server &
381+
361382
- name: Smoke test (${{ matrix.variant }}, ${{ matrix.goos }}-${{ matrix.goarch }})
362383
run: scripts/smoke-test.sh ./codebase-memory-mcp
384+
env:
385+
SMOKE_DOWNLOAD_URL: http://localhost:18080
363386

364387
- name: Binary string audit (${{ matrix.goos }}-${{ matrix.goarch }})
365388
if: matrix.variant == 'standard'
@@ -438,9 +461,22 @@ jobs:
438461
unzip -o "codebase-memory-mcp${SUFFIX}-windows-amd64.zip"
439462
[ -n "$SUFFIX" ] && cp "codebase-memory-mcp${SUFFIX}.exe" codebase-memory-mcp.exe || true
440463
464+
- name: Start artifact server for E2E smoke tests
465+
shell: msys2 {0}
466+
run: |
467+
mkdir -p /tmp/smoke-server
468+
cp codebase-memory-mcp.exe /tmp/smoke-server/codebase-memory-mcp.exe
469+
SUFFIX=${{ matrix.variant == 'ui' && '-ui' || '' }}
470+
cd /tmp/smoke-server
471+
zip -q "codebase-memory-mcp${SUFFIX}-windows-amd64.zip" codebase-memory-mcp.exe
472+
sha256sum *.zip > checksums.txt
473+
python3 -m http.server 18080 -d /tmp/smoke-server &
474+
441475
- name: Smoke test (${{ matrix.variant }}, windows-amd64)
442476
shell: msys2 {0}
443477
run: scripts/smoke-test.sh ./codebase-memory-mcp.exe
478+
env:
479+
SMOKE_DOWNLOAD_URL: http://localhost:18080
444480

445481
- name: Binary string audit (windows-amd64)
446482
if: matrix.variant == 'standard'

.github/workflows/release.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ jobs:
248248
- name: Build standard binary
249249
run: scripts/build.sh --version ${{ inputs.version }} CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
250250

251+
- name: Ad-hoc sign macOS binary
252+
if: startsWith(matrix.os, 'macos')
253+
run: codesign --sign - --force build/c/codebase-memory-mcp
254+
251255
- name: Archive standard binary
252256
run: |
253257
cp LICENSE build/c/
@@ -257,6 +261,10 @@ jobs:
257261
- name: Build UI binary
258262
run: scripts/build.sh --with-ui --version ${{ inputs.version }} CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
259263

264+
- name: Ad-hoc sign macOS UI binary
265+
if: startsWith(matrix.os, 'macos')
266+
run: codesign --sign - --force build/c/codebase-memory-mcp
267+
260268
- name: Frontend integrity scan (post-build dist/)
261269
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
262270
run: scripts/security-ui.sh
@@ -354,8 +362,23 @@ jobs:
354362
tar -xzf codebase-memory-mcp${SUFFIX}-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz
355363
chmod +x codebase-memory-mcp
356364
365+
- name: Start artifact server for E2E smoke tests
366+
run: |
367+
mkdir -p /tmp/smoke-server
368+
cp codebase-memory-mcp /tmp/smoke-server/
369+
OS=${{ matrix.goos }}
370+
ARCH=${{ matrix.goarch }}
371+
SUFFIX=${{ matrix.variant == 'ui' && '-ui' || '' }}
372+
tar -czf "/tmp/smoke-server/codebase-memory-mcp${SUFFIX}-${OS}-${ARCH}.tar.gz" \
373+
-C /tmp/smoke-server codebase-memory-mcp
374+
cd /tmp/smoke-server
375+
sha256sum *.tar.gz > checksums.txt 2>/dev/null || shasum -a 256 *.tar.gz > checksums.txt
376+
python3 -m http.server 18080 -d /tmp/smoke-server &
377+
357378
- name: Smoke test (${{ matrix.variant }}, ${{ matrix.goos }}-${{ matrix.goarch }})
358379
run: scripts/smoke-test.sh ./codebase-memory-mcp
380+
env:
381+
SMOKE_DOWNLOAD_URL: http://localhost:18080
359382

360383
- name: Binary string audit (${{ matrix.goos }}-${{ matrix.goarch }})
361384
if: matrix.variant == 'standard'
@@ -435,9 +458,22 @@ jobs:
435458
unzip -o "codebase-memory-mcp${SUFFIX}-windows-amd64.zip"
436459
[ -n "$SUFFIX" ] && cp "codebase-memory-mcp${SUFFIX}.exe" codebase-memory-mcp.exe || true
437460
461+
- name: Start artifact server for E2E smoke tests
462+
shell: msys2 {0}
463+
run: |
464+
mkdir -p /tmp/smoke-server
465+
cp codebase-memory-mcp.exe /tmp/smoke-server/codebase-memory-mcp.exe
466+
SUFFIX=${{ matrix.variant == 'ui' && '-ui' || '' }}
467+
cd /tmp/smoke-server
468+
zip -q "codebase-memory-mcp${SUFFIX}-windows-amd64.zip" codebase-memory-mcp.exe
469+
sha256sum *.zip > checksums.txt
470+
python3 -m http.server 18080 -d /tmp/smoke-server &
471+
438472
- name: Smoke test (${{ matrix.variant }}, windows-amd64)
439473
shell: msys2 {0}
440474
run: scripts/smoke-test.sh ./codebase-memory-mcp.exe
475+
env:
476+
SMOKE_DOWNLOAD_URL: http://localhost:18080
441477

442478
- name: Binary string audit (windows-amd64)
443479
if: matrix.variant == 'standard'

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ High-quality parsing through [tree-sitter](https://tree-sitter.github.io/tree-si
3333

3434
## Quick Start
3535

36+
**One-line install** (macOS / Linux):
37+
```bash
38+
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
39+
```
40+
41+
With graph visualization UI:
42+
```bash
43+
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash -s -- --ui
44+
```
45+
46+
**Windows** (PowerShell):
47+
```powershell
48+
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.ps1 | iex"
49+
```
50+
51+
Restart your coding agent. Say **"Index this project"** — done.
52+
53+
<details>
54+
<summary>Manual install</summary>
55+
3656
1. **Download** the binary for your platform from the [latest release](https://github.com/DeusData/codebase-memory-mcp/releases/latest):
3757
- `codebase-memory-mcp-<os>-<arch>.tar.gz` — standard (MCP server only)
3858
- `codebase-memory-mcp-ui-<os>-<arch>.tar.gz` — with embedded graph visualization
@@ -44,7 +64,14 @@ High-quality parsing through [tree-sitter](https://tree-sitter.github.io/tree-si
4464
codebase-memory-mcp install
4565
```
4666

47-
3. **Restart** your coding agent. Say **"Index this project"** — done.
67+
3. **Restart** your coding agent.
68+
69+
On macOS, if the binary is killed on launch, fix code signing:
70+
```bash
71+
xattr -d com.apple.quarantine ~/.local/bin/codebase-memory-mcp
72+
codesign --sign - --force ~/.local/bin/codebase-memory-mcp
73+
```
74+
</details>
4875

4976
The `install` command auto-detects all installed coding agents and configures MCP server entries, instruction files, skills, and pre-tool hooks for each.
5077

install.ps1

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# install.ps1 — One-line installer for codebase-memory-mcp (Windows).
2+
#
3+
# Usage:
4+
# powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.ps1 | iex"
5+
#
6+
# Environment:
7+
# CBM_DOWNLOAD_URL Override base URL for downloads (for testing)
8+
9+
$ErrorActionPreference = "Stop"
10+
11+
$Repo = "DeusData/codebase-memory-mcp"
12+
$InstallDir = "$env:LOCALAPPDATA\Programs\codebase-memory-mcp"
13+
$BinName = "codebase-memory-mcp.exe"
14+
$BaseUrl = if ($env:CBM_DOWNLOAD_URL) { $env:CBM_DOWNLOAD_URL } else { "https://github.com/$Repo/releases/latest/download" }
15+
16+
# Detect variant from args (--ui or --standard)
17+
$Variant = "standard"
18+
foreach ($arg in $args) {
19+
if ($arg -eq "--ui") { $Variant = "ui" }
20+
if ($arg -eq "--standard") { $Variant = "standard" }
21+
if ($arg -like "--dir=*") { $InstallDir = $arg.Substring(6) }
22+
}
23+
24+
Write-Host "codebase-memory-mcp installer (Windows)"
25+
Write-Host " variant: $Variant"
26+
Write-Host " target: $InstallDir\$BinName"
27+
Write-Host ""
28+
29+
# Build download URL
30+
if ($Variant -eq "ui") {
31+
$Archive = "codebase-memory-mcp-ui-windows-amd64.zip"
32+
} else {
33+
$Archive = "codebase-memory-mcp-windows-amd64.zip"
34+
}
35+
$Url = "$BaseUrl/$Archive"
36+
37+
# Download
38+
$TmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "cbm-install-$(Get-Random)"
39+
New-Item -ItemType Directory -Path $TmpDir -Force | Out-Null
40+
41+
Write-Host "Downloading $Archive..."
42+
try {
43+
Invoke-WebRequest -Uri $Url -OutFile "$TmpDir\$Archive" -UseBasicParsing
44+
} catch {
45+
Write-Host "error: download failed: $_" -ForegroundColor Red
46+
Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue
47+
exit 1
48+
}
49+
50+
# Remove MOTW (prevents SmartScreen popup)
51+
Unblock-File -Path "$TmpDir\$Archive" -ErrorAction SilentlyContinue
52+
53+
# Checksum verification
54+
$ChecksumUrl = "$BaseUrl/checksums.txt"
55+
try {
56+
Invoke-WebRequest -Uri $ChecksumUrl -OutFile "$TmpDir\checksums.txt" -UseBasicParsing
57+
$checksumLine = Get-Content "$TmpDir\checksums.txt" | Where-Object { $_ -like "*$Archive*" }
58+
if ($checksumLine) {
59+
$expected = ($checksumLine -split '\s+')[0]
60+
$actual = (Get-FileHash -Path "$TmpDir\$Archive" -Algorithm SHA256).Hash.ToLower()
61+
if ($expected -ne $actual) {
62+
Write-Host "error: CHECKSUM MISMATCH!" -ForegroundColor Red
63+
Write-Host " expected: $expected"
64+
Write-Host " actual: $actual"
65+
Remove-Item -Recurse -Force $TmpDir
66+
exit 1
67+
}
68+
Write-Host "Checksum verified."
69+
}
70+
} catch {
71+
Write-Host "warning: could not verify checksum (non-fatal)"
72+
}
73+
74+
# Extract
75+
Write-Host "Extracting..."
76+
Expand-Archive -Path "$TmpDir\$Archive" -DestinationPath $TmpDir -Force
77+
78+
$DlBin = Join-Path $TmpDir $BinName
79+
if (-not (Test-Path $DlBin)) {
80+
# UI variant may have different name in zip
81+
$UiBin = Join-Path $TmpDir "codebase-memory-mcp-ui.exe"
82+
if (Test-Path $UiBin) {
83+
Rename-Item $UiBin $BinName
84+
$DlBin = Join-Path $TmpDir $BinName
85+
} else {
86+
Write-Host "error: binary not found after extraction" -ForegroundColor Red
87+
Remove-Item -Recurse -Force $TmpDir
88+
exit 1
89+
}
90+
}
91+
92+
# Remove MOTW from extracted binary
93+
Unblock-File -Path $DlBin -ErrorAction SilentlyContinue
94+
95+
# Install
96+
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
97+
$Dest = Join-Path $InstallDir $BinName
98+
99+
# Handle replace-if-running (rename-aside)
100+
if (Test-Path $Dest) {
101+
$OldDest = "$Dest.old"
102+
Remove-Item $OldDest -Force -ErrorAction SilentlyContinue
103+
try {
104+
Rename-Item $Dest $OldDest -ErrorAction Stop
105+
} catch {
106+
Write-Host "warning: could not rename existing binary (may be in use)"
107+
}
108+
}
109+
110+
Copy-Item $DlBin $Dest -Force
111+
Unblock-File -Path $Dest -ErrorAction SilentlyContinue
112+
113+
# Verify
114+
try {
115+
$ver = & $Dest --version 2>&1
116+
Write-Host "Installed: $ver"
117+
} catch {
118+
Write-Host "error: installed binary failed to run" -ForegroundColor Red
119+
Remove-Item -Recurse -Force $TmpDir
120+
exit 1
121+
}
122+
123+
# Configure agents
124+
Write-Host ""
125+
Write-Host "Configuring coding agents..."
126+
try {
127+
& $Dest install -y 2>&1 | Write-Host
128+
} catch {
129+
Write-Host "Agent configuration failed (non-fatal)."
130+
Write-Host "Run manually: codebase-memory-mcp install"
131+
}
132+
133+
# Add to PATH (user scope, no admin needed)
134+
$UserPath = [Environment]::GetEnvironmentVariable("PATH", "User")
135+
if ($UserPath -notlike "*$InstallDir*") {
136+
[Environment]::SetEnvironmentVariable("PATH", "$UserPath;$InstallDir", "User")
137+
$env:PATH = "$env:PATH;$InstallDir"
138+
Write-Host "Added $InstallDir to user PATH"
139+
}
140+
141+
# Cleanup
142+
Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue
143+
144+
Write-Host ""
145+
Write-Host "Done! Restart your terminal and coding agent to start using codebase-memory-mcp."

0 commit comments

Comments
 (0)