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
41 changes: 39 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,37 @@ jobs:
path: dist/
if-no-files-found: error

- name: Set up Node 22
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
cache: npm
cache-dependency-path: packages/lock-ts/package-lock.json

- name: Test and pack TypeScript verifier
working-directory: packages/lock-ts
run: |
npm ci
npm test
mkdir -p ../../node-dist
npm pack --pack-destination ../../node-dist

- name: Checksum Python and TypeScript release artifacts
run: |
python - <<'PY'
from hashlib import sha256
from pathlib import Path
artifacts = sorted([*Path("dist").glob("*.whl"), *Path("dist").glob("*.tar.gz"), *Path("node-dist").glob("*.tgz")])
Path("node-dist/SHA256SUMS").write_text("".join(f"{sha256(p.read_bytes()).hexdigest()} {p.name}\n" for p in artifacts))
PY

- name: Upload TypeScript and checksum artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: lock-ts
path: node-dist/
if-no-files-found: error

# --------------------------------------------------------------------------
# Job 2: publish to PyPI via OIDC Trusted Publishing.
#
Expand Down Expand Up @@ -190,10 +221,16 @@ jobs:
name: dist
path: dist/

- name: Sign sdist + wheel and attach bundles to the Release
- name: Download TypeScript and checksum artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: lock-ts
path: dist/

- name: Sign release artifacts and attach bundles to the Release
uses: sigstore/gh-action-sigstore-python@790bc6befb9d733738f18d8f895854b453640ec9 # v3.5.0
with:
inputs: ./dist/*.tar.gz ./dist/*.whl
inputs: ./dist/*.tar.gz ./dist/*.whl ./dist/*.tgz ./dist/SHA256SUMS
# Self-check: verify what we just signed against THIS workflow's own
# identity so a broken run never publishes a bad bundle.
verify: true
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ Streamable HTTP; the v0.3 `guard` proxy adds deterministic runtime *result* insp

## [Unreleased]

## [2.0.0] — 2026-10-02

### Breaking compatibility

- CLI 2.0.0 and TypeScript verifier 0.2.0 implement schema level 4. Existing v1–v3
locks remain readable, but operators must review and re-pin before v4 approval.
Historical signatures must not be treated as approval for the expanded surface.
- The GitHub Release ships the npm-installable TypeScript tarball, signed by the
same release identity as the Python artifacts, with SHA-256 checksums.
This is GitHub artifact distribution, not an npm registry publication.

### Fixed — release validation

- Refresh the dev/CI and Action dependency locks from PyJWT 2.13.0 to 2.15.1
Expand Down
4 changes: 2 additions & 2 deletions DOCUMENTATION_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ scope-honesty box and makes no compliance/regulatory claim.
| Doc | Purpose |
|-----|---------|
| [`RELEASING.md`](RELEASING.md) | Operator runbook: one-time PyPI Trusted-Publisher (OIDC) setup, cut-a-release checklist, post-release verification, rollback/yank. PyPI dist name is `mcp-warden-cli`; CLI/repo stay `mcp-warden`. |
| [`CHANGELOG.md`](CHANGELOG.md) | Keep-a-Changelog history (0.3.0 → 1.0.0 → 1.0.1) with explicit in/out-of-scope. |
| [`.github/workflows/release.yml`](.github/workflows/release.yml) | Publish-on-Release workflow: build sdist+wheel → publish to PyPI via OIDC Trusted Publishing (no stored token, **gated on repo var `PYPI_TRUSTED_PUBLISHER=true`** + `skip-existing`, #64) → Sigstore-keyless sign the artifacts and attach bundles to the Release. Live: `mcp-warden-cli` Trusted Publisher configured + the gate variable set. |
| [`CHANGELOG.md`](CHANGELOG.md) | Keep-a-Changelog history through CLI 2.0.0 / schema level 4 with explicit in/out-of-scope. |
| [`.github/workflows/release.yml`](.github/workflows/release.yml) | Publish-on-Release workflow: build Python distributions + tested TypeScript 0.2.0 tarball → publish Python to PyPI via OIDC Trusted Publishing (no stored token, **gated on repo var `PYPI_TRUSTED_PUBLISHER=true`** + `skip-existing`, #64) → Sigstore-keyless sign Python, TypeScript, and checksums and attach bundles to the Release. Live: `mcp-warden-cli` Trusted Publisher configured + the gate variable set. |
| [`requirements-dev.lock`](requirements-dev.lock) · [`.github/workflows/deps-locked.yml`](.github/workflows/deps-locked.yml) | **(#59)** Hash-pinned dev/CI dependency lock + the "Hash-locked dev/CI install" check (verifies `--require-hashes` install + that the lock stays in sync with `pyproject.toml` without floating to latest, #65). Dependency-update policy lives in [`SECURITY.md`](SECURITY.md). |

---
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Last Updated: 2026-10-02
tool/resource/prompt surface into a signed `warden.lock`, then fails CI when that surface
drifts.** `pin` and `check` support stdio and Streamable HTTP; `guard` is stdio-only.

**Schema level 4** also locks complete tool annotations and output schemas. Changing
**CLI 2.0.0 / schema level 4** locks complete tool annotations and output schemas. Changing
destructiveHint, removing a result schema, or widening its types now triggers drift;
the existing runtime tools/list gate checks these fields against v4 locks too.
Older locks stay readable, but require review and re-pinning for this coverage.
Expand Down
11 changes: 11 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,17 @@ Do this on a clean checkout of `main` with all v1 PRs merged.

---

## TypeScript release artifact

The build job also runs the shared TypeScript conformance suite and `npm pack`.
The npm-installable `.tgz` and `SHA256SUMS` are downloaded only by the signing job;
PyPI receives only the Python distribution artifact. The existing release identity
signs and attaches the TypeScript tarball and checksums alongside Python artifacts.
No npm registry token or publisher is configured by this workflow.

Verify the tarball bundle against the same release workflow identity, then install
the exact GitHub asset into a fresh consumer and import `@mcp-warden/lock`.

## 2. Post-release verification

1. **Install from PyPI** (give the CDN a minute):
Expand Down
17 changes: 7 additions & 10 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,16 @@ sharpen those boundaries are still welcome.

## Supported versions

Security fixes are issued for the latest minor series. Older series are not
Security fixes are issued for the latest released series. Older series are not
patched — upgrade to a supported release.

| Version | Supported |
| ------- | ------------------ |
| 0.3.x | :white_check_mark: |
| 0.2.x | :x: |
| 0.1.x | :x: |
| < 0.1 | :x: |
| Version | Supported |
| ------- | --------- |
| 2.0.x | :white_check_mark: |
| 1.x and earlier | :x: |

> Pre-1.0 note: the public surface is still evolving. The supported series will
> advance with each minor release; only the most recent `0.x` minor receives
> security patches.
CLI 2.0.0 implements schema level 4. Historical v1–v3 **lock formats** remain
readable, but review and re-pin are required to approve the newly covered fields.

## Response window

Expand Down
2 changes: 1 addition & 1 deletion SYSTEM_CONTEXT_DIAGRAM.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Last Updated: 2026-10-02

**Schema level 4** extends capture/lock/check to complete tool annotations and output
**CLI 2.0.0 / schema level 4** extends capture/lock/check to complete tool annotations and output
schemas, with structural output drift and Python/TypeScript parity. The existing
tools/list gate compares those commitments for v4 locks; legacy locks retain narrower
runtime coverage and require re-pin for the new fields. Annotations grant no authority.
Expand Down
19 changes: 18 additions & 1 deletion docs-site/lock-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ become a shared standard rather than one project's internal contract.
## What the format is

The MCP Lock Format v1 records the **declared surface** of an MCP server — the
names, descriptions, input schemas, and derived capability flags it advertises
names, descriptions, input schemas, tool annotations, output schemas, and derived capability flags it advertises
over the `initialize` / `tools/list` / `resources/list` / `prompts/list`
handshake — and produces a **reproducible digest** over that surface so that any
later change ("drift") is detectable deterministically.
Expand All @@ -26,6 +26,23 @@ It is defined in normative, implementation-independent terms:
Two tools that implement the format correctly will compute the **same digest over
the same declared surface** — that byte-reproducibility is the conformance bar.

## Schema level 4 — CLI 2.0.0

The current schema hashes complete tool annotations and output schemas. Missing/null
metadata differs from an empty object. Hint changes and output-schema drift invalidate
an approved baseline; annotations never grant authority. The Python and TypeScript
implementations share the same conformance corpus.

Existing v1–v3 locks remain readable, but upgrading requires reviewing the expanded
surface and re-pinning. Historical signatures do not approve newly covered fields.
Keep the previous lock as review evidence, then run your existing `pin --approve`
workflow (and sign the new baseline when signatures are required).

The [2.0.0 release](https://github.com/DataScience-EngineeringExperts/mcp-warden/releases/tag/v2.0.0)
also distributes the npm-installable TypeScript verifier 0.2.0 with checksums and
Sigstore bundles. The broader Warden checkpoints remain a
[design proposal](https://github.com/DataScience-EngineeringExperts/mcp-warden/blob/main/docs/plans/2026-10-02-tool-integrity-upgrade.md).

## Read the full specification

The complete, normative specification is the source of truth and lives in the
Expand Down
11 changes: 6 additions & 5 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ A matching digest means only that the declared surface is byte-identical to the

```jsonc
{
"schema_version": 3, // integer; see §14 — the current format level
"schema_version": 4, // integer; see §14 — the current format level
"warden_version": "x.y.z", // semver of the tool that wrote the file
"server": { ... }, // §6 server identity
"tools": [ { ... } ], // §7 per-entry, sorted by name
Expand Down Expand Up @@ -428,7 +428,7 @@ relaxations of optional result-inspection checks for that one tool:
An implementation is **conformant** with MCP Lock Format v1 if and only if:

1. It writes and reads a `warden.lock` matching the top-level schema (§3), with
`schema_version` naming the format level it implements (currently `3`, §14).
`schema_version` naming the format level it implements (currently `4`, §14).
2. It canonicalizes per RFC 8785 JCS (§4) and hashes per §5, emitting every digest as
`sha256:` followed by 64 lowercase hex characters.
3. Given the **same declared surface**, it produces a **byte-identical** `overall_digest`
Expand Down Expand Up @@ -468,10 +468,11 @@ in the reference — never a reason to edit the vector.

---

## 13. Minimal worked example
## 13. Historical v3 worked example

A minimal lock for a single-tool server (digests abbreviated for readability; a real lock
carries full 64-hex digests):
This historical v3 example illustrates the pre-migration formula. Current v4 entries
also require the §7.1 annotation/output commitments; see the conformance vectors
for complete current documents. Digests below are abbreviated for readability.

```json
{
Expand Down
12 changes: 12 additions & 0 deletions packages/lock-ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ if (!result.ok) {
console.log("surface matches baseline", digest(surface));
```

## Install the released artifact

Version 0.2.0 is distributed with the CLI 2.0.0 GitHub Release:

```bash
npm install https://github.com/DataScience-EngineeringExperts/mcp-warden/releases/download/v2.0.0/mcp-warden-lock-0.2.0.tgz
```

The release includes SHA-256 checksums and a Sigstore bundle for this tarball.
It is an npm-installable artifact, not an npm registry publication. Review the
[release migration notes](https://github.com/DataScience-EngineeringExperts/mcp-warden/releases/tag/v2.0.0) before re-pinning old locks.

## API

| export | purpose |
Expand Down
4 changes: 2 additions & 2 deletions packages/lock-ts/package-lock.json

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

2 changes: 1 addition & 1 deletion packages/lock-ts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mcp-warden/lock",
"version": "0.1.0",
"version": "0.2.0",
"description": "Zero-dependency verifier for MCP Lock Format v1 (warden.lock): RFC 8785 canonicalization, SHA-256 digests, and drift classification.",
"license": "MIT",
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# `mcp-warden` — install `mcp-warden-cli`, then run `mcp-warden ...`. See README
# impostor warning + CHANGELOG.
name = "mcp-warden-cli"
version = "1.2.0"
version = "2.0.0"
description = "CI-first MCP supply-chain integrity gate: pin and verify the declared tool/resource/prompt surface of an MCP server, plus runtime tool-result inspection (guard/inspect)."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion src/mcp_warden/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
on runtime tool behavior or tool results. See ``docs/THREAT_MODEL.md``.
"""

__version__ = "1.2.0"
__version__ = "2.0.0"
#: Lock schema version. Bumped 3 → 4 for annotation/outputSchema commitments
#: (DSE-1539). Missing/null metadata hashes JSON null, not an empty object.
#: Earlier 2 → 3 migration was #29 (in-document ``$ref`` resolution in
Expand Down
Loading