Conversation
Generated bindings built their documentation links from the FQPN hostname, which comes from whichever CLI fetched the schema. Under OpenTofu that produced registry.opentofu.org/providers/... links, which 404 - that host does not serve the Terraform registry's path shape. Deriving the host from the *fetching CLI* was the real defect: the same provider at the same version generated different output depending on whether `cdktn get` ran under terraform or tofu. The project's declared targets are the stable signal, so linkToDocs now keys off those. OpenTofu is used only when it is the sole declared product. Declaring both, or declaring nothing (DEFAULT_TARGET_VERSIONS declares both), gives the Terraform registry - so the default case is deterministic and output no longer depends on the CLI. That is why no snapshots move. The two registries are not a hostname swap. Confirmed against getDocumentationUrl.ts in opentofu/registry-ui and checked against live renders, OpenTofu uses /provider/ singular, a v-prefixed version, and "datasources" unhyphenated. It has no ephemeral-resource route yet (opentofu/registry-ui#348), so those fall back to the provider page. The registry identity lives in @cdktn/commons because @cdktn/cli-core needs the same mapping for open-constructs#208 - the provider-browse URL in its error text and the hostname it resolves providers from. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Addresses the two code-level readings of open-constructs#208 using the mechanism added for open-constructs#393: the registry comes from the project's declared targetVersions, so OpenTofu only when it is the sole declared product. 1. The "could not find a version" error pointed everyone at registry.terraform.io/browse/providers. An OpenTofu project now gets search.opentofu.org/providers - registry.opentofu.org/browse/providers is a 404, the listing lives on the search host. 2. `cdktn provider add` resolved available versions from registry.terraform.io regardless of target. Both registries expose the same /v1/providers/<ns>/<name>/versions shape and their version lists differ - 42 versions vs 41 for hashicorp/random at time of writing - so an OpenTofu project could be told to pin a version its own registry does not carry. Deliberately out of scope: DEFAULT_HOSTNAME, which normalizes a bare "hashicorp/aws" into a fully qualified source. That is provider *identity*, not resolution, and it is consumed by more than this path - cdktf-config-manager and prebuilt-providers both hardcode stripping the "registry.terraform.io/" prefix, so making normalization registry-aware would break prebuilt matching and cdktf.json round-tripping for OpenTofu projects. It needs its own change with those consumers updated together. The registry parameter defaults to Terraform, so every caller that does not yet thread targetVersions keeps its current behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Folds DEFAULT_HOSTNAME into the registry work, per review. OpenTofu users have been told to fully qualify their providers because normalization hardcoded registry.terraform.io. Two changes so that advice becomes optional rather than required, without breaking anyone following it: - A bare or namespace-only source now expands against the registry the project targets, so `cdktn provider add aws` in an OpenTofu project yields registry.opentofu.org/hashicorp/aws. - A source that already names a host is still left alone, so an explicit registry.opentofu.org/... always wins over the project's target - and over the default, for a project that declares no targetVersions. `isFromTerraformRegistry` becomes `isFromPublicRegistry`. That predicate gated automatic version resolution on the host being Terraform's, so an explicitly qualified OpenTofu provider - exactly what tofu users were told to write - silently skipped resolution and got no version. It now asks whether the host is a registry we can query at all, so private and self-hosted registries are still correctly excluded. Resolution and the browse URL in the error text both follow the constraint's own hostname rather than a registry passed down the call chain, which is what makes explicit qualification win and let the DependencyManager parameter go away again. simplifiedName drops whichever public host it carries, not just Terraform's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jsteinich
force-pushed
the
feat/opentofu-registry-resolution
branch
from
September 19, 2026 14:49
5912d8f to
a3c68a6
Compare
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.
Related issue
Addresses the code-level readings of #208. Stacked on #443 — merge that first; this branch contains its commit and reuses the registry mechanism it adds.
Description
#208's title reads like a
dependency-managerchange while its body is about sample code on registries, so it admits three readings. This takes the two that are code-level, using the sametargetVersions-derived registry as #443 — OpenTofu only when it is the sole declared product, Terraform otherwise.The through-line: OpenTofu users have been told to fully qualify their providers, because everything here hardcoded
registry.terraform.io. These changes make that advice optional rather than required, without breaking anyone already following it.1. Bare sources expand against the project's registry
normalizeProviderSourcehardcoded the Terraform host, socdktn provider add awsalways producedregistry.terraform.io/hashicorp/aws. It now expands against the registry the project targets, so an OpenTofu project getsregistry.opentofu.org/hashicorp/aws.A source that already names a host is still left untouched, so an explicit
registry.opentofu.org/...always wins — over the project's target, and over the default for a project that declares notargetVersions.2. Explicitly qualified OpenTofu providers silently skipped version resolution
This is a live bug on
main, and it hits exactly the users who followed the fully-qualify advice. Version resolution was gated on:where
isFromTerraformRegistry()ishostname === "registry.terraform.io". A provider written asregistry.opentofu.org/hashicorp/awswith no version failed that check, so no version was resolved and none was written.It becomes
isFromPublicRegistry()— whether the host is a registry cdktn can query at all. Private and self-hosted registries are still correctly excluded, since they expose no versions API.3. Resolution and the browse URL follow the constraint
Both now derive from the constraint's own hostname rather than a registry threaded down the call chain. That is what makes explicit qualification win, and it let the
DependencyManagerparameter from the first commit go away again.Both registries expose the same
/v1/providers/{ns}/{name}/versionsshape, and their version lists differ — 42 versus 41 forhashicorp/randomat time of writing — so an OpenTofu project could previously be told to pin a version its own registry does not carry.The error text's browse URL follows too:
search.opentofu.org/providersfor OpenTofu, sinceregistry.opentofu.org/browse/providersis a 404.simplifiedNamedrops whichever public host it carries, not just Terraform's.What is still out of scope
The third reading of #208 — publishing CDK Terrain samples to the OpenTofu registry — is untouched, so the issue stays open for it.
cdktf-config-managerstill strips only the Terraform prefix when writingcdktf.json, which means an OpenTofu project's providers are written fully qualified. That round-trips correctly and matches what those users already write by hand, so it is left alone deliberately rather than risking a strip that normalization would not re-add.Testing
registry-api.test.tscovers all four paths with theMockAgentpattern the neighbouring tests use: default resolves against Terraform; a bare source under an OpenTofu target expands and resolves against OpenTofu; an explicitly qualified OpenTofu source resolves even with no declared target; a private registry is not queryable.nx test @cdktn/cli-core(so the dependency chain is built): all suites pass.Running jest directly in the package without building siblings reports failures on
Cannot find module '@cdktn/hcl2cdk'/'@cdktn/hcl-tools'— pre-existing and unrelated.🤖 Generated with Claude Code