Repository navigation
feat(lib): validate Fn usage against Terraform/OpenTofu versions - #268
Conversation
d18ecd9 to
7b9a82b
Compare
This comment has been minimized.
This comment has been minimized.
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.
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.
|
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
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 |
4c23aa5 to
9171dcd
Compare
…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
…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>
🤖 Release PR — merge to cut a new release. Kept open and rebased as commits land on `main`. --- <details><summary>0.23.4</summary> ## [0.23.4](v0.23.3...v0.23.4) (2026-07-02) ### Features * **cli:** validate Terraform CLI feature versions ([#237](#237)) ([32d434c](32d434c)) * declared Terraform/OpenTofu target versions (validation foundation) ([#269](#269)) ([0aa2343](0aa2343)) * **lib:** S3-backend - Add `useLockfile` field and update `dynamodbTable` deprecated JSDoc ([#234](#234)) ([32a408f](32a408f)) * **lib:** validate Fn usage against Terraform/OpenTofu versions ([#268](#268)) ([cdf8115](cdf8115)) ### Bug Fixes * **cli:** don't mistake terraform error output for a missing-variable prompt ([#267](#267)) ([0ea946f](0ea946f)) * **cli:** release terraform state lock when interrupting diff/deploy ([#284](#284)) ([de617db](de617db)) * **cli:** resolve prebuilt Java provider versions via repo1.maven.org ([#285](#285)) ([d5af07d](d5af07d)) * **gha:** Adding CHANGELOG.md to prettier ignore list ([#258](#258)) ([5160469](5160469)) * **gha:** pull jsii-terraform CI image from GHCR instead of Docker Hub ([#261](#261)) ([f19d34b](f19d34b)) * **provider-generator:** copy only publishable files into the jsii compile bundle ([#292](#292)) ([562d4c7](562d4c7)) * **provider-generator:** match shorthand provider sources against OpenTofu schema keys ([#293](#293)) ([fda0103](fda0103)) * **release:** add Changelog title for correct release-please insertion ([#255](#255)) ([004818a](004818a)) * **release:** drop devEngines.packageManager that broke npm publish ([ef508a6](ef508a6)) * **tools:** repair generate-function-bindings tool ([#273](#273)) ([821e1cf](821e1cf)) ### Miscellaneous Chores * Add Gradle to Mise config ([#271](#271)) ([1578270](1578270)) * add pnpm to mise ([#266](#266)) ([48ab91f](48ab91f)) * add uv to mise ([#260](#260)) ([163cf3d](163cf3d)) * **deps:** bump nrwl/nx-set-shas from 38457b511e60ee4e1da09255b658e480748a1af4 to afb73a62d26e41464e9254689e1fd6122ee683c1 ([#236](#236)) ([b5ac018](b5ac018)) * **deps:** bump the github-actions-backward-compatible group across 1 directory with 7 updates ([#235](#235)) ([de67d9f](de67d9f)) * **deps:** replace uuid dependency with node:crypto.randomUUID ([#291](#291)) ([6d3657a](6d3657a)) * ESLint ignore test edge-provider-bindings ([#270](#270)) ([ba407bb](ba407bb)) * Fix Verdaccio logging config ([#272](#272)) ([aded64b](aded64b)) * **gha:** parallelize provider binding generation for documentation examples ([#244](#244)) ([0a9c955](0a9c955)) * Migrate package manager from yarn to pnpm ([#170](#170)) ([d23da4e](d23da4e)) * migrate planning artifacts to cdktn-planning [skip ci] ([968c358](968c358)) * **release:** add release-please automation for versioning ([#243](#243)) ([c759eec](c759eec)) * Remove dependency-pinner tool ([#250](#250)) ([42c27d5](42c27d5)) * Remove unused dependencies ([#281](#281)) ([c7de65e](c7de65e)) * **tests:** run verdaccio in-process ([#248](#248)) ([c17677d](c17677d)) * Update JSII version constraint ([#245](#245)) ([d89558f](d89558f)) * Update scheduled workflows to only run on open-constructs/cdk-terrain ([#256](#256)) ([ba408cf](ba408cf)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: open-constructs-cdktn[bot] <291052431+open-constructs-cdktn[bot]@users.noreply.github.com>
…ons (RFC-04) (#296) Implements RFC-04 — **provider feature availability**: support the newer provider plugin-protocol capability families with `targetVersions`-aware codegen and synth-time validation. Proposal, dataset, sweep tooling and interactive report live in **open-constructs/cdktn-planning** → `RFCS/04-provider-feature-availability/` (only the merged matrix is vendored here, matching the function-availability split). Builds directly on the #269 foundation (`targetVersions` + `ValidateFeatureTargetSupport`) and the #268 usage-registry pattern. ## Guiding decision **Generate the full surface the schema offers; narrow per project at synth time via `targetVersions`.** Generation-time filtering would fork the generated API by project configuration — impossible for prebuilt providers and hostile to caching. Constraints baked into the validations are the per-product `>=` ranges from the sweep dataset. ## Review guide (one commit per RFC rollout item) 1. **`chore: vendor provider-feature availability matrix`** — dataset digest + README only, no behavior change. 2. **`feat(lib): TerraformEphemeralResource`** — new public base class synthesizing to the top-level `ephemeral` key (JSON + HCL renderer), refs as `ephemeral.<type>.<id>.<attr>`, no provisioners/connection/import/move. Constructor registers the target-version validation unconditionally (new API surface — only fires on use, no feature flag per RFC). Internal `providerFeatureConstraints` map sourced from the vendored matrix. 3. **`feat(provider-generator): acquire newer provider-protocol schema sections`** (Phase 0, a bugfix on its own) — commons types for `functions` / `ephemeral_resource_schemas` / `resource_identity_schemas` / `write_only`; sanitizer walks ephemeral schemas; fetched schemas stamped with the fetching CLI; **cache key now includes CLI product+minor** (a schema fetched once with an old CLI no longer poisons every later generation); fetch-time warning when the fetching binary structurally cannot emit sections the targets admit. 4. **`feat(provider-generator): generate ephemeral resource bindings`** — third schema family mirroring the `data_` pipeline (`EphemeralRandomPassword` in `ephemeral-random-password/`), config extends `TerraformEphemeralMetaArguments`, no `generateConfigForImport`. Zero churn in existing snapshots (ephemeral models append after resources/data sources; class-name dedup is order-dependent). 5. **`feat(provider-generator): generate provider-defined function bindings`** — `TimeProviderFunctions.rfc3339Parse(ts)` → `${provider::time::rfc3339_parse(...)}`; namespace defaults to the registry short name with a `providerLocalName` override (local names change the namespace, aliases don't). Runtime flows through one public jsii chokepoint (`TerraformProviderFunction.invoke`) feeding a usage registry; `TerraformStack` validates usage against `terraform >=1.8.0` / `opentofu >=1.7.0` — note the deliberate asymmetry: OpenTofu *language* support (1.7.0) predates its schema *emission* (1.8.0), so generation and validation use different boundaries. 6. **`feat(provider-generator): deprecate write-only attribute getters, validate usage`** — providers never persist write-only values (every read is `null` by protocol contract), so the state-backed getter is a trap: emitted `@deprecated` now, removal rides the next prebuilt major (JSII-breaking otherwise). Setting one (setter or constructor config) registers usage via a new protected `TerraformResource.registerProviderFeatureUsage` hook — generated code reaches the validation machinery only by extending base classes. 7. **`feat(cli): thread targetVersions into cdktn get`** — `GetOptions.targetVersions` → `ConstructsMaker` → `readSchema`, driving the Phase 0 fetch-time warning; `constraints.json` gains diagnostic stamps (`targetVersions`, fetching `cli`) without affecting the `filterAlreadyGenerated` staleness logic (targets don't change codegen output, so they must not force regeneration). ## Test coverage - Generator: snapshot tests against **real `terraform providers schema -json` fragments** from the sweep (random ephemeral, time functions incl. object returns, vault `*_wo`), plus a synthetic fixture for variadic/reserved-name mapping branches. Zero churn in pre-existing snapshots. - Core: validation matrices mirroring `validations.test.ts` (admit/exclude per product, hint text, the OpenTofu 1.7.0 asymmetry, registry resets). - Schema: emission-gap logic matrix, cache-key suffix behavior, sanitizer walk over ephemeral schemas; CLI stamps in network snapshots are stubbed (environment-dependent). ## Known/deferred - `matchers.test.ts › toPlanSuccessfully` fails in this environment before and after these changes (downloads the real docker provider; verified pre-existing via stash on the unmodified tree). - Deferred per RFC Phase 4: resource identity consumption (schema plumbing already carried), list resources / actions / state stores (Terraform-only today; re-evaluate on opentofu/opentofu#3787). - **Follow-ups tracked as issues**: #308 (nested write-only registration), #309 (matrix drift check / in-repo tooling), #310 (`hcl2cdk` ephemeral conversion), #311 (edge-provider schema cross-language coverage), #312 (ephemeral integration test gated on TF >= 1.10), #313 (pre-existing HCL renderer defects), #304 (first-class `provider_meta`; #314 closed as its duplicate), #316 (remove the deprecated write-only getters at the next prebuilt-provider major — the Phase 3 end state). New this round: #336 (structural typing for object-shaped function params/returns), #337 (runtime CI thin slice on terraform 1.15.x + opentofu 1.12.x — CI's Terraform ceiling is 1.6.5, so the new schema sections are covered by fixture unit tests, the edge-provider compile slice below, and the external demo harness until #337 lands). ## Review findings addressed (from the demo-harness verification comment) - **Fixed — `targetVersions` validation bypass**: `CdktfConfig.targetVersions` (the `runGetInDir` path) now validates via commons `validateTargetVersions` (warn + ignore), and the emission-gap check treats invalid ranges as not-wanted instead of throwing — a malformed range previously crashed `cdktn get` via `semver.intersects`. - **Fixed — ephemeral lifecycle narrowed**: new `TerraformEphemeralResourceLifecycle` (`precondition`/`postcondition` only) replaces the full managed-resource lifecycle on the ephemeral API, before it ships as jsii surface. - **Fixed (docs) — provider-fn self-reference cycle**: generated provider-function JSDoc and `TerraformProviderFunction.invoke` now warn against calling a provider's functions inside that same provider's configuration block. - **Documented — ephemeral × write-only**: registration deliberately skips ephemeral resources — write-only is a state concept, ephemeral resources have no state, and no schema in the sweep (incl. vault's 16 ephemeral resources) combines the two. - **Follow-up — nested write-only registration** (#308): `write_only` inside nested blocks gets the deprecated getter but skips usage registration; deep config scanning deserves its own PR (a miss degrades to the plan-time error, not silent breakage). - **Pre-existing / by design**: the AWS barrel-import OOM predates this PR (lazy-index is the existing mitigation); `Fn.ephemeralasnull` + `sensitive` on outputs is Terraform semantics (docs candidate); list resources / actions / resource identity codegen is the RFC Phase 4 deferral noted above. ## Second review round addressed - **Fixed — cross-App usage-registry leak**: `App` construction now resets both usage registries (a new App = a new synthesis session). Within an App the process-global registry is by design — every stack resolves the same `targetVersions` from App context — but usage no longer leaks into later, unrelated Apps in the same process (the reviewer's jest scenario). Regression tests cover the exact sequence; the flag-gated `Fn` registry had the same latent leak and is reset too. - **Fixed — emission-gap warning on cache hits**: the warning moved from `readProviderSchema` into `readSchema`, running for cached *and* fresh schemas using the `cli_name`/`cli_version` stamps the schema carries. Regression test: two `readSchema` calls against a cache dir → one producer call, two warnings. - **Docs — matrix as source of truth**: both hand-maintained maps now name `features-matrix.json` as their source and cross-reference each other; automated drift check tracked in #309. ## Third review round addressed (cfncompat/awscc demo findings) - **Fixed — dynamic-typed provider-function returns coerced to string**: generated wrappers for `dynamic`/`object`/`map` return types no longer wrap in `Token.asString(...)`; they return the raw `invoke()` `IResolvable`, which `Tokenization.isResolvable()` recognizes — struct-typed attribute assignments (`OutputReference.internalValue`) no longer vanish silently from synth output. - **Fixed — `invoke()` dropped literal `null` positional arguments**: arguments are now validated per position (variadic flattening stays in the generated wrappers where the signature is known), and a latent third bug this exposed was fixed too: `FunctionCall` rendered args via `Array.prototype.join`, which collapses `null` entries to empty strings — resolved `null`/`undefined` now render as the Terraform `null` keyword. Regression tests pin the exact `provider::cfncompat::condition_if(true, null, {"a" = 1})` rendering. ## Fourth review round addressed (jsteinich's CHANGES_REQUESTED) Seven commits on top of the reviewed head, one per finding group (inline replies on each thread carry the details): 1. **Schema fidelity** — `FunctionParameter` gains `is_nullable`, `FunctionSignature` gains `deprecation_message`, and both drop `description_kind` (verified against `internal/command/jsonfunction/{function,parameter}.go` and the OpenTofu equivalent: that field does not exist on function JSON; `allow_null_value`/`allow_unknown_values` are protocol-only names — the old comment was wrong). OpenTofu emits no `deprecation_message` at all (divergence, documented). 2. **Recursive, honest type mapping** — collections recurse (`list(number)` → `number[]` via `Token.asNumberList`, `set(bool)` param → `Array<boolean | IResolvable>`, nested compose); object/map/dynamic returns are declared `IResolvable` instead of `any` (property access on a token is now a compile error); `is_nullable` consumed (trailing → jsii-optional, mid-position → `any`, variadic → `any[]`, docstrings say `T | null`); `deprecation_message` → `@deprecated`; name collisions hard-fail generation with an actionable error. Structural helpers for object shapes: #336. 3. **App-owned usage registries** — recording moved to token-resolve time keyed by the resolving stack's `node.root` (WeakMaps); the App-constructor resets and the "pathological" disclaimer are gone; the interleaved-App false negative is structurally impossible and pinned by regression tests for both registries. 4. **Functions move onto the provider class** — `time.functions.rfc3339Parse(ts)` via a memoized getter fed by `this.terraformResourceType` (the exact `required_providers` key, so the namespace is correct by construction); the static class and `providerLocalName` parameter are gone, mooting the `providerAlias` naming question. Per-method self-reference JSDoc dropped (kept once on `invoke`; docs PR: open-constructs/cdk-terrain-docs#29). 5. **Cleanups** — `registerProviderFeatureUsage` moved to `TerraformElement` (ephemeral resources reuse it); enum casts replaced by a membership guard + direct `ProviderFeature` indexing; hints get their own map instead of runtime label-mangling (messages byte-identical); write-only registration treats explicit `null` as omission (`!= null`, both constructor and setter paths, four pinned tests). 6. **Demo-validation fixes** — exercising the generated bindings in a real app ([demo PR](sakul-learning/cdktn-provider-features-demo#5)) caught three bugs snapshots couldn't: the sibling import needed `/index` under `nodenext`; the wrapper constructor's TS parameter property is rejected by Node's native type-stripping (jsii accepts it — Node is the stricter consumer); variadic rest params need `Array<T>` for union element types. 7. **Edge-provider compile coverage** (closes #311) — the edge schema now carries nine functions (one per generator branch, incl. all three nullability shapes and deprecation), an ephemeral resource, and a `write_only` attribute; its bindings ride the existing postbuild jsii + pacmak flow for all five languages and the `test/<lang>/edge` native-compile suites, independent of CI's Terraform version. **External validation** (full matrix in the [demo PR](sakul-learning/cdktn-provider-features-demo#5)): terraform 1.15.7 and opentofu 1.12.3 generate byte-identical bindings modulo registry-host doc links; schema cache keys per CLI product+minor; omitted/explicit/mid-position nullable args all render the bare `null` keyword in position; generated bindings pass tsc + jsii + pacmak; the targetVersions validation error was demonstrated live through the resolve-time registry. ## Resolves Terraform CDK issues - hashicorp/terraform-cdk#3886 - hashicorp/terraform-cdk#3686 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
I'm going to lock this pull request 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 related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
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