diff --git a/cmds/ocm/topics/common/credentials/topic.go b/cmds/ocm/topics/common/credentials/topic.go
index 8c03cd9759..66d53a40d9 100644
--- a/cmds/ocm/topics/common/credentials/topic.go
+++ b/cmds/ocm/topics/common/credentials/topic.go
@@ -27,32 +27,112 @@ func New(ctx clictx.Context) *cobra.Command {
Use: "credential-handling",
Short: "Provisioning of credentials for credential consumers",
Long: `
-Because of the dynamic nature of the OCM area there are several kinds of
+In contrast to libraries intended for a dedicated technical environment,
+for example the handling of OCI images in OCI registries, the OCM
+ecosystem cannot provide a specialized credential management for a decicated
+environment.
+
+Because of its extensibility working with component versions could
+require access to any kind of technical system, either for storing
+the model elements in a storage backend, or for accessing content
+in any kind of technical storage system. There are several kinds of
credential consumers with potentially completely different kinds of credentials.
Therefore, a common uniform credential management is required, capable to serve
all those use cases.
-This is achieved by establishing a credential request mechanism based on
-generic consumer identities and credential property sets.
-On the one hand every kind of credential consumer uses a dedicated consumer
-type (string). Additionally, it defines a set of properties further describing
-the target/context credentials are required for.
+This credential management brings together various kinds of credential consumers,
+for example the access to artifacts in OCI registries or accessing
+Git repository content, and credential providers, like
+vaults or local files in the filesystem (for example a technology
+specific credential source like the docker config json file for
+accessing OCI registries).
+
+The used credential management model is based on four elements:
+- *Credentials:*
+
+ Credentials are described property set (key/value pairs).
+- *Consumer Ids*
+
+ Because of the extensible nature of the OCM model, credential consumers
+ must be formally identified. A consumer id described a concrete
+ access, which must be authorized.
+
+ This is again achieved by a set of simple named attributes. There is only
+ one defined property, which must always be present, the type
attibute.
+ It denotes the type of the technical environment credentails are required for.
+ For example, for accessing OCI or Git registries. Additionally, there may
+ be any number of arbitrary attributes used to describe the concrete
+ instance of such an environment and access paths in this environment, which
+ should be accessed (for example the OCI registry URL to describe the instance
+ and the repository path for the set of objects, which should be accessed)
+
+ There are two use cases for consumer ids:
+ - *Credential Request.* They are used by a credential consumer to issue a
+ credential request to the credential management. Hereby, they describe the
+ concrete element, which should accessed.
+ - *Credential Assignment.* The credential management allows to assign
+ credentials to consumer ids
+
+- *Credential Providers* or repositories
+
+ Credential repositories are dedicated kinds of implementations, which provide
+ access to names sets of credentials stored in any kind of technical
+ environment, for example a vault or a credentials somewhere on the local
+ filesystem.
-On the other hand credentials can be defined for such sets of identities
-with partial sets of properties (see ocm configfile). A credential
-request is then matched against the available credential settings using matchers,
-which might be specific for dedicated kinds of requests. For example, a hostpath
-matcher matches a path prefix for a pathprefix
property.
+- *Identity Matchers*
-The best matching set of credential properties is then returned to the
-credential consumer, which checks for the expected credential properties.
+ The credential management must resolve crednetial requests against a set
+ of credential assignments. This is not necessarily a complete attribute match
+ for the involved consumer ids. There is typically some kind of matching
+ involved. For example, an assigment is done for an OCI registry with a dedicated
+ server url and prefix for the repository path (type is OCIRegistry, host is
+ ghcr.io, prefixpath is open-component-model). The assigned credentials
+ should be applicable for sub repositories. Som the assignment use a more
+ general consumer id than the concrete credential request (for example for
+ repository path open-component-model/ocm/ocmcli
)
-The following credential consumer types are used:
+ This kind of matching depend on the used attribute and is therefore in general
+ type specific. Therefore, every consumer type uses an own identity matcher,
+ which is then used by the credential management to find the best matching
+ assignment.
+
+The general process for a credential management then looks as follows.
+- credentials provided by credential repositories are assigned to generalized
+ consumer ids.
+- a concrete access operation for a technical environment calculates
+ a detailed consumer id for the element, which should be accessed
+- it asks the credential management for credentials for this id
+- the management examines all defined assignments to find the best
+ matching one based on the provided matching mechanism.
+- it then returns the mapped credentials from the references repository.
+
+The critical task for a user of the toolset is to define those assignments.
+This is basically a manual task, because the credentials stored in vault
+(for example) could be usable for any kind of system, which typically
+cannot be derived from the credential values.
+
+But luckily, those could partly be automated:
+- there may be credential providers, which are technology specific, for example
+ the docker config json is used to describe credentials for OCI registries.
+ Such providers can automatically assign the found credentials to appropriate
+ consumer ids.
+- If the credential store has the possibility to store custom meta data for a
+ credential set, this metadata can be used to describe the intended consumer
+ ids. The provider implementation then uses this info create the appropriate
+ assignments.
+
+### Consumer Types and Matchers
+
+The following credential consumer types are used/supported:
` + listformat.FormatListElements("", consumer) + `\
Those consumer types provide their own matchers, which are often based
on some standard generic matches. Those generic matchers and their
behaviours are described in the following list:
` + listformat.FormatListElements("", standard) + `
-`,
+
+### Credential Providers
+
+` + ctx.CredentialsContext().RepositoryTypes().Describe(),
}
}
diff --git a/components/helminstaller/Dockerfile b/components/helminstaller/Dockerfile
index 02805e6177..d160f60630 100644
--- a/components/helminstaller/Dockerfile
+++ b/components/helminstaller/Dockerfile
@@ -1,4 +1,4 @@
-FROM --platform=$BUILDPLATFORM golang:1.19 AS builder
+FROM --platform=$BUILDPLATFORM golang:1.21 AS builder
ARG COMMIT EFFECTIVE_VERSION GIT_TREE_STATE
ARG TARGETOS TARGETARCH
diff --git a/docs/reference/ocm.md b/docs/reference/ocm.md
index 489f623e2b..321e5082b9 100644
--- a/docs/reference/ocm.md
+++ b/docs/reference/ocm.md
@@ -253,6 +253,16 @@ The value can be a simple type or a JSON/YAML string for complex values
The are temporarily stored in the filesystem, instead of the memory, to avoid
blowing up the memory consumption.
+- ocm.software/compositionmode
[compositionmode
]: *bool* (default: false
+
+ Composition mode decouples a component version provided by a repository
+ implemention from the backened persistence. Added local blobs will
+ and other changes witll not be forwarded to the backend repository until
+ an AddVersion is called on the component.
+ If composition mode is disabled blobs will directly be forwarded to
+ the backend and descriptor updated will be persisted on AddVersion
+ or closing a provided existing component version.
+
- ocm.software/signing/sigstore
[sigstore
]: *sigstore config* Configuration to use for sigstore based signing.
The following fields are used.
diff --git a/docs/reference/ocm_attributes.md b/docs/reference/ocm_attributes.md
index bd243a16fc..772c17f214 100644
--- a/docs/reference/ocm_attributes.md
+++ b/docs/reference/ocm_attributes.md
@@ -163,6 +163,16 @@ OCM library:
The are temporarily stored in the filesystem, instead of the memory, to avoid
blowing up the memory consumption.
+- ocm.software/compositionmode
[compositionmode
]: *bool* (default: false
+
+ Composition mode decouples a component version provided by a repository
+ implemention from the backened persistence. Added local blobs will
+ and other changes witll not be forwarded to the backend repository until
+ an AddVersion is called on the component.
+ If composition mode is disabled blobs will directly be forwarded to
+ the backend and descriptor updated will be persisted on AddVersion
+ or closing a provided existing component version.
+
- ocm.software/signing/sigstore
[sigstore
]: *sigstore config* Configuration to use for sigstore based signing.
The following fields are used.
diff --git a/docs/reference/ocm_credential-handling.md b/docs/reference/ocm_credential-handling.md
index 5ec9b49591..a0e58ef395 100644
--- a/docs/reference/ocm_credential-handling.md
+++ b/docs/reference/ocm_credential-handling.md
@@ -3,27 +3,104 @@
### Description
-Because of the dynamic nature of the OCM area there are several kinds of
+In contrast to libraries intended for a dedicated technical environment,
+for example the handling of OCI images in OCI registries, the OCM
+ecosystem cannot provide a specialized credential management for a decicated
+environment.
+
+Because of its extensibility working with component versions could
+require access to any kind of technical system, either for storing
+the model elements in a storage backend, or for accessing content
+in any kind of technical storage system. There are several kinds of
credential consumers with potentially completely different kinds of credentials.
Therefore, a common uniform credential management is required, capable to serve
all those use cases.
-This is achieved by establishing a credential request mechanism based on
-generic consumer identities and credential property sets.
-On the one hand every kind of credential consumer uses a dedicated consumer
-type (string). Additionally, it defines a set of properties further describing
-the target/context credentials are required for.
-
-On the other hand credentials can be defined for such sets of identities
-with partial sets of properties (see [ocm configfile](ocm_configfile.md)). A credential
-request is then matched against the available credential settings using matchers,
-which might be specific for dedicated kinds of requests. For example, a hostpath
-matcher matches a path prefix for a pathprefix
property.
-
-The best matching set of credential properties is then returned to the
-credential consumer, which checks for the expected credential properties.
-
-The following credential consumer types are used:
+This credential management brings together various kinds of credential consumers,
+for example the access to artifacts in OCI registries or accessing
+Git repository content, and credential providers, like
+vaults or local files in the filesystem (for example a technology
+specific credential source like the docker config json file for
+accessing OCI registries).
+
+The used credential management model is based on four elements:
+- *Credentials:*
+
+ Credentials are described property set (key/value pairs).
+- *Consumer Ids*
+
+ Because of the extensible nature of the OCM model, credential consumers
+ must be formally identified. A consumer id described a concrete
+ access, which must be authorized.
+
+ This is again achieved by a set of simple named attributes. There is only
+ one defined property, which must always be present, the type
attibute.
+ It denotes the type of the technical environment credentails are required for.
+ For example, for accessing OCI or Git registries. Additionally, there may
+ be any number of arbitrary attributes used to describe the concrete
+ instance of such an environment and access paths in this environment, which
+ should be accessed (for example the OCI registry URL to describe the instance
+ and the repository path for the set of objects, which should be accessed)
+
+ There are two use cases for consumer ids:
+ - *Credential Request.* They are used by a credential consumer to issue a
+ credential request to the credential management. Hereby, they describe the
+ concrete element, which should accessed.
+ - *Credential Assignment.* The credential management allows to assign
+ credentials to consumer ids
+
+- *Credential Providers* or repositories
+
+ Credential repositories are dedicated kinds of implementations, which provide
+ access to names sets of credentials stored in any kind of technical
+ environment, for example a vault or a credentials somewhere on the local
+ filesystem.
+
+- *Identity Matchers*
+
+ The credential management must resolve crednetial requests against a set
+ of credential assignments. This is not necessarily a complete attribute match
+ for the involved consumer ids. There is typically some kind of matching
+ involved. For example, an assigment is done for an OCI registry with a dedicated
+ server url and prefix for the repository path (type is OCIRegistry, host is
+ ghcr.io, prefixpath is open-component-model). The assigned credentials
+ should be applicable for sub repositories. Som the assignment use a more
+ general consumer id than the concrete credential request (for example for
+ repository path open-component-model/ocm/ocmcli
)
+
+ This kind of matching depend on the used attribute and is therefore in general
+ type specific. Therefore, every consumer type uses an own identity matcher,
+ which is then used by the credential management to find the best matching
+ assignment.
+
+The general process for a credential management then looks as follows.
+- credentials provided by credential repositories are assigned to generalized
+ consumer ids.
+- a concrete access operation for a technical environment calculates
+ a detailed consumer id for the element, which should be accessed
+- it asks the credential management for credentials for this id
+- the management examines all defined assignments to find the best
+ matching one based on the provided matching mechanism.
+- it then returns the mapped credentials from the references repository.
+
+The critical task for a user of the toolset is to define those assignments.
+This is basically a manual task, because the credentials stored in vault
+(for example) could be usable for any kind of system, which typically
+cannot be derived from the credential values.
+
+But luckily, those could partly be automated:
+- there may be credential providers, which are technology specific, for example
+ the docker config json is used to describe credentials for OCI registries.
+ Such providers can automatically assign the found credentials to appropriate
+ consumer ids.
+- If the credential store has the possibility to store custom meta data for a
+ credential set, this metadata can be used to describe the intended consumer
+ ids. The provider implementation then uses this info create the appropriate
+ assignments.
+
+### Consumer Types and Matchers
+
+The following credential consumer types are used/supported:
- Buildcredentials.ocm.software
: Gardener config credential matcher
It matches the Buildcredentials.ocm.software
consumer type and additionally acts like
@@ -43,6 +120,29 @@ The following credential consumer types are used:
- token
: GitHub personal access token
+ - HashiCorpVault
: HashiCorp Vault credential matcher
+
+ This matcher matches credentials for a HashiCorp vault instance.
+ It uses the following identity attributes:
+ - hostname
: vault server host
+ - scheme
: (optional) URL scheme
+ - port
: (optional) server port
+ - namespace
: vault namespace
+ - secretEngine
: secret engine
+ - pathprefix
: path prefix for secret
+
+
+ Credential consumers of the consumer type HashiCorpVault evaluate the following credential properties:
+
+ - authmeth
: auth method
+ - token
: vault token
+ - roleid
: applrole role id
+ - secretid
: applrole secret id
+ - secretid
: applrole secret id
+
+ The only supported auth methods, so far, are token
and approle
.
+
+
- HelmChartRepository
: Helm chart repository
It matches the HelmChartRepository
consumer type and additionally acts like
@@ -92,6 +192,7 @@ behaviours are described in the following list:
- *type
* (required if set in pattern): the identity type
- *hostname
* (required if set in pattern): the hostname of a server
+ - *scheme
* (optional): the URL scheme of a server
- *port
* (optional): the port of a server
- *pathprefix
* (optional): a path prefix to match. The
element with the most matching path components is selected (separator is /
).
@@ -100,16 +201,98 @@ behaviours are described in the following list:
- partial
: complete match of given pattern ignoring additional attributes
+### Credential Providers
-### SEE ALSO
-##### Parents
+- Credential provider Credentials
-* [ocm](ocm.md) — Open Component Model command line client
+ This repository type can be used to specify a single inline credential
+ set. The default name is the empty string or Credentials
.
+
+ The following versions are supported:
+ - Version v1
+
+ The repository specification supports the following fields:
+ - properties
: *map[string]string*: direct credential fields
+
+
+- Credential provider DockerConfig
+
+ This repository type can be used to access credentials stored in a file
+ following the docker config json format. It take into account the
+ credentials helper section, also. If enabled, the described
+ credentials will be automatically assigned to appropriate consumer ids.
+
+ The following versions are supported:
+ - Version v1
+
+ The repository specification supports the following fields:
+ - dockerConfigFile
: *string*: the file path to a docker config file
+ - dockerConfig
: *json*: an embedded docker config json
+ - propagateConsumerIdentity
: *bool*(optional): enable consumer id propagation
+- Credential provider HashiCorpVault
-##### Additional Links
+ This repository type can be used to access credentials stored in a HashiCorp
+ Vault.
-* [ocm configfile](ocm_configfile.md) — configuration file
+ It provides access to list of secrets stored under a dedicated path in
+ a vault namespace. This list can either explicitly be specified, or
+ it is taken from the metadata of a specified secret.
+
+ The following custom metadata attributes are evaluated:
+ - secrets
this attribute may contain a comma separated list of
+ vault secrets, which should be exposed by this repository instance.
+ The names are evaluated under the path prefix used for the repository.
+ - consumerId
this attribute may contain a JSON encoded
+ consumer id , this secret should be assigned to.
+ - type
if no special attribute is defined this attribute
+ indicated to use the complete custom metadata as consumer id.
+
+ It uses the HashiCorpVault identity matcher and consumer type
+ to requests credentials for the access.
+
+
+ This matcher matches credentials for a HashiCorp vault instance.
+ It uses the following identity attributes:
+ - hostname
: vault server host
+ - scheme
: (optional) URL scheme
+ - port
: (optional) server port
+ - namespace
: vault namespace
+ - secretEngine
: secret engine
+ - pathprefix
: path prefix for secret
+
+
+ It requires the following credential attributes:
+
+ - authmeth
: auth method
+ - token
: vault token
+ - roleid
: applrole role id
+ - secretid
: applrole secret id
+ - secretid
: applrole secret id
+
+ The only supported auth methods, so far, are token
and approle
.
+
+ The following versions are supported:
+ - Version v1
+
+ The repository specification supports the following fields:
+ - serverURL
: *string* (required): the URL of the vault instance
+ - namespace
: *string* (optional): the namespace used to evaluate secrets
+ - secretsEngine
: *string* (optional): the secrets engine to use (default: secrets)
+ - path
: *string* (optional): the path prefix used to lookup secrets
+ - secrets
: *[]string* (optional): list of secrets
+ - propagateConsumerIdentity
: *bool*(optional): evaluate metadata for consumer id propagation
+
+ If the secrets list is empty, all secret entries found in the given path
+ is read.
+
+
+
+### SEE ALSO
+
+##### Parents
+
+* [ocm](ocm.md) — Open Component Model command line client
diff --git a/docs/reference/ocm_download_resources.md b/docs/reference/ocm_download_resources.md
index 46fab78cb9..b48beb3071 100644
--- a/docs/reference/ocm_download_resources.md
+++ b/docs/reference/ocm_download_resources.md
@@ -181,6 +181,7 @@ The downloader name may be a path expression with the following possibilities:
- application/vnd.docker.distribution.manifest.v2+tar+gzip
- application/vnd.gardener.landscaper.blueprint.layer.v1.tar
- application/vnd.gardener.landscaper.blueprint.layer.v1.tar+gzip
+ - application/vnd.gardener.landscaper.blueprint.v1+tar
- application/vnd.gardener.landscaper.blueprint.v1+tar+gzip
- application/vnd.oci.image.manifest.v1+tar
- application/vnd.oci.image.manifest.v1+tar+gzip
diff --git a/docs/reference/ocm_get_credentials.md b/docs/reference/ocm_get_credentials.md
index 64541bc777..5512cc261d 100644
--- a/docs/reference/ocm_get_credentials.md
+++ b/docs/reference/ocm_get_credentials.md
@@ -45,6 +45,29 @@ Matchers exist for the following usage contexts or consumer types:
- token
: GitHub personal access token
+ - HashiCorpVault
: HashiCorp Vault credential matcher
+
+ This matcher matches credentials for a HashiCorp vault instance.
+ It uses the following identity attributes:
+ - hostname
: vault server host
+ - scheme
: (optional) URL scheme
+ - port
: (optional) server port
+ - namespace
: vault namespace
+ - secretEngine
: secret engine
+ - pathprefix
: path prefix for secret
+
+
+ Credential consumers of the consumer type HashiCorpVault evaluate the following credential properties:
+
+ - authmeth
: auth method
+ - token
: vault token
+ - roleid
: applrole role id
+ - secretid
: applrole secret id
+ - secretid
: applrole secret id
+
+ The only supported auth methods, so far, are token
and approle
.
+
+
- HelmChartRepository
: Helm chart repository
It matches the HelmChartRepository
consumer type and additionally acts like
@@ -92,6 +115,7 @@ The following standard identity matchers are supported:
- *type
* (required if set in pattern): the identity type
- *hostname
* (required if set in pattern): the hostname of a server
+ - *scheme
* (optional): the URL scheme of a server
- *port
* (optional): the port of a server
- *pathprefix
* (optional): a path prefix to match. The
element with the most matching path components is selected (separator is /
).
diff --git a/docs/reference/ocm_logging.md b/docs/reference/ocm_logging.md
index 92e011ac65..4ec16172c2 100644
--- a/docs/reference/ocm_logging.md
+++ b/docs/reference/ocm_logging.md
@@ -20,6 +20,7 @@ The following *realms* are used by the command line tool:
- ocm/accessmethod/ociartifact
: access method ociArtifact
- ocm/compdesc
: component descriptor handling
- ocm/credentials/dockerconfig
: docker config handling as credential repository
+ - ocm/credentials/vault
: HashiCorp Vault Access
- ocm/downloader
: Downloaders
- ocm/oci/mapping
: OCM to OCI Registry Mapping
- ocm/oci/ocireg
: OCI repository handling
diff --git a/docs/reference/ocm_ocm-downloadhandlers.md b/docs/reference/ocm_ocm-downloadhandlers.md
index 4ea3ef1eb0..1bbb7c16c6 100644
--- a/docs/reference/ocm_ocm-downloadhandlers.md
+++ b/docs/reference/ocm_ocm-downloadhandlers.md
@@ -93,6 +93,7 @@ The following handler names are possible:
- application/vnd.docker.distribution.manifest.v2+tar+gzip
- application/vnd.gardener.landscaper.blueprint.layer.v1.tar
- application/vnd.gardener.landscaper.blueprint.layer.v1.tar+gzip
+ - application/vnd.gardener.landscaper.blueprint.v1+tar
- application/vnd.gardener.landscaper.blueprint.v1+tar+gzip
- application/vnd.oci.image.manifest.v1+tar
- application/vnd.oci.image.manifest.v1+tar+gzip
diff --git a/go.mod b/go.mod
index 5f7aa0a630..8ec753dc0e 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v1.2.4
+ github.com/hashicorp/vault-client-go v0.4.2
github.com/mandelsoft/filepath v0.0.0-20230412200429-36b1eb66bd27
github.com/mandelsoft/spiff v1.7.0-beta-5
github.com/modern-go/reflect2 v1.0.2
@@ -202,6 +203,8 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.2 // indirect
+ github.com/hashicorp/go-rootcerts v1.0.2 // indirect
+ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.15 // indirect
@@ -253,6 +256,7 @@ require (
github.com/rivo/uniseg v0.4.2 // indirect
github.com/rubenv/sql-migrate v1.3.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/secure-systems-lab/go-securesystemslib v0.6.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
diff --git a/go.sum b/go.sum
index 7aa2ddff03..beb1bfe3c4 100644
--- a/go.sum
+++ b/go.sum
@@ -37,7 +37,9 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94=
+cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk=
cloud.google.com/go/kms v1.12.1 h1:xZmZuwy2cwzsocmKDOPu4BL7umg8QXagQx6fKVmf45U=
+cloud.google.com/go/kms v1.12.1/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -56,6 +58,7 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd h1:1tbEqR4NyQLgiod7vLXSswHteGetAVZrMGCqrJxLKRs=
+github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U=
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw=
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -63,10 +66,15 @@ github.com/Azure/azure-sdk-for-go v46.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 h1:SEy2xmstIphdPwNBUi7uhvjyjhVKISfwjfOJmuy7kg4=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v0.12.0 h1:4Kynh6Hn2ekyIsBgNQJb3dn1+/MyvzfUJebti2emB/A=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v0.12.0/go.mod h1:Q28U+75mpCaSCDowNEmhIo/rmgdkqmkmzI7N6TGR4UY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0 h1:T028gtTPiYt/RMUfs8nVsAL7FDQrfLlrm/NnRG/zcC4=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v0.8.0/go.mod h1:cw4zVQgBby0Z5f2v0itn6se2dDP17nTjbZFXW5uPyHA=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -107,6 +115,7 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -114,6 +123,7 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
+github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/gostackparse v0.6.0 h1:egCGQviIabPwsyoWpGvIBGrEnNWez35aEO7OJ1vBI4o=
github.com/DataDog/gostackparse v0.6.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
@@ -154,6 +164,7 @@ github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.9.3/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8=
+github.com/Microsoft/hcsshim v0.10.0-rc.7/go.mod h1:ILuwjA+kNW+MrN/w5un7n3mTqkwsFu4Bp05/okFUZlE=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -225,12 +236,14 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.44.288 h1:Ln7fIao/nl0ACtelgR1I4AiEw/GLNkKcXfCaHupUW5Q=
+github.com/aws/aws-sdk-go v1.44.288/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250=
github.com/aws/aws-sdk-go-v2 v1.14.0/go.mod h1:ZA3Y8V0LrlWj63MQAnRHgKf/5QB//LSZCPNWlWrNGLU=
github.com/aws/aws-sdk-go-v2 v1.16.16/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k=
@@ -286,6 +299,7 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28/go.mod h1:jj
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17 h1:HfVVR1vItaG6le+Bpw6P4midjBDMKnjMyZnw9MXYUcE=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.17/go.mod h1:YqMdV+gEKCQ59NrB7rzrJdALeBIsYiVi8Inj3+KcqHI=
github.com/aws/aws-sdk-go-v2/service/kms v1.22.2 h1:jwmtdM1/l1DRNy5jQrrYpsQm8zwetkgeqhAqefDr1yI=
+github.com/aws/aws-sdk-go-v2/service/kms v1.22.2/go.mod h1:aNfh11Smy55o65PB3MyKbkM8BFyFUcZmj1k+4g8eNfg=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11 h1:3/gm/JTX9bX8CpzTgIlrtYpB3EVBDxyg/GY/QdcIEZw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.11/go.mod h1:fmgDANqTUCxciViKl9hb/zD5LFbvPINFRgWhDbR+vZo=
github.com/aws/aws-sdk-go-v2/service/sso v1.3.1/go.mod h1:J3A3RGUvuCZjvSuZEcOpHDnzZP/sKbhDWV2T1EOzFIM=
@@ -308,6 +322,7 @@ github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20220228164355-396b2034c795/go.mod h1:8vJsEZ4iRqG+Vx6pKhWK6U00qcj0KC37IsfszMkY6UE=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20150223135152-b965b613227f/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -325,6 +340,7 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
@@ -338,6 +354,7 @@ github.com/buildkite/agent/v3 v3.49.0 h1:FSmRQz8YFhaCXg4MfE7JucPcY7mQ/HWM55ir1j3
github.com/buildkite/agent/v3 v3.49.0/go.mod h1:iasSyh3KPjOPCnyvnZB1trkkX7jrdL8PnLBgjdVJxgU=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
+github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -373,6 +390,7 @@ github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtM
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af h1:6Cpkahw28+gcBdnXQL7LcMTX488+6jl6hfoTMRT6Hm4=
+github.com/cloudfoundry-incubator/candiedyaml v0.0.0-20170901234223-a41693b7b7af/go.mod h1:dOLSIXcRQJiDS1vlrYFNJicoHNZLsBKideE+70hGdV4=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -386,6 +404,7 @@ github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
+github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
@@ -404,6 +423,7 @@ github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTF
github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
+github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@@ -438,6 +458,7 @@ github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EX
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
+github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
@@ -527,6 +548,7 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI=
github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
@@ -545,6 +567,7 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xb
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY=
+github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -557,6 +580,7 @@ github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQ
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
+github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE=
@@ -622,8 +646,11 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw=
+github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA=
github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg=
+github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01/go.mod h1:ypD5nozFk9vcGw1ATYefw6jHe/jZP++Z15/+VTMcWhc=
github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8=
+github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52/go.mod h1:yIquW87NGRw1FU5p5lEkpnt/QxoH5uPAOUlOVkAUuMg=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
@@ -631,15 +658,18 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
+github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
github.com/fluxcd/pkg/ssa v0.24.1 h1:0dn5FqyYdGa+VuDp5EJrkLbPq5xhhSAAkMgGUeMpOM0=
github.com/fluxcd/pkg/ssa v0.24.1/go.mod h1:nEOUOwGotBlNZkTkO6GHPlI0U0BmHTavFd1Jk+TzsGw=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI=
+github.com/foxcpp/go-mockdns v1.0.0/go.mod h1:lgRN6+KxQBawyIghpnl5CezHFGS9VLzvtVlwxvzXTQ4=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
+github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
@@ -688,6 +718,7 @@ github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jT
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
+github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc=
github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
@@ -739,6 +770,7 @@ github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9F
github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
@@ -749,9 +781,11 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-rod/rod v0.113.3 h1:oLiKZW721CCMwA5g7977cWfcAKQ+FuosP47Zf1QiDrA=
+github.com/go-rod/rod v0.113.3/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw=
github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
+github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@@ -854,6 +888,7 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
+github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
@@ -918,6 +953,7 @@ github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkj
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
+github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -929,6 +965,7 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
+github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
@@ -937,6 +974,7 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
+github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -970,6 +1008,7 @@ 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-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
+github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
@@ -980,10 +1019,14 @@ github.com/hashicorp/go-retryablehttp v0.7.2 h1:AcYqCvkpalPnPF2pn0KamgwamS42TqUD
github.com/hashicorp/go-retryablehttp v0.7.2/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs=
+github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
+github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
@@ -991,15 +1034,21 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hashicorp/vault-client-go v0.4.2 h1:XeUXb5jnDuCUhC8HRpkdGPLh1XtzXmiOnF0mXEbARxI=
+github.com/hashicorp/vault-client-go v0.4.2/go.mod h1:4tDw7Uhq5XOxS1fO+oMtotHL7j4sB9cp0T7U6m4FzDY=
github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as=
+github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc=
+github.com/honeycombio/beeline-go v1.10.0/go.mod h1:Zz5WMeQCJzFt2Mvf8t6HC1X8RLskLVR/e8rvcmXB1G8=
github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc=
+github.com/honeycombio/libhoney-go v1.16.0/go.mod h1:izP4fbREuZ3vqC4HlCAmPrcPT9gxyxejRjGtCYpmBn0=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@@ -1027,6 +1076,7 @@ github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbB
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b h1:ZGiXF8sz7PDk6RgkP+A/SFfUD0ZR/AgG6SpRNEDKZy8=
github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b/go.mod h1:hQmNrgofl+IY/8L+n20H6E6PWBBTokdsv+q49j0QhsU=
github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU=
+github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8 h1:CZkYfurY6KGhVtlalI4QwQ6T0Cu6iuY3e0x5RLu96WE=
github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
@@ -1040,6 +1090,7 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4=
+github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
@@ -1098,6 +1149,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
@@ -1174,6 +1226,7 @@ github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
+github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
@@ -1181,6 +1234,7 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfr
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
+github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@@ -1350,7 +1404,9 @@ github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNc
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -1422,6 +1478,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rubenv/sql-migrate v1.3.1 h1:Vx+n4Du8X8VTYuXbhNxdEUoh6wiJERA0GlWocR5FrbA=
github.com/rubenv/sql-migrate v1.3.1/go.mod h1:YzG/Vh82CwyhTFXy+Mf5ahAiiEOpAlHurg+23VEzcsk=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
@@ -1430,6 +1487,7 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
+github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A=
@@ -1449,6 +1507,7 @@ github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
+github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -1464,9 +1523,13 @@ github.com/sigstore/rekor v1.2.2-0.20230530122220-67cc9e58bd23/go.mod h1:h1tOLhl
github.com/sigstore/sigstore v1.7.1 h1:fCATemikcBK0cG4+NcM940MfoIgmioY1vC6E66hXxks=
github.com/sigstore/sigstore v1.7.1/go.mod h1:0PmMzfJP2Y9+lugD0wer4e7TihR5tM7NcIs3bQNk5xg=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.1 h1:rDHrG/63b3nBq3G9plg7iYnWN6lBhOfq/XultlCZgII=
+github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.1/go.mod h1:hl0LRidnJG1uL1lLSHGEjcs+MxLjT65NJ7pX/TQDIsk=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.7.1 h1:X3ezwolP+b1jP3R6XPOWhUU0TZKONiv6EIRuySlZGrY=
+github.com/sigstore/sigstore/pkg/signature/kms/azure v1.7.1/go.mod h1:SG2NPEdX2Vi7CBp/o93kJqXrovkis/T9ou9oxZONyEA=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.7.1 h1:mj1KhdzzP1me994bt1UXhq5KZGSR1SoqxTqcT+hfPMk=
+github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.7.1/go.mod h1:Z7LFrKKfj5ZPhy0YS9HcI4H6kbUQzBsE3e3hR+R3YY8=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.7.1 h1:fhOToGY5fC5TY101an8i/oDYpoLzUJ1nUFwhnHA1+XY=
+github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.7.1/go.mod h1:SN4QZHHDs2VqXh5bRXrIi8vqLbOijIp2XoSlmV/WJ/c=
github.com/sigstore/timestamp-authority v1.1.1 h1:EldrdeBED0edNzDMvYZDf5CyWgtSchtR9DKYyksNR8M=
github.com/sigstore/timestamp-authority v1.1.1/go.mod h1:cEDLEHl/L3ppqKDaiZ3Cg4ikcaYleuq90I/BFNePzF0=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
@@ -1484,6 +1547,7 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY=
+github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -1562,6 +1626,7 @@ github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4D
github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
@@ -1599,7 +1664,9 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
+github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
+github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xanzy/go-gitlab v0.86.0 h1:jR8V9cK9jXRQDb46KOB20NCF3ksY09luaG0IfXE6p7w=
@@ -1622,10 +1689,15 @@ github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ=
+github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns=
github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ=
+github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18=
github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s=
+github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM=
github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE=
+github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg=
github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak=
+github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1689,6 +1761,7 @@ go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
+go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
@@ -1709,6 +1782,7 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
+go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -2142,6 +2216,7 @@ golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNq
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -2229,7 +2304,9 @@ google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
+google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
+google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -2283,6 +2360,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc=
+gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU=
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2336,6 +2414,7 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
+gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
helm.sh/helm/v3 v3.12.2 h1:kFyDBr/mgJUlyGzVTCieG4wW0zmo7fcNRWK0+FKkxqU=
helm.sh/helm/v3 v3.12.2/go.mod h1:v1PMayudIfZAvec3Wp4wAErensvK/rv5fu/xCiE6t3I=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/pkg/cobrautils/flagsets/flagsetscheme/scheme.go b/pkg/cobrautils/flagsets/flagsetscheme/scheme.go
index 78bf5cea41..c403fe28d4 100644
--- a/pkg/cobrautils/flagsets/flagsetscheme/scheme.go
+++ b/pkg/cobrautils/flagsets/flagsetscheme/scheme.go
@@ -8,17 +8,16 @@ import (
"github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
"github.com/open-component-model/ocm/pkg/logging"
"github.com/open-component-model/ocm/pkg/runtime"
+ "github.com/open-component-model/ocm/pkg/runtime/descriptivetype"
"github.com/open-component-model/ocm/pkg/utils"
)
// VersionTypedObjectType is the appropriately extended type interface
// based on runtime.VersionTypedObjectType.
type VersionTypedObjectType[T runtime.VersionedTypedObject] interface {
- runtime.VersionedTypedObjectType[T]
+ descriptivetype.TypedObjectType[T]
ConfigOptionTypeSetHandler() flagsets.ConfigOptionTypeSetHandler
- Description() string
- Format() string
}
////////////////////////////////////////////////////////////////////////////////
@@ -26,26 +25,36 @@ type VersionTypedObjectType[T runtime.VersionedTypedObject] interface {
// TypeScheme is the appropriately extended scheme interface based on
// runtime.TypeScheme.
type TypeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T]] interface {
- runtime.TypeScheme[T, R]
+ descriptivetype.TypeScheme[T, R]
+
CreateConfigTypeSetConfigProvider() flagsets.ConfigTypeOptionSetConfigProvider
}
-type _typeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T]] runtime.TypeScheme[T, R]
+type _typeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T]] interface {
+ descriptivetype.TypeScheme[T, R]
+}
type typeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T], S TypeScheme[T, R]] struct {
- name string
+ cfgname string
description string
group string
typeOption string
_typeScheme[T, R]
}
+func flagExtender[T runtime.VersionedTypedObject, R VersionTypedObjectType[T]](ty R) string {
+ if h := ty.ConfigOptionTypeSetHandler(); h != nil {
+ return utils.IndentLines(flagsets.FormatConfigOptions(h), " ")
+ }
+ return ""
+}
+
// NewTypeScheme provides an TypeScheme implementation based on the interfaces
// and the default runtime.TypeScheme implementation.
-func NewTypeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T], S TypeScheme[T, R]](name, typeOption, desc, group string, unknown runtime.Unstructured, acceptUnknown bool, base ...S) TypeScheme[T, R] {
- scheme := runtime.MustNewDefaultTypeScheme[T, R](unknown, acceptUnknown, nil, utils.Optional(base...))
+func NewTypeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T], S TypeScheme[T, R]](kindname string, cfgname, typeOption, desc, group string, unknown runtime.Unstructured, acceptUnknown bool, base ...S) TypeScheme[T, R] {
+ scheme := descriptivetype.NewTypeScheme[T, R](kindname, flagExtender[T, R], unknown, acceptUnknown, utils.Optional(base...))
return &typeScheme[T, R, S]{
- name: name,
+ cfgname: cfgname,
description: desc,
group: group,
typeOption: typeOption,
@@ -56,9 +65,9 @@ func NewTypeScheme[T runtime.VersionedTypedObject, R VersionTypedObjectType[T],
func (t *typeScheme[T, R, S]) CreateConfigTypeSetConfigProvider() flagsets.ConfigTypeOptionSetConfigProvider {
var prov flagsets.ConfigTypeOptionSetConfigProvider
if t.typeOption == "" {
- prov = flagsets.NewExplicitlyTypedConfigProvider(t.name, t.description, true)
+ prov = flagsets.NewExplicitlyTypedConfigProvider(t.cfgname, t.description, true)
} else {
- prov = flagsets.NewTypedConfigProvider(t.name, t.description, t.typeOption, true)
+ prov = flagsets.NewTypedConfigProvider(t.cfgname, t.description, t.typeOption, true)
}
if t.group != "" {
prov.AddGroups(t.group)
@@ -66,7 +75,7 @@ func (t *typeScheme[T, R, S]) CreateConfigTypeSetConfigProvider() flagsets.Confi
for _, p := range t.KnownTypes() {
err := prov.AddTypeSet(p.ConfigOptionTypeSetHandler())
if err != nil {
- logging.Logger().LogError(err, "cannot compose type CLI options", "type", t.name)
+ logging.Logger().LogError(err, "cannot compose type CLI options", "type", t.cfgname)
}
}
if t.BaseScheme() != nil {
@@ -75,7 +84,7 @@ func (t *typeScheme[T, R, S]) CreateConfigTypeSetConfigProvider() flagsets.Confi
if prov.GetTypeSet(s.GetName()) == nil {
err := prov.AddTypeSet(s)
if err != nil {
- logging.Logger().LogError(err, "cannot compose type CLI options", "type", t.name)
+ logging.Logger().LogError(err, "cannot compose type CLI options", "type", t.cfgname)
}
}
}
diff --git a/pkg/cobrautils/flagsets/flagsetscheme/types.go b/pkg/cobrautils/flagsets/flagsetscheme/types.go
new file mode 100644
index 0000000000..48b8acb25a
--- /dev/null
+++ b/pkg/cobrautils/flagsets/flagsetscheme/types.go
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package flagsetscheme
+
+import (
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
+ "github.com/open-component-model/ocm/pkg/optionutils"
+ "github.com/open-component-model/ocm/pkg/runtime"
+ "github.com/open-component-model/ocm/pkg/runtime/descriptivetype"
+)
+
+type additionalTypeInfo interface {
+ ConfigOptionTypeSetHandler() flagsets.ConfigOptionTypeSetHandler
+ Description() string
+ Format() string
+}
+
+type TypedObjectTypeObject[E runtime.VersionedTypedObject] struct {
+ *descriptivetype.TypedObjectTypeObject[E]
+ handler flagsets.ConfigOptionTypeSetHandler
+ validator func(E) error
+}
+
+var _ additionalTypeInfo = (*TypedObjectTypeObject[runtime.VersionedTypedObject])(nil)
+
+func NewTypedObjectTypeObject[E runtime.VersionedTypedObject](vt runtime.VersionedTypedObjectType[E], opts ...TypeOption) *TypedObjectTypeObject[E] {
+ t := NewTypeObjectTarget[E](&TypedObjectTypeObject[E]{
+ TypedObjectTypeObject: descriptivetype.NewTypedObjectTypeObject[E](vt),
+ })
+ optionutils.ApplyOptions[OptionTarget](t, opts...)
+ return t.target
+}
+
+func (t *TypedObjectTypeObject[E]) ConfigOptionTypeSetHandler() flagsets.ConfigOptionTypeSetHandler {
+ return t.handler
+}
+
+func (t *TypedObjectTypeObject[E]) Validate(e E) error {
+ if t.validator == nil {
+ return nil
+ }
+ return t.validator(e)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// TypeObjectTarget is used as target for option functions, it provides
+// setters for fields, which should nor be modifiable for a final type object.
+type TypeObjectTarget[E runtime.VersionedTypedObject] struct {
+ *descriptivetype.TypeObjectTarget[E]
+ target *TypedObjectTypeObject[E]
+}
+
+func NewTypeObjectTarget[E runtime.VersionedTypedObject](target *TypedObjectTypeObject[E]) *TypeObjectTarget[E] {
+ return &TypeObjectTarget[E]{
+ target: target,
+ TypeObjectTarget: descriptivetype.NewTypeObjectTarget[E](target.TypedObjectTypeObject),
+ }
+}
+
+func (t TypeObjectTarget[E]) SetConfigHandler(value flagsets.ConfigOptionTypeSetHandler) {
+ t.target.handler = value
+}
diff --git a/pkg/cobrautils/flagsets/flagsetscheme/types_options.go b/pkg/cobrautils/flagsets/flagsetscheme/types_options.go
new file mode 100644
index 0000000000..104b76eac9
--- /dev/null
+++ b/pkg/cobrautils/flagsets/flagsetscheme/types_options.go
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package flagsetscheme
+
+import (
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
+ "github.com/open-component-model/ocm/pkg/optionutils"
+ "github.com/open-component-model/ocm/pkg/runtime/descriptivetype"
+)
+
+////////////////////////////////////////////////////////////////////////////////
+// Access Type Options
+
+type OptionTarget interface {
+ descriptivetype.OptionTarget
+ SetConfigHandler(flagsets.ConfigOptionTypeSetHandler)
+}
+
+type TypeOption = optionutils.Option[OptionTarget]
+
+////////////////////////////////////////////////////////////////////////////////
+// options derived from descriptivetype.
+
+func WithFormatSpec(value string) TypeOption {
+ return optionutils.MapOptionTarget[OptionTarget](descriptivetype.WithFormatSpec(value))
+}
+
+func WithDescription(value string) TypeOption {
+ return optionutils.MapOptionTarget[OptionTarget](descriptivetype.WithDescription(value))
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// additional options.
+
+type configOption struct {
+ value flagsets.ConfigOptionTypeSetHandler
+}
+
+func WithConfigHandler(value flagsets.ConfigOptionTypeSetHandler) TypeOption {
+ return configOption{value}
+}
+
+func (o configOption) ApplyTo(t OptionTarget) {
+ t.SetConfigHandler(o.value)
+}
diff --git a/pkg/contexts/credentials/cpi/repotypes.go b/pkg/contexts/credentials/cpi/repotypes.go
index ba33f6bc81..28c5647b35 100644
--- a/pkg/contexts/credentials/cpi/repotypes.go
+++ b/pkg/contexts/credentials/cpi/repotypes.go
@@ -9,6 +9,7 @@ package cpi
import (
"github.com/open-component-model/ocm/pkg/runtime"
+ "github.com/open-component-model/ocm/pkg/runtime/descriptivetype"
)
type RepositoryTypeVersionScheme = runtime.TypeVersionScheme[RepositorySpec, RepositoryType]
@@ -27,14 +28,26 @@ func RegisterRepositoryTypeVersions(s RepositoryTypeVersionScheme) {
////////////////////////////////////////////////////////////////////////////////
-func NewRepositoryType[I RepositorySpec](name string) RepositoryType {
- return runtime.NewVersionedTypedObjectType[RepositorySpec, I](name)
+func NewRepositoryType[I RepositorySpec](name string, opts ...RepositoryOption) RepositoryType {
+ return descriptivetype.NewTypedObjectTypeObject(runtime.NewVersionedTypedObjectType[RepositorySpec, I](name), opts...)
}
-func NewRepositoryTypeByConverter[I RepositorySpec, V runtime.TypedObject](name string, converter runtime.Converter[I, V]) RepositoryType {
- return runtime.NewVersionedTypedObjectTypeByConverter[RepositorySpec, I](name, converter)
+func NewRepositoryTypeByConverter[I RepositorySpec, V runtime.TypedObject](name string, converter runtime.Converter[I, V], opts ...RepositoryOption) RepositoryType {
+ return descriptivetype.NewTypedObjectTypeObject(runtime.NewVersionedTypedObjectTypeByConverter[RepositorySpec, I](name, converter), opts...)
}
-func NewRepositoryTypeByFormatVersion(name string, fmt runtime.FormatVersion[RepositorySpec]) RepositoryType {
- return runtime.NewVersionedTypedObjectTypeByFormatVersion[RepositorySpec](name, fmt)
+func NewRepositoryTypeByFormatVersion(name string, fmt runtime.FormatVersion[RepositorySpec], opts ...RepositoryOption) RepositoryType {
+ return descriptivetype.NewTypedObjectTypeObject(runtime.NewVersionedTypedObjectTypeByFormatVersion[RepositorySpec](name, fmt), opts...)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type RepositoryOption = descriptivetype.Option
+
+func WithDescription(v string) RepositoryOption {
+ return descriptivetype.WithDescription(v)
+}
+
+func WithFormatSpec(v string) RepositoryOption {
+ return descriptivetype.WithFormatSpec(v)
}
diff --git a/pkg/contexts/credentials/identity/hostpath/identity.go b/pkg/contexts/credentials/identity/hostpath/identity.go
index 1813f290e2..612512af50 100644
--- a/pkg/contexts/credentials/identity/hostpath/identity.go
+++ b/pkg/contexts/credentials/identity/hostpath/identity.go
@@ -36,6 +36,7 @@ This matcher works on the following properties:
- *`+ID_TYPE+`
* (required if set in pattern): the identity type
- *`+ID_HOSTNAME+`
* (required if set in pattern): the hostname of a server
+- *`+ID_SCHEME+`
* (optional): the URL scheme of a server
- *`+ID_PORT+`
* (optional): the port of a server
- *`+ID_PATHPREFIX+`
* (optional): a path prefix to match. The
element with the most matching path components is selected (separator is /
).
@@ -45,37 +46,37 @@ This matcher works on the following properties:
var Matcher = IdentityMatcher("")
func IdentityMatcher(identityType string) cpi.IdentityMatcher {
- return func(pattern, cur, id cpi.ConsumerIdentity) bool {
- if pattern[ID_TYPE] != "" && pattern[ID_TYPE] != id[ID_TYPE] {
+ return func(request, cur, id cpi.ConsumerIdentity) bool {
+ if request[ID_TYPE] != "" && request[ID_TYPE] != id[ID_TYPE] {
return false
}
- if identityType != "" && pattern[ID_TYPE] != "" && identityType != pattern[ID_TYPE] {
+ if identityType != "" && request[ID_TYPE] != "" && identityType != request[ID_TYPE] {
return false
}
- if pattern[ID_HOSTNAME] != "" && id[ID_HOSTNAME] != "" && pattern[ID_HOSTNAME] != id[ID_HOSTNAME] {
+ if request[ID_HOSTNAME] != "" && id[ID_HOSTNAME] != "" && request[ID_HOSTNAME] != id[ID_HOSTNAME] {
return false
}
- if pattern[ID_PORT] != "" {
- if id[ID_PORT] != "" && id[ID_PORT] != pattern[ID_PORT] {
+ if request[ID_PORT] != "" {
+ if id[ID_PORT] != "" && id[ID_PORT] != request[ID_PORT] {
return false
}
}
- if pattern[ID_SCHEME] != "" {
- if id[ID_SCHEME] != "" && id[ID_SCHEME] != pattern[ID_SCHEME] {
+ if request[ID_SCHEME] != "" {
+ if id[ID_SCHEME] != "" && id[ID_SCHEME] != request[ID_SCHEME] {
return false
}
}
- if pattern[ID_PATHPREFIX] != "" {
+ if request[ID_PATHPREFIX] != "" {
if id[ID_PATHPREFIX] != "" {
- if len(id[ID_PATHPREFIX]) > len(pattern[ID_PATHPREFIX]) {
+ if len(id[ID_PATHPREFIX]) > len(request[ID_PATHPREFIX]) {
return false
}
- pcomps := strings.Split(pattern[ID_PATHPREFIX], "/")
+ pcomps := strings.Split(request[ID_PATHPREFIX], "/")
icomps := strings.Split(id[ID_PATHPREFIX], "/")
if len(icomps) > len(pcomps) {
return false
@@ -100,10 +101,10 @@ func IdentityMatcher(identityType string) cpi.IdentityMatcher {
if cur[ID_HOSTNAME] == "" && id[ID_HOSTNAME] != "" {
return true
}
- if cur[ID_PORT] == "" && (id[ID_PORT] != "" && pattern[ID_PORT] != "") {
+ if cur[ID_PORT] == "" && (id[ID_PORT] != "" && request[ID_PORT] != "") {
return true
}
- if cur[ID_SCHEME] == "" && (id[ID_SCHEME] != "" && pattern[ID_SCHEME] != "") {
+ if cur[ID_SCHEME] == "" && (id[ID_SCHEME] != "" && request[ID_SCHEME] != "") {
return true
}
diff --git a/pkg/contexts/credentials/interface.go b/pkg/contexts/credentials/interface.go
index eb4037bb2b..054260cd2c 100644
--- a/pkg/contexts/credentials/interface.go
+++ b/pkg/contexts/credentials/interface.go
@@ -84,6 +84,14 @@ func NewCredentials(props common.Properties) Credentials {
return internal.NewCredentials(props)
}
+func CredentialsFromList(props ...string) Credentials {
+ creds := DirectCredentials{}
+ for i := 1; i < len(props); i += 2 {
+ creds[props[i-1]] = props[i]
+ }
+ return creds
+}
+
func ToGenericCredentialsSpec(spec CredentialsSpec) (*GenericCredentialsSpec, error) {
return internal.ToGenericCredentialsSpec(spec)
}
diff --git a/pkg/contexts/credentials/internal/repotypes.go b/pkg/contexts/credentials/internal/repotypes.go
index fd92e59aa2..0e96254d71 100644
--- a/pkg/contexts/credentials/internal/repotypes.go
+++ b/pkg/contexts/credentials/internal/repotypes.go
@@ -12,11 +12,12 @@ import (
"github.com/open-component-model/ocm/pkg/errors"
"github.com/open-component-model/ocm/pkg/generics"
"github.com/open-component-model/ocm/pkg/runtime"
+ "github.com/open-component-model/ocm/pkg/runtime/descriptivetype"
"github.com/open-component-model/ocm/pkg/utils"
)
type RepositoryType interface {
- runtime.VersionedTypedObjectType[RepositorySpec]
+ descriptivetype.TypedObjectType[RepositorySpec]
}
type RepositorySpec interface {
@@ -31,22 +32,22 @@ type (
)
type RepositoryTypeScheme interface {
- runtime.TypeScheme[RepositorySpec, RepositoryType]
+ descriptivetype.TypeScheme[RepositorySpec, RepositoryType]
}
-type _Scheme = runtime.TypeScheme[RepositorySpec, RepositoryType]
+type _Scheme = descriptivetype.TypeScheme[RepositorySpec, RepositoryType]
type repositoryTypeScheme struct {
_Scheme
}
func NewRepositoryTypeScheme(defaultDecoder RepositorySpecDecoder, base ...RepositoryTypeScheme) RepositoryTypeScheme {
- scheme := runtime.MustNewDefaultTypeScheme[RepositorySpec, RepositoryType](&UnknownRepositorySpec{}, true, defaultDecoder, utils.Optional(base...))
+ scheme := descriptivetype.MustNewDefaultTypeScheme[RepositorySpec, RepositoryType, RepositoryTypeScheme]("Credential provider", nil, &UnknownRepositorySpec{}, true, defaultDecoder, utils.Optional(base...))
return &repositoryTypeScheme{scheme}
}
func NewStrictRepositoryTypeScheme(base ...RepositoryTypeScheme) runtime.VersionedTypeRegistry[RepositorySpec, RepositoryType] {
- scheme := runtime.MustNewDefaultTypeScheme[RepositorySpec, RepositoryType](nil, false, nil, utils.Optional(base...))
+ scheme := descriptivetype.MustNewDefaultTypeScheme[RepositorySpec, RepositoryType, RepositoryTypeScheme]("Credential provider", nil, nil, false, nil, utils.Optional(base...))
return &repositoryTypeScheme{scheme}
}
diff --git a/pkg/contexts/credentials/repositories/directcreds/a_usage.go b/pkg/contexts/credentials/repositories/directcreds/a_usage.go
new file mode 100644
index 0000000000..705144e3bf
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/directcreds/a_usage.go
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package directcreds
+
+import (
+ "github.com/open-component-model/ocm/pkg/listformat"
+)
+
+var usage = `
+This repository type can be used to specify a single inline credential
+set. The default name is the empty string or ` + Type + `
.`
+
+var format = `The repository specification supports the following fields:
+` + listformat.FormatListElements("", listformat.StringElementDescriptionList{
+ "properties", "*map[string]string*: direct credential fields",
+})
diff --git a/pkg/contexts/credentials/repositories/directcreds/type.go b/pkg/contexts/credentials/repositories/directcreds/type.go
index 54fef494d6..7fde18b079 100644
--- a/pkg/contexts/credentials/repositories/directcreds/type.go
+++ b/pkg/contexts/credentials/repositories/directcreds/type.go
@@ -17,7 +17,7 @@ const (
func init() {
cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](Type))
- cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](TypeV1))
+ cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](TypeV1, cpi.WithDescription(usage), cpi.WithFormatSpec(format)))
}
// RepositorySpec describes a repository interface for single direct credentials.
diff --git a/pkg/contexts/credentials/repositories/dockerconfig/a_usage.go b/pkg/contexts/credentials/repositories/dockerconfig/a_usage.go
new file mode 100644
index 0000000000..b6f15f95ba
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/dockerconfig/a_usage.go
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package dockerconfig
+
+import (
+ "github.com/open-component-model/ocm/pkg/listformat"
+)
+
+var usage = `
+This repository type can be used to access credentials stored in a file
+following the docker config json format. It take into account the
+credentials helper section, also. If enabled, the described
+credentials will be automatically assigned to appropriate consumer ids.
+`
+
+var format = `The repository specification supports the following fields:
+` + listformat.FormatListElements("", listformat.StringElementDescriptionList{
+ "dockerConfigFile", "*string*: the file path to a docker config file",
+ "dockerConfig", "*json*: an embedded docker config json",
+ "propagateConsumerIdentity", "*bool*(optional): enable consumer id propagation",
+})
diff --git a/pkg/contexts/credentials/repositories/dockerconfig/type.go b/pkg/contexts/credentials/repositories/dockerconfig/type.go
index 8968e92b4f..30acfd93c9 100644
--- a/pkg/contexts/credentials/repositories/dockerconfig/type.go
+++ b/pkg/contexts/credentials/repositories/dockerconfig/type.go
@@ -19,7 +19,7 @@ const (
func init() {
cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](Type))
- cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](TypeV1))
+ cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](TypeV1, cpi.WithDescription(usage), cpi.WithFormatSpec(format)))
}
// RepositorySpec describes a docker config based credential repository interface.
diff --git a/pkg/contexts/credentials/repositories/init.go b/pkg/contexts/credentials/repositories/init.go
index bd9f8e9c7b..84d8ad4bc8 100644
--- a/pkg/contexts/credentials/repositories/init.go
+++ b/pkg/contexts/credentials/repositories/init.go
@@ -11,4 +11,5 @@ import (
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/gardenerconfig"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/memory"
_ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/memory/config"
+ _ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault"
)
diff --git a/pkg/contexts/credentials/repositories/vault/a_usage.go b/pkg/contexts/credentials/repositories/vault/a_usage.go
new file mode 100644
index 0000000000..b772496657
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/a_usage.go
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "strings"
+
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault/identity"
+ "github.com/open-component-model/ocm/pkg/listformat"
+)
+
+func init() {
+ info := cpi.DefaultContext.ConsumerIdentityMatchers().GetInfo(identity.CONSUMER_TYPE)
+ idx := strings.Index(info.Description, "\n")
+ desc := `
+This repository type can be used to access credentials stored in a HashiCorp
+Vault.
+
+It provides access to list of secrets stored under a dedicated path in
+a vault namespace. This list can either explicitly be specified, or
+it is taken from the metadata of a specified secret.
+
+The following custom metadata attributes are evaluated:
+- ` + CUSTOM_SECRETS + `
this attribute may contain a comma separated list of
+ vault secrets, which should be exposed by this repository instance.
+ The names are evaluated under the path prefix used for the repository.
+- ` + CUSTOM_CONSUMERID + `
this attribute may contain a JSON encoded
+ consumer id , this secret should be assigned to.
+- type
if no special attribute is defined this attribute
+ indicated to use the complete custom metadata as consumer id.
+
+It uses the ` + identity.CONSUMER_TYPE + ` identity matcher and consumer type
+to requests credentials for the access.
+` + info.Description[idx:] + `
+
+It requires the following credential attributes:
+
+` + info.CredentialAttributes
+
+ usage = desc
+}
+
+var usage string
+
+var format = `
+The repository specification supports the following fields:
+` + listformat.FormatListElements("", listformat.StringElementDescriptionList{
+ "serverURL", "*string* (required): the URL of the vault instance",
+ "namespace", "*string* (optional): the namespace used to evaluate secrets",
+ "secretsEngine", "*string* (optional): the secrets engine to use (default: secrets)",
+ "path", "*string* (optional): the path prefix used to lookup secrets",
+ "secrets", "*[]string* (optional): list of secrets",
+ "propagateConsumerIdentity", "*bool*(optional): evaluate metadata for consumer id propagation",
+}) + `
+If the secrets list is empty, all secret entries found in the given path
+is read.
+`
diff --git a/pkg/contexts/credentials/repositories/vault/auth.go b/pkg/contexts/credentials/repositories/vault/auth.go
new file mode 100644
index 0000000000..c646e4c2f5
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/auth.go
@@ -0,0 +1,129 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "context"
+ "sort"
+ "sync"
+
+ "github.com/hashicorp/vault-client-go"
+ "github.com/hashicorp/vault-client-go/schema"
+ "golang.org/x/exp/maps"
+
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault/identity"
+ "github.com/open-component-model/ocm/pkg/errors"
+)
+
+type AuthMethod interface {
+ GetName() string
+ Validate(creds cpi.Credentials) error
+ GetToken(ctx context.Context, client *vault.Client, ns string, creds cpi.Credentials) (string, error)
+}
+
+type AuthMethods struct {
+ lock sync.Mutex
+ methods map[string]AuthMethod
+}
+
+var methods = NewAuthMethods()
+
+func NewAuthMethods() *AuthMethods {
+ return &AuthMethods{
+ methods: map[string]AuthMethod{},
+ }
+}
+
+func (r *AuthMethods) Register(m AuthMethod) {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ r.methods[m.GetName()] = m
+}
+
+func (r *AuthMethods) Get(name string) AuthMethod {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ return r.methods[name]
+}
+
+func (r *AuthMethods) Names() []string {
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ names := maps.Keys(r.methods)
+ sort.Strings(names)
+ return names
+}
+
+func RegisterAuthMethod(m AuthMethod) {
+ methods.Register(m)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+func init() {
+ RegisterAuthMethod(&approle{})
+ RegisterAuthMethod(&token{})
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type approle struct{}
+
+var _ AuthMethod = (*approle)(nil)
+
+func (a *approle) GetName() string {
+ return identity.AUTH_APPROLE
+}
+
+func (a *approle) Validate(creds cpi.Credentials) error {
+ if !creds.ExistsProperty(identity.ATTR_ROLEID) {
+ return errors.ErrRequired("credential property", identity.ATTR_ROLEID, a.GetName())
+ }
+ if !creds.ExistsProperty(identity.ATTR_SECRETID) {
+ return errors.ErrRequired("credential property", identity.ATTR_SECRETID, a.GetName())
+ }
+ return nil
+}
+
+func (a *approle) GetToken(ctx context.Context, client *vault.Client, ns string, creds cpi.Credentials) (string, error) {
+ req := schema.AppRoleLoginRequest{
+ RoleId: creds.GetProperty(identity.ATTR_ROLEID),
+ SecretId: creds.GetProperty(identity.ATTR_SECRETID),
+ }
+ resp, err := client.Auth.AppRoleLogin(
+ ctx,
+ req,
+ vault.WithNamespace(ns),
+ )
+ if err != nil {
+ return "", err
+ }
+ return resp.Auth.ClientToken, nil
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type token struct{}
+
+var _ AuthMethod = (*token)(nil)
+
+func (a *token) GetName() string {
+ return identity.AUTH_TOKEN
+}
+
+func (a *token) Validate(creds cpi.Credentials) error {
+ if !creds.ExistsProperty(identity.ATTR_TOKEN) {
+ return errors.ErrRequired("credential property", identity.ATTR_TOKEN, a.GetName())
+ }
+ return nil
+}
+
+func (a *token) GetToken(ctx context.Context, client *vault.Client, ns string, creds cpi.Credentials) (string, error) {
+ return creds.GetProperty(identity.ATTR_TOKEN), nil
+}
diff --git a/pkg/contexts/credentials/repositories/vault/cache.go b/pkg/contexts/credentials/repositories/vault/cache.go
new file mode 100644
index 0000000000..1b2d700bb5
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/cache.go
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "sync"
+
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/datacontext"
+ "github.com/open-component-model/ocm/pkg/errors"
+)
+
+const ATTR_REPOS = "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault"
+
+type Repositories struct {
+ lock sync.Mutex
+ repos map[cpi.ProviderIdentity]*Repository
+}
+
+func newRepositories(datacontext.Context) interface{} {
+ return &Repositories{
+ repos: map[cpi.ProviderIdentity]*Repository{},
+ }
+}
+
+func (r *Repositories) GetRepository(ctx cpi.Context, spec *RepositorySpec) (*Repository, error) {
+ var repo *Repository
+
+ if spec.ServerURL == "" {
+ return nil, errors.ErrInvalid("server url")
+ }
+ r.lock.Lock()
+ defer r.lock.Unlock()
+
+ var err error
+ key := spec.GetKey()
+ repo = r.repos[key]
+ if repo == nil {
+ repo, err = NewRepository(ctx, spec)
+ if err == nil {
+ r.repos[key] = repo
+ }
+ }
+ return repo, err
+}
diff --git a/pkg/contexts/credentials/repositories/vault/identity/identity.go b/pkg/contexts/credentials/repositories/vault/identity/identity.go
new file mode 100644
index 0000000000..79ba43d7eb
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/identity/identity.go
@@ -0,0 +1,128 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package identity
+
+import (
+ "net"
+ "net/url"
+ "strings"
+
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/identity/hostpath"
+ "github.com/open-component-model/ocm/pkg/errors"
+ "github.com/open-component-model/ocm/pkg/listformat"
+)
+
+const CONSUMER_TYPE = "HashiCorpVault"
+
+// identity properties.
+const (
+ ID_HOSTNAME = hostpath.ID_HOSTNAME
+ ID_SCHEMA = hostpath.ID_SCHEME
+ ID_PORT = hostpath.ID_PORT
+ ID_PATHPREFIX = hostpath.ID_PATHPREFIX
+ ID_SECRETENGINE = "secretEngine"
+ ID_NAMESPACE = "namespace"
+)
+
+// credential properties.
+const (
+ ATTR_AUTHMETH = "authmeth"
+ ATTR_TOKEN = cpi.ATTR_TOKEN
+ ATTR_ROLEID = "roleid"
+ ATTR_SECRETID = "secretid"
+)
+
+const (
+ AUTH_APPROLE = "approle"
+ AUTH_TOKEN = "token"
+)
+
+var identityMatcher = hostpath.IdentityMatcher(CONSUMER_TYPE)
+
+func IdentityMatcher(request, cur, id cpi.ConsumerIdentity) bool {
+ if id[ID_NAMESPACE] != request[ID_NAMESPACE] {
+ return false
+ }
+ if id[ID_SECRETENGINE] != "" && id[ID_SECRETENGINE] != request[ID_SECRETENGINE] {
+ return false
+ }
+ return identityMatcher(request, cur, id)
+}
+
+func init() {
+ attrs := listformat.FormatListElements("", listformat.StringElementDescriptionList{
+ ATTR_AUTHMETH, "auth method",
+ ATTR_TOKEN, "vault token",
+ ATTR_ROLEID, "applrole role id",
+ ATTR_SECRETID, "applrole secret id",
+ ATTR_SECRETID, "applrole secret id",
+ })
+ ids := listformat.FormatListElements("", listformat.StringElementDescriptionList{
+ ID_HOSTNAME, "vault server host",
+ ID_SCHEMA, "(optional) URL scheme",
+ ID_PORT, "(optional) server port",
+ ID_NAMESPACE, "vault namespace",
+ ID_SECRETENGINE, "secret engine",
+ ID_PATHPREFIX, "path prefix for secret",
+ })
+ cpi.RegisterStandardIdentity(CONSUMER_TYPE, identityMatcher,
+ `HashiCorp Vault credential matcher
+
+This matcher matches credentials for a HashiCorp vault instance.
+It uses the following identity attributes:
+`+ids,
+ attrs+`
+The only supported auth methods, so far, are token
and approle
.
+`)
+}
+
+func GetConsumerId(serverurl string, namespace string, secretengine string, secretpath string) (cpi.ConsumerIdentity, error) {
+ if serverurl == "" {
+ return nil, errors.Newf("server address must be given")
+ }
+ u, err := url.Parse(serverurl)
+ if err != nil {
+ return nil, errors.ErrInvalidWrap(err, "server url", serverurl)
+ }
+
+ host, port, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ if strings.LastIndex(host, ":") >= 0 {
+ return nil, errors.ErrInvalidWrap(err, "server url", serverurl)
+ }
+ host = u.Host
+ }
+
+ id := cpi.ConsumerIdentity{
+ cpi.ID_TYPE: CONSUMER_TYPE,
+ ID_HOSTNAME: host,
+ }
+ if u.Scheme != "" {
+ id[ID_SCHEMA] = u.Scheme
+ }
+ if port != "" {
+ id[ID_PORT] = port
+ }
+ if namespace != "" {
+ id[ID_NAMESPACE] = namespace
+ }
+ if secretengine != "" {
+ id[ID_SECRETENGINE] = secretengine
+ }
+
+ if secretpath != "" {
+ id[ID_PATHPREFIX] = secretpath
+ }
+ return id, nil
+}
+
+func GetCredentials(ctx cpi.ContextProvider, serverurl, namespace string, secretengine, secretpath string) (cpi.Credentials, error) {
+ id, err := GetConsumerId(serverurl, namespace, secretengine, secretpath)
+ if err != nil {
+ return nil, err
+ }
+ return cpi.CredentialsForConsumer(ctx.CredentialsContext(), id, IdentityMatcher)
+}
diff --git a/pkg/contexts/credentials/repositories/vault/logging.go b/pkg/contexts/credentials/repositories/vault/logging.go
new file mode 100644
index 0000000000..d75d785db6
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/logging.go
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ ocmlog "github.com/open-component-model/ocm/pkg/logging"
+)
+
+var (
+ REALM = ocmlog.DefineSubRealm("HashiCorp Vault Access", "credentials", "vault")
+ log = ocmlog.DynamicLogger(REALM)
+)
diff --git a/pkg/contexts/credentials/repositories/vault/options.go b/pkg/contexts/credentials/repositories/vault/options.go
new file mode 100644
index 0000000000..71031496f1
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/options.go
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "golang.org/x/exp/slices"
+
+ "github.com/open-component-model/ocm/pkg/optionutils"
+ "github.com/open-component-model/ocm/pkg/utils"
+)
+
+type Option = optionutils.Option[*Options]
+
+type Options struct {
+ Namespace string `json:"namespace,omitempty"`
+ SecretsEngine string `json:"secretsEngine,omitempty"`
+ Path string `json:"path,omitempty"`
+ Secrets []string `json:"secrets,omitempty"`
+ PropgateConsumerIdentity bool `json:"propagateConsumerIdentity,omitempty"`
+}
+
+var _ Option = (*Options)(nil)
+
+func (o *Options) ApplyTo(opts *Options) {
+ if o.Namespace != "" {
+ opts.Namespace = o.Namespace
+ }
+ if o.SecretsEngine != "" {
+ opts.SecretsEngine = o.SecretsEngine
+ }
+ if o.Path != "" {
+ opts.Path = o.Path
+ }
+ if o.Secrets != nil {
+ opts.Secrets = slices.Clone(o.Secrets)
+ }
+ opts.PropgateConsumerIdentity = o.PropgateConsumerIdentity
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type ns string
+
+func (o ns) ApplyTo(opts *Options) {
+ opts.Namespace = string(o)
+}
+
+func WithNamespace(s string) Option {
+ return ns(s)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type se string
+
+func (o se) ApplyTo(opts *Options) {
+ opts.SecretsEngine = string(o)
+}
+
+func WithSecretsEngine(s string) Option {
+ return se(s)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type p string
+
+func (o p) ApplyTo(opts *Options) {
+ opts.Path = string(o)
+}
+
+func WithPath(s string) Option {
+ return p(s)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type sec []string
+
+func (o sec) ApplyTo(opts *Options) {
+ opts.Secrets = append(opts.Secrets, []string(o)...)
+}
+
+func WithSecrets(s ...string) Option {
+ return sec(slices.Clone(s))
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type pr bool
+
+func (o pr) ApplyTo(opts *Options) {
+ opts.PropgateConsumerIdentity = bool(o)
+}
+
+func WithPropagation(b ...bool) Option {
+ return pr(utils.OptionalDefaultedBool(true, b...))
+}
diff --git a/pkg/contexts/credentials/repositories/vault/provider.go b/pkg/contexts/credentials/repositories/vault/provider.go
new file mode 100644
index 0000000000..1d8c9fb4ec
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/provider.go
@@ -0,0 +1,290 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "context"
+ "encoding/json"
+ "path"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/hashicorp/vault-client-go"
+ "golang.org/x/exp/slices"
+
+ "github.com/open-component-model/ocm/pkg/common"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault/identity"
+ "github.com/open-component-model/ocm/pkg/errors"
+)
+
+const PROVIDER = "ocm.software/credentialprovider/" + Type
+
+const (
+ CUSTOM_SECRETS = "secrets"
+ CUSTOM_CONSUMERID = "consumerId"
+)
+
+type mapping struct {
+ Id cpi.ConsumerIdentity
+ Name string
+}
+
+type ConsumerProvider struct {
+ lock sync.Mutex
+ credentials map[string]cpi.DirectCredentials
+ repository *Repository
+ creds cpi.CredentialsSource
+ consumer []*mapping
+
+ updated bool
+}
+
+var _ cpi.ConsumerProvider = (*ConsumerProvider)(nil)
+
+func NewConsumerProvider(repo *Repository) (*ConsumerProvider, error) {
+ src, err := repo.ctx.GetCredentialsForConsumer(repo.id)
+ if err != nil {
+ return nil, err
+ }
+ return &ConsumerProvider{
+ creds: src,
+ repository: repo,
+ credentials: map[string]cpi.DirectCredentials{},
+ }, nil
+}
+
+func (p *ConsumerProvider) update() error {
+ var err error
+
+ if p.updated {
+ return nil
+ }
+ p.updated = true
+
+ p.creds, err = p.repository.ctx.GetCredentialsForConsumer(p.repository.id, identity.IdentityMatcher)
+ if err != nil {
+ return err
+ }
+ creds, err := p.creds.Credentials(p.repository.ctx)
+ if err != nil {
+ return err
+ }
+ err = p.validateCreds(creds)
+ if err != nil {
+ return err
+ }
+
+ p.credentials = map[string]cpi.DirectCredentials{}
+ p.consumer = nil
+
+ ctx := context.Background()
+
+ client, err := vault.New(
+ vault.WithAddress(p.repository.spec.ServerURL),
+ vault.WithRequestTimeout(30*time.Second),
+ )
+ if err != nil {
+ return err
+ }
+
+ // vault.WithMountPath("piper/PIPELINE-GROUP-4953/PIPELINE-25042/appRoleCredentials"),
+ token, err := p.getToken(ctx, client, creds)
+ if err != nil {
+ return err
+ }
+
+ if err := client.SetToken(token); err != nil {
+ return err
+ }
+ if err := client.SetNamespace(p.repository.spec.Namespace); err != nil {
+ return err
+ }
+
+ // TODO: support for pure path based access for other secret engine types
+ secrets := slices.Clone(p.repository.spec.Secrets)
+ if len(secrets) == 0 {
+ s, err := client.Secrets.KvV2List(ctx, p.repository.spec.Path,
+ vault.WithMountPath(p.repository.spec.SecretsEngine))
+ if err != nil {
+ return err
+ }
+ for _, k := range s.Data.Keys {
+ if !strings.HasSuffix(k, "/") {
+ secrets = append(secrets, k)
+ }
+ }
+ }
+ for i := 0; i < len(secrets); i++ {
+ n := secrets[i]
+ creds, id, list, err := p.read(ctx, client, n)
+ p.error(err, "error reading vault secret", n)
+ if err == nil {
+ for _, a := range list {
+ if !slices.Contains(secrets, a) {
+ secrets = append(secrets, a)
+ }
+ }
+ if len(id) > 0 {
+ p.consumer = append(p.consumer, &mapping{
+ Id: cpi.ConsumerIdentity(id),
+ Name: n,
+ })
+ }
+ if len(creds) > 0 {
+ p.credentials[n] = cpi.DirectCredentials(creds)
+ }
+ }
+ }
+ return nil
+}
+
+func (p *ConsumerProvider) validateCreds(creds cpi.Credentials) error {
+ m := creds.GetProperty(identity.ATTR_AUTHMETH)
+ if m == "" {
+ return errors.ErrRequired(identity.ATTR_AUTHMETH)
+ }
+ meth := methods.Get(m)
+ if meth == nil {
+ return errors.ErrInvalid(identity.ATTR_AUTHMETH, m)
+ }
+ return meth.Validate(creds)
+}
+
+func (p *ConsumerProvider) getToken(ctx context.Context, client *vault.Client, creds cpi.Credentials) (string, error) {
+ m := creds.GetProperty(identity.ATTR_AUTHMETH)
+ return methods.Get(m).GetToken(ctx, client, p.repository.spec.Namespace, creds)
+}
+
+func (p *ConsumerProvider) error(err error, msg string, secret string, keypairs ...interface{}) {
+ if err == nil {
+ return
+ }
+ log.Error(msg, append(keypairs,
+ "server", p.repository.spec.ServerURL,
+ "namespace", p.repository.spec.Namespace,
+ "engine", p.repository.spec.SecretsEngine,
+ "path", path.Join(p.repository.spec.Path, secret),
+ "error", err.Error(),
+ )...,
+ )
+}
+
+func (p *ConsumerProvider) read(ctx context.Context, client *vault.Client, secret string) (common.Properties, common.Properties, []string, error) {
+ // read the secret
+
+ secret = path.Join(p.repository.spec.Path, secret)
+ s, err := client.Secrets.KvV2Read(ctx, secret,
+ vault.WithMountPath(p.repository.spec.SecretsEngine))
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ var id common.Properties
+ var list []string
+ props := getProps(s.Data.Data)
+
+ if meta, ok := s.Data.Metadata["custom_metadata"].(map[string]interface{}); ok {
+ sub := false
+ if cid := meta[CUSTOM_CONSUMERID]; cid != nil {
+ id = common.Properties{}
+ if err := json.Unmarshal([]byte(cid.(string)), &id); err != nil {
+ id = nil
+ }
+ sub = true
+ }
+ if cid := meta[CUSTOM_SECRETS]; cid != nil {
+ if s, ok := meta[CUSTOM_SECRETS].(string); ok {
+ for _, e := range strings.Split(s, ",") {
+ e = strings.TrimSpace(e)
+ if e != "" {
+ list = append(list, e)
+ }
+ }
+ }
+ sub = true
+ }
+ if _, ok := meta[cpi.ID_TYPE]; !sub && ok {
+ id = getProps(meta)
+ }
+ }
+ return props, id, list, nil
+}
+
+func getProps(data map[string]interface{}) common.Properties {
+ props := common.Properties{}
+ for k, v := range data {
+ if s, ok := v.(string); ok {
+ props[k] = s
+ }
+ }
+ return props
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ConsumerProvider interface
+
+func (p *ConsumerProvider) Unregister(id cpi.ProviderIdentity) {
+}
+
+func (p *ConsumerProvider) Match(req cpi.ConsumerIdentity, cur cpi.ConsumerIdentity, m cpi.IdentityMatcher) (cpi.CredentialsSource, cpi.ConsumerIdentity) {
+ return p.get(req, cur, m)
+}
+
+func (p *ConsumerProvider) Get(req cpi.ConsumerIdentity) (cpi.CredentialsSource, bool) {
+ creds, _ := p.get(req, nil, cpi.CompleteMatch)
+ return creds, creds != nil
+}
+
+func (p *ConsumerProvider) get(req cpi.ConsumerIdentity, cur cpi.ConsumerIdentity, m cpi.IdentityMatcher) (cpi.CredentialsSource, cpi.ConsumerIdentity) {
+ if req.Equals(p.repository.id) {
+ return nil, cur
+ }
+
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ p.update()
+ var creds cpi.CredentialsSource
+
+ for _, a := range p.consumer {
+ if m(req, cur, a.Id) {
+ cur = a.Id
+ creds = p.credentials[a.Name]
+ }
+ }
+ return creds, cur
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// lookup
+
+func (c *ConsumerProvider) ExistsCredentials(name string) (bool, error) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ err := c.update()
+ if err != nil {
+ return false, err
+ }
+ _, ok := c.credentials[name]
+ return ok, nil
+}
+
+func (c *ConsumerProvider) LookupCredentials(name string) (cpi.Credentials, error) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ err := c.update()
+ if err != nil {
+ return nil, err
+ }
+ src, ok := c.credentials[name]
+ if ok {
+ return src, nil
+ }
+ return nil, nil
+}
diff --git a/pkg/contexts/credentials/repositories/vault/repository.go b/pkg/contexts/credentials/repositories/vault/repository.go
new file mode 100644
index 0000000000..c09ed75bde
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/repository.go
@@ -0,0 +1,69 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/internal"
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/vault/identity"
+ "github.com/open-component-model/ocm/pkg/errors"
+)
+
+type Repository struct {
+ ctx cpi.Context
+ spec *RepositorySpec
+ id cpi.ConsumerIdentity
+ provider *ConsumerProvider
+}
+
+var (
+ _ cpi.Repository = (*Repository)(nil)
+ _ cpi.ConsumerIdentityProvider = (*Repository)(nil)
+)
+
+func NewRepository(ctx cpi.Context, spec *RepositorySpec) (*Repository, error) {
+ id, err := identity.GetConsumerId(spec.ServerURL, spec.Namespace, spec.SecretsEngine, spec.Path)
+ if err != nil {
+ return nil, err
+ }
+ r := &Repository{
+ ctx: ctx,
+ spec: spec,
+ id: id,
+ }
+ if spec.ServerURL == "" {
+ return nil, errors.ErrInvalid("server url")
+ }
+ r.provider, err = NewConsumerProvider(r)
+ if err != nil {
+ return nil, err
+ }
+ if spec.PropgateConsumerIdentity {
+ ctx.RegisterConsumerProvider(spec.GetKey(), r.provider)
+ }
+ return r, err
+}
+
+var _ cpi.Repository = &Repository{}
+
+func (r *Repository) ExistsCredentials(name string) (bool, error) {
+ return r.provider.ExistsCredentials(name)
+}
+
+func (r *Repository) LookupCredentials(name string) (cpi.Credentials, error) {
+ return r.provider.LookupCredentials(name)
+}
+
+func (r *Repository) WriteCredentials(name string, creds cpi.Credentials) (cpi.Credentials, error) {
+ return nil, errors.ErrNotSupported("write", "credentials", Type)
+}
+
+func (r *Repository) GetConsumerId(uctx ...internal.UsageContext) internal.ConsumerIdentity {
+ return r.id
+}
+
+func (r *Repository) GetIdentityMatcher() string {
+ return identity.CONSUMER_TYPE
+}
diff --git a/pkg/contexts/credentials/repositories/vault/suite_test.go b/pkg/contexts/credentials/repositories/vault/suite_test.go
new file mode 100644
index 0000000000..9a64144cc1
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/suite_test.go
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault_test
+
+import (
+ "testing"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+)
+
+func TestConfig(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Vault Credentials Test Suite")
+}
diff --git a/pkg/contexts/credentials/repositories/vault/type.go b/pkg/contexts/credentials/repositories/vault/type.go
new file mode 100644
index 0000000000..267ce989af
--- /dev/null
+++ b/pkg/contexts/credentials/repositories/vault/type.go
@@ -0,0 +1,70 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package vault
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "golang.org/x/exp/slices"
+
+ "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
+ "github.com/open-component-model/ocm/pkg/optionutils"
+ "github.com/open-component-model/ocm/pkg/runtime"
+)
+
+const (
+ Type = "HashiCorpVault"
+ TypeV1 = Type + runtime.VersionSeparator + "v1"
+)
+
+func init() {
+ cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](Type))
+ cpi.RegisterRepositoryType(cpi.NewRepositoryType[*RepositorySpec](TypeV1, cpi.WithDescription(usage), cpi.WithFormatSpec(format)))
+}
+
+// RepositorySpec describes a docker config based credential repository interface.
+type RepositorySpec struct {
+ runtime.ObjectVersionedType `json:",inline"`
+ ServerURL string `json:"serverURL"`
+ Options `json:",inline"`
+}
+
+// NewRepositorySpec creates a new memory RepositorySpec.
+func NewRepositorySpec(url string, opts ...Option) *RepositorySpec {
+ return &RepositorySpec{
+ ObjectVersionedType: runtime.NewVersionedTypedObject(Type),
+ ServerURL: url,
+ Options: *optionutils.EvalOptions(opts...),
+ }
+}
+
+func (a *RepositorySpec) GetType() string {
+ return Type
+}
+
+func (a *RepositorySpec) Repository(ctx cpi.Context, creds cpi.Credentials) (cpi.Repository, error) {
+ r := ctx.GetAttributes().GetOrCreateAttribute(ATTR_REPOS, newRepositories)
+ repos, ok := r.(*Repositories)
+ if !ok {
+ return nil, fmt.Errorf("failed to assert type %T to Repositories", r)
+ }
+ spec := *a
+ spec.Secrets = slices.Clone(a.Secrets)
+ if spec.SecretsEngine == "" {
+ spec.SecretsEngine = "secrets"
+ }
+ return repos.GetRepository(ctx, &spec)
+}
+
+func (a *RepositorySpec) GetKey() cpi.ProviderIdentity {
+ spec := *a
+ spec.PropgateConsumerIdentity = false
+ data, err := json.Marshal(&spec)
+ if err == nil {
+ return cpi.ProviderIdentity(data)
+ }
+ return cpi.ProviderIdentity(spec.ServerURL)
+}
diff --git a/pkg/contexts/credentials/usage.go b/pkg/contexts/credentials/usage.go
new file mode 100644
index 0000000000..feb9081bef
--- /dev/null
+++ b/pkg/contexts/credentials/usage.go
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package credentials
+
+func RepositoryUsage(scheme RepositoryTypeScheme) string {
+ s := `
+The following list describes the supported credential providers
+(credential repositories), their specification versions
+and formats. Because of the extensible nature of the OCM model,
+credential consum
+`
+ return s + scheme.Describe()
+}
diff --git a/pkg/contexts/ocm/cpi/accessspec_options.go b/pkg/contexts/ocm/cpi/accessspec_options.go
index 380dc99de2..718277e4e5 100644
--- a/pkg/contexts/ocm/cpi/accessspec_options.go
+++ b/pkg/contexts/ocm/cpi/accessspec_options.go
@@ -6,19 +6,19 @@ package cpi
import (
"github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
- "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi/clitypes"
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets/flagsetscheme"
)
-type AccessSpecTypeOption = clitypes.CLITypeOption
+type AccessSpecTypeOption = flagsetscheme.TypeOption
func WithFormatSpec(value string) AccessSpecTypeOption {
- return clitypes.WithFormatSpec(value)
+ return flagsetscheme.WithFormatSpec(value)
}
func WithDescription(value string) AccessSpecTypeOption {
- return clitypes.WithDescription(value)
+ return flagsetscheme.WithDescription(value)
}
func WithConfigHandler(value flagsets.ConfigOptionTypeSetHandler) AccessSpecTypeOption {
- return clitypes.WithConfigHandler(value)
+ return flagsetscheme.WithConfigHandler(value)
}
diff --git a/pkg/contexts/ocm/cpi/accesstypes.go b/pkg/contexts/ocm/cpi/accesstypes.go
index 14024d5267..f573991325 100644
--- a/pkg/contexts/ocm/cpi/accesstypes.go
+++ b/pkg/contexts/ocm/cpi/accesstypes.go
@@ -5,7 +5,7 @@
package cpi
import (
- "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi/clitypes"
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets/flagsetscheme"
"github.com/open-component-model/ocm/pkg/runtime"
)
@@ -36,13 +36,13 @@ func MustNewAccessSpecMultiFormatVersion(kind string, formats AccessSpecFormatVe
}
func NewAccessSpecType[I AccessSpec](name string, opts ...AccessSpecTypeOption) AccessType {
- return clitypes.NewCLITypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectType[AccessSpec, I](name), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectType[AccessSpec, I](name), opts...)
}
func NewAccessSpecTypeByConverter[I AccessSpec, V runtime.VersionedTypedObject](name string, converter runtime.Converter[I, V], opts ...AccessSpecTypeOption) AccessType {
- return clitypes.NewCLITypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectTypeByConverter[AccessSpec, I, V](name, converter), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectTypeByConverter[AccessSpec, I, V](name, converter), opts...)
}
func NewAccessSpecTypeByFormatVersion(name string, fmt runtime.FormatVersion[AccessSpec], opts ...AccessSpecTypeOption) AccessType {
- return clitypes.NewCLITypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectTypeByFormatVersion[AccessSpec](name, fmt), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[AccessSpec](runtime.NewVersionedTypedObjectTypeByFormatVersion[AccessSpec](name, fmt), opts...)
}
diff --git a/pkg/contexts/ocm/cpi/clitypes/clitypes.go b/pkg/contexts/ocm/cpi/clitypes/clitypes.go
deleted file mode 100644
index cff1aa0cdb..0000000000
--- a/pkg/contexts/ocm/cpi/clitypes/clitypes.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package clitypes
-
-import (
- "github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
- "github.com/open-component-model/ocm/pkg/runtime"
-)
-
-type additionalCLITypeInfo interface {
- ConfigOptionTypeSetHandler() flagsets.ConfigOptionTypeSetHandler
- Description() string
- Format() string
-}
-
-type CLITypedObjectTypeObject[E runtime.VersionedTypedObject] struct {
- runtime.VersionedTypedObjectType[E]
- description string
- format string
- handler flagsets.ConfigOptionTypeSetHandler
- validator func(E) error
-}
-
-var _ additionalCLITypeInfo = (*CLITypedObjectTypeObject[runtime.VersionedTypedObject])(nil)
-
-func NewCLITypedObjectTypeObject[E runtime.VersionedTypedObject](vt runtime.VersionedTypedObjectType[E], opts ...CLITypeOption) *CLITypedObjectTypeObject[E] {
- t := CLIObjectTypeTarget[E]{&CLITypedObjectTypeObject[E]{
- VersionedTypedObjectType: vt,
- }}
- for _, o := range opts {
- o.ApplyToCLIOptionTarget(t)
- }
- return t.target
-}
-
-func (t *CLITypedObjectTypeObject[E]) ConfigOptionTypeSetHandler() flagsets.ConfigOptionTypeSetHandler {
- return t.handler
-}
-
-func (t *CLITypedObjectTypeObject[E]) Description() string {
- return t.description
-}
-
-func (t *CLITypedObjectTypeObject[E]) Format() string {
- return t.format
-}
-
-func (t *CLITypedObjectTypeObject[E]) Validate(e E) error {
- if t.validator == nil {
- return nil
- }
- return t.validator(e)
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// CLIObjectTypeTarget is used as target for option functions, it provides
-// setters for fields, which should nor be modifiable for a final type object.
-type CLIObjectTypeTarget[E runtime.VersionedTypedObject] struct {
- target *CLITypedObjectTypeObject[E]
-}
-
-func (t CLIObjectTypeTarget[E]) SetDescription(value string) {
- t.target.description = value
-}
-
-func (t CLIObjectTypeTarget[E]) SetFormat(value string) {
- t.target.format = value
-}
-
-func (t CLIObjectTypeTarget[E]) SetConfigHandler(value flagsets.ConfigOptionTypeSetHandler) {
- t.target.handler = value
-}
diff --git a/pkg/contexts/ocm/cpi/clitypes/clitypes_options.go b/pkg/contexts/ocm/cpi/clitypes/clitypes_options.go
deleted file mode 100644
index a462552a9a..0000000000
--- a/pkg/contexts/ocm/cpi/clitypes/clitypes_options.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
-//
-// SPDX-License-Identifier: Apache-2.0
-
-package clitypes
-
-import (
- "github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
-)
-
-////////////////////////////////////////////////////////////////////////////////
-// Access Type Options
-
-type CLIOptionTarget interface {
- SetFormat(string)
- SetDescription(string)
- SetConfigHandler(flagsets.ConfigOptionTypeSetHandler)
-}
-
-type CLITypeOption interface {
- ApplyToCLIOptionTarget(CLIOptionTarget)
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-type formatOption struct {
- value string
-}
-
-func WithFormatSpec(value string) CLITypeOption {
- return formatOption{value}
-}
-
-func (o formatOption) ApplyToCLIOptionTarget(t CLIOptionTarget) {
- t.SetFormat(o.value)
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-type descriptionOption struct {
- value string
-}
-
-func WithDescription(value string) CLITypeOption {
- return descriptionOption{value}
-}
-
-func (o descriptionOption) ApplyToCLIOptionTarget(t CLIOptionTarget) {
- t.SetDescription(o.value)
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-type configOption struct {
- value flagsets.ConfigOptionTypeSetHandler
-}
-
-func WithConfigHandler(value flagsets.ConfigOptionTypeSetHandler) CLITypeOption {
- return configOption{value}
-}
-
-func (o configOption) ApplyToCLIOptionTarget(t CLIOptionTarget) {
- t.SetConfigHandler(o.value)
-}
diff --git a/pkg/contexts/ocm/internal/accesstypes.go b/pkg/contexts/ocm/internal/accesstypes.go
index 02f18adf1a..e912cd4388 100644
--- a/pkg/contexts/ocm/internal/accesstypes.go
+++ b/pkg/contexts/ocm/internal/accesstypes.go
@@ -100,11 +100,11 @@ type AccessMethodView interface {
type AccessTypeScheme flagsetscheme.TypeScheme[AccessSpec, AccessType]
func NewAccessTypeScheme(base ...AccessTypeScheme) AccessTypeScheme {
- return flagsetscheme.NewTypeScheme[AccessSpec, AccessType, AccessTypeScheme]("access", "accessType", "blob access specification", "Access Specification Options", &UnknownAccessSpec{}, true, base...)
+ return flagsetscheme.NewTypeScheme[AccessSpec, AccessType, AccessTypeScheme]("Access type", "access", "accessType", "blob access specification", "Access Specification Options", &UnknownAccessSpec{}, true, base...)
}
func NewStrictAccessTypeScheme(base ...AccessTypeScheme) runtime.VersionedTypeRegistry[AccessSpec, AccessType] {
- return flagsetscheme.NewTypeScheme[AccessSpec, AccessType, AccessTypeScheme]("access", "accessType", "blob access specification", "Access Specification Options", nil, false, base...)
+ return flagsetscheme.NewTypeScheme[AccessSpec, AccessType, AccessTypeScheme]("Access type", "access", "accessType", "blob access specification", "Access Specification Options", nil, false, base...)
}
// DefaultAccessTypeScheme contains all globally known access serializer.
diff --git a/pkg/contexts/ocm/labels/routingslip/internal/entrytypes.go b/pkg/contexts/ocm/labels/routingslip/internal/entrytypes.go
index cde0d8496c..932d972c41 100644
--- a/pkg/contexts/ocm/labels/routingslip/internal/entrytypes.go
+++ b/pkg/contexts/ocm/labels/routingslip/internal/entrytypes.go
@@ -45,11 +45,11 @@ type (
type EntryTypeScheme = flagsetscheme.TypeScheme[Entry, EntryType]
func NewEntryTypeScheme(base ...EntryTypeScheme) EntryTypeScheme {
- return flagsetscheme.NewTypeScheme[Entry, EntryType, EntryTypeScheme]("entry", "", "routing slip entry specification", "Entry Specification Options", &UnknownEntry{}, true, base...)
+ return flagsetscheme.NewTypeScheme[Entry, EntryType, EntryTypeScheme]("Entry type", "entry", "", "routing slip entry specification", "Entry Specification Options", &UnknownEntry{}, true, base...)
}
func NewStrictEntryTypeScheme(base ...EntryTypeScheme) EntryTypeScheme {
- return flagsetscheme.NewTypeScheme[Entry, EntryType, EntryTypeScheme]("entry", "", "routing slip entry specification", "Entry Specification Options", nil, false, base...)
+ return flagsetscheme.NewTypeScheme[Entry, EntryType, EntryTypeScheme]("Entry type", "entry", "", "routing slip entry specification", "Entry Specification Options", nil, false, base...)
}
func CreateEntry(t runtime.TypedObject) (Entry, error) {
diff --git a/pkg/contexts/ocm/labels/routingslip/spi/entrytype_options.go b/pkg/contexts/ocm/labels/routingslip/spi/entrytype_options.go
index 127119fbb0..ad727449c7 100644
--- a/pkg/contexts/ocm/labels/routingslip/spi/entrytype_options.go
+++ b/pkg/contexts/ocm/labels/routingslip/spi/entrytype_options.go
@@ -6,19 +6,19 @@ package spi
import (
"github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
- "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi/clitypes"
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets/flagsetscheme"
)
-type EntryTypeOption = clitypes.CLITypeOption
+type EntryTypeOption = flagsetscheme.TypeOption
func WithFormatSpec(value string) EntryTypeOption {
- return clitypes.WithFormatSpec(value)
+ return flagsetscheme.WithFormatSpec(value)
}
func WithDescription(value string) EntryTypeOption {
- return clitypes.WithDescription(value)
+ return flagsetscheme.WithDescription(value)
}
func WithConfigHandler(value flagsets.ConfigOptionTypeSetHandler) EntryTypeOption {
- return clitypes.WithConfigHandler(value)
+ return flagsetscheme.WithConfigHandler(value)
}
diff --git a/pkg/contexts/ocm/labels/routingslip/spi/support.go b/pkg/contexts/ocm/labels/routingslip/spi/support.go
index a46846a127..2a0307208b 100644
--- a/pkg/contexts/ocm/labels/routingslip/spi/support.go
+++ b/pkg/contexts/ocm/labels/routingslip/spi/support.go
@@ -5,7 +5,7 @@
package spi
import (
- "github.com/open-component-model/ocm/pkg/contexts/ocm/cpi/clitypes"
+ "github.com/open-component-model/ocm/pkg/cobrautils/flagsets/flagsetscheme"
"github.com/open-component-model/ocm/pkg/runtime"
)
@@ -30,15 +30,15 @@ func MustNewEntryMultiFormatVersion(kind string, formats EntryFormatVersionRegis
////////////////////////////////////////////////////////////////////////////////
func NewEntryType[I Entry](name string, opts ...EntryTypeOption) EntryType {
- return clitypes.NewCLITypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectType[Entry, I](name), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectType[Entry, I](name), opts...)
}
func NewEntryTypeByConverter[I Entry, V runtime.VersionedTypedObject](name string, converter runtime.Converter[I, V], opts ...EntryTypeOption) EntryType {
- return clitypes.NewCLITypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectTypeByConverter[Entry, I, V](name, converter), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectTypeByConverter[Entry, I, V](name, converter), opts...)
}
func NewEntryTypeByFormatVersion(name string, fmt runtime.FormatVersion[Entry], opts ...EntryTypeOption) EntryType {
- return clitypes.NewCLITypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectTypeByFormatVersion[Entry](name, fmt), opts...)
+ return flagsetscheme.NewTypedObjectTypeObject[Entry](runtime.NewVersionedTypedObjectTypeByFormatVersion[Entry](name, fmt), opts...)
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/pkg/contexts/ocm/usage.go b/pkg/contexts/ocm/usage.go
index b3be485652..7ed4e0e10b 100644
--- a/pkg/contexts/ocm/usage.go
+++ b/pkg/contexts/ocm/usage.go
@@ -4,15 +4,6 @@
package ocm
-import (
- "fmt"
- "strings"
-
- "github.com/open-component-model/ocm/pkg/cobrautils/flagsets"
- "github.com/open-component-model/ocm/pkg/runtime"
- "github.com/open-component-model/ocm/pkg/utils"
-)
-
func AccessUsage(scheme AccessTypeScheme, cli bool) string {
s := `
The following list describes the supported access methods, their versions
@@ -22,65 +13,5 @@ The access method specification can be put below the access
field.
If always requires the field type
describing the kind and version
shown below.
`
- type method struct {
- desc string
- versions map[string]string
- options flagsets.ConfigOptionTypeSetHandler
- }
-
- descs := map[string]*method{}
-
- // gather info for kinds and versions
- for _, n := range scheme.KnownTypeNames() {
- kind, vers := runtime.KindVersion(n)
-
- info := descs[kind]
- if info == nil {
- info = &method{versions: map[string]string{}}
- descs[kind] = info
- }
-
- if vers == "" {
- vers = "v1"
- }
- if _, ok := info.versions[vers]; !ok {
- info.versions[vers] = ""
- }
-
- t := scheme.GetType(n)
-
- if t.ConfigOptionTypeSetHandler() != nil {
- info.options = t.ConfigOptionTypeSetHandler()
- }
- desc := t.Description()
- if desc != "" {
- info.desc = desc
- }
-
- desc = t.Format()
- if desc != "" {
- info.versions[vers] = desc
- }
- }
-
- for _, t := range utils.StringMapKeys(descs) {
- info := descs[t]
- desc := strings.Trim(info.desc, "\n")
- if desc != "" {
- s = fmt.Sprintf("%s\n- Access type %s
\n\n%s\n\n", s, t, utils.IndentLines(desc, " "))
-
- format := ""
- for _, f := range utils.StringMapKeys(info.versions) {
- desc = strings.Trim(info.versions[f], "\n")
- if desc != "" {
- format = fmt.Sprintf("%s\n- Version %s
\n\n%s\n", format, f, utils.IndentLines(desc, " "))
- }
- }
- if format != "" {
- s += fmt.Sprintf(" The following versions are supported:\n%s\n", strings.Trim(utils.IndentLines(format, " "), "\n"))
- }
- }
- s += utils.IndentLines(flagsets.FormatConfigOptions(info.options), " ")
- }
- return s
+ return s + scheme.Describe()
}
diff --git a/pkg/errors/required.go b/pkg/errors/required.go
new file mode 100644
index 0000000000..cd0239459a
--- /dev/null
+++ b/pkg/errors/required.go
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package errors
+
+type RequiredError struct {
+ errinfo
+}
+
+var formatRequired = NewDefaultFormatter("", "required", "for")
+
+func ErrRequired(spec ...string) error {
+ return &RequiredError{newErrInfo(formatRequired, spec...)}
+}
+
+func ErrRequiredWrap(err error, spec ...string) error {
+ return &RequiredError{wrapErrInfo(err, formatRequired, spec...)}
+}
+
+func IsErrNRequired(err error) bool {
+ return IsA(err, &RequiredError{})
+}
+
+func IsErrRequiredKind(err error, kind string) bool {
+ var uerr *RequiredError
+ if err == nil || !As(err, &uerr) {
+ return false
+ }
+ return uerr.kind == kind
+}
+
+func IsErrRequiredElem(err error, kind, elem string) bool {
+ var uerr *RequiredError
+ if err == nil || !As(err, &uerr) {
+ return false
+ }
+ return uerr.kind == kind && uerr.elem != nil && *uerr.elem == elem
+}
diff --git a/pkg/generics/cast.go b/pkg/generics/cast.go
index c27e21d236..3d6336b759 100644
--- a/pkg/generics/cast.go
+++ b/pkg/generics/cast.go
@@ -18,6 +18,8 @@ func TypeOf[T any]() reflect.Type {
return reflect.TypeOf(&ifce).Elem()
}
+// As casts an element typed by a type parameter
+// to a subtype, given by the type parameter T.
func As[T any](o interface{}) T {
var _nil T
if o == nil {
@@ -26,7 +28,7 @@ func As[T any](o interface{}) T {
return o.(T)
}
-// CastPointer casts a pointer/error result to an interface/error
+// AsE casts a pointer/error result to an interface/error
// result.
// In Go this cannot be done directly, because returning a nil pinter
// for an interface return type, would result is a typed nil value for
diff --git a/pkg/optionutils/options.go b/pkg/optionutils/options.go
index 80a29e313e..13f6e6402c 100644
--- a/pkg/optionutils/options.go
+++ b/pkg/optionutils/options.go
@@ -8,12 +8,23 @@ type Option[T any] interface {
ApplyTo(T)
}
+// EvalOptions applies options to a new options object
+// and returns this object.
+// O must be a struct type.
func EvalOptions[O any](opts ...Option[*O]) *O {
var eff O
- for _, opt := range opts {
+ ApplyOptions(&eff, opts...)
+ return &eff
+}
+
+// ApplyOptions applies options to
+// an option target O. O must either
+// be a target interface type or a target struct
+// pointer type.
+func ApplyOptions[O any](opts O, list ...Option[O]) {
+ for _, opt := range list {
if opt != nil {
- opt.ApplyTo(&eff)
+ opt.ApplyTo(opts)
}
}
- return &eff
}
diff --git a/pkg/optionutils/target.go b/pkg/optionutils/target.go
new file mode 100644
index 0000000000..003cc69dae
--- /dev/null
+++ b/pkg/optionutils/target.go
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package optionutils
+
+import (
+ "github.com/open-component-model/ocm/pkg/generics"
+)
+
+/////////////////////////////////////////////////////////////////////////////(//
+// if the option target is an interface, it is easily possible to
+// provide new targets with more options just by extending the
+// target interface. The option consumer the accepts options for
+// the target interface.
+// To be able to reuse options from the base target interface
+// a wrapper option implementation is required which implements
+// the extended option interface and maps it to the base option
+// interface.
+// The following mechanism requires option targets W and B to be
+// interface types.
+
+type targetInterfaceWrapper[B any, W any /*B*/] struct {
+ option Option[B]
+}
+
+func (w *targetInterfaceWrapper[B, W]) ApplyTo(opts W) {
+ w.option.ApplyTo(generics.As[B](opts))
+}
+
+// MapOptionTarget maps the option target interface from
+// B to W, hereby, W must be a subtype of B, which cannot be
+// expressed with Go generics (Type constraint should be W B).
+// If this constraint is not met, there will be a runtime error.
+func MapOptionTarget[W, B any](opt Option[B]) Option[W] {
+ return &targetInterfaceWrapper[B, W]{
+ opt,
+ }
+}
diff --git a/pkg/runtime/descriptivetype/options.go b/pkg/runtime/descriptivetype/options.go
new file mode 100644
index 0000000000..6ed0bd372d
--- /dev/null
+++ b/pkg/runtime/descriptivetype/options.go
@@ -0,0 +1,68 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package descriptivetype
+
+import (
+ "github.com/open-component-model/ocm/pkg/optionutils"
+ "github.com/open-component-model/ocm/pkg/runtime"
+)
+
+////////////////////////////////////////////////////////////////////////////////
+
+// TypeObjectTarget is used as target for option functions, it provides
+// setters for fields, which should not be modifiable for a final type object.
+type TypeObjectTarget[E runtime.VersionedTypedObject] struct {
+ target *TypedObjectTypeObject[E]
+}
+
+func NewTypeObjectTarget[E runtime.VersionedTypedObject](target *TypedObjectTypeObject[E]) *TypeObjectTarget[E] {
+ return &TypeObjectTarget[E]{target}
+}
+
+func (t *TypeObjectTarget[E]) SetDescription(value string) {
+ t.target.description = value
+}
+
+func (t *TypeObjectTarget[E]) SetFormat(value string) {
+ t.target.format = value
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Descriptive Type Options
+
+type OptionTarget interface {
+ SetFormat(string)
+ SetDescription(string)
+}
+
+type Option = optionutils.Option[OptionTarget]
+
+////////////////////////////////////////////////////////////////////////////////
+
+type formatOption struct {
+ value string
+}
+
+func WithFormatSpec(value string) Option {
+ return formatOption{value}
+}
+
+func (o formatOption) ApplyTo(t OptionTarget) {
+ t.SetFormat(o.value)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type descriptionOption struct {
+ value string
+}
+
+func WithDescription(value string) Option {
+ return descriptionOption{value}
+}
+
+func (o descriptionOption) ApplyTo(t OptionTarget) {
+ t.SetDescription(o.value)
+}
diff --git a/pkg/runtime/descriptivetype/type.go b/pkg/runtime/descriptivetype/type.go
new file mode 100644
index 0000000000..ff5e3fb637
--- /dev/null
+++ b/pkg/runtime/descriptivetype/type.go
@@ -0,0 +1,184 @@
+// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Open Component Model contributors.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package descriptivetype
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/open-component-model/ocm/pkg/runtime"
+ "github.com/open-component-model/ocm/pkg/utils"
+)
+
+// DescriptionExtender provides an additional descrition for a type object
+// which is appended to the format description in the schmeme descrition
+// for the type in question.
+type DescriptionExtender[T any] func(t T) string
+
+// TypedObjectType is the appropriately extended type interface
+// based on runtime.VersionTypedObjectType providing support for a functional and
+// format description.
+type TypedObjectType[T runtime.VersionedTypedObject] interface {
+ runtime.VersionedTypedObjectType[T]
+
+ Description() string
+ Format() string
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// TypeScheme is the appropriately extended scheme interface based on
+// runtime.TypeScheme. Based on the additional type info a complete
+// scheme description can be created calling the Describe method.
+type TypeScheme[T runtime.VersionedTypedObject, R TypedObjectType[T]] interface {
+ runtime.TypeScheme[T, R]
+
+ Describe() string
+}
+
+type _typeScheme[T runtime.VersionedTypedObject, R TypedObjectType[T]] interface {
+ runtime.TypeScheme[T, R] // for goland to be able to accept extender argument type
+}
+
+type typeScheme[T runtime.VersionedTypedObject, R TypedObjectType[T], S TypeScheme[T, R]] struct {
+ name string
+ extender DescriptionExtender[R]
+ _typeScheme[T, R]
+}
+
+func MustNewDefaultTypeScheme[T runtime.VersionedTypedObject, R TypedObjectType[T], S TypeScheme[T, R]](name string, extender DescriptionExtender[R], unknown runtime.Unstructured, acceptUnknown bool, defaultdecoder runtime.TypedObjectDecoder[T], base ...TypeScheme[T, R]) TypeScheme[T, R] {
+ scheme := runtime.MustNewDefaultTypeScheme[T, R](unknown, acceptUnknown, defaultdecoder, utils.Optional(base...))
+ return &typeScheme[T, R, S]{
+ name: name,
+ extender: extender,
+ _typeScheme: scheme,
+ }
+}
+
+// NewTypeScheme provides an TypeScheme implementation based on the interfaces
+// and the default runtime.TypeScheme implementation.
+func NewTypeScheme[T runtime.VersionedTypedObject, R TypedObjectType[T], S TypeScheme[T, R]](name string, extender DescriptionExtender[R], unknown runtime.Unstructured, acceptUnknown bool, base ...S) TypeScheme[T, R] {
+ scheme := runtime.MustNewDefaultTypeScheme[T, R](unknown, acceptUnknown, nil, utils.Optional(base...))
+ return &typeScheme[T, R, S]{
+ name: name,
+ extender: extender,
+ _typeScheme: scheme,
+ }
+}
+
+func (t *typeScheme[T, R, S]) KnownTypes() runtime.KnownTypes[T, R] {
+ return t._typeScheme.KnownTypes() // Goland
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+func (t *typeScheme[T, R, S]) Describe() string {
+ s := ""
+ type method struct {
+ desc string
+ versions map[string]string
+ more string
+ }
+
+ descs := map[string]*method{}
+
+ // gather info for kinds and versions
+ for _, n := range t.KnownTypeNames() {
+ kind, vers := runtime.KindVersion(n)
+
+ info := descs[kind]
+ if info == nil {
+ info = &method{versions: map[string]string{}}
+ descs[kind] = info
+ }
+
+ if vers == "" {
+ vers = "v1"
+ }
+ if _, ok := info.versions[vers]; !ok {
+ info.versions[vers] = ""
+ }
+
+ ty := t.GetType(n)
+
+ if t.extender != nil {
+ more := t.extender(ty)
+ if more != "" {
+ info.more = more
+ }
+ }
+ desc := ty.Description()
+ if desc != "" {
+ info.desc = desc
+ }
+
+ desc = ty.Format()
+ if desc != "" {
+ info.versions[vers] = desc
+ }
+ }
+
+ for _, tn := range utils.StringMapKeys(descs) {
+ info := descs[tn]
+ desc := strings.Trim(info.desc, "\n")
+ if desc != "" {
+ s = fmt.Sprintf("%s\n- %s %s
\n\n%s\n\n", s, t.name, tn, utils.IndentLines(desc, " "))
+
+ format := ""
+ for _, f := range utils.StringMapKeys(info.versions) {
+ desc = strings.Trim(info.versions[f], "\n")
+ if desc != "" {
+ format = fmt.Sprintf("%s\n- Version %s
\n\n%s\n", format, f, utils.IndentLines(desc, " "))
+ }
+ }
+ if format != "" {
+ s += fmt.Sprintf(" The following versions are supported:\n%s\n", strings.Trim(utils.IndentLines(format, " "), "\n"))
+ }
+ }
+ s += info.more
+ }
+ return s
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+type descriptiveTypeInfo interface {
+ Description() string
+ Format() string
+}
+
+type TypedObjectTypeObject[T runtime.VersionedTypedObject] struct {
+ runtime.VersionedTypedObjectType[T]
+ description string
+ format string
+ validator func(T) error
+}
+
+var _ descriptiveTypeInfo = (*TypedObjectTypeObject[runtime.VersionedTypedObject])(nil)
+
+func NewTypedObjectTypeObject[E runtime.VersionedTypedObject](vt runtime.VersionedTypedObjectType[E], opts ...Option) *TypedObjectTypeObject[E] {
+ t := NewTypeObjectTarget[E](&TypedObjectTypeObject[E]{
+ VersionedTypedObjectType: vt,
+ })
+ for _, o := range opts {
+ o.ApplyTo(t)
+ }
+ return t.target
+}
+
+func (t *TypedObjectTypeObject[T]) Description() string {
+ return t.description
+}
+
+func (t *TypedObjectTypeObject[T]) Format() string {
+ return t.format
+}
+
+func (t *TypedObjectTypeObject[T]) Validate(e T) error {
+ if t.validator == nil {
+ return nil
+ }
+ return t.validator(e)
+}