-
-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: versioned objects and migrations for syft-client #9464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
bitsofsteve
wants to merge
17
commits into
dev
Choose a base branch
from
stephen/syft-client-migrations
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
5e8d4ee
Add syft-client migration registry and protocol constants
bitsofsteve 6531046
Make VersionInfo a migratable object
bitsofsteve 81bc3f9
Load legacy version files through the migration service
bitsofsteve bee5916
Move the shared migration service into the migrations package
bitsofsteve a5af604
Version the msgv2 proposed-changes message
bitsofsteve b3c4f50
Version the file-change events message
bitsofsteve b80c713
Register historic protocol-0 artifacts for 0.1.117
bitsofsteve 4c4d6d6
Add release artifact export script with protocol-bump guard
bitsofsteve ec1a0ce
Add release fixtures and older-protocol compatibility tests
bitsofsteve 95468fe
VersionInfoV2 carries protocol schemas with v1<->v2 migrations
bitsofsteve 3084703
Feed peer job schemas from PeerManager into JobStorage
bitsofsteve 899ea51
Feed peer dataset schemas into DatasetStorage negotiation
bitsofsteve e87bc51
Register historic schemas explicitly by importing versioned model mod…
pjwerneck caf8a46
Refactor export_release_artifact.py to avoid possible unrecoverable …
pjwerneck 81c3b3e
Merge branch 'dev' into stephen/syft-client-migrations
pjwerneck 23ceee2
pre-commit fixes
pjwerneck 2e21e70
Fix broken integration test and add test for dataset delivery layout
pjwerneck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| """Export the release artifacts for the current syft-client version. | ||
|
|
||
| Run on EVERY release (uv run python scripts/export_release_artifact.py): | ||
| always writes the package release info; additionally writes the protocol | ||
| artifact when this release introduces a new protocol version. | ||
| """ | ||
|
|
||
| import sys | ||
|
|
||
| from syft_client.migrations.history import PACKAGE_ARTIFACTS_DIR, PROTOCOLS_DIR | ||
| from syft_client.migrations.registry import ( | ||
| SYFT_CLIENT_PROTOCOL_VERSION, | ||
| client_registry, | ||
| ) | ||
| from syft_client.version import SYFT_CLIENT_VERSION | ||
|
|
||
|
|
||
| def main() -> None: | ||
| # Import the package so every versioned object is registered. | ||
| import syft_client # noqa: F401 | ||
|
|
||
| if client_registry.protocol_changed_without_bump(): | ||
| sys.exit( | ||
| "The syft-client protocol changed compared to the released " | ||
| f"protocol-{SYFT_CLIENT_PROTOCOL_VERSION}.json; bump " | ||
| "SYFT_CLIENT_PROTOCOL_VERSION in syft_client/migrations/registry.py " | ||
| "before releasing." | ||
| ) | ||
|
|
||
| info_path = PACKAGE_ARTIFACTS_DIR / f"syft-client-{SYFT_CLIENT_VERSION}.json" | ||
| protocol_path = PROTOCOLS_DIR / f"protocol-{SYFT_CLIENT_PROTOCOL_VERSION}.json" | ||
| need_info = not info_path.exists() | ||
| need_protocol = not protocol_path.exists() | ||
|
|
||
| # Single exit when there is nothing left to write | ||
| if not need_info and not need_protocol: | ||
| sys.exit( | ||
| f"Release artifacts already present:\n" | ||
| f" {info_path}\n" | ||
| f" {protocol_path}\n" | ||
| "They are frozen once written. Bump SYFT_CLIENT_VERSION (and " | ||
| "SYFT_CLIENT_PROTOCOL_VERSION if the protocol changed) before " | ||
| "exporting again." | ||
| ) | ||
|
|
||
| if need_info: | ||
| client_registry.compute_released_package_protocol_info().save(info_path) | ||
| print(f"Wrote {info_path}") | ||
| else: | ||
| print(f"Package artifact already present: {info_path}") | ||
|
|
||
| if need_protocol: | ||
| client_registry.compute_released_protocol().save(protocol_path) | ||
| print(f"Wrote {protocol_path} (new protocol version)") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| """Generate a p2p backward-compatibility fixture for the current syft-client release. | ||
|
|
||
| Run on EVERY release, after bumping the version: | ||
|
|
||
| uv run python scripts/generate_release_fixture.py | ||
|
|
||
| Writes the serialized artifacts exactly as this release produces them, into | ||
|
|
||
| tests/migrations/p2p/fixtures/syft_client-<version>-protocol<p>/ | ||
| SYFT_version.json # the published version file | ||
| msgv2_<...>.tar.gz # a proposed-changes message (DS -> DO) | ||
| syfteventsmessagev3_<...>.tar.gz # an events message (DO -> watchers) | ||
|
|
||
| Unlike syft-job there is no local SyftBox tree to snapshot (storage is the | ||
| Google Drive transport), so fixtures are directories of captured blobs; future | ||
| releases loop over them (test_older_protocol_compatibility.py) to prove they | ||
| can still read and round-trip older serialized data. | ||
|
|
||
| Protocol 0 / release 0.1.117 predates this script; its fixture | ||
| (syft_client-0.1.117-protocol0) is hand-authored, like protocol-0.json. | ||
| """ | ||
|
|
||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| from syft_client.migrations.registry import SYFT_CLIENT_PROTOCOL_VERSION | ||
| from syft_client.sync.events.file_change_event import ( | ||
| FileChangeEvent, | ||
| FileChangeEventsMessage, | ||
| ) | ||
| from syft_client.sync.messages.proposed_filechange import ( | ||
| ProposedFileChange, | ||
| ProposedFileChangesMessage, | ||
| ) | ||
| from syft_client.sync.version.version_info import VersionInfo | ||
| from syft_client.version import SYFT_CLIENT_VERSION | ||
|
|
||
| DO_EMAIL = "do@test.org" | ||
| DS_EMAIL = "ds@test.org" | ||
|
|
||
| FIXTURES_DIR = ( | ||
| Path(__file__).resolve().parents[1] / "tests" / "migrations" / "p2p" / "fixtures" | ||
| ) | ||
|
|
||
|
|
||
| def build_version_info() -> VersionInfo: | ||
| # Not VersionInfo.current(): the detected install source is an absolute | ||
| # local path on dev machines, which must not leak into a committed fixture. | ||
| return VersionInfo.current().model_copy( | ||
| update={"syft_client_install_source": "pip"} | ||
| ) | ||
|
|
||
|
|
||
| def build_proposed_message() -> ProposedFileChangesMessage: | ||
| return ProposedFileChangesMessage( | ||
| sender_email=DS_EMAIL, | ||
| proposed_file_changes=[ | ||
| ProposedFileChange( | ||
| path_in_datasite="data/notes.txt", | ||
| content="hello from the release fixture", | ||
| datasite_email=DO_EMAIL, | ||
| ), | ||
| ProposedFileChange( | ||
| path_in_datasite="data/blob.bin", | ||
| content=b"\x00\x01\x02fixture-binary", | ||
| datasite_email=DO_EMAIL, | ||
| ), | ||
| ProposedFileChange( | ||
| path_in_datasite="data/removed.txt", | ||
| content=None, | ||
| old_hash="0" * 64, | ||
| is_deleted=True, | ||
| datasite_email=DO_EMAIL, | ||
| ), | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| def build_events_message( | ||
| proposed: ProposedFileChangesMessage, | ||
| ) -> FileChangeEventsMessage: | ||
| events = [ | ||
| FileChangeEvent.from_proposed_filechange(change) | ||
| for change in proposed.proposed_file_changes | ||
| ] | ||
| return FileChangeEventsMessage(events=events) | ||
|
|
||
|
|
||
| def main() -> None: | ||
| # Any fixture for this version (any protocol) means the version was | ||
| # already released; a released version's serialized form is frozen. | ||
| existing = sorted(FIXTURES_DIR.glob(f"syft_client-{SYFT_CLIENT_VERSION}-protocol*")) | ||
| if existing: | ||
| sys.exit( | ||
| f"{existing[0]} already exists — fixtures are frozen once written. " | ||
| "Bump SYFT_CLIENT_VERSION before generating." | ||
| ) | ||
| target = FIXTURES_DIR / ( | ||
| f"syft_client-{SYFT_CLIENT_VERSION}-protocol{SYFT_CLIENT_PROTOCOL_VERSION}" | ||
| ) | ||
| target.mkdir(parents=True) | ||
|
|
||
| (target / "SYFT_version.json").write_text(build_version_info().to_json()) | ||
|
|
||
| proposed = build_proposed_message() | ||
| (target / proposed.message_filename.as_string()).write_bytes( | ||
| proposed.as_compressed_data() | ||
| ) | ||
|
|
||
| events = build_events_message(proposed) | ||
| (target / events.message_filepath.as_string()).write_bytes( | ||
| events.as_compressed_data() | ||
| ) | ||
|
|
||
| print(f"Wrote {target}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from .registry import ( | ||
| PROTOCOL_NAME, | ||
| SYFT_CLIENT_PROTOCOL_VERSION, | ||
| client_migration_service, | ||
| client_registry, | ||
| load_as_latest, | ||
| ) | ||
|
|
||
| __all__ = [ | ||
| "PROTOCOL_NAME", | ||
| "SYFT_CLIENT_PROTOCOL_VERSION", | ||
| "client_migration_service", | ||
| "client_registry", | ||
| "load_as_latest", | ||
| ] |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| from pathlib import Path | ||
|
|
||
| from syft_migration import ReleasedPackageProtocolInfo, ReleasedProtocol | ||
|
|
||
| from .registry import client_registry | ||
|
|
||
| # Release artifacts of past syft-client releases: | ||
| # package-artifacts/syft-client-<package_version>.json (every release) | ||
| # protocols/protocol-<protocol_version>.json (only when the protocol changed) | ||
| # Generated by scripts/export_release_artifact.py; 0.1.117 / protocol 0 predate | ||
| # the artifact mechanism, so their files are hardcoded as if that release had | ||
| # emitted them. | ||
| HISTORY_DIR = Path(__file__).parent / "history" | ||
| PACKAGE_ARTIFACTS_DIR = HISTORY_DIR / "package-artifacts" | ||
| PROTOCOLS_DIR = HISTORY_DIR / "protocols" | ||
|
|
||
|
|
||
| def register_historic_schemas() -> None: | ||
| """Register the release artifacts of past releases into the client registry. | ||
|
|
||
| Must run after the versioned models are imported: with | ||
| ``raise_for_unknown_objects`` an artifact listing an object version this | ||
| release cannot load fails at import time instead of at migration time. | ||
| """ | ||
| for path in sorted(PACKAGE_ARTIFACTS_DIR.glob("*.json")): | ||
| client_registry.register_released_package_protocol_info( | ||
| ReleasedPackageProtocolInfo.load(path), raise_for_unknown_objects=True | ||
| ) | ||
| for path in sorted(PROTOCOLS_DIR.glob("*.json")): | ||
| client_registry.register_released_protocol( | ||
| ReleasedProtocol.load(path), raise_for_unknown_objects=True | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.