Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @git-stunts
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [5.3.2] — Unreleased
## [5.3.3] — Unreleased

### Added
- **Review automation baseline** — added `.github/CODEOWNERS` with repo-wide ownership for `@git-stunts`.
- **Release runbook** — added `docs/RELEASE.md` and linked it from `CONTRIBUTING.md` as the canonical patch-release workflow.
- **`pnpm release:verify`** — new maintainer-facing release helper runs the full release checklist, captures observed test counts, and prints a Markdown summary that can be pasted into release notes or changelog prep.
- **Deterministic property-based envelope coverage** — added a `fast-check`-backed property suite for envelope-encrypted store/restore round-trips and tamper rejection across empty, boundary-adjacent, and multi-chunk payload sizes.

### Changed
- **GitHub Actions runtime maintenance** — CI and release workflows now run on `actions/checkout@v6` and `actions/setup-node@v6`, clearing the Node 20 deprecation warnings from GitHub-hosted runners.
- **Ubuntu-based Docker test stages** — the local/CI Node, Bun, and Deno test images now build on `ubuntu:24.04`, copying runtime binaries from the official upstream images instead of inheriting Debian-based runtime images directly, and the final test commands now run as an unprivileged `gitstunts` user.
- **Test conventions expanded** — `test/CONVENTIONS.md` now documents Git tree filename ordering, Docker-only integration policy, pinned integration `fileParallelism: false`, and direct-argv subprocess helpers.

### Fixed
- **Bun blob writes in Git persistence** — `GitPersistenceAdapter.writeBlob()` now hashes temp files instead of piping large buffers through `git hash-object --stdin` under Bun, avoiding unhandled `EPIPE` failures during real Git-backed stores.
- **Release verification runner failures** — `runReleaseVerify()` now converts thrown step-runner errors into structured step failures with a `ReleaseVerifyError` summary instead of letting raw exceptions escape.

## [5.3.2] — 2026-03-15

### Changed
- **Vitest workspace split** — unit, integration, and benchmark suites now live in explicit workspace projects so the integration suite always runs with `fileParallelism: false`, regardless of the exact CLI invocation shape.
Expand Down
10 changes: 8 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,18 @@
2. **Install Git Hooks**: Run `bash scripts/install-hooks.sh` to set up local quality gates. This will ensure that linting and unit tests pass before every push.
3. **Run Tests Locally**:
- `pnpm test` for unit tests.
- `pnpm run test:integration` for integration tests (requires Docker).
- `pnpm run test:integration:node` for Node integration tests (requires Docker).
- `pnpm run test:integration:bun` for Bun integration tests.
- `pnpm run test:integration:deno` for Deno integration tests.
4. **Prepare Releases**:
- `pnpm release:verify` for the full release checklist and release-note summary output.
- Follow [docs/RELEASE.md](./docs/RELEASE.md) for the canonical patch-release flow.

## Quality Gates
We enforce high standards for code quality:
- **Linting**: Must pass `pnpm run lint`.
- **Unit Tests**: All unit tests must pass.
- **Integration Tests**: Must pass across Node, Bun, and Deno runtimes.
- **Release Prep**: `pnpm release:verify` must pass before a tag is created.

These gates are enforced both locally via git hooks and in CI/CD.
These gates are enforced both locally via git hooks and in CI/CD.
44 changes: 33 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,54 @@
FROM ubuntu:24.04 AS ubuntu-base
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates git \
&& groupadd --system gitstunts \
&& useradd --system --gid gitstunts --create-home --shell /usr/sbin/nologin gitstunts \
&& rm -rf /var/lib/apt/lists/*

FROM node:22 AS node-runtime
FROM oven/bun:1 AS bun-runtime
FROM denoland/deno:ubuntu-2.7.1 AS deno-runtime

# --- Node ---
FROM node:22-slim AS node
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
RUN corepack enable && corepack prepare pnpm@10 --activate
FROM ubuntu-base AS node
COPY --from=node-runtime /usr/local/ /usr/local/
RUN npm install -g pnpm@10
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN chown -R gitstunts:gitstunts /app
ENV GIT_STUNTS_DOCKER=1
ENV HOME=/home/gitstunts
USER gitstunts
CMD ["pnpm", "vitest", "run", "test/unit"]

# --- Bun ---
FROM oven/bun:1-slim AS bun
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
FROM ubuntu-base AS bun
COPY --from=bun-runtime /usr/local/bin/bun /usr/local/bin/bun
COPY --from=bun-runtime /usr/local/bin/bunx /usr/local/bin/bunx
WORKDIR /app
COPY package.json bun.lock* ./
COPY package.json ./
RUN bun install
COPY . .
RUN chown -R gitstunts:gitstunts /app
ENV GIT_STUNTS_DOCKER=1
ENV HOME=/home/gitstunts
USER gitstunts
CMD ["bunx", "vitest", "run", "test/unit"]

# --- Deno ---
FROM denoland/deno:2.7.1 AS deno
USER root
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
FROM ubuntu-base AS deno
COPY --from=deno-runtime /usr/bin/deno /usr/local/bin/deno
COPY --from=node-runtime /usr/local/bin/node /usr/local/bin/node
WORKDIR /app
COPY package.json deno.lock* ./
COPY package.json ./
RUN deno install --allow-scripts || true
COPY . .
RUN deno install --allow-scripts
RUN chown -R gitstunts:gitstunts /app
ENV GIT_STUNTS_DOCKER=1
CMD ["deno", "run", "-A", "npm:vitest", "run", "test/unit"]
ENV HOME=/home/gitstunts
USER gitstunts
CMD ["deno", "run", "-A", "npm:vitest", "run", "test/unit"]
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ We use the object database.

<img src="./docs/demo.gif" alt="git-cas demo" />

## What's new in v5.3.2

**Patch release — runtime/test stabilization.**

- **Explicit Vitest workspace projects** — unit, integration, and benchmark suites now run as named workspace projects, with the integration suite always pinned to `fileParallelism: false`.
- **Deterministic cross-runtime integration behavior** — Bun and Deno no longer depend on Vitest CLI argv shape to avoid subprocess `EPIPE` races.
- **CLI version sync** — `git-cas --version` now reads package metadata instead of a stale literal, so the binary reports the correct in-repo release line.

See [CHANGELOG.md](./CHANGELOG.md) for the full list of changes.

## What's new in v5.3.1

**Patch release — repeated chunk tree fix.**
Expand Down
11 changes: 6 additions & 5 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ lives in [GRAVEYARD.md](./GRAVEYARD.md).

## Current Reality

- **Current release:** `v5.3.1` (2026-03-15)
- **Current line:** M16 Capstone shipped in `v5.3.0`; `v5.3.1` is the maintenance follow-up that fixed repeated-chunk tree emission for repetitive content.
- **Current release:** `v5.3.2` (2026-03-15)
- **Current line:** M16 Capstone shipped in `v5.3.0`; `v5.3.1` fixed repeated-chunk tree emission for repetitive content; `v5.3.2` stabilized test/runtime tooling; `v5.3.3` is the remaining M17 Ledger closeout in flight.
- **Supported runtimes:** Node.js 22.x (primary), Bun, Deno
- **Current operator experience:** the human-facing CLI/TUI is shipped now; the machine-facing agent CLI is planned next.

Expand Down Expand Up @@ -55,14 +55,15 @@ The agent CLI is a first-class workflow, not an extension of the human `--json`
| v5.2.0 | M12 | Carousel | Key rotation without re-encrypting data | ✅ Shipped |
| v5.3.0 | M16 | Capstone | Audit remediation and security hardening | ✅ Shipped |
| v5.3.1 | — | Maintenance | Repeated-chunk tree integrity fix | ✅ Shipped |
| v5.3.2 | — | Maintenance | Vitest workspace split, CLI version sync, and runtime/tooling stabilization | ✅ Shipped |

Older history remains in [CHANGELOG.md](./CHANGELOG.md).

## Planned Release Sequence

| Version | Milestone | Codename | Theme | Status |
|---------|-----------|----------|-------|--------|
| v5.3.2 | M17 | Ledger | Planning and ops reset | 📝 Planned |
| v5.3.3 | M17 | Ledger | Planning and ops reset | 📝 Planned |
| v5.4.0 | M18 | Relay | LLM-native CLI foundation | 📝 Planned |
| v5.5.0 | M19 | Nouveau | Bijou v3 human UX refresh | 📝 Planned |
| v5.6.0 | M20 | Sentinel | Vault health and safety | 📝 Planned |
Expand All @@ -75,7 +76,7 @@ Older history remains in [CHANGELOG.md](./CHANGELOG.md).
## Dependency Sequence

```text
M16 Capstone + v5.3.1 maintenance ✅
M16 Capstone + v5.3.1/v5.3.2 maintenance ✅
|
M17 Ledger
|
Expand All @@ -101,7 +102,7 @@ interface split, then the human TUI refresh, and only then the broader feature e

## Open Milestones

### M17 — Ledger (`v5.3.2`)
### M17 — Ledger (`v5.3.3`)

**Theme:** planning and operational reset after Capstone.

Expand Down
11 changes: 6 additions & 5 deletions STATUS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# @git-stunts/cas — Project Status

**Current release:** `v5.3.1`
**Current branch version:** `v5.3.2`
**Current release:** `v5.3.2`
**Current branch version:** `v5.3.3`
**Last release:** `2026-03-15`
**Current line:** M16 Capstone shipped in `v5.3.0`; `v5.3.1` fixed repeated-chunk tree emission; `v5.3.2` is the next maintenance/doc/test follow-up in flight.
**Current line:** M16 Capstone shipped in `v5.3.0`; `v5.3.1` fixed repeated-chunk tree emission; `v5.3.2` stabilized test/runtime tooling; `v5.3.3` is the remaining M17 closeout in flight.
**Runtimes:** Node.js 22.x, Bun, Deno

---
Expand All @@ -19,6 +19,7 @@

| Version | Milestone | Highlights |
|---------|-----------|------------|
| `v5.3.2` | Maintenance | Vitest workspace split for deterministic integration runs; CLI version sync; test/runtime tooling stabilization |
| `v5.3.1` | Maintenance | Repeated-chunk tree integrity fix; unique chunk tree entries; `git fsck` regression coverage |
| `v5.3.0` | M16 Capstone | Audit remediation, `.casrc`, passphrase-file support, restore guards, `encryptionCount`, lifecycle rename |
| `v5.2.0` | M12 Carousel | Key rotation without re-encrypting data |
Expand All @@ -34,7 +35,7 @@ Milestone labels are thematic and non-sequential; the versions above are listed

## Next Up

### M17 — Ledger (`v5.3.2`)
### M17 — Ledger (`v5.3.3`)

Planning and ops reset:

Expand Down Expand Up @@ -69,7 +70,7 @@ Human UX refresh:

| Version | Milestone | Theme |
|---------|-----------|-------|
| `v5.3.2` | M17 Ledger | Planning and ops reset |
| `v5.3.3` | M17 Ledger | Planning and ops reset |
| `v5.4.0` | M18 Relay | LLM-native CLI foundation |
| `v5.5.0` | M19 Nouveau | Bijou v3 human UX refresh |
| `v5.6.0` | M20 Sentinel | Vault health and safety |
Expand Down
8 changes: 3 additions & 5 deletions bin/git-cas.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { program, Option } from 'commander';
import GitPlumbing, { ShellRunnerFactory } from '@git-stunts/plumbing';
import ContentAddressableStore, { EventEmitterObserver, CborCodec } from '../index.js';
import Manifest from '../src/domain/value-objects/Manifest.js';
import { createGitPlumbing } from '../src/infrastructure/createGitPlumbing.js';
import { createStoreProgress, createRestoreProgress } from './ui/progress.js';
import { renderEncryptionCard } from './ui/encryption-card.js';
import { renderHistoryTimeline } from './ui/history-timeline.js';
Expand Down Expand Up @@ -55,8 +55,7 @@ function readKeyFile(keyFilePath) {
* @returns {ContentAddressableStore}
*/
function createCas(cwd, opts = {}) {
const runner = ShellRunnerFactory.create();
const plumbing = new GitPlumbing({ runner, cwd });
const plumbing = createGitPlumbing({ cwd });
/** @type {Record<string, any>} */
const casOpts = { plumbing, ...opts };
if (casOpts.codec === 'cbor') {
Expand Down Expand Up @@ -530,8 +529,7 @@ vault
.option('-n, --max-count <n>', 'Limit number of commits')
.option('--pretty', 'Render as color-coded timeline')
.action(runAction(async (/** @type {Record<string, any>} */ opts) => {
const runner = ShellRunnerFactory.create();
const plumbing = new GitPlumbing({ runner, cwd: opts.cwd || '.' });
const plumbing = createGitPlumbing({ cwd: opts.cwd || '.' });
const args = ['log', '--oneline', ContentAddressableStore.VAULT_REF];
if (opts.maxCount) {
const n = parseInt(opts.maxCount, 10);
Expand Down
46 changes: 46 additions & 0 deletions docs/RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Release Workflow

This document defines the canonical patch-release flow for `git-cas`.

## Patch Release Flow

1. Branch from `main`.
2. Bump the in-flight version in `package.json` and `jsr.json`.
3. Add a new unreleased section to `CHANGELOG.md`.
4. Run `pnpm release:verify`.
5. Open a pull request and wait for review.
6. Merge to `main`.
7. Sync local `main` to `origin/main`.
8. Run `pnpm release:verify` again on `main`.
9. Finalize release-facing docs:
- mark the changelog entry released
- update the lead README “What’s new” section
- update `STATUS.md` and `ROADMAP.md`
10. Create and push the tag (`vX.Y.Z`).

## Release Verification

`pnpm release:verify` is the maintainer-facing verification entrypoint for
release prep. It runs the repository release gates in order and prints a
Markdown summary that can be pasted into release notes or changelog prep.

Current release verification includes:

- `pnpm run lint`
- `pnpm test`
- `docker compose run --build --rm test-bun bunx vitest run test/unit`
- `docker compose run --build --rm test-deno deno run -A npm:vitest run test/unit`
- `pnpm run test:integration:node`
- `pnpm run test:integration:bun`
- `pnpm run test:integration:deno`
- `npm pack --dry-run`
- `npx jsr publish --dry-run --allow-dirty`

The helper is intentionally read-only with respect to release notes. It does
not edit `CHANGELOG.md`; it only prints a summary block for maintainers.

## Release Notes Discipline

- Treat release tags as immutable.
- Do not tag until the merged `main` branch passes release verification.
- If any runtime fails, fix the underlying problem before tagging.
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@git-stunts/git-cas",
"version": "5.3.2",
"version": "5.3.3",
"exports": {
".": "./index.js",
"./service": "./src/domain/services/CasService.js",
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@git-stunts/git-cas",
"version": "5.3.2",
"version": "5.3.3",
"description": "Content-addressed storage backed by Git's object database, with optional encryption and pluggable codecs",
"type": "module",
"main": "index.js",
Expand Down Expand Up @@ -62,6 +62,7 @@
"test:platforms": "bats --jobs 3 test/platform/runtimes.bats",
"benchmark": "vitest bench test/benchmark",
"benchmark:local": "vitest bench test/benchmark",
"release:verify": "node scripts/release/verify.js",
"lint": "eslint .",
"format": "prettier --write ."
},
Expand All @@ -85,6 +86,7 @@
"@eslint/js": "^9.17.0",
"@types/node": "^25.3.2",
"eslint": "^9.17.0",
"fast-check": "^4.6.0",
"jsr": "^0.14.2",
"prettier": "^3.4.2",
"vitest": "^2.1.8"
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading