Skip to content

Release v5.11.0 — security hardening, coverage closure, CI matrix on macOS #187

Release v5.11.0 — security hardening, coverage closure, CI matrix on macOS

Release v5.11.0 — security hardening, coverage closure, CI matrix on macOS #187

Workflow file for this run

name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
build-and-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
node-version: [20, 22, 24]
steps:
- uses: actions/checkout@v5
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node-version }}
cache: npm
- name: Install dependencies
run: npm ci
- name: Audit dependencies
run: npm audit --audit-level=high
- name: Build
run: npm run build
- name: Run tests
run: npm test
- name: Run tests with coverage
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
run: npm run test:coverage
- name: Upload coverage report
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
uses: actions/upload-artifact@v5
with:
name: coverage-report
path: coverage/
retention-days: 14
- name: Check coverage thresholds
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
run: |
if [ -f coverage/coverage-summary.json ]; then
echo "Coverage summary:"
cat coverage/coverage-summary.json | node -e "
const data = JSON.parse(require('fs').readFileSync('/dev/stdin', 'utf8'));
const t = data.total;
console.log(' Statements:', t.statements.pct + '%');
console.log(' Branches: ', t.branches.pct + '%');
console.log(' Functions: ', t.functions.pct + '%');
console.log(' Lines: ', t.lines.pct + '%');
"
fi
# v5.8.3 (#92): targeted guardrail — fail when a newly-added
# src/lib/**/*.ts(x) file ships with 0% statement coverage. Catches
# the regression mode that landed v5.8.0 in three back-to-back CI
# failures (new modules without tests dropping the global average
# under the 50% threshold).
- name: Check coverage of newly-added files
if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24
run: |
git fetch --depth=50 origin master:refs/remotes/origin/master 2>/dev/null || true
COVERAGE_BASE_REF=origin/master node scripts/check-new-file-coverage.mjs
- name: Verify build output
run: |
test -f dist/index.js
test -f dist/cli.js
echo "Build artifacts verified"
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
- run: npm ci
- name: TypeScript strict check
run: npx tsc --noEmit
multi-project-test:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build
- name: Multi-project scenario test
run: |
set -e
# Create three separate "projects" in temp dirs
PROJ_A=$(mktemp -d)
PROJ_B=$(mktemp -d)
PROJ_C=$(mktemp -d)
echo "=== Initializing three projects ==="
node dist/cli.js init --directory "$PROJ_A"
node dist/cli.js init --directory "$PROJ_B"
node dist/cli.js init --directory "$PROJ_C"
echo "=== Adding memories to each project ==="
GNOSYS_PROJECT="$PROJ_A" node dist/cli.js add-structured \
--title "Alpha Architecture" \
--content "Project Alpha uses microservices with gRPC." \
--category architecture
GNOSYS_PROJECT="$PROJ_B" node dist/cli.js add-structured \
--title "Beta Testing Strategy" \
--content "Project Beta uses integration testing with TestContainers." \
--category requirements
GNOSYS_PROJECT="$PROJ_C" node dist/cli.js add-structured \
--title "Gamma Deployment" \
--content "Project Gamma deploys to Kubernetes with Helm charts." \
--category decisions
echo "=== Verifying project isolation ==="
A_COUNT=$(GNOSYS_PROJECT="$PROJ_A" node dist/cli.js stats --json | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).totalCount))")
B_COUNT=$(GNOSYS_PROJECT="$PROJ_B" node dist/cli.js stats --json | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).totalCount))")
C_COUNT=$(GNOSYS_PROJECT="$PROJ_C" node dist/cli.js stats --json | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).totalCount))")
echo "Project A: $A_COUNT memories"
echo "Project B: $B_COUNT memories"
echo "Project C: $C_COUNT memories"
[ "$A_COUNT" -ge 1 ] || { echo "FAIL: Project A has $A_COUNT memories"; exit 1; }
[ "$B_COUNT" -ge 1 ] || { echo "FAIL: Project B has $B_COUNT memories"; exit 1; }
[ "$C_COUNT" -ge 1 ] || { echo "FAIL: Project C has $C_COUNT memories"; exit 1; }
echo "=== Cross-project search isolation ==="
A_SEARCH=$(GNOSYS_PROJECT="$PROJ_A" node dist/cli.js search "microservices" --json | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).results?.length ?? 0))")
B_SEARCH=$(GNOSYS_PROJECT="$PROJ_B" node dist/cli.js search "microservices" --json | node -e "process.stdout.write(String(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).results?.length ?? 0))")
echo "Search 'microservices' in A: $A_SEARCH results"
echo "Search 'microservices' in B: $B_SEARCH results"
echo "=== CLI commands work across projects ==="
GNOSYS_PROJECT="$PROJ_A" node dist/cli.js list --json > /dev/null
# v5.7.1: `gnosys dashboard` was removed; use `gnosys status --system`.
GNOSYS_PROJECT="$PROJ_B" node dist/cli.js status --system --json > /dev/null
GNOSYS_PROJECT="$PROJ_C" node dist/cli.js audit --json > /dev/null
rm -rf "$PROJ_A" "$PROJ_B" "$PROJ_C"
echo "Multi-project scenario passed"
network-share-simulation:
runs-on: ubuntu-latest
needs: build-and-test
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build
- name: Network share simulation (tmpfs)
run: |
set -e
# Create tmpfs mount to simulate network share latency/behavior
SHARE_DIR=$(mktemp -d)
echo "Using simulated share at $SHARE_DIR"
# Initialize project on "network share"
node dist/cli.js init --directory "$SHARE_DIR"
# Verify initialization — DB-only architecture uses central ~/.gnosys/gnosys.db
test -d "$SHARE_DIR/.gnosys" || { echo "FAIL: .gnosys dir not created"; exit 1; }
test -f "$SHARE_DIR/.gnosys/gnosys.json" || { echo "FAIL: gnosys.json not created"; exit 1; }
test -f "$HOME/.gnosys/gnosys.db" || { echo "FAIL: central gnosys.db not created"; exit 1; }
# Add and search memories
GNOSYS_PROJECT="$SHARE_DIR" node dist/cli.js add-structured \
--title "Shared Knowledge" \
--content "This memory lives on a network share." \
--category concepts
SEARCH_RESULT=$(GNOSYS_PROJECT="$SHARE_DIR" node dist/cli.js search "network share" --json 2>/dev/null || echo '{"results":[]}')
echo "Search result: $SEARCH_RESULT"
# Verify stats
STATS=$(GNOSYS_PROJECT="$SHARE_DIR" node dist/cli.js stats --json)
echo "Stats: $STATS"
rm -rf "$SHARE_DIR"
echo "Network share simulation passed"