fix(runtime): retain malformed launch publications safely

This commit is contained in:
Alexandre Teixeira
2026-10-02 23:57:57 +01:00
parent 3d7d32dbe2
commit 721b5ca831
2 changed files with 27 additions and 1 deletions
+2 -1
View File
@@ -438,7 +438,8 @@ def retire_launch(launch, containment_id, *, job=None):
published = json.loads(path.read_text())
except FileNotFoundError:
return False
if (published.get("launch") != launch.to_dict()
if (not isinstance(published, dict)
or published.get("launch") != launch.to_dict()
or published.get("containment_id") != containment_id
or published.get("job") != (job.to_dict() if job else None)):
return False
+25
View File
@@ -94,6 +94,31 @@ async def test_retired_publication_cannot_replay_bound_reservation(workspace):
tool_execution._active_workspace.reset(token)
@pytest.mark.parametrize('publication', [[], None, 'malformed'])
def test_nonobject_publication_cannot_be_retired(workspace, publication):
resource, rec = seed(workspace, status='done')
path = resources.launch_path(resource.generation)
path.write_text(json.dumps(publication))
launch = identities.ProcessLaunchResource.from_dict(rec['launch_resource'])
assert not resources.retire_launch(launch, resource.containment_id, job=resource)
assert json.loads(path.read_text()) == publication
async def test_corrupt_publication_retirement_preserves_command_result(workspace, monkeypatch):
attach = resources.attach_containment_processes
paths = []
def corrupt_after_attachment(launch, containment_id):
observed = attach(launch, containment_id)
path = resources.launch_path(launch.generation)
path.write_text('[]')
paths.append(path)
return observed
monkeypatch.setattr(resources, 'attach_containment_processes', corrupt_after_attachment)
_, result = await dispatch(authority(workspace), 'bash', 'printf completed')
assert result['exit_code'] == 0 and result['output'] == 'completed', result
assert paths[0].read_text() == '[]'
@pytest.mark.parametrize('status,followed_up,old,removed', [
('running', True, True, False), ('done', False, True, False),
('done', True, False, False), ('done', True, True, True), ('failed', True, True, True),