Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 14 additions & 119 deletions .github/workflows/_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ on:
description: 'Generate build provenance attestations for release artifacts'
type: boolean
default: false
ui_only:
description: 'Build only the UI runtime archives'
type: boolean
default: false

permissions:
contents: read
id-token: write
Expand Down Expand Up @@ -67,34 +62,7 @@ jobs:
with:
node-version: "22"

- name: Build standard binary
if: ${{ !inputs.ui_only }}
env:
VERSION: ${{ inputs.version }}
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" "CC=$CC" "CXX=$CXX"
else
scripts/build.sh "CC=$CC" "CXX=$CXX"
fi

- name: Ad-hoc sign macOS standard binary
if: ${{ !inputs.ui_only && startsWith(matrix.os, 'macos') }}
run: codesign --sign - --force build/c/codebase-memory-mcp

- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
run: scripts/package-release.sh ${{ matrix.goos }} ${{ matrix.goarch }}

- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-${{ matrix.goos }}-${{ matrix.goarch }}.tar.gz

- name: Build UI binary
- name: Build release binary with UI
env:
VERSION: ${{ inputs.version }}
CC: ${{ matrix.cc }}
Expand All @@ -106,7 +74,7 @@ jobs:
scripts/build.sh --with-ui "CC=$CC" "CXX=$CXX"
fi

- name: Ad-hoc sign macOS UI binary
- name: Ad-hoc sign macOS release binary
if: startsWith(matrix.os, 'macos')
run: codesign --sign - --force build/c/codebase-memory-mcp

Expand All @@ -116,10 +84,10 @@ jobs:

# Archive layout/name live in the ONE canonical script the local
# artifact-flow smoke lane also runs (venue-parity contract).
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
run: scripts/package-release.sh ${{ matrix.goos }} ${{ matrix.goarch }} --variant ui

- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
Expand Down Expand Up @@ -150,30 +118,7 @@ jobs:
with:
node-version: "22"

- name: Build standard binary
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=clang CXX=clang++
else
scripts/build.sh CC=clang CXX=clang++
fi

- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
run: scripts/package-release.sh windows amd64 CC=clang CXX=clang++

- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-windows-amd64.zip

- name: Build UI binary
- name: Build release binary with UI
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
Expand All @@ -186,11 +131,11 @@ jobs:

# Archive layout/name live in the ONE canonical script the local
# artifact-flow smoke lane also runs (venue-parity contract).
- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
shell: msys2 {0}
run: scripts/package-release.sh windows amd64 --variant ui CC=clang CXX=clang++

- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
Expand Down Expand Up @@ -225,30 +170,7 @@ jobs:
with:
node-version: "22"

- name: Build standard binary
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=clang CXX=clang++
else
scripts/build.sh CC=clang CXX=clang++
fi

- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
shell: msys2 {0}
run: scripts/package-release.sh windows arm64 CC=clang CXX=clang++

- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-windows-arm64.zip

- name: Build UI binary
- name: Build release binary with UI
shell: msys2 {0}
env:
VERSION: ${{ inputs.version }}
Expand All @@ -259,11 +181,11 @@ jobs:
scripts/build.sh --with-ui CC=clang CXX=clang++
fi

- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
shell: msys2 {0}
run: scripts/package-release.sh windows arm64 --variant ui CC=clang CXX=clang++

- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
Expand Down Expand Up @@ -297,34 +219,7 @@ jobs:
with:
node-version: "22"

- name: Build standard binary (static)
if: ${{ !inputs.ui_only }}
env:
VERSION: ${{ inputs.version }}
run: |
if [ -n "$VERSION" ]; then
scripts/build.sh --version "$VERSION" CC=gcc CXX=g++ STATIC=1
else
scripts/build.sh CC=gcc CXX=g++ STATIC=1
fi

- name: Verify standard static linking
if: ${{ !inputs.ui_only }}
run: |
file build/c/codebase-memory-mcp
ldd build/c/codebase-memory-mcp 2>&1 | grep -q "not a dynamic executable" || ldd build/c/codebase-memory-mcp 2>&1 | grep -q "statically linked"

- name: Archive standard binary (canonical package-release.sh)
if: ${{ !inputs.ui_only }}
run: scripts/package-release.sh linux ${{ matrix.arch }}-portable

- name: Attest standard binary provenance
if: ${{ inputs.attest && !inputs.ui_only }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: codebase-memory-mcp-linux-${{ matrix.arch }}-portable.tar.gz

- name: Build UI binary (static)
- name: Build release binary with UI (static)
env:
VERSION: ${{ inputs.version }}
run: |
Expand All @@ -334,15 +229,15 @@ jobs:
scripts/build.sh --with-ui CC=gcc CXX=g++ STATIC=1
fi

- name: Verify UI static linking
- name: Verify release static linking
run: |
file build/c/codebase-memory-mcp
ldd build/c/codebase-memory-mcp 2>&1 | grep -q "not a dynamic executable" || ldd build/c/codebase-memory-mcp 2>&1 | grep -q "statically linked"

- name: Archive UI binary (canonical package-release.sh)
- name: Archive release binary (canonical package-release.sh)
run: scripts/package-release.sh linux ${{ matrix.arch }}-portable --variant ui

- name: Attest UI binary provenance
- name: Attest release binary provenance
if: ${{ inputs.attest }}
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
Expand Down
19 changes: 4 additions & 15 deletions .github/workflows/_smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ on:
description: 'Smoke the shipped binaries on the broad platform matrix (extra OS versions) instead of the core set'
type: boolean
default: false
ui_only:
description: 'Smoke only the UI runtime archives'
type: boolean
default: false

permissions:
contents: read

Expand All @@ -34,7 +29,6 @@ jobs:
id: set
env:
BROAD: ${{ inputs.broad_platforms }}
UI_ONLY: ${{ inputs.ui_only }}
run: |
CORE_UNIX='[
{"os":"ubuntu-latest","goos":"linux","goarch":"amd64"},
Expand Down Expand Up @@ -77,14 +71,9 @@ jobs:
WIN=$(jq -cn --argjson a "$CORE_WIN" '$a')
PORTABLE=$(jq -cn --argjson a "$CORE_PORTABLE" '$a')
fi
# Keep the variant dimension explicit because the smoke wrappers use it
# to require and validate the UI pack. VT-focused dry runs select only
# UI; release compatibility retains both variants until migration.
if [ "$UI_ONLY" = "true" ]; then
VARIANTS='["ui"]'
else
VARIANTS='["standard","ui"]'
fi
# Keep the UI marker explicit because the smoke wrappers use it to
# require and validate the shipped content-addressed frontend pack.
VARIANTS='["ui"]'
UNIX_M=$(jq -cn --argjson a "$UNIX" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
WIN_M=$(jq -cn --argjson a "$WIN" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
PORTABLE_M=$(jq -cn --argjson a "$PORTABLE" --argjson v "$VARIANTS" '{include:[$a[] as $o | $v[] as $t | ($o + {variant:$t})]}')
Expand Down Expand Up @@ -140,7 +129,7 @@ jobs:
scripts/security-network.sh "$BIN"

- name: MCP robustness test (selected linux-amd64 runtime)
if: matrix.goos == 'linux' && matrix.goarch == 'amd64' && (inputs.ui_only || matrix.variant == 'standard')
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
run: |
BIN="$RUNNER_TEMP/cbm-artifact/codebase-memory-mcp"
scripts/security-fuzz.sh "$BIN"
Expand Down
12 changes: 5 additions & 7 deletions .github/workflows/dry-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ jobs:
uses: ./.github/workflows/_build.yml
with:
attest: false
ui_only: true

# ── Smoke test every binary ────────────────────────────────────
# Run unless builds were skipped or a build leg FAILED. Every build leg
Expand All @@ -103,7 +102,6 @@ jobs:
uses: ./.github/workflows/_smoke.yml
with:
broad_platforms: true
ui_only: true

# ── Soak tests (optional, parallel with smoke) ────────────────
soak:
Expand Down Expand Up @@ -146,13 +144,13 @@ jobs:
with:
pattern: binaries-*
merge-multiple: true
path: assets
path: ${{ runner.temp }}/release-archives

# Same extraction the release verify job performs, so the bytes handed to
# VirusTotal here are the bytes a user would download and run.
# Same extraction the release verify job performs. VirusTotal receives
# only extracted files and unpacked UI assets, never .tar.gz/.zip containers.
- name: Extract archive artifacts
run: |
scripts/ci/extract-release-archives.sh assets binaries \
scripts/ci/extract-release-archives.sh "$RUNNER_TEMP/release-archives" binaries \
--archive-scope=ui \
--expect-archives=8 \
--expect-binaries=8 \
Expand All @@ -167,7 +165,7 @@ jobs:
files: binaries/objects/*
request_rate: 4

# Same ZERO-tolerance gate as the release. Every artifact must arrive
# Same ZERO-tolerance gate as the release. Every extracted object must arrive
# naturally clean; any malicious or suspicious verdict fails this run.
- name: Wait for VirusTotal results
env:
Expand Down
24 changes: 13 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,18 +212,20 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ inputs.version }}
run: |
mkdir -p assets binaries
gh release download "$VERSION" --dir assets --repo "$GITHUB_REPOSITORY" --pattern '*.tar.gz' --pattern '*.zip'
scripts/ci/extract-release-archives.sh assets binaries \
--expect-archives=16 \
--expect-binaries=16 \
ARCHIVE_DIR="$RUNNER_TEMP/release-archives"
mkdir -p "$ARCHIVE_DIR" binaries
gh release download "$VERSION" --dir "$ARCHIVE_DIR" --repo "$GITHUB_REPOSITORY" --pattern '*.tar.gz' --pattern '*.zip'
scripts/ci/extract-release-archives.sh "$ARCHIVE_DIR" binaries \
--archive-scope=ui \
--expect-archives=8 \
--expect-binaries=8 \
--expect-packs=8 \
--expect-runtime-files=64
--expect-runtime-files=32

- name: Security audits on all unique release objects
- name: Security audits on all unique extracted release objects
run: |
# Audit every distinct archive/member/UI-asset byte sequence. The
# associations manifest preserves every shipped archive location.
# Audit every distinct extracted member/UI-asset byte sequence. The
# associations manifest retains each source archive's SHA-256.
# security-strings.sh detects file type and applies binary-only
# rules (URL allowlist, dangerous-command detection) only to real
# binaries; for shell scripts it still runs credential and base64
Expand All @@ -242,7 +244,7 @@ jobs:
files: binaries/objects/*
request_rate: 4

# ZERO tolerance: every artifact must arrive naturally clean. Any
# ZERO tolerance: every extracted object must arrive naturally clean. Any
# malicious or suspicious verdict blocks the release with no exception.
- name: Wait for VirusTotal results
env:
Expand Down Expand Up @@ -274,7 +276,7 @@ jobs:
VT_RESULTS_PATH: binaries/vt-results.tsv
run: bash scripts/ci/publish-vt-evidence.sh

# Renders the exact scan scope plus archive SHA-256/engine evidence. It
# Renders extracted-file scan results plus archive SHA-256 provenance. It
# runs only after the exact-set zero-tolerance gate passed.
- name: Append VirusTotal scan links to release notes
env:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ High-quality parsing through [tree-sitter](https://tree-sitter.github.io/tree-si

> **Research** — The design and benchmarks behind this project are described in the preprint [*Codebase-Memory: Tree-Sitter-Based Knowledge Graphs for LLM Code Exploration via MCP*](https://arxiv.org/abs/2603.27277) (arXiv:2603.27277). Evaluated across 31 real-world repositories: 83% answer quality, 10× fewer tokens, 2.1× fewer tool calls vs. file-by-file exploration.

> **Security & Trust** — This tool reads your codebase and writes to your agent configuration files. That is what it is designed to do. If you prefer to audit before running, the [full source is here](https://github.com/DeusData/codebase-memory-mcp). Release archives are signed and checksummed; every distinct shipped archive, member, and UI-asset byte object is submitted to VirusTotal. The release notes record the measured engine count and exact 0/N result; publication requires at least 50 decisive engine results with zero malicious and zero suspicious verdicts. All processing happens 100% locally; your code never leaves your machine. Found a security issue? We want to know — see [SECURITY.md](SECURITY.md). Security is Priority #1 for us.
> **Security & Trust** — This tool reads your codebase and writes to your agent configuration files. That is what it is designed to do. If you prefer to audit before running, the [full source is here](https://github.com/DeusData/codebase-memory-mcp). Release archives are signed and checksummed; every distinct extracted member and unpacked UI asset is submitted to VirusTotal, while the downloadable `.tar.gz`/`.zip` containers themselves are not. The release notes record the measured engine count and exact 0/N result; publication requires at least 50 decisive engine results with zero malicious and zero suspicious verdicts. All processing happens 100% locally; your code never leaves your machine. Found a security issue? We want to know — see [SECURITY.md](SECURITY.md). Security is Priority #1 for us.

<p align="center">
<img src="docs/graph-ui-screenshot.png" alt="Graph visualization UI showing the codebase-memory-mcp knowledge graph" width="800">
Expand Down Expand Up @@ -791,7 +791,7 @@ internal/cbm/ Vendored tree-sitter grammars (158 languages) + AST extrac

Every release is verified through a multi-layer pipeline before publication:

- **VirusTotal** — every release object is scanned (minimum 50 decisive engines; zero malicious and zero suspicious required). Release notes summarize the archive rows and link durable public association, exact-scan-set, and per-object result files containing every measured engine count and VirusTotal report URL.
- **VirusTotal** — every distinct extracted release file and unpacked UI asset is scanned; downloadable `.tar.gz`/`.zip` containers are not submitted (minimum 50 decisive engines; zero malicious and zero suspicious required). Release notes retain archive SHA-256 provenance and link durable public association, exact-scan-set, and per-object result files containing every measured engine count and VirusTotal report URL.
- **SLSA Level 3** — cryptographic build provenance generated by the trusted GitHub Actions build workflow; verify with `gh attestation verify <file> --repo DeusData/codebase-memory-mcp --signer-workflow DeusData/codebase-memory-mcp/.github/workflows/_build.yml`
- **Sigstore cosign** — keyless signatures on all artifacts; bundles included in every release
- **SHA-256 checksums** — `checksums.txt` published with every release; verified by both install scripts before extraction
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ disclosure. Research conducted under this policy is considered authorised.

## Security Measures

This project implements multiple layers of security verification. Every release archive and its extracted runtime objects must pass all checks before users can download it (draft → verify → publish flow).
This project implements multiple layers of security verification. Every release archive is signed and checksummed, and every extracted runtime object must pass its applicable checks before users can download it (draft → verify → publish flow).

### Build-Time (CI — every commit)

Expand Down Expand Up @@ -126,7 +126,7 @@ Releases are created as **drafts** (invisible to users) and only published after
2. **Sigstore cosign signing** — keyless digital signatures verifiable by anyone
3. **SBOM** — Software Bill of Materials (SPDX) listing all vendored dependencies
4. **SHA-256 checksums** — published with every release
5. **VirusTotal scanning** — every distinct shipped archive, member, and UI-asset byte object is scanned. Each completed analysis must contain at least 50 decisive engine results, zero malicious verdicts, and zero suspicious verdicts. Release notes summarize archive results and link durable public association, exact-scan-set, per-object-result, and evidence-checksum assets.
5. **VirusTotal scanning** — every distinct extracted member and unpacked UI asset is scanned; downloadable `.tar.gz`/`.zip` containers are not submitted. Each completed analysis must contain at least 50 decisive engine results, zero malicious verdicts, and zero suspicious verdicts. Release notes retain archive SHA-256 provenance and link durable public association, exact-scan-set, per-object-result, and evidence-checksum assets.
6. **OpenSSF Scorecard** — repository security health score

Scope of the SLSA claim: this is a build provenance claim for release
Expand Down
Loading
Loading