// Copyright 2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration

import (
	"encoding/base64"
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	corev1 "k8s.io/api/core/v1"

	"go.pinniped.dev/internal/certauthority"
	"go.pinniped.dev/internal/here"
	"go.pinniped.dev/test/testlib"
)

// TestTLSSpecValidationSupervisor_Parallel tests kubebuilder and status condition validation
// on the TLSSpec in Pinniped supervisor IdentityProvider CRDs.
func TestTLSSpecValidationSupervisor_Parallel(t *testing.T) {
	env := testlib.IntegrationEnv(t)

	ca, err := certauthority.New("pinniped-test", 24*time.Hour)
	require.NoError(t, err)
	indentedCAPEM := indentForHeredoc(string(ca.Bundle()))

	oidcIDPTemplate := here.Doc(`
		apiVersion: idp.supervisor.%s/v1alpha1
		kind: OIDCIdentityProvider
		metadata:
			name: %s
			namespace: %s
		spec:
			issuer: %s
			authorizationConfig:
				additionalScopes: [offline_access, email]
				allowPasswordGrant: true
			client:
				secretName: foo-bar-client-credentials
			%s
	`)

	ldapIDPTemplate := here.Doc(`
		apiVersion: idp.supervisor.%s/v1alpha1
		kind: LDAPIdentityProvider
		metadata:
			name: %s
			namespace: %s
		spec:
			host: %s
			bind:
				secretName: foo-bar-bind-credentials
			userSearch:
				base: foo
				attributes:
					username: bar
					uid: baz
			%s
	`)

	activeDirectoryIDPTemplate := here.Doc(`
		apiVersion: idp.supervisor.%s/v1alpha1
		kind: ActiveDirectoryIdentityProvider
		metadata:
			name: %s
			namespace: %s
		spec:
			host: %s
			bind:
				secretName: foo-bar-bind-credentials
			%s
	`)

	githubIDPTemplate := here.Doc(`
		apiVersion: idp.supervisor.%s/v1alpha1
		kind: GitHubIdentityProvider
		metadata:
			name: %s
			namespace: %s
		spec:
			allowAuthentication:
				organizations:
					policy: AllGitHubUsers
			client:
				secretName: does-not-matter
			githubAPI:
				%s
	`)

	testCases := []struct {
		name string

		tlsYAML func(secretOrConfigmapName string) string

		secretOrConfigmapKind     string
		secretType                string
		secretOrConfigmapDataYAML string

		wantErrorSnippets            []string
		wantGitHubErrorSnippets      []string
		wantTLSValidConditionMessage func(namespace string, secretOrConfigmapName string) string
	}{
		{
			name: "should disallow certificate authority data source with missing name",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							key: bar
				`)
			},
			wantErrorSnippets: []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.name: Required value`},
			wantGitHubErrorSnippets: []string{
				`The %s "%s" is invalid:`,
				"spec.githubAPI.tls.certificateAuthorityDataSource.name: Required value",
			},
		},
		{
			name: "should disallow certificate authority data source with empty value for name",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: ""
							key: bar
				`)
			},
			wantErrorSnippets:       []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.name: Invalid value: "": spec.tls.certificateAuthorityDataSource.name in body should be at least 1 chars long`},
			wantGitHubErrorSnippets: []string{`The %s "%s" is invalid: spec.githubAPI.tls.certificateAuthorityDataSource.name: Invalid value: "": spec.githubAPI.tls.certificateAuthorityDataSource.name in body should be at least 1 chars long`},
		},
		{
			name: "should disallow certificate authority data source with missing key",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: foo
				`)
			},
			wantErrorSnippets: []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.key: Required value`},
			wantGitHubErrorSnippets: []string{
				`The %s "%s" is invalid:`,
				"spec.githubAPI.tls.certificateAuthorityDataSource.key: Required value",
			},
		},
		{
			name: "should disallow certificate authority data source with empty value for key",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: foo
							key: ""
				`)
			},
			wantErrorSnippets:       []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.key: Invalid value: "": spec.tls.certificateAuthorityDataSource.key in body should be at least 1 chars long`},
			wantGitHubErrorSnippets: []string{`The %s "%s" is invalid: spec.githubAPI.tls.certificateAuthorityDataSource.key: Invalid value: "": spec.githubAPI.tls.certificateAuthorityDataSource.key in body should be at least 1 chars long`},
		},
		{
			name: "should disallow certificate authority data source with missing kind",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							name: foo
							key: bar
				`)
			},
			wantErrorSnippets: []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.kind: Required value`},
			wantGitHubErrorSnippets: []string{
				`The %s "%s" is invalid:`,
				"spec.githubAPI.tls.certificateAuthorityDataSource.kind: Required value",
			},
		},
		{
			name: "should disallow certificate authority data source with empty value for kind",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: ""
							name: foo
							key: bar
				`)
			},
			wantErrorSnippets: []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.kind: Unsupported value: "": supported values: "Secret", "ConfigMap"`},
			wantGitHubErrorSnippets: []string{
				`The %s "%s" is invalid:`,
				`spec.githubAPI.tls.certificateAuthorityDataSource.kind: Unsupported value: "": supported values: "Secret", "ConfigMap"`,
			},
		},
		{
			name: "should disallow certificate authority data source with invalid kind",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: sorcery
							name: foo
							key: bar
				`)
			},
			wantErrorSnippets: []string{`The %s "%s" is invalid: spec.tls.certificateAuthorityDataSource.kind: Unsupported value: "sorcery": supported values: "Secret", "ConfigMap"`},
			wantGitHubErrorSnippets: []string{
				`The %s "%s" is invalid:`,
				`spec.githubAPI.tls.certificateAuthorityDataSource.kind: Unsupported value: "sorcery": supported values: "Secret", "ConfigMap"`,
			},
		},
		{
			name: "should get error condition when using both fields of the tls spec",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityData: "some CA data"
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: foo
							key: bar
				`)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return "spec.tls is invalid: both tls.certificateAuthorityDataSource and tls.certificateAuthorityData provided"
			},
		},
		{
			name: "should get error condition when certificateAuthorityData is not base64 data",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityData: "this is not base64 encoded"
				`)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return `spec.tls.certificateAuthorityData is invalid: illegal base64 data at input byte 4`
			},
		},
		{
			name: "should get error condition when certificateAuthorityData does not contain PEM data",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityData: "%s"
				`, base64.StdEncoding.EncodeToString([]byte("this is not PEM data")))
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return `spec.tls.certificateAuthorityData is invalid: no base64-encoded PEM certificates found in 28 bytes of data (PEM certificates must begin with "-----BEGIN CERTIFICATE-----")`
			},
		},
		{
			name: "should get error condition when using a ConfigMap source and the ConfigMap does not exist",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: this-cm-does-not-exist
							key: bar
				`)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: failed to get configmap "%s/this-cm-does-not-exist": configmap "this-cm-does-not-exist" not found`,
					namespace)
			},
		},
		{
			name: "should get error condition when using a Secret source and the Secret does not exist",
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Doc(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: this-secret-does-not-exist
							key: bar
				`)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: failed to get secret "%s/this-secret-does-not-exist": secret "this-secret-does-not-exist" not found`,
					namespace)
			},
		},
		{
			name:                  "should get error condition when using a Secret source and the Secret is the wrong type",
			secretOrConfigmapKind: "Secret",
			secretType:            "wrong-type",
			secretOrConfigmapDataYAML: here.Doc(`
				bar: "does not matter for this test"
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: secret "%s/%s" of type "wrong-type" cannot be used as a certificate authority data source`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a Secret source and the key does not exist",
			secretOrConfigmapKind: "Secret",
			secretType:            string(corev1.SecretTypeOpaque),
			secretOrConfigmapDataYAML: here.Doc(`
				foo: "foo is the wrong key"
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" not found in secret "%s/%s"`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a ConfigMap source and the key does not exist",
			secretOrConfigmapKind: "ConfigMap",
			secretOrConfigmapDataYAML: here.Doc(`
				foo: "foo is the wrong key"
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" not found in configmap "%s/%s"`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a Secret source and the key has an empty value",
			secretOrConfigmapKind: "Secret",
			secretType:            string(corev1.SecretTypeOpaque),
			secretOrConfigmapDataYAML: here.Doc(`
				bar: ""
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" has empty value in secret "%s/%s"`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a ConfigMap source and the key has an empty value",
			secretOrConfigmapKind: "ConfigMap",
			secretOrConfigmapDataYAML: here.Doc(`
				bar: ""
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" has empty value in configmap "%s/%s"`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a Secret source and the Secret contains data which is not in PEM format",
			secretOrConfigmapKind: "Secret",
			secretType:            string(corev1.SecretTypeOpaque),
			secretOrConfigmapDataYAML: here.Doc(`
				bar: "this is not a PEM cert"
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" with 22 bytes of data in secret "%s/%s" is not a PEM-encoded certificate (PEM certificates must begin with "-----BEGIN CERTIFICATE-----")`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should get error condition when using a ConfigMap source and the ConfigMap contains data which is not in PEM format",
			secretOrConfigmapKind: "ConfigMap",
			secretOrConfigmapDataYAML: here.Doc(`
				bar: "this is not a PEM cert"
			`),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return fmt.Sprintf(
					`spec.tls.certificateAuthorityDataSource is invalid: key "bar" with 22 bytes of data in configmap "%s/%s" is not a PEM-encoded certificate (PEM certificates must begin with "-----BEGIN CERTIFICATE-----")`,
					namespace, secretOrConfigmapName)
			},
		},
		{
			name:                  "should create a custom resource passing all validations using a Secret source of type Opaque",
			secretOrConfigmapKind: "Secret",
			secretType:            string(corev1.SecretTypeOpaque),
			secretOrConfigmapDataYAML: here.Docf(`
				bar: |
					%s
			`, indentedCAPEM),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets:       nil,
			wantGitHubErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return "spec.tls is valid: using configured CA bundle"
			},
		},
		{
			name:                  "should create a custom resource passing all validations using a Secret source of type tls",
			secretOrConfigmapKind: "Secret",
			secretType:            string(corev1.SecretTypeTLS),
			secretOrConfigmapDataYAML: here.Docf(`
				tls.crt: foo
				tls.key: foo
				bar: |
					%s
			`, indentedCAPEM),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: Secret
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets:       nil,
			wantGitHubErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return "spec.tls is valid: using configured CA bundle"
			},
		},
		{
			name:                  "should create a custom resource passing all validations using a ConfigMap source",
			secretOrConfigmapKind: "ConfigMap",
			secretOrConfigmapDataYAML: here.Docf(`
				bar: |
					%s
			`, indentedCAPEM),
			tlsYAML: func(secretOrConfigmapName string) string {
				return here.Docf(`
					tls:
						certificateAuthorityDataSource:
							kind: ConfigMap
							name: %s
							key: bar
				`, secretOrConfigmapName)
			},
			wantErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return `spec.tls is valid: using configured CA bundle`
			},
		},
		{
			name:                    "should create a custom resource without any tls spec",
			tlsYAML:                 func(secretOrConfigmapName string) string { return "" },
			wantErrorSnippets:       nil,
			wantGitHubErrorSnippets: nil,
			wantTLSValidConditionMessage: func(namespace string, secretOrConfigmapName string) string {
				return "spec.tls is valid: no TLS configuration provided: using default root CA bundle from container image"
			},
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			t.Run("apply OIDC IDP", func(t *testing.T) {
				resourceName := "test-oidc-idp-" + testlib.RandHex(t, 7)

				secretOrConfigmapResourceName := createSecretOrConfigMapFromData(t,
					resourceName,
					env.SupervisorNamespace,
					tc.secretOrConfigmapKind,
					tc.secretType,
					tc.secretOrConfigmapDataYAML,
				)

				yamlBytes := []byte(fmt.Sprintf(oidcIDPTemplate,
					env.APIGroupSuffix, resourceName, env.SupervisorNamespace, env.SupervisorUpstreamOIDC.Issuer,
					indentForHeredoc(tc.tlsYAML(secretOrConfigmapResourceName))))

				stdOut, stdErr, err := performKubectlApply(t, resourceName, yamlBytes)
				requireKubectlApplyResult(t, stdOut, stdErr, err,
					fmt.Sprintf(`oidcidentityprovider.idp.supervisor.%s`, env.APIGroupSuffix),
					tc.wantErrorSnippets,
					"OIDCIdentityProvider",
					resourceName,
				)

				if tc.wantErrorSnippets == nil {
					requireTLSValidConditionMessageOnResource(t,
						resourceName,
						env.SupervisorNamespace,
						"OIDCIdentityProvider",
						tc.wantTLSValidConditionMessage(env.SupervisorNamespace, secretOrConfigmapResourceName),
					)
				}
			})

			t.Run("apply LDAP IDP", func(t *testing.T) {
				resourceName := "test-ldap-idp-" + testlib.RandHex(t, 7)

				secretOrConfigmapResourceName := createSecretOrConfigMapFromData(t,
					resourceName,
					env.SupervisorNamespace,
					tc.secretOrConfigmapKind,
					tc.secretType,
					tc.secretOrConfigmapDataYAML,
				)

				yamlBytes := []byte(fmt.Sprintf(ldapIDPTemplate,
					env.APIGroupSuffix, resourceName, env.SupervisorNamespace, env.SupervisorUpstreamLDAP.Host,
					indentForHeredoc(tc.tlsYAML(secretOrConfigmapResourceName))))

				stdOut, stdErr, err := performKubectlApply(t, resourceName, yamlBytes)
				requireKubectlApplyResult(t, stdOut, stdErr, err,
					fmt.Sprintf(`ldapidentityprovider.idp.supervisor.%s`, env.APIGroupSuffix),
					tc.wantErrorSnippets,
					"LDAPIdentityProvider",
					resourceName,
				)

				if tc.wantErrorSnippets == nil {
					requireTLSValidConditionMessageOnResource(t,
						resourceName,
						env.SupervisorNamespace,
						"LDAPIdentityProvider",
						tc.wantTLSValidConditionMessage(env.SupervisorNamespace, secretOrConfigmapResourceName),
					)
				}
			})

			t.Run("apply ActiveDirectory IDP", func(t *testing.T) {
				resourceName := "test-ad-idp-" + testlib.RandHex(t, 7)

				secretOrConfigmapResourceName := createSecretOrConfigMapFromData(t,
					resourceName,
					env.SupervisorNamespace,
					tc.secretOrConfigmapKind,
					tc.secretType,
					tc.secretOrConfigmapDataYAML,
				)

				yamlBytes := []byte(fmt.Sprintf(activeDirectoryIDPTemplate,
					env.APIGroupSuffix, resourceName, env.SupervisorNamespace, env.SupervisorUpstreamLDAP.Host,
					indentForHeredoc(tc.tlsYAML(secretOrConfigmapResourceName))))

				stdOut, stdErr, err := performKubectlApply(t, resourceName, yamlBytes)
				requireKubectlApplyResult(t, stdOut, stdErr, err,
					fmt.Sprintf(`activedirectoryidentityprovider.idp.supervisor.%s`, env.APIGroupSuffix),
					tc.wantErrorSnippets,
					"ActiveDirectoryIdentityProvider",
					resourceName,
				)

				if tc.wantErrorSnippets == nil {
					requireTLSValidConditionMessageOnResource(t,
						resourceName,
						env.SupervisorNamespace,
						"ActiveDirectoryIdentityProvider",
						tc.wantTLSValidConditionMessage(env.SupervisorNamespace, secretOrConfigmapResourceName),
					)
				}
			})

			t.Run("apply GitHub IDP", func(t *testing.T) {
				resourceName := "test-github-idp-" + testlib.RandHex(t, 7)

				secretOrConfigmapResourceName := createSecretOrConfigMapFromData(t,
					resourceName,
					env.SupervisorNamespace,
					tc.secretOrConfigmapKind,
					tc.secretType,
					tc.secretOrConfigmapDataYAML,
				)

				// GitHub is nested deeper.
				indentedTLSYAMLForGitHub := indentForHeredoc(indentForHeredoc(tc.tlsYAML(secretOrConfigmapResourceName)))

				yamlBytes := []byte(fmt.Sprintf(githubIDPTemplate,
					env.APIGroupSuffix, resourceName, env.SupervisorNamespace, indentedTLSYAMLForGitHub))

				stdOut, stdErr, err := performKubectlApply(t, resourceName, yamlBytes)
				requireKubectlApplyResult(t, stdOut, stdErr, err,
					fmt.Sprintf(`githubidentityprovider.idp.supervisor.%s`, env.APIGroupSuffix),
					tc.wantGitHubErrorSnippets,
					"GitHubIdentityProvider",
					resourceName,
				)

				if tc.wantGitHubErrorSnippets == nil {
					requireTLSValidConditionMessageOnResource(t,
						resourceName,
						env.SupervisorNamespace,
						"GitHubIdentityProvider",
						// The tls spec location is different for GitHubIdentityProvider, so adjust the expectation.
						strings.Replace(
							tc.wantTLSValidConditionMessage(env.SupervisorNamespace, secretOrConfigmapResourceName),
							"spec.tls", "spec.githubAPI.tls", 1),
					)
				}
			})
		})
	}
}
