Repository: knative/pkg (go)

Issue:
Eventing TLS: Add AddressableFromDestination method on the resolver
After https://github.com/knative/pkg/issues/2711 is implemented, as the [Eventing TLS feature track](https://docs.google.com/document/d/1H-x_oji8LqkCyd7tlsSyclmUe7FAmEJPgRxOU_0pkn8/edit) describes we should add a new method on the [resolver](https://github.com/knative/pkg/blob/main/resolver/addressable_resolver.go) as follow:

```golang
AddressableFromDestination(ctx Context, dest Destination, parent interface{}) (*Addressable, error)
```

The implementation should be similar to `URIFromDestination`

https://github.com/knative/pkg/blob/main/resolver/addressable_resolver.go#L75-L76C10

but with the following additional algorithm/logic:

- If status.addresses of the resolved destination is set (has at least 1 element)
  - if dest.ref.address is not specified:
    - Select the first (in order) address from all addresses
    - If no address is found use status.address of the resolved destination
  -  else
     - Select the first (in order) address from all addresses with name == dest.ref.address
     - If no address is found return an error explaining that the address with name <address_value> cannot be found/resolved
- else return `status.address` of the resolved destination


Since the new `AddressableFromDestination` is a superset of `URIFromDestination`, the `URIFromDestination` should make use of the `AddressableFromDestination` method but return the  resolved URI

## Additional Info

- https://docs.google.com/document/d/1H-x_oji8LqkCyd7tlsSyclmUe7FAmEJPgRxOU_0pkn8/edit?resourcekey=0-lzDIPJsZOP3G17QE_g1lHw#

/good-first-issue
/kind feature
/area API


Pull request description:
Eventing TLS: Added AddressableFromDestination method on the resolver
<!-- Thanks for sending a pull request! -->

# Changes

<!-- 
Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! 

- :gift: Add new feature
- :bug: Fix bug
- :broom: Update or clean up current behavior
- :wastebasket: Remove feature or internal logic
-->

- :gift: Add new feature
- :broom: Update or clean up current behavior
- as the [Eventing TLS feature track](https://docs.google.com/document/d/1H-x_oji8LqkCyd7tlsSyclmUe7FAmEJPgRxOU_0pkn8/edit) describes I added AddressableFromDestination on the [resolver](https://github.com/knative/pkg/blob/main/resolver/addressable_resolver.go?rgh-link-date=2023-04-03T12%3A48%3A46Z) as follow:

```go
AddressableFromDestination(ctx Context, dest Destination, parent interface{}) (*Addressable, error)
```

<!--
In addition, categorize the changes you're making using the "/kind" Prow command, example:

/kind <kind>

Supported kinds are: api-change, bug, cleanup, deprecation, removal, documentation, enhancement, performance

-->
/kind feature

<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #2714

<!-- Please include the 'why' behind your changes if no issue exists -->

**Release Note**

<!--
:page_facing_up: If this change has user-visible impact, write a release note in the block
below. Include the string "action required" if additional action is required of
users switching to the new release, for example in case of a breaking change.

Write as if you are speaking to users, not other Knative contributors. If this
change has no user-visible impact, no release-note is needed.
-->
```release-note
Added AddressableFromDestination method on the resolver
```

**Docs**

<!--
:book: If this change has user-visible impact, link to an issue or PR in
https://github.com/knative/docs.

See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files

Please use the following format for linking documentation:
- [knative/docs]: <issue or pr link>
- [Feature Track]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```


Patch:
diff --git a/.github/workflows/knative-releasability.yaml b/.github/workflows/knative-releasability.yaml
deleted file mode 100644
index 1c360e3af..000000000
--- a/.github/workflows/knative-releasability.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2022 The Knative Authors.
-# SPDX-License-Identifier: Apache-2.0
-
-# This file is automagically synced here from github.com/knative-sandbox/knobots
-
-name: 'Releasability'
-
-on:
-  schedule:
-    - cron: '0 1 * * 1-5' # 6am Pacific, weekdays.
-
-  workflow_dispatch:      # Manual trigger.
-    inputs:
-      releaseFamily:
-        description: 'Release? (vX.Y)'
-        required: false
-      moduleReleaseFamily:
-        description: 'Module Release? (vX.Y)'
-        required: false
-      slackChannel:
-        description: 'Slack Channel'
-        required: false
-
-jobs:
-  releasability:
-    uses: knative/actions/.github/workflows/reusable-releasability.yaml@main
-    with:
-      releaseFamily: ${{ github.event.inputs.releaseFamily || 'v1.9' }}
-      moduleReleaseFamily: ${{ github.event.inputs.moduleReleaseFamily || 'v0.36' }}
-      slackChannel: ${{ github.event.inputs.slackChannel }}
-    secrets:
-      SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
diff --git a/.github/workflows/knative-release-notes.yaml b/.github/workflows/knative-release-notes.yaml
deleted file mode 100644
index 1e63da78a..000000000
--- a/.github/workflows/knative-release-notes.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2020 The Knative Authors.
-# SPDX-License-Identifier: Apache-2.0
-
-# This file is automagically synced here from github.com/knative-sandbox/knobots
-
-name: 'Release Notes'
-
-on:
-  workflow_dispatch:
-    inputs:
-      branch:
-        description: 'Branch'
-        required: true
-        default: 'main'
-      start-rev:
-        description: 'Start Tag (defaults to merge-base(branch, prev-branch))'
-        required: false
-      end-rev:
-        description: 'End Tag (defaults to HEAD of the target branch)'
-        required: false
-
-jobs:
-  release-notes:
-    uses: knative/actions/.github/workflows/reusable-release-notes.yaml@main
-    with:
-      branch: ${{ github.event.inputs.branch }}
-      start-rev: ${{ github.event.inputs.start-rev }}
-      end-rev: ${{ github.event.inputs.end-rev }}
diff --git a/.github/workflows/knative-vulnerability.yaml b/.github/workflows/knative-vulnerability.yaml
deleted file mode 100644
index 828acae6d..000000000
--- a/.github/workflows/knative-vulnerability.yaml
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2021 The Knative Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This file is automagically synced here from github.com/knative-sandbox/.github
-# repo by knobots: https://github.com/knative-sandbox/knobots and will be overwritten.
-
-name: 'Vulnerability scan'
-
-on:
-  schedule:
-    - cron: '0 1 1,15 * *' # 6am Pacific, 1st of the month to not exceed limits (200 total for all repos).
-  workflow_dispatch: {}
-
-jobs:
-  snyk:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@master
-
-      - name: Run Snyk to check for vulnerabilities
-        uses: snyk/actions/golang@master
-        continue-on-error: true # To make sure that SARIF upload gets called
-        env:
-          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
-        with:
-          args: --sarif-file-output=snyk.sarif
-
-      - name: Upload result to GitHub Code Scanning
-        uses: github/codeql-action/upload-sarif@v1
-        with:
-          sarif_file: snyk.sarif
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 078b1b75e..2f03e1499 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -23,10 +23,8 @@ aliases:
   - pmbanugo
   - snneji
   docs-wg-leads:
-  - abrennan89
   - snneji
   docs-writers:
-  - abrennan89
   - csantanapr
   - psschwei
   - snneji
@@ -71,6 +69,8 @@ aliases:
   - lance
   - mchmarny
   - nainaz
+  - pierDipi
+  - pradnyavmw
   - psschwei
   - puerco
   - salaboy
@@ -78,8 +78,10 @@ aliases:
   - upodroid
   - zroubalik
   knative-release-leads:
-  - evankanderson
-  - psschwei
+  - dsimansk
+  - kvmware
+  - pierDipi
+  - pradnyavmw
   knative-robots:
   - knative-automation
   - knative-prow-releaser-robot
@@ -155,8 +157,6 @@ aliases:
   - mchmarny
   - smoser-ibm
   ux-wg-leads:
-  - abrennan89
   - snneji
   ux-writers:
-  - abrennan89
   - snneji
diff --git a/apis/duck/v1/knative_reference.go b/apis/duck/v1/knative_reference.go
index c723c147a..4d03b6b97 100644
--- a/apis/duck/v1/knative_reference.go
+++ b/apis/duck/v1/knative_reference.go
@@ -128,3 +128,12 @@ func isKReferenceGroupAllowed(ctx context.Context) bool {
 func KReferenceGroupAllowed(ctx context.Context) context.Context {
 	return context.WithValue(ctx, isGroupAllowed{}, struct{}{})
 }
+
+func (kr *KReference) String() string {
+	address := ""
+	if kr.Address != nil {
+		address = *kr.Address
+	}
+	return fmt.Sprintf("Kind = %s, Namespace = %s, Name = %s, APIVersion = %s, Group = %s, Address = %s",
+		kr.Kind, kr.Namespace, kr.Name, kr.APIVersion, kr.Group, address)
+}
diff --git a/go.mod b/go.mod
index 9b6818712..e8946386f 100644
--- a/go.mod
+++ b/go.mod
@@ -50,7 +50,7 @@ require (
 	k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9
 	k8s.io/klog/v2 v2.80.2-0.20221028030830-9ae4992afb54
 	k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2
-	knative.dev/hack v0.0.0-20230330174700-1421f120c36b
+	knative.dev/hack v0.0.0-20230417170854-f591fea109b3
 	sigs.k8s.io/yaml v1.3.0
 )
 
diff --git a/go.sum b/go.sum
index 245128207..3188663f9 100644
--- a/go.sum
+++ b/go.sum
@@ -962,8 +962,8 @@ k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkI
 k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
 k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2 h1:GfD9OzL11kvZN5iArC6oTS7RTj7oJOIfnislxYlqTj8=
 k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-knative.dev/hack v0.0.0-20230330174700-1421f120c36b h1:20HMZEfXRdMPObZcV2MiZmcoJ9ms98qeWx0aUoHUAnc=
-knative.dev/hack v0.0.0-20230330174700-1421f120c36b/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q=
+knative.dev/hack v0.0.0-20230417170854-f591fea109b3 h1:+W4WBOq83tfGXKhtv8OB/uJeYqze3zh69GKiz1ucuqk=
+knative.dev/hack v0.0.0-20230417170854-f591fea109b3/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q=
 pgregory.net/rapid v0.3.3 h1:jCjBsY4ln4Atz78QoBWxUEvAHaFyNDQg9+WU62aCn1U=
 pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/metrics/opencensus_exporter.go b/metrics/opencensus_exporter.go
index eaeac4a56..59e33ab09 100644
--- a/metrics/opencensus_exporter.go
+++ b/metrics/opencensus_exporter.go
@@ -99,7 +99,7 @@ func getCredentials(component string, secret *corev1.Secret, logger *zap.Sugared
 		return nil
 	}
 	return credentials.NewTLS(&tls.Config{
-		MinVersion: tls.VersionTLS12,
+		MinVersion: tls.VersionTLS13,
 		GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
 			cert, err := tls.X509KeyPair(secret.Data["client-cert.pem"], secret.Data["client-key.pem"])
 			if err != nil {
diff --git a/resolver/addressable_resolver.go b/resolver/addressable_resolver.go
index d6995947a..c53a13d39 100644
--- a/resolver/addressable_resolver.go
+++ b/resolver/addressable_resolver.go
@@ -26,6 +26,7 @@ import (
 
 	"knative.dev/pkg/client/injection/ducks/duck/v1/addressable"
 	"knative.dev/pkg/controller"
+	"knative.dev/pkg/network"
 
 	corev1 "k8s.io/api/core/v1"
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
@@ -35,7 +36,6 @@ import (
 	pkgapisduck "knative.dev/pkg/apis/duck"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
 	duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
-	"knative.dev/pkg/network"
 	"knative.dev/pkg/tracker"
 )
 
@@ -74,9 +74,9 @@ func NewURIResolverFromTracker(ctx context.Context, t tracker.Interface, resolve
 
 // URIFromDestination resolves a v1beta1.Destination into a URI string.
 func (r *URIResolver) URIFromDestination(ctx context.Context, dest duckv1beta1.Destination, parent interface{}) (string, error) {
-	var deprecatedObjectReference *corev1.ObjectReference
+	var deprecatedObjectReference *duckv1.KReference
 	if !(dest.DeprecatedAPIVersion == "" && dest.DeprecatedKind == "" && dest.DeprecatedName == "" && dest.DeprecatedNamespace == "") {
-		deprecatedObjectReference = &corev1.ObjectReference{
+		deprecatedObjectReference = &duckv1.KReference{
 			Kind:       dest.DeprecatedKind,
 			APIVersion: dest.DeprecatedAPIVersion,
 			Name:       dest.DeprecatedName,
@@ -86,41 +86,64 @@ func (r *URIResolver) URIFromDestination(ctx context.Context, dest duckv1beta1.D
 	if dest.Ref != nil && deprecatedObjectReference != nil {
 		return "", errors.New("ref and [apiVersion, kind, name] can't be both present")
 	}
-	var ref *corev1.ObjectReference
+
+	var ref *duckv1.KReference
 	if dest.Ref != nil {
-		ref = dest.Ref
+		ref = &duckv1.KReference{
+			Kind:       dest.Ref.Kind,
+			Namespace:  dest.Ref.Namespace,
+			Name:       dest.Ref.Name,
+			APIVersion: dest.Ref.APIVersion,
+		}
 	} else {
 		ref = deprecatedObjectReference
 	}
-	if ref != nil {
-		url, err := r.URIFromObjectReference(ctx, ref, parent)
-		if err != nil {
-			return "", err
-		}
-		if dest.URI != nil {
-			if dest.URI.URL().IsAbs() {
-				return "", errors.New("absolute URI is not allowed when Ref or [apiVersion, kind, name] exists")
-			}
-			return url.ResolveReference(dest.URI).String(), nil
-		}
-		return url.URL().String(), nil
-	}
 
-	if dest.URI != nil {
-		// IsAbs check whether the URL has a non-empty scheme. Besides the non non-empty scheme, we also require dest.URI has a non-empty host
-		if !dest.URI.URL().IsAbs() || dest.URI.Host == "" {
-			return "", fmt.Errorf("URI is not absolute (both scheme and host should be non-empty): %q", dest.URI.String())
-		}
-		return dest.URI.String(), nil
+	u, err := r.URIFromDestinationV1(ctx, duckv1.Destination{Ref: ref, URI: dest.URI, CACerts: dest.CACerts}, parent)
+	if err != nil {
+		return "", err
 	}
-
-	return "", errors.New("destination missing Ref, [apiVersion, kind, name] and URI, expected at least one")
+	return u.String(), nil
 }
 
 // URIFromDestinationV1 resolves a v1.Destination into a URL.
 func (r *URIResolver) URIFromDestinationV1(ctx context.Context, dest duckv1.Destination, parent interface{}) (*apis.URL, error) {
+	addr, err := r.AddressableFromDestinationV1(ctx, dest, parent)
+	if err != nil {
+		return nil, err
+	}
+	return addr.URL, nil
+}
+
+func (r *URIResolver) URIFromKReference(ctx context.Context, ref *duckv1.KReference, parent interface{}) (*apis.URL, error) {
+	dest := duckv1.Destination{
+		Ref: ref,
+	}
+	addr, err := r.AddressableFromDestinationV1(ctx, dest, parent)
+	if err != nil {
+		return nil, err
+	}
+	return addr.URL, nil
+}
+
+// URIFromObjectReference resolves an ObjectReference to a URI string.
+func (r *URIResolver) URIFromObjectReference(ctx context.Context, ref *corev1.ObjectReference, parent interface{}) (*apis.URL, error) {
+	if ref == nil {
+		return nil, apierrs.NewBadRequest("ref is nil")
+	}
+	dest := duckv1.KReference{
+		Kind:       ref.Kind,
+		Namespace:  ref.Namespace,
+		Name:       ref.Name,
+		APIVersion: ref.APIVersion,
+	}
+	return r.URIFromKReference(ctx, &dest, parent)
+}
+
+// AddressableFromDestinationV1 resolves a v1.Destination into a duckv1.Addressable.
+func (r *URIResolver) AddressableFromDestinationV1(ctx context.Context, dest duckv1.Destination, parent interface{}) (*duckv1.Addressable, error) {
 	if dest.Ref != nil {
-		url, err := r.URIFromKReference(ctx, dest.Ref, parent)
+		addr, err := r.addressableFromDestinationRef(ctx, dest, parent)
 		if err != nil {
 			return nil, err
 		}
@@ -128,50 +151,60 @@ func (r *URIResolver) URIFromDestinationV1(ctx context.Context, dest duckv1.Dest
 			if dest.URI.URL().IsAbs() {
 				return nil, errors.New("absolute URI is not allowed when Ref or [apiVersion, kind, name] exists")
 			}
-			return url.ResolveReference(dest.URI), nil
+			addr.URL = addr.URL.ResolveReference(dest.URI)
+			return addr, nil
 		}
-		return url, nil
+		return addr, nil
 	}
 
 	if dest.URI != nil {
 		// IsAbs check whether the URL has a non-empty scheme. Besides the non non-empty scheme, we also require dest.URI has a non-empty host
 		if !dest.URI.URL().IsAbs() || dest.URI.Host == "" {
-			return nil, fmt.Errorf("URI is not absolute(both scheme and host should be non-empty): %q", dest.URI.String())
+			return nil, fmt.Errorf("URI is not absolute (both scheme and host should be non-empty): %q", dest.URI.String())
 		}
-		return dest.URI, nil
+		return &duckv1.Addressable{
+			URL:     dest.URI,
+			CACerts: dest.CACerts,
+		}, nil
 	}
 
 	return nil, errors.New("destination missing Ref and URI, expected at least one")
 }
 
-func (r *URIResolver) URIFromKReference(ctx context.Context, ref *duckv1.KReference, parent interface{}) (*apis.URL, error) {
-	return r.URIFromObjectReference(ctx, &corev1.ObjectReference{Name: ref.Name, Namespace: ref.Namespace, APIVersion: ref.APIVersion, Kind: ref.Kind}, parent)
-}
-
-// URIFromObjectReference resolves an ObjectReference to a URI string.
-func (r *URIResolver) URIFromObjectReference(ctx context.Context, ref *corev1.ObjectReference, parent interface{}) (*apis.URL, error) {
-	if ref == nil {
+func (r *URIResolver) addressableFromDestinationRef(ctx context.Context, dest duckv1.Destination, parent interface{}) (*duckv1.Addressable, error) {
+	if dest.Ref == nil {
 		return nil, apierrs.NewBadRequest("ref is nil")
 	}
 
+	or := &corev1.ObjectReference{
+		Kind:       dest.Ref.Kind,
+		Namespace:  dest.Ref.Namespace,
+		Name:       dest.Ref.Name,
+		APIVersion: dest.Ref.APIVersion,
+	}
+
 	// try custom resolvers first
 	for _, resolver := range r.resolvers {
-		handled, url, err := resolver(ctx, ref)
+		handled, url, err := resolver(ctx, or)
 		if handled {
-			return url, err
+			return &duckv1.Addressable{
+				Name:    dest.Ref.Address,
+				URL:     url,
+				CACerts: dest.CACerts,
+			}, err
 		}
 
 		// when handled is false, both url and err are ignored.
 	}
 
-	gvr, _ := meta.UnsafeGuessKindToResource(ref.GroupVersionKind())
+	gvr, _ := meta.UnsafeGuessKindToResource(or.GroupVersionKind())
 	if err := r.tracker.TrackReference(tracker.Reference{
-		APIVersion: ref.APIVersion,
-		Kind:       ref.Kind,
-		Namespace:  ref.Namespace,
-		Name:       ref.Name,
+		APIVersion: dest.Ref.APIVersion,
+		Kind:       dest.Ref.Kind,
+		Namespace:  dest.Ref.Namespace,
+		Name:       dest.Ref.Name,
 	}, parent); err != nil {
-		return nil, fmt.Errorf("failed to track reference %s %s/%s: %w", gvr.String(), ref.Namespace, ref.Name, err)
+		return nil, fmt.Errorf("failed to track reference %s %s/%s: %w", gvr.String(), dest.Ref.Namespace, dest.Ref.Name, err)
 	}
 
 	lister, err := r.listerFactory(gvr)
@@ -179,35 +212,80 @@ func (r *URIResolver) URIFromObjectReference(ctx context.Context, ref *corev1.Ob
 		return nil, fmt.Errorf("failed to get lister for %s: %w", gvr.String(), err)
 	}
 
-	obj, err := lister.ByNamespace(ref.Namespace).Get(ref.Name)
+	obj, err := lister.ByNamespace(dest.Ref.Namespace).Get(dest.Ref.Name)
 	if err != nil {
-		return nil, fmt.Errorf("failed to get object %s/%s: %w", ref.Namespace, ref.Name, err)
+		return nil, fmt.Errorf("failed to get object %s/%s: %w", dest.Ref.Namespace, dest.Ref.Name, err)
 	}
 
 	// K8s Services are special cased. They can be called, even though they do not satisfy the
 	// Callable interface.
-	if ref.APIVersion == "v1" && ref.Kind == "Service" {
+	if dest.Ref.APIVersion == "v1" && dest.Ref.Kind == "Service" {
 		url := &apis.URL{
 			Scheme: "http",
-			Host:   network.GetServiceHostname(ref.Name, ref.Namespace),
+			Host:   network.GetServiceHostname(dest.Ref.Name, dest.Ref.Namespace),
 			Path:   "",
 		}
-		return url, nil
+		if dest.CACerts != nil && *dest.CACerts != "" {
+			url.Scheme = "https"
+		}
+		return &duckv1.Addressable{
+			Name:    dest.Ref.Address,
+			URL:     url,
+			CACerts: dest.CACerts,
+		}, nil
 	}
 
 	addressable, ok := obj.(*duckv1.AddressableType)
 	if !ok {
-		return nil, apierrs.NewBadRequest(fmt.Sprintf("%+v (%T) is not an AddressableType", ref, ref))
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("%s(%T) is not an AddressableType", dest.Ref, dest.Ref))
 	}
-	if addressable.Status.Address == nil {
-		return nil, apierrs.NewBadRequest(fmt.Sprintf("address not set for %+v", ref))
+
+	addr, err := r.selectAddress(dest, addressable)
+	if err != nil {
+		return nil, err
 	}
-	url := addressable.Status.Address.URL
-	if url == nil {
-		return nil, apierrs.NewBadRequest(fmt.Sprintf("URL missing in address of %+v", ref))
+	// Do not modify informer copy.
+	addr = addr.DeepCopy()
+
+	if addr.URL == nil {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("URL missing in address of %s", dest.Ref))
 	}
-	if url.Host == "" {
-		return nil, apierrs.NewBadRequest(fmt.Sprintf("hostname missing in address of %+v", ref))
+	if addr.URL.Host == "" {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("hostname missing in address of %s", dest.Ref))
 	}
-	return url, nil
+
+	if addr.CACerts == nil {
+		addr.CACerts = dest.CACerts
+	}
+
+	return addr, nil
+}
+
+// selectAddress selects a single address from the given AddressableType
+func (r *URIResolver) selectAddress(dest duckv1.Destination, addressable *duckv1.AddressableType) (*duckv1.Addressable, error) {
+	if len(addressable.Status.Addresses) == 0 && addressable.Status.Address == nil {
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("address not set for %s", dest.Ref))
+	}
+
+	// if dest.ref.address is specified:
+	// - select the first (in order) address from status.addresses with name == dest.ref.address
+	// - If no address is found return an error explaining that the address with name dest.ref.address
+	//   cannot be found/resolved
+	if dest.Ref.Address != nil && *dest.Ref.Address != "" {
+		for _, addr := range addressable.Status.Addresses {
+			if addr.Name != nil && *addr.Name == *dest.Ref.Address {
+				return &addr, nil
+			}
+		}
+		return nil, apierrs.NewBadRequest(fmt.Sprintf("address with name %q not found for %s", *dest.Ref.Address, dest.Ref))
+	}
+
+	// if dest.ref.address is not specified:
+	// - select the first (in order) address from status.addresses
+	// - If no address is found in addresses use status.address
+	if len(addressable.Status.Addresses) > 0 {
+		return &addressable.Status.Addresses[0], nil
+	}
+
+	return addressable.Status.Address, nil
 }
diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh
index 2a411db1e..df9d3f9ad 100644
--- a/vendor/knative.dev/hack/library.sh
+++ b/vendor/knative.dev/hack/library.sh
@@ -657,7 +657,7 @@ function foreach_go_module() {
       echo "Command '${cmd}' failed in module $gomod_dir: $failed" >&2
       return $failed
     fi
-  done < <(go_run knative.dev/toolbox/modscope@latest ls -p)
+  done < <(go_run knative.dev/test-infra/tools/modscope@latest ls -p)
 }
 
 # Update go deps.
@@ -709,7 +709,7 @@ function __go_update_deps_for_module() {
     else
       group "Upgrading to release ${RELEASE}"
     fi
-    FLOATING_DEPS+=( $(go_run knative.dev/toolbox/buoy@latest float ./go.mod "${buoyArgs[@]}") )
+    FLOATING_DEPS+=( $(go_run knative.dev/test-infra/buoy@latest float ./go.mod "${buoyArgs[@]}") )
     if [[ ${#FLOATING_DEPS[@]} > 0 ]]; then
       echo "Floating deps to ${FLOATING_DEPS[@]}"
       go get -d ${FLOATING_DEPS[@]}
@@ -754,7 +754,7 @@ function __go_update_deps_for_module() {
 # Intended to be used like:
 #   export MODULE_NAME=$(go_mod_module_name)
 function go_mod_module_name() {
-  go_run knative.dev/toolbox/modscope@latest current
+  go_run knative.dev/test-infra/tools/modscope@latest current
 }
 
 # Return a GOPATH to a temp directory. Works around the out-of-GOPATH issues
@@ -778,7 +778,7 @@ function go_mod_gopath_hack() {
 # Run kntest tool
 # Parameters: $1..$n - parameters passed to the tool.
 function run_kntest() {
-  go_run knative.dev/toolbox/kntest/cmd/kntest@latest "$@"
+  go_run knative.dev/test-infra/tools/kntest/cmd/kntest@latest "$@"
 }
 
 # Run go-licenses to update licenses.
diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh
index 135fa8b7c..5d4f09a89 100644
--- a/vendor/knative.dev/hack/release.sh
+++ b/vendor/knative.dev/hack/release.sh
@@ -51,6 +51,7 @@ function tag_images_in_yamls() {
   local DOCKER_BASE="${KO_DOCKER_REPO}/${REPO_ROOT_DIR/$SRC_DIR}"
   local GEO_REGIONS="${GEO_REPLICATION[@]} "
   echo "Tagging any images under '${DOCKER_BASE}' with ${TAG}"
+  # shellcheck disable=SC2068
   for file in $@; do
     [[ "${file##*.}" != "yaml" ]] && continue
     echo "Inspecting ${file}"
@@ -316,7 +317,8 @@ function build_from_source() {
 function get_images_in_yamls() {
   rm -rf "$IMAGES_REFS_FILE"
   echo "Assembling a list of image refences to sign"
-  for file in "$@"; do
+  # shellcheck disable=SC2068
+  for file in $@; do
     [[ "${file##*.}" != "yaml" ]] && continue
     echo "Inspecting ${file}"
     while read -r image; do
@@ -407,10 +409,11 @@ function sign_release() {
   if [[ -f "$IMAGES_REFS_FILE" ]]; then
     COSIGN_EXPERIMENTAL=1 cosign sign $(cat "$IMAGES_REFS_FILE") \
       --recursive --identity-token="${ID_TOKEN}"
+    cp "${IMAGES_REFS_FILE}" "${ARTIFACTS}"
     if  [ -n "${ATTEST_IMAGES:-}" ]; then # Temporary Feature Gate
       provenance-generator --clone-log=/logs/clone.json \
         --image-refs="$IMAGES_REFS_FILE" --output=attestation.json
-      mkdir -p "${ARTIFACTS}"/attestation && cp attestation.json "${ARTIFACTS}"/attestation
+      mkdir -p "${ARTIFACTS}" && cp attestation.json "${ARTIFACTS}"
       COSIGN_EXPERIMENTAL=1 cosign attest $(cat "$IMAGES_REFS_FILE") \
         --recursive --identity-token="${ID_TOKEN}" \
         --predicate=attestation.json --type=slsaprovenance
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c5e2d9fd5..5a3430c56 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1118,7 +1118,7 @@ k8s.io/utils/net
 k8s.io/utils/pointer
 k8s.io/utils/strings/slices
 k8s.io/utils/trace
-# knative.dev/hack v0.0.0-20230330174700-1421f120c36b
+# knative.dev/hack v0.0.0-20230417170854-f591fea109b3
 ## explicit; go 1.18
 knative.dev/hack
 # sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2
diff --git a/webhook/env.go b/webhook/env.go
index da8a1bd89..ffb757011 100644
--- a/webhook/env.go
+++ b/webhook/env.go
@@ -17,6 +17,7 @@ limitations under the License.
 package webhook
 
 import (
+	"crypto/tls"
 	"fmt"
 	"os"
 	"strconv"
@@ -29,6 +30,8 @@ const (
 	webhookNameEnvKey = "WEBHOOK_NAME"
 
 	secretNameEnvKey = "WEBHOOK_SECRET_NAME" //nolint:gosec // This is not a hardcoded credential
+
+	tlsMinVersionEnvKey = "WEBHOOK_TLS_MIN_VERSION"
 )
 
 // PortFromEnv returns the webhook port set by portEnvKey, or default port if env var is not set.
@@ -66,3 +69,16 @@ func SecretNameFromEnv(defaultSecretName string) string {
 	}
 	return secret
 }
+
+func TLSMinVersionFromEnv(defaultTLSMinVersion uint16) uint16 {
+	switch tlsMinVersion := os.Getenv(tlsMinVersionEnvKey); tlsMinVersion {
+	case "1.2":
+		return tls.VersionTLS12
+	case "1.3":
+		return tls.VersionTLS13
+	case "":
+		return defaultTLSMinVersion
+	default:
+		panic(fmt.Sprintf("the environment variable %q has to be either '1.2' or '1.3'", tlsMinVersionEnvKey))
+	}
+}
diff --git a/webhook/webhook.go b/webhook/webhook.go
index 6099e6ac5..779d388d2 100644
--- a/webhook/webhook.go
+++ b/webhook/webhook.go
@@ -40,6 +40,10 @@ import (
 
 // Options contains the configuration for the webhook
 type Options struct {
+	// TLSMinVersion contains the minimum TLS version that is acceptable to communicate with the API server.
+	// TLS 1.3 is the minimum version if not specified otherwise.
+	TLSMinVersion uint16
+
 	// ServiceName is the service name of the webhook.
 	ServiceName string
 
@@ -119,6 +123,13 @@ func New(
 		opts.StatsReporter = reporter
 	}
 
+	defaultTLSMinVersion := uint16(tls.VersionTLS13)
+	if opts.TLSMinVersion == 0 {
+		opts.TLSMinVersion = TLSMinVersionFromEnv(defaultTLSMinVersion)
+	} else if opts.TLSMinVersion != tls.VersionTLS12 && opts.TLSMinVersion != tls.VersionTLS13 {
+		return nil, fmt.Errorf("unsupported TLS version: %d", opts.TLSMinVersion)
+	}
+
 	syncCtx, cancel := context.WithCancel(context.Background())
 
 	webhook = &Webhook{
@@ -136,7 +147,7 @@ func New(
 		secretInformer := kubeinformerfactory.Get(ctx).Core().V1().Secrets()
 
 		webhook.tlsConfig = &tls.Config{
-			MinVersion: tls.VersionTLS12,
+			MinVersion: opts.TLSMinVersion,
 
 			// If we return (nil, error) the client sees - 'tls: internal error"
 			// If we return (nil, nil) the client sees - 'tls: no certificates configured'


Test patch:
diff --git a/network/transports_test.go b/network/transports_test.go
index 3cb58ebda..112219dd3 100644
--- a/network/transports_test.go
+++ b/network/transports_test.go
@@ -189,7 +189,7 @@ func exampleTLSConf() *tls.Config {
 	return &tls.Config{
 		InsecureSkipVerify: false,
 		ServerName:         "example.com",
-		MinVersion:         tls.VersionTLS12,
+		MinVersion:         tls.VersionTLS13,
 	}
 }
 
diff --git a/resolver/addressable_resolver_test.go b/resolver/addressable_resolver_test.go
index 86526c5a0..5cb699b98 100644
--- a/resolver/addressable_resolver_test.go
+++ b/resolver/addressable_resolver_test.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/equality"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/runtime/schema"
@@ -42,10 +43,16 @@ import (
 
 const (
 	addressableDNS                           = "http://addressable.sink.svc.cluster.local"
+	addressableDNS1                          = "http://addressable.sink1.svc.cluster.local"
+	addressableDNS2                          = "http://addressable.sink2.svc.cluster.local"
+	addressableDNS3                          = "http://addressable.sink3.svc.cluster.local"
 	addressableDNSWithPathAndTrailingSlash   = "http://addressable.sink.svc.cluster.local/bar/"
 	addressableDNSWithPathAndNoTrailingSlash = "http://addressable.sink.svc.cluster.local/bar"
 
 	addressableName       = "testsink"
+	addressableName1      = "testsink1"
+	addressableName2      = "testsink2"
+	addressableName3      = "testsink3"
 	addressableKind       = "Sink"
 	addressableAPIVersion = "duck.knative.dev/v1"
 
@@ -55,6 +62,21 @@ const (
 	unaddressableResource   = "kresources.duck.knative.dev"
 
 	testNS = "testnamespace"
+
+	CACert = `-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----`
 )
 
 func init() {
@@ -87,7 +109,7 @@ func TestGetURIDestinationV1Beta1(t *testing.T) {
 		wantURI string
 		wantErr string
 	}{"nil everything": {
-		wantErr: "destination missing Ref, [apiVersion, kind, name] and URI, expected at least one",
+		wantErr: "destination missing Ref and URI, expected at least one",
 	}, "Happy URI with path": {
 		dest: duckv1beta1.Destination{
 			URI: &apis.URL{
@@ -327,26 +349,26 @@ func TestGetURIDestinationV1Beta1(t *testing.T) {
 				addressableNilURL(),
 			},
 			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
-			wantErr: fmt.Sprintf("URL missing in address of %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("URL missing in address of %s", unaddressableKnativeRef()),
 		},
 		"nil address": {
 			objects: []runtime.Object{
 				addressableNilAddress(),
 			},
 			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
-			wantErr: fmt.Sprintf("address not set for %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
 		}, "missing host": {
 			objects: []runtime.Object{
 				addressableNoHostURL(),
 			},
 			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
-			wantErr: fmt.Sprintf("hostname missing in address of %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("hostname missing in address of %s", unaddressableKnativeRef()),
 		}, "missing status": {
 			objects: []runtime.Object{
 				addressableNoStatus(),
 			},
 			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
-			wantErr: fmt.Sprintf("address not set for %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
 		}, "notFound": {
 			dest:    duckv1beta1.Destination{Ref: unaddressableRef()},
 			wantErr: fmt.Sprintf("failed to get object %s/%s: %s %q not found", testNS, unaddressableName, unaddressableResource, unaddressableName),
@@ -404,14 +426,14 @@ func TestGetURIDestinationV1(t *testing.T) {
 				Host: "example.com",
 			},
 		},
-		wantErr: fmt.Sprintf("URI is not absolute(both scheme and host should be non-empty): %q", "//example.com"),
+		wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "//example.com"),
 	}, "URI with no host": {
 		dest: duckv1.Destination{
 			URI: &apis.URL{
 				Scheme: "http",
 			},
 		},
-		wantErr: fmt.Sprintf("URI is not absolute(both scheme and host should be non-empty): %q", "http:"),
+		wantErr: fmt.Sprintf("URI is not absolute (both scheme and host should be non-empty): %q", "http:"),
 	},
 		"happy ref": {
 			objects: []runtime.Object{
@@ -510,26 +532,26 @@ func TestGetURIDestinationV1(t *testing.T) {
 				addressableNilURL(),
 			},
 			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
-			wantErr: fmt.Sprintf("URL missing in address of %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("URL missing in address of %s", unaddressableKnativeRef()),
 		},
 		"nil address": {
 			objects: []runtime.Object{
 				addressableNilAddress(),
 			},
 			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
-			wantErr: fmt.Sprintf("address not set for %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
 		}, "missing host": {
 			objects: []runtime.Object{
 				addressableNoHostURL(),
 			},
 			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
-			wantErr: fmt.Sprintf("hostname missing in address of %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("hostname missing in address of %s", unaddressableKnativeRef()),
 		}, "missing status": {
 			objects: []runtime.Object{
 				addressableNoStatus(),
 			},
 			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
-			wantErr: fmt.Sprintf("address not set for %+v", unaddressableRef()),
+			wantErr: fmt.Sprintf("address not set for %s", unaddressableKnativeRef()),
 		}, "notFound": {
 			dest:    duckv1.Destination{Ref: unaddressableKnativeRef()},
 			wantErr: fmt.Sprintf("failed to get object %s/%s: %s %q not found", testNS, unaddressableName, unaddressableResource, unaddressableName),
@@ -628,6 +650,232 @@ Namespace: a lowercase RFC 1123 label must consist of lower case alphanumeric ch
 	}
 }
 
+func TestAddressableFromDestinationV1(t *testing.T) {
+	tests := map[string]struct {
+		objects         []runtime.Object
+		dest            duckv1.Destination
+		addr            *unstructured.Unstructured
+		customResolvers []resolver.RefResolverFunc
+		wantAddress     *duckv1.Addressable
+		wantErr         string
+	}{"address and addresses are not set": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableNoAddresses(),
+		},
+		addr:    addressableNoAddresses(),
+		wantErr: fmt.Sprintf("address not set for %s", addressableKnativeRef()),
+	}, "ref.address is set on destination and is present in target addressable addresses": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRefWithAddress(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableWithAddresses(),
+		},
+		wantAddress: addrWithNameAndCACerts(),
+		addr:        addressableWithAddresses(),
+	}, "ref.address is set on destination and is NOT present in target addressable addresses": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRefWithAddress(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableWithDifferentAddresses(),
+		},
+		addr:    addressableWithDifferentAddresses(),
+		wantErr: fmt.Sprintf("address with name %q not found for %s", *addressableKnativeRefWithAddress().Address, addressableKnativeRefWithAddress()),
+	}, "address and addresses are set but no destination.ref.address is set": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableWithAddresses(),
+		},
+		addr:        addressableWithAddresses(),
+		wantAddress: addrWithNameAndCACerts(),
+	}, "only address is set and no destination.ref.address is set": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableWithAddressOnly(),
+		},
+		addr:        addressableWithAddressOnly(),
+		wantAddress: addrWithNameAndCACerts(),
+	}}
+
+	for n, tc := range tests {
+		t.Run(n, func(t *testing.T) {
+			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
+			ctx = addressable.WithDuck(ctx)
+			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
+
+			// Run it twice since this should be idempotent. URI Resolver should
+			// not modify the cache's copy.
+			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+
+			if gotErr != nil {
+				if tc.wantErr != "" {
+					if got, want := gotErr.Error(), tc.wantErr; got != want {
+						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
+					}
+				} else {
+					t.Error("Unexpected error:", gotErr)
+				}
+				return
+			}
+			if !equality.Semantic.DeepEqual(addr, tc.wantAddress) {
+				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(addr, tc.wantAddress))
+			}
+		})
+	}
+}
+
+func TestAddressableFromDestinationScheme(t *testing.T) {
+	cert := CACert
+	tests := map[string]struct {
+		objects         []runtime.Object
+		dest            duckv1.Destination
+		addr            *unstructured.Unstructured
+		customResolvers []resolver.RefResolverFunc
+		wantScheme      string
+		wantErr         string
+	}{"destination is a raw k8s serving and there is CACerts set ": {
+		dest: duckv1.Destination{
+			Ref: k8sServiceRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+			CACerts: &cert,
+		},
+		objects: []runtime.Object{
+			getAddressableFromKRef(k8sServiceRef()),
+		},
+		wantScheme: "https",
+		addr:       addressableWithAddresses(),
+	}}
+
+	for n, tc := range tests {
+		t.Run(n, func(t *testing.T) {
+			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
+			ctx = addressable.WithDuck(ctx)
+			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
+
+			// Run it twice since this should be idempotent. URI Resolver should
+			// not modify the cache's copy.
+			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+
+			if gotErr != nil {
+				if tc.wantErr != "" {
+					if got, want := gotErr.Error(), tc.wantErr; got != want {
+						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
+					}
+				} else {
+					t.Error("Unexpected error:", gotErr)
+				}
+			}
+			if got, want := addr.URL.Scheme, tc.wantScheme; got != want {
+				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
+			}
+		})
+	}
+}
+
+func TestAddressableFromDestinationV1CACerts(t *testing.T) {
+	certDestination := "CA CERT FOR DESTINATION"
+	tests := map[string]struct {
+		objects         []runtime.Object
+		dest            duckv1.Destination
+		addr            *unstructured.Unstructured
+		customResolvers []resolver.RefResolverFunc
+		wantCert        string
+		wantErr         string
+	}{"CACerts is set on the target addressable": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+		},
+		objects: []runtime.Object{
+			addressableWithCACert(),
+		},
+		addr:     addressableWithCACert(),
+		wantErr:  fmt.Sprintf("address with name %q not found for %+v", *addressableKnativeRefWithAddress().Address, addressableKnativeRefWithAddress()),
+		wantCert: CACert,
+	}, "CACerts is not set on the target addressable but it is set on the destination": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+			CACerts: &certDestination,
+		},
+		objects: []runtime.Object{
+			addressableWithAddresses(),
+		},
+		addr:     addressableWithAddresses(),
+		wantCert: certDestination,
+	}, "CACerts is set on the target addressable and it is set on the destination": {
+		dest: duckv1.Destination{
+			Ref: addressableKnativeRef(),
+			URI: &apis.URL{
+				Path: "/foo",
+			},
+			CACerts: &certDestination,
+		},
+		objects: []runtime.Object{
+			addressableWithCACert(),
+		},
+		addr:     addressableWithCACert(),
+		wantCert: CACert,
+	}}
+
+	for n, tc := range tests {
+		t.Run(n, func(t *testing.T) {
+			ctx, _ := fakedynamicclient.With(context.Background(), scheme.Scheme, tc.objects...)
+			ctx = addressable.WithDuck(ctx)
+			r := resolver.NewURIResolverFromTracker(ctx, tracker.New(func(types.NamespacedName) {}, 0), tc.customResolvers...)
+
+			// Run it twice since this should be idempotent. URI Resolver should
+			// not modify the cache's copy.
+			_, _ = r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+			addr, gotErr := r.AddressableFromDestinationV1(ctx, tc.dest, tc.addr)
+
+			if gotErr != nil {
+				if tc.wantErr != "" {
+					if got, want := gotErr.Error(), tc.wantErr; got != want {
+						t.Errorf("Unexpected error (-want, +got) =\n%s", cmp.Diff(want, got))
+					}
+				} else {
+					t.Error("Unexpected error:", gotErr)
+				}
+			}
+			if got, want := *addr.CACerts, tc.wantCert; got != want {
+				t.Errorf("Unexpected object (-want, +got) =\n%s", cmp.Diff(want, got))
+			}
+		})
+	}
+}
+
 func getAddressable() *unstructured.Unstructured {
 	return &unstructured.Unstructured{
 		Object: map[string]interface{}{
@@ -776,6 +1024,17 @@ func addressableKnativeRef() *duckv1.KReference {
 	}
 }
 
+func addressableKnativeRefWithAddress() *duckv1.KReference {
+	address := addressableName
+	return &duckv1.KReference{
+		Kind:       addressableKind,
+		Name:       addressableName,
+		APIVersion: addressableAPIVersion,
+		Namespace:  testNS,
+		Address:    &address,
+	}
+}
+
 func addressableRef() *corev1.ObjectReference {
 	return &corev1.ObjectReference{
 		Kind:       addressableKind,
@@ -814,7 +1073,127 @@ func getAddressableFromKRef(ref *duckv1.KReference) *unstructured.Unstructured {
 			},
 			"status": map[string]interface{}{
 				"address": map[string]interface{}{
-					"url": addressableDNS,
+					"url":  addressableDNS,
+					"name": addressableDNS,
+				},
+			},
+		},
+	}
+}
+
+func addressableNoAddresses() *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": addressableAPIVersion,
+			"kind":       addressableKind,
+			"metadata": map[string]interface{}{
+				"namespace": testNS,
+				"name":      addressableName,
+			},
+			"status": map[string]interface{}{
+				"address":   map[string]interface{}(nil),
+				"addresses": []interface{}{},
+			},
+		},
+	}
+}
+
+func addressableWithAddresses() *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": addressableAPIVersion,
+			"kind":       addressableKind,
+			"metadata": map[string]interface{}{
+				"namespace": testNS,
+				"name":      addressableName,
+			},
+			"status": map[string]interface{}{
+				"address": map[string]interface{}{
+					"url":  addressableDNS,
+					"name": addressableName,
+				},
+				"addresses": []interface{}{
+					map[string]interface{}{
+						"url":  addressableDNS,
+						"name": addressableName,
+					}, map[string]interface{}{
+						"url":  addressableDNS1,
+						"name": addressableName1,
+					}, map[string]interface{}{
+						"url":  addressableDNS2,
+						"name": addressableName2,
+					}, map[string]interface{}{
+						"url":  addressableDNS3,
+						"name": addressableName3,
+					},
+				},
+			},
+		},
+	}
+}
+
+func addressableWithAddressOnly() *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": addressableAPIVersion,
+			"kind":       addressableKind,
+			"metadata": map[string]interface{}{
+				"namespace": testNS,
+				"name":      addressableName,
+			},
+			"status": map[string]interface{}{
+				"address": map[string]interface{}{
+					"url":  addressableDNS,
+					"name": addressableName,
+				},
+				"addresses": []interface{}{},
+			},
+		},
+	}
+}
+
+func addressableWithDifferentAddresses() *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": addressableAPIVersion,
+			"kind":       addressableKind,
+			"metadata": map[string]interface{}{
+				"namespace": testNS,
+				"name":      addressableName,
+			},
+			"status": map[string]interface{}{
+				"address": map[string]interface{}{
+					"url":  addressableDNS,
+					"name": addressableName,
+				},
+				"addresses": []interface{}{
+					map[string]interface{}{
+						"url":  addressableDNS1,
+						"name": addressableName1,
+					}, map[string]interface{}{
+						"url":  addressableDNS2,
+						"name": addressableName2,
+					},
+				},
+			},
+		},
+	}
+}
+
+func addressableWithCACert() *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": addressableAPIVersion,
+			"kind":       addressableKind,
+			"metadata": map[string]interface{}{
+				"namespace": testNS,
+				"name":      addressableName,
+			},
+			"status": map[string]interface{}{
+				"address": map[string]interface{}{
+					"url":     addressableDNS,
+					"name":    addressableName,
+					"CACerts": CACert,
 				},
 			},
 		},
@@ -835,3 +1214,15 @@ func sampleURIResolver(ctx context.Context, ref *corev1.ObjectReference) (bool,
 func noopURIResolver(ctx context.Context, ref *corev1.ObjectReference) (bool, *apis.URL, error) {
 	return false, nil, nil
 }
+
+func addrWithNameAndCACerts() *duckv1.Addressable {
+	addrName := addressableName
+	return &duckv1.Addressable{
+		Name: &addrName,
+		URL: &apis.URL{
+			Host:   "addressable.sink.svc.cluster.local",
+			Scheme: "http",
+			Path:   "/foo",
+		},
+	}
+}
diff --git a/vendor/knative.dev/hack/presubmit-tests.sh b/vendor/knative.dev/hack/presubmit-tests.sh
index 1c6e5a8df..1f6f18252 100644
--- a/vendor/knative.dev/hack/presubmit-tests.sh
+++ b/vendor/knative.dev/hack/presubmit-tests.sh
@@ -139,7 +139,7 @@ function __build_test_runner_for_module() {
   # Don't merge these two lines, or return code will always be 0.
   # Get all build tags in go code (ignore /vendor, /hack and /third_party)
   local tags
-  tags="$(go run knative.dev/toolbox/go-ls-tags@latest --joiner=,)"
+  tags="$(go run knative.dev/test-infra/tools/go-ls-tags@latest --joiner=,)"
   local go_pkg_dirs
   go_pkg_dirs="$(go list -tags "${tags}" ./...)" || return $?
   if [[ -z "${go_pkg_dirs}" ]]; then
diff --git a/webhook/env_test.go b/webhook/env_test.go
index df5a0db9e..b60beb349 100644
--- a/webhook/env_test.go
+++ b/webhook/env_test.go
@@ -17,14 +17,16 @@ limitations under the License.
 package webhook
 
 import (
+	"crypto/tls"
 	"testing"
 )
 
 const (
 	testMissingInputName = "MissingInput"
 
-	testDefaultPort       = 8888
-	testDefaultSecretName = "webhook-certs"
+	testDefaultPort          = 8888
+	testDefaultSecretName    = "webhook-certs"
+	testDefaultTLSMinVersion = tls.VersionTLS13
 )
 
 type portTest struct {
@@ -48,6 +50,13 @@ type secretNameTest struct {
 	wantPanic bool
 }
 
+type tlsMinVersionTest struct {
+	name      string
+	in        string
+	want      uint16
+	wantPanic bool
+}
+
 func TestPort(t *testing.T) {
 	tests := []portTest{{
 		name: testMissingInputName,
@@ -164,3 +173,51 @@ func TestSecretName(t *testing.T) {
 		})
 	}
 }
+
+func TestTLSMinVersion(t *testing.T) {
+	tests := []tlsMinVersionTest{{
+		name: testMissingInputName,
+		want: testDefaultTLSMinVersion,
+	}, {
+		name: "EmptyInput",
+		in:   "",
+		want: testDefaultTLSMinVersion,
+	}, {
+		name:      "InvalidInputTrailingSpace",
+		in:        "1.2  ",
+		wantPanic: true,
+	}, {
+		name:      "InvalidInput",
+		in:        "1.0",
+		wantPanic: true,
+	}, {
+		name: "ValidInputTLS12",
+		in:   "1.2",
+		want: tls.VersionTLS12,
+	}, {
+		name: "ValidInputTLS13",
+		in:   "1.3",
+		want: tls.VersionTLS13,
+	}}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			// tlsMinVersionEnvKey is unset when testing missing input.
+			if tc.name != testMissingInputName {
+				t.Setenv(tlsMinVersionEnvKey, tc.in)
+			}
+
+			defer func() {
+				if r := recover(); r == nil && tc.wantPanic {
+					t.Error("Did not panic")
+				} else if r != nil && !tc.wantPanic {
+					t.Error("Got unexpected panic")
+				}
+			}()
+
+			if got := TLSMinVersionFromEnv(testDefaultTLSMinVersion); got != tc.want {
+				t.Errorf("TLSMinVersionFromEnv = %d, want: %d", got, tc.want)
+			}
+		})
+	}
+}
diff --git a/webhook/webhook_test.go b/webhook/webhook_test.go
index 8cd4bc03b..34c95d3fe 100644
--- a/webhook/webhook_test.go
+++ b/webhook/webhook_test.go
@@ -18,6 +18,7 @@ package webhook
 
 import (
 	"context"
+	"crypto/tls"
 	"fmt"
 	"net"
 	"testing"
@@ -93,3 +94,34 @@ func TestRegistrationStopChanFire(t *testing.T) {
 		t.Error("Unexpected success to dial to port", opts.Port)
 	}
 }
+
+func newAdmissionControllerWebhook(t *testing.T, options Options, acs ...interface{}) (*Webhook, error) {
+	ctx, cancel, _ := SetupFakeContextWithCancel(t)
+	defer cancel()
+	ctx = WithOptions(ctx, options)
+	return New(ctx, acs)
+}
+
+func TestTLSMinVersionWebhookOption(t *testing.T) {
+	opts := newDefaultOptions()
+	t.Run("when TLSMinVersion is not configured, and the default is used", func(t *testing.T) {
+		_, err := newAdmissionControllerWebhook(t, opts)
+		if err != nil {
+			t.Fatal("Unexpected error", err)
+		}
+	})
+	t.Run("when the TLS minimum version configured is supported", func(t *testing.T) {
+		opts.TLSMinVersion = tls.VersionTLS12
+		_, err := newAdmissionControllerWebhook(t, opts)
+		if err != nil {
+			t.Fatal("Unexpected error", err)
+		}
+	})
+	t.Run("when the TLS minimum version configured is not supported", func(t *testing.T) {
+		opts.TLSMinVersion = tls.VersionTLS11
+		_, err := newAdmissionControllerWebhook(t, opts)
+		if err == nil {
+			t.Fatal("Admission Controller Webhook creation expected to fail due to unsupported TLS version")
+		}
+	})
+}