Skip to content

Commit f5de945

Browse files
authored
Release v5.11.0 — security hardening, coverage closure, CI matrix (#8)
Release v5.11.0 — security hardening, coverage closure, CI matrix on macOS
2 parents 6e674ad + 64a40a1 commit f5de945

219 files changed

Lines changed: 9988 additions & 1061 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,20 @@ on:
88

99
jobs:
1010
build-and-test:
11-
runs-on: ubuntu-latest
11+
runs-on: ${{ matrix.os }}
1212

1313
strategy:
14+
fail-fast: false
1415
matrix:
15-
node-version: [22, 24]
16+
os: [ubuntu-latest, macos-latest]
17+
node-version: [20, 22, 24]
18+
exclude:
19+
# macOS Node 20 truncates `gnosys --help` mid-output when stdout is a
20+
# pipe (Node 20.x macOS stdout-flush-on-exit quirk). Affects only
21+
# piped capture; interactive use is fine. Track separately; re-enable
22+
# once on Node 22+ or when the stdout-flush bug is patched upstream.
23+
- os: macos-latest
24+
node-version: 20
1625

1726
steps:
1827
- uses: actions/checkout@v5
@@ -36,19 +45,19 @@ jobs:
3645
run: npm test
3746

3847
- name: Run tests with coverage
39-
if: matrix.node-version == 24
48+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
4049
run: npm run test:coverage
4150

4251
- name: Upload coverage report
43-
if: matrix.node-version == 24
52+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
4453
uses: actions/upload-artifact@v5
4554
with:
4655
name: coverage-report
4756
path: coverage/
4857
retention-days: 14
4958

5059
- name: Check coverage thresholds
51-
if: matrix.node-version == 24
60+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
5261
run: |
5362
if [ -f coverage/coverage-summary.json ]; then
5463
echo "Coverage summary:"
@@ -68,7 +77,7 @@ jobs:
6877
# failures (new modules without tests dropping the global average
6978
# under the 50% threshold).
7079
- name: Check coverage of newly-added files
71-
if: matrix.node-version == 24
80+
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
7281
run: |
7382
git fetch --depth=50 origin master:refs/remotes/origin/master 2>/dev/null || true
7483
COVERAGE_BASE_REF=origin/master node scripts/check-new-file-coverage.mjs

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ coverage/
1212
# Agent config, rules & skills (local-only — AGENTS.md stays public)
1313
rules/
1414
.gnosys/
15-
CLAUDE.md
15+
/CLAUDE.md
1616
.claude/
1717
.cursor/
1818
.codex/
19+
20+
# Negate the CLAUDE.md ignore for this golden fixture (macOS case-insensitive FS)
21+
!src/test/fixtures/ide-init/claude.md

.madgerc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"detectiveOptions": {
3+
"ts": { "skipAsyncImports": true },
4+
"es6": { "skipAsyncImports": true }
5+
}
6+
}

CHANGELOG.md

Lines changed: 143 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,128 @@ All notable changes to Gnosys are documented here.
55
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
### Historical versions
9+
10+
Detailed CHANGELOG coverage begins at **5.2.16**. Earlier 5.0.0–5.2.15 releases and a few 5.2.x patches without individual entries (5.2.17, 5.2.18, 5.2.21) are tracked via [git tags](https://github.com/proticom/gnosys/tags). Versions 5.2.13, 5.2.14, and 5.2.15 were CHANGELOG-only and never published to npm.
11+
12+
## [5.11.0] — 2026-05-26
13+
14+
Pending release — bundles 84 commits since 5.10.0 covering a network-hosted MCP
15+
transport, a hardened HTTP surface, structured logging, a v5.12 portability
16+
track, and the C/D/E hardening + documentation review.
17+
18+
### Added
19+
20+
- **Network-hosted MCP transport (v5.12 Phases A–E).** Run Gnosys as a remote
21+
MCP server over Streamable HTTP, containerize it, and point local IDEs at it.
22+
- `gnosys serve --transport http` — Streamable HTTP transport for network MCP
23+
(v5.12 Phase A + C).
24+
- Capability registrations collected as replayable thunks so HTTP sessions
25+
replay the same tool surface as stdio (v5.12 Phase A foundation).
26+
- `gnosys connect` — point an IDE at a remote Gnosys server (v5.12 Phase B).
27+
- `gnosys centralize` — seed a central server's brain from a local one
28+
(v5.12 Phase E).
29+
- Docker support for the network-hosted MCP server (v5.12 Phase D).
30+
- **Structured logging (D.5).** Text, JSON, and file sinks for operational
31+
visibility across CLI and server modes.
32+
- **Audit rows for remote sync.** Push/pull operations now emit audit rows for
33+
sync observability.
34+
- **HTTP CORS guard.** Default-deny browser origins on the HTTP transport.
35+
- **Atomic config writes.** Config updates use temp-then-rename for crash safety.
36+
- **Preference key validation.** Invalid preference keys get did-you-mean hints.
37+
- **`--json` on read-only commands.** Seven read-only CLI commands now support
38+
machine-readable output.
39+
- **Provenance in reads.** `source_file` surfaced in reads; audit file ingestion
40+
tracked.
41+
- **Export transparency.** Excluded-archived count surfaced so exports do not
42+
silently drop memories.
43+
- **`gnosys upgrade` package-manager detection.** Upgrade command detects npm,
44+
pnpm, or yarn automatically.
45+
- **npm discoverability.** Added `model-context-protocol` and `agent-memory`
46+
keywords to package.json.
47+
- **Documentation and ADRs (E.4–E.8).**
48+
- Generated `docs/cli.md` from `src/cli.ts` (E.5) and `docs/mcp-tools.md`
49+
from `src/index.ts` (E.4).
50+
- Backfilled 8 ADRs from Gnosys memory (E.6).
51+
- `docs/source-of-truth.md` — content map for where docs live (E.8).
52+
- `docs/threat-model.md` — security threat model (A.13).
53+
- `docs/coverage-baseline.md` — C.1 coverage gate baseline (CC.5).
54+
- Setup walkthrough, configuration precedence chains, LLM provider contract,
55+
search-modes comparison, cost model, update-integrity notes, and network-MCP
56+
rate-limiting rationale.
57+
- **Acceptance smokes (C.9).** MCP, WebKB, and sync smoke tests at the
58+
acceptance layer.
59+
- **Test coverage expansion.** Extended suites for ingest (100% lines), dream
60+
(95%), db (88%), remote (80%), HTTP session isolation, bearer-token contract,
61+
MCP registration replay, search golden corpus, lifecycle invariants, DB
62+
recovery, and adversarial ingest fixtures.
63+
64+
### Changed
65+
66+
- **CI test matrix on Linux + macOS (C.7).** Tests now run on both platforms.
67+
- **Node 18 & 20 in CI.** Matrix expanded so `engines.node >=18` is verified.
68+
- **Biome linter (B.2).** Adopted Biome as the project linter.
69+
- **Dependency cleanup (B.3/B.4).** Removed dead exports, declared jszip,
70+
added knip; resolved circular dependencies.
71+
- **DB-only history (B.3).** Removed legacy git-backed rollback/history paths;
72+
SQLite is the sole source of truth.
73+
- **CHANGELOG backfill (E.2).** Added 5.4.1/5.4.3 entries and the Historical
74+
versions preamble note.
75+
- **README updates.** Slimmed and repositioned; documents both `gnosys` and
76+
`gnosys-mcp` bins, Node.js >= 18 prerequisite, optional native deps with
77+
install hints, and a complete MCP Tool Reference table (all 51 tools).
78+
- **DB performance.** Indexed `memories.modified` and `memories.created`.
79+
80+
### Fixed
81+
82+
- **Path traversal in export (A.5).** `gnosys export` no longer allows
83+
directory escape via crafted paths.
84+
- **Shell injection (A.8).** `cp` and `open` subprocess calls use argv arrays
85+
instead of shell strings.
86+
- **File permissions (A.11).** `.env` and `gnosys.db` created with `0600`
87+
permissions.
88+
- **Clean build / clean dist (20.13).** `dist/` cleaned before build so deleted modules are
89+
not shipped to npm.
90+
- **Legacy schema migration.** DB migrates v1/v2 legacy schema before applying
91+
current `SCHEMA_SQL`.
92+
- **npm provenance.** Canonicalized `repository.url` for npm provenance.
93+
- **README tool table.** Removed stale `gnosys_rollback` reference.
94+
- **Package assets.** `docs/logo.svg` shipped so the README logo renders on npm.
95+
- **MCP error envelopes.** Tool errors normalized via `formatMcpError`.
96+
- **Machine ID stability.** `GNOSYS_MACHINE_ID` env override for stable id
97+
across hostname changes.
98+
- **DB busy timeout.** All file-based `Database()` opens set `busy_timeout`.
99+
- **Embeddings install hint.** One-line hint when `@xenova/transformers` is
100+
missing.
101+
- **LLM request timeouts.** Enforced on all provider calls.
102+
- **HTTP session cleanup.** Idle sessions reaped to stop disconnect leaks.
103+
104+
### Security
105+
106+
- **HTTP auth on non-loopback bind.** Server refuses to start without an auth
107+
token when bound beyond loopback; bearer-token contract locked by tests.
108+
- **HTTP DoS hardening.** Request body size bounded; receive-time limits
109+
enforced.
110+
- **SSRF parity (17.4).** `safeFetch` used for import-from-URL; web ingest
111+
closes redirect bypass, loopback, and IP-encoding holes.
112+
- **DOCX zip-bomb guard.** DOCX extractor rejects archives that exceed safe
113+
size limits.
114+
- **API key redaction.** Format-agnostic redaction in LLM provider error
115+
messages.
116+
- **Prompt injection hardening.** Synthesis prompt in `gnosys ask` hardened
117+
against embedded prompt injection.
118+
- **CORS default-deny.** Browser origins blocked unless explicitly allowed
119+
(also listed under Added).
120+
121+
122+
### Removed
123+
124+
- **Node 18 support.** Node 18 reached End-of-Life in April 2025; the modern
125+
test toolchain (vitest + rolldown) now imports `node:util.styleText`, which
126+
only exists on Node 20.12+. The CI matrix was updated to Node 20/22/24 ×
127+
Linux/macOS and `engines.node` was raised to `>=20.12.0`. The README's
128+
install prerequisite changed from "Node.js ≥ 18" to "Node.js ≥ 20.12".
129+
8130
## [5.10.0] — 2026-05-23
9131

10132
Machine-portable project paths, plus repository/community-standards groundwork.
@@ -1127,24 +1249,17 @@ transitive, both functional, neither breaking. Tracked in road-006.
11271249

11281250
- **`gnosys dream run` — explicit manual trigger.** The bare `gnosys dream` already runs a cycle, but users naturally type `dream run` to match the `dream log` pattern. Added an alias subcommand. Both forms now check the central DB's `dream_machine_id` designation before running and refuse on non-designated machines unless `--force` is passed.
11291251

1130-
1252+
## [5.4.3] — 2026-05-02
11311253

11321254
### Fixed
11331255

1134-
- **Postinstall output now visible during `npm install -g`.** npm 7+ hides postinstall stdout for global installs but shows stderr — switched our messages to stderr so users actually see "Gnosys v5.4.3 installed / Run `gnosys upgrade`" after a global install.
1135-
- **Postinstall version read fixed.** Previously printed "Gnosys vunknown" because `require("fs")` doesn't work in ESM modules. Replaced with proper top-level `import { readFileSync }` and `import.meta.url`-based path resolution.
1256+
- **Postinstall output now visible during `npm install -g`.** npm 7+ hides postinstall stdout for global installs but shows stderr — switched messages to stderr so users see the installed version and upgrade hint after a global install.
1257+
- **Postinstall version read fixed.** Previously printed "Gnosys vunknown" because `require("fs")` doesn't work in ESM modules. Replaced with top-level `readFileSync` and `import.meta.url`-based path resolution.
11361258

11371259
### Added
11381260

1139-
- **Upgrade nudge on first CLI invocation.** Tracks `last_seen_version` in central DB meta. On every CLI command boot, if the installed version differs from what's stored, print a one-line stderr notice:
1140-
```
1141-
gnosys: upgraded to v5.4.3 (from v5.4.2). Run 'gnosys upgrade' to sync registered projects.
1142-
```
1143-
Fires once per upgrade, then updates the meta. Skipped when running `gnosys upgrade` itself, when `GNOSYS_SKIP_UPGRADE_NUDGE=1` is set, or when the central DB is unavailable. Belt-and-suspenders for cases where the postinstall hook silently fails (CI, Docker builds, `--ignore-scripts`).
1144-
1145-
### Known issue (deferred to v5.5.0)
1146-
1147-
- `npm install` still prints `npm warn deprecated prebuild-install@7.1.3: No longer maintained.` This is a transitive deprecation: `prebuild-install` is pulled in by `better-sqlite3` and (via `sharp`) by `@xenova/transformers`. The package still works correctly — the maintainer has just announced no future patches. Migrating `@xenova/transformers` (now a stale package) to `@huggingface/transformers@4.x` (the modern rebrand) is planned for v5.5.0 and will remove half of the dependency chain. The other half waits on `better-sqlite3` migrating to `node-gyp-build` upstream.
1261+
- **Upgrade nudge on first CLI invocation.** Tracks `last_seen_version` in central DB meta. When the installed version differs from what's stored, prints a one-line stderr notice, then updates meta. Skipped for `gnosys upgrade`, when `GNOSYS_SKIP_UPGRADE_NUDGE=1`, or when the central DB is unavailable.
1262+
- **`CODE_OF_CONDUCT.md`** at the repository root.
11481263

11491264
## [5.4.2] — 2026-05-01
11501265

@@ -1178,6 +1293,22 @@ The pattern is now consistent: `gnosys setup` runs the full wizard, and `gnosys
11781293
- gnosys-tests regression suite extended with `dream-log.test.ts`, `setup-dream.test.ts`, `removed-commands.test.ts`, plus DREAM HEALTH assertion in `dashboard.test.ts`.
11791294
- Manual smoke: dashboard surfaces DREAM HEALTH; designated machine probe runs at MCP boot; dream log filters work; removed commands return non-zero with "unknown command".
11801295

1296+
## [5.4.1] — 2026-05-01
1297+
1298+
### Added
1299+
1300+
- **Remote-first architecture.** Reads hit the remote NAS DB when reachable; local DB is an offline-only cache with a stderr fallback notice when remote is unreachable. `GnosysDB.openLocal()` for explicit local sync ops; `GNOSYS_LOCAL_ONLY=1` forces local-only mode.
1301+
- **ULID memory IDs** for new memories (`prefix-<ULID>`); existing prefix-N IDs unchanged.
1302+
- **Regression suite** extended for the v5.4.x architecture changes.
1303+
1304+
### Changed
1305+
1306+
- **Sync now includes the projects table**`push()`, `pull()`, `sync()`, and `migrate()` sync project rows as well as memories. `SyncResult` gains `projectsPushed` / `projectsPulled` counters.
1307+
1308+
### Fixed
1309+
1310+
- Ten-bug sweep (B1–B10): central-DB routing for `gnosys graph` and dashboard project counts; removed stale dashboard labels; ESM-safe keychain lookup with Linux `secret-tool` support; dashboard border alignment; live ollama/lmstudio probes; deep-merge for `loadConfig`; SQLITE_CORRUPT recovery hints in MCP write errors; WAL autocheckpoint pragma; LLM error messages reference the configured provider's env var.
1311+
11811312
## [5.4.0] — 2026-04-30
11821313

11831314
### Added — three new IDE integrations

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ src/
169169
└── prompts/ # System prompts
170170
```
171171

172+
## Documentation
173+
174+
For where each kind of doc belongs (user-facing site vs in-repo source of truth vs Gnosys memory), see [`docs/source-of-truth.md`](docs/source-of-truth.md).
175+
172176
## Testing
173177

174178
### Test Structure

Dockerfile

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,31 @@ FROM node:20-alpine
2121

2222
WORKDIR /app
2323

24-
# Runtime needs git for history/rollback features
24+
# Runtime needs git for history/rollback features (busybox provides wget for the healthcheck)
2525
RUN apk add --no-cache git
2626

2727
# Copy built artifacts and production dependencies
2828
COPY --from=builder /app/dist ./dist
2929
COPY --from=builder /app/node_modules ./node_modules
3030
COPY --from=builder /app/package.json ./
3131

32-
# Create a default working directory for .gnosys vault
33-
RUN mkdir -p /data
32+
# v5.12: the brain lives on a host-local volume (/data). NEVER back this with an
33+
# SMB/NFS share — network filesystems corrupt SQLite under gnosys's many small
34+
# writes. GNOSYS_LOCAL_ONLY keeps this server authoritative (no remote hop).
35+
ENV NODE_ENV=production \
36+
GNOSYS_HOME=/data \
37+
GNOSYS_LOCAL_ONLY=1
3438

35-
WORKDIR /data
39+
RUN mkdir -p /data && chown -R node:node /data /app
40+
USER node
41+
VOLUME /data
42+
EXPOSE 7777
3643

37-
# Default: start the MCP server (stdio mode)
44+
# Set GNOSYS_SERVE_TOKEN at runtime to require `Authorization: Bearer <token>`.
45+
HEALTHCHECK --interval=30s --timeout=5s --start-period=25s --retries=3 \
46+
CMD wget -qO- http://127.0.0.1:7777/health || exit 1
47+
48+
# Network-hosted MCP. Binds 0.0.0.0 INSIDE the container (isolated); control
49+
# external access with the host firewall / Tailscale + a bearer token.
3850
ENTRYPOINT ["node", "/app/dist/cli.js"]
39-
CMD ["serve"]
51+
CMD ["serve", "--transport", "http", "--host", "0.0.0.0", "--port", "7777"]

0 commit comments

Comments
 (0)