diff --git a/.specsmith/requirements.json b/.specsmith/requirements.json index 41b2b814..841503d7 100644 --- a/.specsmith/requirements.json +++ b/.specsmith/requirements.json @@ -3560,12 +3560,13 @@ "id": "REQ-366", "version": 1, "title": "Activating the chronomemory ChronoStore ESDB backend requires a valid commercial license key", - "description": "When chronomemory is installed, specsmith must verify the presence and cryptographic validity of an Ed25519-signed license file before activating ChronoStore (ChronoMemory backend engine). The license file location is resolved from SPECSMITH_ESDB_KEY environment variable or ~/.specsmith/esdb.key. If the key is absent or invalid the backend silently falls back to SqliteStore with a one-time warning. The SPECSMITH_ESDB_BACKEND=sqlite environment variable force-selects SQLite regardless of key presence.", + "description": "When chronomemory is installed, specsmith must verify the presence and cryptographic validity of an Ed25519-signed license file before activating ChronoStore (ChronoMemory backend engine). The license file location is resolved from SPECSMITH_ESDB_KEY environment variable or ~/.specsmith/esdb.key. If the key is absent or invalid the backend silently falls back to SqliteStore with a one-time warning. The SPECSMITH_ESDB_BACKEND=sqlite environment variable force-selects SQLite regardless of key presence. The base specsmith package must include the cryptography verifier required by `specsmith esdb enable`, so clean pip and pipx installations can activate a valid license without a separate dependency injection.", "source": "commercial licensing model", "status": "accepted", "test_ids": [ "TEST-367", - "TEST-372" + "TEST-372", + "TEST-472" ] }, { diff --git a/.specsmith/testcases.json b/.specsmith/testcases.json index 1f552489..09ca252e 100644 --- a/.specsmith/testcases.json +++ b/.specsmith/testcases.json @@ -5110,5 +5110,17 @@ "input": {}, "expected_behavior": {}, "confidence": 1.0 + }, + { + "id": "TEST-472", + "version": 1, + "title": "Base package metadata includes cryptography for ESDB license activation", + "description": "Verify pyproject.toml lists cryptography in base project dependencies, so a clean pipx install can execute specsmith esdb enable without a manual pipx inject.", + "requirement_id": "REQ-366", + "type": "unit", + "verification_method": "pytest tests/test_esdb_license.py::test_base_install_includes_cryptography_for_license_verification", + "input": {}, + "expected_behavior": {}, + "confidence": 1.0 } ] \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f6b12fd3..1d290023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ consolidated into the next published release. ## [Unreleased] +## [0.22.1] - 2026-07-13 +### Fixed +- **ESDB license activation in pipx** (#295) - The Ed25519 `cryptography` verifier + is now a base SpecSmith dependency, so `specsmith esdb enable` works in a clean + `pipx install specsmith` environment without a manual `pipx inject` workaround. + ## [0.22.0] - 2026-07-10 ### Added - CPU fallback for local model detection (REQ-445) - When no GPU is detected, @@ -922,7 +928,8 @@ See git history for per-commit details on intermediate versions. --- -[Unreleased]: https://github.com/layer1labs/specsmith/compare/v0.22.0...HEAD +[Unreleased]: https://github.com/layer1labs/specsmith/compare/v0.22.1...HEAD +[0.22.1]: https://github.com/layer1labs/specsmith/compare/v0.22.0...v0.22.1 [0.22.0]: https://github.com/layer1labs/specsmith/compare/v0.20.1...v0.22.0 [0.20.1]: https://github.com/layer1labs/specsmith/compare/v0.20.0...v0.20.1 [0.20.0]: https://github.com/layer1labs/specsmith/compare/v0.19.2...v0.20.0 diff --git a/README.md b/README.md index 1f58228b..3f730d71 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend: pip install "specsmith[esdb]" # installs chronomemory from PyPI # or if using pipx: pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv +# The license verifier is included in base specsmith; no cryptography injection is needed. # Step 2 — activate your license key specsmith esdb enable --key-file /path/to/your.esdb.key diff --git a/docs/COMPLIANCE.md b/docs/COMPLIANCE.md index c302d203..7648c1ae 100644 --- a/docs/COMPLIANCE.md +++ b/docs/COMPLIANCE.md @@ -8,7 +8,7 @@ - **Type**: python - **Language**: python - **VCS Platform**: github -- **Spec Version**: 0.22.0 +- **Spec Version**: 0.22.1 ## Verification Tools @@ -21,10 +21,10 @@ ## Audit Summary -- **Passed**: 73 -- **Failed**: 0 +- **Passed**: 74 +- **Failed**: 1 - **Fixable**: 0 -- **Status**: Healthy +- **Status**: Issues found - ✓ Required file AGENTS.md exists - ✓ Required file LEDGER.md exists @@ -50,7 +50,7 @@ - ✓ session-protocol.yaml valid (m001 content-blob, kind=session-protocol) - ✓ verification.yaml valid (m001 content-blob, kind=verification) - ✓ All 412 accepted REQ(s) have test coverage -- ✓ LEDGER.md has 467 lines (within 500 threshold) +- ✓ LEDGER.md has 475 lines (within 500 threshold) - ✓ 0 open, 0 closed TODOs - ✓ AGENTS.md: 122 lines - ✓ docs/governance/RULES.md: 18 lines @@ -99,9 +99,13 @@ - ✓ WI-DA14F483 risk=medium gates satisfied - ✓ WI-8F467602 risk=medium gates satisfied - ✓ WI-5C560143 risk=medium gates satisfied +- ✗ WI-6C92EE21 risk=medium missing gates: linked tests +- ✓ WI-260B314F risk=low gates satisfied ## Recent Activity +- `bf45813 Merge pull request #294 from layer1labs/codex/close-release-0.22.0` +- `0f75440 chore(governance): close v0.22.0 release` - `61b556e Merge pull request #293 from layer1labs/codex/release-0.22.0` - `1f75e19 release: prepare v0.22.0` - `52c33fd KILL SWITCH ACTIVATED: emergency stop` @@ -110,11 +114,9 @@ - `05d3e38 fix: clear remaining post-merge CodeQL findings` - `eafcd63 Merge pull request #291 from layer1labs/codex/epistemic-release` - `76adac6 fix: resolve remaining CodeQL review findings` -- `cf91bab merge: integrate Zoo/Roo governance configuration` -- `ec2e978 wi_close WI-094C4FE3: Published archive/feat-zoo-roo-mcp-integration-202` **Contributors:** -- 725 Tristen Pierson +- 726 Tristen Pierson - 5 dependabot[bot] - 1 Aqil Aziz diff --git a/docs/LEDGER.md b/docs/LEDGER.md index c387f2a9..38d8b63e 100644 --- a/docs/LEDGER.md +++ b/docs/LEDGER.md @@ -465,3 +465,17 @@ - **Type**: wi_close - **Status**: complete - **Chain hash**: `f3bbad392d19900e...` + +## 2026-07-13T18:08 — KILL SWITCH ACTIVATED: emergency stop +- **Author**: specsmith-operator +- **Type**: kill-switch +- **REQs affected**: REG-005 +- **Status**: complete +- **Epistemic status**: high +- **Chain hash**: `46ed7529d803de9b...` + +## 2026-07-13T18:35 — wi_archive WI-6C92EE21: Superseded by WI-260B314F, which implements issue #295 under REQ-366 with TEST-472 coverage. +- **Author**: specsmith +- **Type**: wi_archive +- **Status**: complete +- **Chain hash**: `f43dc947dfb44117...` diff --git a/docs/SPECSMITH.yml b/docs/SPECSMITH.yml index d84bb37c..45e724b1 100644 --- a/docs/SPECSMITH.yml +++ b/docs/SPECSMITH.yml @@ -9,7 +9,7 @@ description: | through governance, traceability, and automated compliance checking. type: python -version: 0.22.0 +version: 0.22.1 license: MIT author: Layer1 Labs url: https://github.com/layer1labs/specsmith diff --git a/docs/requirements/yaml_governance.yml b/docs/requirements/yaml_governance.yml index ef644821..922dbd99 100644 --- a/docs/requirements/yaml_governance.yml +++ b/docs/requirements/yaml_governance.yml @@ -638,7 +638,9 @@ from SPECSMITH_ESDB_KEY environment variable or ~/.specsmith/esdb.key. If the key is absent or invalid the backend silently falls back to SqliteStore with a one-time warning. The SPECSMITH_ESDB_BACKEND=sqlite environment variable force-selects - SQLite regardless of key presence. + SQLite regardless of key presence. The base specsmith package must include the + cryptography verifier required by `specsmith esdb enable`, so clean pip and pipx + installations can activate a valid license without a separate dependency injection. source: commercial licensing model - id: REQ-367 title: chronomemory must carry a proprietary commercial license separate from specsmith diff --git a/docs/site/esdb.md b/docs/site/esdb.md index 5c6605aa..0c0f1c95 100644 --- a/docs/site/esdb.md +++ b/docs/site/esdb.md @@ -207,6 +207,10 @@ specsmith esdb enable --key-file /path/to/your-org.esdb.key The key is copied to `~/.specsmith/esdb.key`. Every subsequent specsmith command automatically uses ChronoStore as long as the key is present and valid. +The Ed25519 verifier used by `specsmith esdb enable` is included with the base +specsmith package, including `pipx` installs. Only the commercial `chronomemory` +backend needs the extra `pipx inject` step above. + **Step 3 — verify ChronoStore is active** ```bash diff --git a/docs/site/esdb/installation.md b/docs/site/esdb/installation.md index f4cced06..7bff6a96 100644 --- a/docs/site/esdb/installation.md +++ b/docs/site/esdb/installation.md @@ -13,6 +13,10 @@ Terms: [COMMERCIAL-LICENSE.md (ChronoMemory only)](https://github.com/layer1labs If you use specsmith, the simplest path is `pip install "specsmith[esdb]"`. See the [ESDB overview](../esdb.md#licensing) for the full two-tier licensing summary. +The base specsmith package includes the Ed25519 license verifier, including in a +`pipx` installation. Only the commercial ChronoMemory backend needs an additional +package install. + --- ## Requirements @@ -39,6 +43,8 @@ specsmith esdb enable --key-file /path/to/your.esdb.key specsmith esdb status # confirms ChronoMemory / ChronoStore backend is active ``` +No `pipx inject specsmith cryptography` step is required before activating a license. + ## Install standalone (without specsmith) ```bash diff --git a/docs/tests/overflow.yml b/docs/tests/overflow.yml index b04a36ca..1b5a5d43 100644 --- a/docs/tests/overflow.yml +++ b/docs/tests/overflow.yml @@ -648,5 +648,5 @@ type: integration verification_method: pytest tests/test_esdb_enforcement.py -k save_does_not_commit description: Verify save normalizes the Git policy, commits no SQLite cache, migration - backup, marker, state, or agent migration artifact, and retains the mergeable session - event log as canonical source of truth. + backup, marker, state, or agent migration artifact, and retains the mergeable + session event log as canonical source of truth. diff --git a/docs/tests/yaml_governance.yml b/docs/tests/yaml_governance.yml index bf91e4fb..4dc0d266 100644 --- a/docs/tests/yaml_governance.yml +++ b/docs/tests/yaml_governance.yml @@ -1184,3 +1184,11 @@ input: {} expected_behavior: {} confidence: 1.0 +- id: TEST-472 + title: Base package metadata includes cryptography for ESDB license activation + requirement_id: REQ-366 + type: unit + verification_method: pytest tests/test_esdb_license.py::test_base_install_includes_cryptography_for_license_verification + description: Verify pyproject.toml lists cryptography in base project dependencies, + so a clean pipx install can execute specsmith esdb enable without a manual pipx + inject. diff --git a/pyproject.toml b/pyproject.toml index 7a2fbf7c..2eb76c63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "specsmith" -version = "0.22.0" +version = "0.22.1" description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider." readme = "README.md" license = "MIT" @@ -37,6 +37,8 @@ classifiers = [ dependencies = [ "click>=8.1", + # `specsmith esdb enable` verifies Ed25519 license signatures in every install. + "cryptography>=42.0", "jinja2>=3.1", "pyyaml>=6.0", "pydantic>=2.0", @@ -54,7 +56,6 @@ dev = [ "mypy>=1.10", "pre-commit>=3.0", "types-pyyaml>=6.0", - "cryptography>=42.0", # needed for test_esdb_license.py signing helpers ] # ESDB commercial backend — requires a valid license from licensing@layer1labs.ai # Install: pip install specsmith[esdb] @@ -62,7 +63,6 @@ dev = [ # Terms: https://github.com/layer1labs/specsmith/blob/develop/COMMERCIAL-LICENSE.md esdb = [ "chronomemory>=0.2.7", # proprietary commercial — ChronoMemory terms only (not SQLite free tier) - "cryptography>=42.0", ] docs = [ "mkdocs>=1.6", @@ -95,8 +95,8 @@ all = [ "ruff>=0.4", "mypy>=1.10", ] -# cryptography for license verification (usable without full esdb extra) -license-verify = ["cryptography>=42.0"] +# Compatibility extra: cryptography is now part of every supported installation. +license-verify = [] [project.scripts] specsmith = "specsmith.cli:main" diff --git a/src/specsmith/__init__.py b/src/specsmith/__init__.py index 11d99bcb..d2989e06 100644 --- a/src/specsmith/__init__.py +++ b/src/specsmith/__init__.py @@ -8,4 +8,4 @@ try: __version__: str = _pkg_version("specsmith") except PackageNotFoundError: # running from source without install - __version__ = "0.22.0" # fallback: keep in sync with pyproject.toml + __version__ = "0.22.1" # fallback: keep in sync with pyproject.toml diff --git a/src/specsmith/cli.py b/src/specsmith/cli.py index 2eca77af..91791368 100644 --- a/src/specsmith/cli.py +++ b/src/specsmith/cli.py @@ -3853,7 +3853,7 @@ def channel_set_cmd(channel: str) -> None: if channel == "stable" and is_prerelease_version(__version__): raise click.UsageError( "Cannot select stable while a prerelease is installed. " - f"Install a stable build first: {version_mismatch_remediation('0.22.0')}" + f"Install a stable build first: {version_mismatch_remediation('0.22.1')}" ) set_persisted_channel(channel) diff --git a/src/specsmith/config.py b/src/specsmith/config.py index ea5d3454..7df7a64b 100644 --- a/src/specsmith/config.py +++ b/src/specsmith/config.py @@ -140,7 +140,7 @@ class ProjectConfig(BaseModel): ), ) language: str = Field(default="python", description="Primary language/runtime") - spec_version: str = Field(default="0.22.0", description="Spec version to scaffold from") + spec_version: str = Field(default="0.22.1", description="Spec version to scaffold from") description: str = Field(default="", description="Short project description") # Options diff --git a/tests/test_esdb_license.py b/tests/test_esdb_license.py index f8604c13..db877ef1 100644 --- a/tests/test_esdb_license.py +++ b/tests/test_esdb_license.py @@ -67,6 +67,18 @@ def _make_license_file( # --------------------------------------------------------------------------- +def test_base_install_includes_cryptography_for_license_verification() -> None: + """TEST-472: pipx base installs need the verifier used by esdb enable.""" + pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml" + base_dependencies = pyproject.read_text(encoding="utf-8").split( + "[project.optional-dependencies]", maxsplit=1 + )[0] + + assert any( + line.strip().startswith('"cryptography>=42.0"') for line in base_dependencies.splitlines() + ) + + def test_valid_license(tmp_path: Path) -> None: key = _make_license_file(tmp_path) status = verify_license_file(key)