Repository navigation
fix(code-executors): preserve hard-linked output files (#7906) - #7932
OKAN-SOFTWARE wants to merge 2 commits into
Conversation
BlueRaddish
left a comment
There was a problem hiding this comment.
The new islnk() branch also follows hard links to symbolic-link members, so a valid output archive can now abort the whole result instead of ignoring its symlinks.
For example, keep an ordinary outputs/ordinary.txt in the archive, then add:
symlink = tarfile.TarInfo('outputs/symbolic.txt')
symlink.type = tarfile.SYMTYPE
symlink.linkname = 'missing-target'
tar.addfile(symlink)
alias = tarfile.TarInfo('outputs/hard-symlink.txt')
alias.type = tarfile.LNKTYPE
alias.linkname = 'outputs/symbolic.txt'
tar.addfile(alias)At head 63048908976ef965aaefaa01e2e2c366ab9c6626, tar.extractfile(alias) follows the symbolic target and raises KeyError: "linkname 'outputs/missing-target' not found". _get_output_files() does not catch it, so execute_code() loses the successful execution result and the unrelated ordinary output. Parent 95d8610e returns that ordinary file and ignores both links. If the symlink instead points to ordinary.txt, the head exports hard-symlink.txt with the target's data, although the direct symlink is excluded.
This is not restricted to a fabricated archive type: Moby's archive producer records hard links for non-directory entries, and its Unix handling explicitly accounts for hard links to symlinks. A hard-linked symlink inode should remain excluded along with other symlinks, rather than being treated as a regular-file output.
Please check the resolved hard-link target's entry type before extracting, excluding symbolic-link targets while preserving the ordinary hard-link contents and expansion budget. A regression for the archive above would cover the result-loss case.
Verification: I compared five real TAR fixtures against the exact parent/head execute_code, _execute_code_locked, _prepare_directories, _get_output_files, and MIME helper source, with the original File/input/result dataclasses. Ordinary files and direct-symlink exclusion remain controls on both revisions; regular-file hard links gain the intended second output on the head. The two hard-linked-symlink cases produce the differences described above. These were Windows/Python 3.13.14 CPU checks with the Docker I/O boundary recorded and stubbed; I did not start Docker, execute generated code, import the complete ADK package, or run the owning/full tox suites. OpenAI Codex assisted with this review.
|
Thanks for catching this edge case. Addressed in commit Added regression coverage for broken and valid symlink targets, ordinary hard links, and chained hard links. Validation:
The full multi-version suite and live Docker E2E tests have not been rerun for this correction. Ready for another review. Thank you! |
Link to Issue or Description of Change
Closes #7906
Problem:
ContainerCodeExecutorsilently drops output files represented as TAR hard-link entries because_get_output_files()only processes regular files usingTarInfo.isfile().Solution:
member.isfile() or member.islnk().Testing Plan
Unit Tests:
Results:
Additional validation:
Full Test Suite:
The full suite was attempted using Tox. Python 3.11 collected 22,640 tests but stopped at an A2A client-factory test with:
AttributeError: 'CustomFactory' object has no attribute '_httpx_client'This failure occurs outside the modified container executor files. The complete multi-version suite has not passed locally.
Manual End-to-End (E2E) Tests:
Live Docker integration testing has not yet been performed. The regression tests use mocked Docker archives.
For manual verification, execute code that creates two hard-linked files inside the container's output directory using
os.link(), then verify that both filenames appear inCodeExecutionResult.output_fileswith identical contents.Checklist
CONTRIBUTING.mddocument.Additional Context
The issue author confirmed that this contribution is welcome and offered to review the pull request.
The Google Individual Contributor License Agreement is on file, and the GitHub CLA check has passed.