Repository navigation
Description
Problem
PR #321 explored an opt-in canonicalAssetHashes scheme that frames entry type, relative path, payload size, and payload. That is useful follow-up work, but the current representation does not yet describe every artifact-affecting property:
- regular-file records omit the Unix mode that
archiveSyncpreserves in ZIP external attributes; - directories contribute no records, so adding or removing an empty directory is invisible.
A reproduced mode case changes the emitted archive bytes while retaining the same canonical asset hash:
{
"canonicalHashBefore": "0D3C9E0875B72106054DC334DF123995",
"canonicalHashAfter": "0D3C9E0875B72106054DC334DF123995",
"canonicalEqual": true,
"archiveBytesEqual": false
}This work was split conceptually from PR #321 so that its symlink fix can retain the narrower compatibility-preserving approach: keep the historical content hash for trees without symlinks and combine separately framed symlink metadata under a tagged outer digest only for symlink-bearing trees.
Why Git/Nix do not have this hole
The framing idea is sound, but Git and Nix serialize a richer object model than (type, path, payload length, payload) alone:
- A Git tree records each child's mode, name, and object ID. Directories are represented by tree objects, regular executable files differ through mode
100755versus100644, and symlinks use mode120000. - Nix NAR serialization explicitly represents directory entries/node types and an executable marker for regular files.
Therefore copying only the payload framing pattern, without their metadata model, drops properties those formats include in their canonical representation.
Proposed scope
Design and introduce the canonical scheme in a dedicated, feature-flagged PR:
- Define which source-tree properties affect emitted
ARCHIVE,DIRECTORY, andFILEassets. - Frame directory entries explicitly, including empty directories.
- Include relevant preserved mode bits (at minimum executable state; preferably the exact permission mask if that is the emitted contract).
- Keep record ordering and path normalization deterministic across supported platforms.
- Specify root-symlink behavior.
- Add compatibility and behavior tests before enabling the future flag.
Acceptance criteria
- File rename changes the canonical hash.
- Entry-boundary shifts change the canonical hash.
- File/symlink swaps and symlink retargeting change the canonical hash.
0644→0755changes the canonical hash when it changes emitted artifact metadata.- Adding/removing an empty directory changes the canonical hash for directory/archive assets where that directory is emitted.
- Identical logical trees hash deterministically across repeated runs.
- Legacy hashing remains available until the intended compatibility boundary.
Follow-up from #321.
Activity
sakul-learning commentedon Jul 11, 2026
@vincenthsh — opened as the feature-flagged follow-up to PR #321 so the current PR can retain only the compatibility-preserving symlink hash fix (option 3). The issue captures the missing Git/Nix metadata semantics and acceptance criteria.
fix(lib): frame symlink metadata in asset hashes, share the symlink-a…
fix(lib)!: preserve symlinks in TerraformAsset walkers (#321)
feat(lib): canonical asset hashes behind the canonicalAssetHashes flag
feat(lib): canonical asset hashes behind the canonicalAssetHashes flag
feat(lib): canonical asset hashes behind the canonicalAssetHashes fea…
feat(lib): canonical asset hashes behind the canonicalAssetHashes fea…
github-actions commentedon Aug 18, 2026
I'm going to lock this issue because it has been closed for 30 days. This helps our maintainers find and focus on the active issues. If you've found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.