diff --git a/charts/console-rapid/charts/controller-0.0.201.tgz b/charts/console-rapid/charts/controller-0.0.201.tgz
index a0b495bf36..57e85f60f7 100644
Binary files a/charts/console-rapid/charts/controller-0.0.201.tgz and b/charts/console-rapid/charts/controller-0.0.201.tgz differ
diff --git a/charts/console/charts/controller-0.0.201.tgz b/charts/console/charts/controller-0.0.201.tgz
index 74d300f23d..0938b3edd8 100644
Binary files a/charts/console/charts/controller-0.0.201.tgz and b/charts/console/charts/controller-0.0.201.tgz differ
diff --git a/charts/controller/crds/deployments.plural.sh_personas.yaml b/charts/controller/crds/deployments.plural.sh_personas.yaml
index b056d1ed59..9b1e246490 100644
--- a/charts/controller/crds/deployments.plural.sh_personas.yaml
+++ b/charts/controller/crds/deployments.plural.sh_personas.yaml
@@ -160,11 +160,6 @@ spec:
Permissions enables the permissions action in the flow header when set to true.
This allows personas to manage flow permissions from the flow detail page.
type: boolean
- startWorkbenchJob:
- description: |-
- StartWorkbenchJob enables the "Start workbench job" action in the flow header when set to true.
- This allows personas to launch workbench jobs directly from the flow detail page.
- type: boolean
pipelines:
description: |-
Pipelines enables access to flow pipeline features when set to true.
@@ -175,6 +170,11 @@ spec:
Previews enables access to flow preview environment features when set to true.
This includes viewing and managing preview environments associated with flows.
type: boolean
+ startWorkbenchJob:
+ description: |-
+ StartWorkbenchJob enables the "Start workbench job" action in the flow header when set to true.
+ This allows personas to launch workbench jobs directly from the flow detail page.
+ type: boolean
workbenches:
description: |-
Workbenches enables access to flow workbench features when set to true.
diff --git a/charts/controller/crds/deployments.plural.sh_workbenchtools.yaml b/charts/controller/crds/deployments.plural.sh_workbenchtools.yaml
index fcaf370701..9163c27e28 100644
--- a/charts/controller/crds/deployments.plural.sh_workbenchtools.yaml
+++ b/charts/controller/crds/deployments.plural.sh_workbenchtools.yaml
@@ -52,6 +52,58 @@ spec:
spec:
description: WorkbenchToolSpec defines the desired state of a WorkbenchTool.
properties:
+ approval:
+ description: Whether this tool requires approval before execution.
+ type: boolean
+ bindings:
+ description: Bindings define the read and write access policies for
+ this tool.
+ properties:
+ read:
+ description: Read bindings.
+ items:
+ description: Binding used to assign permissions to a resource
+ for a user or a group in the system.
+ properties:
+ UserID:
+ type: string
+ groupID:
+ type: string
+ groupName:
+ type: string
+ id:
+ description: |-
+ ID of a binding.
+ Deprecated.
+ Do not use.
+ type: string
+ userEmail:
+ type: string
+ type: object
+ type: array
+ write:
+ description: Write bindings.
+ items:
+ description: Binding used to assign permissions to a resource
+ for a user or a group in the system.
+ properties:
+ UserID:
+ type: string
+ groupID:
+ type: string
+ groupName:
+ type: string
+ id:
+ description: |-
+ ID of a binding.
+ Deprecated.
+ Do not use.
+ type: string
+ userEmail:
+ type: string
+ type: object
+ type: array
+ type: object
categories:
description: Categories for the tool.
items:
@@ -193,6 +245,10 @@ spec:
- key
type: object
x-kubernetes-map-type: atomic
+ prometheusUrl:
+ description: Optional azure managed prometheus url if you
+ wish to use it for metrics.
+ type: string
subscriptionId:
description: Azure subscription id.
type: string
@@ -205,6 +261,138 @@ spec:
- subscriptionId
- tenantId
type: object
+ azureDevops:
+ description: Azure DevOps connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the Azure
+ DevOps personal access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional REST API root (defaults to https://dev.azure.com).
+ type: string
+ type: object
+ azureFunction:
+ description: Azure Function / Cloud Function configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ identifier:
+ description: Cloud Function identifier.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - description
+ - identifier
+ type: object
+ bitbucket:
+ description: Bitbucket Cloud connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the Bitbucket
+ app password or access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional Bitbucket Cloud API base URL.
+ type: string
+ type: object
+ bitbucketDatacenter:
+ description: Bitbucket Data Center connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the HTTP
+ access token or personal access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Bitbucket Data Center REST API base URL.
+ type: string
+ required:
+ - url
+ type: object
+ cloudRun:
+ description: Google Cloud Run service configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ identifier:
+ description: Cloud Run service identifier.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - description
+ - identifier
+ type: object
cloudwatch:
description: Cloudwatch connection (metrics, logs).
properties:
@@ -336,6 +524,330 @@ spec:
description: Datadog site (e.g. datadoghq.com).
type: string
type: object
+ docker:
+ description: Docker/OCI registry connection.
+ properties:
+ auth:
+ description: Registry authentication credentials and optional
+ proxy.
+ properties:
+ aws:
+ description: |-
+ Aws specifies AWS-specific authentication for Amazon ECR and other AWS-hosted repositories.
+ Supports both static credentials and IAM role-based authentication for secure access
+ to private repositories hosted in Amazon Web Services.
+ properties:
+ accessKey:
+ description: |-
+ AccessKey specifies the AWS access key ID for authentication.
+ When using static credentials, this should be set along with the secret access key.
+ For enhanced security, consider using IAM roles instead of static credentials.
+ type: string
+ assumeRoleArn:
+ description: |-
+ AssumeRoleArn specifies an AWS IAM role ARN to assume for repository access.
+ This enables cross-account access and role-based authentication, providing
+ enhanced security and flexibility in AWS environments.
+ type: string
+ secretAccessKeySecretKeyRef:
+ description: |-
+ SecretAccessKeySecretKeyRef references a specific key within a Kubernetes Secret containing the secret access key.
+ This is the preferred method for storing AWS credentials as it allows multiple
+ credential sets to be organized within a single secret.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secretAccessKeySecretRef:
+ description: |-
+ SecretAccessKeySecretRef references a Kubernetes Secret containing the AWS secret access key.
+ The entire secret content will be used as the secret access key.
+ This approach is deprecated in favor of SecretAccessKeySecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ azure:
+ description: |-
+ Azure specifies Azure-specific authentication for Azure Container Registry (ACR).
+ Supports service principal authentication and managed identity for secure access
+ to private repositories hosted in Microsoft Azure.
+ properties:
+ clientId:
+ description: |-
+ ClientID specifies the Azure service principal client ID.
+ This is used in conjunction with the client secret to authenticate with Azure services.
+ type: string
+ clientSecretSecretKeyRef:
+ description: |-
+ ClientSecretSecretKeyRef references a specific key within a Kubernetes Secret containing the client secret.
+ This is the preferred method for storing Azure credentials as it allows proper
+ secret organization and key-based access control.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ clientSecretSecretRef:
+ description: |-
+ ClientSecretSecretRef references a Kubernetes Secret containing the Azure service principal client secret.
+ The entire secret content will be used as the client secret.
+ This approach is deprecated in favor of ClientSecretSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ subscriptionId:
+ description: |-
+ SubscriptionID specifies the Azure subscription ID.
+ This identifies the Azure subscription containing the resources
+ and may be required for certain repository access scenarios.
+ type: string
+ tenantId:
+ description: |-
+ TenantID specifies the Azure Active Directory tenant ID.
+ This identifies the Azure AD instance that contains the service principal
+ and is required for proper authentication scope.
+ type: string
+ type: object
+ basic:
+ description: |-
+ Basic specifies username/password authentication for repositories that support HTTP Basic Auth.
+ Commonly used with private Helm repositories, Harbor registries, and other traditional
+ repository managers that implement standard HTTP authentication.
+ properties:
+ passwordSecretKeyRef:
+ description: |-
+ PasswordSecretKeyRef references a specific key within a Kubernetes Secret that contains the password.
+ This is the preferred method for password storage as it allows multiple credentials
+ to be stored in a single secret with proper key-based access.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ passwordSecretRef:
+ description: |-
+ PasswordSecretRef references a Kubernetes Secret containing the password for Basic authentication.
+ The entire secret content will be used as the password.
+ This approach is deprecated in favor of PasswordSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: |-
+ Username specifies the username for HTTP Basic authentication.
+ This is typically a user account or service account name configured
+ in the target repository system.
+ type: string
+ required:
+ - username
+ type: object
+ bearer:
+ description: |-
+ Bearer specifies token-based authentication for repositories that support Bearer tokens.
+ Used with modern container registries and repositories that implement OAuth2 or similar
+ token-based authentication schemes.
+ properties:
+ tokenSecretKeyRef:
+ description: |-
+ TokenSecretKeyRef references a specific key within a Kubernetes Secret that contains the bearer token.
+ This is the preferred method for token storage as it allows multiple tokens
+ to be stored in a single secret with proper key-based access.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tokenSecretRef:
+ description: |-
+ TokenSecretRef references a Kubernetes Secret containing the bearer token.
+ The entire secret content will be used as the authentication token.
+ This approach is deprecated in favor of TokenSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ gcp:
+ description: |-
+ Gcp specifies Google Cloud-specific authentication for Google Artifact Registry.
+ Supports service account key authentication for secure access to private
+ repositories hosted in Google Cloud Platform.
+ properties:
+ applicationCredentialsSecretKeyRef:
+ description: |-
+ ApplicationCredentialsSecretKeyRef references a specific key within a Kubernetes Secret containing the service account JSON.
+ This is the preferred method for storing GCP credentials as it allows multiple
+ service account keys to be organized within a single secret with proper access control.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ applicationCredentialsSecretRef:
+ description: |-
+ ApplicationCredentialsSecretRef references a Kubernetes Secret containing the GCP service account key JSON.
+ The entire secret content will be used as the service account credentials.
+ This approach is deprecated in favor of ApplicationCredentialsSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ proxy:
+ description: Proxy configures an HTTP proxy for requests
+ to this Helm repository or OCI registry.
+ properties:
+ noproxy:
+ description: The comma-separated list of hosts that
+ should not be proxied, will behave equivalently
+ to a NOPROXY env var.
+ type: string
+ url:
+ description: The url of your HTTP proxy.
+ type: string
+ required:
+ - url
+ type: object
+ type: object
+ provider:
+ description: 'Registry authentication provider: BASIC, BEARER,
+ AWS, AZURE, or GCP.'
+ enum:
+ - BASIC
+ - BEARER
+ - GCP
+ - AZURE
+ - AWS
+ type: string
+ url:
+ description: Registry host or base URL (defaults to registry-1.docker.io).
+ type: string
+ type: object
dynatrace:
description: Dynatrace connection (metrics, logs, traces).
properties:
@@ -413,12 +925,149 @@ spec:
- url
- username
type: object
+ exa:
+ description: Exa connection (search).
+ properties:
+ apiKeySecretRef:
+ description: Reference to a secret key containing the exa
+ API key.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ github:
+ description: GitHub connection (integration).
+ properties:
+ accessTokenSecretRef:
+ description: Reference to a secret key containing an optional
+ GitHub personal access token or fine-grained token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ appId:
+ description: GitHub App ID (use with installationId and privateKey
+ instead of accessToken).
+ type: string
+ installationId:
+ description: GitHub App installation ID for this organization
+ or account.
+ type: string
+ privateKeySecretRef:
+ description: Reference to a secret key containing the PEM
+ private key for the GitHub App.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ toolset:
+ description: 'Optional native tool subset: issues, pull_requests,
+ repos, security, default/all, or omit for all tools.'
+ type: string
+ url:
+ description: Optional GitHub REST API base URL (defaults to
+ https://api.github.com/; set for GitHub Enterprise Server).
+ type: string
+ type: object
+ gitlab:
+ description: GitLab connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the GitLab
+ personal access token or project/group token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional GitLab API base URL (defaults to https://gitlab.com
+ when omitted).
+ type: string
+ type: object
http:
description: Http tool configuration.
properties:
body:
description: Request body.
type: string
+ function:
+ description: When true, exposes this HTTP tool as a workbench
+ action; execution may require approval when tool approval
+ is enabled.
+ type: boolean
headers:
description: Request headers.
items:
@@ -515,6 +1164,23 @@ spec:
required:
- url
type: object
+ lambda:
+ description: AWS Lambda function configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ lambdaArn:
+ description: AWS Lambda function ARN.
+ type: string
+ required:
+ - description
+ - lambdaArn
+ type: object
linear:
description: Linear connection (ticketing).
properties:
@@ -609,9 +1275,168 @@ spec:
required:
- url
type: object
+ opensearch:
+ description: AWS OpenSearch connection (logs).
+ properties:
+ assumeRoleArn:
+ description: Optional IAM role ARN to assume before signing
+ OpenSearch requests.
+ type: string
+ awsAccessKeyIdSecretRef:
+ description: Reference to a secret key containing the AWS
+ access key id for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsRegion:
+ description: AWS region for SigV4 authentication.
+ type: string
+ awsSecretAccessKeySecretRef:
+ description: Reference to a secret key containing the AWS
+ secret access key for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ host:
+ description: AWS OpenSearch endpoint.
+ type: string
+ index:
+ description: OpenSearch index.
+ type: string
+ usePodIdentity:
+ description: Whether to use pod identity (IRSA/Workload Identity)
+ for AWS authentication instead of static credentials.
+ type: boolean
+ required:
+ - host
+ - index
+ type: object
+ pagerduty:
+ description: PagerDuty connection (integration).
+ properties:
+ apiTokenSecretRef:
+ description: Reference to a secret key containing the pagerduty
+ REST API key.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
prometheus:
description: Prometheus connection (metrics).
properties:
+ awsAccessKeyIdSecretRef:
+ description: Reference to a secret key containing the AWS
+ access key id for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsRegion:
+ description: AWS region for SigV4 authentication.
+ type: string
+ awsSecretAccessKeySecretRef:
+ description: Reference to a secret key containing the AWS
+ secret access key for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsSigv4:
+ description: Whether to sign requests with AWS SigV4.
+ type: boolean
passwordSecretRef:
description: Reference to a secret key containing the basic
auth password.
@@ -674,6 +1499,68 @@ spec:
required:
- url
type: object
+ sentry:
+ description: Sentry connection (error tracking).
+ properties:
+ accessTokenSecretRef:
+ description: Reference to a secret key containing the Sentry
+ user auth token or internal integration token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional Sentry API host (defaults to https://sentry.io;
+ set for self-hosted).
+ type: string
+ type: object
+ slack:
+ description: Slack connection (integration).
+ properties:
+ botTokenSecretRef:
+ description: Reference to a secret key containing the slack
+ bot user OAuth token (xoxb-...).
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
splunk:
description: Splunk connection (logs).
properties:
@@ -736,6 +1623,45 @@ spec:
required:
- url
type: object
+ teams:
+ description: Microsoft Teams / Graph connection (integration).
+ properties:
+ clientId:
+ description: Microsoft Entra application (client) id.
+ type: string
+ clientSecretSecretRef:
+ description: Reference to a secret key containing the microsoft
+ entra client secret.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tenantId:
+ description: Microsoft Entra tenant (directory) id.
+ type: string
+ required:
+ - clientId
+ - clientSecretSecretRef
+ - tenantId
+ type: object
tempo:
description: Tempo connection (traces).
properties:
@@ -914,6 +1840,50 @@ spec:
example: 5m30s
type: string
type: object
+ scmConnectionRef:
+ description: The SCM connection for this tool (e.g. shared Git provider
+ credentials).
+ properties:
+ apiVersion:
+ description: API version of the referent.
+ type: string
+ fieldPath:
+ description: |-
+ If referring to a piece of an object instead of an entire object, this string
+ should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
+ For example, if the object reference is to a container within a pod, this would take on a value like:
+ "spec.containers{name}" (where "name" refers to the name of the container that triggered
+ the event) or if no container name is specified "spec.containers[2]" (container with
+ index 2 in this pod). This syntax is chosen only to have some well-defined way of
+ referencing a part of an object.
+ type: string
+ kind:
+ description: |-
+ Kind of the referent.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ name:
+ description: |-
+ Name of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ namespace:
+ description: |-
+ Namespace of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
+ type: string
+ resourceVersion:
+ description: |-
+ Specific resourceVersion to which this reference is made, if any.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+ type: string
+ uid:
+ description: |-
+ UID of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
tool:
description: The type of tool.
enum:
@@ -933,6 +1903,20 @@ spec:
- AZURE
- CLOUD
- JAEGER
+ - EXA
+ - GITHUB
+ - SLACK
+ - TEAMS
+ - GITLAB
+ - BITBUCKET
+ - BITBUCKET_DATACENTER
+ - AZURE_DEVOPS
+ - PAGERDUTY
+ - OPENSEARCH
+ - LAMBDA
+ - CLOUD_RUN
+ - AZURE_FUNCTION
+ - DOCKER
type: string
required:
- tool
diff --git a/go/controller/api/v1alpha1/workbenchtool_types.go b/go/controller/api/v1alpha1/workbenchtool_types.go
index 598b7ba413..5e799c438f 100644
--- a/go/controller/api/v1alpha1/workbenchtool_types.go
+++ b/go/controller/api/v1alpha1/workbenchtool_types.go
@@ -80,9 +80,10 @@ func (in *WorkbenchTool) ConsoleName() string {
return in.Name
}
-// Diff compares the current WorkbenchTool spec with its last known state.
-func (in *WorkbenchTool) Diff(hasher Hasher) (changed bool, sha string, err error) {
- currentSha, err := hasher(in.Spec)
+// Diff compares the resolved WorkbenchTool attributes with their last known state.
+// Attributes include secret values, so credential rotation is detected.
+func (in *WorkbenchTool) Diff(attrs console.WorkbenchToolAttributes, hasher Hasher) (changed bool, sha string, err error) {
+ currentSha, err := hasher(attrs)
if err != nil {
return false, "", err
}
@@ -94,7 +95,7 @@ func (in *WorkbenchTool) SetCondition(condition metav1.Condition) {
meta.SetStatusCondition(&in.Status.Conditions, condition)
}
-func (in *WorkbenchTool) Attributes(ctx context.Context, c client.Client, projectID, mcpServerID, cloudConnectionID *string) (console.WorkbenchToolAttributes, error) {
+func (in *WorkbenchTool) Attributes(ctx context.Context, c client.Client, projectID, mcpServerID, cloudConnectionID, scmConnectionID *string, readBindings, writeBindings []*console.PolicyBindingAttributes) (console.WorkbenchToolAttributes, error) {
configuration, err := in.Spec.Configuration.Attributes(ctx, c, in.Namespace)
if err != nil {
return console.WorkbenchToolAttributes{}, err
@@ -107,6 +108,10 @@ func (in *WorkbenchTool) Attributes(ctx context.Context, c client.Client, projec
ProjectID: projectID,
McpServerID: mcpServerID,
CloudConnectionID: cloudConnectionID,
+ ScmConnectionID: scmConnectionID,
+ Approval: in.Spec.Approval,
+ ReadBindings: readBindings,
+ WriteBindings: writeBindings,
Configuration: configuration,
}, nil
}
@@ -121,13 +126,17 @@ type WorkbenchToolSpec struct {
// The type of tool.
// +kubebuilder:validation:Required
- // +kubebuilder:validation:Enum:=HTTP;ELASTIC;DATADOG;PROMETHEUS;LOKI;TEMPO;SENTRY;MCP;LINEAR;ATLASSIAN;SPLUNK;DYNATRACE;CLOUDWATCH;AZURE;CLOUD;JAEGER
+ // +kubebuilder:validation:Enum:=HTTP;ELASTIC;DATADOG;PROMETHEUS;LOKI;TEMPO;SENTRY;MCP;LINEAR;ATLASSIAN;SPLUNK;DYNATRACE;CLOUDWATCH;AZURE;CLOUD;JAEGER;EXA;GITHUB;SLACK;TEAMS;GITLAB;BITBUCKET;BITBUCKET_DATACENTER;AZURE_DEVOPS;PAGERDUTY;OPENSEARCH;LAMBDA;CLOUD_RUN;AZURE_FUNCTION;DOCKER
Tool console.WorkbenchToolType `json:"tool"`
// Categories for the tool.
// +kubebuilder:validation:Optional
Categories []console.WorkbenchToolCategory `json:"categories,omitempty"`
+ // Whether this tool requires approval before execution.
+ // +kubebuilder:validation:Optional
+ Approval *bool `json:"approval,omitempty"`
+
// The project for this tool.
// +kubebuilder:validation:Optional
ProjectRef *corev1.ObjectReference `json:"projectRef,omitempty"`
@@ -140,6 +149,14 @@ type WorkbenchToolSpec struct {
// +kubebuilder:validation:Optional
CloudConnectionRef *corev1.ObjectReference `json:"cloudConnectionRef,omitempty"`
+ // The SCM connection for this tool (e.g. shared Git provider credentials).
+ // +kubebuilder:validation:Optional
+ ScmConnectionRef *corev1.ObjectReference `json:"scmConnectionRef,omitempty"`
+
+ // Bindings define the read and write access policies for this tool.
+ // +kubebuilder:validation:Optional
+ Bindings *Bindings `json:"bindings,omitempty"`
+
// Tool configuration (e.g. HTTP).
// +kubebuilder:validation:Optional
Configuration *WorkbenchToolConfiguration `json:"configuration,omitempty"`
@@ -158,6 +175,10 @@ type WorkbenchToolConfiguration struct {
// +kubebuilder:validation:Optional
Elastic *WorkbenchToolElasticConfig `json:"elastic,omitempty"`
+ // AWS OpenSearch connection (logs).
+ // +kubebuilder:validation:Optional
+ Opensearch *WorkbenchToolOpensearchConfig `json:"opensearch,omitempty"`
+
// Prometheus connection (metrics).
// +kubebuilder:validation:Optional
Prometheus *WorkbenchToolPrometheusConfig `json:"prometheus,omitempty"`
@@ -194,13 +215,69 @@ type WorkbenchToolConfiguration struct {
// +kubebuilder:validation:Optional
Azure *WorkbenchToolAzureConfig `json:"azure,omitempty"`
+ // Sentry connection (error tracking).
+ // +kubebuilder:validation:Optional
+ Sentry *WorkbenchToolSentryConfig `json:"sentry,omitempty"`
+
// Linear connection (ticketing).
// +kubebuilder:validation:Optional
Linear *WorkbenchToolLinearConfig `json:"linear,omitempty"`
+ // Slack connection (integration).
+ // +kubebuilder:validation:Optional
+ Slack *WorkbenchToolSlackConfig `json:"slack,omitempty"`
+
+ // PagerDuty connection (integration).
+ // +kubebuilder:validation:Optional
+ Pagerduty *WorkbenchToolPagerdutyConfig `json:"pagerduty,omitempty"`
+
+ // Microsoft Teams / Graph connection (integration).
+ // +kubebuilder:validation:Optional
+ Teams *WorkbenchToolTeamsConfig `json:"teams,omitempty"`
+
// Atlassian/jira connection (ticketing).
// +kubebuilder:validation:Optional
Atlassian *WorkbenchToolAtlassianConfig `json:"atlassian,omitempty"`
+
+ // Exa connection (search).
+ // +kubebuilder:validation:Optional
+ Exa *WorkbenchToolExaConfig `json:"exa,omitempty"`
+
+ // GitHub connection (integration).
+ // +kubebuilder:validation:Optional
+ Github *WorkbenchToolGithubConfig `json:"github,omitempty"`
+
+ // GitLab connection (scm).
+ // +kubebuilder:validation:Optional
+ Gitlab *WorkbenchToolGitlabConfig `json:"gitlab,omitempty"`
+
+ // Bitbucket Cloud connection (scm).
+ // +kubebuilder:validation:Optional
+ Bitbucket *WorkbenchToolBitbucketConfig `json:"bitbucket,omitempty"`
+
+ // Bitbucket Data Center connection (scm).
+ // +kubebuilder:validation:Optional
+ BitbucketDatacenter *WorkbenchToolBitbucketDatacenterConfig `json:"bitbucketDatacenter,omitempty"`
+
+ // Azure DevOps connection (scm).
+ // +kubebuilder:validation:Optional
+ AzureDevops *WorkbenchToolAzureDevopsConfig `json:"azureDevops,omitempty"`
+
+ // AWS Lambda function configuration.
+ // +kubebuilder:validation:Optional
+ Lambda *WorkbenchToolLambdaConfig `json:"lambda,omitempty"`
+
+ // Google Cloud Run service configuration.
+ // +kubebuilder:validation:Optional
+ CloudRun *WorkbenchToolCloudRunConfig `json:"cloudRun,omitempty"`
+
+ // Azure Function / Cloud Function configuration.
+ // +kubebuilder:validation:Optional
+ AzureFunction *WorkbenchToolAzureFunctionConfig `json:"azureFunction,omitempty"`
+
+ // Docker/OCI registry connection.
+ // +kubebuilder:validation:Optional
+ Docker *WorkbenchToolDockerConfig `json:"docker,omitempty"`
}
func (c *WorkbenchToolConfiguration) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolConfigurationAttributes, error) {
@@ -213,6 +290,11 @@ func (c *WorkbenchToolConfiguration) Attributes(ctx context.Context, cl client.C
return nil, err
}
+ opensearch, err := c.Opensearch.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
prometheus, err := c.Prometheus.Attributes(ctx, cl, namespace)
if err != nil {
return nil, err
@@ -258,30 +340,95 @@ func (c *WorkbenchToolConfiguration) Attributes(ctx context.Context, cl client.C
return nil, err
}
+ sentry, err := c.Sentry.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
linear, err := c.Linear.Attributes(ctx, cl, namespace)
if err != nil {
return nil, err
}
+ slack, err := c.Slack.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ pagerduty, err := c.Pagerduty.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ teams, err := c.Teams.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
atlassian, err := c.Atlassian.Attributes(ctx, cl, namespace)
if err != nil {
return nil, err
}
+ exa, err := c.Exa.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ github, err := c.Github.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ gitlab, err := c.Gitlab.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ bitbucket, err := c.Bitbucket.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ bitbucketDatacenter, err := c.BitbucketDatacenter.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ azureDevops, err := c.AzureDevops.Attributes(ctx, cl, namespace)
+ if err != nil {
+ return nil, err
+ }
+
return &console.WorkbenchToolConfigurationAttributes{
- HTTP: c.HTTP.Attributes(),
- Elastic: elastic,
- Prometheus: prometheus,
- Loki: loki,
- Tempo: tempo,
- Jaeger: jaeger,
- Splunk: splunk,
- Datadog: datadog,
- Dynatrace: dynatrace,
- Cloudwatch: cloudwatch,
- Azure: azure,
- Linear: linear,
- Atlassian: atlassian,
+ HTTP: c.HTTP.Attributes(),
+ Elastic: elastic,
+ Opensearch: opensearch,
+ Prometheus: prometheus,
+ Loki: loki,
+ Tempo: tempo,
+ Jaeger: jaeger,
+ Splunk: splunk,
+ Datadog: datadog,
+ Dynatrace: dynatrace,
+ Cloudwatch: cloudwatch,
+ Azure: azure,
+ Sentry: sentry,
+ Linear: linear,
+ Slack: slack,
+ Pagerduty: pagerduty,
+ Teams: teams,
+ Atlassian: atlassian,
+ Exa: exa,
+ Github: github,
+ Gitlab: gitlab,
+ Bitbucket: bitbucket,
+ BitbucketDatacenter: bitbucketDatacenter,
+ AzureDevops: azureDevops,
+ Lambda: c.Lambda.Attributes(),
+ CloudRun: c.CloudRun.Attributes(),
+ AzureFunction: c.AzureFunction.Attributes(),
+ Docker: c.Docker.Attributes(),
}, nil
}
@@ -298,6 +445,10 @@ type WorkbenchToolHTTPConfig struct {
// +kubebuilder:validation:Enum:=GET;POST;PUT;DELETE;PATCH
Method console.WorkbenchToolHTTPMethod `json:"method"`
+ // When true, exposes this HTTP tool as a workbench action; execution may require approval when tool approval is enabled.
+ // +kubebuilder:validation:Optional
+ Function *bool `json:"function,omitempty"`
+
// Request headers.
// +kubebuilder:validation:Optional
Headers []WorkbenchToolHTTPHeader `json:"headers,omitempty"`
@@ -318,8 +469,9 @@ func (c *WorkbenchToolHTTPConfig) Attributes() *console.WorkbenchToolHTTPConfigu
}
return &console.WorkbenchToolHTTPConfigurationAttributes{
- URL: c.URL,
- Method: c.Method,
+ URL: c.URL,
+ Method: c.Method,
+ Function: c.Function,
Headers: lo.Map(c.Headers, func(header WorkbenchToolHTTPHeader, _ int) *console.WorkbenchToolHTTPHeaderAttributes {
return &console.WorkbenchToolHTTPHeaderAttributes{
Name: header.Name,
@@ -383,6 +535,69 @@ func (c *WorkbenchToolElasticConfig) Attributes(ctx context.Context, cl client.C
return attr, nil
}
+// WorkbenchToolOpensearchConfig defines an AWS OpenSearch connection.
+type WorkbenchToolOpensearchConfig struct {
+ // AWS OpenSearch endpoint.
+ // +kubebuilder:validation:Required
+ Host string `json:"host"`
+
+ // OpenSearch index.
+ // +kubebuilder:validation:Required
+ Index string `json:"index"`
+
+ // Reference to a secret key containing the AWS access key id for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSAccessKeyIDSecretRef *corev1.SecretKeySelector `json:"awsAccessKeyIdSecretRef,omitempty"`
+
+ // Reference to a secret key containing the AWS secret access key for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSSecretAccessKeySecretRef *corev1.SecretKeySelector `json:"awsSecretAccessKeySecretRef,omitempty"`
+
+ // AWS region for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSRegion *string `json:"awsRegion,omitempty"`
+
+ // Optional IAM role ARN to assume before signing OpenSearch requests.
+ // +kubebuilder:validation:Optional
+ AssumeRoleArn *string `json:"assumeRoleArn,omitempty"`
+
+ // Whether to use pod identity (IRSA/Workload Identity) for AWS authentication instead of static credentials.
+ // +kubebuilder:validation:Optional
+ UsePodIdentity *bool `json:"usePodIdentity,omitempty"`
+}
+
+func (c *WorkbenchToolOpensearchConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolOpensearchConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolOpensearchConnectionAttributes{
+ Host: c.Host,
+ Index: c.Index,
+ AWSRegion: c.AWSRegion,
+ AssumeRoleArn: c.AssumeRoleArn,
+ UsePodIdentity: c.UsePodIdentity,
+ }
+
+ if c.AWSAccessKeyIDSecretRef != nil {
+ accessKeyID, err := utils.GetSecretKey(ctx, cl, c.AWSAccessKeyIDSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AWSAccessKeyID = lo.ToPtr(accessKeyID)
+ }
+
+ if c.AWSSecretAccessKeySecretRef != nil {
+ secretAccessKey, err := utils.GetSecretKey(ctx, cl, c.AWSSecretAccessKeySecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AWSSecretAccessKey = lo.ToPtr(secretAccessKey)
+ }
+
+ return attr, nil
+}
+
// WorkbenchToolPrometheusConfig defines a prometheus connection.
type WorkbenchToolPrometheusConfig struct {
// Prometheus base URL.
@@ -404,6 +619,22 @@ type WorkbenchToolPrometheusConfig struct {
// Optional tenant id (e.g. for Mimir).
// +kubebuilder:validation:Optional
TenantID *string `json:"tenantId,omitempty"`
+
+ // Whether to sign requests with AWS SigV4.
+ // +kubebuilder:validation:Optional
+ AWSSigv4 *bool `json:"awsSigv4,omitempty"`
+
+ // Reference to a secret key containing the AWS access key id for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSAccessKeyIDSecretRef *corev1.SecretKeySelector `json:"awsAccessKeyIdSecretRef,omitempty"`
+
+ // Reference to a secret key containing the AWS secret access key for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSSecretAccessKeySecretRef *corev1.SecretKeySelector `json:"awsSecretAccessKeySecretRef,omitempty"`
+
+ // AWS region for SigV4 authentication.
+ // +kubebuilder:validation:Optional
+ AWSRegion *string `json:"awsRegion,omitempty"`
}
func (c *WorkbenchToolPrometheusConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolPrometheusConnectionAttributes, error) {
@@ -412,9 +643,11 @@ func (c *WorkbenchToolPrometheusConfig) Attributes(ctx context.Context, cl clien
}
attr := &console.WorkbenchToolPrometheusConnectionAttributes{
- URL: c.URL,
- Username: c.Username,
- TenantID: c.TenantID,
+ URL: c.URL,
+ Username: c.Username,
+ TenantID: c.TenantID,
+ AWSSigv4: c.AWSSigv4,
+ AWSRegion: c.AWSRegion,
}
if c.TokenSecretRef != nil {
@@ -433,6 +666,22 @@ func (c *WorkbenchToolPrometheusConfig) Attributes(ctx context.Context, cl clien
attr.Password = lo.ToPtr(password)
}
+ if c.AWSAccessKeyIDSecretRef != nil {
+ accessKeyID, err := utils.GetSecretKey(ctx, cl, c.AWSAccessKeyIDSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AWSAccessKeyID = lo.ToPtr(accessKeyID)
+ }
+
+ if c.AWSSecretAccessKeySecretRef != nil {
+ secretAccessKey, err := utils.GetSecretKey(ctx, cl, c.AWSSecretAccessKeySecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AWSSecretAccessKey = lo.ToPtr(secretAccessKey)
+ }
+
return attr, nil
}
@@ -788,6 +1037,10 @@ type WorkbenchToolAzureConfig struct {
// Reference to a secret key containing the azure client secret.
// +kubebuilder:validation:Required
ClientSecretSecretRef corev1.SecretKeySelector `json:"clientSecretSecretRef"`
+
+ // Optional azure managed prometheus url if you wish to use it for metrics.
+ // +kubebuilder:validation:Optional
+ PrometheusURL *string `json:"prometheusUrl,omitempty"`
}
func (c *WorkbenchToolAzureConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolAzureConnectionAttributes, error) {
@@ -805,6 +1058,7 @@ func (c *WorkbenchToolAzureConfig) Attributes(ctx context.Context, cl client.Cli
TenantID: c.TenantID,
ClientID: c.ClientID,
ClientSecret: clientSecret,
+ PrometheusURL: c.PrometheusURL,
}, nil
}
@@ -875,3 +1129,441 @@ func (c *WorkbenchToolAtlassianConfig) Attributes(ctx context.Context, cl client
return attr, nil
}
+
+// WorkbenchToolSentryConfig defines a sentry connection.
+type WorkbenchToolSentryConfig struct {
+ // Optional Sentry API host (defaults to https://sentry.io; set for self-hosted).
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Reference to a secret key containing the Sentry user auth token or internal integration token.
+ // +kubebuilder:validation:Optional
+ AccessTokenSecretRef *corev1.SecretKeySelector `json:"accessTokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolSentryConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolSentryConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolSentryConnectionAttributes{
+ URL: c.URL,
+ }
+
+ if c.AccessTokenSecretRef != nil {
+ accessToken, err := utils.GetSecretKey(ctx, cl, c.AccessTokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AccessToken = lo.ToPtr(accessToken)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolSlackConfig defines a slack connection.
+type WorkbenchToolSlackConfig struct {
+ // Reference to a secret key containing the slack bot user OAuth token (xoxb-...).
+ // +kubebuilder:validation:Optional
+ BotTokenSecretRef *corev1.SecretKeySelector `json:"botTokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolSlackConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolSlackConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolSlackConnectionAttributes{}
+
+ if c.BotTokenSecretRef != nil {
+ botToken, err := utils.GetSecretKey(ctx, cl, c.BotTokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.BotToken = lo.ToPtr(botToken)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolPagerdutyConfig defines a pagerduty connection.
+type WorkbenchToolPagerdutyConfig struct {
+ // Reference to a secret key containing the pagerduty REST API key.
+ // +kubebuilder:validation:Optional
+ APITokenSecretRef *corev1.SecretKeySelector `json:"apiTokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolPagerdutyConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolPagerdutyConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolPagerdutyConnectionAttributes{}
+
+ if c.APITokenSecretRef != nil {
+ apiToken, err := utils.GetSecretKey(ctx, cl, c.APITokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.APIToken = lo.ToPtr(apiToken)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolTeamsConfig defines a microsoft teams / graph connection.
+type WorkbenchToolTeamsConfig struct {
+ // Microsoft Entra application (client) id.
+ // +kubebuilder:validation:Required
+ ClientID string `json:"clientId"`
+
+ // Reference to a secret key containing the microsoft entra client secret.
+ // +kubebuilder:validation:Required
+ ClientSecretSecretRef corev1.SecretKeySelector `json:"clientSecretSecretRef"`
+
+ // Microsoft Entra tenant (directory) id.
+ // +kubebuilder:validation:Required
+ TenantID string `json:"tenantId"`
+}
+
+func (c *WorkbenchToolTeamsConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolTeamsConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ clientSecret, err := utils.GetSecretKey(ctx, cl, &c.ClientSecretSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ return &console.WorkbenchToolTeamsConnectionAttributes{
+ ClientID: c.ClientID,
+ ClientSecret: clientSecret,
+ TenantID: c.TenantID,
+ }, nil
+}
+
+// WorkbenchToolExaConfig defines an exa connection.
+type WorkbenchToolExaConfig struct {
+ // Reference to a secret key containing the exa API key.
+ // +kubebuilder:validation:Optional
+ APIKeySecretRef *corev1.SecretKeySelector `json:"apiKeySecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolExaConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolExaConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolExaConnectionAttributes{}
+
+ if c.APIKeySecretRef != nil {
+ apiKey, err := utils.GetSecretKey(ctx, cl, c.APIKeySecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.APIKey = lo.ToPtr(apiKey)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolGithubConfig defines a github connection.
+type WorkbenchToolGithubConfig struct {
+ // Optional GitHub REST API base URL (defaults to https://api.github.com/; set for GitHub Enterprise Server).
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Reference to a secret key containing an optional GitHub personal access token or fine-grained token.
+ // +kubebuilder:validation:Optional
+ AccessTokenSecretRef *corev1.SecretKeySelector `json:"accessTokenSecretRef,omitempty"`
+
+ // Optional native tool subset: issues, pull_requests, repos, security, default/all, or omit for all tools.
+ // +kubebuilder:validation:Optional
+ Toolset *string `json:"toolset,omitempty"`
+
+ // GitHub App ID (use with installationId and privateKey instead of accessToken).
+ // +kubebuilder:validation:Optional
+ AppID *string `json:"appId,omitempty"`
+
+ // GitHub App installation ID for this organization or account.
+ // +kubebuilder:validation:Optional
+ InstallationID *string `json:"installationId,omitempty"`
+
+ // Reference to a secret key containing the PEM private key for the GitHub App.
+ // +kubebuilder:validation:Optional
+ PrivateKeySecretRef *corev1.SecretKeySelector `json:"privateKeySecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolGithubConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolGithubConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolGithubConnectionAttributes{
+ URL: c.URL,
+ Toolset: c.Toolset,
+ AppID: c.AppID,
+ InstallationID: c.InstallationID,
+ }
+
+ if c.AccessTokenSecretRef != nil {
+ accessToken, err := utils.GetSecretKey(ctx, cl, c.AccessTokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.AccessToken = lo.ToPtr(accessToken)
+ }
+
+ if c.PrivateKeySecretRef != nil {
+ privateKey, err := utils.GetSecretKey(ctx, cl, c.PrivateKeySecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.PrivateKey = lo.ToPtr(privateKey)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolGitlabConfig defines a gitlab connection.
+type WorkbenchToolGitlabConfig struct {
+ // Optional GitLab API base URL (defaults to https://gitlab.com when omitted).
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Reference to a secret key containing the GitLab personal access token or project/group token.
+ // +kubebuilder:validation:Optional
+ TokenSecretRef *corev1.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolGitlabConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolGitlabConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolGitlabConnectionAttributes{
+ URL: c.URL,
+ }
+
+ if c.TokenSecretRef != nil {
+ token, err := utils.GetSecretKey(ctx, cl, c.TokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.Token = lo.ToPtr(token)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolBitbucketConfig defines a bitbucket cloud connection.
+type WorkbenchToolBitbucketConfig struct {
+ // Optional Bitbucket Cloud API base URL.
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Reference to a secret key containing the Bitbucket app password or access token.
+ // +kubebuilder:validation:Optional
+ TokenSecretRef *corev1.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolBitbucketConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolBitbucketConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolBitbucketConnectionAttributes{
+ URL: c.URL,
+ }
+
+ if c.TokenSecretRef != nil {
+ token, err := utils.GetSecretKey(ctx, cl, c.TokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.Token = lo.ToPtr(token)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolBitbucketDatacenterConfig defines a bitbucket data center connection.
+type WorkbenchToolBitbucketDatacenterConfig struct {
+ // Bitbucket Data Center REST API base URL.
+ // +kubebuilder:validation:Required
+ URL string `json:"url"`
+
+ // Reference to a secret key containing the HTTP access token or personal access token.
+ // +kubebuilder:validation:Optional
+ TokenSecretRef *corev1.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolBitbucketDatacenterConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolBitbucketDatacenterConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolBitbucketDatacenterConnectionAttributes{
+ URL: c.URL,
+ }
+
+ if c.TokenSecretRef != nil {
+ token, err := utils.GetSecretKey(ctx, cl, c.TokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.Token = lo.ToPtr(token)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolAzureDevopsConfig defines an azure devops connection.
+type WorkbenchToolAzureDevopsConfig struct {
+ // Optional REST API root (defaults to https://dev.azure.com).
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Reference to a secret key containing the Azure DevOps personal access token.
+ // +kubebuilder:validation:Optional
+ TokenSecretRef *corev1.SecretKeySelector `json:"tokenSecretRef,omitempty"`
+}
+
+func (c *WorkbenchToolAzureDevopsConfig) Attributes(ctx context.Context, cl client.Client, namespace string) (*console.WorkbenchToolAzureDevopsConnectionAttributes, error) {
+ if c == nil {
+ return nil, nil
+ }
+
+ attr := &console.WorkbenchToolAzureDevopsConnectionAttributes{
+ URL: c.URL,
+ }
+
+ if c.TokenSecretRef != nil {
+ token, err := utils.GetSecretKey(ctx, cl, c.TokenSecretRef, namespace)
+ if err != nil {
+ return nil, err
+ }
+ attr.Token = lo.ToPtr(token)
+ }
+
+ return attr, nil
+}
+
+// WorkbenchToolLambdaConfig defines an AWS Lambda function configuration.
+type WorkbenchToolLambdaConfig struct {
+ // AWS Lambda function ARN.
+ // +kubebuilder:validation:Required
+ LambdaArn string `json:"lambdaArn"`
+
+ // Description of the function exposed to the agent.
+ // +kubebuilder:validation:Required
+ Description string `json:"description"`
+
+ // JSON schema for the tool input.
+ // +kubebuilder:validation:Optional
+ InputSchema *runtime.RawExtension `json:"inputSchema,omitempty"`
+}
+
+func (c *WorkbenchToolLambdaConfig) Attributes() *console.WorkbenchToolLambdaConnectionAttributes {
+ if c == nil {
+ return nil
+ }
+
+ attr := &console.WorkbenchToolLambdaConnectionAttributes{
+ LambdaArn: c.LambdaArn,
+ Description: c.Description,
+ }
+ if c.InputSchema != nil {
+ attr.InputSchema = lo.ToPtr(string(c.InputSchema.Raw))
+ }
+ return attr
+}
+
+// WorkbenchToolCloudRunConfig defines a Google Cloud Run service configuration.
+type WorkbenchToolCloudRunConfig struct {
+ // Cloud Run service identifier.
+ // +kubebuilder:validation:Required
+ Identifier string `json:"identifier"`
+
+ // Description of the function exposed to the agent.
+ // +kubebuilder:validation:Required
+ Description string `json:"description"`
+
+ // JSON schema for the tool input.
+ // +kubebuilder:validation:Optional
+ InputSchema *runtime.RawExtension `json:"inputSchema,omitempty"`
+}
+
+func (c *WorkbenchToolCloudRunConfig) Attributes() *console.WorkbenchToolCloudRunConnectionAttributes {
+ if c == nil {
+ return nil
+ }
+
+ attr := &console.WorkbenchToolCloudRunConnectionAttributes{
+ Identifier: c.Identifier,
+ Description: c.Description,
+ }
+ if c.InputSchema != nil {
+ attr.InputSchema = lo.ToPtr(string(c.InputSchema.Raw))
+ }
+ return attr
+}
+
+// WorkbenchToolAzureFunctionConfig defines an Azure Function / Cloud Function configuration.
+type WorkbenchToolAzureFunctionConfig struct {
+ // Cloud Function identifier.
+ // +kubebuilder:validation:Required
+ Identifier string `json:"identifier"`
+
+ // Description of the function exposed to the agent.
+ // +kubebuilder:validation:Required
+ Description string `json:"description"`
+
+ // JSON schema for the tool input.
+ // +kubebuilder:validation:Optional
+ InputSchema *runtime.RawExtension `json:"inputSchema,omitempty"`
+}
+
+func (c *WorkbenchToolAzureFunctionConfig) Attributes() *console.WorkbenchToolAzureFunctionConnectionAttributes {
+ if c == nil {
+ return nil
+ }
+
+ attr := &console.WorkbenchToolAzureFunctionConnectionAttributes{
+ Identifier: c.Identifier,
+ Description: c.Description,
+ }
+ if c.InputSchema != nil {
+ attr.InputSchema = lo.ToPtr(string(c.InputSchema.Raw))
+ }
+ return attr
+}
+
+// WorkbenchToolDockerConfig defines a docker/OCI registry connection.
+// Auth secrets are resolved by the reconciler via HelmRepositoryAuth helpers.
+type WorkbenchToolDockerConfig struct {
+ // Registry host or base URL (defaults to registry-1.docker.io).
+ // +kubebuilder:validation:Optional
+ URL *string `json:"url,omitempty"`
+
+ // Registry authentication provider: BASIC, BEARER, AWS, AZURE, or GCP.
+ // +kubebuilder:validation:Optional
+ // +kubebuilder:validation:Enum:=BASIC;BEARER;GCP;AZURE;AWS
+ Provider *console.HelmAuthProvider `json:"provider,omitempty"`
+
+ // Registry authentication credentials and optional proxy.
+ // +kubebuilder:validation:Optional
+ Auth *HelmRepositoryAuth `json:"auth,omitempty"`
+}
+
+func (c *WorkbenchToolDockerConfig) Attributes() *console.WorkbenchToolDockerConnectionAttributes {
+ if c == nil {
+ return nil
+ }
+
+ return &console.WorkbenchToolDockerConnectionAttributes{
+ URL: c.URL,
+ Provider: c.Provider,
+ }
+}
diff --git a/go/controller/api/v1alpha1/zz_generated.deepcopy.go b/go/controller/api/v1alpha1/zz_generated.deepcopy.go
index c647e86657..be61390665 100644
--- a/go/controller/api/v1alpha1/zz_generated.deepcopy.go
+++ b/go/controller/api/v1alpha1/zz_generated.deepcopy.go
@@ -10627,6 +10627,11 @@ func (in *WorkbenchToolAtlassianConfig) DeepCopy() *WorkbenchToolAtlassianConfig
func (in *WorkbenchToolAzureConfig) DeepCopyInto(out *WorkbenchToolAzureConfig) {
*out = *in
in.ClientSecretSecretRef.DeepCopyInto(&out.ClientSecretSecretRef)
+ if in.PrometheusURL != nil {
+ in, out := &in.PrometheusURL, &out.PrometheusURL
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolAzureConfig.
@@ -10639,6 +10644,116 @@ func (in *WorkbenchToolAzureConfig) DeepCopy() *WorkbenchToolAzureConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolAzureDevopsConfig) DeepCopyInto(out *WorkbenchToolAzureDevopsConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.TokenSecretRef != nil {
+ in, out := &in.TokenSecretRef, &out.TokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolAzureDevopsConfig.
+func (in *WorkbenchToolAzureDevopsConfig) DeepCopy() *WorkbenchToolAzureDevopsConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolAzureDevopsConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolAzureFunctionConfig) DeepCopyInto(out *WorkbenchToolAzureFunctionConfig) {
+ *out = *in
+ if in.InputSchema != nil {
+ in, out := &in.InputSchema, &out.InputSchema
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolAzureFunctionConfig.
+func (in *WorkbenchToolAzureFunctionConfig) DeepCopy() *WorkbenchToolAzureFunctionConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolAzureFunctionConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolBitbucketConfig) DeepCopyInto(out *WorkbenchToolBitbucketConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.TokenSecretRef != nil {
+ in, out := &in.TokenSecretRef, &out.TokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolBitbucketConfig.
+func (in *WorkbenchToolBitbucketConfig) DeepCopy() *WorkbenchToolBitbucketConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolBitbucketConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolBitbucketDatacenterConfig) DeepCopyInto(out *WorkbenchToolBitbucketDatacenterConfig) {
+ *out = *in
+ if in.TokenSecretRef != nil {
+ in, out := &in.TokenSecretRef, &out.TokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolBitbucketDatacenterConfig.
+func (in *WorkbenchToolBitbucketDatacenterConfig) DeepCopy() *WorkbenchToolBitbucketDatacenterConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolBitbucketDatacenterConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolCloudRunConfig) DeepCopyInto(out *WorkbenchToolCloudRunConfig) {
+ *out = *in
+ if in.InputSchema != nil {
+ in, out := &in.InputSchema, &out.InputSchema
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolCloudRunConfig.
+func (in *WorkbenchToolCloudRunConfig) DeepCopy() *WorkbenchToolCloudRunConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolCloudRunConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolCloudwatchConfig) DeepCopyInto(out *WorkbenchToolCloudwatchConfig) {
*out = *in
@@ -10697,6 +10812,11 @@ func (in *WorkbenchToolConfiguration) DeepCopyInto(out *WorkbenchToolConfigurati
*out = new(WorkbenchToolElasticConfig)
(*in).DeepCopyInto(*out)
}
+ if in.Opensearch != nil {
+ in, out := &in.Opensearch, &out.Opensearch
+ *out = new(WorkbenchToolOpensearchConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.Prometheus != nil {
in, out := &in.Prometheus, &out.Prometheus
*out = new(WorkbenchToolPrometheusConfig)
@@ -10742,16 +10862,86 @@ func (in *WorkbenchToolConfiguration) DeepCopyInto(out *WorkbenchToolConfigurati
*out = new(WorkbenchToolAzureConfig)
(*in).DeepCopyInto(*out)
}
+ if in.Sentry != nil {
+ in, out := &in.Sentry, &out.Sentry
+ *out = new(WorkbenchToolSentryConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.Linear != nil {
in, out := &in.Linear, &out.Linear
*out = new(WorkbenchToolLinearConfig)
(*in).DeepCopyInto(*out)
}
+ if in.Slack != nil {
+ in, out := &in.Slack, &out.Slack
+ *out = new(WorkbenchToolSlackConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Pagerduty != nil {
+ in, out := &in.Pagerduty, &out.Pagerduty
+ *out = new(WorkbenchToolPagerdutyConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Teams != nil {
+ in, out := &in.Teams, &out.Teams
+ *out = new(WorkbenchToolTeamsConfig)
+ (*in).DeepCopyInto(*out)
+ }
if in.Atlassian != nil {
in, out := &in.Atlassian, &out.Atlassian
*out = new(WorkbenchToolAtlassianConfig)
(*in).DeepCopyInto(*out)
}
+ if in.Exa != nil {
+ in, out := &in.Exa, &out.Exa
+ *out = new(WorkbenchToolExaConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Github != nil {
+ in, out := &in.Github, &out.Github
+ *out = new(WorkbenchToolGithubConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Gitlab != nil {
+ in, out := &in.Gitlab, &out.Gitlab
+ *out = new(WorkbenchToolGitlabConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Bitbucket != nil {
+ in, out := &in.Bitbucket, &out.Bitbucket
+ *out = new(WorkbenchToolBitbucketConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.BitbucketDatacenter != nil {
+ in, out := &in.BitbucketDatacenter, &out.BitbucketDatacenter
+ *out = new(WorkbenchToolBitbucketDatacenterConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AzureDevops != nil {
+ in, out := &in.AzureDevops, &out.AzureDevops
+ *out = new(WorkbenchToolAzureDevopsConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Lambda != nil {
+ in, out := &in.Lambda, &out.Lambda
+ *out = new(WorkbenchToolLambdaConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.CloudRun != nil {
+ in, out := &in.CloudRun, &out.CloudRun
+ *out = new(WorkbenchToolCloudRunConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AzureFunction != nil {
+ in, out := &in.AzureFunction, &out.AzureFunction
+ *out = new(WorkbenchToolAzureFunctionConfig)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Docker != nil {
+ in, out := &in.Docker, &out.Docker
+ *out = new(WorkbenchToolDockerConfig)
+ (*in).DeepCopyInto(*out)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolConfiguration.
@@ -10794,6 +10984,36 @@ func (in *WorkbenchToolDatadogConfig) DeepCopy() *WorkbenchToolDatadogConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolDockerConfig) DeepCopyInto(out *WorkbenchToolDockerConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.Provider != nil {
+ in, out := &in.Provider, &out.Provider
+ *out = new(client.HelmAuthProvider)
+ **out = **in
+ }
+ if in.Auth != nil {
+ in, out := &in.Auth, &out.Auth
+ *out = new(HelmRepositoryAuth)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolDockerConfig.
+func (in *WorkbenchToolDockerConfig) DeepCopy() *WorkbenchToolDockerConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolDockerConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolDynatraceConfig) DeepCopyInto(out *WorkbenchToolDynatraceConfig) {
*out = *in
@@ -10830,9 +11050,104 @@ func (in *WorkbenchToolElasticConfig) DeepCopy() *WorkbenchToolElasticConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolExaConfig) DeepCopyInto(out *WorkbenchToolExaConfig) {
+ *out = *in
+ if in.APIKeySecretRef != nil {
+ in, out := &in.APIKeySecretRef, &out.APIKeySecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolExaConfig.
+func (in *WorkbenchToolExaConfig) DeepCopy() *WorkbenchToolExaConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolExaConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolGithubConfig) DeepCopyInto(out *WorkbenchToolGithubConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.AccessTokenSecretRef != nil {
+ in, out := &in.AccessTokenSecretRef, &out.AccessTokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Toolset != nil {
+ in, out := &in.Toolset, &out.Toolset
+ *out = new(string)
+ **out = **in
+ }
+ if in.AppID != nil {
+ in, out := &in.AppID, &out.AppID
+ *out = new(string)
+ **out = **in
+ }
+ if in.InstallationID != nil {
+ in, out := &in.InstallationID, &out.InstallationID
+ *out = new(string)
+ **out = **in
+ }
+ if in.PrivateKeySecretRef != nil {
+ in, out := &in.PrivateKeySecretRef, &out.PrivateKeySecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolGithubConfig.
+func (in *WorkbenchToolGithubConfig) DeepCopy() *WorkbenchToolGithubConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolGithubConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolGitlabConfig) DeepCopyInto(out *WorkbenchToolGitlabConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.TokenSecretRef != nil {
+ in, out := &in.TokenSecretRef, &out.TokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolGitlabConfig.
+func (in *WorkbenchToolGitlabConfig) DeepCopy() *WorkbenchToolGitlabConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolGitlabConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolHTTPConfig) DeepCopyInto(out *WorkbenchToolHTTPConfig) {
*out = *in
+ if in.Function != nil {
+ in, out := &in.Function, &out.Function
+ *out = new(bool)
+ **out = **in
+ }
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = make([]WorkbenchToolHTTPHeader, len(*in))
@@ -10917,6 +11232,26 @@ func (in *WorkbenchToolJaegerConfig) DeepCopy() *WorkbenchToolJaegerConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolLambdaConfig) DeepCopyInto(out *WorkbenchToolLambdaConfig) {
+ *out = *in
+ if in.InputSchema != nil {
+ in, out := &in.InputSchema, &out.InputSchema
+ *out = new(runtime.RawExtension)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolLambdaConfig.
+func (in *WorkbenchToolLambdaConfig) DeepCopy() *WorkbenchToolLambdaConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolLambdaConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolLinearConfig) DeepCopyInto(out *WorkbenchToolLinearConfig) {
*out = *in
@@ -11004,6 +11339,66 @@ func (in *WorkbenchToolLokiConfig) DeepCopy() *WorkbenchToolLokiConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolOpensearchConfig) DeepCopyInto(out *WorkbenchToolOpensearchConfig) {
+ *out = *in
+ if in.AWSAccessKeyIDSecretRef != nil {
+ in, out := &in.AWSAccessKeyIDSecretRef, &out.AWSAccessKeyIDSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AWSSecretAccessKeySecretRef != nil {
+ in, out := &in.AWSSecretAccessKeySecretRef, &out.AWSSecretAccessKeySecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AWSRegion != nil {
+ in, out := &in.AWSRegion, &out.AWSRegion
+ *out = new(string)
+ **out = **in
+ }
+ if in.AssumeRoleArn != nil {
+ in, out := &in.AssumeRoleArn, &out.AssumeRoleArn
+ *out = new(string)
+ **out = **in
+ }
+ if in.UsePodIdentity != nil {
+ in, out := &in.UsePodIdentity, &out.UsePodIdentity
+ *out = new(bool)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolOpensearchConfig.
+func (in *WorkbenchToolOpensearchConfig) DeepCopy() *WorkbenchToolOpensearchConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolOpensearchConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolPagerdutyConfig) DeepCopyInto(out *WorkbenchToolPagerdutyConfig) {
+ *out = *in
+ if in.APITokenSecretRef != nil {
+ in, out := &in.APITokenSecretRef, &out.APITokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolPagerdutyConfig.
+func (in *WorkbenchToolPagerdutyConfig) DeepCopy() *WorkbenchToolPagerdutyConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolPagerdutyConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolPrometheusConfig) DeepCopyInto(out *WorkbenchToolPrometheusConfig) {
*out = *in
@@ -11027,6 +11422,26 @@ func (in *WorkbenchToolPrometheusConfig) DeepCopyInto(out *WorkbenchToolPromethe
*out = new(string)
**out = **in
}
+ if in.AWSSigv4 != nil {
+ in, out := &in.AWSSigv4, &out.AWSSigv4
+ *out = new(bool)
+ **out = **in
+ }
+ if in.AWSAccessKeyIDSecretRef != nil {
+ in, out := &in.AWSAccessKeyIDSecretRef, &out.AWSAccessKeyIDSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AWSSecretAccessKeySecretRef != nil {
+ in, out := &in.AWSSecretAccessKeySecretRef, &out.AWSSecretAccessKeySecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.AWSRegion != nil {
+ in, out := &in.AWSRegion, &out.AWSRegion
+ *out = new(string)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolPrometheusConfig.
@@ -11039,6 +11454,51 @@ func (in *WorkbenchToolPrometheusConfig) DeepCopy() *WorkbenchToolPrometheusConf
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolSentryConfig) DeepCopyInto(out *WorkbenchToolSentryConfig) {
+ *out = *in
+ if in.URL != nil {
+ in, out := &in.URL, &out.URL
+ *out = new(string)
+ **out = **in
+ }
+ if in.AccessTokenSecretRef != nil {
+ in, out := &in.AccessTokenSecretRef, &out.AccessTokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolSentryConfig.
+func (in *WorkbenchToolSentryConfig) DeepCopy() *WorkbenchToolSentryConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolSentryConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolSlackConfig) DeepCopyInto(out *WorkbenchToolSlackConfig) {
+ *out = *in
+ if in.BotTokenSecretRef != nil {
+ in, out := &in.BotTokenSecretRef, &out.BotTokenSecretRef
+ *out = new(v1.SecretKeySelector)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolSlackConfig.
+func (in *WorkbenchToolSlackConfig) DeepCopy() *WorkbenchToolSlackConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolSlackConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolSpec) DeepCopyInto(out *WorkbenchToolSpec) {
*out = *in
@@ -11052,6 +11512,11 @@ func (in *WorkbenchToolSpec) DeepCopyInto(out *WorkbenchToolSpec) {
*out = make([]client.WorkbenchToolCategory, len(*in))
copy(*out, *in)
}
+ if in.Approval != nil {
+ in, out := &in.Approval, &out.Approval
+ *out = new(bool)
+ **out = **in
+ }
if in.ProjectRef != nil {
in, out := &in.ProjectRef, &out.ProjectRef
*out = new(v1.ObjectReference)
@@ -11067,6 +11532,16 @@ func (in *WorkbenchToolSpec) DeepCopyInto(out *WorkbenchToolSpec) {
*out = new(v1.ObjectReference)
**out = **in
}
+ if in.ScmConnectionRef != nil {
+ in, out := &in.ScmConnectionRef, &out.ScmConnectionRef
+ *out = new(v1.ObjectReference)
+ **out = **in
+ }
+ if in.Bindings != nil {
+ in, out := &in.Bindings, &out.Bindings
+ *out = new(Bindings)
+ (*in).DeepCopyInto(*out)
+ }
if in.Configuration != nil {
in, out := &in.Configuration, &out.Configuration
*out = new(WorkbenchToolConfiguration)
@@ -11119,6 +11594,22 @@ func (in *WorkbenchToolSplunkConfig) DeepCopy() *WorkbenchToolSplunkConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *WorkbenchToolTeamsConfig) DeepCopyInto(out *WorkbenchToolTeamsConfig) {
+ *out = *in
+ in.ClientSecretSecretRef.DeepCopyInto(&out.ClientSecretSecretRef)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkbenchToolTeamsConfig.
+func (in *WorkbenchToolTeamsConfig) DeepCopy() *WorkbenchToolTeamsConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(WorkbenchToolTeamsConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkbenchToolTempoConfig) DeepCopyInto(out *WorkbenchToolTempoConfig) {
*out = *in
diff --git a/go/controller/config/crd/bases/deployments.plural.sh_personas.yaml b/go/controller/config/crd/bases/deployments.plural.sh_personas.yaml
index b056d1ed59..9b1e246490 100644
--- a/go/controller/config/crd/bases/deployments.plural.sh_personas.yaml
+++ b/go/controller/config/crd/bases/deployments.plural.sh_personas.yaml
@@ -160,11 +160,6 @@ spec:
Permissions enables the permissions action in the flow header when set to true.
This allows personas to manage flow permissions from the flow detail page.
type: boolean
- startWorkbenchJob:
- description: |-
- StartWorkbenchJob enables the "Start workbench job" action in the flow header when set to true.
- This allows personas to launch workbench jobs directly from the flow detail page.
- type: boolean
pipelines:
description: |-
Pipelines enables access to flow pipeline features when set to true.
@@ -175,6 +170,11 @@ spec:
Previews enables access to flow preview environment features when set to true.
This includes viewing and managing preview environments associated with flows.
type: boolean
+ startWorkbenchJob:
+ description: |-
+ StartWorkbenchJob enables the "Start workbench job" action in the flow header when set to true.
+ This allows personas to launch workbench jobs directly from the flow detail page.
+ type: boolean
workbenches:
description: |-
Workbenches enables access to flow workbench features when set to true.
diff --git a/go/controller/config/crd/bases/deployments.plural.sh_workbenchtools.yaml b/go/controller/config/crd/bases/deployments.plural.sh_workbenchtools.yaml
index fcaf370701..9163c27e28 100644
--- a/go/controller/config/crd/bases/deployments.plural.sh_workbenchtools.yaml
+++ b/go/controller/config/crd/bases/deployments.plural.sh_workbenchtools.yaml
@@ -52,6 +52,58 @@ spec:
spec:
description: WorkbenchToolSpec defines the desired state of a WorkbenchTool.
properties:
+ approval:
+ description: Whether this tool requires approval before execution.
+ type: boolean
+ bindings:
+ description: Bindings define the read and write access policies for
+ this tool.
+ properties:
+ read:
+ description: Read bindings.
+ items:
+ description: Binding used to assign permissions to a resource
+ for a user or a group in the system.
+ properties:
+ UserID:
+ type: string
+ groupID:
+ type: string
+ groupName:
+ type: string
+ id:
+ description: |-
+ ID of a binding.
+ Deprecated.
+ Do not use.
+ type: string
+ userEmail:
+ type: string
+ type: object
+ type: array
+ write:
+ description: Write bindings.
+ items:
+ description: Binding used to assign permissions to a resource
+ for a user or a group in the system.
+ properties:
+ UserID:
+ type: string
+ groupID:
+ type: string
+ groupName:
+ type: string
+ id:
+ description: |-
+ ID of a binding.
+ Deprecated.
+ Do not use.
+ type: string
+ userEmail:
+ type: string
+ type: object
+ type: array
+ type: object
categories:
description: Categories for the tool.
items:
@@ -193,6 +245,10 @@ spec:
- key
type: object
x-kubernetes-map-type: atomic
+ prometheusUrl:
+ description: Optional azure managed prometheus url if you
+ wish to use it for metrics.
+ type: string
subscriptionId:
description: Azure subscription id.
type: string
@@ -205,6 +261,138 @@ spec:
- subscriptionId
- tenantId
type: object
+ azureDevops:
+ description: Azure DevOps connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the Azure
+ DevOps personal access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional REST API root (defaults to https://dev.azure.com).
+ type: string
+ type: object
+ azureFunction:
+ description: Azure Function / Cloud Function configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ identifier:
+ description: Cloud Function identifier.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - description
+ - identifier
+ type: object
+ bitbucket:
+ description: Bitbucket Cloud connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the Bitbucket
+ app password or access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional Bitbucket Cloud API base URL.
+ type: string
+ type: object
+ bitbucketDatacenter:
+ description: Bitbucket Data Center connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the HTTP
+ access token or personal access token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Bitbucket Data Center REST API base URL.
+ type: string
+ required:
+ - url
+ type: object
+ cloudRun:
+ description: Google Cloud Run service configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ identifier:
+ description: Cloud Run service identifier.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ required:
+ - description
+ - identifier
+ type: object
cloudwatch:
description: Cloudwatch connection (metrics, logs).
properties:
@@ -336,6 +524,330 @@ spec:
description: Datadog site (e.g. datadoghq.com).
type: string
type: object
+ docker:
+ description: Docker/OCI registry connection.
+ properties:
+ auth:
+ description: Registry authentication credentials and optional
+ proxy.
+ properties:
+ aws:
+ description: |-
+ Aws specifies AWS-specific authentication for Amazon ECR and other AWS-hosted repositories.
+ Supports both static credentials and IAM role-based authentication for secure access
+ to private repositories hosted in Amazon Web Services.
+ properties:
+ accessKey:
+ description: |-
+ AccessKey specifies the AWS access key ID for authentication.
+ When using static credentials, this should be set along with the secret access key.
+ For enhanced security, consider using IAM roles instead of static credentials.
+ type: string
+ assumeRoleArn:
+ description: |-
+ AssumeRoleArn specifies an AWS IAM role ARN to assume for repository access.
+ This enables cross-account access and role-based authentication, providing
+ enhanced security and flexibility in AWS environments.
+ type: string
+ secretAccessKeySecretKeyRef:
+ description: |-
+ SecretAccessKeySecretKeyRef references a specific key within a Kubernetes Secret containing the secret access key.
+ This is the preferred method for storing AWS credentials as it allows multiple
+ credential sets to be organized within a single secret.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ secretAccessKeySecretRef:
+ description: |-
+ SecretAccessKeySecretRef references a Kubernetes Secret containing the AWS secret access key.
+ The entire secret content will be used as the secret access key.
+ This approach is deprecated in favor of SecretAccessKeySecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ azure:
+ description: |-
+ Azure specifies Azure-specific authentication for Azure Container Registry (ACR).
+ Supports service principal authentication and managed identity for secure access
+ to private repositories hosted in Microsoft Azure.
+ properties:
+ clientId:
+ description: |-
+ ClientID specifies the Azure service principal client ID.
+ This is used in conjunction with the client secret to authenticate with Azure services.
+ type: string
+ clientSecretSecretKeyRef:
+ description: |-
+ ClientSecretSecretKeyRef references a specific key within a Kubernetes Secret containing the client secret.
+ This is the preferred method for storing Azure credentials as it allows proper
+ secret organization and key-based access control.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ clientSecretSecretRef:
+ description: |-
+ ClientSecretSecretRef references a Kubernetes Secret containing the Azure service principal client secret.
+ The entire secret content will be used as the client secret.
+ This approach is deprecated in favor of ClientSecretSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ subscriptionId:
+ description: |-
+ SubscriptionID specifies the Azure subscription ID.
+ This identifies the Azure subscription containing the resources
+ and may be required for certain repository access scenarios.
+ type: string
+ tenantId:
+ description: |-
+ TenantID specifies the Azure Active Directory tenant ID.
+ This identifies the Azure AD instance that contains the service principal
+ and is required for proper authentication scope.
+ type: string
+ type: object
+ basic:
+ description: |-
+ Basic specifies username/password authentication for repositories that support HTTP Basic Auth.
+ Commonly used with private Helm repositories, Harbor registries, and other traditional
+ repository managers that implement standard HTTP authentication.
+ properties:
+ passwordSecretKeyRef:
+ description: |-
+ PasswordSecretKeyRef references a specific key within a Kubernetes Secret that contains the password.
+ This is the preferred method for password storage as it allows multiple credentials
+ to be stored in a single secret with proper key-based access.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ passwordSecretRef:
+ description: |-
+ PasswordSecretRef references a Kubernetes Secret containing the password for Basic authentication.
+ The entire secret content will be used as the password.
+ This approach is deprecated in favor of PasswordSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ username:
+ description: |-
+ Username specifies the username for HTTP Basic authentication.
+ This is typically a user account or service account name configured
+ in the target repository system.
+ type: string
+ required:
+ - username
+ type: object
+ bearer:
+ description: |-
+ Bearer specifies token-based authentication for repositories that support Bearer tokens.
+ Used with modern container registries and repositories that implement OAuth2 or similar
+ token-based authentication schemes.
+ properties:
+ tokenSecretKeyRef:
+ description: |-
+ TokenSecretKeyRef references a specific key within a Kubernetes Secret that contains the bearer token.
+ This is the preferred method for token storage as it allows multiple tokens
+ to be stored in a single secret with proper key-based access.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tokenSecretRef:
+ description: |-
+ TokenSecretRef references a Kubernetes Secret containing the bearer token.
+ The entire secret content will be used as the authentication token.
+ This approach is deprecated in favor of TokenSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ gcp:
+ description: |-
+ Gcp specifies Google Cloud-specific authentication for Google Artifact Registry.
+ Supports service account key authentication for secure access to private
+ repositories hosted in Google Cloud Platform.
+ properties:
+ applicationCredentialsSecretKeyRef:
+ description: |-
+ ApplicationCredentialsSecretKeyRef references a specific key within a Kubernetes Secret containing the service account JSON.
+ This is the preferred method for storing GCP credentials as it allows multiple
+ service account keys to be organized within a single secret with proper access control.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its
+ key must be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ applicationCredentialsSecretRef:
+ description: |-
+ ApplicationCredentialsSecretRef references a Kubernetes Secret containing the GCP service account key JSON.
+ The entire secret content will be used as the service account credentials.
+ This approach is deprecated in favor of ApplicationCredentialsSecretKeyRef for better secret management.
+ properties:
+ name:
+ description: name is unique within a namespace
+ to reference a secret resource.
+ type: string
+ namespace:
+ description: namespace defines the space within
+ which the secret name must be unique.
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ proxy:
+ description: Proxy configures an HTTP proxy for requests
+ to this Helm repository or OCI registry.
+ properties:
+ noproxy:
+ description: The comma-separated list of hosts that
+ should not be proxied, will behave equivalently
+ to a NOPROXY env var.
+ type: string
+ url:
+ description: The url of your HTTP proxy.
+ type: string
+ required:
+ - url
+ type: object
+ type: object
+ provider:
+ description: 'Registry authentication provider: BASIC, BEARER,
+ AWS, AZURE, or GCP.'
+ enum:
+ - BASIC
+ - BEARER
+ - GCP
+ - AZURE
+ - AWS
+ type: string
+ url:
+ description: Registry host or base URL (defaults to registry-1.docker.io).
+ type: string
+ type: object
dynatrace:
description: Dynatrace connection (metrics, logs, traces).
properties:
@@ -413,12 +925,149 @@ spec:
- url
- username
type: object
+ exa:
+ description: Exa connection (search).
+ properties:
+ apiKeySecretRef:
+ description: Reference to a secret key containing the exa
+ API key.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ github:
+ description: GitHub connection (integration).
+ properties:
+ accessTokenSecretRef:
+ description: Reference to a secret key containing an optional
+ GitHub personal access token or fine-grained token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ appId:
+ description: GitHub App ID (use with installationId and privateKey
+ instead of accessToken).
+ type: string
+ installationId:
+ description: GitHub App installation ID for this organization
+ or account.
+ type: string
+ privateKeySecretRef:
+ description: Reference to a secret key containing the PEM
+ private key for the GitHub App.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ toolset:
+ description: 'Optional native tool subset: issues, pull_requests,
+ repos, security, default/all, or omit for all tools.'
+ type: string
+ url:
+ description: Optional GitHub REST API base URL (defaults to
+ https://api.github.com/; set for GitHub Enterprise Server).
+ type: string
+ type: object
+ gitlab:
+ description: GitLab connection (scm).
+ properties:
+ tokenSecretRef:
+ description: Reference to a secret key containing the GitLab
+ personal access token or project/group token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional GitLab API base URL (defaults to https://gitlab.com
+ when omitted).
+ type: string
+ type: object
http:
description: Http tool configuration.
properties:
body:
description: Request body.
type: string
+ function:
+ description: When true, exposes this HTTP tool as a workbench
+ action; execution may require approval when tool approval
+ is enabled.
+ type: boolean
headers:
description: Request headers.
items:
@@ -515,6 +1164,23 @@ spec:
required:
- url
type: object
+ lambda:
+ description: AWS Lambda function configuration.
+ properties:
+ description:
+ description: Description of the function exposed to the agent.
+ type: string
+ inputSchema:
+ description: JSON schema for the tool input.
+ type: object
+ x-kubernetes-preserve-unknown-fields: true
+ lambdaArn:
+ description: AWS Lambda function ARN.
+ type: string
+ required:
+ - description
+ - lambdaArn
+ type: object
linear:
description: Linear connection (ticketing).
properties:
@@ -609,9 +1275,168 @@ spec:
required:
- url
type: object
+ opensearch:
+ description: AWS OpenSearch connection (logs).
+ properties:
+ assumeRoleArn:
+ description: Optional IAM role ARN to assume before signing
+ OpenSearch requests.
+ type: string
+ awsAccessKeyIdSecretRef:
+ description: Reference to a secret key containing the AWS
+ access key id for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsRegion:
+ description: AWS region for SigV4 authentication.
+ type: string
+ awsSecretAccessKeySecretRef:
+ description: Reference to a secret key containing the AWS
+ secret access key for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ host:
+ description: AWS OpenSearch endpoint.
+ type: string
+ index:
+ description: OpenSearch index.
+ type: string
+ usePodIdentity:
+ description: Whether to use pod identity (IRSA/Workload Identity)
+ for AWS authentication instead of static credentials.
+ type: boolean
+ required:
+ - host
+ - index
+ type: object
+ pagerduty:
+ description: PagerDuty connection (integration).
+ properties:
+ apiTokenSecretRef:
+ description: Reference to a secret key containing the pagerduty
+ REST API key.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
prometheus:
description: Prometheus connection (metrics).
properties:
+ awsAccessKeyIdSecretRef:
+ description: Reference to a secret key containing the AWS
+ access key id for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsRegion:
+ description: AWS region for SigV4 authentication.
+ type: string
+ awsSecretAccessKeySecretRef:
+ description: Reference to a secret key containing the AWS
+ secret access key for SigV4 authentication.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ awsSigv4:
+ description: Whether to sign requests with AWS SigV4.
+ type: boolean
passwordSecretRef:
description: Reference to a secret key containing the basic
auth password.
@@ -674,6 +1499,68 @@ spec:
required:
- url
type: object
+ sentry:
+ description: Sentry connection (error tracking).
+ properties:
+ accessTokenSecretRef:
+ description: Reference to a secret key containing the Sentry
+ user auth token or internal integration token.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ url:
+ description: Optional Sentry API host (defaults to https://sentry.io;
+ set for self-hosted).
+ type: string
+ type: object
+ slack:
+ description: Slack connection (integration).
+ properties:
+ botTokenSecretRef:
+ description: Reference to a secret key containing the slack
+ bot user OAuth token (xoxb-...).
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
splunk:
description: Splunk connection (logs).
properties:
@@ -736,6 +1623,45 @@ spec:
required:
- url
type: object
+ teams:
+ description: Microsoft Teams / Graph connection (integration).
+ properties:
+ clientId:
+ description: Microsoft Entra application (client) id.
+ type: string
+ clientSecretSecretRef:
+ description: Reference to a secret key containing the microsoft
+ entra client secret.
+ properties:
+ key:
+ description: The key of the secret to select from. Must
+ be a valid secret key.
+ type: string
+ name:
+ default: ""
+ description: |-
+ Name of the referent.
+ This field is effectively required, but due to backwards compatibility is
+ allowed to be empty. Instances of this type with an empty value here are
+ almost certainly wrong.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ optional:
+ description: Specify whether the Secret or its key must
+ be defined
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ tenantId:
+ description: Microsoft Entra tenant (directory) id.
+ type: string
+ required:
+ - clientId
+ - clientSecretSecretRef
+ - tenantId
+ type: object
tempo:
description: Tempo connection (traces).
properties:
@@ -914,6 +1840,50 @@ spec:
example: 5m30s
type: string
type: object
+ scmConnectionRef:
+ description: The SCM connection for this tool (e.g. shared Git provider
+ credentials).
+ properties:
+ apiVersion:
+ description: API version of the referent.
+ type: string
+ fieldPath:
+ description: |-
+ If referring to a piece of an object instead of an entire object, this string
+ should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
+ For example, if the object reference is to a container within a pod, this would take on a value like:
+ "spec.containers{name}" (where "name" refers to the name of the container that triggered
+ the event) or if no container name is specified "spec.containers[2]" (container with
+ index 2 in this pod). This syntax is chosen only to have some well-defined way of
+ referencing a part of an object.
+ type: string
+ kind:
+ description: |-
+ Kind of the referent.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
+ type: string
+ name:
+ description: |-
+ Name of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
+ type: string
+ namespace:
+ description: |-
+ Namespace of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
+ type: string
+ resourceVersion:
+ description: |-
+ Specific resourceVersion to which this reference is made, if any.
+ More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
+ type: string
+ uid:
+ description: |-
+ UID of the referent.
+ More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
+ type: string
+ type: object
+ x-kubernetes-map-type: atomic
tool:
description: The type of tool.
enum:
@@ -933,6 +1903,20 @@ spec:
- AZURE
- CLOUD
- JAEGER
+ - EXA
+ - GITHUB
+ - SLACK
+ - TEAMS
+ - GITLAB
+ - BITBUCKET
+ - BITBUCKET_DATACENTER
+ - AZURE_DEVOPS
+ - PAGERDUTY
+ - OPENSEARCH
+ - LAMBDA
+ - CLOUD_RUN
+ - AZURE_FUNCTION
+ - DOCKER
type: string
required:
- tool
diff --git a/go/controller/config/samples/workbench.yaml b/go/controller/config/samples/workbench.yaml
index 284333008d..8ed7d7211d 100644
--- a/go/controller/config/samples/workbench.yaml
+++ b/go/controller/config/samples/workbench.yaml
@@ -14,6 +14,24 @@ stringData:
clientSecret: "placeholder"
accessToken: "placeholder"
apiToken: "placeholder"
+ botToken: "xoxb-placeholder"
+ privateKey: |
+ -----BEGIN RSA PRIVATE KEY-----
+ placeholder
+ -----END RSA PRIVATE KEY-----
+---
+# Dedicated Docker registry secret so credential rotation can be tested independently:
+# kubectl patch secret workbench-docker-creds -n default --type merge -p '{"stringData":{"token":"rotated-token"}}'
+# Then confirm the WorkbenchTool reconciles and Console receives the new token.
+apiVersion: v1
+kind: Secret
+metadata:
+ name: workbench-docker-creds
+ namespace: default
+stringData:
+ token: "initial-registry-token"
+ password: "initial-registry-password"
+ username: "registry-user"
---
apiVersion: deployments.plural.sh/v1alpha1
kind: WorkbenchTool
@@ -31,10 +49,12 @@ spec:
tool: HTTP
categories:
- INTEGRATION
+ approval: true
configuration:
http:
url: https://api.example.com/health
method: GET
+ function: true
inputSchema:
type: object
properties:
@@ -102,6 +122,14 @@ spec:
name: workbench-tool-creds
key: password
tenantId: my-tenant
+ awsSigv4: true
+ awsRegion: us-east-1
+ awsAccessKeyIdSecretRef:
+ name: workbench-tool-creds
+ key: accessKeyId
+ awsSecretAccessKeySecretRef:
+ name: workbench-tool-creds
+ key: secretAccessKey
---
apiVersion: deployments.plural.sh/v1alpha1
kind: WorkbenchTool
@@ -154,6 +182,36 @@ spec:
---
apiVersion: deployments.plural.sh/v1alpha1
kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-opensearch-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-opensearch-sample
+ namespace: default
+spec:
+ name: workbenchtool_opensearch_sample
+ tool: OPENSEARCH
+ categories:
+ - LOGS
+ configuration:
+ opensearch:
+ host: https://search-my-domain.us-east-1.es.amazonaws.com
+ index: logs-*
+ awsRegion: us-east-1
+ assumeRoleArn: arn:aws:iam::123456789012:role/opensearch-reader
+ usePodIdentity: false
+ awsAccessKeyIdSecretRef:
+ name: workbench-tool-creds
+ key: accessKeyId
+ awsSecretAccessKeySecretRef:
+ name: workbench-tool-creds
+ key: secretAccessKey
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
metadata:
labels:
app.kubernetes.io/name: workbenchtool
@@ -282,6 +340,30 @@ spec:
clientSecretSecretRef:
name: workbench-tool-creds
key: clientSecret
+ prometheusUrl: https://my-workspace.eastus.prometheus.monitor.azure.com
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-sentry-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-sentry-sample
+ namespace: default
+spec:
+ name: workbenchtool_sentry_sample
+ tool: SENTRY
+ categories:
+ - ERROR_TRACKING
+ configuration:
+ sentry:
+ url: https://sentry.io
+ accessTokenSecretRef:
+ name: workbench-tool-creds
+ key: accessToken
---
apiVersion: deployments.plural.sh/v1alpha1
kind: WorkbenchTool
@@ -330,6 +412,356 @@ spec:
---
apiVersion: deployments.plural.sh/v1alpha1
kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-slack-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-slack-sample
+ namespace: default
+spec:
+ name: workbenchtool_slack_sample
+ tool: SLACK
+ categories:
+ - CHAT
+ configuration:
+ slack:
+ botTokenSecretRef:
+ name: workbench-tool-creds
+ key: botToken
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-pagerduty-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-pagerduty-sample
+ namespace: default
+spec:
+ name: workbenchtool_pagerduty_sample
+ tool: PAGERDUTY
+ categories:
+ - INTEGRATION
+ configuration:
+ pagerduty:
+ apiTokenSecretRef:
+ name: workbench-tool-creds
+ key: apiToken
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-teams-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-teams-sample
+ namespace: default
+spec:
+ name: workbenchtool_teams_sample
+ tool: TEAMS
+ categories:
+ - CHAT
+ configuration:
+ teams:
+ clientId: 00000000-0000-0000-0000-000000000010
+ tenantId: 00000000-0000-0000-0000-000000000011
+ clientSecretSecretRef:
+ name: workbench-tool-creds
+ key: clientSecret
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-exa-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-exa-sample
+ namespace: default
+spec:
+ name: workbenchtool_exa_sample
+ tool: EXA
+ categories:
+ - SEARCH
+ configuration:
+ exa:
+ apiKeySecretRef:
+ name: workbench-tool-creds
+ key: apiKey
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-github-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-github-sample
+ namespace: default
+spec:
+ name: workbenchtool_github_sample
+ tool: GITHUB
+ categories:
+ - SCM
+ scmConnectionRef:
+ name: github
+ configuration:
+ github:
+ url: https://api.github.com/
+ toolset: default
+ appId: "123456"
+ installationId: "987654"
+ privateKeySecretRef:
+ name: workbench-tool-creds
+ key: privateKey
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-gitlab-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-gitlab-sample
+ namespace: default
+spec:
+ name: workbenchtool_gitlab_sample
+ tool: GITLAB
+ categories:
+ - SCM
+ configuration:
+ gitlab:
+ url: https://gitlab.com
+ tokenSecretRef:
+ name: workbench-tool-creds
+ key: token
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-bitbucket-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-bitbucket-sample
+ namespace: default
+spec:
+ name: workbenchtool_bitbucket_sample
+ tool: BITBUCKET
+ categories:
+ - SCM
+ configuration:
+ bitbucket:
+ url: https://api.bitbucket.org
+ tokenSecretRef:
+ name: workbench-tool-creds
+ key: token
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-bitbucket-dc-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-bitbucket-dc-sample
+ namespace: default
+spec:
+ name: workbenchtool_bitbucket_dc_sample
+ tool: BITBUCKET_DATACENTER
+ categories:
+ - SCM
+ configuration:
+ bitbucketDatacenter:
+ url: https://bitbucket.example.com
+ tokenSecretRef:
+ name: workbench-tool-creds
+ key: token
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-azure-devops-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-azure-devops-sample
+ namespace: default
+spec:
+ name: workbenchtool_azure_devops_sample
+ tool: AZURE_DEVOPS
+ categories:
+ - SCM
+ configuration:
+ azureDevops:
+ url: https://dev.azure.com/my-org
+ tokenSecretRef:
+ name: workbench-tool-creds
+ key: token
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-lambda-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-lambda-sample
+ namespace: default
+spec:
+ name: workbenchtool_lambda_sample
+ tool: LAMBDA
+ categories:
+ - FUNCTION
+ approval: true
+ configuration:
+ lambda:
+ lambdaArn: arn:aws:lambda:us-east-1:123456789012:function:my-function
+ description: Invoke a custom Lambda function from the workbench
+ inputSchema:
+ type: object
+ properties:
+ payload:
+ type: string
+ required:
+ - payload
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-cloud-run-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-cloud-run-sample
+ namespace: default
+spec:
+ name: workbenchtool_cloud_run_sample
+ tool: CLOUD_RUN
+ categories:
+ - FUNCTION
+ configuration:
+ cloudRun:
+ identifier: projects/my-project/locations/us-central1/services/my-service
+ description: Invoke a Cloud Run service from the workbench
+ inputSchema:
+ type: object
+ properties:
+ path:
+ type: string
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-azure-function-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-azure-function-sample
+ namespace: default
+spec:
+ name: workbenchtool_azure_function_sample
+ tool: AZURE_FUNCTION
+ categories:
+ - FUNCTION
+ configuration:
+ azureFunction:
+ identifier: https://my-function-app.azurewebsites.net/api/HttpTrigger
+ description: Invoke an Azure Function from the workbench
+ inputSchema:
+ type: object
+ properties:
+ name:
+ type: string
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-docker-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-docker-sample
+ namespace: default
+spec:
+ name: workbenchtool_docker_sample
+ tool: DOCKER
+ categories:
+ - INTEGRATION
+ reconciliation:
+ driftDetection: true
+ interval: 1m
+ configuration:
+ docker:
+ url: registry-1.docker.io
+ provider: BEARER
+ auth:
+ proxy:
+ url: http://proxy.example.com:8080
+ noproxy: localhost,127.0.0.1
+ bearer:
+ tokenSecretKeyRef:
+ name: workbench-docker-creds
+ key: token
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
+metadata:
+ labels:
+ app.kubernetes.io/name: workbenchtool
+ app.kubernetes.io/instance: workbenchtool-docker-basic-sample
+ app.kubernetes.io/part-of: controller
+ app.kubernetes.io/managed-by: kustomize
+ app.kubernetes.io/created-by: controller
+ name: workbenchtool-docker-basic-sample
+ namespace: default
+spec:
+ name: workbenchtool_docker_basic_sample
+ tool: DOCKER
+ categories:
+ - INTEGRATION
+ configuration:
+ docker:
+ url: ghcr.io
+ provider: BASIC
+ auth:
+ basic:
+ username: registry-user
+ passwordSecretKeyRef:
+ name: workbench-docker-creds
+ key: password
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: WorkbenchTool
metadata:
labels:
app.kubernetes.io/name: workbenchtool
@@ -402,6 +834,26 @@ spec:
namespace: default
key: secretAccessKey
---
+apiVersion: v1
+kind: Secret
+metadata:
+ name: github-token
+ namespace: default
+stringData:
+ token: "test-token"
+---
+apiVersion: deployments.plural.sh/v1alpha1
+kind: ScmConnection
+metadata:
+ name: github
+spec:
+ name: scm-test-github
+ type: GITHUB
+ tokenSecretRef:
+ name: github-token
+ namespace: default
+ username: "johndoe"
+---
apiVersion: deployments.plural.sh/v1alpha1
kind: Workbench
metadata:
@@ -428,6 +880,8 @@ spec:
namespace: default
- name: workbenchtool-elastic-sample
namespace: default
+ - name: workbenchtool-opensearch-sample
+ namespace: default
- name: workbenchtool-tempo-sample
namespace: default
- name: workbenchtool-datadog-sample
@@ -438,10 +892,40 @@ spec:
namespace: default
- name: workbenchtool-azure-sample
namespace: default
+ - name: workbenchtool-sentry-sample
+ namespace: default
- name: workbenchtool-linear-sample
namespace: default
- name: workbenchtool-atlassian-sample
namespace: default
+ - name: workbenchtool-slack-sample
+ namespace: default
+ - name: workbenchtool-pagerduty-sample
+ namespace: default
+ - name: workbenchtool-teams-sample
+ namespace: default
+ - name: workbenchtool-exa-sample
+ namespace: default
+ - name: workbenchtool-github-sample
+ namespace: default
+ - name: workbenchtool-gitlab-sample
+ namespace: default
+ - name: workbenchtool-bitbucket-sample
+ namespace: default
+ - name: workbenchtool-bitbucket-dc-sample
+ namespace: default
+ - name: workbenchtool-azure-devops-sample
+ namespace: default
+ - name: workbenchtool-lambda-sample
+ namespace: default
+ - name: workbenchtool-cloud-run-sample
+ namespace: default
+ - name: workbenchtool-azure-function-sample
+ namespace: default
+ - name: workbenchtool-docker-sample
+ namespace: default
+ - name: workbenchtool-docker-basic-sample
+ namespace: default
- name: workbenchtool-mcp-sample
namespace: default
- name: workbenchtool-cloud-sample
diff --git a/go/controller/docs/api.md b/go/controller/docs/api.md
index 30f3ae25c7..e66bba9774 100644
--- a/go/controller/docs/api.md
+++ b/go/controller/docs/api.md
@@ -380,6 +380,7 @@ _Appears in:_
- [ProjectSpec](#projectspec)
- [ServiceSpec](#servicespec)
- [WorkbenchSpec](#workbenchspec)
+- [WorkbenchToolSpec](#workbenchtoolspec)
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
@@ -1976,6 +1977,7 @@ _Appears in:_
- [HelmRepositorySpec](#helmrepositoryspec)
- [ObserverHelm](#observerhelm)
- [ObserverOci](#observeroci)
+- [WorkbenchToolDockerConfig](#workbenchtooldockerconfig)
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
@@ -5761,6 +5763,94 @@ _Appears in:_
| `tenantId` _string_ | Azure tenant id. | | Required: \{\}
|
| `clientId` _string_ | Azure client id. | | Required: \{\}
|
| `clientSecretSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the azure client secret. | | Required: \{\}
|
+| `prometheusUrl` _string_ | Optional azure managed prometheus url if you wish to use it for metrics. | | Optional: \{\}
|
+
+
+#### WorkbenchToolAzureDevopsConfig
+
+
+
+WorkbenchToolAzureDevopsConfig defines an azure devops connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Optional REST API root (defaults to https://dev.azure.com). | | Optional: \{\}
|
+| `tokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the Azure DevOps personal access token. | | Optional: \{\}
|
+
+
+#### WorkbenchToolAzureFunctionConfig
+
+
+
+WorkbenchToolAzureFunctionConfig defines an Azure Function / Cloud Function configuration.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `identifier` _string_ | Cloud Function identifier. | | Required: \{\}
|
+| `description` _string_ | Description of the function exposed to the agent. | | Required: \{\}
|
+| `inputSchema` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg)_ | JSON schema for the tool input. | | Optional: \{\}
|
+
+
+#### WorkbenchToolBitbucketConfig
+
+
+
+WorkbenchToolBitbucketConfig defines a bitbucket cloud connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Optional Bitbucket Cloud API base URL. | | Optional: \{\}
|
+| `tokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the Bitbucket app password or access token. | | Optional: \{\}
|
+
+
+#### WorkbenchToolBitbucketDatacenterConfig
+
+
+
+WorkbenchToolBitbucketDatacenterConfig defines a bitbucket data center connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Bitbucket Data Center REST API base URL. | | Required: \{\}
|
+| `tokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the HTTP access token or personal access token. | | Optional: \{\}
|
+
+
+#### WorkbenchToolCloudRunConfig
+
+
+
+WorkbenchToolCloudRunConfig defines a Google Cloud Run service configuration.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `identifier` _string_ | Cloud Run service identifier. | | Required: \{\}
|
+| `description` _string_ | Description of the function exposed to the agent. | | Required: \{\}
|
+| `inputSchema` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg)_ | JSON schema for the tool input. | | Optional: \{\}
|
#### WorkbenchToolCloudwatchConfig
@@ -5800,6 +5890,7 @@ _Appears in:_
| --- | --- | --- | --- |
| `http` _[WorkbenchToolHTTPConfig](#workbenchtoolhttpconfig)_ | Http tool configuration. | | Optional: \{\}
|
| `elastic` _[WorkbenchToolElasticConfig](#workbenchtoolelasticconfig)_ | Elasticsearch connection (logs). | | Optional: \{\}
|
+| `opensearch` _[WorkbenchToolOpensearchConfig](#workbenchtoolopensearchconfig)_ | AWS OpenSearch connection (logs). | | Optional: \{\}
|
| `prometheus` _[WorkbenchToolPrometheusConfig](#workbenchtoolprometheusconfig)_ | Prometheus connection (metrics). | | Optional: \{\}
|
| `loki` _[WorkbenchToolLokiConfig](#workbenchtoollokiconfig)_ | Loki connection (logs). | | Optional: \{\}
|
| `tempo` _[WorkbenchToolTempoConfig](#workbenchtooltempoconfig)_ | Tempo connection (traces). | | Optional: \{\}
|
@@ -5809,8 +5900,22 @@ _Appears in:_
| `dynatrace` _[WorkbenchToolDynatraceConfig](#workbenchtooldynatraceconfig)_ | Dynatrace connection (metrics, logs, traces). | | Optional: \{\}
|
| `cloudwatch` _[WorkbenchToolCloudwatchConfig](#workbenchtoolcloudwatchconfig)_ | Cloudwatch connection (metrics, logs). | | Optional: \{\}
|
| `azure` _[WorkbenchToolAzureConfig](#workbenchtoolazureconfig)_ | Azure monitor connection (metrics). | | Optional: \{\}
|
+| `sentry` _[WorkbenchToolSentryConfig](#workbenchtoolsentryconfig)_ | Sentry connection (error tracking). | | Optional: \{\}
|
| `linear` _[WorkbenchToolLinearConfig](#workbenchtoollinearconfig)_ | Linear connection (ticketing). | | Optional: \{\}
|
+| `slack` _[WorkbenchToolSlackConfig](#workbenchtoolslackconfig)_ | Slack connection (integration). | | Optional: \{\}
|
+| `pagerduty` _[WorkbenchToolPagerdutyConfig](#workbenchtoolpagerdutyconfig)_ | PagerDuty connection (integration). | | Optional: \{\}
|
+| `teams` _[WorkbenchToolTeamsConfig](#workbenchtoolteamsconfig)_ | Microsoft Teams / Graph connection (integration). | | Optional: \{\}
|
| `atlassian` _[WorkbenchToolAtlassianConfig](#workbenchtoolatlassianconfig)_ | Atlassian/jira connection (ticketing). | | Optional: \{\}
|
+| `exa` _[WorkbenchToolExaConfig](#workbenchtoolexaconfig)_ | Exa connection (search). | | Optional: \{\}
|
+| `github` _[WorkbenchToolGithubConfig](#workbenchtoolgithubconfig)_ | GitHub connection (integration). | | Optional: \{\}
|
+| `gitlab` _[WorkbenchToolGitlabConfig](#workbenchtoolgitlabconfig)_ | GitLab connection (scm). | | Optional: \{\}
|
+| `bitbucket` _[WorkbenchToolBitbucketConfig](#workbenchtoolbitbucketconfig)_ | Bitbucket Cloud connection (scm). | | Optional: \{\}
|
+| `bitbucketDatacenter` _[WorkbenchToolBitbucketDatacenterConfig](#workbenchtoolbitbucketdatacenterconfig)_ | Bitbucket Data Center connection (scm). | | Optional: \{\}
|
+| `azureDevops` _[WorkbenchToolAzureDevopsConfig](#workbenchtoolazuredevopsconfig)_ | Azure DevOps connection (scm). | | Optional: \{\}
|
+| `lambda` _[WorkbenchToolLambdaConfig](#workbenchtoollambdaconfig)_ | AWS Lambda function configuration. | | Optional: \{\}
|
+| `cloudRun` _[WorkbenchToolCloudRunConfig](#workbenchtoolcloudrunconfig)_ | Google Cloud Run service configuration. | | Optional: \{\}
|
+| `azureFunction` _[WorkbenchToolAzureFunctionConfig](#workbenchtoolazurefunctionconfig)_ | Azure Function / Cloud Function configuration. | | Optional: \{\}
|
+| `docker` _[WorkbenchToolDockerConfig](#workbenchtooldockerconfig)_ | Docker/OCI registry connection. | | Optional: \{\}
|
#### WorkbenchToolDatadogConfig
@@ -5831,6 +5936,25 @@ _Appears in:_
| `appKeySecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the datadog application key. | | Optional: \{\}
|
+#### WorkbenchToolDockerConfig
+
+
+
+WorkbenchToolDockerConfig defines a docker/OCI registry connection.
+Auth secrets are resolved by the reconciler via HelmRepositoryAuth helpers.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Registry host or base URL (defaults to registry-1.docker.io). | | Optional: \{\}
|
+| `provider` _[HelmAuthProvider](#helmauthprovider)_ | Registry authentication provider: BASIC, BEARER, AWS, AZURE, or GCP. | | Enum: [BASIC BEARER GCP AZURE AWS]
Optional: \{\}
|
+| `auth` _[HelmRepositoryAuth](#helmrepositoryauth)_ | Registry authentication credentials and optional proxy. | | Optional: \{\}
|
+
+
#### WorkbenchToolDynatraceConfig
@@ -5867,6 +5991,60 @@ _Appears in:_
| `index` _string_ | Elasticsearch index. | | Required: \{\}
|
+#### WorkbenchToolExaConfig
+
+
+
+WorkbenchToolExaConfig defines an exa connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiKeySecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the exa API key. | | Optional: \{\}
|
+
+
+#### WorkbenchToolGithubConfig
+
+
+
+WorkbenchToolGithubConfig defines a github connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Optional GitHub REST API base URL (defaults to https://api.github.com/; set for GitHub Enterprise Server). | | Optional: \{\}
|
+| `accessTokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing an optional GitHub personal access token or fine-grained token. | | Optional: \{\}
|
+| `toolset` _string_ | Optional native tool subset: issues, pull_requests, repos, security, default/all, or omit for all tools. | | Optional: \{\}
|
+| `appId` _string_ | GitHub App ID (use with installationId and privateKey instead of accessToken). | | Optional: \{\}
|
+| `installationId` _string_ | GitHub App installation ID for this organization or account. | | Optional: \{\}
|
+| `privateKeySecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the PEM private key for the GitHub App. | | Optional: \{\}
|
+
+
+#### WorkbenchToolGitlabConfig
+
+
+
+WorkbenchToolGitlabConfig defines a gitlab connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Optional GitLab API base URL (defaults to https://gitlab.com when omitted). | | Optional: \{\}
|
+| `tokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the GitLab personal access token or project/group token. | | Optional: \{\}
|
+
+
#### WorkbenchToolHTTPConfig
@@ -5882,6 +6060,7 @@ _Appears in:_
| --- | --- | --- | --- |
| `url` _string_ | The request URL. | | Format: uri
Required: \{\}
Type: string
|
| `method` _[WorkbenchToolHTTPMethod](#workbenchtoolhttpmethod)_ | The HTTP method. | | Enum: [GET POST PUT DELETE PATCH]
Required: \{\}
|
+| `function` _boolean_ | When true, exposes this HTTP tool as a workbench action; execution may require approval when tool approval is enabled. | | Optional: \{\}
|
| `headers` _[WorkbenchToolHTTPHeader](#workbenchtoolhttpheader) array_ | Request headers. | | Optional: \{\}
|
| `body` _string_ | Request body. | | Optional: \{\}
Type: string
|
| `inputSchema` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg)_ | JSON schema for the tool input. | | Required: \{\}
|
@@ -5923,6 +6102,24 @@ _Appears in:_
| `passwordSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the basic auth password. | | Optional: \{\}
|
+#### WorkbenchToolLambdaConfig
+
+
+
+WorkbenchToolLambdaConfig defines an AWS Lambda function configuration.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `lambdaArn` _string_ | AWS Lambda function ARN. | | Required: \{\}
|
+| `description` _string_ | Description of the function exposed to the agent. | | Required: \{\}
|
+| `inputSchema` _[RawExtension](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#rawextension-runtime-pkg)_ | JSON schema for the tool input. | | Optional: \{\}
|
+
+
#### WorkbenchToolLinearConfig
@@ -5959,6 +6156,44 @@ _Appears in:_
| `tenantId` _string_ | Optional tenant id. | | Optional: \{\}
|
+#### WorkbenchToolOpensearchConfig
+
+
+
+WorkbenchToolOpensearchConfig defines an AWS OpenSearch connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `host` _string_ | AWS OpenSearch endpoint. | | Required: \{\}
|
+| `index` _string_ | OpenSearch index. | | Required: \{\}
|
+| `awsAccessKeyIdSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the AWS access key id for SigV4 authentication. | | Optional: \{\}
|
+| `awsSecretAccessKeySecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the AWS secret access key for SigV4 authentication. | | Optional: \{\}
|
+| `awsRegion` _string_ | AWS region for SigV4 authentication. | | Optional: \{\}
|
+| `assumeRoleArn` _string_ | Optional IAM role ARN to assume before signing OpenSearch requests. | | Optional: \{\}
|
+| `usePodIdentity` _boolean_ | Whether to use pod identity (IRSA/Workload Identity) for AWS authentication instead of static credentials. | | Optional: \{\}
|
+
+
+#### WorkbenchToolPagerdutyConfig
+
+
+
+WorkbenchToolPagerdutyConfig defines a pagerduty connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `apiTokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the pagerduty REST API key. | | Optional: \{\}
|
+
+
#### WorkbenchToolPrometheusConfig
@@ -5977,6 +6212,43 @@ _Appears in:_
| `username` _string_ | Basic auth username. | | Optional: \{\}
|
| `passwordSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the basic auth password. | | Optional: \{\}
|
| `tenantId` _string_ | Optional tenant id (e.g. for Mimir). | | Optional: \{\}
|
+| `awsSigv4` _boolean_ | Whether to sign requests with AWS SigV4. | | Optional: \{\}
|
+| `awsAccessKeyIdSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the AWS access key id for SigV4 authentication. | | Optional: \{\}
|
+| `awsSecretAccessKeySecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the AWS secret access key for SigV4 authentication. | | Optional: \{\}
|
+| `awsRegion` _string_ | AWS region for SigV4 authentication. | | Optional: \{\}
|
+
+
+#### WorkbenchToolSentryConfig
+
+
+
+WorkbenchToolSentryConfig defines a sentry connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `url` _string_ | Optional Sentry API host (defaults to https://sentry.io; set for self-hosted). | | Optional: \{\}
|
+| `accessTokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the Sentry user auth token or internal integration token. | | Optional: \{\}
|
+
+
+#### WorkbenchToolSlackConfig
+
+
+
+WorkbenchToolSlackConfig defines a slack connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `botTokenSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the slack bot user OAuth token (xoxb-...). | | Optional: \{\}
|
#### WorkbenchToolSpec
@@ -5993,11 +6265,14 @@ _Appears in:_
| Field | Description | Default | Validation |
| --- | --- | --- | --- |
| `name` _string_ | The name of the tool (a-z, 0-9, underscores). If not set, metadata.name is used. | | Optional: \{\}
Pattern: `^[a-z0-9_]+$`
Type: string
|
-| `tool` _[WorkbenchToolType](#workbenchtooltype)_ | The type of tool. | | Enum: [HTTP ELASTIC DATADOG PROMETHEUS LOKI TEMPO SENTRY MCP LINEAR ATLASSIAN SPLUNK DYNATRACE CLOUDWATCH AZURE CLOUD JAEGER]
Required: \{\}
|
+| `tool` _[WorkbenchToolType](#workbenchtooltype)_ | The type of tool. | | Enum: [HTTP ELASTIC DATADOG PROMETHEUS LOKI TEMPO SENTRY MCP LINEAR ATLASSIAN SPLUNK DYNATRACE CLOUDWATCH AZURE CLOUD JAEGER EXA GITHUB SLACK TEAMS GITLAB BITBUCKET BITBUCKET_DATACENTER AZURE_DEVOPS PAGERDUTY OPENSEARCH LAMBDA CLOUD_RUN AZURE_FUNCTION DOCKER]
Required: \{\}
|
| `categories` _WorkbenchToolCategory array_ | Categories for the tool. | | Optional: \{\}
|
+| `approval` _boolean_ | Whether this tool requires approval before execution. | | Optional: \{\}
|
| `projectRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectreference-v1-core)_ | The project for this tool. | | Optional: \{\}
|
| `mcpServerRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectreference-v1-core)_ | The mcp server for this tool. | | Optional: \{\}
|
| `cloudConnectionRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectreference-v1-core)_ | The cloud connection for this tool (e.g. infrastructure cloud tools). | | Optional: \{\}
|
+| `scmConnectionRef` _[ObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#objectreference-v1-core)_ | The SCM connection for this tool (e.g. shared Git provider credentials). | | Optional: \{\}
|
+| `bindings` _[Bindings](#bindings)_ | Bindings define the read and write access policies for this tool. | | Optional: \{\}
|
| `configuration` _[WorkbenchToolConfiguration](#workbenchtoolconfiguration)_ | Tool configuration (e.g. HTTP). | | Optional: \{\}
|
| `reconciliation` _[Reconciliation](#reconciliation)_ | | | Optional: \{\}
|
@@ -6021,6 +6296,24 @@ _Appears in:_
| `passwordSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the basic auth password. | | Optional: \{\}
|
+#### WorkbenchToolTeamsConfig
+
+
+
+WorkbenchToolTeamsConfig defines a microsoft teams / graph connection.
+
+
+
+_Appears in:_
+- [WorkbenchToolConfiguration](#workbenchtoolconfiguration)
+
+| Field | Description | Default | Validation |
+| --- | --- | --- | --- |
+| `clientId` _string_ | Microsoft Entra application (client) id. | | Required: \{\}
|
+| `clientSecretSecretRef` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#secretkeyselector-v1-core)_ | Reference to a secret key containing the microsoft entra client secret. | | Required: \{\}
|
+| `tenantId` _string_ | Microsoft Entra tenant (directory) id. | | Required: \{\}
|
+
+
#### WorkbenchToolTempoConfig
diff --git a/go/controller/internal/controller/workbench_tool_controller.go b/go/controller/internal/controller/workbench_tool_controller.go
index fd99c905b9..b17fefdd92 100644
--- a/go/controller/internal/controller/workbench_tool_controller.go
+++ b/go/controller/internal/controller/workbench_tool_controller.go
@@ -10,6 +10,7 @@ import (
"github.com/pluralsh/console/go/controller/internal/credentials"
"github.com/samber/lo"
+ corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -101,14 +102,6 @@ func (in *WorkbenchToolReconciler) Reconcile(ctx context.Context, req reconcile.
// Mark resource as managed by this operator.
utils.MarkCondition(workbenchTool.SetCondition, v1alpha1.ReadonlyConditionType, v1.ConditionFalse, v1alpha1.ReadonlyConditionReason, "")
- // Get WorkbenchTool SHA that can be saved back in the status to check for changes
- changed, sha, err := workbenchTool.Diff(utils.HashObject)
- if err != nil {
- logger.Error(err, "unable to calculate workbench tool SHA")
- utils.MarkCondition(workbenchTool.SetCondition, v1alpha1.SynchronizedConditionType, v1.ConditionFalse, v1alpha1.SynchronizedConditionReasonError, err.Error())
- return ctrl.Result{}, err
- }
-
// Get the project for the workbench tool.
project, res, err := common.Project(ctx, in.Client, in.Scheme, workbenchTool)
if res != nil || err != nil {
@@ -127,8 +120,39 @@ func (in *WorkbenchToolReconciler) Reconcile(ctx context.Context, req reconcile.
return common.HandleRequeue(res, err, workbenchTool.SetCondition)
}
+ // Resolve ScmConnectionRef to get the SCM connection ID.
+ scmConnectionID, res, err := in.resolveScmConnectionRef(ctx, workbenchTool)
+ if res != nil || err != nil {
+ return common.HandleRequeue(res, err, workbenchTool.SetCondition)
+ }
+
+ // Resolve policy bindings.
+ readBindings, writeBindings, err := in.resolveBindings(workbenchTool)
+ if err != nil {
+ return common.HandleRequeue(nil, err, workbenchTool.SetCondition)
+ }
+
+ // Add controller refs to Docker auth secrets so credential rotation triggers reconcile.
+ if err := in.tryAddDockerOwnerRef(ctx, workbenchTool); err != nil {
+ utils.MarkCondition(workbenchTool.SetCondition, v1alpha1.SynchronizedConditionType, v1.ConditionFalse, v1alpha1.SynchronizedConditionReasonError, err.Error())
+ return ctrl.Result{}, err
+ }
+
+ attrs, err := in.attributes(ctx, workbenchTool, project.Status.ID, mcpServerID, cloudConnectionID, scmConnectionID, readBindings, writeBindings)
+ if err != nil {
+ return common.HandleRequeue(nil, err, workbenchTool.SetCondition)
+ }
+
+ // Hash resolved attributes (includes secret values) so credential rotation is detected.
+ changed, sha, err := workbenchTool.Diff(attrs, utils.HashObject)
+ if err != nil {
+ logger.Error(err, "unable to calculate workbench tool SHA")
+ utils.MarkCondition(workbenchTool.SetCondition, v1alpha1.SynchronizedConditionType, v1.ConditionFalse, v1alpha1.SynchronizedConditionReasonError, err.Error())
+ return ctrl.Result{}, err
+ }
+
// Sync WorkbenchTool CRD with the Console API
- apiWorkbenchTool, err := in.sync(ctx, workbenchTool, project, mcpServerID, cloudConnectionID, changed)
+ apiWorkbenchTool, err := in.sync(ctx, workbenchTool, attrs, changed)
if err != nil {
return common.HandleRequeue(nil, err, workbenchTool.SetCondition)
}
@@ -270,7 +294,46 @@ func (in *WorkbenchToolReconciler) resolveCloudConnectionRef(ctx context.Context
return cloudConnection.Status.ID, nil, nil
}
-func (in *WorkbenchToolReconciler) sync(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool, project *v1alpha1.Project, mcpServerID, cloudConnectionID *string, changed bool) (*console.WorkbenchToolFragment, error) {
+func (in *WorkbenchToolReconciler) resolveScmConnectionRef(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool) (*string, *ctrl.Result, error) {
+ ref := workbenchTool.Spec.ScmConnectionRef
+ if ref == nil {
+ return nil, nil, nil
+ }
+
+ scmConnection := &v1alpha1.ScmConnection{}
+ if err := in.Get(ctx, client.ObjectKey{Name: ref.Name, Namespace: ref.Namespace}, scmConnection); err != nil {
+ if errors.IsNotFound(err) {
+ return nil, new(common.Wait()), fmt.Errorf("ScmConnection not found: %s", err.Error())
+ }
+ return nil, nil, fmt.Errorf("failed to get ScmConnection: %s", err.Error())
+ }
+
+ if !scmConnection.Status.HasID() {
+ return nil, new(common.Wait()), fmt.Errorf("ScmConnection is not ready")
+ }
+
+ return scmConnection.Status.ID, nil, nil
+}
+
+func (in *WorkbenchToolReconciler) resolveBindings(workbenchTool *v1alpha1.WorkbenchTool) (readBindings, writeBindings []*console.PolicyBindingAttributes, err error) {
+ if workbenchTool.Spec.Bindings == nil {
+ return nil, nil, nil
+ }
+
+ readBindings, err = common.BindingsAttributes(workbenchTool.Spec.Bindings.Read)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ writeBindings, err = common.BindingsAttributes(workbenchTool.Spec.Bindings.Write)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return readBindings, writeBindings, nil
+}
+
+func (in *WorkbenchToolReconciler) sync(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool, attrs console.WorkbenchToolAttributes, changed bool) (*console.WorkbenchToolFragment, error) {
logger := log.FromContext(ctx)
existingWorkbenchTool, err := in.ConsoleClient.GetWorkbenchTool(ctx, nil, new(workbenchTool.ConsoleName()))
@@ -279,19 +342,11 @@ func (in *WorkbenchToolReconciler) sync(ctx context.Context, workbenchTool *v1al
return nil, err
}
- attrs, err := workbenchTool.Attributes(ctx, in.Client, project.Status.ID, mcpServerID, cloudConnectionID)
- if err != nil {
- return nil, err
- }
logger.Info(fmt.Sprintf("%s workbench tool does not exist, creating it", workbenchTool.ConsoleName()))
return in.ConsoleClient.CreateWorkbenchTool(ctx, attrs)
}
- if changed || in.cloudConnectionChanged(existingWorkbenchTool, cloudConnectionID) {
- attrs, err := workbenchTool.Attributes(ctx, in.Client, project.Status.ID, mcpServerID, cloudConnectionID)
- if err != nil {
- return nil, err
- }
+ if changed {
logger.Info(fmt.Sprintf("updating workbench tool %s", workbenchTool.ConsoleName()))
return in.ConsoleClient.UpdateWorkbenchTool(ctx, existingWorkbenchTool.ID, attrs)
}
@@ -299,13 +354,70 @@ func (in *WorkbenchToolReconciler) sync(ctx context.Context, workbenchTool *v1al
return existingWorkbenchTool, nil
}
-func (in *WorkbenchToolReconciler) cloudConnectionChanged(workbenchTool *console.WorkbenchToolFragment, cloudConnectionID *string) bool {
- existingCloudConnectionID := ""
- if workbenchTool.CloudConnection != nil {
- existingCloudConnectionID = workbenchTool.CloudConnection.ID
+func (in *WorkbenchToolReconciler) attributes(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool, projectID, mcpServerID, cloudConnectionID, scmConnectionID *string, readBindings, writeBindings []*console.PolicyBindingAttributes) (console.WorkbenchToolAttributes, error) {
+ attrs, err := workbenchTool.Attributes(ctx, in.Client, projectID, mcpServerID, cloudConnectionID, scmConnectionID, readBindings, writeBindings)
+ if err != nil {
+ return console.WorkbenchToolAttributes{}, err
+ }
+
+ if err := in.attachDockerAuth(ctx, workbenchTool, &attrs); err != nil {
+ return console.WorkbenchToolAttributes{}, err
+ }
+
+ return attrs, nil
+}
+
+func (in *WorkbenchToolReconciler) attachDockerAuth(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool, attrs *console.WorkbenchToolAttributes) error {
+ if workbenchTool.Spec.Configuration == nil || workbenchTool.Spec.Configuration.Docker == nil {
+ return nil
+ }
+
+ docker := workbenchTool.Spec.Configuration.Docker
+ authHelper := &HelmRepositoryAuth{Client: in.Client, Scheme: in.Scheme}
+ authAttrs, err := authHelper.HelmAuthAttributes(ctx, workbenchTool.Namespace, docker.Provider, docker.Auth)
+ if err != nil {
+ return err
+ }
+ if authAttrs == nil {
+ return nil
+ }
+
+ if attrs.Configuration == nil {
+ attrs.Configuration = &console.WorkbenchToolConfigurationAttributes{}
+ }
+ if attrs.Configuration.Docker == nil {
+ attrs.Configuration.Docker = &console.WorkbenchToolDockerConnectionAttributes{
+ URL: docker.URL,
+ Provider: docker.Provider,
+ }
+ }
+ attrs.Configuration.Docker.Auth = authAttrs
+ return nil
+}
+
+func (in *WorkbenchToolReconciler) tryAddDockerOwnerRef(ctx context.Context, workbenchTool *v1alpha1.WorkbenchTool) error {
+ if workbenchTool.Spec.Configuration == nil || workbenchTool.Spec.Configuration.Docker == nil {
+ return nil
+ }
+
+ authHelper := &HelmRepositoryAuth{Client: in.Client, Scheme: in.Scheme}
+ secretRef := authHelper.getAuthSecretRef(&v1alpha1.HelmRepository{
+ ObjectMeta: v1.ObjectMeta{Namespace: workbenchTool.Namespace},
+ Spec: v1alpha1.HelmRepositorySpec{
+ Provider: workbenchTool.Spec.Configuration.Docker.Provider,
+ Auth: workbenchTool.Spec.Configuration.Docker.Auth,
+ },
+ })
+ if secretRef == nil {
+ return nil
+ }
+
+ secret, err := utils.GetSecret(ctx, in.Client, secretRef)
+ if err != nil {
+ return err
}
- return existingCloudConnectionID != lo.FromPtr(cloudConnectionID)
+ return utils.TryAddControllerRef(ctx, in.Client, workbenchTool, secret, in.Scheme)
}
// SetupWithManager is responsible for initializing a new reconciler within the provided ctrl.Manager.
@@ -315,5 +427,6 @@ func (in *WorkbenchToolReconciler) SetupWithManager(mgr ctrl.Manager) error {
WithOptions(controller.Options{MaxConcurrentReconciles: 1}).
Watches(&v1alpha1.NamespaceCredentials{}, credentials.OnCredentialsChange(in.Client, new(v1alpha1.WorkbenchToolList))).
For(&v1alpha1.WorkbenchTool{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
+ Owns(&corev1.Secret{}, builder.WithPredicates(predicate.ResourceVersionChangedPredicate{})).
Complete(in)
}
diff --git a/go/controller/internal/controller/workbench_tool_controller_test.go b/go/controller/internal/controller/workbench_tool_controller_test.go
index 5ac0319fe6..0c7649df7c 100644
--- a/go/controller/internal/controller/workbench_tool_controller_test.go
+++ b/go/controller/internal/controller/workbench_tool_controller_test.go
@@ -486,4 +486,437 @@ var _ = Describe("Workbench Tool Controller", Ordered, func() {
Expect(err).NotTo(HaveOccurred())
})
})
+
+ Context("When reconciling a Docker tool with bearer auth", func() {
+ const (
+ workbenchToolName = "wt-docker"
+ workbenchToolSpecName = "wt_docker"
+ namespace = "default"
+ id = "docker-tool-123"
+ secretName = "docker-creds"
+ initialToken = "initial-registry-token"
+ rotatedToken = "rotated-registry-token"
+ )
+
+ ctx := context.Background()
+ typeNamespacedName := types.NamespacedName{Name: workbenchToolName, Namespace: namespace}
+ secretNamespacedName := types.NamespacedName{Name: secretName, Namespace: namespace}
+
+ BeforeAll(func() {
+ By("creating the Docker credentials secret")
+ Expect(common.MaybeCreate(k8sClient, &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: secretName,
+ Namespace: namespace,
+ },
+ Data: map[string][]byte{
+ "token": []byte(initialToken),
+ },
+ }, nil)).To(Succeed())
+
+ By("creating the Docker WorkbenchTool resource")
+ err := k8sClient.Get(ctx, typeNamespacedName, &v1alpha1.WorkbenchTool{})
+ if err != nil && errors.IsNotFound(err) {
+ Expect(common.MaybeCreate(k8sClient, &v1alpha1.WorkbenchTool{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: workbenchToolName,
+ Namespace: namespace,
+ },
+ Spec: v1alpha1.WorkbenchToolSpec{
+ Name: lo.ToPtr(workbenchToolSpecName),
+ Tool: gqlclient.WorkbenchToolTypeDocker,
+ Categories: []gqlclient.WorkbenchToolCategory{gqlclient.WorkbenchToolCategoryIntegration},
+ Approval: lo.ToPtr(true),
+ Configuration: &v1alpha1.WorkbenchToolConfiguration{
+ Docker: &v1alpha1.WorkbenchToolDockerConfig{
+ URL: lo.ToPtr("registry-1.docker.io"),
+ Provider: lo.ToPtr(gqlclient.HelmAuthProviderBearer),
+ Auth: &v1alpha1.HelmRepositoryAuth{
+ Proxy: &v1alpha1.HttpProxyConfiguration{
+ URL: "http://proxy.example.com:8080",
+ NoProxy: lo.ToPtr("localhost,127.0.0.1"),
+ },
+ Bearer: &v1alpha1.HelmRepositoryAuthBearer{
+ TokenSecretKeyRef: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
+ Key: "token",
+ },
+ },
+ },
+ },
+ },
+ },
+ }, nil)).To(Succeed())
+ }
+ })
+
+ AfterAll(func() {
+ workbenchTool := &v1alpha1.WorkbenchTool{}
+ if err := k8sClient.Get(ctx, typeNamespacedName, workbenchTool); err == nil {
+ By("cleaning up WorkbenchTool")
+ Expect(k8sClient.Delete(ctx, workbenchTool)).To(Succeed())
+ }
+ secret := &corev1.Secret{}
+ if err := k8sClient.Get(ctx, secretNamespacedName, secret); err == nil {
+ Expect(k8sClient.Delete(ctx, secret)).To(Succeed())
+ }
+ })
+
+ It("should resolve Docker auth, proxy, approval and own the secret", func() {
+ fakeConsoleClient := mocks.NewConsoleClientMock(mocks.TestingT)
+ fakeConsoleClient.On("UseCredentials", mock.Anything, mock.Anything).Return("", nil)
+ fakeConsoleClient.On("GetWorkbenchToolTiny", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("GetWorkbenchTool", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("CreateWorkbenchTool", mock.Anything, mock.MatchedBy(func(attrs gqlclient.WorkbenchToolAttributes) bool {
+ if attrs.Approval == nil || !*attrs.Approval {
+ return false
+ }
+ if attrs.Configuration == nil || attrs.Configuration.Docker == nil || attrs.Configuration.Docker.Auth == nil {
+ return false
+ }
+ auth := attrs.Configuration.Docker.Auth
+ if auth.Bearer == nil || auth.Bearer.Token != initialToken {
+ return false
+ }
+ if auth.Proxy == nil || auth.Proxy.URL != "http://proxy.example.com:8080" {
+ return false
+ }
+ return auth.Proxy.Noproxy != nil && *auth.Proxy.Noproxy == "localhost,127.0.0.1"
+ })).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+
+ reconciler := &controller.WorkbenchToolReconciler{
+ Client: k8sClient,
+ Scheme: k8sClient.Scheme(),
+ ConsoleClient: fakeConsoleClient,
+ CredentialsCache: nil,
+ }
+
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
+ Expect(err).NotTo(HaveOccurred())
+
+ wt := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, wt)).To(Succeed())
+ Expect(wt.Status.ID).To(Equal(lo.ToPtr(id)))
+ Expect(wt.Status.SHA).NotTo(BeNil())
+
+ secret := &corev1.Secret{}
+ Expect(k8sClient.Get(ctx, secretNamespacedName, secret)).To(Succeed())
+ Expect(secret.OwnerReferences).NotTo(BeEmpty())
+ Expect(secret.OwnerReferences[0].Kind).To(Equal("WorkbenchTool"))
+ Expect(secret.OwnerReferences[0].Name).To(Equal(workbenchToolName))
+ })
+
+ It("should update when Docker secret credentials are rotated without a spec change", func() {
+ wt := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, wt)).To(Succeed())
+ Expect(wt.Status.SHA).NotTo(BeNil())
+ currentSHA := *wt.Status.SHA
+
+ secret := &corev1.Secret{}
+ Expect(k8sClient.Get(ctx, secretNamespacedName, secret)).To(Succeed())
+ secret.Data["token"] = []byte(rotatedToken)
+ Expect(k8sClient.Update(ctx, secret)).To(Succeed())
+
+ Expect(common.MaybePatch(k8sClient, &v1alpha1.WorkbenchTool{
+ ObjectMeta: metav1.ObjectMeta{Name: workbenchToolName, Namespace: namespace},
+ }, func(p *v1alpha1.WorkbenchTool) {
+ p.Status.ID = lo.ToPtr(id)
+ p.Status.SHA = lo.ToPtr(currentSHA)
+ })).To(Succeed())
+
+ fakeConsoleClient := mocks.NewConsoleClientMock(mocks.TestingT)
+ fakeConsoleClient.On("UseCredentials", mock.Anything, mock.Anything).Return("", nil)
+ fakeConsoleClient.On("GetWorkbenchTool", mock.Anything, mock.Anything, mock.Anything).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+ fakeConsoleClient.On("UpdateWorkbenchTool", mock.Anything, id, mock.MatchedBy(func(attrs gqlclient.WorkbenchToolAttributes) bool {
+ return attrs.Configuration != nil &&
+ attrs.Configuration.Docker != nil &&
+ attrs.Configuration.Docker.Auth != nil &&
+ attrs.Configuration.Docker.Auth.Bearer != nil &&
+ attrs.Configuration.Docker.Auth.Bearer.Token == rotatedToken
+ })).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+
+ reconciler := &controller.WorkbenchToolReconciler{
+ Client: k8sClient,
+ Scheme: k8sClient.Scheme(),
+ ConsoleClient: fakeConsoleClient,
+ CredentialsCache: nil,
+ }
+
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
+ Expect(err).NotTo(HaveOccurred())
+
+ updated := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, updated)).To(Succeed())
+ Expect(updated.Status.SHA).NotTo(BeNil())
+ Expect(*updated.Status.SHA).NotTo(Equal(currentSHA))
+ })
+ })
+
+ Context("When reconciling a GitHub tool with ScmConnectionRef", func() {
+ const (
+ workbenchToolName = "wt-github"
+ workbenchToolSpecName = "wt_github"
+ namespace = "default"
+ id = "github-tool-123"
+ scmConnectionName = "wt-github-scm"
+ scmConnectionID = "scm-conn-id-123"
+ secretName = "github-tool-creds"
+ )
+
+ ctx := context.Background()
+ typeNamespacedName := types.NamespacedName{Name: workbenchToolName, Namespace: namespace}
+
+ BeforeAll(func() {
+ By("creating the GitHub credentials secret")
+ Expect(common.MaybeCreate(k8sClient, &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: secretName,
+ Namespace: namespace,
+ },
+ Data: map[string][]byte{
+ "accessToken": []byte("ghp_test_token"),
+ },
+ }, nil)).To(Succeed())
+
+ By("creating the ScmConnection resource with a status ID")
+ Expect(common.MaybeCreate(k8sClient, &v1alpha1.ScmConnection{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: scmConnectionName,
+ },
+ Spec: v1alpha1.ScmConnectionSpec{
+ Name: scmConnectionName,
+ Type: gqlclient.ScmTypeGithub,
+ },
+ }, func(p *v1alpha1.ScmConnection) {
+ p.Status.ID = lo.ToPtr(scmConnectionID)
+ })).To(Succeed())
+
+ By("creating the WorkbenchTool resource")
+ err := k8sClient.Get(ctx, typeNamespacedName, &v1alpha1.WorkbenchTool{})
+ if err != nil && errors.IsNotFound(err) {
+ Expect(common.MaybeCreate(k8sClient, &v1alpha1.WorkbenchTool{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: workbenchToolName,
+ Namespace: namespace,
+ },
+ Spec: v1alpha1.WorkbenchToolSpec{
+ Name: lo.ToPtr(workbenchToolSpecName),
+ Tool: gqlclient.WorkbenchToolTypeGithub,
+ Categories: []gqlclient.WorkbenchToolCategory{
+ gqlclient.WorkbenchToolCategoryScm,
+ },
+ ScmConnectionRef: &corev1.ObjectReference{
+ Name: scmConnectionName,
+ },
+ Bindings: &v1alpha1.Bindings{
+ Read: []v1alpha1.Binding{
+ {UserID: lo.ToPtr("user-read-id")},
+ },
+ Write: []v1alpha1.Binding{
+ {UserID: lo.ToPtr("user-write-id")},
+ },
+ },
+ Configuration: &v1alpha1.WorkbenchToolConfiguration{
+ Github: &v1alpha1.WorkbenchToolGithubConfig{
+ URL: lo.ToPtr("https://api.github.com/"),
+ Toolset: lo.ToPtr("default"),
+ AccessTokenSecretRef: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
+ Key: "accessToken",
+ },
+ },
+ },
+ },
+ }, nil)).To(Succeed())
+ }
+ })
+
+ AfterAll(func() {
+ workbenchTool := &v1alpha1.WorkbenchTool{}
+ if err := k8sClient.Get(ctx, typeNamespacedName, workbenchTool); err == nil {
+ By("cleaning up WorkbenchTool")
+ Expect(k8sClient.Delete(ctx, workbenchTool)).To(Succeed())
+ }
+ scm := &v1alpha1.ScmConnection{}
+ if err := k8sClient.Get(ctx, types.NamespacedName{Name: scmConnectionName}, scm); err == nil {
+ Expect(k8sClient.Delete(ctx, scm)).To(Succeed())
+ }
+ secret := &corev1.Secret{}
+ if err := k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret); err == nil {
+ Expect(k8sClient.Delete(ctx, secret)).To(Succeed())
+ }
+ })
+
+ It("should resolve ScmConnectionRef, bindings and GitHub configuration", func() {
+ fakeConsoleClient := mocks.NewConsoleClientMock(mocks.TestingT)
+ fakeConsoleClient.On("UseCredentials", mock.Anything, mock.Anything).Return("", nil)
+ fakeConsoleClient.On("GetWorkbenchToolTiny", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("GetWorkbenchTool", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("CreateWorkbenchTool", mock.Anything, mock.MatchedBy(func(attrs gqlclient.WorkbenchToolAttributes) bool {
+ if attrs.ScmConnectionID == nil || *attrs.ScmConnectionID != scmConnectionID {
+ return false
+ }
+ if len(attrs.ReadBindings) != 1 || attrs.ReadBindings[0].UserID == nil || *attrs.ReadBindings[0].UserID != "user-read-id" {
+ return false
+ }
+ if len(attrs.WriteBindings) != 1 || attrs.WriteBindings[0].UserID == nil || *attrs.WriteBindings[0].UserID != "user-write-id" {
+ return false
+ }
+ if attrs.Configuration == nil || attrs.Configuration.Github == nil {
+ return false
+ }
+ return attrs.Configuration.Github.AccessToken != nil && *attrs.Configuration.Github.AccessToken == "ghp_test_token"
+ })).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+
+ reconciler := &controller.WorkbenchToolReconciler{
+ Client: k8sClient,
+ Scheme: k8sClient.Scheme(),
+ ConsoleClient: fakeConsoleClient,
+ CredentialsCache: nil,
+ }
+
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
+ Expect(err).NotTo(HaveOccurred())
+
+ wt := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, wt)).To(Succeed())
+ Expect(wt.Status.ID).To(Equal(lo.ToPtr(id)))
+ })
+ })
+
+ Context("When reconciling Prometheus secret rotation", func() {
+ const (
+ workbenchToolName = "wt-prometheus-rotate"
+ workbenchToolSpecName = "wt_prometheus_rotate"
+ namespace = "default"
+ id = "prometheus-rotate-123"
+ secretName = "prometheus-rotate-creds"
+ initialToken = "prom-token-v1"
+ rotatedToken = "prom-token-v2"
+ )
+
+ ctx := context.Background()
+ typeNamespacedName := types.NamespacedName{Name: workbenchToolName, Namespace: namespace}
+ secretNamespacedName := types.NamespacedName{Name: secretName, Namespace: namespace}
+
+ BeforeAll(func() {
+ By("creating the Prometheus credentials secret")
+ Expect(common.MaybeCreate(k8sClient, &corev1.Secret{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: secretName,
+ Namespace: namespace,
+ },
+ Data: map[string][]byte{
+ "token": []byte(initialToken),
+ },
+ }, nil)).To(Succeed())
+
+ By("creating the Prometheus WorkbenchTool resource")
+ err := k8sClient.Get(ctx, typeNamespacedName, &v1alpha1.WorkbenchTool{})
+ if err != nil && errors.IsNotFound(err) {
+ Expect(common.MaybeCreate(k8sClient, &v1alpha1.WorkbenchTool{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: workbenchToolName,
+ Namespace: namespace,
+ },
+ Spec: v1alpha1.WorkbenchToolSpec{
+ Name: lo.ToPtr(workbenchToolSpecName),
+ Tool: gqlclient.WorkbenchToolTypePrometheus,
+ Configuration: &v1alpha1.WorkbenchToolConfiguration{
+ Prometheus: &v1alpha1.WorkbenchToolPrometheusConfig{
+ URL: "https://prometheus.example.com",
+ TokenSecretRef: &corev1.SecretKeySelector{
+ LocalObjectReference: corev1.LocalObjectReference{Name: secretName},
+ Key: "token",
+ },
+ AWSSigv4: lo.ToPtr(true),
+ AWSRegion: lo.ToPtr("us-east-1"),
+ },
+ },
+ },
+ }, nil)).To(Succeed())
+ }
+ })
+
+ AfterAll(func() {
+ workbenchTool := &v1alpha1.WorkbenchTool{}
+ if err := k8sClient.Get(ctx, typeNamespacedName, workbenchTool); err == nil {
+ Expect(k8sClient.Delete(ctx, workbenchTool)).To(Succeed())
+ }
+ secret := &corev1.Secret{}
+ if err := k8sClient.Get(ctx, secretNamespacedName, secret); err == nil {
+ Expect(k8sClient.Delete(ctx, secret)).To(Succeed())
+ }
+ })
+
+ It("should create with resolved Prometheus secrets and AWS SigV4 fields", func() {
+ fakeConsoleClient := mocks.NewConsoleClientMock(mocks.TestingT)
+ fakeConsoleClient.On("UseCredentials", mock.Anything, mock.Anything).Return("", nil)
+ fakeConsoleClient.On("GetWorkbenchToolTiny", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("GetWorkbenchTool", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.NewNotFound(schema.GroupResource{}, id))
+ fakeConsoleClient.On("CreateWorkbenchTool", mock.Anything, mock.MatchedBy(func(attrs gqlclient.WorkbenchToolAttributes) bool {
+ if attrs.Configuration == nil || attrs.Configuration.Prometheus == nil {
+ return false
+ }
+ prom := attrs.Configuration.Prometheus
+ return prom.Token != nil && *prom.Token == initialToken &&
+ prom.AWSSigv4 != nil && *prom.AWSSigv4 &&
+ prom.AWSRegion != nil && *prom.AWSRegion == "us-east-1"
+ })).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+
+ reconciler := &controller.WorkbenchToolReconciler{
+ Client: k8sClient,
+ Scheme: k8sClient.Scheme(),
+ ConsoleClient: fakeConsoleClient,
+ CredentialsCache: nil,
+ }
+
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
+ Expect(err).NotTo(HaveOccurred())
+ })
+
+ It("should update when Prometheus secret credentials are rotated without a spec change", func() {
+ wt := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, wt)).To(Succeed())
+ Expect(wt.Status.SHA).NotTo(BeNil())
+ currentSHA := *wt.Status.SHA
+
+ secret := &corev1.Secret{}
+ Expect(k8sClient.Get(ctx, secretNamespacedName, secret)).To(Succeed())
+ secret.Data["token"] = []byte(rotatedToken)
+ Expect(k8sClient.Update(ctx, secret)).To(Succeed())
+
+ Expect(common.MaybePatch(k8sClient, &v1alpha1.WorkbenchTool{
+ ObjectMeta: metav1.ObjectMeta{Name: workbenchToolName, Namespace: namespace},
+ }, func(p *v1alpha1.WorkbenchTool) {
+ p.Status.ID = lo.ToPtr(id)
+ p.Status.SHA = lo.ToPtr(currentSHA)
+ })).To(Succeed())
+
+ fakeConsoleClient := mocks.NewConsoleClientMock(mocks.TestingT)
+ fakeConsoleClient.On("UseCredentials", mock.Anything, mock.Anything).Return("", nil)
+ fakeConsoleClient.On("GetWorkbenchTool", mock.Anything, mock.Anything, mock.Anything).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+ fakeConsoleClient.On("UpdateWorkbenchTool", mock.Anything, id, mock.MatchedBy(func(attrs gqlclient.WorkbenchToolAttributes) bool {
+ return attrs.Configuration != nil &&
+ attrs.Configuration.Prometheus != nil &&
+ attrs.Configuration.Prometheus.Token != nil &&
+ *attrs.Configuration.Prometheus.Token == rotatedToken
+ })).Return(&gqlclient.WorkbenchToolFragment{ID: id}, nil)
+
+ reconciler := &controller.WorkbenchToolReconciler{
+ Client: k8sClient,
+ Scheme: k8sClient.Scheme(),
+ ConsoleClient: fakeConsoleClient,
+ CredentialsCache: nil,
+ }
+
+ _, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: typeNamespacedName})
+ Expect(err).NotTo(HaveOccurred())
+
+ updated := &v1alpha1.WorkbenchTool{}
+ Expect(k8sClient.Get(ctx, typeNamespacedName, updated)).To(Succeed())
+ Expect(updated.Status.SHA).NotTo(BeNil())
+ Expect(*updated.Status.SHA).NotTo(Equal(currentSHA))
+ })
+ })
})