Repository navigation
feat: release job outputs and logs through one path - #9604
Merged
Merged
Conversation
The runner moves the outputs to staging/, like the logs. A reader gets them only through JobInfo.release(filenames, readers), which replaces _release_to_submitter, share_outputs and share_logs. release also grants the files that an earlier release moved, so a later share reaches the DS after an output policy released the outputs to other readers. The enclave releases the outputs before it forwards them, and writes the receipt into the staged outputs.
The enclave releases disclosures to the submitter and the DOs, and pushes them to the same readers, so each party that gets a file can read it. Outputs go out through _release_results, which releases them and then pushes them to the same readers. A release with no readers moves nothing, so blocked outputs stay in staging/. The DO tutorial points to share_job_results instead of the removed share_outputs.
release_artifacts becomes the private _move_to_review, so release is the only public way to release a file. The private share and forward methods become _release_job_results, _release_results_once, _release_outputs and _push_new_disclosures, and the people who get a file are recipients throughout. JobStorage.remove_outputs replaces the two loops that deleted the outputs of an earlier run.
A syft.pub.yaml in the staged outputs decided who reads them, so a job could release its own outputs past the output policy. The runner now fails such a job, shares its outputs with nobody, and records the reason in staging/ for the DO only. Each run also drops the recipients and the outputs error of the run before. shutil.move kept the job's symlinks, so a link into the run copy broke when the run copy was removed, an absolute link stayed live in the SyftBox, and a symlinked outputs folder made rerun fail. The outputs are now copied with the links followed, as the runner did before outputs were staged, and the copy skips the permission files.
remove_outputs also removes the read grant on the outputs, so the outputs of a rerun reach only the recipients of the new release. release() builds no permission context when nothing is released, and the enclave releases a job only while a granted item is still staged, so a tick with nothing new does no permission work. The enclave pushes only the job state. The read grant and the sync already deliver released outputs and disclosures, so the push sent them twice; forwarded_artifacts.json goes with it. The runner docstrings say outputs wait in staging/, and the rerun test now checks that the released outputs are removed.
The rebase on dev kept an import of syft.sync.transport.protocols, which dev renamed to syft.sync.connections.protocols, so syft_enclaves.client failed to import.
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
share({name: recipients}) replaces release(filenames, recipients).
Therefore each file can have its own recipients. share_outputs, share_logs
and share_disclosures replace release_logs and release_disclosures. The
runner and enclave methods that call them use "share" in their names, not
"release".
The runner writes the outputs, the logs, the exit code and the policy files into the review folder of the job. It gives nobody read access to these files. JobInfo.share only gives read access to a file. Therefore the commit removes staging/. The owner record and the api-request build folder move to review/. reset_run deletes the files of the last run and removes all read access to them. JobInfo.rerun and the runner call it. Therefore a new run does not keep the readers of the old run. The enclave shares the granted items of each finished job on every tick.
When the runner copies the outputs to review/, it skips each syft.pub.yaml. The runner ignores case when it compares the names. It logs the skipped names for the DO. The job no longer fails. Therefore a job that copies a folder with a permission file in it still shares its outputs. If SYFT_JOB_ALLOW_OUTPUT_PERMISSION_FILES is true, the runner keeps the files. SyftJobConfig reads this variable once. It raises an error for any value other than true or false.
When the enclave distributes a job, it gives each DO of the job read access to state.yaml. The sync then sends each status change to the DOs. The enclave no longer pushes state.yaml with the outputs. A permission rule for one file overrides the folder rule that lets the submitter read state.yaml. Therefore the rule for state.yaml also names the submitter.
syft-perms used each path as a rule pattern. The matcher reads *, ?, [ and
\ as glob syntax, and {{ as the start of a template. Therefore a job named *
got a grant that matched the files of every other job. A job named
{{.Year}} made the grant fail.
Each of these characters now goes into a character class of its own.
Therefore a pattern matches only its path. copy_permissions escapes the file
name too. remove_permission_for_user still finds its rule through the path,
not through the pattern.
PermissionModifier.add_permission_for_pattern adds a user to the rule for a glob pattern in the permission file of a folder. Unlike add_permission_for_user, it does not escape the pattern, so one rule can cover files that do not exist yet, such as the state of every job.
grant_ds_review_read becomes grant_ds_state_and_disclosures_read, which says what it grants. It writes each pattern through add_permission_for_pattern instead of editing the rule set by hand. The patterns are written out instead of generated from the codecs. A test runs once per protocol version, so a new protocol without its patterns fails. Setting up a DS folder no longer removes the old read grant on the whole folder. The runner already does that before any job runs, through replace_ds_folder_read.
… datasite Each syft-perms write reloaded every permission file in the datasite. Now the modifier puts the saved rule set in the context's tree, which is what the reload did for each file. remove_all_rules now updates the tree too, so the same context no longer reports a removed grant.
requested_disclosures becomes requested_read_permissions, the data owner's grant becomes approved_read_permissions (approve(read_permissions=...)), and granted_disclosures becomes read_permissions_to_share. The module, the item enum, the helpers, the enclave and api fields, the syft-bg config key and the files on disk are renamed the same way, with no fallback for the old names.
Read permissions are now {file in the job's review folder: [emails]}, and
both live in state.yaml (JobStateV2, job protocol 3). The data owner copies
the valid part of the submitter's request from config.yaml at receipt, and
sets the approved part at approval, within the request. Only the data
owner writes state.yaml, so the submitter can never approve itself.
approved_read_permissions.json and the item names (logs, traceback_frames,
return_code) are gone; the DS reads only state.yaml before a share.
An api lists the run files a caller may read, and a call's job requests and
gets them for the caller, so api jobs now share them. The email approval
approves the requested files that its config lists. In the enclave a file
goes only to the emails that the submitter requested and every party
approved, and the enclave reads and writes the state through the job
storage, so older peers get a state they can read.
A submitter asks with share_logs and share_outputs, or with a share_files dict, not both. The job client builds the requested read permissions from them; "outputs" is now a file a read permission can name. An enclave submit also takes share_logs_with_owners and share_outputs_with_owners for every data owner of the job; share_results_with_do is gone. approve() takes read_permissions or share_requested_files, not both, and builds the approved permissions from them and the request. For enclaves share_requested_files is the default. The runner takes share_requested_files too. Approved outputs still go only to readers the output policy allows, and in the enclave only with the receipt.
The output policy now gets read_permissions.json, filled with the job's approved read permissions from the api, instead of recipients.json. It may narrow or widen them; the result, with only the submitter and approved peers as readers, becomes the job's approved read permissions. A deny approves none, and a failed job shares no outputs. An api call's outputs follow its read permissions, not share_outputs_with_submitter, and a new api lets callers read the outputs unless it lists other files. Read permissions no longer limit the file names to a fixed list. The data owner drops request entries that leave the job's folder when it receives the job; the submitter's side only checks the shape.
- Rename the share flags to share_logs_with_submitter / share_outputs_with_submitter, add share_job_results, and pass approvals as share_files. - Remove traceback frame capture (traceback_frames.json). - Add request_stderr / request_stdout to the enclave client. Each data owner writes <do_email>_requested_permissions_update.json in the job's review folder; the enclave shares a log, or its first n_chars, once every data owner made the same request. - Share all of a finished job's results in distribute_results on every tick, so later approvals (outputs included) reach their readers. The receipt is still written once. - Show stdout of failed jobs, and fall back to a shared log head when the full log is not there.
A key must be a plain path inside the job's folder: "." (the whole folder) and second names such as "./stderr.txt" or "stderr.txt/" are refused, so the logs warning and other checks on file names cannot be bypassed. The logs warning now also covers a folder that holds a log. On the DS side, share_files names are tidied before the check, so "./stderr.txt" becomes "stderr.txt".
A failed api call (error exit, crash or timeout) never runs its output policy, so the files the api allows went out unchecked. The runner now skips the share for it and leaves the approval as the api set it.
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.
Summary
A DO shared job results two ways: grant read in place (
share_outputs,share_logs), or move files from staging and grant (release_logs,release_disclosures). This PR leaves one path: outputs wait instaging/like logs, andJobInfo.release(filenames, recipients)moves them toreview/and grants read access.Changes
staging/and reach a reader only through a release.share_outputs,share_logsand_release_to_submitterare removed.JobInfo.releasewith no recipients moves nothing, so blocked outputs stay instaging/.JobInfo.release. The enclave now grants read on the disclosures it releases._release_job_results,_release_outputs,_disclosure_recipients). The publicshare_job_resultsand its flags are unchanged.syft.pub.yamlinto its outputs and give itself readers, past the output policy andshare_outputs_with_submitter=False. The job now fails, and only the DO sees the reason.Testing
test_staging.py,test_policies.pyandtest_disclosures.py; each fails without its fix.Asana task
https://app.asana.com/1/1185126988600652/project/1210542925864934/task/1220052874945931?focus=true