All notable changes to the SchemaPin project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
SkillSignature.schema_version: Optional caller-supplied semver string identifying this version of the signed artifact. Opaque to SchemaPin (treated as a tag); surfaced viaVerificationResult.schema_versionfor policy use.SkillSignature.previous_hash: Optionalsha256:<hex>of the prior signed version'sskill_hash. Forms a hash chain across successive signatures.SignOptions.with_schema_version/SignOptions.with_previous_hash(Rust); equivalent fields on the Python dataclass, JS options object, and Go struct. Either field bumpsschemapin_versionto"1.4".verify_chain(current, previous): New chain-verification helper in every language. Returns success whencurrent.previous_hash == previous.skill_hash. Distinguishes two failure modes —NoPreviousHash(current sig lacks the field) andMismatch(both present but unequal). Pure-metadata check; cryptographic verification of both signatures must happen separately.VerificationResult.schema_version/VerificationResult.previous_hash: New optional fields, mirrored from the signature when present. No automatic enforcement — chain verification is opt-in viaverify_chain.ChainError: Per-language error/exception type carrying the kind (no_previous_hash/mismatch) and, on mismatch, the expected and observed values.
- Section 18: Schema Version Binding — wire format, informational verifier semantics for
schema_versionandprevious_hash, opt-in chain verification, operational pattern (per-toollatest_known_hashpinned alongside the TOFU key), backward compatibility.
- All four implementations bumped to
1.4.0-alpha.2(1.4.0a2for Python per PEP 440).
- Item #2 from the v1.4 roadmap. The full v1.4.0 release also requires items 4–8 (canonicalization id, A2A context, A2A trust bundles, scan-aware signatures, cross-agent schema cache).
- Both new fields are additive optional fields — v1.3 verifiers ignore them, and v1.4 signatures without lineage opts behave identically to v1.3 signatures.
SkillSignature::expires_at: Optional ISO 8601 / RFC 3339 timestamp on.schemapin.sigdocuments. v1.3 verifiers ignore the field; v1.4 verifiers degrade expired signatures to a warning rather than failing.SignOptionsbuilder (SignOptions::new().with_expires_in(Duration::days(N))): Optional sign-time configuration. Wraps the existingsign_skillparameters and addsexpires_in. The legacysign_skillfunction delegates tosign_skill_with_optionsfor backward compatibility.VerificationResult::expired+VerificationResult::expires_at: Surface expiration state on the result.validremainstruefor expired signatures (degraded, not failed), and asignature_expiredwarning is appended.VerificationResult::with_expiration_check: Helper applied automatically byverify_skill_offlineafter a successful signature check. Unparseable timestamps emit asignature_expires_at_unparseablewarning rather than failing closed.- Documents written by
sign_skill_with_optionswithexpires_inset advertiseschemapin_version: "1.4"; documents withoutexpires_atretain"1.3".
- New
dnsmodule withDnsTxtRecord,parse_txt_record,verify_dns_match, andtxt_record_name. Always available; the parser/matcher have no DNS dependencies. fetch_dns_txt(domain): Async lookup behind the newdnsCargo feature. Brings inhickory-resolver,tokio, andasync-trait.verify_skill_offline_with_dns(...): Variant ofverify_skill_offlinethat accepts an optional&DnsTxtRecord. A mismatching record converts the result into a hardDOMAIN_MISMATCHfailure; an absent record is a no-op (DNS TXT is additive).- TXT record format:
_schemapin.{domain}IN TXT"v=schemapin1; kid=...; fp=sha256:...". Whitespace-tolerant parser, case-insensitive onfp, ignores unknown fields for forward compatibility.
- Section 16: Signature Expiration —
expires_atfield, degraded-vs-failed semantics, backward compatibility. - Section 17: DNS TXT Cross-Verification —
_schemapin.{domain}TXT record format, verifier semantics, lookup name construction. - Section 12: Updated version compatibility note for v1.4.
- Rust crate version:
1.3.0→1.4.0-alpha.1. sign_skillnow formatssigned_atwith second-level precision and aZUTC suffix (RFC 3339SecondsFormat::Secs). Existing v1.3 signatures continue to verify; the change only affects newly minted signatures.
- This is the first v1.4 alpha. Python, JavaScript, and Go implementations follow in subsequent alphas before the v1.4.0 release.
- Both new features are additive optional fields/records — v1.3 clients are unaffected.
skillmodule (Rust, Python, JavaScript, Go): Deterministic directory canonicalization and cryptographic signing for AgentSkills (SKILL.md) folders.canonicalize_skill(): Recursively walks skill directory in sorted order, hashes each file asSHA256(relative_path + content), produces deterministic root hash and file manifest. Skips.schemapin.sigand symlinks.parse_skill_name(): Extracts skill name from SKILL.md YAML frontmattername:field, falls back to directory basename.sign_skill(): Signs a skill folder with an ECDSA P-256 private key. Writes.schemapin.sigJSON containing root hash, per-file manifest, signature, domain, signer KID, and timestamp.verify_skill_offline(): 7-step offline verification: load signature, validate discovery, extract key, check revocation, TOFU pin, canonicalize and compare, verify ECDSA signature.verify_skill_with_resolver(): Resolves discovery and revocation documents viaSchemaResolvertrait, then delegates to offline verification.load_signature(): Loads and parses.schemapin.sigJSON from a skill directory.detect_tampered_files(): Compares current file manifest against signed manifest, reports modified, added, and removed files.SkillSignaturestruct: Serializable signature document withschemapin_version,skill_name,skill_hash,signature,signed_at,domain,signer_kid, andfile_manifest.
- Bumped
cryptographydependency from 44.0.1/45.0.5 to 46.0.5 in Python and server packages.
error.rs: UnifiedErrortype usingthiserror, wrappingcrypto::ErrorviaFrom. Feature-gatedHttpvariant.ErrorCodeenum for structured verification results.types/discovery.rs:WellKnownResponsewith optionalcontactandrevocation_endpointfields.types/revocation.rs:RevocationDocument,RevokedKey,RevocationReasonenum (KeyCompromise,Superseded,CessationOfOperation,PrivilegeWithdrawn).types/pinning.rs:PinnedTool,PinnedKey,TrustLevelenum (Tofu,Verified,Pinned).types/bundle.rs:SchemaPinTrustBundle,BundledDiscoverywithfind_discovery()andfind_revocation()methods.canonicalize.rs: JSON canonicalization with recursive key sorting and SHA-256 hashing. Functions:canonicalize_schema(),hash_canonical(),canonicalize_and_hash().discovery.rs: URL construction, validation, builder. Functions:construct_well_known_url(),validate_well_known_response(),build_well_known_response(),check_key_revocation(), and fetch-gatedfetch_well_known().revocation.rs: Standalone revocation documents. Functions:build_revocation_document(),add_revoked_key(),check_revocation(),check_revocation_combined(), and fetch-gatedfetch_revocation_document().pinning.rs: TOFU key pinning keyed bytool_id@domain.KeyPinStorewithcheck_and_pin(),add_key(),get_tool(), JSON serialization.PinningResultenum andcheck_pinning()wrapper.resolver.rs:SchemaResolvertrait with 4 implementations:WellKnownResolver(fetch-gated),LocalFileResolver,TrustBundleResolver,ChainResolver.AsyncSchemaResolvertrait (fetch-gated).verification.rs:VerificationResultstruct. Functions:verify_schema_offline()(7-step flow),verify_schema_with_resolver(), and fetch-gatedverify_schema().
revocation.py:RevocationReasonenum,RevokedKey/RevocationDocumentdataclasses. Functions:build_revocation_document(),add_revoked_key(),check_revocation(),check_revocation_combined(),fetch_revocation_document().bundle.py:SchemaPinTrustBundledataclass withfind_discovery(),find_revocation(). FlattenedBundledDiscoveryformat via dict merging.resolver.py:SchemaResolverABC with 4 implementations:WellKnownResolver,LocalFileResolver,TrustBundleResolver,ChainResolver.verification.py:ErrorCodeenum (8 codes),KeyPinStorein-memory pin store,VerificationResultdataclass. Functions:verify_schema_offline()(7-step flow),verify_schema_with_resolver().utils.py:create_well_known_response()now acceptsrevocation_endpointparameter, defaultschema_versionchanged to"1.2".
revocation.js:RevocationReasonconstants. Functions:buildRevocationDocument(),addRevokedKey(),checkRevocation(),checkRevocationCombined(),fetchRevocationDocument().bundle.js: Functions:createTrustBundle(),createBundledDiscovery(),findDiscovery(),findRevocation(),parseTrustBundle(). Flattened format via object spread.resolver.js:SchemaResolverbase class with 4 implementations:WellKnownResolver,LocalFileResolver,TrustBundleResolver,ChainResolver.verification.js:ErrorCodeconstants,KeyPinStoreclass. Functions:verifySchemaOffline()(7-step flow),verifySchemaWithResolver().utils.js:createWellKnownResponse()now acceptsrevocationEndpointparameter, defaultschemaVersionchanged to"1.2".
pkg/revocation/:RevocationReasontype with constants,RevokedKey/RevocationDocumentstructs. Functions:BuildRevocationDocument(),AddRevokedKey(),CheckRevocation(),CheckRevocationCombined(),FetchRevocationDocument().pkg/bundle/:SchemaPinTrustBundlestruct withFindDiscovery(),FindRevocation().BundledDiscoverywith customMarshalJSON/UnmarshalJSONfor flattened format.pkg/resolver/:SchemaResolverinterface with 4 implementations:WellKnownResolver,LocalFileResolver,TrustBundleResolver,ChainResolver.pkg/verification/:ErrorCodetype (8 codes),KeyPinStorestruct,VerificationResultstruct. Functions:VerifySchemaOffline()(7-step flow),VerifySchemaWithResolver().pkg/discovery/: AddedRevocationEndpointfield toWellKnownResponse.pkg/utils/:CreateWellKnownResponse()now acceptsrevocationEndpointparameter, defaultschemaVersionchanged to"1.2".
- Section 6: Added
revocation_endpointandcontactoptional fields to.well-knownresponse. - Section 8.5: Standalone Revocation Document format.
- Section 8.6: Revocation Reasons (
key_compromise,superseded,cessation_of_operation,privilege_withdrawn). - Section 8.7: Combined Revocation Checking (simple list + standalone document).
- Section 13: Trust Bundles — format, use cases,
SchemaPinTrustBundlestructure. - Section 14: Discovery Resolver —
SchemaResolverabstraction, four implementations,fetchfeature gate. - Section 15: Offline Verification —
verify_schema_offline()as core primitive, 7-step flow. - Section 12: Updated backward compatibility note for v1.2.
- Rust: Version bumped from 1.1.7 to 1.2.0
- Rust: Added
serde_json,thiserror,chronodependencies - Rust: Added feature-gated
reqwest,tokio,async-traitdependencies underfetchfeature - Rust: Added
tempfiledev-dependency - Python: Version bumped from 1.1.7 to 1.2.0
- JavaScript: Version bumped from 1.1.7 to 1.2.0
- Go: Version bumped from 1.1.7 to 1.2.0
- All languages: Default
schema_versionincreate_well_known_response()changed from"1.1"to"1.2"
- Backward Compatible: Existing core/crypto modules are untouched — no breaking changes in any language
- No new dependencies: Python uses stdlib
dataclasses/json/abc, JS uses Node builtins, Go uses stdlib - Feature Flags (Rust only):
default = [](everything except HTTP).fetchenables HTTP-based discovery. - 109 Python tests, 96 JavaScript tests, and all Go tests pass
- Go:
NewSchemaVerificationWorkflownow validates that pinning database path is not empty - Go: Fixed all golangci-lint errors (unchecked error returns, gosimple, ineffassign)
- Rust: Fixed
cargo fmtformatting issues in core and crypto modules - CI: Fixed version consistency check in release-combined workflow (grep for
var Versionnotconst Version) - CI: Fixed GitHub Release race condition where parallel release workflows would fail trying to create duplicate releases
- CI: Fixed duplicate
[dependencies]section in crates.io release workflow test step
- python-multipart: Updated from 0.0.18 to 0.0.22 to fix HIGH severity CVE (dependabot alert #18)
- js-yaml transitive CVE: Eliminated by migrating ESLint from v8 to v9 flat config, removing the vulnerable transitive dependency (dependabot alert #17, MEDIUM severity)
- brace-expansion: Updated to fix low severity ReDoS vulnerability
- cryptography: Updated from 44.0.1 to 45.0.5 in server requirements to align with main Python package
- ESLint 9 migration: Replaced legacy
.eslintrc.cjswitheslint.config.js(flat config format) in JavaScript package - Version alignment: Server and integration demo versions now aligned with core library versions
python-multipart0.0.18 → 0.0.22 (server)cryptography44.0.1 → 45.0.5 (server)eslint^8.57.0 → ^9.0.0 (JavaScript devDependencies)- Added
@eslint/js^9.0.0 andglobals^16.0.0 (JavaScript devDependencies)
- Schema Version 1.1: Enhanced
.well-known/schemapin.jsonformat withrevoked_keysarray - Key Revocation Support: Automatic checking of revoked keys during verification
- Backward Compatibility: Full support for schema v1.0 endpoints
- Revocation Validation: Comprehensive validation of revoked key entries
- Interactive Pinning: User prompts for key pinning decisions with detailed information
- Domain Policies: Configurable policies for automatic vs. interactive pinning
- Enhanced UX: Rich terminal output with colored status indicators and clear prompts
- Key Management: Advanced key pinning with metadata and policy enforcement
- schemapin-keygen: Complete key generation tool with ECDSA/RSA support
- schemapin-sign: Schema signing tool with batch processing and metadata
- schemapin-verify: Verification tool with interactive pinning and discovery
- Comprehensive Options: Full CLI interface with extensive configuration options
- Integration Demo: Complete cross-language compatibility demonstration
- Production Server: Docker-ready
.well-knownendpoint server - Real-world Examples: Practical usage scenarios and deployment guides
- Cross-language Testing: Validation of Python/JavaScript interoperability
- Python Package: Complete PyPI-ready package with modern packaging standards
- JavaScript Package: npm-ready package with comprehensive metadata
- Build Scripts: Automated building and testing infrastructure
- Distribution Tools: Publishing workflows and validation scripts
- ECDSA P-256 Signatures: Industry-standard cryptographic verification
- Schema Canonicalization: Deterministic JSON serialization for consistent hashing
- Trust-On-First-Use (TOFU): Secure key pinning with user control
- Public Key Discovery: RFC 8615 compliant
.well-knownendpoint discovery
- Key Revocation: Comprehensive revocation checking and validation
- Signature Verification: Robust cryptographic signature validation
- Key Pinning Storage: Secure local storage of pinned keys with metadata
- Domain Validation: Proper domain-based key association and verification
- High-level APIs: Simple workflows for both developers and clients
- Comprehensive Testing: Full test suites with security validation
- Rich Documentation: Complete API documentation and usage examples
- Cross-platform Support: Works on Linux, macOS, and Windows
- Modern Packaging: Uses pyproject.toml and latest npm standards
- Comprehensive Metadata: Rich package information for discoverability
- Development Tools: Integrated linting, testing, and quality checks
- Security Compliance: Bandit security scanning and vulnerability checks
- Signature Algorithm: ECDSA with P-256 curve (secp256r1)
- Hash Algorithm: SHA-256 for schema integrity
- Key Format: PEM encoding for interoperability
- Signature Format: Base64 encoding for transport
- RFC 8615:
.well-knownURI specification compliance - JSON Schema: Structured schema validation and canonicalization
- HTTP Standards: Proper HTTP headers and status codes
- Cross-language: Full Python and JavaScript compatibility
- Python: PEP 517/518 compliant with pyproject.toml
- JavaScript: Modern ES modules with comprehensive exports
- Semantic Versioning: Proper version management and compatibility
- License Compliance: MIT license with proper attribution
cryptography>=41.0.0- ECDSA cryptographic operationsrequests>=2.31.0- HTTP client for key discovery- Python 3.8+ support with type hints
- Node.js 18.0.0+ - Modern JavaScript runtime
- Zero external dependencies - Uses built-in crypto module
- ES modules with proper exports configuration
- None - Full backward compatibility maintained
- All cryptographic operations use industry-standard algorithms
- Key revocation checking prevents use of compromised keys
- Interactive pinning provides user control over trust decisions
- Secure storage of pinned keys with proper metadata
- Existing v1.0 implementations continue to work without changes
- New features are opt-in and backward compatible
- CLI tools provide migration assistance for existing workflows
- Initial release of SchemaPin protocol
- Basic ECDSA P-256 signature verification
- Simple key pinning mechanism
- Python and JavaScript reference implementations
- Core cryptographic operations and schema canonicalization
For more details on any release, see the GitHub releases page.