The SBOM hardcoded '158-grammars' for the tree-sitter-grammars aggregate;
the true count is now 159 (Mojo + InterSystems ObjectScript vendored, nim
dropped since the literal was last set), so the shipped SBOM under-counted.
Compute the count from the vendored grammar directories so it cannot drift
again. Also correct the non-MIT summary, which named only clojure CC0-1.0 +
jinja2/just Apache-2.0 while omitting fennel (CC0), the other eight Apache
grammars, fish (Unlicense) and pine/templ (ISC); it now lists the full
non-MIT family set and is explicitly non-exhaustive, deferring to
MANIFEST.md as authoritative. Data-only change to generated sbom.json; no
build or gating behavior changes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Rebased onto current main and reworked in response to review. Three of the four
Windows reds were fixed upstream since the branch was cut at b075f05, so they are
now green regression guards; the fourth stays a genuine known-red.
- test_non_ascii_path.py (#636/#357): green guard - fixed by #700 (per-pass
readers now route through cbm_fopen -> _wfopen). Re-verified green on main.
- test_hook_augment.py (#618): green guard - fixed by #619 (cbm_is_walkable_abs_path
accepts drive-letter X:/ cwd). Re-verified green on main.
- test_ui_drive_listing.py (#548): rewritten. The fix exposes drives via a new
roots[] field, not the dirs[] array the old test asserted (which would stay red
against fixed code). Now asserts every fixed drive is in roots and browsable.
Re-verified green on main (drives C:/D:/E:).
- test_cli_non_ascii_arg.py (#423/#20): unchanged - main() is still narrow-argv
with no wide command line, so this remains genuinely red (the keeper).
- scripts/test-windows.ps1: split green guards (gate CI) from opt-in known-reds;
add -GuardsOnly; run indexing in-process (CBM_INDEX_SUPERVISOR=0) so a guard
reflects the path/hook/drive fix under test, not the index-worker spawn path.
- .github/workflows/_test.yml: new test-windows-guards job builds the product+UI
binary (scripts/build.sh --with-ui) and runs the guards with -GuardsOnly so
#700/#619/#548 stay enforced on Windows CI.
- RED_TEST_ANALYSIS.md: refreshed to record the landed fixes and current status.
Signed-off-by: Flipper <jacobphilipp@ymail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#581 (query-path memory growth) does not reproduce in our soak: a 10-min,
200-file query-only run shows RSS flat-to-shrinking and committed plateauing
(mimalloc already purges on free, purge_delay=0). Rather than ship speculative
mitigations for a leak we cannot measure, this adds the observability to find it
where it actually occurs, plus a continuous guard.
- diag: the diagnostics writer now appends a PERSISTENT NDJSON memory trajectory
(one sample / 5s: rss, committed, peak fields, page_faults, fd, queries), kept
on exit (rotates to a .1 generation past 8 MB) so users can send the time
series post-mortem. The previous latest-snapshot file was overwritten every 5s
and deleted on stop.
- ci: the soak now also runs a read-only query-leak leg (CBM_SOAK_MODE query-leak,
no reindex/mutate) on every platform including Windows, so a regression that
introduces a query-path leak is caught. soak-test.sh RESULTS_DIR is now
env-overridable so both legs keep separate artifacts.
- docs: README Troubleshooting and Diagnostics section + a bug-report field
explain the no-telemetry stance and how to capture and share the trajectory.
Build clean; unit suite 5714/0; trajectory verified to persist post-exit.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The ubuntu-24.04-arm test leg (native ARM64 Linux running the full suite under
AddressSanitizer + the FastAPI incremental index) exceeds the 60-minute job
timeout and was killed, failing ci-ok even though the suite was on track to pass.
ARM + ASan is legitimately 2-3x slower than x86-64.
Raise the substantial compute jobs (test, build, bug-repro board, soak's short
legs, security/codeql, cross-platform smoke, fast-repro) to a generous 240-minute
(4h) cap so a slow-but-correct runner can't false-timeout. Trivial aggregator
jobs (5/10/15m: setup-matrix, ci-ok, dco, lint, license-gate, quick smokes) and
the intentional soak caps (300/320m) are unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The native CLANGARM64 toolchain compiles the project fine, but linking the test
build fails: LLVM ships no AddressSanitizer runtime for aarch64-w64-windows-gnu
(libclang_rt.asan_dynamic.dll.a not found). ASan also cannot intercept under
x86-64 emulation, so Windows ARM64 has no working ASan by any toolchain.
Run the windows-11-arm leg with SANITIZE= (no sanitizer) so it builds and runs
the full suite natively as a real, required functional gate. ASan/UBSan coverage
is provided by the other nine legs, including native-ARM Linux/macOS; x86-64
Windows keeps full sanitizers.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
windows-11-arm is an ARM64 runner but the test matrix built it with the x86-64
msys2 environment (CLANG64), so the binary ran under Windows-on-ARM x86-64
emulation. AddressSanitizer's function interception cannot patch the emulated
system DLLs there (interception_win: unhandled instruction -> asan_malloc_win.cpp
CHECK failed), crashing in ASan init before any test ran. That was being hidden
behind optional:true.
Pin each Windows leg's msys2 environment + package arch to the RUNNER
architecture: x86-64 runners use CLANG64 (mingw-w64-clang-x86_64-*), the ARM64
runner uses CLANGARM64 (mingw-w64-clang-aarch64-*). The windows-11-arm binary is
now native ARM64, so ASan instruments native code and the leg is a real,
non-optional gate (matching smoke.yml, which already uses CLANGARM64 for it).
Every other matrix leg already used a toolchain matching its runner arch.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- repro_main: RUN_SUITE honors CBM_REPRO_ONLY (comma list of suite-name
substrings) for fast targeted validation of a single fix.
- fast-repro.yml: ASan single-platform (the no-sanitizer build crashed some
suites); single-platform is the speedup vs the 5-platform board.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- repro_main.c: redefine RUN_SUITE to print '[SUITE] <name> P passed, F failed'
so board/fast-lane output is greppable for which suites still have reds.
- bug-repro.yml: exclude qa/fast-** / qa/soak-** / qa/smoke-** from the board
push trigger (those branches run only their dedicated lane workflow).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Avoids waiting ~15min for the full 5-platform ASan board just to see whether a
fix dropped the red count. Pushing a qa/fast-** branch builds+runs test-repro on
ubuntu-latest without sanitizers (~5min). The full bug-repro.yml board stays the
comprehensive all-platform check.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
dry-run.yml and release.yml now pass broad_platforms:true to _test.yml + _smoke.yml,
which add (via a dynamic setup-matrix job) ubuntu-22.04 (older glibc / AlmaLinux
class), ubuntu-22.04-arm, macos-15, windows-2025, windows-11-arm on top of the core
set — a broader 'does it run everywhere' picture. The PR gate (pr.yml) and the
shipped release-binary targets (_build.yml) are unchanged. Broad-only legs are
tagged optional + continue-on-error, so a flaky/less-common runner is visible but
never blocks a release.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- scripts/smoke-invariants.sh: 30-check battery against the PROD binary —
--version/--help, MCP initialize handshake with stdin OPEN (#513), tools/list
(all 14), EVERY tool invocable with valid JSON-RPC + no crash, index→non-empty
graph, malformed-input resilience (bad JSON / empty / huge line / binary /
non-UTF8 / missing path), clean EOF exit, shared-lib resolution, install
dry-run. Bounded waits (read -t / timeout), no sleep loops; msys2-safe.
- .github/workflows/smoke.yml: runs it on the WIDEST runner matrix — ubuntu
22.04+24.04 (x64+arm64; 22.04 = older glibc / AlmaLinux class), macos
14/15/15-intel, windows 2022/2025 + windows-11-arm (experimental). A FAIL on
any platform is a binary a user would receive. workflow_dispatch + qa/smoke-**.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
#581 explicitly crashes Windows (50+ GB virtual memory → crash), so Windows is
the most important soak target — the earlier 2-platform cap (ubuntu+macos) missed
exactly where the bug manifests. Expand to the full matrix: linux amd64+arm64,
darwin arm64+amd64, and a windows-latest msys2 job (mirrors _soak.yml's windows
build + .exe binary-path detection). All legs run the query-leak mode, 320-min
budget.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
timeout-minutes is evaluated at workflow setup, where the inputs context is null
on push events; fromJSON(inputs.duration_minutes || '240') + 60 was a startup
failure (0 jobs), so the soak never ran on qa/soak-** either. Use a fixed 320-min
budget (covers the 240-min default soak + build + analysis).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- _soak.yml: timeout-minutes was 30 (soak-quick) / 45 (asan) while nightly passes
duration_minutes=240 — every 'nightly 4h soak' was silently KILLED at 30 min and
never ran multi-hour. Raise to 300/60 so the soak can actually complete.
- soak-test.sh: add CBM_SOAK_MODE=query-leak (default unchanged). It indexes once
then hammers read-only tools (search_graph/query_graph/trace_path/
get_code_snippet/search_code) with NO reindex/mutation — so index_repository's
cbm_mem_collect never runs to sweep the query-only leak #581 implicates. The
existing RSS ceiling/slope/ratio checks become the #581 detector.
- soak.yml: workflow_dispatch (duration_minutes, mode) + push to qa/soak-** ;
builds the prod binary and runs the soak with timeout = duration + 60, on
ubuntu + macos. Pushing a qa/soak-* branch starts a real multi-hour run.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Stand up a separate, non-gating reproduce-first suite that holds one RED case
per open bug issue (the redness is the deliverable + the regression guard):
- tests/repro/ + repro_main.c -> `make test-repro` (its own runner with its own
main + counters; deliberately EXCLUDED from ALL_TEST_SRCS so the gating
`make test` / ci-ok required check stays green and PRs are not wedged)
- repro_extraction.c: first reproduction, #554 -- a C++ out-of-line method's
inner CALLS edge must attribute to the class-qualified Method QN, not the
Module; ties the call's enclosing_func_qn to the method definition's own
qualified_name so a class-qualifier drop (the live root cause) fails it
- scripts/repro.sh: build+run the board; a build/link failure fails the job,
while expected test redness is reported as the board state (job stays green)
- .github/workflows/bug-repro.yml: workflow_dispatch (platform filter) + qa/**
push; runs the board on linux x2 / macos x2 / windows so many bug vectors can
be reproduced on many platforms at once
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Three native GitHub Actions to automate the mechanical parts of issue
triage:
- stale.yml: actions/stale scoped to the awaiting-reporter label —
warns at 21 days idle, closes at 35, auto-resets when the reporter
replies. Never touches PRs or unlabeled issues.
- label-actions.yml + .github/label-actions.yml: posts a templated
comment when duplicate or awaiting-reporter is applied (duplicates are
linked, not auto-closed).
- issue-labeler.yml + .github/issue-labeler.yml: adds area labels
(windows, stability/performance, parsing/quality, editor/integration,
ux/behavior, cypher, language-request) from title/body keywords.
Additive only; base bug/enhancement labels still come from the forms.
All third-party actions pinned to full commit SHAs with least-privilege
per-job permissions (issues: write only where required).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- graph-ui: bump vite ^6.4.2 -> ^6.4.3 and add overrides pinning the transitive
form-data >=4.0.6 and @babel/core >=7.29.6 (all dev-scope build/test deps, not
shipped in the binary). Clears the 4 open Dependabot alerts and Scorecard's
VulnerabilitiesID. `npm audit` now reports 0 vulnerabilities.
- codeql.yml: move `security-events: write` from the workflow top level to the
`analyze` job (top level is now `contents: read`), resolving Scorecard's
TokenPermissionsID least-privilege finding. CodeQL still uploads results from the
job-scoped token.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Homebrew only discovers formulae under Formula/ at the tap root. Add a
symlink to the pkg/homebrew/ location so `brew install` works.
Signed-off-by: Michael Hackner <mhackner@gmail.com>
A new push to a PR (or ref) now cancels the in-progress validation for
the previous commit instead of letting obsolete pipelines run to
completion. Drafts deliberately keep the full gate set — multi-platform
feedback matters most during iteration.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Adds the Contributor Covenant 2.1 code of conduct (canonical text,
byte-verified against upstream) and reproduction-first issue forms that
ask for shareable reproductions — dummy snippets or public OSS repos —
plus logs and exact commands, never proprietary code. CONTRIBUTING.md
now states explicitly that a Signed-off-by line certifies the DCO in
full for that contribution, with GitHub ToS inbound=outbound noted as
the independent backstop. The VirusTotal badge now points at the latest
release instead of a pinned historical scan.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
PRs now run security gates, lint, and the full test suite (perf
assertions excluded — they stay in dry runs and releases where a
timing-flaky red cannot block a merge). Builds, smoke and soak remain
maintainer-driven.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Pull requests run the security island only — static audit, license
gates, and the CodeQL gate plus the ci-ok summary; the full dry-run
chain (lint/test/build/smoke) stays maintainer-driven via
workflow_dispatch. The CodeQL gate now resolves the PR head SHA instead
of the synthetic merge commit so it can find the analysis run.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Pull requests now execute the dry-run chain (security including the
license gates, lint, full test suite, all build legs, smoke) plus a
single ci-ok summary job that fails unless every stage succeeded.
Branch protection requires dco + ci-ok, so nothing unverified can merge
— including from admins. CodeQL also runs on pull requests so the
security island completes on PR commits.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Every commit must now carry a Signed-off-by trailer matching its
author, certifying the right to submit the change under the project's
MIT license (DCO 1.1, the Linux kernel mechanism). Enforcement is
strict at three layers: a commit-msg hook rejects unsigned commits
locally (scripts/install-git-hooks.sh), and the new DCO workflow
rejects every push and pull request containing one. Merge commits and
bot authors are exempt, matching standard DCO checks.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
The license gate now proves itself before running: a --selftest mode
plants an unlicensed vendored file and asserts the structural layer
detects it, so a silently broken gate can no longer pass. The
byte-identity provenance audit gains exit-code semantics (any verdict
outside the accepted set fails) and runs as a blocking step in the
security workflow for both dry runs and releases.
The server.json sync step read its version from pkg/npm/package.json,
which can lag behind the release being published in the dispatched
commit. Use the workflow's version input instead — it is authoritative
for the run.
With soak_level=none the soak job is skipped; release-draft already
handles that with an explicit condition, but verify and the publish
jobs relied on the default success() check, which treats a skipped
ancestor as non-success and silently skips the whole publish chain.
Give each downstream job an explicit condition that only blocks on
real failures or cancellations.
Release archives now carry THIRD_PARTY_NOTICES.md, generated by
scripts/gen-third-party-notices.sh from THIRD_PARTY.md, the grammar
manifest, and the per-component license texts; the Homebrew formula
and AUR PKGBUILD install it alongside the binary. The SBOM gains
per-component license metadata, corrected versions, and the previously
missing vendored libraries. The security workflow gains a
vendored-license scan with an explicit allow-list policy, and the
release workflow exposes a skip_perf input for releases that do not
touch pipeline logic.
The release tag must point at the commit the artifacts were built from (github.sha). The step tagged whatever the job checkout resolved to - the branch head at job START - so a commit pushed to main mid-run moved the tag target; when that head commit happened to touch .github/workflows/, the GitHub App token's tag push was rejected outright (refusing to create refs at workflow-modifying commits), failing the 0.8.0 draft.
The 0.8.0 release failed at publish-registries because pkg/npm/package.json still carried the previous hand-pinned version and npm refuses to publish over an existing release. The job now rewrites pkg/npm/package.json and pkg/pypi/pyproject.toml from the workflow's version input (with grep verification that the injection took) before publishing, so a forgotten manual bump can never fail the pipeline again. server.json needs no injection - publish-mcp-registry already syncs it from the published npm package.
packaging/glama -> pkg/glama so all packaging lives under pkg/. Update the
_smoke.yml job command and the Dockerfile/comment references to the new path.
verify.sh is path-relative (dirname $0), so its logic is unchanged.
The standard linux release binary dynamically links glibc 2.38+ and
GLIBCXX_3.4.32, so it fails to start on Debian 11, Ubuntu 20.04/22.04,
RHEL/Rocky 8/9, Amazon Linux 2, etc. — yet install.sh, the npm and PyPI
wrappers, and the binary's own self-update all fetched it by default,
contradicting the "single static binary" promise.
Point every linux install + self-update path at the fully-static
"-portable" asset (gcc -static), which has no glibc floor. macOS/Windows
are unaffected and unchanged.
- install.sh, pkg/npm/install.js, pkg/pypi _cli.py: select -portable on linux
- src/cli/cli.c: self-update download URL AND checksum archive name both use
-portable on linux (they must match or the update fails checksum verify)
- scripts/smoke-test.sh: assert linux self-update targets the -portable asset
- scripts/ci/check-glibc-compat.sh: new guard — runs the binary inside
debian:bullseye (glibc 2.31) and asserts it starts
- _smoke.yml: run the guard on the portable binary in smoke-linux-portable
Reproduced: standard binary -> "GLIBC_2.38 not found" on glibc 2.31;
portable binary runs cleanly.
- glama.json claims maintainership on glama.ai.
- packaging/glama/Dockerfile wraps the static Linux binary in a minimal
image so Glama can launch the stdio server and run its MCP introspection
checks (which power the directory score badge). The tool needs no Docker
to run; this image is only for the directory integration. Fetches the
latest release binary, arch-aware via TARGETARCH.
- packaging/glama/verify.sh builds the image and asserts the server answers
initialize + tools/list with no project indexed.
- _smoke.yml runs verify.sh as a non-gating job (continue-on-error) so the
integration is guarded against drift without ever blocking a release.
- Add `mcpName` to the npm package and an `mcp-name:` marker to the PyPI
README so the registry can verify package ownership for both.
- Rewrite server.json to reference the npm + PyPI packages instead of
five per-platform mcpb tarballs. The old form was pinned to a stale
0.6.1 with hardcoded SHA-256s that needed manual updates every release;
the package form only needs a version sync. Also trims the description
to the registry's 100-character limit.
- Add a publish-mcp-registry job: downloads mcp-publisher, authenticates
via GitHub Actions OIDC (no token, no device flow), syncs server.json's
version to the just-published npm package, and publishes. It runs after
npm/PyPI but does not gate the release un-draft, so a registry outage
never blocks shipping and the job can be retried on its own.