feat(lib): validate Fn usage against Terraform/OpenTofu versions#268
Merged
Conversation
so0k
commented
Jun 11, 2026
so0k
commented
Jun 11, 2026
so0k
commented
Jun 11, 2026
so0k
commented
Jun 11, 2026
so0k
commented
Jun 11, 2026
d18ecd9 to
7b9a82b
Compare
This comment has been minimized.
This comment has been minimized.
4 tasks
This comment was marked as resolved.
This comment was marked as resolved.
7b9a82b to
30a4cb8
Compare
03dc31f to
12f9975
Compare
30a4cb8 to
72db7b9
Compare
This comment was marked as duplicate.
This comment was marked as duplicate.
72db7b9 to
e2a5af1
Compare
This comment was marked as resolved.
This comment was marked as resolved.
Contributor
Up to you Vincent. My only comment on this Pr would be why are we using Python scripts rather than Node? |
This comment was marked as resolved.
This comment was marked as resolved.
Contributor
|
Personally, I would merge #262 first, and then refactor your changes on top, otherwise these PRs gain more and more bloat and are then difficult to review. |
1af9ee5 to
4c23aa5
Compare
831c0e1 to
d99e731
Compare
Contributor
Author
Done! #262 merged, #269 rebased to main (Ready to merge) and this PR stacked on that to land the missing function support from TF 1.5.x -> TF(latest)/OTF(latest) with synth time validation |
jsteinich
reviewed
Jun 13, 2026
4c23aa5 to
9171dcd
Compare
jsteinich
pushed a commit
that referenced
this pull request
Jun 25, 2026
…ion) (#269) ## Summary > Reworks unreleased #237 to not run terraform binary during synth Prerequisite for #268. Instead of probing whichever Terraform/OpenTofu binary happens to be installed during synth, projects declare the runtimes they intend to support, and validations answer: *"is this feature supported by the project's declared target range?"* — deterministically, with no binary required. Installed-binary verification becomes an explicit opt-in for commands that execute the binary anyway. ```jsonc // cdktf.json { "targetVersions": { "terraform": ">=1.5.7", "opentofu": ">=1.6.0" }, "validateInstalledBinary": true // opt-in, off by default } ``` ### Commits 1. **feat(cli): add targetVersions to cdktf.json config** — typed field in `@cdktn/commons`; `parseConfig` validates product names and npm-semver ranges (Terraform's `~>` syntax is rejected with a hint — npm semver would silently parse it as `~` with different semantics) and threads the declaration to apps through the existing `CDKTF_CONTEXT_JSON` channel. Also adds `parseTerraformCliVersion` to commons and the `validateInstalledBinary` flag. 2. **feat(lib): validate features against declared runtime targets** — `resolveTargetVersions(scope)` (context → dual-baseline default `terraform >=1.5.7` + `opentofu >=1.6.0`), `checkFeatureSupportedByTargets` (semver range **subset**: a feature passes only if supported across the *entire* declared range of every targeted product), and `ValidateFeatureTargetSupport` (an `IValidation` that never executes a binary). Synth-time binary probing is removed: `ValidateTerraformFeatureVersion` (merged unreleased in #237, zero call sites) is deleted together with its execSync machinery — the pure `parseTerraformCliVersion` parser and the `TerraformFeatureVersionConstraints` type remain. The long-released `ValidateBinaryVersion` and the resource-move probe built on it stay unchanged as the legacy exception, both marked `TODO(target-versions)`. 3. **feat(cli): opt-in installed-binary verification** — when `validateInstalledBinary: true`, `initalizeTerraform` (the diff/deploy/destroy chokepoint, where the binary is about to run anyway) verifies the installed product/version against the declared targets. Declared targets are deliberately *not* treated as proof about the local binary. 4. **feat(cli): write default targetVersions in init templates** — new projects get the dual baseline explicitly in `cdktf.json`. ### Semantics - **Subset check**: declaring `terraform: ">=1.5.7"` while using a feature that needs `>=1.8.0` fails — the project claims to support 1.5.7..1.8.0 where the feature is missing. The fix is raising the declared floor (or narrowing the range), which keeps the declaration honest. - **Missing product key in a feature's constraints** = unsupported by that product; **missing product key in declared targets** = the project doesn't target that product. - **Undeclared** = dual product baseline (strictest, most portable interpretation). - **Synth never executes a binary.** The only places a binary is run are commands that execute it anyway (opt-in `validateInstalledBinary`) and the legacy `ValidateBinaryVersion`/resource-move path kept for compatibility. ### Stacked work #268 (function availability validation) is stacked on this branch: its `ValidateFunctionVersionSupport` checks used `Fn` functions against the declared targets via `checkFeatureSupportedByTargets`, gated by the `validateFunctionVersions` feature flag. ## Test plan - [x] `@cdktn/commons`: 83/83 — parser accepts constraint-shaped targets, rejects unknown products / malformed ranges / `~>` / empty declarations / non-strings; context payload merge - [x] `cdktn`: 425/426 — resolver default + context override + malformed-context errors; subset pass/fail; independent product evaluation; product-not-targeted skip; complex ranges; `ValidateFeatureTargetSupport` end-to-end with an execSync spy proving no binary call (the 1 failure is the pre-existing Docker-daemon-dependent `matchers.test.ts`, unrelated) - [x] `@cdktn/cli-core`: 146 passed / 30 skipped (dist-dependent) — installed-binary check helper: satisfies/outside-range/undeclared-product/unparseable/default-baseline - [ ] Integration: existing init tests exercise the new template field in CI 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tooling Vendor functions-matrix.json — a per-function availability map across every stable Terraform (>=1.5.7) and OpenTofu (>=1.6.0) release — and the TypeScript tooling that consumes and maintains it: - update-function-matrix: delta updater for new releases (downloads only unseen versions into a temp dir, warns loudly if a function disappears) - generate-function-availability: emits the version-constraint map consumed by the cdktn validation (only non-universal functions) - matrix.ts: shared matrix location + types The baseline data sweep that produced the matrix — the per-release `metadata functions -json` dumps plus the build-matrix.py / build-report.py / sweep.sh scripts and the interactive HTML report — lives in the open-constructs/cdktn-planning repo (RFCS/function-availability); only the resulting matrix is vendored here. A README in function-availability/ points there. Mark the matrix linguist-generated and exclude the directory from copywrite headers, prettier and eslint. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The checked-in functions.json predated Terraform 1.8, so Fn was missing every function added since. generate.ts now: - drops `core::` namespaced aliases (terraform >=1.8 reports every builtin twice; the aliases are not valid identifiers) - merges OpenTofu-only functions from the availability matrix so Fn covers both products, linking their docstrings to opentofu.org New on Fn (and the hcl2cdk convert map): convert, ephemeralasnull, issensitive, templatestring, base64gunzip, cidrcontains, urldecode. None have variadic parameters, so no new INTERNAL_METHODS overrides. Upstream metadata also refined return types: format now returns string and formatlist string[] (previously any); rendered expressions are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e flag Terraform and OpenTofu support different function sets (and introduce shared functions at different versions). With the validateFunctionVersions feature flag enabled, every TerraformStack validates the functions used through Fn against the project's declared targetVersions instead of letting `terraform plan` fail later: - functions/usage-registry: records each Fn call at the terraformFunction() chokepoint (process-global by design; ~5ns per call) - ValidateFunctionVersionSupport: checks only functions present in the generated availability map against the declared targets via checkFeatureSupportedByTargets (range subset), with an availability hint pointing at the products/versions that do support the function - purely declarative: no binary is executed, so synth behaves identically in CI and environments without Terraform/OpenTofu installed (verifying the installed binary is the separate opt-in validateInstalledBinary CLI behavior) - add flag to FUTURE_FLAGS so cdktn init enables it for new projects Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The test runs every synth with a nonexistent TERRAFORM_BINARY_NAME, proving the validation never executes a binary: outcomes are driven purely by the declared targetVersions in cdktf.json (default baseline fails for a function introduced later; raising the declared floor makes it pass). Document in test/Readme.md how the .terraform.versions.json matrix and the CI Docker image binaries relate to TERRAFORM_BINARY_NAME, which tests execute a binary, and that synth-time validations are deliberately not version-sensitive. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The integration test sets a nonexistent TERRAFORM_BINARY_NAME to prove the Fn version validation is purely declarative (no binary executed). But the test's cdktf.json declared hashicorp/random, so setupTypescriptProject's `cdktn get` tried to fetch that provider's schema via `terraform init` and failed before any assertion ran. main.ts never uses the random provider, so removing it makes `cdktn get` a no-op and lets the nonexistent-binary premise hold across the entire flow (init -> get -> synth), strengthening the "no binary executed" guarantee. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d99e731 to
ea4e8df
Compare
so0k
commented
Jun 25, 2026
so0k
commented
Jun 25, 2026
1 task
…etVersions Function version validation checks Fn usage against the declared targetVersions using the vendored availability matrix; it never executes a Terraform/OpenTofu CLI. Only the optional binary verification validation runs <binary> version. Correct the stale wording in features.ts, the generator docstring, and test/Readme.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jsteinich
approved these changes
Jun 26, 2026
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
Terraform and OpenTofu have diverged in their built-in function sets, and the checked-in function metadata predated Terraform 1.8 — so
Fnwas missing every function added since, and using a function your targeted runtimes don't support only failed atterraform plantime. This PR fixes the bindings generator, regenerates the bindings to cover both products, and adds an opt-in synth-time validation of function usage against the project's declared targets.Full Source data: open-constructs/cdktn-planning - RFCS/03-function-availability/PROPOSAL.md
Full function matrix: https://cdktn.io/function-matrix.html
Commits (reviewable independently)
metadata functions -jsonacross every stable Terraform (1.5.7→1.15.6, 66 releases) and OpenTofu (1.6.0→1.12.1, 54 releases) release intofunctions-matrix.json. Includes apnpm update-function-matrixdelta updater for new releases (downloads only unseen versions) and the generator for the availability map. Baseline sweep scripts are marked linguist-generated and excluded from copywrite/prettier/eslint.core::aliases (terraform ≥1.8 reports every builtin twice; not valid identifiers), merges OpenTofu-only functions from the matrix. New onFnand thecdktn convertmap:convert,ephemeralasnull,issensitive,templatestring,base64gunzip,cidrcontains,urldecode. None are variadic, so no newINTERNAL_METHODS. Upstream metadata also refinedformat/formatlistreturn types (any→string/string[]; rendered expressions unchanged).validateFunctionVersionsflag) — a usage registry recordsFncalls at theterraformFunction()chokepoint (~5ns/call, 0.04% of anFncall);ValidateFunctionVersionSupportchecks used functions from the generated availability map against the project's declaredtargetVersionsviacheckFeatureSupportedByTargets(range subset), with an availability hint pointing at the products/versions that do support the function. Purely declarative — no binary is ever executed; synth behaves identically in CI and environments without Terraform/OpenTofu installed. Added toFUTURE_FLAGSsocdktn initenables it for new projects.TERRAFORM_BINARY_NAME, proving no binary involvement: the default baseline targets deterministically rejectissensitive(introduced TF 1.8 / Tofu 1.7), and raising the declared floor incdktf.jsonmakes it pass.Example validation error:
Companion docs PR: open-constructs/cdk-terrain-docs
Test plan
pnpm nx test cdktn— 433/434 pass (the one failure ismatchers.test.tstoPlanSuccessfully, which requires a running Docker daemon; environmental, unrelated)validations.test.ts: baseline functions never resolve targets (execSync spy), default-baseline rejection, declared-targets pass (no exec), product-exclusive with availability hint, OpenTofu-only targeting, malformed declared targets, flag on/off wiringnx run cdktn:build)pnpm packagedist (runs in CI); deterministic across the version matrix — no binary is executed🤖 Generated with Claude Code