All notable changes to squash-ai are documented here.
Format: Conventional Commits ยท Keep a Changelog
CLAUDE.md, README.md, and SQUASH_MASTER_PLAN.md to reflect the two-deadline
landscape. The Article 50 deadline (Dec 2, 2026) is now the near-term regulatory forcing
function โ 6 months away โ and all transparency/watermarking sprint work is load-bearing
against that date.The demo earns the next user: every failing clause is actionable, every scan is auditable, every gap is a number a CFO will read.
squash/financial_risk.py โ clause-level USD exposure quantification:
RISK_TABLE covers all 27 clause IDs the quick-check catalogue emits.low_usd, high_usd, risk_level, rationale, and a
public citation (GDPR Art. 83, CCPA ยง1798.155, EU AI Act Art. 99,
AICPA TSC, FTC ยง5, etc.).quantify(clause_id), aggregate_exposure(ids), format_usd(n),
covered_clause_ids().squash/clause_remediation.py โ per-clause redline + suggested fix:
label, issue, original, suggested_fix (paste-ready clause
text), citation.build_remediation(missing) -> RemediationReport enriched with the
matching RiskBand per clause (so the demo can render one row per
clause with a paired exposure pill).squash/scan_history.py โ append-only audit trail:
ScanHistory backed by SQLite (path-overridable, default
~/.squash/scan_history.db; :memory: for tests).record(), list(limit, offset, framework, verdict), count(),
stats(), pass_rate_sparkline(points, bucket_seconds).global_history() lazy singleton + reset_global_history() test hook.GET /r/{hash}/remediation โ returns the RemediationReport for a
stored quick-check share hash. Entries include dollar_low_usd /
dollar_high_usd, the envelope includes aggregate exposure.GET /history?limit=&offset=&framework=&verdict=&sparkline= โ paginated
history with optional pass-rate sparkline. Public-by-design (added to
_UNAUTHED_PATHS).POST /quick-check now appends every scan to ScanHistory
(failures swallowed so the user-facing path can never break).demo/index.html โ three new UI surfaces:
est. exposure $150Kโ$17M ยท 5 clauses ยท est. โ not legal advice.<details> per failing clause with a side-by-side red/green diff,
risk pill, dollar pill, issue summary, and regulatory citation.tests/test_squash_p1_sprint.py) โ financial-risk
table coverage + bounds + format helpers, remediation catalogue
symmetry, scan-history validation / pagination / capacity / sparkline,
TestClient-driven /r/{hash}/remediation and /history (status,
validation, filter, isolation via in-memory singleton), demo HTML
structural smoke, and the version-bump assertion.PLAN.md (NEW) โ short-horizon execution plan, with the full
P1 / P2 / P3 researched feature roadmap (custom playbook builder,
multi-framework parallel scoring, async dev API, bulk portfolio,
confidence scores, jurisdiction-aware scoring, collaborative
annotation).The demo is the compliance scanner โ visuals communicate everything.
GET /r/{hash}/card.svg โ viral SVG score card. 600ร340 standalone
SVG with verdict glyph (โฆ pass / โณ warn / โ fail), primary score and
framework, three sub-score chips (GDPR / CCPA / SOC 2), policy-type
label, UTC timestamp, and share-hash footer. Renders identically in
Slack unfurls, Twitter cards, GitHub READMEs, and blog embeds. No
external dependencies โ pure stdlib SVG construction.GET /trending โ public viral feed. Returns {total, top, policy_types}
where top is the top-N policy types by check count plus per-type
pass / warn / fail / pass-rate counters. Backed by an in-process
StatsTracker recorded on every /quick-check call. Auth-free by design.squash/quick_check.py additions:
AVAILABLE_FRAMEWORKS is now {gdpr, ccpa,
eu-ai-act, soc2, general}.detect_policy_type() โ heuristic classifier across 8 doc types
(privacy_policy, terms_of_service, gdpr_dpa, ccpa_notice,
cookie_policy, ai_system_card, soc2_report, other).score_all_frameworks() โ multi-framework scorer used by the SVG card.StatsTracker + get_global_stats() โ thread-safe in-memory aggregate.POLICY_TYPES taxonomy export.POST /quick-check response now includes card_url (when share=True)
and embeds policy_type in the share payload.demo/index.html โ full visual rebuild. #06060f background with
faint purple dot grid. Animated horizontal scan beam (@keyframes scan).
Borderless dark textarea with glowing caret. Single circular #7c3aed
submit orb with breathing pulse ring (@keyframes breathe); morphs to
spinner during scan. Result reveal: large verdict glyph in colored
outer-glow card, three orbiting framework dots, sub-score chips, inline
SVG card preview with copy-link orb. Faint trending sidebar with
per-policy-type glyphs and pass-rate bars. prefers-reduced-motion
respected. All Sprint 29 DOM hooks preserved.squash/__init__.py exports: QUICK_CHECK_POLICY_TYPES,
QuickCheckStatsTracker, detect_quick_check_policy_type,
get_quick_check_stats, score_quick_check_all_frameworks.tests/test_squash_sprint30.py โ 63 new tests covering the SOC 2
framework, policy-type detection, multi-framework scorer, thread-safe
stats tracker, both new API endpoints (200/400/404/no-auth/headers/body),
card-url presence in /quick-check response, the visual primitives in
the rebuilt UI, and the Sprint 29 contract preservation.pyproject.toml and squash/__init__.py to 3.7.0.tests/test_squash_w73.py version-pin updated to 3.7.0.tests/test_squash_sprint29.py version assertions loosened to
>= 3.6.0 so future bumps donโt break the Sprint 29 gate./trending is public; /r/{hash}/card.svg
inherits via the existing /r/ prefix rule.A share permalink is now an instantly-renderable, framework-aware billboard.
A founder pastes their privacy policy, gets a /r/{hash}/card.svg, drops
the URL into Slack, and the unfurl preview is a Squash-branded compliance
score. /trending turns aggregate behaviour into social proof: โwhat
policies are people checking right now.โ The visual UI rebuild collapses
the cognitive distance between โI have a documentโ and โI have a verdictโ
to a single keystroke on a breathing purple orb.
demo/index.html โ new โ00. Quick compliance checkโ panel
above the attest demo. Pre-loaded textarea (01_privacy_policy.txt),
five-policy selector with auto-framework hinting, framework picker,
one-click โRun Compliance Checkโ button, live elapsed-time counter,
inline pass/warn/fail badge, score, summary, two-column matched/missing
clause grid, and a โShare this resultโ copy-link block. Hero gains a
โPaste any policy. Get a compliance verdict in seconds.โ headline plus
three checkmark claim pills (GDPR ยท CCPA ยท SOC 2).demo/result.html โ branded shareable result page. Reads the share
hash from /share/<hex>, /r/<hex>, or ?h=<hex>, fetches the
canonical JSON from GET /r/{hash}, and renders verdict, score,
framework, retrieval timestamp, clause breakdown, and a copy-link CTA.
Permalink expiry is documented inline.GET /demo โ FastAPI route that serves demo/index.html with a
no-cache header so the demo iterates fast.GET /demo/sample_policies/{name} โ allowlisted plain-text serving
of the five Sprint 28 sample policies (path-traversal-safe via resolved
prefix check + explicit allowlist). The interactive panel uses this
endpoint to swap samples without page reload.GET /share/{share_hash} โ browser-friendly HTML view of a stored
quick-check result. Validates the hash and returns 404 immediately if
the share has been evicted.tests/test_squash_sprint29.py โ perf gate (/quick-check must
respond in under 1500 ms across the entire sample corpus on cold and
warm cache), demo-page hero/section/JS smoke tests, sample-policy
endpoint coverage and traversal-rejection tests, share HTML routing
tests, and version assertions._UNAUTHED_PATHS now includes /demo, /quick-check/frameworks, and
the /demo/ and /share/ prefixes โ the entire demo experience
remains login-free, matching the Sprint 28 viral-by-default design.pyproject.toml, squash/__init__.py).squash/quick_check.py โ One-click compliance heuristic for pasted
policy text. Stdlib-only. Public surface: run_quick_check, QuickCheckResult,
ResultStore, make_share_hash, is_valid_share_hash, AVAILABLE_FRAMEWORKS.
Built-in clause libraries: gdpr (6 clauses), ccpa (5), eu-ai-act (5),
general (5). framework="auto" runs every library and returns the best
match. Score 0โ100 โ verdict pass (โฅ80) / warn (50โ79) / fail (<50).
Deterministic โ identical input yields byte-identical result dict.POST /quick-check โ Public, auth-free FastAPI endpoint. Accepts
application/json ({text, framework?, share?}) or text/plain (raw
body is the text; ?framework= and ?share= query params). Returns
pass/warn/fail verdict, score, matched/missing clause lists, summary,
and (when share=true) a share_hash + share_url permalink.
Sub-2-second response on realistic policy snippets up to 200 KB.GET /r/{share_hash} โ Anonymous, auth-free permalink resolver.
Shareable hash-keyed permalinks for quick-check results. Backed by an
in-memory FIFO store (capacity 10,000) that mirrors writes to a JSON
file when SQUASH_QUICKCHECK_STORE is set. 16-hex-char hashes derived
from the canonical RFC-8785-ordered result payload โ identical inputs
produce identical hashes (idempotent, viral-link friendly).GET /quick-check/frameworks โ List of accepted frameworks.demo/sample_policies/ โ 5 realistic synthetic policy snippets
(privacy policy, terms of service, GDPR Art. 28 DPA, CCPA notice,
cookie policy) for demo visitors to paste immediately.getsquash.dev/demo, live
Compliance Score badge wired to /badge/eu-ai-act/compliant, and a
one-click compliance check section at the top of the README with a
curl example and JSON response shape.tests/test_squash_sprint28.py โ 63 new tests covering
run_quick_check semantics + thresholds + determinism + validation,
every framework against the sample-policy corpus, ResultStore
put/get/eviction/persistence, hash-helper validation, all four new
endpoints (auth-free, JSON + text/plain, 404/400/422 paths), README
badge presence, and the CI workflow contract.squash/__init__.py exports: run_quick_check, QuickCheckResult,
QuickCheckStore, QUICK_CHECK_FRAMEWORKS, make_quick_check_hash,
is_valid_quick_check_hash.pyproject.toml and squash/__init__.py to 3.5.0.quick_check.py)./quick-check and /r/* are now public by
design โ same posture as /badge/* and /health.The single biggest barrier to first-time-user adoption is the gap between
โI have a privacy policyโ and โI have a model artefact ready for squash
attest.โ /quick-check collapses that gap to a single curl. Anyone can
paste their privacy policy into the demo, get a verdict in two seconds,
and share the result with a single anonymous URL. The output explicitly
points the visitor at pip install squash-ai && squash attest for the
real run.
squash/insurance.py โ AI Cyber Insurance Risk Package generator: InsurancePackage
builder, ModelRiskProfile per-model risk summary, InsuranceBuilder artefact scanner.
Aggregates attestation records, VEX CVEs, drift events, incidents, bias audit results, and
data lineage presence into a single quantified risk record per model. Stdlib-only; zero new
dependencies.MunichReAdapter โ Maps InsurancePackage to Munich Reโs AI cyber underwriting schema:
5 control domains (technical_security, operational_excellence, ai_governance,
data_quality_provenance, incident_resilience) each rated AโD; overall AI Maturity Level
1โ4; coverage recommendation (STANDARD / ENHANCED / SPECIALIST).CoalitionAdapter โ Maps to Coalitionโs AI Risk Assessment schema: 5 risk categories
(ai_model_security, ai_operational_risk, ai_governance, ai_incident_history,
third_party_ai_risk) each scored 0โ100; weighted aggregate (30/25/20/15/10).GenericAdapter โ Generic JSON schema for underwriters without a published format;
designed as the fallback and for regulatory filing purposes.InsurancePackage.save_zip() โ Signed submission bundle: insurance-package.json,
insurance-munich-re.json, insurance-coalition.json, insurance-generic.json,
insurance-executive-summary.md, integrity.sha256 (SHA-256 file-hash manifest).squash insurance-package CLI โ squash insurance-package --models-dir ./models
--org 'Acme Corp' --underwriter munich-re --json --zip ./bundle.zip --quiet.
Flags: --underwriter {munich-re,coalition,generic}, --json, --zip PATH,
--output-dir, --org, --quiet.tests/test_squash_c6_insurance.py โ 76 tests covering: ModelRiskProfile.to_dict,
_compute_risk_tier formula, InsuranceBuilder single/multi-model/empty/degraded paths,
all three adapters (AโD rating, maturity levels, risk interpretation bands),
save_zip integrity manifest verification, CLI integration (all 5 subcommand variants),
numerical correctness assertions, and no-external-deps import checks.squash/__init__.py exports: ModelRiskProfile, InsurancePackage, InsuranceBuilder,
MunichReAdapter, CoalitionAdapter, GenericAdapter.Chief Risk Officer + insurance procurement. AI cyber-insurance underwriters (Munich Re,
Coalition, AIG, Beazley) are publicly demanding standardised evidence packages before
quoting a policy. squash insurance-package generates the package automatically from
existing squash artefacts โ no new data collection required.
squash demo discovers real GGUF models from
~/.ollama/models/ and scans them via the real AttestPipeline. Prefers small
models (smollm, qwen2.5, qwen3, tinyllama) for fast demo runs.squash demo --server if running.squash demo starts demo/server.py in the
background so the interactive section works immediately when the report opens.squash demo crash on Python 3.12+ โ duplicate diff and webhook subparser
registrations caused argparse.ArgumentError: conflicting subparser on every invocation.
Renamed old CycloneDX SBOM diff subcommand to sbom-diff and old K8s admission
webhook to k8s-webhook.TemporaryDirectory context exited before
the user could open the path. Output now persists at ~/Desktop/squash-demo/TIMESTAMP/.type: ignore comments removed from
clock.py, canon.py, edge_formats.py, scanner.py; risk.py type annotations
fixed (dict โ dict[str, Any]); pyproject.toml overrides added for non-Phase-G
modules (nist_rmf, model_card, report, integrations.kubernetes).google/osv-scanner-action@v1 tag deleted upstream;
bumped to @v2.0.2.cyclonedx-py was writing the SBOM into dist/
causing pypa/gh-action-pypi-publish to reject it as an invalid distribution;
moved to sbom/ subdirectory.upload-assets: true fails with Server Error when
triggered via workflow_dispatch (no release event context); set to false and
decoupled publish job from provenance success.squash demo Konjo Edition โ full animated rewrite of the sales demo CLI:
four-act Rich flow (Setup โ Scan โ Verdict โ Output), color-coded compliance score
panel, auto-opens HTML report in browser and output folder in Finder/Explorer.squash/demo_report.py โ self-contained HTML executive compliance summary
(15 KB, zero external deps, Konjo dark aesthetic matching demo/index.html).
WeasyPrint PDF export when available.--no-open, --no-color, --explore flags on squash demo.build-wheel.yml โ GitHub Actions workflow that builds a universal wheel on
every push to main and uploads it as a 14-day artifact for fast CI installs.[demo] optional-dep group โ pip install "squash-ai[demo]" pulls rich>=12.0
for the animated CLI experience.โCorrectness is the floor, not the ceiling.โ
Major version bump for the cryptographic-chain hardening lane: every Tier-0/1 attestation is now byte-identical on rerun, every signed payload flows through RFC 8785 canonical JSON, every cert ID is keyed on the input (uuid5, never uuid4), every clock is injectable, every release wheel + Docker image carries SLSA Build Level 3 provenance, and the entire chain โ input manifest โ canonical body โ Ed25519 โ RFC 3161 TSA โ SLSA โ is verifiable end-to-end via
squash self-verify.
squash/canon.py โ RFC 8785 (JCS) canonical JSON encoder.
Wraps the rfc8785 reference library when present; pure-stdlib
fallback otherwise. Rejects naive datetimes, non-finite floats,
non-string dict keys, and unknown types โ no silent default=str
coercion. Sets serialised sorted by their canonical-bytes key.squash/clock.py โ injectable Clock protocol with SystemClock
(production) and FrozenClock (tests). with_clock() context manager
squash/ids.py โ deterministic_uuid(payload) โ
uuid5(SQUASH_NS, canonical), cert_id(prefix, payload) โ
"{prefix}-{16-hex}". Project namespace pinned forever
(8b7c4a2e-1d3f-5e6a-9b8c-0d1e2f3a4b5c).squash/input_manifest.py โ SHA-256 every ingested file BEFORE
any analysis runs (Step 0 of every squash attest). Self-hashing
manifest schema squash.input-manifest/v1. verify_manifest()
re-hashes and compares.squash/tsa.py โ RFC 3161 trusted-timestamp client. Hand-rolled
DER TimeStampReq encoder (no third-party PKIX wrapper). Endpoint via
SQUASH_TSA_URL env var (default http://timestamp.digicert.com).squash/self_verify.py โ full chain walker.
input_manifest โ canonical body โ Ed25519 โ RFC 3161 โ SLSA.squash self-verify -d <dir> [--offline] [--json].squash verify --check-timestamp.AttestConfig.timestamp_with_tsa / tsa_url โ opt-in TSA
roundtrip; emits tsa_token.json. Master record now embeds
input_manifest_sha256.AUDIT_BASELINE.md ยง7, 22 line-items)attest.py, slsa.py, anchor.py, chain_attest.py,
hallucination_attest.py, drift_certificate.py, carbon_attest.py,
data_lineage.py, sbom_builder.py, oms_signer.py,
webhook_delivery.py โ every signed/anchored payload now flows
through squash.canon; every clock injectable; every cert ID via
squash.ids.cert_id.data_lineage.py:252 โ REPRODUCIBILITY KILLER FIX. cert_id no
longer mixes datetime.now() into the hash input.slsa.py._attach_to_bom โ now idempotent (no duplicate ext-refs).134 new Phase-G tests across 10 new files + 2 atheris fuzz harnesses:
test_canon_compat.py (26), test_clock.py (10), test_ids.py (9),
test_reproducibility.py (10), test_phase_g_property.py (11),
test_phase_g_negative.py (27), test_phase_g_edge.py (19),
test_phase_g_concurrency.py (5), test_phase_g_security.py (10),
test_phase_g_snapshot.py (9), plus tests/fuzz/fuzz_canon.py and
tests/fuzz/fuzz_input_manifest.py for the nightly 100K-iter run.
Test count: 5,226 โ 5,362 passing.
pyproject.toml โ mypy --strict override on the 6 Phase-G primitive
modules..bandit โ bandit config for bandit -r squash/ -ll..semgrep.yml โ 4 custom rules: squash-no-json-dumps-in-signing-paths,
squash-no-default-str, squash-no-utcnow, squash-no-uuid4-in-signed-body..github/workflows/ci.yml rebuilt with 6 jobs: test (3.10/3.11/3.12),
coverage with Tier-0 floor gate, reproducibility, mypy strict,
security (bandit + semgrep + pip-audit), CycloneDX SBOM artefact..github/workflows/nightly.yml โ rotating mutmut on Tier-0 modules
(6-day cycle), 100K-iter atheris fuzz, OSV-Scanner, perf baseline..github/workflows/publish.yml โ SLSA Build L3 via
slsa-framework/slsa-github-generator@v2.0.0. Three jobs: build,
provenance (delegated trusted builder), publish to PyPI via Trusted
Publishing..github/workflows/publish-image.yml โ provenance: mode=max +
actions/attest-build-provenance@v2 for OCI image attestations on GHCR.demo/demo.py โ 10-section runnable Python walkthrough.demo/server.py โ stdlib ThreadingHTTPServer exposing 8 real
squash endpoints. Boots in <1.2 s.demo/index.html โ interactive demo page (40 KB, dark Konjo
aesthetic). 5 interactive panels all hitting the real backend.squash demo --walkthrough / squash demo --server [--port N]
โ defer to the bundled demo/ scripts.AUDIT_BASELINE.md โ 22-point line-numbered fix list.TIER_MAP.md โ every squash/*.py classified Tier 0โ4 with
per-tier coverage / mutation / mypy / repro gates.SQUASH_MASTER_PLAN.md โ Phase G section with G.1 โ G.7 ticket
grid, execution status table, v3.0.0 exit criteria.action.yml โ adds plural policies input (recommended v3+ alias
for policy); both work, policies takes precedence when set.squash/__init__.py โ version drift fixed (was 0.9.14 vs
pyproject 2.7.0; both now 3.0.0).README.md โ adds Bulletproof Edition badges (Reproducibility,
SLSA L3, Scorecard, Sigstore, RFC 8785, RFC 3161).CLAUDE.md โ adds the KONJO acronym (Know ยท Outline ยท Nail ยท
Justify ยท Optimize) to the top.license_conflict.py split into database.py / scanner.py /
reporter.py โ 1,357-line refactor scheduled as a focused follow-up PR.โHow do we compare?โ โ Every enterprise QBR starts here. 8 sector baselines ยท percentile placement ยท k-anonymity ยท DP noise.
squash/benchmark.py โ 8 curated sector baselines (KPMG/Accenture/MIT Sloan/Clifford Chance, n=2,124), Gaussian CDF percentile engine, k-anonymity gate (MIN_K=5), DP noise (ฯ=5% range), ComplianceProfile, BenchmarkEngine, build_profile_from_registry(), load_result(), benchmark() one-liner.squash industry-benchmark report|compare|list-sectorsA multinational LLM deployment touches 6+ jurisdictions on average. Today the legal compliance mapping is a one-week consulting engagement per deployment. This compresses it into a single command.
squash/compliance_matrix.py โ full implementation:
Jurisdiction enum โ 11 codes (Global, EU, US, US-Fed, US-CO, US-NYC,
UK, SG, CA, AU, CN) with friendly aliases (usa โ US, singapore โ SG,
colorado โ US-CO, etc.).Requirement โ dataclass with jurisdictions, regulations, evidence
paths/files, severity, and four built-in rules: must_exist,
must_be_truthy, must_be_at_least (with threshold), custom.ComplianceMatrix.build() โ produces (requirement ร jurisdiction) โ
status matrix. Status is pass / fail / partial / n/a /
unknown. Reads evidence from a passed-in attestation dict and/or
a model directoryโs *.json artifacts.MatrixSummary โ pass/fail/partial/n/a/unknown counts +
coverage_pct over applicable cells.coverage_by_jurisdiction() โ per-jurisdiction pass percentage.GapAnalyser.plan() โ greedy coverage-per-fix sequencing: each
step is the squash control that addresses the largest number of
currently-failing cells; iterates until empty.to_text(), to_markdown(), to_json(), to_html() โ
HTML is pure Python with zero JavaScript dependencies, semantic
cell pass/fail/partial/na/unknown classes, severity-coloured
row borders, embedded remediation plan.load_attestation_dir() โ best-effort: load every *.json under a
model directory into a flat namespace keyed by file stem.squash compliance-matrix โ single-command:
--regions eu,us,uk,sg,ca (CSV; canonical codes or aliases)--models PATH (read squash artifacts from this directory)--attestation PATH.json (merge with โmodels)--format text|json|md|html ยท --output PATH ยท --model-id ID--remediation (append sequenced remediation plan)--fail-on-gap (exit 1 on any FAIL/PARTIAL โ CI gate)--list-jurisdictions ยท --list-requirementsload_attestation_dir (3), CLI handler
(9: missing/unknown regions, text/json/html/remediation outputs,
fail-on-gap exit code, list helpers, attestation file merge), parser
registration (1).EU AI Act Art. 9 + Art. 13 ยท NIST AI RMF ยท ISO 42001 ยง6 ยท GDPR Art. 30 ยท Colorado AI Act ยท NYC LL144 ยง1894 ยท SEC AI Operation Comply ยท FedRAMP AC-2 ยท FDA AI/ML Action Plan ยท UK ICO AI guidance ยท Singapore Model AI Governance Framework v2
1 user โ 50-user network effect. The GitHub App is the wedge that turns squash from a tool into infrastructure.
squash/github_app.py โ full GitHub App implementation:
GitHubAppConfig โ YAML/JSON config (App ID, private key, webhook
secret, model patterns, policies, listen host/port); load_config()
dump_config_template() round-trip; validate() returns a list
of human-readable errors.make_jwt() โ RS256 GitHub App JWT (stdlib + cryptography), no PyJWT
dependency; โค9-minute lifetime per GitHubโs reference value.GitHubAppAuth โ per-installation access-token cache with 60s leeway
invalidate() for forced rotation.GitHubAppClient โ urllib-based REST wrapper:
create_check_run, update_check_run, list_pull_request_files
(auto-paginated), get_commit. Raises GitHubApiError(status, msg).WebhookVerifier โ constant-time HMAC-SHA256 verification of the
X-Hub-Signature-256 header.ModelFileMatcher โ pattern-based decision (default 21 patterns:
*.safetensors, *.gguf, *.bin, *.pt, *.onnx, tokenizer*,
model_card.md, squash-attest.json, โฆ).AttestationRunner โ wraps squash.attest.AttestPipeline,
renders results as a Check Run output payload (markdown table of
policy verdicts, scan status, artefact list).AttestationOutcome โ passed/failed โ success/failure Check Run
conclusion.WebhookHandler โ dispatches pull_request (opened, synchronize,
reopened, ready_for_review), push (with branch-deleted skip), and
ping; clones repo at head_sha, runs runner, posts pending โ
completed Check Runs.clone_repo_at_sha() โ shallow git fetch + detached git checkout.serve() โ stdlib threading HTTP server with /healthz +
/webhook endpoints; HMAC-verified, JSON-bodied.squash github-app โ four subcommands:
serve --config app.yaml [--host โฆ] [--port โฆ]attest --config app.yaml --installation-id N --repo OWNER/NAME --sha SHA
[--paths โฆ] [--workdir โฆ] [--no-clone] [--dry-run] [--json]config --init PATH | --check PATH | --show-defaultsverify-webhook --secret S --signature 'sha256=โฆ' --body โฆ | --body-file โฆEU AI Act Art. 9 (post-market monitoring) ยท NIST AI RMF MEASURE 2 ยท ISO 42001 ยง9.1 (CI gating as preventive control)
squash freeze โ Emergency Response (W221-W222)โ The Red Button. Highest drama-per-hour ratio in the entire roadmap. 20% of organisations have a tested AI incident-response plan. This is one of them.
squash/freeze.py โ Emergency response orchestrator:
FreezeOrchestrator โ single-shot, atomically coordinates five existing
subsystems (attestation_registry, webhook_delivery, ledger, notifications,
incident) into one CLI commandFreezeStep enum โ REGISTRY_REVOKE / WEBHOOK_BROADCAST / LEDGER_LOG /
NOTIFICATION / INCIDENT_PACKAGEFreezeReceipt โ tamper-evident record (SHA-256 + Ed25519) of every freeze
invocation; to_json(), summary(), canonical_payload_bytes()freeze() โ module-level convenience entry pointread_ledger() โ append-only JSONL audit trail at
~/.squash/freeze_ledger.jsonlverify_receipt() โ Ed25519 signature check + tamper detectionsquash freeze โ three subcommands:
squash freeze --attestation-id att://โฆ --reason "CVE-2026-1234" (default)squash freeze --model-path ./model.safetensors --severity criticalsquash freeze ledger --limit 20squash freeze verify ./freeze_receipt.json--priv-key, --out, --format json|md|text, --no-incident,
--state-dir, --webhook-timeout, --actor, --reason, --severity,
--category, --affected-persons, --incident-dirsquash/webhook_delivery.py โ WebhookEvent.ATTESTATION_FROZEN addedsquash/notifications.py โ ATTESTATION_FROZEN constant + title templateEU AI Act Article 73 (serious incident reporting) ยท NIST AI RMF MANAGE 4.1 (incident response) ยท ISO 42001 ยง9.1 (corrective action)
92% of organisations lack full visibility into their AI identities. 73% of CISOs would invest immediately โ if the product existed. Now it does.
squash/identity_governor.py โ AI identity attestation engine:
IdentityPrincipal โ normalised identity model for all three providers
(AWS IAM, Azure AD, Okta); adapters never leak provider-specific typesLeastPrivilegePolicy โ declared minimum-necessary permissions; loads from JSON;
scaffold_policy() generates a starter fileLeastPrivilegeAnalyser โ 5 deterministic rule engine:
IdentityAttestation โ schema squash.identity.attestation/v1;
Ed25519 signed (same keypair as anchor/drift/hallucination certs);
to_json(), to_markdown(), summary(), load_attestation()IdentityGovernor โ orchestrator: principal โ analyse โ sign โ certsquash/integrations/aws_iam.py โ AWS IAM adapter; reads roles via boto3
(lazy-imported); normalises attached + inline policies as scopes; tag filtersquash/integrations/azure_ad.py โ Azure AD adapter; reads service principals
via Microsoft Graph REST (stdlib urllib โ no azure-identity SDK required);
credential age from passwordCredentials/keyCredentialssquash/integrations/okta.py โ Okta adapter; reads service apps + OAuth grants
via Okta REST API (stdlib urllib); label filtersquash attest-identity โ 4 subcommands:
attest --provider aws-iam|azure-ad|okta|file --principal NAME [--policy FILE]
[--priv-key KEY] [--fail-on-violation] [--out PATH] [--format json|md|text]verify <cert.json> โ Ed25519 signature checklist-principals --provider ... [--filter LABEL]policy-init --principal NAME [--out FILE]NIST AI RMF GOVERN 1.1 ยท EU AI Act Art. 9 ยท SOC 2 CC6.1 ยท FedRAMP AC-2 ยท CIS Controls v8 Control 5 ยท OWASP Agentic AI AA3
EU AI Act Article 9(1)(f) requires post-market monitoring throughout the AI system lifecycle. 18% production hallucination rate ยท 39% of chatbots reworked in 2024.
squash/hallucination_monitor.py โ Runtime hallucination monitor:
RequestSampler โ configurable sample-rate (default 5%) interceptor; scores live
request/response pairs; thread-safe; zero overhead on unsampled requestsRollingWindow โ fixed-size append-only ring buffer (default 1000 entries); JSONL
persisted so the monitor survives restarts; Wilson 95% CI on demand; since= filterscore_live_response() โ three modes: grounded (full C7 scorer with GT), RAG
context-only (token overlap against context), black-box (structural heuristics:
absolute claim detection, hedging language, entity density)BreachEngine โ confirmed breach requires BOTH point estimate > threshold AND CI lo
threshold; prevents false alarms from small samples; fires
on_breachcallback
notify_breach() โ routes breach events to existing webhook_delivery + logs to
attestation_registry (no new storage format)score_batch() โ offline/cron scoring of collected request/response pairsbuild_monitor_report() โ OK / WARN / BREACH status reportrun_monitor() โ daemon and --once cron modessquash hallucination-monitor โ 4 subcommands:
run --endpoint URL [--sample-rate 0.05] [--threshold 0.10] [--once]score --response TEXT [--context TEXT] [--ground-truth TEXT]status [--state-dir PATH]batch --requests-file requests.json [--fail-on-breach]C7 attests a model pre-deploy on a fixed probe set. C10 monitors live traffic continuously โ EU AI Act Art. 9 post-market monitoring obligation.
$67.4B in 2024 AI hallucination losses ยท 47% of executives made decisions on hallucinated content.
squash hallucination-attestconverts this into a signed domain-calibrated certificate.
squash/hallucination_attest.py โ Signed hallucination rate certificate:
verify_certificate() for tamper detectionmock:// for offline testingsquash hallucination-attest attest|verify|show|list-probes
--fail-on-exceed flag for CI gatingSOC 2 Type II is the most-requested item in enterprise procurement (MEDDPICC). Without it, most $50K+ ACVs cannot proceed to contract. Sprint 18 wraps squashโs existing building blocks โ signed attestations, hash-chained audit log, policy engine, RBAC, uptime monitoring โ in the AICPA Trust Services Criteria and produces an auditor-ready evidence bundle on demand.
# Coverage report across all 65 TSC controls
squash soc2 readiness
# Filter to specific category or status
squash soc2 readiness --category CC --status PARTIAL --json
# Build auditor-ready ZIP evidence bundle
squash soc2 evidence --output ./evidence/ --window 365
squash/soc2.py (NEW) โ complete SOC 2 Type II readiness engine (W218โW220):
W218 โ 65-control TSC catalogue with squash mappings:
W219 โ EvidenceCollector:
EvidenceCollector.collect_all(catalogue) โ per-control ControlDossierwindow_days parameter: 365 for Type II (default), 1 for Type I point-in-timeControlDossier.to_dict() / to_markdown() โ per-control evidence narrativeW220 โ CLI + ZIP evidence bundle:
Soc2CoverageReport.build() โ coverage stats + category bars + gap/partial listsSoc2EvidenceBundle.build() โ auditor-ready ZIP:
controls_index.json โ all 65 controls with statuscoverage_summary.md โ human-readable reportdossiers/{ID}_evidence.json + *.md โ one pair per control (130 files)attestations/ โ last 10 signed attestation payloadsSHA256SUMS โ SHA-256 integrity manifest for every file (independently verifiable)squash/cli.py โ squash soc2 readiness + squash soc2 evidence:
--window, --json, --category filter, --status filter--output, --window, --no-attestationsKey squash โ TSC mappings:
| TSC Control | Squash Component | Status |
|---|---|---|
| CC6.1 Logical Access | auth.py + oms_signer.py + Sigstore | COVERED |
| CC6.8 Malicious Software | scanner.py + adapter_scanner.py | COVERED |
| CC7.2 Monitoring | governor.py hash-chained audit log | COVERED |
| CC7.4 Incident Response | incident.py + squash freeze | COVERED |
| CC8.1 Change Management | slsa.py + approval_workflow.py | COVERED |
| CC9.2 Vendor Risk | vendor_registry.py + procurement_scoring.py | COVERED |
| PI1.1โPI1.4 Processing | attest.py + attestation_registry.py | 4/4 COVERED |
Module count: 99 โ 100 (soc2.py).
New buyer: General Counsel. The GC approving an AI model for content generation, legal drafting, or code assistance needs a signed certificate answering three questions: What is the derivation chain? What copyright-heavy training sources exist? Has the model memorised copyrighted text?
squash genealogy --model ./model --deployment-domain legal-drafting
squash genealogy --model ./model --endpoint http://localhost:8080/v1/complete
squash genealogy --model ./model --block-on-contamination
squash copyright-check --model ./model --deployment-use commercial
squash copyright-check --model ./model --json --fail-on-incompatible
Stats: 60 new tests ยท 0 regressions ยท 4416 passing ยท 78 โ 80 modules
Every Fortune 500 procurement team is writing AI vendor questionnaires. They take 4 weeks each. Sprint 28 turns the Trust Package into a queryable API โ the credit-score equivalent for AI compliance. Whoeverโs score the buyer asks for becomes the de facto standard.
# Query the score for any vendor (public, no auth required)
curl https://squash.works/v1/score/acme-corp
# โ {"score": 87.4, "tier": "VERIFIED", "frameworks": ["eu-ai-act","iso-42001"], ...}
# Get score breakdown (Pro plan)
curl -H "Authorization: Bearer sq_live_..." https://squash.works/v1/score/acme-corp
# โ {..., "breakdown": {"compliance_score": 92.0, "freshness": 85.0, ...}}
# Score history time-series (Enterprise)
curl -H "Authorization: Bearer sq_live_..." https://squash.works/v1/score/acme-corp/history
# Embeddable badge SVG for vendor README
<img src="https://squash.works/v1/score/acme-corp/badge" />
# CLI โ local registry scoring
squash score acme-corp --local --breakdown
squash score acme-corp --local --history --json
squash/procurement_scoring.py (NEW) โ complete scoring engine:
ProcurementScorer.score_vendor(vendor) โ VendorScore with five-component score:
AttestationRegistryVendorRegistry| Tier thresholds: CERTIFIED โฅ 90 | VERIFIED โฅ 75 | BASIC โฅ 50 | UNVERIFIED < 50 |
score_history(vendor, months=12) โ monthly time-series snapshotsbadge_svg(vendor, score, tier) โ embeddable shields.io-style SVGsquash/api.py โ 3 new endpoints (W246โW247):
GET /v1/score/{vendor} โ public, unauthenticated; returns basic score + tier; Pro unlocks breakdown field; Enterprise unlocks historyGET /v1/score/{vendor}/history โ authenticated; Pro = 3 months; Enterprise = 12 monthsGET /v1/score/{vendor}/badge โ public SVG badge (avoids path conflict with existing /badge/{framework}/{status})/v1/score/* endpoints added to public path prefix (IP rate-limit only, no API key required)squash/cli.py โ squash score <vendor> (W248):
--breakdown โ per-component scores--history / --months N โ time-series--local โ query local registry (offline, no API call)--api-url โ override squash API base URL--json โ structured outputFreemium model:
| Field | Unauthenticated | Pro | Team | Enterprise |
|---|---|---|---|---|
| score + tier | โ | โ | โ | โ |
| breakdown | โ | โ | โ | โ |
| history | โ (402) | 3 months | 3 months | 12 months |
Module count: 96 โ 99 (procurement_scoring.py + concurrent sprints).
New buyer motion: Chief Risk Officer + insurance procurement. AI cyber-insurance is crystallising in 2026. Underwriters demand standardised evidence packages before quoting. Squash generates the whole submission in one command.
squash insurance-package --models-dir ./models --org "Acme Corp"
squash insurance-package --models-dir ./models --zip ./insurance-bundle.zip
squash insurance-package --models-dir ./models --json --underwriter munich-re
squash/insurance.py (NEW MODULE โ W235โW236):
ModelRiskProfile โ per-model: risk tier (HIGH/MEDIUM/LOW), compliance score, CVE count, drift events, incident count, bias status, last_attested, attestation_id, scan_status, control presence flagsInsurancePackage โ aggregate: risk score 0โ100, compliance score, response-plan status, total models, risk distribution, to_json/to_markdown/save/save_zipInsuranceBuilder.build(models_dir, org_name) โ reads squash artefacts (attest, scan, VEX, drift, incident, bias, lineage, annex IV) from model dir tree; graceful degradation when artefacts absentrisk = 100 โ compliance_score + 20ร(critical_cves>0) + 10ร(scan_unsafe) + 10ร(drift>5) + 15ร(incidents>0) + 20ร(no_policy), clipped [0,100]Multi-model discovery โ auto-detects per-model subdirectories or single-model root
MunichReAdapter (W236) โ Munich Re AI cyber schema: 5 control domains (Technical Security, Operational Excellence, AI Governance, Data Quality Provenance, Incident Resilience) each rated AโD, overall AI Maturity Level 1โ4, coverage recommendation (STANDARD / ENHANCED / SPECIALIST)CoalitionAdapter (W236) โ Coalition AI Risk Assessment: 5 categories (AI Model Security, AI Operational Risk, AI Governance, AI Incident History, Third-Party AI Risk) scored 0โ100 with weighted aggregate; assessment text per categoryGenericAdapter (W236) โ flat, field-rich schema for underwriters without a published formatsquash/cli.py โ squash insurance-package first-class command (W237):
--models-dir PATH (default: cwd)--org NAME--output-dir DIR (writes insurance-package.{json,md})--zip PATH (writes signed ZIP bundle with integrity manifest)--json (structured JSON to stdout)--underwriter {munich-re,coalition,generic} (print specific format with โjson)--quietsave_zip()): 6 files + integrity.sha256 SHA-256 manifest:
insurance-package.json ยท insurance-munich-re.json ยท insurance-coalition.json ยท insurance-generic.json ยท insurance-executive-summary.md ยท integrity.sha256tests/test_squash_sprint24.py (NEW) โ 48 tests:
insurance.py) ยท 77 โ 78 modulesinsurance-package) with 7 flagsThe ESG / sustainability office is a new buyer motion. CSRD applies to all large EU companies from 2025. Squash carbon attestation is the machine-readable, cryptographically signed proof these frameworks demand.
# BERT-base in Ireland, 100K inferences/day
squash attest-carbon \
--model-id bert-base \
--params 110M \
--region eu-west-1 \
--hardware a100 \
--inferences-per-day 100000 \
--csrd --sign
# 7B model in Stockholm (green grid) vs Sydney (coal)
squash attest-carbon --model-id llama-7b --params 7B --region eu-north-1 --json
squash attest-carbon --model-id llama-7b --params 7B --region ap-southeast-2 --json
# Enrich existing ML-BOM with energy fields
squash attest-carbon --model-id bert-base --params 110M --region us-east-1 --bom ./mlbom.json
squash/carbon_attest.py (NEW) โ complete carbon + energy attestation engine:
W259 โ FLOP estimator ร carbon intensity ร compute engine:
estimate_flops(param_count, architecture, seq_len) โ 6 architecture families: transformer (2ยทNยทL, Kaplan 2020), MoE (2ยท(N/8)ยทL sparse routing), embedding (capped L=128), diffusion (2ยทNยทT_steps, T=20), CNN (2ยทN), RNN (2ยทNยทL)lookup_grid_intensity(region, cache, live) โ 90+ regions covering all major AWS/GCP/Azure zones + ISO country codes; live Electricity Maps API with SQLite cacheestimate_energy(flop_estimate, hardware, utilization, tokens, pue) โ kWh/inference, kWh/1M-tokensCarbonAttestation.compute(...) โ gCOโeq/inference, kgCOโeq/day, tCOโeq/year (location + market-based), HMAC-SHA256 signedW260 โ CSRD/CSDDD/UK PRA/OMB-DOE/EU AI Act field mapping:
to_csrd(renewable_energy_fraction, scope3_embodied_factor) โ ESRS E1-4/E1-5 Scope 2 (location + market-based) + Scope 3 estimated fieldsto_regulatory(framework) โ csrd |
csddd | uk_pra_ss1_23 | omb_doe | eu_ai_act |
W261 โ ML-BOM CycloneDX enrichment + CLI:
enrich_mlbom(bom_path, cert) โ injects environmentalConsiderations.squash_carbon into first component; adds squash-carbon-attestation external reference; idempotentsquash/cli.py โ squash attest-carbon subcommand:
--model-id, --params (int or shorthand 110M/7B/1.5T), --region, --architecture, --hardware--inferences-per-day, --tokens-per-inference, --seq-len, --utilization, --pue--renewable-fraction, --live-intensity (Electricity Maps)--sign, --output, --bom (ML-BOM enrichment), --csrd, --framework, --jsonGrid intensity table covers 90+ regions:
Module count: 86 โ 88 (carbon_attest.py; 2 additional modules added by concurrent sprints).
78% of executives canโt pass an AI governance audit in 90 days.
squash simulate-audit closes that gap in 60 seconds. Mock regulatory
examination from the examinerโs perspective โ answers pulled from squash
attestation data, gaps flagged, prioritised remediation roadmap included.
squash simulate-audit --regulator EU-AI-Act --models-dir ./model
squash simulate-audit --regulator NIST-RMF --json
squash simulate-audit --regulator SEC --output-dir ./compliance/
squash simulate-audit --regulator FDA --fail-below 60
squash/audit_sim.py (NEW MODULE โ W229โW230):
ExamQuestion โ q_id, article, question, answer_sources, answer_cli, weight (1โ3), category, days_to_closeExamAnswer โ status (PASS/PARTIAL/FAIL/N/A), evidence_found/missing, gap_description, remediationReadinessReport โ overall_score, readiness_tier, answers, roadmap, executive summary; to_json(), to_markdown(), save()AuditSimulator.simulate(model_path, regulator) โ ReadinessReportsquash/cli.py โ squash simulate-audit first-class command (W231):
--regulator {EU-AI-Act,NIST-RMF,SEC,FDA} (default: EU-AI-Act)--models-dir PATH (default: cwd)--output-dir DIR (writes audit-readiness.{json,md})--json (structured JSON to stdout)--fail-below N (exit 1 if score < N โ CI gate)--quiettests/test_squash_sprint22.py (NEW) โ 48 tests:
audit_sim.pySQUASH_MASTER_PLAN.md โ Track C / C5 marked shippedaudit_sim.py) ยท 76 โ 77 modulessimulate-audit) with 6 flagsOpenAI / Anthropic / Google / Meta / Mistral sunset models quarterly. Every sunset breaks a version-tied Annex IV record. Most teams discover deprecations the day inference returns a 404. Squash deprecation-watch fires alerts before that day arrives.
# Scan asset registry against all 5 provider feeds
squash deprecation-watch --lead-time 30
# Check a specific model
squash deprecation-watch --check gpt-4-0613
# List all known deprecations as JSON
squash deprecation-watch --list --json
# Alert on Slack, fail CI if any alerts
squash deprecation-watch --alert-channel slack --fail-on-alert
squash/deprecation_watch.py (NEW) โ complete deprecation watch engine (W265):
DeprecationEntry โ provider, model_id, aliases, sunset_date, impact (BREAKING/SOFT/INFORMATIONAL), successor_model, days_until_sunset, is_sunsetted, matches() with segment-aware prefix matchingDeprecationAlert โ asset ร entry match with days_remaining, migration_effort, re_attestation_checklist, is_urgent(), summary()DeprecationStore โ SQLite cache (~/.squash/deprecation_cache.db) for entries + scan historyDeprecationWatcher โ main engine: load_feeds(), scan(), check_model(), list_entries()Migration effort estimator (W266): heuristic based on impact ร environment ร risk tier โ CRITICAL (BREAKING + prod + high-risk) โ HIGH โ MEDIUM โ LOW
Re-attestation checklist (W266): per-model checklist with squash-specific commands (squash attest, squash publish, squash annex-iv generate, squash iso42001, etc.)
Alert routing (W266): route_alerts() โ stdout |
slack | json; delegates Slack to squash/notifications.py |
squash/cli.py โ squash deprecation-watch subcommand:
--lead-time DAYS (default 30), --provider, --check MODEL_ID, --list--model-ids (comma-sep, bypass registry), --alert-channel, --checklist--json, --fail-on-alert, --include-informational, --include-sunsettedModule count: 85 โ 86 (deprecation_watch.py). All count guards updated.
Turns squash from a quarterly compliance tool into a daily intelligence service. Poll SEC.gov, NIST.gov, EUR-Lex, and any custom RSS feed for new AI governance requirements, map them to squash policy controls, and surface gap analysis against the local model portfolio โ all from a single cron-friendly command.
# One-shot poll (add to cron)
squash watch-regulatory --once --models-dir ./models --alert-channel slack
# 6-hour daemon
squash watch-regulatory --interval 6h --alert-channel slack
# Custom state legislature feed
squash watch-regulatory --once --extra-feed name=legiscan,url=https://...,keywords=artificial+intelligence
# Dry run โ see what would surface without persisting
squash watch-regulatory --once --dry-run --json
squash/regulatory_watch.py (NEW MODULE โ W243โW244):
RegulatoryEvent โ event_id, source, title, url, published, summary, severity, fetched_atGapAnalysisResult โ maps event โ matched_reg_ids, squash_controls, models_to_re_attest, recommended_actionsWatcherConfig โ sources, extra_feeds, timeout, max_events, alert_channel, db_pathSecAdapter โ SEC press-release RSS; AI-relevance filteredNistAdapter โ NIST CSRC publications RSS; AI-relevance filteredEurLexAdapter โ EUR-Lex Official Journal RSS; AI-relevance filteredGenericRssAdapter โ any RSS 2.0 or Atom feed with configurable keyword filter_parse_rss): namespace-aware Atom + RSS 2.0 parser (stdlib only); AI-relevance keyword filter (18 terms); severity scoring (HIGH/MEDIUM/LOW) from title + source~/.squash/regulatory_events.db): event IDs persisted; second poll returns 0 new events for already-seen items; mark_all_seen() for bulk catch-upgap_analysis(event, models_dir)):
regulatory_feed.py per matched regulationmodels_dir that should be re-attesteddays_to_act from the regulationโs enforcement deadlinesquash.notifications for Slack/Teams/webhook channelsparse_interval() โ parse '6h', '1d', '30m', bare secondssquash/cli.py โ squash watch-regulatory first-class command (W245):
--once / --interval INTERVAL (cron-friendly / continuous-daemon)--sources {sec,nist,eurlex} (repeatable; default: all three)--extra-feed name=NAME,url=URL[,keywords=k1+k2] (repeatable)--models-dir DIR (gap analysis against local attestations)--alert-channel {stdout,slack,teams,webhook}--db-path PATH (override default ~/.squash/regulatory_events.db)--dry-run (fetch without persist; shows what would surface)--json (structured JSON: new_events count + full gap_results array)--max-events N (per-poll cap; default 50)--quiettests/test_squash_sprint27.py (NEW) โ 63 tests:
parse_interval (6h, 1d, 30m, plain seconds, empty, invalid)_http_get; per-source graceful failureRegulatoryWatcher: first-poll returns all, second-poll deduplicates, new event on third poll surfaces, mark_all_seen, load_historysummary_text, to_dictregulatory_watch.pySQUASH_MASTER_PLAN.md โ Track C / C4 marked shippedregulatory_watch.py) ยท 75 โ 76 moduleswatch-regulatory) with 10 flagsThe CISO leave-behind that closes deals. A fully branded executive PDF from squash annex-iv generate --branded with cover page, KPI scorecard, exec summary, full Annex IV body, and signature block. WeasyPrint-based; degrades to an HTML preview when WeasyPrint is absent.
squash annex-iv generate --root ./model \
--system-name "BERT Sentiment Classifier" \
--format pdf \
--branded \
--org "Acme Corp" \
--author "ML Platform Team" \
--output-dir ./compliance/
squash/pdf_report.py (NEW MODULE) โ complete branded PDF engine:
BrandedPDFConfig(org_name, author, logo_path, accent_color, include_cover, include_exec_summary, include_signature, confidentiality_label)PDFReportBuilder(config).build_html(doc) โ full HTML string (preview without WeasyPrint)PDFReportBuilder(config).build_from_document(doc) โ raw PDF bytesPDFReportBuilder(config).save(doc, output_dir, stem) โ writes *.pdf + *.html; degrades to HTML-only when WeasyPrint is absent<script>, <style> injection impossiblesquash/templates/annex_iv_branded.css (NEW) โ 370-line WeasyPrint-compatible CSS:
@page rules with running headers (@top-right confidentiality label, @bottom-right page counter, @bottom-center document title)cover (zero margins), exec-summary (custom top margin), default body#22c55e accent, #0a0f1a navysquash/templates/squash-logo-dark.svg + squash-logo-light.svg + squash-logo-mark.svg (NEW brand assets) โ Squash wordmark extracted from marketing site design; embedded inline in the cover page
squash/cli.py โ squash annex-iv generate gains --branded, --org, --author, --logo, --accent flags:
--branded โ triggers PDFReportBuilder after the normal save; WeasyPrint absence is a warning, not an error--org NAME โ organisation name on cover--author NAME โ preparer name on cover--logo PATH โ custom SVG/PNG logo (replaces Squash wordmark)--accent HEX โ brand accent override (default #22c55e)tests/test_squash_w208_pdf_report.py (NEW) โ 47 tests:
save(): WeasyPrint mock path, graceful degradationModule count: 74 โ 75 (pdf_report.py + templates/ directory with 3 SVGs + 1 CSS โ only pdf_report.py counts as a Python module)
LoRA adapters are perceived as โsmall therefore low-risk.โ They are not. A LoRA adapter is a complete behavioural rewrite in megabytes. JFrog Security (2024) found ~100 malicious models on HuggingFace, several establishing reverse-shell on load. This sprint ships the first dedicated adapter security gate in the compliance-as-code ecosystem.
# Block any non-safetensors adapter outright (policy gate)
squash scan-adapter --lora ./adapter.pt --require-safetensors
# โ rc=2, CRITICAL: --require-safetensors violated
# Scan a safetensors adapter with signed certificate
squash scan-adapter --lora ./adapter.safetensors --sign
# โ CLEAN ยท 2 tensors ยท 0 findings ยท Certificate: adapter-squash-adapter-scan.json
# Full JSON report for CI integration
squash scan-adapter --lora ./adapter.safetensors --json
# โ {"risk_level": "CLEAN", "findings": [], "adapter_hash": "...", ...}
squash/adapter_scanner.py (new module) โ complete standalone adapter scanner:
detect_format(path) โ magic-byte detection of safetensors vs. pickle vs. unknownscan_pickle_opcodes(path) โ GLOBAL, REDUCE, STACK_GLOBAL, NEWOBJ scan without deserialisationscan_shell_patterns(path) โ text-pattern sweep for injection strings (safe on any format)parse_safetensors_header(path) โ header integrity + out-of-bounds offset detection_analyse_tensors(path, tensors) โ per-tensor stats: mean, std, kurtosis, l2_norm, NaN/Inf_compute_concentration(stats) โ layer-concentration score (single layer > 85% of total L2 norm)scan_adapter(path, require_safetensors, sign, output_path) โ AdapterScanReportsquash-adapter-scan.json certificate (HMAC-SHA256 of report payload)squash/cli.py โ squash scan-adapter command:
--lora <path> โ adapter file to scan--require-safetensors โ exit rc=2 if adapter is not safetensors format--sign โ embed HMAC-SHA256 signature in certificate JSON--output <path> โ custom certificate output path--json โ emit full JSON report to stdout for CI parsingThreat model covered (W257):
| Threat | Detection | Severity |
|---|---|---|
| Pickle / PyTorch format | PK-001 GLOBAL/REDUCE/STACK_GLOBAL opcodes | CRITICAL |
| Pickle without explicit opcodes | PK-002 inherent execution risk | HIGH |
--require-safetensors policy violation |
PK-003 format gate | CRITICAL |
| Shell injection strings in any format | SH-001 pattern sweep | CRITICAL |
| safetensors OOB read vector | ST-006 offset > file size | CRITICAL |
| Malformed safetensors header | ST-001โST-004 integrity checks | CRITICAL |
| NaN / Inf weights | WD-001/WD-002 float sentinel check | HIGH |
| Kurtosis anomaly (spike weights) | WD-003 excess kurtosis > 8 | HIGH/MEDIUM |
| High-value target (embed_tokens/lm_head) large magnitude | WD-004 | HIGH |
| Layer concentration (backdoor in one layer) | WD-005 > 85% L2 in single tensor | MEDIUM |
Statistical thresholds tuned against (W258):
| Clean kurtosis threshold: | kurtosis | < 8 for all 3 clean fixtures |
Module count: 73 โ 74 (adapter_scanner.py)
The passive-retention surface. Squash stays in front of the CISOโs eyes between active sessions. A weekly or monthly portfolio email lands in the inbox with five-metric posture, top-5 risk movers, and the August 2 countdown โ no dashboard login required.
# Cron-friendly stdout dump (no SMTP needed)
squash digest send --period weekly --dry-run --models-dir ./models
# Render-only preview (text / HTML / JSON)
squash digest preview --models-dir ./models --format html --output ./digest.html
# Send via any SMTP (Resend / Mailgun / SES / direct)
SQUASH_SMTP_HOST=smtp.resend.com SQUASH_SMTP_FROM=ciso-digest@acme.com \
squash digest send --period weekly --org "Acme ML" \
--recipients ciso@acme.com --recipients vp-eng@acme.com \
--dashboard-url https://app.getsquash.dev/acme
squash/notifications.py extension โ ComplianceDigestBuilder (W209):
ComplianceDigest dataclass โ period, subject, summary, top_movers,
deadlines, html_body, text_body, dashboard_url, org_nameDigestMover โ model_id, score, score_delta, violations, CVEs,
risk tier, drift flag, last_attestedDigestDeadline โ label, ISO date, days_remaining; sorted
soonest-first; past deadlines bury at the endComplianceDigestBuilder.build(period, models_dir|dashboard, org_name,
dashboard_url, score_history, deadlines, now):
dashboard.Dashboard (no new data sources)score_history is supplied<style> / <link> / <script> / javascript:, table-based
layout, no remote images, no JS, defensive Outlook-friendlysquash/notifications.py โ SMTP send path (W209):
SmtpConfig dataclass with env-var fallbacks (SQUASH_SMTP_HOST,
_PORT, _USER, _PASSWORD, _FROM, _TLS); is_configured
property gates the live sendsend_email_digest(digest, recipients, smtp, dry_run):
multipart/alternative MIME message with
both bodies, opens stdlib smtplib.SMTP with optional STARTTLS,
sends to all recipients, surfaces SMTP errors as a structured
DigestSendResultSQUASH_SMTP_* at the providerโs SMTP relay โ zero
provider-specific code in squashsquash/cli.py โ squash digest preview / squash digest send (W210):
digest commandpreview โ renders to stdout (default text) or to file;
--format text|html|json; --output FILEsend โ emails via SMTP; --recipients (repeatable),
--dry-run, --smtp-host, --smtp-port, --smtp-from,
--no-tls_add_common_digest_args:
--period {weekly,monthly}, --models-dir, --org,
--dashboard-url, --score-history JSON_FILE, --quiettests/test_squash_w209_w210_digest.py (NEW) โ 37 tests covering:
to_dict() round-tripis_configured predicatesmtplib.SMTP mocked at the import
boundary to verify starttls+login+sendmail calls,
no-credentials path, error propagation--output
file write, --score-history happy + bad-input paths, send
--dry-run with and without recipients, unconfigured SMTP exits 1squash/notifications.py โ adds digest types + SMTP path at the
end of file; existing NotificationDispatcher semantics unchangedsquash/cli.py โ adds digest command with two subcommandsSQUASH_MASTER_PLAN.md โ Track B / B3 marked shipped alongside
Sprint 15 W209/W210notifications.py
and cli.py. Module count unchanged.The Konjo discipline this sprint: 0 new modules. The dashboard
already had every metric needed; B3 is purely a render layer + a
delivery layer over the existing telemetry. No graveyards, no parallel
data path, no provider-specific code (Resend / Mailgun / SES are all
SMTP relays โ no need to write a Resend adapter when stdlib smtplib
already works against any of them). The --dry-run flag exposes the
exact same render the live send produces โ โpreviewโ and โsendโ are
the same code path branching on whether to hit the network. ๊ฑด์กฐ
applied to the surface area: one builder, two delivery paths, one CLI.
The first Track B parallel item. The free top-of-funnel growth tool any ML engineer can run against any public HuggingFace model in one command โ no login, no enterprise SaaS, no sales call. Squashโs brand-builder on the platform with the largest concentration of ML engineers in the world.
squash scan hf://meta-llama/Llama-3.1-8B-Instruct
squash scan hf://microsoft/phi-3@v2.0 --policy enterprise-strict --output-dir ./out
squash scan hf://acme/private --hf-token $HF_TOKEN --download-weights
squash/hf_scanner.py (NEW MODULE โ W205):
HFRef / RepoMetadata / HFScanReport dataclassesparse_hf_uri(uri) โ strict URI parser supporting
hf://owner/model[@revision] form (revisions can include / for
branch names like feat/my-branch)is_hf_uri(s) โ cheap predicate, no network callHFScanner.scan(uri, ...) โ orchestrator that:
huggingface_hub,snapshot_download to a temp directory (light mode by
default โ skips weight files; opt-in via download_weights=True),HfApi.model_info (license,
downloads, last_modified, library_name, pipeline_tag, tags, sha),ModelScanner.scan_directory against the snapshot,PolicyEngine.evaluate,HFScanReport with to_json() /
to_markdown() / save() methods,keep_download=Truegetsquash.dev for self-serve installsquash/cli.py โ squash scan hf://... integration (W205):
_cmd_scan now detects hf:// prefix on the positional argument
and routes to a new _cmd_scan_hf handler โ no new subcommand,
just a transparent extension of the existing squash scanhf:// mode:
--policy POLICY (repeatable) โ policy preview to evaluate--output-dir DIR โ where to write squash-hf-scan.{json,md}
(default: cwd)--download-weights โ opt into full weight download (default
light mode skips weights โ keeps the public scanner fast and cheap)--keep-download โ retain the temp directory after scan--hf-token TOKEN โ HF Hub token for private/gated repos;
falls back to HUGGING_FACE_HUB_TOKEN / HF_TOKEN env--quiet โ suppress non-essential output--json-result and --sarif flags now also apply
to the hf:// path--exit-2-on-unsafe)tests/test_squash_w205_hf_scanner.py (NEW) โ 40 tests covering:
is_hf_uri predicate)RepoMetadata.to_dict + HFScanReport JSON / Markdown
serialisation including findings-table truncation at 25 + policy
preview tablesave() writes both JSON + MarkdownHFScanner.scan() with huggingface_hub mocked at the
sys.modules import boundary โ tests revision is forwarded,
light-mode default skips weights, --download-weights lifts the
filter, keep_download=True preserves the temp dir, missing
huggingface_hub raises clean ImportErrorhuggingface_hub before squash.cli imports it โ tests
help surface, malformed URI rc=2, clean scan writes both
artefacts, policy preview lands in the JSON, @revision carried
through, local-path regression guard confirms existing
behaviour is untouchedtest_squash_model_card.py,
test_squash_wave49.py, test_squash_wave52.py,
test_squash_wave5355.py, test_squash_sprint11/12/13.py) all bumped
71 โ 72 with explanatory comments noting the gate now tracks current
count rather than sprint-snapshot count.SQUASH_MASTER_PLAN.md โ Track B / B1 marked shipped
alongside Sprint 14 W205.squash/hf_scanner.py) ยท 71 โ 72 modulessquash scan (hf:// mode)The Konjo discipline this sprint: B1 is the highest-leverage parallel
item that depends only on the existing scanner + policy modules. Same
calendar week ships A1/A2 (Track A) + C1 (Track C) too โ exactly the
parallelisation insight the master plan codifies. The hf:// path
extends squash scan rather than introducing a new top-level
subcommand: one user-facing entry point, two backends, zero learning
overhead. Light-mode default (no weight download) keeps the public
scanner fast & cheap; --download-weights is opt-in for users who
want the full security audit. ๊ฑด์กฐ applied to the surface area.
squash/washing_detector.py โ AI washing detection engine (W223-W225 / Track C / C2):
Claim Extractor (ClaimExtractor, 28 patterns across 9 claim types)
Deterministic regex-based extraction over Markdown, HTML, plain text, PDF, DOCX.
Pattern taxonomy covers: ACCURACY_CLAIM (benchmarks, error rates), COMPLIANCE_CLAIM
(EU AI Act, GDPR, HIPAA, NIST RMF, SOX), CERTIFICATION_CLAIM (ISO 42001, FedRAMP,
SOC 2), SAFETY_CLAIM (no hallucinations, bias-tested, safe-for-clinical),
FAIRNESS_CLAIM (unbiased, demographic parity), DATA_CLAIM (training data size/source,
no-PII), SECURITY_CLAIM (pen-tested, no backdoors, enterprise-grade),
SUPERLATIVE_CLAIM (worldโs first, outperforms GPT-4, 100% guaranteed),
CAPABILITY_CLAIM (medical diagnosis, legal advice, financial recommendations).
95.7% recall on the 50-claim SEC/FTC enforcement benchmark โ above the 90% spec target.
Divergence Engine (DivergenceEngine, 12 cross-reference rules)
Cross-references extracted claims against AttestationEvidence (master_record.json,
bias_audit.json, data_lineage.json). Four finding types:
FACTUAL_MISMATCH (CRITICAL): claim contradicts signed attestation evidence
(e.g. โEU AI Act compliantโ when eu-ai-act score = 38/100)UNSUPPORTED_CLAIM (HIGH): claim type has a known evidence requirement and
no evidence existsUNDOCUMENTED_SUPERLATIVE (CRITICAL/MEDIUM): absolute claims without verifiable basisTEMPORAL_MISMATCH (HIGH): compliance claim backed by attestation >90 days oldRules: EU AI Act/GDPR/HIPAA/NIST/ISO 42001 score thresholds; passed=False gate; no-hallucination absolute claim always flagged; bias audit required for fairness/bias-safety claims; PII absence requires data lineage; security scan required for security claims; security scan FAIL โ CRITICAL; high-stakes domains (medical/legal/ financial) always CRITICAL regardless of attestation state; staleness check (90-day window).
Report (WashingReport) โ schema squash.washing.report/v1;
CLEAN/LOW/MEDIUM/HIGH/CRITICAL verdict; to_json(), to_markdown(), summary();
JSON round-trip via load_report(). Every finding names its rule_id, legal_risk,
and specific remediation โ handed directly to legal counsel without translation.
Evidence Loader (load_evidence, AttestationEvidence) โ loads and normalises
master_record.json, bias_audit.json, and data_lineage.json into a typed evidence
object with framework score lookup (with canonical aliases for all framework variants).
squash detect-washing โ 2 subcommands:
scan <doc_paths...> [--master-record PATH] [--bias-audit PATH] [--data-lineage PATH]
[--model-id ID] [--format text|json|md] [--fail-on low|medium|high|critical]report <report.json> โ render a saved reporttests/test_washing_detector.py โ 38 tests:
SEC โOperation AI Complyโ (2024) produced enforcement actions. The SECโs 2026
examination priorities list AI-related disclosures as a top-tier focus.
squash detect-washing is the first ML compliance tool that compares prose
capability claims against signed attestation evidence automatically.
squash/license_conflict.py โ SPDX licence conflict engine (W196 / B10):
Knowledge Base (LicenseKnowledgeBase / resolve_spdx)
73 SPDX identifiers + 9 AI model custom licences fully described: permissive
(MIT, Apache-2.0, BSD variants, CC0), weak copyleft (LGPL, MPL-2.0),
strong copyleft (GPL-2.0/3.0), network copyleft (AGPL-3.0), ShareAlike
(CC-BY-SA-4.0, ODbL-1.0), non-commercial (CC-BY-NC family), and AI custom
licences (LLaMA 2/3, Gemma, Mistral, BLOOM/OpenRAIL, Falcon, Code Llama).
Canonical alias map normalises variant spellings (gpl3, apache2, llama2, etc.)
and gracefully falls back to LicenseRef-unknown for unresolved identifiers.
SPDX Expression Parser (LicenseExpression)
Compound SPDX expressions: MIT OR Apache-2.0, GPL-2.0-only WITH
Classpath-exception-2.0. Picks the most permissive option from OR-joined
choices using a kind-score ordering โ no regex abuse, explicit token split.
12 Conflict Rules (ConflictChecker)
| Rule | Description |
|โโ|โโโโ-|
| LC-001 | Non-commercial licence in commercial/SaaS deployment (CRITICAL) |
| LC-002 | AGPL network-copyleft trigger in SaaS API (HIGH) |
| LC-003 | Strong copyleft in closed-source commercial product (HIGH) |
| LC-004 | ShareAlike dataset may contaminate model weights (MEDIUM, unsettled law) |
| LC-005 | NoDerivatives licence โ fine-tuning prohibited (HIGH) |
| LC-006 | LLaMA 2 commercial use threshold (MEDIUM, flagged for awareness) |
| LC-007 | LLaMA 2/3 competing-product prohibition (HIGH) |
| LC-008 | Gemma competing-model prohibition (MEDIUM) |
| LC-009 | BLOOM/OpenRAIL use-restriction clauses (MEDIUM) |
| LC-010 | Unknown/unresolved licence โ all rights reserved (HIGH) |
| LC-011 | GPL-2.0-only incompatible with Apache-2.0 (HIGH) |
| LC-012 | Version-locked copyleft mixing (e.g. GPL-2.0-only + GPL-3.0-only) (HIGH) |
Scanner (LicenseScanner)
Walks project trees extracting licences from: requirements.txt,
pyproject.toml, package.json, Cargo.toml, LICENSE/COPYING
files (text-sniffing), model card README.md (YAML frontmatter), model
config.json/master_record.json, dataset_infos.json, and provenance
JSON. tomllib (Python 3.11+) or tomli for TOML; graceful skip on Python
3.9/3.10 without it. Curated licence map for 45+ well-known packages.
Obligation Extractor (extract_obligations)
Attribution requirements, source-disclosure obligations, AGPL network-user
source rights, LLaMA โBuilt with Meta Llamaโ attribution โ all surfaced as
actionable strings in the report.
Report (LicenseConflictReport)
Schema squash.license.conflict.report/v1; CLEAN/LOW/MEDIUM/HIGH/CRITICAL
risk; to_json(), to_markdown(), summary(); JSON round-trip via
load_report().
squash license-check โ 3 subcommands:
scan <path> [--use-case research|commercial|open_source|saas_api|internal|government] [--format text|json|md] [--fail-on medium|high|critical]explain <SPDX_ID> โ print full metadata for any known licencereport <report.json> โ render a saved reporttests/test_license_conflict.py โ 55 tests covering all 12 conflict
rules, knowledge base, expression parser, scanner, obligations, end-to-end
clean/conflicted projects, JSON round-trip, and CLI smoke.squash/data_poison.py โ six-layer training data poisoning scanner (W195 / B9):
Layer 1 โ Threat Intelligence (ThreatIntelChecker)
Cross-references dataset file hashes against a curated registry of known-poisoned
and known-compromised datasets. Definitive detection with zero false positives on
a match. Seed set covers Badnets SST-2, Hidden Killer clean-label, and documented
HuggingFace supply-chain incidents.
Layer 2 โ Label Integrity (LabelIntegrityChecker)
Shannon entropy analysis, class imbalance ratio (flagged at >50x), and per-class
Z-score spike detection (flagged at z > 4). Reads CSV/TSV/JSONL label files.
Label-flipping attacks always leave an entropy signature detectable by this layer.
Layer 3 โ Duplicate Injection Detection (DuplicateDetector)
SHA-256 content-hash duplicate rate per file. Adversarial sample amplification
(inserting the same poisoned sample N times) is flagged at >5% duplicate rate
(MEDIUM) and >20% (HIGH). Covers JSONL, CSV, TSV, and plain text.
Layer 4 โ Statistical Outlier Detection (OutlierDetector)
Z-score analysis on numerical feature columns (threshold z > 5). Adversarially
crafted inputs lie off the data manifold and are extreme outliers. Constant
columns (synthetic data indicator) are also flagged. Numpy-accelerated with
stdlib statistics fallback for air-gapped environments.
Layer 5 โ Backdoor Trigger Pattern Scan (TriggerPatternScanner)
Searches for 9 known NLP backdoor trigger tokens (Badnets cf, Hidden Killer
mn, instruction-tuning poison tq, zero-width space, BOM markers, GPT special
tokens). Also detects Unicode homoglyph character mixing (Latin + Cyrillic/Greek
in the same token โ the invisible-trigger attack class from Boucher et al. 2022).
Layer 6 โ Provenance Chain Integrity (ProvenanceIntegrityChecker)
Flags missing provenance records, file modification timestamps post-dating claimed
creation dates, and suspicious source URL patterns (Mega.nz, Pastebin, anonfiles,
darkweb/onion domains).
Aggregation โ weighted risk score โ CLEAN / LOW / MEDIUM / HIGH / CRITICAL.
CRITICAL check hit immediately elevates report regardless of aggregate score.
Prioritised remediations generated per flagged layer.
squash data-poison โ 2 subcommands:
scan <dataset_path> [--format text|json|md] [--out PATH] [--fail-on low|medium|high|critical] [--provenance PATH]report <report.json> โ render a previously saved reporttests/test_data_poison.py โ 39 tests covering all six layers, end-to-end
clean/poisoned datasets, JSON round-trip, Markdown render, and CLI smoke.
Module count gates updated (71โ72); full suite clean.squash/drift_certificate.py โ Drift SLA Certificate generator (W194 / Tier 3 B7):
DriftSLASpec โ typed SLA contract: model, framework, min_score, window_days,
max_violation_rate, min_snapshots, org. Input validation on all parameters.ScoreLedger โ append-only JSONL ledger of compliance score snapshots per model per
framework. Populated from master_record.json files via ingest() or directly via
add_snapshot(). Supports time-window, model, and framework filtering.SLAEvaluator โ computes SLA result over a ledger slice: passes/fails, compliance
rate, score stats (min/max/avg/p10), violation count, contiguous violation windows.
Mathematically exact: violation rate is per-snapshot, not per-calendar-day bucket.ViolationWindow โ contiguous run of below-threshold snapshots with min score.DriftCertificate โ signed certificate envelope with squash.drift.certificate/v1
schema marker; body_dict() produces the canonical signed surface (excludes sig/key);
to_markdown(), to_html(), to_json() renderers; HTML is print-ready for PDF via
weasyprint.DriftCertificateIssuer โ signs certificates with Ed25519 (same keypair as
LocalAnchor); public key embedded in envelope; verify() detects tampered spec,
tampered result, unknown schema, and unsigned certs.load_certificate() โ round-trip JSON deserialiser.SQUASH_DRIFT_LEDGER env var for CI/air-gap ledger path override.squash drift-cert โ 5 subcommands:
ingest <master_record.json> โ append snapshot to ledgerissue --model --framework --min-score --window [--priv-key] [--out] [--format]verify <cert.json> โ signature + self-consistency checkshow <cert.json> โ human-readable Markdown renderexport <cert.json> --format md|html|pdf โ export certificatetests/test_drift_certificate.py โ 30 tests:
violation_rate = violations / snapshots is computed to full float precision,
not rounded to a daily bucket. A certificate is wrong or it is right โ no rounding mode.squash/anchor.py โ Merkle-tree audit-trail anchoring (W193 / Tier 3 #29):
MerkleTree โ domain-separated (RFC 6962) binary Merkle tree; pure stdlib SHA-256;
odd-level duplicate-tail to prevent phantom-node attacks; O(n) build, O(log n) proof.MerkleProof โ frozen, self-contained inclusion proof that verifies with stdlib only;
no squash code, no network, no trust in the issuer beyond holding their public key.LocalAnchor โ Ed25519 signature over root || leaf_count || timestamp;
public key embedded in the anchor record so verifiers need no separate key fetch;
works in air-gapped / FedRAMP environments; signing payload is canonical JSON.OpenTimestampsAnchor โ submits Merkle root to the Bitcoin-backed OTS aggregator
network; produces a .ots file; verification via ots verify at a Bitcoin node.EthereumAnchor โ posts root as EVM calldata (0x73717368 magic + 32-byte root +
uint64 leaf_count) via Foundry cast; chain-agnostic (mainnet, Base, Optimism, Polygon);
verifiable by anyone with cast tx <hash> input.AnchorLedger โ append-only JSONL ledger (~/.squash/anchor/); stageโcommitโverify
workflow; export_proof() emits a portable, self-contained squash.anchor.proof/v1
doc that a third party can verify with 30 lines of stdlib Python.canonical_json() + hash_attestation() โ deterministic attestation hashing;
two organisations producing semantically identical attestations get bit-identical hashes,
enabling cross-organisation verification.verify_proof() โ standalone reference verifier; the auditorโs side of the protocol.squash anchor โ 6 subcommands:
add <master_record.json> โ stage into pending batchcommit --backend local|opentimestamps|ethereum โ build Merkle root + anchorverify <attestation_id> โ Merkle inclusion + backend witness checkproof <attestation_id> [--out PATH] โ emit portable proof JSONlist โ all committed anchors (ANSI + --json)status โ pending batch + last anchortests/test_anchor.py โ 23 tests:
verify_proof() with no ledger accessSQUASH_ANCHOR_DIR env override; CLI subcommand registration; status on empty ledgercryptography, already in the squash tree.integrations/terraform/ โ full Terraform provider in Go, built on
terraform-plugin-framework v1.13.0:
squash_attestation resource โ runs squash attest, captures the
master record JSON, exposes attestation_id, overall_score,
passed, framework_scores, SBOM/signature paths. Replacement on
model_path change preserves an immutable provenance trail.squash_policy_check resource โ declarative compliance gate; fails
terraform apply when score drops below min_score or when
require_passed = true and the upstream attestation did not pass.
Lets a regression block every dependent resource via the dependency
graph (no admission controller required).squash_compliance_score data source โ read an existing
master_record.json without re-running the pipeline; surfaces
top_frameworks for compact downstream gating.cli_path, models_dir, policy, api_key
(sensitive), offline โ every field has an env-var fallback for
CI/air-gap parity.internal/squashcli/ โ stdlib-only core (zero external deps).
Argv builder + master-record JSON parser + injectable Runner
interface. Tested offline; the package the FedRAMP / CMMC story
rests on.go test -race -count=1.make build / make install / make test / make test-core.integrations/terraform/pulumi/ โ Pulumi parity:
examples/typescript and examples/python show the
@pulumi/command shell-out pattern that works today.integrations/terraform/examples/):
basic โ single model, signed, gated.multi-model-gate โ for_each over a model registry.data-source-gate โ gate a deploy on a CI-produced record.integrations/terraform/docs/:
index.md, resources/attestation.md, resources/policy_check.md,
data-sources/compliance_score.md.integrations/terraform/terraform-registry-manifest.json โ
protocol v6 manifest for Terraform Registry publication.terraform apply, no
goroutines, no daemons, no background workers.squash/annual_review.py โ Annual AI System Compliance Review Generator (W182):
AnnualReviewGenerator.generate(): 12-month compliance review from model directoriessquash annual-review --year 2025 [--models-dir ./models] [--json] CLIsquash/attestation_registry.py โ Public Attestation Registry (W183):
AttestationRegistry.publish(): SHA-256 attestation fingerprinting; att:// URI schemeatt://attestations.getsquash.dev/org/model_id/entry_id URI formatAttestationRegistry.verify(): re-hashes stored payload; detects tamperingAttestationRegistry.revoke(): marks attestation revoked; verify returns INVALIDAttestationRegistry.lookup(): filter by model_id, org, or entry_id~/.squash/attestation_registry.db); remote-ready architecturesquash publish / squash lookup / squash verify-entry CLIsquash/dashboard.py โ CISO / Executive Terminal Dashboard (W184):
Dashboard.build(): scans model directories; computes 5 key metrics--json output for VS Code webview consumptionsquash dashboard [--models-dir ./models] [--json] [--no-color] CLIsquash/regulatory_feed.py โ Regulatory Intelligence Feed (W185):
squash regulatory status/list/updates/deadlines subcommands--since DATE filter for change log; --days N for deadline window--json output on all subcommandssquash/due_diligence.py โ M&A / Investment AI Due Diligence Package (W186):
DueDiligenceGenerator.generate(): comprehensive AI compliance snapshotsquash due-diligence --company AcmeCorp [--deal-type investment] CLIvscode-extension/ โ VS Code Extension (W187):
package.json โ full VS Code Marketplace manifest:
squash-sidebar containersquash.cliPath, squash.defaultPolicy, squash.autoAttest,
squash.showStatusBar, squash.apiKey, squash.modelsDirsquash.runAttestationsrc/extension.ts โ TypeScript implementation (~350 lines):
ModelPortfolioProvider / ViolationsProvider / DeadlinesProvider tree viewsrunSquash() subprocess wrapper (calls squash CLI with configurable path)squash dashboard --json output*.{gguf,bin,safetensors,pt,pth} with auto-attesttsconfig.json โ TypeScript compiler config (ES2022, Node16 modules)package.json, extension.ts, tsconfig.json)squash/cli.py โ 9 new commands: annual-review, publish, lookup,
verify-entry, dashboard, regulatory (+4 subcommands), due-diligencetests/test_squash_model_card.py โ module count gate updated 60 โ 65SQUASH_MASTER_PLAN.md โ Sprint 8 complete; situation report updated to v1.3.0vscode-extension/)squash/vendor_registry.py โ AI Vendor Risk Register (W178):
VendorRegistry: SQLite-backed register of all third-party AI vendorsVendorRiskTier: CRITICAL / HIGH / MEDIUM / LOW risk tieringQuestionnaireGenerator: 36-question due-diligence questionnaire per risk tier
(Model Governance, Training Data, Security, Bias & Fairness, Data Handling,
Explainability, Human Oversight, Incident Response, Attestation)import_trust_package(): verify vendor Trust Packages and record compliance scoresquash vendor add/list/questionnaire/import-trust-package/summary CLIsquash/asset_registry.py โ AI Asset Registry (W179):
AssetRegistry: SQLite-backed inventory of every AI model in the organizationsync_from_attestation(): auto-populates from squash attestation artifactssquash registry add/sync/list/summary/export CLIsquash/data_lineage.py โ Training Data Lineage Certificate (W180):
DataLineageTracer.trace(): traces datasets from model config / provenance files / MLflowsquash data-lineage [--datasets ...] [--fail-on-pii] [--fail-on-license] CLIsquash/bias_audit.py โ Algorithmic Bias Audit (W181):
BiasAuditor.audit(): computes 5 fairness metrics across all protected attribute groupsBiasAuditReport with signed audit ID and data hashsquash bias-audit --predictions pred.csv --protected age,gender
--standard nyc_local_law_144 [--fail-on-fail] CLIsquash/cli.py โ 8 new commands: vendor (with 5 subcommands), registry (with 5 subcommands), data-lineage, bias-audittests/test_squash_model_card.py โ module count gate updated 56 โ 60SQUASH_MASTER_PLAN.md โ Sprint 7 complete; Sprint 8 roadmap added (W182โW187)squash/iso42001.py โ ISO/IEC 42001:2023 AI Management System readiness assessment (W170):
Iso42001Assessor.assess(): 38-control gap analysis covering Clauses 4โ10 and Annex AReadinessLevel enum: CERTIFIED_READY / SUBSTANTIALLY_COMPLIANT / PARTIAL / EARLY_STAGEsquash iso42001 ./model [--format json] [--fail-below SCORE] CLI commandtests/test_squash_sprint5.pysquash/trust_package.py โ Signed vendor attestation bundle exporter + verifier (W171):
TrustPackageBuilder.build(): bundles CycloneDX ML-BOM, SPDX, NIST RMF, VEX, SLSA, ISO 42001 report into signed ZIP with SHA-256 manifestTrustPackageVerifier.verify(): integrity check of all artifacts + manifest in <10 secondssquash trust-package ./model --output vendor.zip [--sign] [--model-id ID] CLIsquash verify-trust-package vendor.zip [--json] [--fail-on-error] CLIsquash/agent_audit.py โ OWASP Agentic AI Top 10 (December 2025) compliance audit (W172):
AgentAuditor.audit(): audits all 10 agentic AI risks from any agent manifest formatsquash agent-audit ./agent.json [--fail-on-critical] [--format json] CLIsquash/incident.py โ AI incident response package generator (W173):
IncidentResponder.respond(): structured incident package with attestation snapshot, EU AI Act Article 73 disclosure, drift delta, and remediation planIncidentSeverity enum: critical โ serious โ moderate โ minor (with regulatory threshold mapping)IncidentCategory enum: 10 categories (bias_discrimination, pii_exposure, prompt_injection, etc.)squash incident ./model --description "..." [--severity serious] [--affected-persons N] CLIsquash/board_report.py โ Executive AI compliance board report generator (W174):
BoardReportGenerator.generate(): quarterly board report from model portfoliosquash board-report --quarter Q2-2026 [--models-dir ./models] [--output-dir ./report] [--json] CLIsquash/cli.py โ 7 new commands: iso42001, trust-package, verify-trust-package, agent-audit, incident, board-reporttests/test_squash_model_card.py โ module count gate updated from 51 โ 56 (Sprint 5 +5 modules)SQUASH_MASTER_PLAN.md โ Sprint 5 roadmap + Sprint 7 (Enterprise Moat) waves W178โW187 added; market intelligence section added with structural market shift analysis ($340M โ $4.83B TAM)pyproject.toml โ Development Status :: 5 - Production/Stable; stripe>=8.0 billing extra; PEP 561 py.typed; expanded keywords and classifiersREADME.md overhaul (W157) โ Tagline โSquash violations, not velocity.โ; squash demo as first command; Sprint 4B feature table; Startup tier ($499/month); Prometheus sample; compliance badge examplesfly.toml โ Production hardening: min_machines_running=1, 512MB/2vCPU, /metrics scrape config, rolling deployDockerfile โ OCI labels, curl healthcheck, stripe>=8.0, sentry-sdk[fastapi], PYTHONDONTWRITEBYTECODEPOST /billing/checkout (W155) โ Stripe Checkout session creation: plans pro/startup/team/enterprise, returns {checkout_url, session_id, plan} (HTTP 201), 422 on invalid plansquash/billing.py โ Startup + Team tiers in plan map (SQUASH_STRIPE_PRICE_STARTUP, SQUASH_STRIPE_PRICE_TEAM)website/ โ Next.js 14 + Tailwind landing page (W156): live countdown, terminal demo, feature grid, pricing table, Vercel deploy configdocs/launch/hn-post.md (W158) โ Show HN post draft with title options, body, anticipated Q&Adocs/launch/devto-article.md (W158) โ Full Dev.to article draftdocs/launch/design-partner-outreach.md (W159) โ 3 email templates, pitch call script, target list, design partner termssquash/py.typed โ PEP 561 typed package markertests/test_squash_w155.pySQUASH_MASTER_PLAN.md Sprint 4B section for full details.action.yml โ GitHub Actions composite action v1.0 (W145):
model-path (required), policies, sign, fail-on-violation, api-key, output-dir, annex-iv, squash-version.passed, score, artifacts-dir, bom-digest.actions/setup-python@v5, pip install squash-ai, squash attest, optional Annex IV generation, actions/upload-artifact@v4 (90-day retention).shield, color=blue.@main refs explicitly forbidden by test gate.integrations/gitlab-ci/squash.gitlab-ci.yml โ GitLab CI template (W147):
.squash_attest (base), .squash_attest_soft (allow_failure), .squash_attest_full (sign + Annex IV + multi-policy).SQUASH_POLICIES, SQUASH_SIGN, SQUASH_FAIL_HARD, SQUASH_ANNEX_IV, SQUASH_VERSION, SQUASH_OUTPUT_DIR.squash_result.json always saved.integrations/jenkins/vars/squashAttest.groovy โ Jenkins shared library step (W148):
squashAttest(modelPath:, policies:, sign:, failOnViolation:, outputDir:, annexIv:, squashVersion:, apiKey:).withCredentials() for API key; readJSON for result parsing; unstable() on violation.squash-attestation) for downstream stages..github/workflows/publish-image.yml โ GHCR Docker image publish workflow (W149):
workflow_dispatch.latest, branch, semver major/minor, SHA short.docker run.secrets.GITHUB_TOKEN (no PAT required).integrations/kubernetes-helm/ โ Helm chart for Kubernetes admission controller (W150):
Chart.yaml: apiVersion v2, type application, appVersion 0.9.14.values.yaml: replicaCount=2, image=ghcr.io/konjoai/squash, webhook.port=8443, failurePolicy=Ignore, excludeNamespaces=[kube-system], policies=[eu-ai-act], podSecurityContext.runAsNonRoot=true.templates/deployment.yaml: liveness+readiness probes on /health, TLS cert volume mount, SQUASH_API_TOKEN from secret ref.templates/service.yaml: ClusterIP on 443 โ 8443.templates/validatingwebhookconfiguration.yaml: admissionReviewVersions=[v1], namespaceSelector exclusions, cert-manager annotation support.templates/_helpers.tpl, templates/serviceaccount.yaml, templates/rbac.yaml.squash/integrations/mlflow.py โ MLflowSquash.attest_run() fully wired: AttestPipeline.run() โ mlflow.log_artifacts() โ mlflow.set_tags() with squash.* namespace tags.squash.passed, squash.scan_status, per-policy squash.policy.<name>.passed/errors.output_dir defaults to model_path.parent / "squash".squash/model_card.py: datetime.UTC โ datetime.timezone.utc (Python 3.10 compat, caused 17+ test failures).squash/api.py: datetime.UTC โ datetime.timezone.utc in _ts_now(); Retry-After header added to IP-rate-limit 429 responses.tests/test_squash_model_card.py: path fixed from squish/squash โ squash, module count updated to 47; squish.squash.cli โ squash.cli in CLI subprocess tests.squash/auth.py โ DB-backed API key management (W137):
KeyStore: thread-safe in-memory + optional SQLite persistence; SHA-256 key hashing (never plaintext).KeyRecord: plan-aware monthly_quota, rate_per_min, quota_remaining.generate(), verify(), revoke(), update_plan(), increment_attestation_count(), reset_quota().POST /keys (create), DELETE /keys/{key_id} (revoke) HTTP endpoints.get_key_store() / reset_key_store() for test isolation.squash/rate_limiter.py โ Per-key plan-based sliding-window rate limiter (W138):
X-RateLimit-Limit / X-RateLimit-Remaining response headers on every authenticated request.SQUASH_API_TOKEN still works as ops bypass; DB keys take priority.Dockerfile + fly.toml + .github/workflows/deploy.yml โ Fly.io deployment (W139):
squash user, port 4444, Docker HEALTHCHECK.iad region, 256MB RAM, auto-stop, rolling deploy strategy.FLY_API_TOKEN secret; concurrency guard.squash/postgres_db.py โ PostgreSQL (Neon) cloud DB connector (W140):
PostgresDB with psycopg2, same interface as CloudDB; JSONB columns for tenant + event records.make_postgres_db() factory reads SQUASH_DATABASE_URL; graceful SQLite fallback when absent.tenants, event_log (with index), api_keys tables โ all IF NOT EXISTS.squash/billing.py โ Stripe subscription integration (W141):
verify_stripe_signature() โ HMAC-SHA256 with 300s clock tolerance.StripeWebhookHandler: checkout.session.completed (upgrade), subscription.updated/deleted (plan sync), invoice.payment_failed (no immediate downgrade).POST /billing/webhook endpoint bypasses API key auth; Stripe-Signature verified internally.squash/quota.py โ Monthly attestation quota enforcement (W142):
QuotaEnforcer.check() before pipeline; consume() after successful attestation.QuotaCheckResult with X-Quota-Used / Limit / Remaining response headers./attest returns HTTP 429 with quota details when limit exhausted.GET /account/status + GET /account/usage โ Authenticated account endpoints (W143):
squash/monitoring.py โ Sentry error tracking + health endpoints (W144):
setup_sentry(): reads SQUASH_SENTRY_DSN, no-op when absent or sentry-sdk not installed.build_health_report(): DB liveness probe, uptime, version, component status dict.GET /health/ping โ "pong" (Better Uptime monitor target).GET /health/detailed โ full health report; 503 when degraded. Both bypass auth.squash annex-iv generate CLI command โ Sprint S1 exit gate:
--root DIR: auto-discovers TensorBoard logs, training configs, Python scripts; runs full W128โW133 artifact extraction pipeline.--format md html json pdf: selectable output formats (default: md json).--system-name, --version, --risk-level {minimal,limited,high,unacceptable}: Annex IV ยง1(a) and ยง4 metadata.--mlflow-run, --wandb-run ENTITY/PROJECT/RUN_ID, --hf-dataset (repeatable): optional cloud augmentation; all fail gracefully with warnings.--no-validate, --fail-on-warning: pipeline-mode control.squash annex-iv validate PATH: reconstruct and re-validate any annex_iv.json; exit 2 on hard fail, 1 on warning (with --fail-on-warning).tests/test_squash_w135.py.squash/annex_iv_generator.py โ EU AI Act Annex IV document generator:
AnnexIVGenerator.generate(result, *, system_name, version, ...) โ produces a complete 12-section AnnexIVDocument from ArtifactExtractionResult (W128-W132 outputs) + supplemental metadata kwargs.โ
Full / โ ๏ธ Partial / โ Missing badges.AnnexIVDocument.to_markdown() โ human-readable, version-controllable, diff-friendly Markdown with header table, section badges, metric tables, code blocks.AnnexIVDocument.to_html() โ standalone HTML with embedded professional CSS (print-ready, dark branded header, score badge color-coded to compliance level). Falls back to minimal MDโHTML if markdown package absent.AnnexIVDocument.to_json() โ machine-readable export with all sections, completeness scores, gaps, and summary block.AnnexIVDocument.to_pdf(path) โ PDF via weasyprint (optional dep); raises ImportError cleanly when absent.AnnexIVDocument.save(output_dir, formats, stem) โ multi-format save; PDF failure silently skipped.AnnexIVValidator.validate(doc) โ ValidationReport: hard-fails on ยง1(a)/ยง2(a)/ยง3(a) below threshold; warnings on ยง3(b)/ยง5/ยง6(a)/overall; bias gap triggers Art. 10(2)(f) warning. report.is_submittable = no hard fails.ValidationReport.summary() โ one-line status string for CLI output.tests/test_squash_w133.py: 83 tests โ badge thresholds, weighted scoring, all 12 sections full/empty/partial, Markdown structure, JSON roundtrip, HTML structure, save() multi-format, validator hard-fails and warnings, full pipeline integration.squash/code_scanner_ast.py โ new module (zero external deps, stdlib ast only):
CodeArtifacts dataclass โ ยง1(c) evidence: imports, framework, optimizers, loss functions, model classes, data loaders, checkpoint ops, training loop patterns, requirements.ImportRecord โ per-import record with module, names, alias, purpose classification, line number.OptimizerCall โ optimizer instantiation with short_name, framework, extracted constant kwargs (lr, weight_decay, etc.), line number.CodeScanner.scan_source(source, path) โ scan Python source string; handles SyntaxError gracefully.CodeScanner.scan_file(path) โ scan a single .py file; handles missing files gracefully.CodeScanner.scan_directory(root, pattern) โ recursive directory scan.CodeScanner.merge(artifacts) โ merge multiple per-file artifacts, deduplicating imports by module, setting framework from merged import list.CodeScanner.scan_requirements(path) โ parse requirements.txt / pyproject.toml โ package spec list.CodeScanner.scan_training_run(root) โ end-to-end: scan all .py files + auto-discover requirements files.nn, F, Keras, and generic names โ all underscore-normalized for uniform matching.torch.save, save_pretrained, save_model, save_weights, model.save(), pickle.dump, etc.DataLoader, load_dataset, DataPipe, ImageFolder, etc.model.fit, trainer.train, for epoch in range(...) loop.from_pretrained() calls + model = SomeClass(...) assignment heuristic.ArtifactExtractor.from_training_script(path) โ CodeArtifacts wrapper.ArtifactExtractor.from_training_directory(root) โ merged CodeArtifacts wrapper.ArtifactExtractionResult.code: CodeArtifacts | None field added; is_empty() updated; to_annex_iv_dict() emits section_1c from code when present (preferred over TrainingConfig).from_run_dir() updated to auto-discover .py files and populate result.code.tests/test_squash_w132.py: 107 tests โ AST helper units, pattern matchers, full script scans (PyTorch/TF/HuggingFace/JAX/MLX), edge cases, file/dir/merge/requirements scanning, Annex IV ยง1(c) structure, wrapper integration. Zero mocking, zero network, zero external deps.DatasetProvenance dataclass โ structured EU AI Act Annex IV ยง2(a) evidence: license, languages, task categories, size, source datasets, split info, bias analysis flag, citation, provenance timestamps.DatasetProvenance.completeness_score() โ weighted 0โ100 scoring aligned with Article 10(2) obligations. Weights: description (20), license (20), languages (15), source_datasets (15), task_categories (10), size_category (10), bias_analysis (5), citation (5).DatasetProvenance.completeness_gaps() โ returns list of missing field labels for auditor gap reports.DatasetProvenance.annex_iv_section_2a() โ full ยง2(a) evidence block including bias analysis block with actionable note when missing.ArtifactExtractor.from_huggingface_dataset(dataset_id, *, token, revision) โ DatasetProvenance: HfApi.dataset_info() for structured metadata + DatasetCard.load() for README bias/citation extraction. Card load failure handled gracefully.ArtifactExtractor.from_huggingface_dataset_list(dataset_ids) โ list[DatasetProvenance]: multi-dataset extraction with partial-failure fallback records.ArtifactExtractionResult.datasets: list[DatasetProvenance] field added; is_empty() and to_annex_iv_dict() updated to include section_2a._has_bias_content(): EU AI Act Art. 10(2)(f) keyword scanner (bias, fairness, demographic, underrepresented, discrimination, etc.)_extract_citation(): BibTeX entry extractor from README text._parse_hf_tags(): namespace:value splitter for HuggingFace raw tags._build_dataset_provenance(): assembles DatasetProvenance from HfApi DatasetInfo + card content.tests/test_squash_w131.py: 73 tests โ keyword detection, BibTeX extraction, tag parsing, completeness scoring, gap reporting, ยง2(a) structure, mock HfApi integration, card load failure, partial list failure, all three Annex IV sections in combined dict output.ArtifactExtractor.from_wandb_run(run_id, *, entity, project, include_system_metrics) โ TrainingMetrics: single-pass scan_history() streaming โ O(1) memory, all series built in one traversal. W&B timestamps are already in seconds (no conversion needed). None values and non-numeric entries silently skipped. System metrics (system/) excluded by default, opt-in via flag. Addresses Annex IV ยง3(b).ArtifactExtractor.from_wandb_config(run_id, *, entity, project) โ TrainingConfig: strips _wandb internal config keys before extraction. Addresses Annex IV ยง1(c).ArtifactExtractor.from_wandb_run_full(...) โ ArtifactExtractionResult: single api.run() call โ no duplicate round-trips. Both Annex IV sections from one path._build_wandb_path(): normalises run_id / entity / project into the canonical "entity/project/run_id" path W&B Api expects; full paths passed through verbatim._extract_wandb_metrics() / _extract_wandb_config(): private helpers for single-object extraction, composable by from_wandb_run_full.tests/test_squash_w130.py: 54 tests โ path construction, single-pass streaming, None-skip, system metric opt-in, _wandb key stripping, single api.run() call assertion, ImportError paths, Annex IV routing. Pure mocks, zero credentials, zero network.ArtifactExtractor.from_mlflow_run(run_id, tracking_uri) โ TrainingMetrics: full metric history via MlflowClient.get_metric_history(), msโs wall_time conversion, sorted by step. Addresses Annex IV ยง3(b).ArtifactExtractor.from_mlflow_params(run_id, tracking_uri) โ TrainingConfig: run params with numeric string coercion (int, float, bool). Addresses Annex IV ยง1(c).ArtifactExtractor.from_mlflow_run_full(run_id, tracking_uri) โ ArtifactExtractionResult: both metrics and config in one call, single MlflowClient round-trip._coerce_mlflow_param(): type coercion for MLflowโs string-typed params.file:// tracking URI supported โ no MLflow server required in CI.tests/test_squash_w129.py: 55 tests โ coercion unit tests, full metric history, multi-step, wall_time seconds, metadata fields, ImportError paths, Annex IV section routing. Uses local file-store fixtures, no live credentials.squash/artifact_extractor.py: Annex IV artifact extraction engine โ ArtifactExtractor, TrainingMetrics, TrainingConfig, MetricSeries, ArtifactExtractionResultArtifactExtractor.from_tensorboard_logs(): zero-dependency native TFRecord binary reader + fast path via tensorboard SDK; extracts all scalar series for Annex IV ยง3(b)ArtifactExtractor.from_training_config(): YAML / JSON / TOML training config parser; extracts optimizer, scheduler, training loop settings for Annex IV ยง1(c)ArtifactExtractor.from_config_dict(): parse already-loaded config dict (MLflow params, W&B config, etc.)ArtifactExtractor.from_run_dir(): auto-discover .tfevents.* + config files in a training run directorytests/test_squash_w128.py: 50 tests โ binary parser unit tests, round-trip TFRecord, nested config extraction, auto-discovery, Annex IV section structure validationkonjoai/squish into standalone konjoai/squash repository via git filter-repo with full git history preservedsquish.squash import paths updated to squash across 112 source filesimport squish version references replaced with import squash as squish in sbom_builder.py, attest.py, spdx_builder.pysquash/__init__.py updated: standalone docstring, __version__ = "0.9.14" addedpyproject.toml: standalone squash-ai package, Apache 2.0 license, modular extras (api, signing, sbom, integrations, dev)CLAUDE.md: squash-specific contributor conventions (squash hard rules, compliance framework coverage, API contracts)SQUASH_MASTER_PLAN.md: master GTM plan from zero to $10M ARR committed to repoREADME.md: developer-first landing page with EU AI Act countdown framing.github/workflows/ci.yml: pytest matrix (Python 3.10/3.11/3.12), ruff lint, security audit.github/workflows/publish.yml: trusted PyPI publishing on releasesquash/nist_rmf.py: NIST AI RMF 1.0 controls scanner (NistRmfScanner, 42 controls across GOVERNยทMAPยทMEASUREยทMANAGE)Extracted with full git history. See git log --oneline for complete wave history.
For full history prior to repo separation, see konjoai/squish git history.