KeiSeiKit-1.0/CHANGELOG.md
Parfii-bot f12eb9f83c fix(v0.21.1): wave-audit consolidated — 5 critic HIGH + 2 security HIGH + 3 polish
Closes 10 audit findings from 4-agent wave (critic + security +
architect + validator) on v0.21.0.

CRITIC HIGH (5):
  H1 s3_cloud::commit() was listing with delimiter='/' — nested
     writes silently dropped from manifest hash. Added
     list_recursive() (no delimiter), filter manifest-*.json from
     hash input.
  H2 S3Cfg access_key_env + secret_key_env were advertised in TOML
     but never read. Wired via resolve_explicit_creds() with
     aws-credential-types. Partial-set or empty-resolve → error.
  H3 display::sanitize_display missing in detach.rs + mount.rs
     (regression of v0.19.2 L9 ANSI injection fix). Applied at 8
     print sites. 2 new integration tests.
  H4 adapters/jsonmcp.rs RESTORED (was lost in earlier merge).
     107 LOC shared module: load_json_or_empty / upsert_under_key /
     remove_under_key / persist. claude_code 163→105, cursor 165→106,
     zed 178→114. Unified error handling via ConfigParseError.
  H5 ENV_LOCK shared across kei-store tests. New test_env.rs (24 LOC)
     exposed under cfg(any(test, feature='s3')). github.rs +
     s3_cloud/tests.rs + s3_smoke.rs all use shared mutex. Fixes
     parallel-test race on KEI_STORE_S3_ENDPOINT.

SECURITY HIGH (2):
  SEC-H1 scripts/install-actionlint.sh — added sha256 verify
     (shasum/sha256sum) before extract. ACTIONLINT_SHA256_OVERRIDE
     env var for CI injection. Per-platform constants marked
     [UNVERIFIED: SKIP] pending live checksums.txt fetch (agent had
     no WebFetch this session — user follow-up: paste from
     https://github.com/rhysd/actionlint/releases/download/v1.7.12/checksums.txt).
  SEC-H2 S3 SSRF/IMDS guard. validate_endpoint() rejects:
     loopback (127/8, ::1, localhost), link-local (169.254/16,
     fe80::/10), metadata hostnames (google/azure). Override via
     KEI_STORE_S3_ALLOW_INTERNAL=1. HTTP rejected unless
     KEI_STORE_S3_ALLOW_INSECURE=1. Custom endpoint now REQUIRES
     explicit creds (no IMDS chain leak via third-party endpoint).
     4 reject + 3 accept tests pass.

POLISH (3):
  D1 docs/USB-BRAIN-GUIDE.md — ⚠️ WARNING block under Prerequisites:
     exFAT/FAT32 NOT safe for multi-client attach (SQLite WAL needs
     shared-mem mmap). Use ONE client at a time on those FSes.
     New Troubleshooting entry 'SQLite corruption on mount-attach'.
  D2 '~5 MB release binary growth' now labelled [estimate, E5 —
     not yet measured] in CHANGELOG.md + s3_cloud/mod.rs header.
  D3 scripts/validate-workflow-shas.sh exits 2 (not 0) when
     UNVERIFIED_COUNT > 0 and GITHUB_TOKEN absent. Distinguishes
     'network denied' from 'all good'.

REAL VERIFICATION (pasted by agent):
  cargo check -p keisei -p kei-store: Finished (clean)
  cargo test -p keisei --release: 30 passed 0 failed
  cargo test -p kei-store --release: 10 + 9 passed (default features)
  cargo test -p kei-store --features s3 --release:
    31 + 9 + 6 = 46 passed (with s3)
  bash -n scripts/*.sh: OK
  regen-counts.sh --check: no drift

Constructor Pattern: largest new src 200 LOC (s3_cloud/mod.rs, at
limit). jsonmcp.rs 107 LOC. test_env.rs 24 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:03:17 +08:00

21 KiB
Raw Blame History

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Entries are generated from the git history via _primitives/_rust/kei-changelog (a conventional-commits walker). Regenerate a single version block with, e.g.:

_primitives/_rust/target/release/kei-changelog \
  --from v0.14.2 --to v0.15.0 --version v0.15.0 --update CHANGELOG.md

Unreleased

Work in flight on feat/v0.16-changelog-gen and follow-up branches. Only placeholders — no corresponding commits exist yet. Any line that ships must be replaced with the real commit summary before release.

Added

  • primitives (v0.21 — keisei SSoT relocation + Scope enum):
    • Marker file relocated from ~/.claude/keisei-attached.toml to ~/.keisei/attached.toml. ~/.claude/ is Claude-Code-specific territory and should not host cross-adapter keisei state. config::read() performs a one-shot migration the first time it runs under v0.21: if the legacy file exists and the new location is empty, the marker moves over (new file written, legacy file deleted) and a stderr notice is emitted.
    • Scope enum (user / project) on the ClientAdapter trait. Adapters declare supported_scopes(); config_path(scope), attach(brain, scope), detach(brain_name, scope) are scope-aware. Claude Code and Cursor support both scopes; Continue and Zed are user-only. keisei attach gains --scope=<user|project> (default user); keisei mount stays host-wide (Scope::User fan-out by design).
    • Marker schema v3: each [[attachments]] entry carries scope = "user" | "project". Pre-v0.21 markers without the field default to Scope::User silently. New error variant Error::ScopeUnsupported { client, scope, supported } fires when a caller asks for a scope the adapter doesn't advertise.
  • primitives (v0.21 — kei-store real S3 backend):
    • S3CloudStore — functional S3 / R2 / MinIO / Wasabi backend via aws-sdk-s3 v1. GetObject / PutObject / ListObjectsV2 (paginated) / DeleteObject wired behind the existing MemoryStore trait (sync-over-async via a single-thread tokio runtime). Enables keisei attach s3://my-bucket/brain/ as a real cloud-mount path, not just a local stub.
    • Opt-in feature flag s3 on the kei-store crate — off by default so users who don't need cloud pay zero binary weight. Enabling adds tokio + hyper + rustls + aws-sdk-s3 (~5 MB release binary growth [estimate, E5 — not yet measured; would require cargo build --release before/after feature flag]).
    • AWS default credential chain honoured (env vars → ~/.aws/credentials → IMDS). No new credential format; RULE 0.8 secrets-single-source unchanged.
    • Endpoint override for non-AWS S3-compat providers via KEI_STORE_S3_ENDPOINT env var (runtime) or s3.endpoint in store-config.toml (persistent). Path-style addressing auto-enabled when a custom endpoint is set (MinIO / some R2 configs).
    • "Branch" semantics: S3 has no native branching, so a branch is modelled as a key prefix (<branch>/<path>). branch() sets the active prefix in-memory; default main.
    • Factory auto-routes: backend = "s3" + feature s3 + s3.bucket set → real cloud; otherwise falls back to the v0.14 local-manifest stub (still behind KEI_STORE_ALLOW_S3_STUB=1).
    • Path-traversal guard parity with FilesystemStore: absolute and ..-component paths rejected before keys are spliced.
  • tests/battle: Docker-based clean-Ubuntu install test — tests/battle/Dockerfile.install-test + verify.sh + battle-entry.sh + README. Builds a fresh ubuntu:24.04 image, runs install.sh --profile=<minimal|core|dev|full> under --yes, then asserts post-install counts (blocks ≥ 79, skills ≥ 39, top hooks ≥ 10, _lib hooks ≥ 2), runs hooks/_lib/test-gate.sh, and validates settings.json. First real-world "does it work on a fresh machine?" signal — CI previously only ran --no-execute dry-runs. v0.21 ship-blocker for any profile that regresses.
  • primitives (v0.20 — brain schema v2 + per-client hint):
    • Brain schema v2 with per-platform mcp_server dispatch — a single brain directory can now host binaries for darwin-arm64/darwin-x64/linux-x64/linux-arm64/windows-x64 and keisei attach picks the right one automatically. Schema v1 (single string) still accepted for backward-compat.
    • ClientAdapter::post_attach_hint() — per-client reload instruction, no more hardcoded Claude-Code string in the orchestrator.
  • primitives: keisei CLI MVP — attach <brain-path> + status subcommands for mounting a portable exobrain directory into Claude Code. First step of the v0.18 exobrain architecture (multi-client adapter surface prepared; only claude-code adapter ships in MVP).
  • primitives (v0.19 — multi-client exobrain):
    • keisei mount <brain-path> — attach a brain to EVERY detected AI client in one shot (Claude Code + Cursor + Continue + Zed).
    • keisei detach — remove the brain from every client recorded in the marker, preserving user's other MCP/context-server entries.
    • keisei list-adapters — tabular dump of every registered adapter and whether it's detected on this host.
    • 3 new ClientAdapter implementations: cursor (.cursor/mcp.json project-local or ~/.cursor/mcp.json global), continue (~/.continue/config.{yaml,json} — YAML preferred, JSON fallback), zed (~/Library/Application Support/Zed/settings.json on macOS or ~/.config/zed/settings.json on Linux, under context_servers).
    • keisei-attached.toml schema v2 — carries a list of [[attachments]] (client_type + config_path) instead of a single client_type. v1 markers read transparently (auto-migrated in memory).
    • New error variants: AdapterFailed { client, reason } and ConfigParseError { path, reason }.
  • Placeholder: CHANGELOG.md generation wired through kei-changelog (this file).
  • Placeholder: .github/workflows/release.yml — tag-driven multi-platform release.
  • Placeholder: pre-built-binary install path in install.sh (KEI_SKIP_RUST_BUILD=1).
  • added: kei-mcp-server single-binary compile for 5 platforms (linux/darwin/windows × x64/arm64 where available) via bun build --compile — v0.18 Phase 1 of the exobrain distribution architecture. Ships as bare binaries + .sha256 sums on every GitHub release; install.sh detects a dropped binary at _primitives/_rust/target/release/kei-mcp-server-<os>-<arch> and skips bun/npm build. Opt-out via KEI_SKIP_MCP_BUILD=1. See _ts_packages/packages/mcp-server/BUILD.md.

Changed

  • Placeholder: plugin / block format refresh targeted for v0.16.0.

Security

  • primitives/keisei (v0.19.2 audit polish — M1): keisei-attached.toml marker is now chmod 0o600 on unix (Windows unchanged — no equivalent bit). The marker carries the resolved brain_path and every attached client's config path; restricting it to owner-only closes the residual "other local user can enumerate attached brains" surface.
  • primitives/keisei (v0.19.2 audit polish — L9): every manifest-sourced string printed by status and attach (brain name, brain path, client/config paths) is now scrubbed through display::sanitize_display, which replaces every ASCII control byte (< 0x20 or == 0x7F) with ?. Closes the escape-sequence injection surface from a malicious brain.name like "evil\x1b[2Jpayload" that would otherwise clear the user's terminal or rewrite already-printed lines.
  • primitives/keisei (v0.19.2 audit polish — L12): manifest.toml is now capped at 64 KiB (Error::ManifestTooLarge { size, max }). The check runs off fs::metadata before read_to_string so an attacker-supplied 1 GB file can't exhaust memory inside the toml parser. Legit manifests are ~1 KB; the cap is three orders of magnitude of headroom.

Fixed

  • Placeholder: hook-bypass edge case follow-up to v0.15.1.
  • primitives/kei-store (v0.21.1 audit wave, HIGH-1): S3CloudStore::commit() now calls a new list_recursive(prefix) helper (ListObjectsV2 without delimiter) so every nested key under the branch — e.g. write("traces/x.jsonl", ...) — contributes to the manifest hash. The previous implementation called list("") which under the hood used delimiter="/" and hid all sub-directory writes from the commit, silently breaking hash-stability. commit() ALSO strips any existing manifest-*.json entries from the input so the hash is stable across repeated commits on unchanged data.
  • primitives/kei-store (v0.21.1 audit wave, HIGH-2): S3Cfg::access_key_env + S3Cfg::secret_key_env are now wired through to the aws-sdk-s3 builder. When both are set, we resolve the named env vars into an explicit Credentials provider and overlay it on the SDK config. Partial configuration (only one of the two set) now returns an error rather than silently ignoring it. Previously both fields were dead — configured users were getting the ambient AWS default chain instead of the named pair.
  • primitives/kei-store (v0.21.1 audit wave, HIGH-5): all tests that mutate process env on KEI_STORE_* vars now take a shared test_env::ENV_LOCK mutex (exposed under cfg(any(test, feature = "s3"))). Prevents cargo-test parallelism from racing multiple tests on the same env state. github.rs dedups onto the shared lock; s3_cloud/tests.rs + tests/s3_smoke.rs now use it.
  • primitives/keisei (v0.21.1 audit wave, HIGH-3): detach.rs + mount.rs now scrub every manifest-sourced string (brain name, brain path, config path, client type, error reason) through display::sanitize_display before println! / eprintln!. status.rs + attach.rs were already compliant; this closes the L9 regression gap for the other two print sites. Two new integration tests (detach_sanitizes_control_chars_in_marker_fields, mount_sanitizes_control_chars_in_error_reason) assert source-level guard presence.
  • primitives/keisei (v0.21.1 audit wave, HIGH-4): extracted adapters/jsonmcp.rs (~107 LOC) as the shared JSON merge/remove/persist helper used by the claude-code, cursor, and zed adapters. All three adapters drop from ~170 LOC to ~105 LOC each and share a uniform error-surfacing contract (Error::ConfigParseError { path } rather than raw serde_json on parse failure). continue_adapter.rs is YAML-based and is unaffected.
  • security (v0.21.1 audit wave, H1): scripts/install-actionlint.sh now verifies SHA-256 of the downloaded tarball before extraction. Per (OS, ARCH) hashes are pinned at the top of the script and documented as the output of checksums.txt on the upstream release page. If a hash is marked SKIP (documented as [UNVERIFIED] pending live fetch), the installer prints a WARNING. Missing shasum / sha256sum is a hard exit 2 — refuses to install an unverified binary. Env override ACTIONLINT_SHA256_OVERRIDE=<hex> lets CI inject the hash at runtime.
  • security (v0.21.1 audit wave, H2): kei-store::s3_cloud::client::validate_endpoint rejects loopback / link-local / metadata hosts (127.0.0.0/8, ::1, 169.254.0.0/16, fe80::/10, metadata.google.internal, etc.) and plain-HTTP URLs by default. Closes the SSRF / IMDS-leak surface where an attacker-controlled KEI_STORE_S3_ENDPOINT pointed at http://169.254.169.254 would cause the AWS default credential chain to sign requests against the instance metadata endpoint and leak IMDS creds. Env overrides: KEI_STORE_S3_ALLOW_INTERNAL=1 (local MinIO / tests), KEI_STORE_S3_ALLOW_INSECURE=1 (plain-HTTP). When a custom endpoint is set, explicit access_key_env + secret_key_env are REQUIRED — the default credential chain is no longer consulted for non-AWS endpoints.
  • docs (v0.21.1 audit wave, D1): docs/USB-BRAIN-GUIDE.md now warns that exFAT / FAT32 are NOT safe for multi-client attach — SQLite WAL shared-memory mmap doesn't work reliably on those filesystems. Recommends APFS / ext4 / NTFS for keisei mount. Troubleshooting entry "SQLite corruption on mount-attach" added with recovery steps.
  • docs (v0.21.1 audit wave, D2): the "~5 MB release binary growth" claim for the s3 feature is now labelled [estimate, E5 — not yet measured] in both CHANGELOG.md and the s3_cloud module doc-comment. Prevents over-claim until a real cargo build --release before/after comparison is landed.
  • scripts (v0.21.1 audit wave, D3): scripts/validate-workflow-shas.sh now exits 2 when UNVERIFIED pins exist AND no GITHUB_TOKEN was provided (rate-limit path). Previously silently returned 0 which masked incomplete verification in CI.
  • primitives/keisei (v0.19 audit hardening): close 3 Security HIGH + 3 Critic HIGH + 2 Critic MEDIUM findings. Path-escape guard on mcp_server + memory/artifacts/manifests (absolute / .. / canonical-mismatch → PathEscape); brain-name regex ^[a-z][a-z0-9_-]{0,63}$ (InvalidName); symlink-rooted brain inputs rejected (BrainIsSymlink — closes USB → $HOME pivot); MCP-entry collision check across all 4 adapters (NameConflict instead of silent clobber); dropped unused rusqlite dep (no C toolchain tail); BrainPaths.{memory,artifacts,manifests} relaxed to Option<String>; $KEISEI_HOME/$HOME resolver deduped into paths.rs SSoT; fsx::write_atomic rewritten on tempfile::NamedTempFile for Windows + cross-fs correctness; 5 adversarial integration tests added (16 total pass).
  • primitives/keisei (v0.19.2 polish): dropped unused ClientAdapter imports from mount.rs + detach.rs; Error::NotAttached and AttachRecord::has_client now carry explicit #[allow(dead_code)] markers documenting that they're reserved for future callers / test-only respectively. cargo check -p keisei is warning-clean; integration suite is 19/19 pass (3 new: marker_file_has_0600_perms_on_unix, status_sanitizes_control_chars_in_brain_name, manifest_too_large_rejected). brain.rs module-level doc-comment now lists the v0.19 invariants (path confinement / symlink reject / name regex / manifest size cap) and flags schema v2 as v0.20.

Security

  • Pinned all GitHub Actions (ci.yml, release.yml) by full commit SHA to defend against CVE-2025-30066-class supply-chain attacks via mutable tag re-pointing.
  • Removed || bun install fallback from release.yml build-mcp-binary job — lockfile is now strictly REQUIRED (H4 audit finding).
  • Added .github/dependabot.yml for weekly SHA update PRs on github-actions, npm, and cargo ecosystems.
  • v0.20.1 — workflow validation defense-in-depth: motivated by the 2026-04-22 incident where dtolnay/rust-toolchain@3c5f7ea... SHA-pinned a specific Rust version (1.94.1 branch tip) instead of "install current stable", breaking CI for 4 jobs. Added three gates against the incident class: scripts/install-actionlint.sh (pinned v1.7.12 installer, macOS-arm64 + linux-x64), scripts/lint-workflows.sh (actionlint runner, advisory if binary missing), scripts/validate-workflow-shas.sh (git-ls-remote every uses: <repo>@<sha40> pin; exits 1 on SHA MISSING, soft-continues on network errors with [UNVERIFIED]), scripts/pre-commit-workflow-lint.sh (symlink-to-install pre-commit hook, fires only when workflow files are staged), and new workflow-lint CI job running the two validators on every push + PR.

0.15.0 — 2026-04-22

Added

  • primitives: kei-artifact typed handoff pipeline (BMAD-style doc passthrough) (3f303b7)
  • blocks: 5 cognitive mode blocks + 2 manifest wirings (fdfc690)

0.14.2 — 2026-04-22

Added

  • hooks: runtime controls via KEI_DISABLED_HOOKS + KEI_HOOK_PROFILE (v0.14.2) (1a448e8)

Removed

  • genesis-scan from public kit (internal tool, Bundle-only) (268226b)

0.14.1 — 2026-04-22

Added

  • ci: GitHub Actions workflows + .claude/worktrees gitignore (407e8b7)

Changed

  • readme + install: reconcile all count drift (F4 RELEASE BLOCKER) (0199fd4)
  • rust: misc schema/main refactor in 8 crates (assorted CP splits) (61448b9)
  • mock-render: split main.rs 227 LOC into 4 cubes (F5a Constructor Pattern) (ad5977d)

Fixed

  • kei-auth: remove --key CLI flag (F12 HIGH — /proc/cmdline leak) (b449587)
  • kei-refactor-engine: retract 'git apply-ready' claim (F1 RELEASE BLOCKER) (f50ef43)
  • kei-store: path-traversal guard (F2 RELEASE BLOCKER) + S3 stub gate (F7) + GitHub RULE 0.1 guard (F8) (ad9c53f)

0.14.0 — 2026-04-22

Added

  • primitives: 10 Rust crates extracted from LBM (Genesis-scrubbed) (a5e6649)
  • ts-packages: 6 TS packages — MCP server + 5 external-API adapters (7b647d5)

Changed

  • rust-core: Constructor-Pattern splits in kei-router + kei-auth (afed921)

0.13.0 — 2026-04-22

Added

  • integration: deep-sleep wired into MANIFEST + sleep-setup Phase 3b + README (bcd80f6)
  • primitives: 4 Rust crates for deep-sleep — conflict-scan, refactor-engine, graph-check, store (0f75493)
  • skills: /onboard auto-project-analyze with 3-mode apply (full-auto / step-by-step / full-manual) (1396139)

Changed

  • readme: "Why Rust, not Python" paragraph in author note (92c918a)
  • readme: clarify "my sample, not claim of originality" in author note (47d2448)
  • readme: add "double sorry" disclaimer in author note (3d5d768)
  • readme: move "From the author" to opening, expand with transformer-error context (fd67315)
  • readme: add "From the author" note (b103c3d)

0.12.0 — 2026-04-22

Added

  • integration: Phase A incubation wired into trigger + install + README (d72de64)
  • skills: /sleep-on-it 6-phase wizard + kei-sleep-queue CRUD + incubation prompt (30df6cb)

0.11.0 — 2026-04-22

Added

  • integration: --with-sleep-sync flag + README Cloud REM sync section (1dd05c6)
  • skills: /sleep-setup 5-phase wizard (click + 1 free-text URL) (b658f81)
  • hooks: session-end-dump calls kei-sleep-sync after ingest (1ab39d5)
  • primitives: kei-sleep-setup wizard + kei-sleep-sync helper + trigger template (4fdaab6)

0.10.0 — 2026-04-22

Added

  • integration: register genesis-scan in MANIFEST core+full + README + install.sh sizing (93ba0a0)
  • hooks: git-pre-commit-genesis — template for repo symlink into .git/hooks/pre-commit (670af3f)
  • primitives: genesis-scan Rust — patent-IP leak detector (CI / pre-commit) (5db8548)
  • integration: wire kei-memory into MANIFEST + settings-snippet + README for v0.10 (0b5da5a)
  • skills: /self-audit 5-phase triage pipeline (334a867)
  • hooks: 3 self-audit triggers — stop / milestone / error-spike (a5c3896)
  • primitives: kei-memory Rust crate — offline session analyzer (Genesis-clean) (448fc07)

0.9.1 — 2026-04-21

Added

  • install: interactive menu (whiptail / dialog / plain) + confirm screen + --yes / --no-execute (4809269)

0.9.0 — 2026-04-21

Added

  • install: modular profiles + --add / --remove / --list incremental install (b1b8de0)
  • primitives: MANIFEST.toml — SSoT for 21 primitives + 6 profiles (764a999)

Changed

  • readme: install profiles table + migration note for v0.9.0 (47931a3)

BREAKING: default install profile is now minimal (was full). Re-run with --profile=full to preserve prior behaviour.

0.8.0 — 2026-04-21

Added

  • install: copy _primitives/ + build Rust workspace; register agent-fork-logger + site-wysiwyd hooks (b0d9389)
  • hooks: site-wysiwyd-check PostToolUse(Edit | Write) drift advisory (c2041b4)
  • skills: /site-create pipeline (phases 04 — phases 56 deferred) (839ae57)

Changed

  • compose-solution: prior-art grep paths + phase-5 cross-refs for 10 pipelines + 21 primitives (f664cbc)
  • readme: v0.8.0 — 73 blocks / 34 skills / 21 primitives / 6 hooks / 11 bridges + pipelines section (ed7d566)