github MakazhanAlpamys/Soup v0.60.0
v0.60.0 — Supply Chain Security

latest releases: v0.76.1, v0.76.0, v0.75.2...
5 months ago

What's New

Six controls that hosted vendors structurally can't provide — every piece is opt-in for operators who want enforcement, every piece is dual-use security with a clear procurement story.

Adapter trust as procurement-grade controls

  • soup adapters scan <adapter> — spectral analysis of LoRA weights pre-load. Flags rank-1 dominance (the canonical weight-space trojan pattern), top-1 singular-vector energy concentration, NaN/Inf in weights, and Frobenius-norm outliers via robust median+MAD bucketing. Pure numpy (no torch). Exit codes 0=OK / 1=WARN / 3=FAIL.
  • soup adapters sign / verify [--strict] — deterministic Merkle-root manifest over every file in the adapter dir (including nested tokenizer/ / processor/ subdirs). Tamper any file, verify fails. unsigned backend live; sigstore + ed25519 deferred to v0.60.1.
  • soup adapters check-safetensors [--strict] — refuses pickle / PyTorch-classic weights at the boundary. Closed 8-entry unsafe-extension allowlist. Exit code 3 under --strict for CI gating.
  • NamespacePinStore trust-on-first-use SQLite — anti-AI-Jacking. Records (repo_id, author, created_at) first time Soup sees a HF repo; refuses author change or backward created_at jump unless --allow-namespace-shift <new-author> opt-in matches (case-insensitive). Bool opt-in rejected — prevents a free-for-all bypass.
  • License-conflict matrix at soup adapters merge — closed allowlist of 33 SPDX-ish licenses; --license <id> --license-override <reason> gate; refuses non-commercial+permissive, strong-copyleft+permissive, restricted-use+permissive merges unless 8+ char justification supplied.
  • soup airgap-bundle --model <m> --output <out.tar> — signed tarball with deterministic dataset labeling (sorted basename, NOT argv order); 100 GiB cap; TOCTOU-hardened atomic write; tarfile.data_filter set on Python 3.12+ for safe extraction.

Test count

9294 → 9446 (+152 net across 6 new test files). Review-fix coverage across 5 waves (python / security / code / tdd / smoke): 0 CRITICAL + 12 HIGH + 11 MEDIUM + 6 LOW fixed before tag.

Install / Upgrade

pip install --upgrade soup-cli==0.60.0

Security

All six controls follow the project's standard hardening:

  • Path containment via shared enforce_under_cwd_and_no_symlink helper (TOCTOU-safe).
  • Atomic writes via tempfile.mkstemp + os.replace from the sibling temp file.
  • Symlink rejection at the target path BEFORE every write (lstat + S_ISLNK, before realpath).
  • Bool-as-int rejection on every numeric input (Python treats True as 1).
  • Null-byte / oversize / non-string rejection at every public string boundary.
  • Frozen dataclasses for value types; MappingProxyType for public registries.

New SSRF / supply-chain specifics:

  • NamespacePinStore constructor refuses paths outside $HOME / $CWD / $TMPDIR; pre-placed symlinks at the DB path rejected before sqlite3.connect; POSIX 0o600 perms.
  • compute_adapter_manifest is recursive (catches nested tokenizer-dir tamper); hardlinks pointing outside the adapter dir caught via per-file realpath+commonpath check.
  • _load_signature uses direct os.lstat-then-open (no isfile-then-open race); 16 MiB cap on .soup-signature.json.
  • inspect_airgap_bundle 64 MiB manifest cap; tarfile.data_filter set for any future caller adding extractall.
  • License override reason validation: 8-char min (defends against --license-override y), 4096-char max, null-byte rejected, TypeError on non-string.

Known Limitations

  1. Sigstore + ed25519 signing deferred to v0.60.1 — UNSIGNED backend ships live (offline Merkle-root tamper detection works today); the live signers raise NotImplementedError with explicit v0.60.1 marker. Same stub-then-live cadence as v0.27.0 MII / v0.50.0 GRPO Plus / v0.56.0 diagnose / v0.59.0 attest.
  2. Namespace-pin not yet wired into HF download path — helpers ship live but the integration into utils/hubs.download_repo lands in v0.60.1. Operators can call verify_namespace manually via Python API today.
  3. License gate is opt-in, not enforced — --license <id> required to invoke the gate; auto-extraction from adapter_config.json / HF model-card metadata lands in v0.60.1.
  4. Airgap bundle does NOT yet auto-attach v0.59 repro-receipt — train→bundle handoff wiring is v0.60.1.
  5. Strict-safetensors is extension-based only — a pickle stream renamed to .safetensors bypasses the static scan. Magic-byte check (PK\x03\x04 / \x80 pickle opcodes) is a v0.60.1 follow-up.
  6. License override is captured in the CLI panel but NOT yet auto-emitted to audit-log — v0.59 audit_log.append_audit_event integration lands in v0.60.1.
  7. NamespacePinStore SQLite is single-process — concurrent soup train runs racing on the TOFU write may serialise via SQLite locking; WAL + cross-process file-lock tracked for v0.60.1.
  8. Adapter scan false-negative on multi-vector trojans — sophisticated attacks distributing energy across many singular vectors will pass; per-arch threshold profiles tracked for v0.60.x. Conservative-by-design false-positive bias (<1% on healthy fine-tunes) is the priority.

🤖 Generated with Claude Code

Don't miss a new Soup release

NewReleases is sending notifications on new releases.