refactor(wcm): adopt SDK 0.27.0, and fix six demos it broke - #91
Merged
Conversation
Two things, and the second was not planned.
The digest recipe now comes from wcm.artifact_digest. It was implemented here
and copied into two Marketplace integrations, with nothing keeping the three in
step; a recipe that exists three times stops being one recipe, and the drift
shows up as weights_hash not matching, which reads as tampered weights.
sha256_artifact becomes a thin wrapper passing follow_symlinks=True, because a
Hugging Face snapshot directory is a symlink tree and the SDK refuses symlinks
by default.
flip_first_byte is gone. It existed so the demo could show a tampered hash
without writing to the model somebody just downloaded, which is a property worth
keeping, but it meant maintaining a second hashing path that existed only to
fake tampering. tampered_digest copies the artifact, flips a byte, hashes the
copy and discards it. Costs disk on a demo that already downloaded the model,
and buys a demonstration where the bytes genuinely differ. The test asserting
the original is untouched is kept and strengthened.
Then, verifying against the published package: SIX demos that pass on 0.26.0
fail on 0.27.0. None of them touch the digest recipe, so this is the release
itself, and it is the security work in that release doing its job.
refuse_and_wipe, open_model_e2e, closed_model_e2e, revocation_kill_switch,
channel_binding, real_open_model
#98 refuses release unless the manifest identity is pinned out of band.
Every one of these built a broker that would have released against any
manifest reusing a held weights hash. Fixed by pinning
manifest_identity(manifest), which is the correct usage and what these
demos should have been modelling.
sovereign_self_custody
#95 requires a SIGNED memory sweep; an unsigned fingerprint is refused
rather than accepted on trust, because an aliasing attack that can fake a
readback can also fake an unsigned claim about it. Replaced the mock
fingerprint with a real run_memory_sweep over a BytearrayMemoryRange and
gave the broker the sweep key. The demo is better for it: it now
demonstrates the control instead of stubbing it.
Also fixed a latent bug this exposed: the failure branch called
decision.failures() on a property. It had never run, because the gate had
never refused. An error path that only executes when something is wrong is
exactly the one worth checking.
CI ran the demo scripts and never ran the tests in this directory. They cover
the artifact digest, which is the value a manifest binds, so a change to it that
no demo happens to exercise would land unnoticed. Added a pytest step, and
bumped the stale >=0.21.0 floor in the model-signing step to match.
Verified against published 0.27.0 in a clean venv: 13 demos run, 10 tests pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014NL8o3PXq6kfs2SdmBv6ak
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two things. The second was not planned and is the one to read.
1. The digest recipe comes from the SDK now
It was implemented here and copied into two Marketplace integrations, with nothing keeping the three in step.
weight-custody-manifest0.27.0 publisheswcm.artifact_digest, sosha256_artifactbecomes a thin wrapper.follow_symlinks=True, because a Hugging Face snapshot directory is a symlink tree:snapshot_downloadpopulatessnapshots/<revision>/with links into a content-addressedblobs/directory. The SDK refuses symlinks by default, which is right for an artifact somebody handed you and wrong for a cache you just populated yourself.flip_first_byteis gone. It existed so the demo could show a tampered hash without writing to the model somebody just downloaded, which is worth keeping, but it meant maintaining a second hashing path that existed only to fake tampering.tampered_digestcopies the artifact, flips a byte, hashes the copy and discards it. Costs disk on a demo that already downloaded the model, and buys a demonstration where the bytes genuinely differ. The test asserting the original is untouched is kept and strengthened.2. Six demos pass on 0.26.0 and fail on 0.27.0
None of them touch the digest recipe. This is the release itself, and it is the security work in it doing exactly its job.
refuse_and_wipe,open_model_e2e,closed_model_e2e,revocation_kill_switch,channel_binding,real_open_modelsovereign_self_custodyEvery one of the first six built a broker that would have released against any manifest reusing a held weights hash. That is precisely what #98 closed. Fixed by pinning
manifest_identity(manifest), which is the correct usage and what these demos should have been modelling all along.For
sovereign_self_custody, an unsigned fingerprint is now refused rather than accepted on trust, because an aliasing attack that can fake a readback can also fake an unsigned claim about it. Replaced the mock fingerprint with a realrun_memory_sweepover aBytearrayMemoryRangeand gave the broker the sweep key. The demo is better for it: it demonstrates the control instead of stubbing it.A latent bug that surfaced with it
sovereign_self_custodycalleddecision.failures()on a property. It had never run, because the gate had never refused. An error path that only executes when something is wrong is exactly the one worth having correct.CI never ran the tests in this directory
The job runs the demo scripts and stops there. The tests cover the artifact digest, which is the value a manifest binds, so a change to it that no demo happens to exercise would land unnoticed. Added a pytest step, and bumped the stale
>=0.21.0floor in the model-signing step to matchrequirements.txt.Verified
Against published 0.27.0 in a clean venv: 13 demos run, 10 tests pass. Confirmed the six failures reproduce on 0.26.0-vs-0.27.0 before fixing, so the attribution is not a guess.
🤖 Generated with Claude Code
https://claude.ai/code/session_014NL8o3PXq6kfs2SdmBv6ak