addrs: Disallow provider source addresses starting with terraform-

The main motivation here is to produce a helpful error if a user
incorrectly uses the terraform-provider- prefix (which we see on provider
VCS repositories and plugin executables) as part of the source address.

However, this also more broadly blocks "terraform-" as a prefix in
anticipation of whatever instinct causes the phenomenon where e.g.
Python's PyPI has thousands of packages whose names start with "python-",
even though everything on PyPI is for Python by definition. This is
definitely not _necessary_, but it's better to be restrictive at first
and weaken later as needed.
This commit is contained in:
Martin Atkins 2020-07-07 15:44:28 -07:00
parent 7909dd318d
commit 0a46ded3e7
3 changed files with 69 additions and 0 deletions

View File

@ -324,6 +324,51 @@ func ParseProviderSourceString(str string) (Provider, tfdiags.Diagnostics) {
return Provider{}, diags
}
// Due to how plugin executables are named and provider git repositories
// are conventionally named, it's a reasonable and
// apparently-somewhat-common user error to incorrectly use the
// "terraform-provider-" prefix in a provider source address. There is
// no good reason for a provider to have the prefix "terraform-" anyway,
// so we've made that invalid from the start both so we can give feedback
// to provider developers about the terraform- prefix being redundant
// and give specialized feedback to folks who incorrectly use the full
// terraform-provider- prefix to help them self-correct.
const redundantPrefix = "terraform-"
const userErrorPrefix = "terraform-provider-"
if strings.HasPrefix(ret.Type, redundantPrefix) {
if strings.HasPrefix(ret.Type, userErrorPrefix) {
// Likely user error. We only return this specialized error if
// whatever is after the prefix would otherwise be a
// syntactically-valid provider type, so we don't end up advising
// the user to try something that would be invalid for another
// reason anyway.
// (This is mainly just for robustness, because the validation
// we already did above should've rejected most/all ways for
// the suggestedType to end up invalid here.)
suggestedType := ret.Type[len(userErrorPrefix):]
if _, err := ParseProviderPart(suggestedType); err == nil {
suggestedAddr := ret
suggestedAddr.Type = suggestedType
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid provider type",
fmt.Sprintf("Provider source %q has a type with the prefix %q, which isn't valid. Although that prefix is often used in the names of version control repositories for Terraform providers, provider source strings should not include it.\n\nDid you mean %q?", ret.ForDisplay(), userErrorPrefix, suggestedAddr.ForDisplay()),
))
return Provider{}, diags
}
}
// Otherwise, probably instead an incorrectly-named provider, perhaps
// arising from a similar instinct to what causes there to be
// thousands of Python packages on PyPI with "python-"-prefixed
// names.
diags = diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Invalid provider type",
fmt.Sprintf("Provider source %q has a type with the prefix %q, which isn't allowed because it would be redundant to name a Terraform provider with that prefix. If you are the author of this provider, rename it to not include the prefix.", ret, redundantPrefix),
))
return Provider{}, diags
}
return ret, diags
}

View File

@ -379,6 +379,20 @@ func TestParseProviderSourceStr(t *testing.T) {
Provider{},
true,
},
// We forbid the terraform- prefix both because it's redundant to
// include "terraform" in a Terraform provider name and because we use
// the longer prefix terraform-provider- to hint for users who might be
// accidentally using the git repository name or executable file name
// instead of the provider type.
"example.com/hashicorp/terraform-provider-bad": {
Provider{},
true,
},
"example.com/hashicorp/terraform-bad": {
Provider{},
true,
},
}
for name, test := range tests {

View File

@ -0,0 +1,10 @@
terraform {
required_providers {
usererror = { # ERROR: Invalid provider type
source = "foo/terraform-provider-foo"
}
badname = { # ERROR: Invalid provider type
source = "foo/terraform-foo"
}
}
}