Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
10d4bf7
chore(migration): prepare ByteFolk GitHub coordinates (#142)
PeterGuy326 Sep 1, 2026
1332bf4
ci(release): add npm-publish job (OIDC Trusted Publishing) for mem-mc…
PeterGuy326 Sep 2, 2026
2e4ec46
build(deps-dev): bump browserslist from 4.28.2 to 4.28.8 in /web (#159)
dependabot[bot] Sep 3, 2026
4cf4452
chore(codeowners): add third independent reviewer (#138)
PeterGuy326 Sep 3, 2026
87d235b
fix(web): make the proxy the single authority for the shared security…
waterbro-8 Sep 3, 2026
7a194f1
fix(npm): bound Windows cache-lock contention retries (#137)
PeterGuy326 Sep 4, 2026
2986fe3
ci: enable free security baseline
PeterGuy326 Sep 8, 2026
87db0df
chore(web): refresh audited development dependencies (#192)
PeterGuy326 Sep 10, 2026
39e8946
fix(npm): follow the registry identifier to the bytefolk namespace (#…
waterbro-8 Sep 10, 2026
a1436d2
build(deps-dev): bump postcss-selector-parser from 6.1.2 to 6.1.4 in …
dependabot[bot] Sep 10, 2026
d9d0969
fix(cli-memd): withhold URLs whose credentials cannot be attributed (…
waterbro-8 Sep 10, 2026
55d09b2
build(worker): raise the pypdf floor and pin to 6.18.0 (#188)
waterbro-8 Sep 10, 2026
3e8acae
build(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.2 in /se…
dependabot[bot] Sep 10, 2026
3c13f04
docs(governance): add GOVERNANCE.md with the tag-ruleset record corre…
PeterGuy326 Sep 11, 2026
f1cc9eb
fix(ci): resolve MinIO images from quay.io after the Docker Hub withd…
waterbro-8 Sep 16, 2026
2c524cc
ci(security): run CodeQL on fork pull requests (#205)
PeterGuy326 Sep 17, 2026
f00fff7
chore(ci): correct CodeQL pinned-version annotations (#203)
PeterGuy326 Sep 17, 2026
0a0b55f
docs(goal): correct four stale status statements for merged capabilit…
sun-970 Sep 17, 2026
ced64a1
fix(web): unify shared tokens, alignment and empty states (#212)
PeterGuy326 Sep 17, 2026
904e8e7
fix(release): validate compare links and protect checksum output (suc…
PeterGuy326 Sep 17, 2026
1b27aac
fix(ci): run Web tests and preserve audit evidence (successor to #169…
PeterGuy326 Sep 17, 2026
6543983
fix(search): publish lexical route corrections (successor to #183) (#…
PeterGuy326 Sep 17, 2026
ae30bd5
fix(recall): publish fail-closed producer corrections (successor to #…
PeterGuy326 Sep 17, 2026
243697d
fix(folders): clean up blobs on recursive delete (#177)
waterbro-8 Sep 18, 2026
884b54d
docs(onboarding): make deploy/compose the primary onboarding path (#109)
waterbro-8 Sep 18, 2026
f72e294
refactor(ingest): extract the shared local ingestion core (#111) (#217)
waterbro-8 Sep 18, 2026
5d60f66
perf(index): add cosine HNSW indexes and text continuation (#173) (#219)
waterbro-8 Sep 18, 2026
3cf85bf
feat(release): publish installable memd and reconcile /v1/version (#1…
waterbro-8 Sep 18, 2026
e0e47c7
feat(memory): add durable-memory.v1 principal-bound contract (#220) (…
sun-970 Sep 18, 2026
fa63a9a
fix(ingest): bound cursor lock waits so a wedged peer cannot hang ing…
PeterGuy326 Sep 19, 2026
7b8bad3
chore(release): rebase ByteFolk mem-mcp 0.1.2 and add MCP Registry OI…
waterbro-8 Sep 20, 2026
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
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Changes require review from the organization administrator or the designated
# independent reviewer, so code-owner review is satisfiable without admin bypass.
* @PeterGuy326 @Bindy-lbb
* @PeterGuy326 @Bindy-lbb @waterbro-8
49 changes: 49 additions & 0 deletions .github/workflows/bytefolk-scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: ByteFolk Scorecard

on:
push:
branches:
- main
schedule:
- cron: '43 3 * * 1'
workflow_dispatch:

permissions:
contents: read

jobs:
scorecard:
name: OpenSSF Scorecard
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: read
actions: read
pull-requests: read
security-events: write
id-token: write
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Run Scorecard analysis
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- name: Upload Scorecard artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scorecard-results
path: results.sarif
if-no-files-found: error
retention-days: 14

- name: Upload Scorecard results
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
sarif_file: results.sarif
69 changes: 69 additions & 0 deletions .github/workflows/bytefolk-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: ByteFolk Security Baseline

on:
pull_request:
push:
branches:
- main
schedule:
- cron: '17 3 * * 1'
workflow_dispatch:

permissions:
contents: read

jobs:
dependency-review:
name: Dependency review
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Review dependency changes
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high
fail-on-scopes: runtime
comment-summary-in-pr: never

codeql:
name: CodeQL (${{ matrix.language }})
runs-on: ubuntu-24.04
timeout-minutes: 30
permissions:
contents: read
actions: read
packages: read
security-events: write
strategy:
fail-fast: false
matrix:
language:
- go
- python
- javascript-typescript
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
languages: ${{ matrix.language }}
queries: security-extended

- name: Autobuild Go
if: ${{ matrix.language == 'go' }}
uses: github/codeql-action/autobuild@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9

- name: Analyze
uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9
with:
category: /language:${{ matrix.language }}
111 changes: 110 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,24 @@ jobs:

- name: Audit dependencies
working-directory: web
run: npm run audit
# shell: bash is load-bearing: the default bash -e {0} shell has no
# pipefail, so tee would report its own exit status and a failing audit
# would pass this gate.
shell: bash
run: npm run audit 2>&1 | tee "${RUNNER_TEMP}/web-audit-transcript.txt"

- name: Upload audit evidence
if: always() && !cancelled()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: web-audit-transcript-${{ github.sha }}
path: ${{ runner.temp }}/web-audit-transcript.txt
if-no-files-found: error
retention-days: 14

- name: Run unit tests
working-directory: web
run: npm test

- name: Lint
working-directory: web
Expand Down Expand Up @@ -351,6 +368,80 @@ jobs:
node --check platforms.js
npm pack --dry-run --ignore-scripts

windows-audit-evidence:
name: Windows audit evidence
# The batch helper exists to prove audit-retry.mjs works on a real cmd.exe,
# where only `npm run` supplies npm_execpath. Its regression test replays the
# batch source against a stub npm.cmd, so it proves the mechanics but never
# the execution. This job is the execution, and it is a job rather than an
# `if: runner.os == 'Windows'` step inside npm-wrapper-compatibility so the
# check name itself documents the Windows dependency.
runs-on: windows-2025
timeout-minutes: 20

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: "24"
cache: npm
cache-dependency-path: web/package-lock.json

- name: Install dependencies
working-directory: web
run: npm ci

- name: Test Windows audit evidence helper
run: node --test scripts/test_win_audit_verify.mjs

- name: Run Windows audit evidence helper against the real registry
working-directory: web
# shell: bash is load-bearing: with the default shell there is no
# pipefail, so tee's exit status would replace cmd.exe's and the
# helper's nonzero-audit assertion would become unfalsifiable.
shell: bash
run: |
# //d //c, not /d /c: git-bash rewrites a leading /d and /c into D:/
# and C:/, which leaves cmd.exe with no option flags. It then prints
# its interactive banner and exits 0, so the helper never runs and the
# job goes green on an empty transcript.
cmd.exe //d //c "..\scripts\win-audit-verify.bat" 2>&1 \
| tee "${RUNNER_TEMP}/win-audit-transcript.txt"

- name: Verify the transcript is real evidence
shell: bash
# A successful cmd.exe proves nothing on its own; the transcript has to
# show the helper actually reached its report and gated on a passing
# audit, or this job would silently certify nothing.
run: |
transcript="${RUNNER_TEMP}/win-audit-transcript.txt"
for needle in \
"\[win-audit-verify\] starting npm run audit" \
"\[win-audit-verify\] finished at" \
"\[win-audit-verify\] npm run audit exit code: 0" \
"found 0 vulnerabilities"
do
if ! grep -q -- "$needle" "$transcript"; then
echo "::error::win-audit-verify.bat did not produce '$needle'; the Windows audit evidence is not real."
sed -n '1,40p' "$transcript"
exit 1
fi
done

- name: Upload Windows audit evidence
if: always() && !cancelled()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: win-audit-transcript-${{ github.sha }}
path: ${{ runner.temp }}/win-audit-transcript.txt
if-no-files-found: error
retention-days: 14

deployment:
name: Deployment profiles
runs-on: ubuntu-24.04
Expand All @@ -364,3 +455,21 @@ jobs:

- name: Validate deployment configuration and production images
run: make test-deploy-build

- name: Validate web security response headers
run: |
# The header contract is measured against the nginx that actually ships,
# so it runs on the image the step above built. That image ends its own
# build at USER 101, which cannot install packages, so the tools go into
# a throwaway child image that returns to that user id afterwards -- the
# harness then still runs unprivileged, as the container does in
# production.
printf 'FROM mem-web:deploy-validation\nUSER root\nRUN apk add --no-cache bash curl python3 gettext\nUSER 101\n' \
>"${RUNNER_TEMP}/headers.Dockerfile"
docker build --tag mem-web-headers:validation \
-f "${RUNNER_TEMP}/headers.Dockerfile" "${RUNNER_TEMP}"
docker run --rm \
--volume "${GITHUB_WORKSPACE}:/src:ro" \
--env NGINX_BIN=/usr/sbin/nginx \
mem-web-headers:validation \
bash /src/scripts/test_nginx_security_headers.sh
115 changes: 115 additions & 0 deletions .github/workflows/mcp-registry-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: MCP Registry Publish

# G5: official MCP Registry metadata. Does not host the binary.
# Requires G4: @bytefolk/mem-mcp must already be on npm with matching mcpName.
# Auth is GitHub OIDC against io.github.bytefolk/* — not a personal device login.
# Founder gate: environment mcp-registry (same owner as npm-release).

on:
workflow_dispatch:
inputs:
version:
description: "Published npm/package version (e.g. 0.1.2, no v prefix)"
required: true
type: string

permissions:
contents: read

concurrency:
group: mcp-registry-publish-bytefolk-mem-mcp
cancel-in-progress: false

jobs:
publish:
name: Publish io.github.bytefolk/mem-mcp (OIDC)
if: github.repository == 'bytefolk/mem'
runs-on: ubuntu-24.04
timeout-minutes: 10
environment: mcp-registry
permissions:
contents: read
id-token: write
steps:
- name: Check out default branch for registry manifest
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Require @bytefolk/mem-mcp on npm before Registry write
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
if [[ ! "${VERSION}" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
echo "expected X.Y.Z, got ${VERSION}" >&2
exit 1
fi
meta="$(curl -fsS "https://registry.npmjs.org/@bytefolk/mem-mcp/${VERSION}")"
name="$(python3 -c 'import json,sys; print(json.load(sys.stdin)["name"])' <<<"${meta}")"
mcp="$(python3 -c 'import json,sys; print(json.load(sys.stdin).get("mcpName",""))' <<<"${meta}")"
[[ "${name}" == "@bytefolk/mem-mcp" ]]
[[ "${mcp}" == "io.github.bytefolk/mem-mcp" ]]

- name: Install mcp-publisher
env:
MCP_PUBLISHER_VERSION: v1.8.1
MCP_PUBLISHER_LINUX_AMD64_SHA256: a06c9096dcb9727c13555b6be26c7effa707b01f06a4c561ba7a3635443cf2cc
MCP_PUBLISHER_LINUX_ARM64_SHA256: 8dd75a6cf6845688b5d4e46df58d3ca26d5c8d233bb0626606e1db82c5e883e4
run: |
set -euo pipefail
os="$(uname -s | tr '[:upper:]' '[:lower:]')"
arch="$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')"
checksum_var="MCP_PUBLISHER_$(printf '%s_%s' "${os}" "${arch}" | tr '[:lower:]' '[:upper:]')_SHA256"
checksum="${!checksum_var:-}"
[[ "${checksum}" =~ ^[0-9a-f]{64}$ ]] || {
echo "no pinned mcp-publisher checksum for ${os}/${arch}" >&2
exit 1
}
archive="${RUNNER_TEMP}/mcp-publisher_${os}_${arch}.tar.gz"
curl -fsSL --retry 3 \
"https://github.com/modelcontextprotocol/registry/releases/download/${MCP_PUBLISHER_VERSION}/mcp-publisher_${os}_${arch}.tar.gz" \
--output "${archive}"
printf '%s %s\n' "${checksum}" "${archive}" | sha256sum --check --strict
tar -xzf "${archive}" mcp-publisher
chmod +x ./mcp-publisher

- name: Stage official server.json
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
python3 - <<'PY'
import json, os
path = "npm/mcp-registry.server.json"
with open(path) as f:
doc = json.load(f)
version = os.environ["VERSION"]
doc["version"] = version
doc["packages"][0]["version"] = version
with open("server.json", "w") as f:
json.dump(doc, f, indent=2)
f.write("\n")
PY

- name: Login with GitHub OIDC and publish
run: |
set -euo pipefail
./mcp-publisher login github-oidc
./mcp-publisher publish

- name: Read back Registry search
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
curl -fsS "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.bytefolk/mem-mcp" \
| tee "${RUNNER_TEMP}/mcp-registry-readback.json"
python3 - <<'PY'
import json, os, sys
data = json.load(open(os.environ["RUNNER_TEMP"] + "/mcp-registry-readback.json"))
servers = data.get("servers") or data.get("result") or []
if not servers:
sys.exit("HOLD: registry search returned no servers")
print("G5 readback: %s" % json.dumps(servers[0])[:2000])
PY
1 change: 1 addition & 0 deletions .github/workflows/memory-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ jobs:
scripts/acceptance_agent_memory.sh \
scripts/generate_release_checksums.sh \
scripts/render_release_notes.sh \
scripts/test_release_checksum_output_safety.sh \
scripts/test_release_helpers_compat.sh \
scripts/test_release_guards.sh \
scripts/test_validate_release_action_pins_compat.sh \
Expand Down
Loading
Loading