New Upstream Release - golang-github-hashicorp-terraform-svchost

Ready changes

Summary

Merged new upstream version: 0.1.1 (was: 0.0.1).

Resulting package

Built on 2023-07-11T08:41 (took 5m11s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-github-hashicorp-terraform-svchost-dev

Lintian Result

Diff

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..0ff5bf3
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @hashicorp/tf-cli
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..0c8b092
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,5 @@
+# Code of Conduct
+
+HashiCorp Community Guidelines apply to you when interacting with the community here on GitHub and contributing code.
+
+Please read the full text at https://www.hashicorp.com/community-guidelines
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 54c4f3b..dd445cc 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,3 +1,5 @@
+# Copyright (c) HashiCorp, Inc.
+
 version: 2
 updates:
   - package-ecosystem: "gomod"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 1b63b72..3222222 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,5 +1,5 @@
 <!--
-Thank you for contributing to hashicorp/terraform-svchost! Please read docs/CONTRIBUTING.md for detailed information when preparing your change.
+Thank you for contributing to hashicorp/terraform-svchost! Please read CONTRIBUTING.md for detailed information when preparing your change.
 
 Please fill out the remaining template to assist code reviewers and testers with incorporating your change. If a section does not apply, feel free to delete it.
 -->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8cdeea7..02b6590 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,16 +9,32 @@ on:
       - main
 
 jobs:
+  copywrite:
+    name: Run Header Copyright
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
+
+      - name: Install Copywrite
+        id: install
+        uses: hashicorp/setup-copywrite@v1.1.2
+
+      - name: Output Installed Copywrite Version
+        run: echo "Installed Copywrite CLI ${{steps.install.outputs.version}}"
+
+      - name: Run Copywrite Header Compliance
+        run: copywrite headers --plan
   test:
     runs-on: ubuntu-latest
     timeout-minutes: 5
 
     steps:
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
 
       - name: Set up Go
-        uses: actions/setup-go@v3
+        uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
         with:
           go-version-file: go.mod
           cache: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..ed9f993
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,13 @@
+## v0.1.1
+
+The `disco.Disco` and `auth.CachingCredentialsSource` implementations are now safe for concurrent calls. Previously concurrent calls could potentially corrupt the internal cache maps or cause the Go runtime to panic.
+
+## v0.1.0
+
+#### Features:
+
+- Adds hostname `Alias` method to service discovery, making it possible to interpret one hostname as another.
+
+## v0.0.1
+
+Initial release
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..c12e3bb
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,3 @@
+# Contributing to the svchost library
+
+If you find an issue or would like to add a feature, please add an issue in GitHub. We welcome your contributions - fork the repo and submit a pull request.
diff --git a/README.md b/README.md
index 61581f5..3a12f01 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
-# Terraform svchost package
+# terraform-svchost
 
-[![CI Tests](https://github.com/hashicorp/terraform-svchost/actions/workflows/ci.yml/badge.svg)](https://github.com/hashicorp/terraform-svchost/actions/workflows/ci.yml)
+[![CI Tests](https://github.com/hashicorp/terraform-svchost/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/hashicorp/terraform-svchost/actions/workflows/ci.yml)
 [![GitHub license](https://img.shields.io/github/license/hashicorp/terraform-svchost.svg)](https://github.com/hashicorp/terraform-svchost/blob/main/LICENSE)
 [![GoDoc](https://godoc.org/github.com/hashicorp/terraform-svchost?status.svg)](https://godoc.org/github.com/hashicorp/terraform-svchost)
 [![Go Report Card](https://goreportcard.com/badge/github.com/hashicorp/terraform-svchost)](https://goreportcard.com/report/github.com/hashicorp/terraform-svchost)
 [![GitHub issues](https://img.shields.io/github/issues/hashicorp/terraform-svchost.svg)](https://github.com/hashicorp/terraform-svchost/issues)
 
-This package provides friendly hostnames, and is used by [terraform](https://github.com/hashicorp/terraform).
\ No newline at end of file
+This package provides friendly hostnames, and is used by [terraform](https://github.com/hashicorp/terraform).
diff --git a/auth/cache.go b/auth/cache.go
index 0dae567..65084d5 100644
--- a/auth/cache.go
+++ b/auth/cache.go
@@ -1,7 +1,11 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
-	"github.com/hashicorp/terraform-svchost"
+	"sync"
+
+	svchost "github.com/hashicorp/terraform-svchost"
 )
 
 // CachingCredentialsSource creates a new credentials source that wraps another
@@ -21,6 +25,7 @@ func CachingCredentialsSource(source CredentialsSource) CredentialsSource {
 type cachingCredentialsSource struct {
 	source CredentialsSource
 	cache  map[svchost.Hostname]HostCredentials
+	mu     sync.Mutex
 }
 
 // ForHost passes the given hostname on to the wrapped credentials source and
@@ -31,16 +36,21 @@ type cachingCredentialsSource struct {
 // No cache entry is created if the wrapped source returns an error, to allow
 // the caller to retry the failing operation.
 func (s *cachingCredentialsSource) ForHost(host svchost.Hostname) (HostCredentials, error) {
+	s.mu.Lock()
 	if cache, cached := s.cache[host]; cached {
+		s.mu.Unlock()
 		return cache, nil
 	}
+	s.mu.Unlock()
 
 	result, err := s.source.ForHost(host)
 	if err != nil {
 		return result, err
 	}
 
+	s.mu.Lock()
 	s.cache[host] = result
+	s.mu.Unlock()
 	return result, nil
 }
 
@@ -48,7 +58,9 @@ func (s *cachingCredentialsSource) StoreForHost(host svchost.Hostname, credentia
 	// We'll delete the cache entry even if the store fails, since that just
 	// means that the next read will go to the real store and get a chance to
 	// see which object (old or new) is actually present.
+	s.mu.Lock()
 	delete(s.cache, host)
+	s.mu.Unlock()
 	return s.source.StoreForHost(host, credentials)
 }
 
@@ -56,6 +68,8 @@ func (s *cachingCredentialsSource) ForgetForHost(host svchost.Hostname) error {
 	// We'll delete the cache entry even if the store fails, since that just
 	// means that the next read will go to the real store and get a chance to
 	// see if the object is still present.
+	s.mu.Lock()
 	delete(s.cache, host)
+	s.mu.Unlock()
 	return s.source.ForgetForHost(host)
 }
diff --git a/auth/credentials.go b/auth/credentials.go
index 36441cd..c3fd64a 100644
--- a/auth/credentials.go
+++ b/auth/credentials.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 // Package auth contains types and functions to manage authentication
 // credentials for service hosts.
 package auth
diff --git a/auth/from_map.go b/auth/from_map.go
index 7198c67..a7a81d7 100644
--- a/auth/from_map.go
+++ b/auth/from_map.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/helper_program.go b/auth/helper_program.go
index 76505f2..8c4591d 100644
--- a/auth/helper_program.go
+++ b/auth/helper_program.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/helper_program_test.go b/auth/helper_program_test.go
index 65ce49e..8d2849d 100644
--- a/auth/helper_program_test.go
+++ b/auth/helper_program_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/static.go b/auth/static.go
index f8b0b07..2474451 100644
--- a/auth/static.go
+++ b/auth/static.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/static_test.go b/auth/static_test.go
index 026a9ab..9675e2f 100644
--- a/auth/static_test.go
+++ b/auth/static_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/testdata/main.go b/auth/testdata/main.go
index 1abd5fc..ae0caba 100644
--- a/auth/testdata/main.go
+++ b/auth/testdata/main.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package main
 
 import (
diff --git a/auth/token_credentials.go b/auth/token_credentials.go
index 1d36553..d5ccefb 100644
--- a/auth/token_credentials.go
+++ b/auth/token_credentials.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/auth/token_credentials_test.go b/auth/token_credentials_test.go
index 61f2c9b..c434692 100644
--- a/auth/token_credentials_test.go
+++ b/auth/token_credentials_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package auth
 
 import (
diff --git a/debian/changelog b/debian/changelog
index 5a55763..e5e220f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-hashicorp-terraform-svchost (0.1.1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Tue, 11 Jul 2023 08:36:38 -0000
+
 golang-github-hashicorp-terraform-svchost (0.0.1-1) unstable; urgency=medium
 
   * Team upload.
diff --git a/debian/patches/disable-strange-tests.patch b/debian/patches/disable-strange-tests.patch
index 0b9d63c..b4b77b3 100644
--- a/debian/patches/disable-strange-tests.patch
+++ b/debian/patches/disable-strange-tests.patch
@@ -1,11 +1,11 @@
 Description: some tests require files in paths that are not compatible with Debian packaging
              in order to make life easier, these tests are disabled
 Author: Thorsten Alteholz <debian@alteholz.de>
-Index: golang-github-hashicorp-terraform-svchost/auth/helper_program_test.go
+Index: golang-github-hashicorp-terraform-svchost.git/auth/helper_program_test.go
 ===================================================================
---- golang-github-hashicorp-terraform-svchost.orig/auth/helper_program_test.go	2021-01-14 22:49:14.418474744 +0000
-+++ golang-github-hashicorp-terraform-svchost/auth/helper_program_test.go	2021-01-14 23:56:24.740968416 +0000
-@@ -5,7 +5,6 @@
+--- golang-github-hashicorp-terraform-svchost.git.orig/auth/helper_program_test.go
++++ golang-github-hashicorp-terraform-svchost.git/auth/helper_program_test.go
+@@ -7,7 +7,6 @@ import (
  	"path/filepath"
  	"testing"
  
@@ -13,7 +13,7 @@ Index: golang-github-hashicorp-terraform-svchost/auth/helper_program_test.go
  )
  
  func TestHelperProgramCredentialsSource(t *testing.T) {
-@@ -17,67 +16,4 @@
+@@ -19,67 +18,4 @@ func TestHelperProgramCredentialsSource(
  	program := filepath.Join(wd, "testdata/test-helper")
  	t.Logf("testing with helper at %s", program)
  
diff --git a/disco/disco.go b/disco/disco.go
index f4ddac4..9a535d5 100644
--- a/disco/disco.go
+++ b/disco/disco.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 // Package disco handles Terraform's remote service discovery protocol.
 //
 // This protocol allows mapping from a service hostname, as produced by the
@@ -10,14 +12,14 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
 	"mime"
 	"net/http"
 	"net/url"
+	"sync"
 	"time"
 
-	"github.com/hashicorp/terraform-svchost"
+	svchost "github.com/hashicorp/terraform-svchost"
 	"github.com/hashicorp/terraform-svchost/auth"
 )
 
@@ -42,8 +44,12 @@ var httpTransport = defaultHttpTransport()
 // hostnames and caches the results by hostname to avoid repeated requests
 // for the same information.
 type Disco struct {
+	// must lock "mu" while interacting with these maps
+	aliases   map[svchost.Hostname]svchost.Hostname
 	hostCache map[svchost.Hostname]*Host
-	credsSrc  auth.CredentialsSource
+	mu        sync.Mutex
+
+	credsSrc auth.CredentialsSource
 
 	// Transport is a custom http.RoundTripper to use.
 	Transport http.RoundTripper
@@ -69,6 +75,7 @@ func New() *Disco {
 // the given credentials source.
 func NewWithCredentialsSource(credsSrc auth.CredentialsSource) *Disco {
 	return &Disco{
+		aliases:   make(map[svchost.Hostname]svchost.Hostname),
 		hostCache: make(map[svchost.Hostname]*Host),
 		credsSrc:  credsSrc,
 		Transport: httpTransport,
@@ -104,11 +111,17 @@ func (d *Disco) CredentialsSource() auth.CredentialsSource {
 }
 
 // CredentialsForHost returns a non-nil HostCredentials if the embedded source has
-// credentials available for the host, and a nil HostCredentials if it does not.
+// credentials available for the host, or host alias, and a nil HostCredentials if it does not.
 func (d *Disco) CredentialsForHost(hostname svchost.Hostname) (auth.HostCredentials, error) {
 	if d.credsSrc == nil {
 		return nil, nil
 	}
+	d.mu.Lock()
+	defer d.mu.Unlock()
+	if aliasedHost, aliasExists := d.aliases[hostname]; aliasExists {
+		log.Printf("[DEBUG] CredentialsForHost found alias %s for %s", hostname, aliasedHost)
+		hostname = aliasedHost
+	}
 	return d.credsSrc.ForHost(hostname)
 }
 
@@ -127,6 +140,7 @@ func (d *Disco) ForceHostServices(hostname svchost.Hostname, services map[string
 		services = map[string]interface{}{}
 	}
 
+	d.mu.Lock()
 	d.hostCache[hostname] = &Host{
 		discoURL: &url.URL{
 			Scheme: "https",
@@ -137,6 +151,16 @@ func (d *Disco) ForceHostServices(hostname svchost.Hostname, services map[string
 		services:  services,
 		transport: d.Transport,
 	}
+	d.mu.Unlock()
+}
+
+// Alias accepts an alias and target Hostname. When service discovery is performed
+// or credentials are requested for the alias hostname, the target will be consulted instead.
+func (d *Disco) Alias(alias, target svchost.Hostname) {
+	log.Printf("[DEBUG] Service discovery for %s aliased as %s", target, alias)
+	d.mu.Lock()
+	d.aliases[alias] = target
+	d.mu.Unlock()
 }
 
 // Discover runs the discovery protocol against the given hostname (which must
@@ -150,15 +174,29 @@ func (d *Disco) ForceHostServices(hostname svchost.Hostname, services map[string
 // or due to the host not providing Terraform services at all, since we don't
 // wish to expose the detail of whole-host discovery to an end-user.
 func (d *Disco) Discover(hostname svchost.Hostname) (*Host, error) {
+	// In this method we use d.mu locking only to avoid corrupting d.hostCache
+	// by concurrent writes, and not to prevent concurrent discovery requests.
+	// If two clients concurrently request the same hostname then we could
+	// potentially send two concurrent discovery requests over the network,
+	// in which case it's unspecified which one will "win" and end up being
+	// stored in the cache for future requests. In practice this shouldn't
+	// matter because we're already assuming (by caching the results at all)
+	// that a host will generally not vary its results in meaningful ways
+	// between requests made in close time proximity.
+	d.mu.Lock()
 	if host, cached := d.hostCache[hostname]; cached {
+		d.mu.Unlock()
 		return host, nil
 	}
+	d.mu.Unlock()
 
 	host, err := d.discover(hostname)
 	if err != nil {
 		return nil, err
 	}
+	d.mu.Lock()
 	d.hostCache[hostname] = host
+	d.mu.Unlock()
 
 	return host, nil
 }
@@ -175,7 +213,18 @@ func (d *Disco) DiscoverServiceURL(hostname svchost.Hostname, serviceID string)
 
 // discover implements the actual discovery process, with its result cached
 // by the public-facing Discover method.
+//
+// This must be called _without_ d.mu locked. d.mu is there only to protect
+// the integrity of our internal maps, and not to prevent multiple concurrent
+// service discovery lookups even for the same hostname.
 func (d *Disco) discover(hostname svchost.Hostname) (*Host, error) {
+	d.mu.Lock()
+	if aliasedHost, aliasExists := d.aliases[hostname]; aliasExists {
+		log.Printf("[DEBUG] Discover found alias %s for %s", hostname, aliasedHost)
+		hostname = aliasedHost
+	}
+	d.mu.Unlock()
+
 	discoURL := &url.URL{
 		Scheme: "https",
 		Host:   hostname.String(),
@@ -259,7 +308,7 @@ func (d *Disco) discover(hostname svchost.Hostname) (*Host, error) {
 	// size, but we'll at least prevent reading the entire thing into memory.
 	lr := io.LimitReader(resp.Body, maxDiscoDocBytes)
 
-	servicesBytes, err := ioutil.ReadAll(lr)
+	servicesBytes, err := io.ReadAll(lr)
 	if err != nil {
 		return nil, fmt.Errorf("error reading discovery document body: %v", err)
 	}
@@ -277,10 +326,30 @@ func (d *Disco) discover(hostname svchost.Hostname) (*Host, error) {
 // Forget invalidates any cached record of the given hostname. If the host
 // has no cache entry then this is a no-op.
 func (d *Disco) Forget(hostname svchost.Hostname) {
+	d.mu.Lock()
+	d.forgetInternal(hostname)
+	d.mu.Unlock()
+}
+
+// forgetInternal is the main implementation of Forget that assumes the
+// caller has already locked d.mu, so this can also be used in other
+// places like ForgetAlias.
+func (d *Disco) forgetInternal(hostname svchost.Hostname) {
 	delete(d.hostCache, hostname)
 }
 
 // ForgetAll is like Forget, but for all of the hostnames that have cache entries.
 func (d *Disco) ForgetAll() {
+	d.mu.Lock()
 	d.hostCache = make(map[svchost.Hostname]*Host)
+	d.mu.Unlock()
+}
+
+// ForgetAlias removes a previously aliased hostname as well as its cached entry, if any exist.
+// If the alias has no target then this is a no-op.
+func (d *Disco) ForgetAlias(alias svchost.Hostname) {
+	d.mu.Lock()
+	delete(d.aliases, alias)
+	d.forgetInternal(alias)
+	d.mu.Unlock()
 }
diff --git a/disco/disco_test.go b/disco/disco_test.go
index 981fec0..ef7e4d6 100644
--- a/disco/disco_test.go
+++ b/disco/disco_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package disco
 
 import (
@@ -10,7 +12,7 @@ import (
 	"testing"
 	"time"
 
-	"github.com/hashicorp/terraform-svchost"
+	svchost "github.com/hashicorp/terraform-svchost"
 	"github.com/hashicorp/terraform-svchost/auth"
 )
 
@@ -325,7 +327,7 @@ func TestDiscover(t *testing.T) {
 		})
 		portStr2, close2 := testServer(func(w http.ResponseWriter, r *http.Request) {
 			// This server is the one that redirects.
-			http.Redirect(w, r, "https://127.0.0.1"+portStr1+"/.well-known/terraform.json", 302)
+			http.Redirect(w, r, "https://localhost"+portStr1+"/.well-known/terraform.json", 302)
 		})
 		defer close1()
 		defer close2()
@@ -356,12 +358,80 @@ func TestDiscover(t *testing.T) {
 		// The base URL for the host object should be the URL we redirected to,
 		// rather than the we redirected _from_.
 		gotBaseURL := discovered.discoURL.String()
-		wantBaseURL := "https://127.0.0.1" + portStr1 + "/.well-known/terraform.json"
+		wantBaseURL := "https://localhost" + portStr1 + "/.well-known/terraform.json"
 		if gotBaseURL != wantBaseURL {
 			t.Errorf("incorrect base url %s; want %s", gotBaseURL, wantBaseURL)
 		}
 
 	})
+
+	t.Run("alias", func(t *testing.T) {
+		// The server will listen on localhost and we will expect this response
+		// by requesting discovery on the alias.
+		portStr, close := testServer(func(w http.ResponseWriter, r *http.Request) {
+			resp := []byte(`
+{
+"thingy.v1": "http://example.com/foo"
+}
+`)
+			w.Header().Add("Content-Type", "application/json")
+			w.Header().Add("Content-Length", strconv.Itoa(len(resp)))
+			w.Write(resp)
+		})
+		defer close()
+
+		target, err := svchost.ForComparison("localhost" + portStr)
+		if err != nil {
+			t.Fatalf("test server hostname is invalid: %s", err)
+		}
+		alias, err := svchost.ForComparison("not-a-real-host-dont-even-try.no")
+		if err != nil {
+			t.Fatalf("alias hostname is invalid: %s", err)
+		}
+
+		d := New()
+		d.SetCredentialsSource(auth.StaticCredentialsSource(map[svchost.Hostname]map[string]any{
+			target: {
+				"token": "hunter2",
+			},
+		}))
+
+		d.Alias(alias, target)
+
+		discovered, err := d.Discover(alias)
+		if err != nil {
+			t.Fatalf("unexpected discovery error: %s", err)
+		}
+
+		gotURL, err := discovered.ServiceURL("thingy.v1")
+		if err != nil {
+			t.Fatalf("unexpected service URL error: %s", err)
+		}
+		if gotURL == nil {
+			t.Fatalf("found no URL for thingy.v1")
+		}
+		if got, want := gotURL.String(), "http://example.com/foo"; got != want {
+			t.Fatalf("wrong result %q; want %q", got, want)
+		}
+
+		aliasCreds, err := d.CredentialsForHost(alias)
+		if err != nil {
+			t.Fatalf("unexpected credentials error: %s", err)
+		}
+		if aliasCreds.Token() != "hunter2" {
+			t.Fatalf("found no credentials for alias")
+		}
+
+		d.ForgetAlias(alias)
+
+		discovered, err = d.Discover(alias)
+		if err == nil {
+			t.Error("expected error, got none")
+		}
+		if discovered != nil {
+			t.Error("expected discovered to be nil, got non-nil")
+		}
+	})
 }
 
 func testServer(h func(w http.ResponseWriter, r *http.Request)) (portStr string, close func()) {
diff --git a/disco/host.go b/disco/host.go
index d0ec8ee..eee5250 100644
--- a/disco/host.go
+++ b/disco/host.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package disco
 
 import (
diff --git a/disco/host_test.go b/disco/host_test.go
index ad18f1b..795aadb 100644
--- a/disco/host_test.go
+++ b/disco/host_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package disco
 
 import (
diff --git a/disco/http_transport.go b/disco/http_transport.go
index 7e4a385..f98274d 100644
--- a/disco/http_transport.go
+++ b/disco/http_transport.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package disco
 
 import (
diff --git a/disco/oauth_client.go b/disco/oauth_client.go
index 9df16eb..0b4f358 100644
--- a/disco/oauth_client.go
+++ b/disco/oauth_client.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package disco
 
 import (
diff --git a/go.mod b/go.mod
index 6e89b86..f26140b 100644
--- a/go.mod
+++ b/go.mod
@@ -6,14 +6,15 @@ require (
 	github.com/google/go-cmp v0.5.9
 	github.com/hashicorp/go-cleanhttp v0.5.2
 	github.com/hashicorp/go-version v1.6.0
-	github.com/zclconf/go-cty v1.12.1
-	golang.org/x/net v0.5.0
-	golang.org/x/oauth2 v0.4.0
+	github.com/zclconf/go-cty v1.13.1
+	golang.org/x/net v0.8.0
+	golang.org/x/oauth2 v0.6.0
 )
 
 require (
+	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
-	golang.org/x/text v0.6.0 // indirect
+	golang.org/x/text v0.8.0 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 08d575e..1ca0c71 100644
--- a/go.sum
+++ b/go.sum
@@ -1,3 +1,5 @@
+github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
+github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@@ -9,19 +11,19 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
 github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
 github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
 github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY=
-github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
+github.com/zclconf/go-cty v1.13.1 h1:0a6bRwuiSHtAmqCqNOE+c2oHgepv0ctoxU4FUe43kwc=
+github.com/zclconf/go-cty v1.13.1/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
-golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
-golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
-golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
+golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
+golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
-golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
diff --git a/label_iter.go b/label_iter.go
index af8ccba..eb87568 100644
--- a/label_iter.go
+++ b/label_iter.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package svchost
 
 import (
diff --git a/svchost.go b/svchost.go
index 22f6338..45a7029 100644
--- a/svchost.go
+++ b/svchost.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 // Package svchost deals with the representations of the so-called "friendly
 // hostnames" that we use to represent systems that provide Terraform-native
 // remote services, such as module registry, remote operations, etc.
diff --git a/svchost_test.go b/svchost_test.go
index 76e8133..af4137b 100644
--- a/svchost_test.go
+++ b/svchost_test.go
@@ -1,3 +1,5 @@
+// Copyright (c) HashiCorp, Inc.
+
 package svchost
 
 import "testing"

More details

Full run details