You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(lib): canonical asset hashes behind the canonicalAssetHashes feature flag (#323)
### Description
Closes#322. ~~Stacked on #321~~ — #321 has merged and this branch is
rebased onto current `main`; the diff is now the single canonical-hash
commit.
Adds the canonical entry-framed asset hash as a `canonicalAssetHashes`
feature flag (`FUTURE_FLAGS`: enabled for new projects by `cdktn init`,
opt-in via `cdktf.json` context for existing projects, becomes the
default at the next major). The legacy scheme — including #321's
compatibility-preserving symlink handling — stays untouched as the
default.
### The canonical representation
Modeled on git trees and Nix NAR, which serialize a full metadata model
rather than payload framing alone. Every record contains what affects
the emitted artifact:
| entry | frame |
| --- | --- |
| file | `F <mode> <relPath>\0<size>\0` + content |
| symlink | `L <mode> <relPath>\0<target byte length>\0` + target |
| directory (incl. empty) | `D <relPath>\0` |
- `<mode>` is the octal permission mask (`0o7777` bits) — exactly the
bits `archiveSync` preserves in zip external attributes, closing the
hole found in review where `0644` → `0755` changed archive bytes but not
the hash.
- Directories contribute explicit records (no mode — neither
`archiveSync` nor `copySync` preserves directory permissions), so
adding/removing an empty directory is visible.
- Entries are framed in sorted directory order with `/`-separated
relative paths; a symlink at the root is followed, matching how the
asset source path is opened when the artifact is emitted.
### Acceptance criteria from #322
Each has a dedicated test in
`packages/cdktn/test/canonical-asset-hash.test.ts`:
- [x] File rename changes the canonical hash (and a paired assertion
that legacy cannot see it)
- [x] Entry-boundary shifts change the canonical hash
- [x] File/symlink swaps and symlink retargeting change the canonical
hash
- [x] `0644` → `0755` changes the canonical hash
- [x] Adding/removing an empty directory changes the canonical hash
- [x] Identical logical trees hash deterministically (two locations +
repeated runs)
- [x] Legacy hashing remains available (flag off; `Testing.app({
enableFutureFlags: false })` covers the compat case per the
`features.ts` test rule)
### Testing
Full `cdktn` suite green (464 passing; the pre-existing environmental
`matchers.test.ts` → `toPlanSuccessfully` failure shells out to a real
`terraform plan` and is unrelated). jsii build green. Docs for the flag
are being handled separately in the docs repository (the stacked docs PR
#324 was closed in favor of that).
### Checklist
- [x] I have updated the PR title to match [CDKTN's style
guide](https://github.com/open-constructs/cdk-terrain/blob/main/CONTRIBUTING.md#pull-requests-1)
- [x] I have run the linter on my code locally
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation if
applicable (stacked docs PR follows)
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works if applicable
- [x] New and existing unit tests pass locally with my changes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: vincent de smet <vincent.drl@gmail.com>
0 commit comments