Offline verification for GuardSpine evidence bundles
Project description
guardspine-verify
Verify GuardSpine evidence bundles offline - no trust required.
Spec Version: v0.2.0 + v0.2.1 | Package Version: 0.2.1
Installation
pip install guardspine-verify
Or install from source:
git clone https://github.com/DNYoussef/guardspine-verify.git
cd guardspine-verify
pip install -e .
Quick Start
# Verify a JSON bundle
guardspine-verify bundle.json
# Verify a ZIP export
guardspine-verify evidence-bundle-2024-01-15.zip
# Verbose output
guardspine-verify bundle.json --verbose
# Output JSON report
guardspine-verify bundle.json --format json > report.json
What It Verifies
| Check | Description |
|---|---|
| Version | Bundle version must be one of 0.2.0, 0.2.1 |
| Hash Chain | Each entry's previous_hash matches prior chain_hash |
| Chain Binding | Chain entries map 1:1 to items (count, item_id, content_hash) |
| Root Hash | Computed Merkle root matches stored root |
| Content Hashes | Each item's content_hash matches SHA-256 of canonical JSON content |
| Sequence | Chain sequence numbers are contiguous starting from 0 |
| Signatures | Cryptographic signatures verify (Ed25519, RSA, ECDSA) |
| Sanitization (optional) | --check-sanitized validates redaction metadata and token consistency |
CLI sanitization flags:
--check-sanitized: evaluate optionalsanitizationcontract and[HIDDEN:*]token consistency--require-sanitized: fail if sanitization block is missing or invalid--fail-on-raw-entropy: treat post-sanitization high-entropy survivors as hard failures
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Bundle verified successfully |
| 1 | Verification failed |
| 2 | Invalid input (file not found, parse error) |
Python API
from guardspine_verify import verify_bundle_data, VerificationResult
# Verify bundle data directly
import json
with open("bundle.json") as f:
bundle = json.load(f)
result = verify_bundle_data(bundle)
if result.verified:
print("Bundle verified!")
else:
print(f"Verification failed:")
for error in result.errors:
print(f" - {error}")
print(f"Status: {result.status}")
print(f"Hash chain: {result.hash_chain_status}")
print(f"Signatures: {result.signature_status}")
Note: A verify_bundles() batch API is planned for a future release.
Verification Result
@dataclass
class VerificationResult:
verified: bool
status: str # "verified" | "mismatch" | "error"
hash_chain_status: str
root_hash_status: str
content_hash_status: str
signature_status: str
errors: list[str]
warnings: list[str]
verified_at: datetime
details: dict[str, Any]
Supported Algorithms
| Algorithm | Status |
|---|---|
| SHA-256 | Supported |
| Ed25519 | Supported |
| RSA-SHA256 | Supported |
| ECDSA-P256 | Supported |
Supported Input Formats
| Format | Extension | Description |
|---|---|---|
| JSON | .json |
Single bundle file |
| ZIP | .zip |
Exported bundle package |
| Directory | folder | Unpacked bundle with manifest |
Integration with CI/CD
# GitHub Actions
- name: Verify Evidence Bundles
run: |
pip install guardspine-verify
guardspine-verify ./evidence/*.json
# GitLab CI
verify-evidence:
script:
- pip install guardspine-verify
- guardspine-verify ./evidence/*.json
Security
This verifier:
- Does not require network access
- Does not phone home
- Does not store any data
- Is fully auditable (open source)
- Has no external dependencies for core verification
PII-Shield Integration
guardspine-verify validates PII-Shield sanitization attestations embedded in evidence bundles.
Why
When bundles are sanitized before sealing (e.g., by codeguard-action or rlm-docsync), the sanitization block attests what engine was used, how many redactions were applied, and what token format was used. The verifier checks this attestation for consistency and can also detect secrets that survived sanitization via entropy analysis.
Where
Sanitization verification runs inside guardspine_verify/verifier.py as an optional verification pass, controlled by CLI flags.
How
# Check sanitization attestation (warn on issues)
guardspine-verify bundle.json --check-sanitized
# Require sanitization (fail if missing or invalid)
guardspine-verify bundle.json --require-sanitized
# Treat post-sanitization high-entropy survivors as failures
guardspine-verify bundle.json --require-sanitized --fail-on-raw-entropy
The verifier checks:
sanitization.redaction_countmatches actual[HIDDEN:<id>]token countengine_versionis valid semvertoken_formatmatches the tokens found in bundle content- High-entropy strings that survived sanitization (optional hard fail)
GuardSpine's own hash fields (content_hash, chain_hash, root_hash, etc.) are excluded from entropy analysis to avoid false positives.
Related Projects
| Project | Description |
|---|---|
| guardspine-spec | Bundle specification |
| GuardSpine | Full governance platform |
| guardspine-connector-template | Connector SDK |
Contributing
See CONTRIBUTING.md.
License
Apache 2.0 - See LICENSE.
GuardSpine: Verifiable governance evidence you don't have to trust.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file guardspine_verify-0.2.1.tar.gz.
File metadata
- Download URL: guardspine_verify-0.2.1.tar.gz
- Upload date:
- Size: 35.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
951e5de1515a2675463e0e0a80ebe9cabe2744618a2aaf9c084970d250f6e372
|
|
| MD5 |
6f501d659407e9babb557120c1946683
|
|
| BLAKE2b-256 |
1786ecf988b45078d16d44e26434506f305128ec870c8fa9ec01a46f681df62a
|
File details
Details for the file guardspine_verify-0.2.1-py3-none-any.whl.
File metadata
- Download URL: guardspine_verify-0.2.1-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
866651b3381b3efe277583cdf384f9ddeef617953cf9b8696a757e1d368a816f
|
|
| MD5 |
87c6d30dba4782d9f7b0911bb1a87d3e
|
|
| BLAKE2b-256 |
b3b8a491e4605c6b0522f7ae42fddc02b5ce09082aa1b474f922ed73de689a6a
|