mirror of
https://github.com/opentofu/opentofu.git
synced 2026-05-28 04:15:54 -04:00
ociauthconfig: Require valid syntax for Docker-style config auths
Previously we just required the slash-separated segments to match without imposing any further constraint, but if the Docker-style config syntax evolves to allow other syntaxes here in future it'd be better for us to just ignore what we don't recognize rather than get confused into trying to match it in the current way. ParseRepositoryAddressPrefix is an exported function because package cliconfig will use it in a future commit to deal with our OpenTofu-specific equivalent of the "auths" objects: oci_credentials blocks in the CLI configuration. Signed-off-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
parent
ecf67c0ef7
commit
2eb7954fa5
2 changed files with 77 additions and 3 deletions
|
|
@ -182,12 +182,24 @@ func dockerCLIStyleAuthMatch(authsPropertyName string, wantRegistryDomain, wantR
|
|||
if authsPropertyName == "" {
|
||||
return NoCredentialsSpecificity // Invalid
|
||||
}
|
||||
gotDomain, gotRepositoryPath, havePath := strings.Cut(authsPropertyName, "/")
|
||||
var gotDomain, gotRepositoryPath string
|
||||
if strings.Count(authsPropertyName, "/") > 0 {
|
||||
var err error
|
||||
gotDomain, gotRepositoryPath, err = ParseRepositoryAddressPrefix(authsPropertyName)
|
||||
if err != nil {
|
||||
// Since these Docker CLI-style config files are not exclusively for OpenTofu,
|
||||
// we just silently ignore a property whose name we can't make sense of
|
||||
// in case a future version of this format adds something new that we
|
||||
// don't yet support.
|
||||
return NoCredentialsSpecificity // Invalid
|
||||
}
|
||||
} else {
|
||||
gotDomain = authsPropertyName
|
||||
}
|
||||
if gotDomain != wantRegistryDomain {
|
||||
return NoCredentialsSpecificity // does not match
|
||||
}
|
||||
if !havePath {
|
||||
// Domain-only match fast path
|
||||
if gotRepositoryPath == "" {
|
||||
return DomainCredentialsSpecificity // matches only the domain
|
||||
}
|
||||
// If authsPropertyName includes a path (that is: if gotRepositoryPath != "")
|
||||
|
|
|
|||
62
internal/command/cliconfig/ociauthconfig/repository_addr.go
Normal file
62
internal/command/cliconfig/ociauthconfig/repository_addr.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) The OpenTofu Authors
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright (c) 2023 HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package ociauthconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
orasregistry "oras.land/oras-go/v2/registry"
|
||||
)
|
||||
|
||||
// ParseRepositoryAddressPrefix attempts to parse the given string as the compact
|
||||
// "registry-domain/repository-path" format, returning the separate registry domain
|
||||
// and repository path parts if it's valid.
|
||||
//
|
||||
// This function is intended for the repository address prefix syntax used for
|
||||
// specifying "auths" in the Docker CLI-style config format, and for OpenTofu's
|
||||
// own oci_credentials CLI configuration blocks that follow the same syntax.
|
||||
//
|
||||
// The registry-domain portion can optionally include a port number delimited
|
||||
// by a colon, like "localhost:5000". The repository-path portion is optional,
|
||||
// with an address without it referring to all repositories on the given
|
||||
// registry domain.
|
||||
func ParseRepositoryAddressPrefix(addr string) (registryDomain, repositoryPath string, err error) {
|
||||
// For now we're relying on the ORAS implementation of parsing, but if we decide to
|
||||
// move away from ORAS for other registry client purposes then we can either
|
||||
// implement something similar inline here or find an alternative external library
|
||||
// to use for this.
|
||||
// We're actually using the _reference_ parser here, since a reference incorporates
|
||||
// a repository address, but we'll reject after the fact any result that includes
|
||||
// a tag or digest portion since we're not intending to accept addresses of specific
|
||||
// artifacts.
|
||||
|
||||
if strings.Count(addr, "/") != 0 {
|
||||
// This seems to be an address with both a registry and a repository path.
|
||||
ref, parseErr := orasregistry.ParseReference(addr)
|
||||
if parseErr != nil {
|
||||
// The ORAS function returns errors with sufficient context that any
|
||||
// further decoration we might add here would be redundant. For example,
|
||||
// this might return an error whose message is
|
||||
// "invalid reference: invalid registry invalid:thing:blah".
|
||||
return "", "", parseErr
|
||||
}
|
||||
if ref.Reference != "" {
|
||||
return "", "", fmt.Errorf("invalid reference: artifact tag or digest not allowed")
|
||||
}
|
||||
return ref.Registry, ref.Repository, nil
|
||||
}
|
||||
|
||||
// If we get here then it seems like we have _just_ a domain part. ORAS does
|
||||
// not have a separate function just for parsing a domain, so we'll borrow the
|
||||
// validate function from its reference parser instead.
|
||||
ref := &orasregistry.Reference{
|
||||
Registry: addr,
|
||||
}
|
||||
err = ref.ValidateRegistry()
|
||||
// ValidateRegistry returns an error with a string like "invalid reference: invalid registry invalid:thing:blah"
|
||||
return addr, "", err
|
||||
}
|
||||
Loading…
Reference in a new issue