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
2 changes: 1 addition & 1 deletion .github/scripts/verify-release-boundary.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const releasePolicy = await readFile(
);
const workflowSha256 = createHash('sha256').update(workflow).digest('hex');
const expectedWorkflowSha256 =
'9177c8dbf0a75c85e79389f24390c0d83bdad8937a763ca1fa661ac3064f1315';
'7c3e6bfe5e9697fc2122dcc29d39387f2d78a224178471ab530ec04dec8e48de';

const build = job('build-and-verify', 'publish');
const publish = job('publish', 'publish-release');
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- run: npm run check

Expand All @@ -43,6 +45,8 @@ jobs:
with:
node-version: 24
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- name: Verify LF policy and formatting
shell: pwsh
Expand Down
16 changes: 3 additions & 13 deletions .github/workflows/node-sqlite-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,8 @@ jobs:
with:
node-version: 24
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- name: Pack the pinned Diamond source
env:
DIAMOND_COMMIT: 326da7e48d77cddc5a58e21cf65d872ecb9b3b74
run: |
git clone --filter=blob:none https://github.com/gnolith/diamond.git "$RUNNER_TEMP/diamond"
git -C "$RUNNER_TEMP/diamond" checkout --detach "$DIAMOND_COMMIT"
test "$(git -C "$RUNNER_TEMP/diamond" rev-parse HEAD)" = "$DIAMOND_COMMIT"
npm ci --prefix "$RUNNER_TEMP/diamond"
npm pack "$RUNNER_TEMP/diamond" --pack-destination "$RUNNER_TEMP"
- name: Verify packed-artifact node:sqlite parity
env:
DIAMOND_TARBALL: ${{ runner.temp }}/gnolith-diamond-0.4.0.tgz
DIAMOND_TARBALL_SHA256: ac8e34810a8504bd891b36a199973f2d65ef652555644813c7a36f1c7016c9d2
run: node scripts/node-sqlite-parity.mjs
run: npm run parity:node-sqlite
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ jobs:
with:
node-version: 24
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- run: npm run check
- run: npm run release:check -- "${{ github.ref_name }}"
Expand Down
58 changes: 58 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Security

on:
workflow_dispatch:
pull_request:
push:
branches: [main]
schedule:
- cron: '23 8 * * 1'

permissions:
actions: read
contents: read
pull-requests: read
security-events: write

jobs:
dependency-review:
if: github.event_name == 'pull_request' && github.event.repository.private == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0

audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- run: npm run build
- run: npm run security:dev-check

secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Install checksum-pinned GitLeaks CLI
env:
GITLEAKS_VERSION: 8.30.1
GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
run: |
archive="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
curl --fail --location --silent --show-error \
--output "$RUNNER_TEMP/$archive" \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/$archive"
echo "$GITLEAKS_SHA256 $RUNNER_TEMP/$archive" | sha256sum --check -
tar -xzf "$RUNNER_TEMP/$archive" -C "$RUNNER_TEMP" gitleaks
- name: Scan complete Git history for secrets
run: |
"$RUNNER_TEMP/gitleaks" git --config .gitleaks.toml --redact --verbose --no-banner .
38 changes: 4 additions & 34 deletions .github/workflows/taproot-peer-conformance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,8 @@ jobs:
with:
node-version: 24
cache: npm
- name: Materialize checksum-bound local peer artifacts
run: node scripts/materialize-peer-artifacts.mjs
- run: npm ci
- name: Pack the authorization-foundation Taproot source
env:
TAPROOT_COMMIT: 819fe054ebb867e1ca92518bfd3b1aa6c5aa277d
run: |
git clone --filter=blob:none https://github.com/gnolith/taproot.git "$RUNNER_TEMP/taproot"
git -C "$RUNNER_TEMP/taproot" checkout --detach "$TAPROOT_COMMIT"
test "$(git -C "$RUNNER_TEMP/taproot" rev-parse HEAD)" = "$TAPROOT_COMMIT"
npm ci --prefix "$RUNNER_TEMP/taproot"
npm pack "$RUNNER_TEMP/taproot" --pack-destination "$RUNNER_TEMP"
- name: Install exact packed peers
run: |
workshop_version="$(node -p "require('./package.json').version")"
npm pack . --pack-destination "$RUNNER_TEMP"
mkdir "$RUNNER_TEMP/peer-consumer"
cd "$RUNNER_TEMP/peer-consumer"
npm init --yes
npm install --legacy-peer-deps --ignore-scripts --no-audit --no-fund \
"$RUNNER_TEMP/gnolith-taproot-0.4.0.tgz" \
"$RUNNER_TEMP/gnolith-workshop-${workshop_version}.tgz" \
"@gnolith/diamond@0.4.0" \
"miniflare@4.20260714.0"
cp "$GITHUB_WORKSPACE/.github/scripts/taproot-peer-conformance.ts" conformance.ts
cp "$GITHUB_WORKSPACE/.github/scripts/taproot-runtime-conformance.mjs" conformance.mjs
cp "$GITHUB_WORKSPACE/.github/scripts/taproot-d1-runtime-conformance.mjs" conformance-d1.mjs
- name: Verify exact typed boundary between packed peers
run: |
cd "$RUNNER_TEMP/peer-consumer"
node "$GITHUB_WORKSPACE/node_modules/typescript/bin/tsc" \
--noEmit --strict --skipLibCheck --target ES2022 \
--module NodeNext --moduleResolution NodeNext conformance.ts
- name: Verify packed runtime authorization guard
run: node "$RUNNER_TEMP/peer-consumer/conformance.mjs"
- name: Verify packed persisted D1 authorization guard
run: node "$RUNNER_TEMP/peer-consumer/conformance-d1.mjs"
- name: Verify the exact assembled packed process
run: npm run packed:process-check
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules/
dist/
coverage/
.artifacts/
.wrangler/
.release/
*.tgz
Expand Down
11 changes: 11 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
title = "Workshop secret scanning"

[extend]
useDefault = true

[[allowlists]]
description = "Known non-secret item idempotency fixture"
condition = "AND"
regexTarget = "secret"
regexes = ['''^item-subject-v1$''']
paths = ['''(^|/)test/search\.integration\.test\.ts$''']
7 changes: 2 additions & 5 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
node_modules/
dist/
coverage/
.wrangler/
*.tgz
src/generated/**
schemas/*.json
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
# Changelog

## [0.5.0]

- Replaced the UI/Site/Worker package with the `gnolith-workshop` self-hosted
executable, one listener, authenticated MCP and BFF, and explicit offline
bootstrap.
- Generated one 52-operation `gnolith` catalog shared by schemas, MCP, BFF,
validation, and the generic client.
- Added separate local-bearer and remote-OAuth profiles, fail-closed readiness,
verified immutable Waystone assets, bounded lifecycle controls, task leases,
and owner-scoped backup APIs.
- Added a read-only, bounded exact-0.4.2 legacy-owner decoder and owner-bound
adoption adapter with opaque fragments, migration-ledger evidence, digests,
and Task/Memory/Prompt/revision contribution counts.
- Coupled task lease claim, release, and completion atomically to canonical
source/history updates, durable idempotency receipts, and lease audit events.
- Added schema 8 durable credential/bootstrap receipts and an exact Taproot
authorization-bootstrap owner adapter.
- Added schema 11 sealed authorization administration, durable principal,
membership, credential/OAuth, audit, and semantic configuration state.
- Added offline semantic configuration with exact revision/fingerprint
receipts, fail-closed endpoint policy, and truthful degraded/ready status.
- Added public bounded local-filesystem ResourceBlob backup/restore ports with
private content-addressed paths, verified staging, collision checks, rebinds,
rollback, and symlink/traversal defenses.
- Made owner restore collision-safe and repeatable on a fresh current target,
preserving one canonical copy of task idempotency receipts, revisions, and
outcomes while rejecting inconsistent duplicates.
- Distinguished schema-declared authorization administration targets from the
transport-authenticated caller, serialized manual and automatic search
materialization, fenced simultaneous task claims, and rejected encoded
asset traversal before Node URL normalization.
- Defined the exact domain-separated local-bearer credential digest in the
public operation schema, exposed its safe digest helper, hardened
recursively encoded dot-segment rejection, and returned bounded manual
materialization job/result/health evidence.
- Removed legacy operation aliases, UI and CSS exports, Site route factories,
stdio transport, and the parallel hand-written MCP catalog.

All notable changes follow Keep a Changelog and Semantic Versioning.

## [0.4.2] - 2026-07-22
Expand Down
58 changes: 15 additions & 43 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,20 @@
# Compatibility

Workshop 0.4.x targets:
Workshop 0.5 is a breaking reset and requires Diamond and Taproot 0.5 candidate
APIs. It supports Node.js 22 or newer with native SQLite or an injected D1-like
persistence adapter.

- Diamond `>=0.4.0 <0.5.0` through injected SQLite/query services
- Taproot `>=0.4.0 <0.5.0`; this breaking line includes canonical external
Task, Memory, and Prompt producer registration, sealed atomic mutations,
bounded legacy adoption, authorized hydration, durable materialization, and
semantic-search administration.
- Waystone plugin contract `>=0.1.0 <0.3.0`; released Waystone 0.2.x accepts
Workshop's structural plugin shape through its public
`WorkshopCompatibleWaystonePlugin` and `createWaystoneRegistry` boundary.
- React `>=19 <20`
- TypeScript `>=5.9 <6`
- MCP protocol `2025-11-25`, with `2025-06-18` and `2025-03-26` negotiation
- MCP TypeScript SDK `1.29.x` for interoperability verification
- vinext `1.0.0-beta.2` (isolated package-consumer target)
- Cloudflare Workers compatibility date `2026-07-20` or later
- Node.js 22 or 24 for development and release tooling
Removed surfaces: `@gnolith/workshop/ui`, `@gnolith/workshop/site`, CSS exports,
Worker-specific handlers, stdio MCP, and the legacy tool dispatcher. Removed
operation aliases are documented only in
`schemas/legacy-operation-names-v1.json` and are never accepted at runtime.

The exact Workshop tarball compiles in isolated vinext/Vite and Worker
consumers. A separate disposable consumer installs the exact tarball with
public Waystone 0.2.0 and React 19 through normal npm peer resolution, compiles
the public declarations, and registers the Workshop plugin through Waystone's
public compatibility adapter. These fixtures inject or stub Diamond, Taproot,
identity, and host bindings; they verify Workshop package compatibility only
and perform no remote deployment. They do not assemble or qualify a complete
Gnolith Site.
Waystone is optional static content. Workshop serves only a verified immutable
`waystone-assets-v1` manifest and does not import or initialize a Waystone
runtime. The canonical safe mount is `/app`; service and protocol routes remain
reserved.

The generic exact-package declaration consumer also compiles the required
Task/Memory history methods on `WorkshopClient` and their process-core service
signatures, including the shared bounded history options. Its public-version
mode repeats normal npm resolution after publication.

CI also packs released Taproot 0.4.0 source commit
`819fe054ebb867e1ca92518bfd3b1aa6c5aa277d` and checks bidirectional structural
compatibility for authorization contexts and visibility scopes, the real
authorized reader, host-capability-bound guards, and all three Workshop search
producer domains. The packed runtime lane exercises native SQLite and persisted
Miniflare D1, including D1 disposal/recreation and cursor continuation. It also
asserts that raw repository/deep-result surfaces are absent. This
package-to-package lane detects contract drift without provisioning or accepting
a complete Site.

The Codex agent creating a Site owns the compatibility of the complete host
bundle, including its chosen peer entry points, runtime flags, infrastructure,
and deployment configuration. Compatibility range changes still require a
documented Workshop release.
Semantic configuration accepts OpenAI-compatible and Ollama-compatible
providers with SQLite or Qdrant vectors. Ollama remains degraded/unavailable
until a separately supplied immutable model is actually ready; Workshop never
pulls a floating model or invents a model digest.
Loading
Loading