Skip to content
Open
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
22 changes: 14 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:

- name: Configure Git User
run: |
# Redirect global git config to a file in /tmp to avoid polluting the host system
# and ensure we have write permissions regardless of the workspace setup.
touch /tmp/.gitconfig_ci
echo "GIT_CONFIG_GLOBAL=/tmp/.gitconfig_ci" >> $GITHUB_ENV
export GIT_CONFIG_GLOBAL="/tmp/.gitconfig_ci"
git config --global user.email "ci@git-cms.local"
git config --global user.name "CI Bot"
git config --global init.defaultBranch main
Expand All @@ -53,19 +58,20 @@ jobs:
container:
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

# Git is required in the container to perform plumbing operations during E2E tests
# Git is required in the container to perform plumbing operations during E2E tests.
# Installing it BEFORE checkout ensures actions/checkout performs a real clone.
- name: Install Git
run: apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/*

- uses: actions/checkout@v4

- name: Configure Git User
run: |
# Redirect global git config to a file in /tmp to avoid polluting the host system
# and ensure we have write permissions regardless of the workspace setup.
touch /tmp/.gitconfig_ci
echo "GIT_CONFIG_GLOBAL=/tmp/.gitconfig_ci" >> $GITHUB_ENV
export GIT_CONFIG_GLOBAL="/tmp/.gitconfig_ci"
git config --global user.email "ci@git-cms.local"
git config --global user.name "CI Bot"
git config --global init.defaultBranch main
Expand Down
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@

All notable changes to git-cms are documented in this file.

## [1.1.5] — 2026-02-14

### Fixed

- **(Security) Git identity leakage:** Removed `git config --global` from host-level modification in CI workflow (`.github/workflows/ci.yml`). Scripts now use an isolated global config file via `GIT_CONFIG_GLOBAL` redirected to `/tmp`, preventing accidental modification of host global settings if workflows are executed locally (e.g., via `act`).
- `QUICK_REFERENCE.md`: `revert` command description corrected — sets state to `reverted`, not `draft`
- `QUICK_REFERENCE.md`: state machine diagram refined to accurately show `draft`→`reverted` transition
- `QUICK_REFERENCE.md`: HTTP API table uses canonical `optional` notation and clarifies optimistic concurrency for `publish`
- `docs/GETTING_STARTED.md`: migration walkthrough refined (separated idempotency/dry-run, clarified no-op behavior)
- `check-doc-drift.sh`: recursive search for deleted files and root-level documentation links
- `check-doc-drift.sh`: improved regex for CLI and API matching to prevent substring false positives and support underscores/digits
- `QUICK_REFERENCE.md`: state derivation rule clarified — "draft ref only" requires no `Status` trailer or `Status: draft`
- `QUICK_REFERENCE.md`: `<40-hex>` replaced with `<oid>` for hash-format-agnostic docs
- `docs/GETTING_STARTED.md`: migration walkthrough clarifies no-dry-run vs idempotency
- `check-doc-drift.sh`: API endpoint matching uses backtick-delimited grep (prevents substring false positives)
- `check-doc-drift.sh`: deleted-file search recurses into docs subdirectories
- `check-doc-drift.sh`: root GS links regex handles `../` relative path prefixes

## [1.1.4] — 2026-02-14

### Changed

- Consolidate and update documentation for M1.1, M1.2, M1.3, CE2, and CE3
- `QUICK_REFERENCE.md` is now the canonical reference for all 9 CLI commands, 10 HTTP API endpoints, and state machine
- `docs/GETTING_STARTED.md` updated with version history, migration, unpublish/revert workflows
- `README.md` updated with missing CLI commands and choose-your-path navigation
- `ROADMAP.md` milestone statuses updated (M1.1, M1.2, M1.3, CE2, CE3 → complete)
- Root `GETTING_STARTED.md` and `REPO_WALKTHROUGH.md` replaced with redirect stubs
- `docs/ADR.md` file tree updated (removed `REPO_WALKTHROUGH.md`, added `CONTENT_ID_POLICY.md` and `LAYOUT_SPEC.md`)

### Added

- `scripts/check-doc-drift.sh` — automated doc drift detection (CLI commands, HTTP endpoints, stale references)
- `npm run check:docs` script

### Fixed

- Doc freshness banners now reference v1.1.4 (was v1.1.3)
- `check-doc-drift.sh`: CLI/API regex broadened to `[a-z0-9_-]+` for future-proofing
- `check-doc-drift.sh`: CLI command matching uses backtick-delimited grep to prevent substring false positives
- `check-doc-drift.sh`: `root_gs_links` check was computed but never evaluated (dead code)

## [1.1.3] — 2026-02-14

### Fixed
Expand Down Expand Up @@ -102,6 +144,7 @@ All notable changes to git-cms are documented in this file.
- **(P2) walkLimit divergence:** Extracted `HISTORY_WALK_LIMIT` as a shared exported constant used by both `_validateAncestry` and the server's history limit clamp

[Unreleased]: https://github.com/flyingrobots/git-cms/compare/main...git-stunts
[1.1.4]: https://github.com/flyingrobots/git-cms/compare/v1.1.3...v1.1.4
[1.1.3]: https://github.com/flyingrobots/git-cms/compare/v1.1.2...v1.1.3
[1.1.2]: https://github.com/flyingrobots/git-cms/compare/v1.1.1...v1.1.2
[1.1.1]: https://github.com/flyingrobots/git-cms/compare/v1.1.0...v1.1.1
Expand Down
74 changes: 2 additions & 72 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,3 @@
# Getting Started with Git CMS
# Getting Started

This quick guide is the lightweight entry point. For the full Docker-focused walkthrough in the docs folder, see [`docs/GETTING_STARTED.md`](docs/GETTING_STARTED.md).

---

## Prerequisites

- Git
- Node.js 22+
- Docker Desktop (recommended for safe testing)

---

## Installation

### Option A: Local CLI Install

```bash
git clone https://github.com/flyingrobots/git-cms.git
cd git-cms
npm install
npm link
```

### Option B: Docker (Recommended)

```bash
git clone https://github.com/flyingrobots/git-cms.git
cd git-cms
npm run setup
npm run dev
```

Open the UI at [http://localhost:4638/](http://localhost:4638/).

---

## First Article

1. Click `+ New Article`.
2. Set a slug like `my-first-post`.
3. Add title + body content.
4. Click `Save Draft`.
5. Click `Publish` when ready.

---

## CLI Basics

```bash
# Draft reads content from stdin
echo "# Hello" | git cms draft hello-world "Hello World"

# List drafts
git cms list

# Publish
git cms publish hello-world

# Show article
git cms show hello-world
```

---

## Safety Notes

- Prefer Docker workflows while learning.
- Use a dedicated test repository for local CLI experimentation.
- Avoid running low-level Git plumbing in repositories you care about.

See [`TESTING_GUIDE.md`](TESTING_GUIDE.md) for safety and cleanup procedures.
This guide has moved to [`docs/GETTING_STARTED.md`](docs/GETTING_STARTED.md).
157 changes: 135 additions & 22 deletions QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Git CMS Quick Reference

One-page cheat sheet for Git CMS commands and concepts.
> Validated against v1.1.5 on 2026-02-14.

One-page cheat sheet for Git CMS commands, API endpoints, and concepts.

---

Expand All @@ -27,10 +29,25 @@ npm run demo # Watch a guided walkthrough
| `npm test` | Run integration tests in Docker |
| `npm run test:setup` | Run setup-script tests (BATS) |
| `npm run test:local` | Run Vitest directly on host (advanced) |
| `npm run check:docs` | Check documentation drift against source code |

---

## CLI Commands (Inside Container)
## CLI Commands

All 9 commands available via `node bin/git-cms.js <command>` or `git cms <command>` (if linked):

| Command | Usage | Description |
|---------|-------|-------------|
| `draft` | `echo "body" \| git cms draft <slug> "Title"` | Create or update a draft (reads body from stdin) |
| `publish` | `git cms publish <slug>` | Fast-forward published ref to match draft |
| `unpublish` | `git cms unpublish <slug>` | Remove from published, keep as unpublished draft |
| `revert` | `git cms revert <slug>` | Move article to 'reverted' state (creates new draft commit with `Status: reverted` trailer) |
| `list` | `git cms list` | List all draft articles |
| `show` | `git cms show <slug>` | Print article title and body |
| `serve` | `git cms serve` | Start HTTP API + Admin UI on port 4638 |
| `migrate` | `git cms migrate` | Run pending layout migrations (forward-only, idempotent) |
| `layout-version` | `git cms layout-version` | Print repo and codebase layout versions |

```bash
# Enter container
Expand All @@ -45,12 +62,24 @@ node bin/git-cms.js list
# Publish a draft
node bin/git-cms.js publish my-slug

# Unpublish
node bin/git-cms.js unpublish my-slug

# Revert to 'reverted' state
node bin/git-cms.js revert my-slug

# Read article content
node bin/git-cms.js show my-slug

# Start HTTP API + Admin UI
node bin/git-cms.js serve

# Check layout version
node bin/git-cms.js layout-version

# Run pending migrations
node bin/git-cms.js migrate

# Exit container
exit
```
Expand All @@ -59,6 +88,63 @@ exit

---

## HTTP API

All endpoints are served by `git cms serve` (default port 4638). Slugs are NFKC-normalized on the server.

| Method | Path | Params / Body | Description |
|--------|------|---------------|-------------|
| `GET` | `/api/cms/list` | `?kind=articles\|published` | List articles by kind |
| `GET` | `/api/cms/show` | `?slug=xxx&kind=articles` | Read article content |
| `POST` | `/api/cms/snapshot` | `{ slug, title, body, trailers (optional) }` | Create or update a draft |
| `POST` | `/api/cms/publish` | `{ slug, sha (optional) }` | Publish a draft (omitting `sha` uses optimistic concurrency) |
| `POST` | `/api/cms/unpublish` | `{ slug }` | Unpublish an article |
| `POST` | `/api/cms/revert` | `{ slug }` | Revert to draft state |
| `GET` | `/api/cms/history` | `?slug=xxx&limit=50` | List version history (max 200) |
| `GET` | `/api/cms/show-version` | `?slug=xxx&sha=<oid>` | Read a specific historical version |
| `POST` | `/api/cms/restore` | `{ slug, sha }` | Restore a historical version as new draft |
| `POST` | `/api/cms/upload` | `{ slug, filename, data }` | Upload base64-encoded asset (encrypted) |

---

## State Machine

Articles move through four states. Transitions are enforced by `ContentStatePolicy.js`.

```text
States: draft, published, unpublished, reverted

revert
┌──────────┐ ─────────────────► ┌──────────┐
┌───►│ draft │ │ reverted │
│ └────┬──────┘ ◄──────────────── └──────────┘
│ │ publish save
│ ▼
│ ┌──────────┐ unpublish ┌─────────────┐
│ │ published │───────────────►│ unpublished │
│ └────┬──────┘ └──┬────────┬──┘
│ │ publish (update) │ │
│ └──────────┐ publish │ │
│ ▼ │ │ │
│ ┌──────────┐│ │ │
│ │ published │◄──────┘ │
│ └──────────┘ │
│ save │
└────────────────────────────────────────────┘
```

**Effective state** is derived from which refs exist:
- Draft ref only (no `Status` trailer, or `Status: draft`) → `draft`
- Both draft + published refs → `published`
- Draft ref with `Status: unpublished` trailer → `unpublished`
- Draft ref with `Status: reverted` trailer → `reverted`

**Restoring a version creates a new commit — git-cms never rewrites history.**

See [`docs/LAYOUT_SPEC.md`](docs/LAYOUT_SPEC.md) for the full ref namespace and state derivation rules.

---

## Core Concept

### Traditional CMS
Expand Down Expand Up @@ -89,6 +175,22 @@ The trick: content lives in commit messages while commits point at the repo's em

---

## Architecture (Lego Blocks)

```text
git-cms
-> CmsService (orchestrator)
-> @git-stunts/plumbing (Git execution)
-> @git-stunts/trailer-codec (trailer encode/decode)
-> @git-stunts/git-warp (commit graph primitives)
-> @git-stunts/git-cas (asset chunk + manifest storage)
-> @git-stunts/vault (secret/key resolution)
```

This replaced older in-repo helpers (`src/lib/git.js`, `src/lib/parse.js`, `src/lib/chunks.js`, `src/lib/secrets.js`).

---

## Inspecting with Git

```bash
Expand All @@ -107,20 +209,6 @@ git hash-object -t tree /dev/null

---

## Architecture (Lego Blocks)

```text
git-cms
-> CmsService (orchestrator)
-> @git-stunts/plumbing (Git execution)
-> @git-stunts/trailer-codec (trailer encode/decode)
-> @git-stunts/git-warp (commit graph primitives)
-> @git-stunts/git-cas (asset chunk + manifest storage)
-> @git-stunts/vault (secret/key resolution)
```

---

## Commit Message Shape

```text
Expand All @@ -139,6 +227,19 @@ Trailers are parsed by `@git-stunts/trailer-codec`.

---

## Testing Surface

| Test File | Coverage |
|-----------|----------|
| `test/git.test.js` | Integration tests — CRUD, publish, unpublish, revert, state machine, content identity |
| `test/chunks.test.js` | Asset encryption and chunking |
| `test/server.test.js` | HTTP API endpoints, validation, error responses |
| `test/git-e2e.test.js` | Real-git smoke tests (subprocess forks) |
| `test/setup.bats` | Setup script tests (BATS) |
| `test/run-docker.sh` | Docker test harness |

---

## Troubleshooting

### Cannot find module `@git-stunts/...`
Expand Down Expand Up @@ -166,9 +267,21 @@ Start Docker Desktop (macOS/Windows) or start Docker service on Linux.

## Docs Map

- `README.md`: overview + quick start
- `TESTING_GUIDE.md`: safe test workflow
- `docs/GETTING_STARTED.md`: full walkthrough
- `docs/ADR.md`: architecture decision record
- `scripts/README.md`: helper script docs
- `test/README.md`: test suite docs
| File | Contents |
|------|----------|
| [`README.md`](README.md) | Overview + quick start |
| [`TESTING_GUIDE.md`](TESTING_GUIDE.md) | Safe test workflow |
| [`QUICK_REFERENCE.md`](QUICK_REFERENCE.md) | This file — canonical CLI/API/state machine reference |
| [`ROADMAP.md`](ROADMAP.md) | M0–M6 milestone plan |
| [`docs/GETTING_STARTED.md`](docs/GETTING_STARTED.md) | Full onboarding walkthrough |
| [`docs/ADR.md`](docs/ADR.md) | Architecture decision record |
| [`docs/CONTENT_ID_POLICY.md`](docs/CONTENT_ID_POLICY.md) | Slug validation and content identity rules |
| [`docs/LAYOUT_SPEC.md`](docs/LAYOUT_SPEC.md) | Ref namespace, layout versions, migration policy |
| [`scripts/README.md`](scripts/README.md) | Helper script docs |
| [`test/README.md`](test/README.md) | Test suite docs |

**Removed docs** (redirect stubs remain for one release cycle):
- `GETTING_STARTED.md` (root) — moved to `docs/GETTING_STARTED.md`
- `REPO_WALKTHROUGH.md` — consolidated into this file

**Repository:** [https://github.com/flyingrobots/git-cms](https://github.com/flyingrobots/git-cms)
Loading