From d1be03edd03697a4f726315c20089365cb528b3d Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Fri, 13 Jun 2025 16:15:41 -0500 Subject: [PATCH 01/27] Update USAGEGUIDE.md --- USAGEGUIDE.md | 232 +++++++++++++------------------------------------- 1 file changed, 60 insertions(+), 172 deletions(-) diff --git a/USAGEGUIDE.md b/USAGEGUIDE.md index 956c09c..b94a9e1 100644 --- a/USAGEGUIDE.md +++ b/USAGEGUIDE.md @@ -5,143 +5,50 @@ ## Table of Contents -- [Configuration Options](#configuration-options) -- [Prerequisites](#prerequisites) -- [Deploying 1Password Connect to Kubernetes](#deploying-1password-connect-to-kubernetes) -- [Kubernetes Operator Deployment With Connect](#kubernetes-operator-deployment-with-connect) -- [Kubernetes Operator Deployment With Service Account](#kubernetes-operator-deployment-with-service-account) -- [Usage](#usage) -- [Configuring Automatic Rolling Restarts of Deployments](#configuring-automatic-rolling-restarts-of-deployments) -- [Development](#development) +1. [Prerequisites](#prerequisites) +2. [Configuration Options](#configuration-options) +3. [Use Kubernetes Operator with Service Account](#use-kubernetes-operator-with-service-account) + - [Create a Service Account](#1-create-a-service-account) + - [Create a Kubernetes secret](#2-create-a-kubernetes-secret-for-the-service-account) + - [Deploy the Operator](#3-deploy-the-operator) +4. [Use Kubernetes Operator with Connect](#use-kubernetes-operator-with-connect) + - [Deploy with Helm](#1-deploy-with-helm) + - [Deploy manually](#2-deploy-manually) +5. [Logging level](#logging-level) +6. [Usage examples](#usage-examples) +7. [How 1Password Items Map to Kubernetes Secrets](#how-1password-items-map-to-kubernetes-secrets) +8. [Configuring Automatic Rolling Restarts of Deployments](#configuring-automatic-rolling-restarts-of-deployments) +9. [Development](#development) + +--- ## Prerequisites - [1Password Command Line Tool Installed](https://1password.com/downloads/command-line/) - [`kubectl` installed](https://kubernetes.io/docs/tasks/tools/install-kubectl/) - [`docker` installed](https://docs.docker.com/get-docker/) -- [A `1password-credentials.json` file generated and a 1Password Connect API Token issued for the K8s Operator integration](https://developer.1password.com/docs/connect/get-started/#step-1-set-up-a-secrets-automation-workflow) + +--- ## Configuration options There are 2 ways 1Password Operator can talk to 1Password servers: - **Connect**: It uses the 1Password Connect API to access items in 1Password. - **Service Account**: It uses [1Password SDK](https://developer.1password.com/docs/sdks/) and [Service Account](https://developer.1password.com/docs/service-accounts) to access items in 1Password. -## Deploying 1Password Connect to Kubernetes +--- -If 1Password Connect is already running, you can skip this step. +## Use Kubernetes Operator with Service Account -There are options to deploy 1Password Connect: - -- [Deploy with Helm](#deploy-with-helm) -- [Deploy using the Connect Operator](#deploy-using-the-connect-operator) - -### Deploy with Helm - -The 1Password Connect Helm Chart helps to simplify the deployment of 1Password Connect and the 1Password Connect Kubernetes Operator to Kubernetes. - -[The 1Password Connect Helm Chart can be found here.](https://github.com/1Password/connect-helm-charts) - -### Deploy using the Connect Operator - -This guide will provide a quickstart option for deploying a default configuration of 1Password Connect via starting the deploying the 1Password Connect Operator, however, it is recommended that you instead deploy your own manifest file if customization of the 1Password Connect deployment is desired. - -Encode the `1password-credentials.json` file you generated in the prerequisite steps and save it to a file named `op-session`: - -```bash -cat 1password-credentials.json | base64 | \ - tr '/+' '_-' | tr -d '=' | tr -d '\n' > op-session -``` - -Create a Kubernetes secret from the op-session file: - -```bash -kubectl create secret generic op-credentials --from-file=op-session -``` - -Add the following environment variable to the onepassword-connect-operator container in `/config/manager/manager.yaml`: - -```yaml -- name: MANAGE_CONNECT - value: "true" -``` - -Adding this environment variable will have the operator automatically deploy a default configuration of 1Password Connect to the current namespace. - -## Kubernetes Operator Deployment with Connect - -#### Create Kubernetes Secret for OP_CONNECT_TOKEN #### - -Create a Connect token for the operator and save it as a Kubernetes Secret: - -```bash -kubectl create secret generic onepassword-token --from-literal=token="" -``` - -If you do not have a token for the operator, you can generate a token and save it to Kubernetes with the following command: - -```bash -kubectl create secret generic onepassword-token --from-literal=token=$(op create connect token op-k8s-operator --vault ) -``` - -**Deploying the Operator** - -An sample Deployment yaml can be found at `/config/manager/manager.yaml`. - -To further configure the 1Password Kubernetes Operator the following Environment variables can be set in the operator yaml: - -- **OP_CONNECT_HOST** *(required)*: Specifies the host name within Kubernetes in which to access the 1Password Connect. -- **WATCH_NAMESPACE:** *(default: watch all namespaces)*: Comma separated list of what Namespaces to watch for changes. -- **POLLING_INTERVAL** *(default: 600)*: The number of seconds the 1Password Kubernetes Operator will wait before checking for updates from 1Password Connect. -- **MANAGE_CONNECT** *(default: false)*: If set to true, on deployment of the operator, a default configuration of the OnePassword Connect Service will be deployed to the current namespace. -- **AUTO_RESTART** (default: false): If set to true, the operator will restart any deployment using a secret from 1Password Connect. This can be overwritten by namespace, deployment, or individual secret. More details on AUTO_RESTART can be found in the ["Configuring Automatic Rolling Restarts of Deployments"](#configuring-automatic-rolling-restarts-of-deployments) section. - -You can also set the logging level by setting `--zap-log-level` as an arg on the containers to either `debug`, `info` or `error`. (Note: the default value is `debug`.) - -Example: -```yaml -. -. -. -containers: - - command: - - /manager - args: - - --leader-elect - - --zap-log-level=info - image: 1password/onepassword-operator:latest -. -. -. -``` -To deploy the operator, simply run the following command: - -```shell -make deploy -``` - -**Undeploy Operator** - -``` -make undeploy -``` - -## Kubernetes Operator Deployment with Service Account - -#### Create Kubernetes Secret for OP_SERVICE_ACCOUNT_TOKEN #### - -Create a Service Account token for the operator and save it as a Kubernetes Secret: +### 1. [Create a service account](https://developer.1password.com/docs/service-accounts/get-started#create-a-service-account) +### 2. Create a Kubernetes secret for the Service Account +- Set `OP_SERVICE_ACCOUNT_TOKEN` environment variable to the service account token you created in the previous step. This token will be used by the operator to access 1Password items. +- Create Kubernetes secret: ```bash kubectl create secret generic onepassword-service-account-token --from-literal=token="$OP_SERVICE_ACCOUNT_TOKEN" ``` -If you do not have a token for the operator, you can generate a token and save it to Kubernetes with the following command: - -```bash -kubectl create secret generic onepassword-service-account-token --from-literal=token=$(op service-account create my-service-account --vault Dev:read_items --vault Test:read_items,write_items) -``` - -**Deploying the Operator** +### 3. Deploy the Operator An sample Deployment yaml can be found at `/config/manager/manager.yaml`. To use Operator with Service Account, you need to set the `OP_SERVICE_ACCOUNT_TOKEN` environment variable in the `/config/manager/manager.yaml`. And remove `OP_CONNECT_TOKEN` and `OP_CONNECT_HOST` environment variables. @@ -153,24 +60,6 @@ To further configure the 1Password Kubernetes Operator the following Environment - **POLLING_INTERVAL** *(default: 600)*: The number of seconds the 1Password Kubernetes Operator will wait before checking for updates from 1Password. - **AUTO_RESTART** (default: false): If set to true, the operator will restart any deployment using a secret from 1Password. This can be overwritten by namespace, deployment, or individual secret. More details on AUTO_RESTART can be found in the ["Configuring Automatic Rolling Restarts of Deployments"](#configuring-automatic-rolling-restarts-of-deployments) section. -You can also set the logging level by setting `--zap-log-level` as an arg on the containers to either `debug`, `info` or `error`. (Note: the default value is `debug`.) - -Example: -```yaml -. -. -. -containers: - - command: - - /manager - args: - - --leader-elect - - --zap-log-level=info - image: 1password/onepassword-operator:latest -. -. -. -``` To deploy the operator, simply run the following command: ```shell @@ -183,59 +72,56 @@ make deploy make undeploy ``` -## Usage +--- -To create a Kubernetes Secret from a 1Password item, create a yaml file with the following +## Use Kubernetes Operator with Connect +### 1. [Deploy with Helm](https://developer.1password.com/docs/k8s/operator/?deployment-type=helm#helm-step-1) +### 2. [Deploy manually](https://developer.1password.com/docs/k8s/operator/?deployment-type=manual#manual-step-1) + +To further configure the 1Password Kubernetes Operator the following Environment variables can be set in the operator yaml: + +- **OP_CONNECT_HOST** *(required)*: Specifies the host name within Kubernetes in which to access the 1Password Connect. +- **WATCH_NAMESPACE:** *(default: watch all namespaces)*: Comma separated list of what Namespaces to watch for changes. +- **POLLING_INTERVAL** *(default: 600)*: The number of seconds the 1Password Kubernetes Operator will wait before checking for updates from 1Password Connect. +- **MANAGE_CONNECT** *(default: false)*: If set to true, on deployment of the operator, a default configuration of the OnePassword Connect Service will be deployed to the current namespace. +- **AUTO_RESTART** (default: false): If set to true, the operator will restart any deployment using a secret from 1Password Connect. This can be overwritten by namespace, deployment, or individual secret. More details on AUTO_RESTART can be found in the ["Configuring Automatic Rolling Restarts of Deployments"](#configuring-automatic-rolling-restarts-of-deployments) section. + +--- + +## Logging level +You can set the logging level by setting `--zap-log-level` as an arg on the containers to either `debug`, `info` or `error`. The default value is `debug`. + +Example: ```yaml -apiVersion: onepassword.com/v1 -kind: OnePasswordItem -metadata: - name: #this name will also be used for naming the generated kubernetes secret -spec: - itemPath: "vaults//items/" +.... +containers: + - command: + - /manager + args: + - --leader-elect + - --zap-log-level=info + image: 1password/onepassword-operator:latest +.... ``` -Deploy the OnePasswordItem to Kubernetes: +--- -```bash -kubectl apply -f .yaml -``` +## [Usage examples](https://developer.1password.com/docs/k8s/operator/?deployment-type=manual#usage-examples) -To test that the Kubernetes Secret check that the following command returns a secret: +--- -```bash -kubectl get secret -``` - -**Note:** Deleting the `OnePasswordItem` that you've created will automatically delete the created Kubernetes Secret. - -To create a single Kubernetes Secret for a deployment, add the following annotations to the deployment metadata: - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: deployment-example - annotations: - operator.1password.io/item-path: "vaults//items/" - operator.1password.io/item-name: "" -``` - -Applying this yaml file will create a Kubernetes Secret with the name `` and contents from the location specified at the specified Item Path. +## How 1Password Items Map to Kubernetes Secrets The contents of the Kubernetes secret will be key-value pairs in which the keys are the fields of the 1Password item and the values are the corresponding values stored in 1Password. In case of fields that store files, the file's contents will be used as the value. Within an item, if both a field storing a file and a field of another type have the same name, the file field will be ignored and the other field will take precedence. -**Note:** Deleting the Deployment that you've created will automatically delete the created Kubernetes Secret only if the deployment is still annotated with `operator.1password.io/item-path` and `operator.1password.io/item-name` and no other deployment is using the secret. +Deleting the Deployment that you've created will automatically delete the created Kubernetes Secret only if the deployment is still annotated with `operator.1password.io/item-path` and `operator.1password.io/item-name` and no other deployment is using the secret. If a 1Password Item that is linked to a Kubernetes Secret is updated within the POLLING_INTERVAL the associated Kubernetes Secret will be updated. However, if you do not want a specific secret to be updated you can add the tag `operator.1password.io:ignore-secret` to the item stored in 1Password. While this tag is in place, any updates made to an item will not trigger an update to the associated secret in Kubernetes. ---- - -**NOTE** If multiple 1Password vaults/items have the same `title` when using a title in the access path, the desired action will be performed on the oldest vault/item. @@ -302,6 +188,8 @@ metadata: If the value is not set, the auto restart settings on the deployment will be used. +--- + ## Development ### How it works From 0582c2d6e1b3100674dd5b2b7e7c5b1fc00b27d2 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Fri, 13 Jun 2025 16:22:18 -0500 Subject: [PATCH 02/27] Bump go version to 1.24 --- Dockerfile | 2 +- go.mod | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 207ceb3..385d016 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.22 as builder +FROM golang:1.24 as builder ARG TARGETOS ARG TARGETARCH diff --git a/go.mod b/go.mod index d383404..bf42587 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/1Password/onepassword-operator -go 1.22.0 +go 1.24 -toolchain go1.24.1 +toolchain go1.24.4 require ( github.com/1Password/connect-sdk-go v1.5.3 From 64aad3d573681e9212f5b7bb9369003b07ffebc6 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Fri, 13 Jun 2025 16:23:45 -0500 Subject: [PATCH 03/27] Revert version change, as should be done in the release MR --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index c46e83f..3557c0f 100644 --- a/version/version.go +++ b/version/version.go @@ -1,6 +1,6 @@ package version var ( - OperatorVersion = "1.9.0" + OperatorVersion = "1.8.1" OperatorSDKVersion = "1.34.1" ) From 475860a364db9d7021bf847353239b5ad75c030b Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 19:43:45 -0500 Subject: [PATCH 04/27] Make changelog description more detailed --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7aa83ba..d43eb48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ # v1.9.0 ## Features - * Support Service Accounts. {#160} + * Support fetching secrets using Service Accounts to authenticate with 1Password. {#160} --- From cff4d194ba72f920ad1738e152ac8350c310c023 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 19:45:23 -0500 Subject: [PATCH 05/27] Update constructor function name --- cmd/main.go | 2 +- pkg/onepassword/client/client.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 3ee68f7..e096a5f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -152,7 +152,7 @@ func main() { } // Setup One Password Client - opClient, err := opclient.NewClient(version.OperatorVersion) + opClient, err := opclient.NewFromEnvironment(version.OperatorVersion) if err != nil { setupLog.Error(err, "unable to create 1Password client") os.Exit(1) diff --git a/pkg/onepassword/client/client.go b/pkg/onepassword/client/client.go index 7147381..52db568 100644 --- a/pkg/onepassword/client/client.go +++ b/pkg/onepassword/client/client.go @@ -18,8 +18,8 @@ type Client interface { GetVaultsByTitle(title string) ([]model.Vault, error) } -// NewClient creates a new 1Password client based on the provided configuration. -func NewClient(integrationVersion string) (Client, error) { +// NewFromEnvironment creates a new 1Password client based on the provided configuration. +func NewFromEnvironment(integrationVersion string) (Client, error) { connectHost, _ := os.LookupEnv("OP_CONNECT_HOST") connectToken, _ := os.LookupEnv("OP_CONNECT_TOKEN") serviceAccountToken, _ := os.LookupEnv("OP_SERVICE_ACCOUNT_TOKEN") From 1fa5bccec2c97b73e5d2095afde70aa102f06340 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:03:36 -0500 Subject: [PATCH 06/27] Upse `copy` to copy tags --- pkg/onepassword/model/item.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/onepassword/model/item.go b/pkg/onepassword/model/item.go index 9066204..ebf13e4 100644 --- a/pkg/onepassword/model/item.go +++ b/pkg/onepassword/model/item.go @@ -52,9 +52,8 @@ func (i *Item) FromSDKItem(item *sdk.Item) { i.VaultID = item.VaultID i.Version = int(item.Version) - for _, tag := range item.Tags { - i.Tags = append(i.Tags, tag) - } + i.Tags = make([]string, len(item.Tags)) + copy(i.Tags, item.Tags) for _, field := range item.Fields { i.Fields = append(i.Fields, ItemField{ @@ -79,9 +78,8 @@ func (i *Item) FromSDKItemOverview(item *sdk.ItemOverview) { i.ID = item.ID i.VaultID = item.VaultID - for _, tag := range item.Tags { - i.Tags = append(i.Tags, tag) - } + i.Tags = make([]string, len(item.Tags)) + copy(i.Tags, item.Tags) i.CreatedAt = item.CreatedAt } From 922f3c8929763ac3f4d1a16f830c43a3e4e04d66 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:07:29 -0500 Subject: [PATCH 07/27] Map `CreatedAt` --- pkg/onepassword/model/vault.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/onepassword/model/vault.go b/pkg/onepassword/model/vault.go index e90e492..5cf26e1 100644 --- a/pkg/onepassword/model/vault.go +++ b/pkg/onepassword/model/vault.go @@ -19,5 +19,5 @@ func (v *Vault) FromConnectVault(vault *connect.Vault) { func (v *Vault) FromSDKVault(vault *sdk.VaultOverview) { v.ID = vault.ID - v.CreatedAt = time.Now() // TODO: add to SDK and use it instead of time.Now() + v.CreatedAt = vault.CreatedAt } From a0475d71705d14a705d7bf64a8d030f145ad65ba Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:09:35 -0500 Subject: [PATCH 08/27] Check `created_at` in the SDK mapper test --- pkg/onepassword/model/vault_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/onepassword/model/vault_test.go b/pkg/onepassword/model/vault_test.go index 48c7be2..d6ba34b 100644 --- a/pkg/onepassword/model/vault_test.go +++ b/pkg/onepassword/model/vault_test.go @@ -23,14 +23,15 @@ func TestVault_FromConnectVault(t *testing.T) { require.Equal(t, connectVault.CreatedAt, vault.CreatedAt) } -// TODO: check CreatedAt when available func TestVault_FromSDKVault(t *testing.T) { sdkVault := &sdk.VaultOverview{ - ID: "test-id", + ID: "test-id", + CreatedAt: time.Now(), } vault := &Vault{} vault.FromSDKVault(sdkVault) require.Equal(t, sdkVault.ID, vault.ID) + require.Equal(t, sdkVault.CreatedAt, vault.CreatedAt) } From ae9b673f962b0e6e0673d0b1783d62c3578c67b2 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:11:13 -0500 Subject: [PATCH 09/27] Remove commented code --- pkg/onepassword/secret_update_handler_test.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pkg/onepassword/secret_update_handler_test.go b/pkg/onepassword/secret_update_handler_test.go index f6dad7f..7c93bd6 100644 --- a/pkg/onepassword/secret_update_handler_test.go +++ b/pkg/onepassword/secret_update_handler_test.go @@ -807,15 +807,6 @@ func TestUpdateSecretHandler(t *testing.T) { mockOpClient := &mocks.TestClient{} mockOpClient.On("GetItemByID", mock.Anything, mock.Anything).Return(createItem(), nil) - //mocks.DoGetItemFunc = func(uuid string, vaultUUID string) (*onepassword.Item, error) { - // - // item := onepassword.Item{} - // item.Fields = generateFields(testData.opItem["username"], testData.opItem["password"]) - // item.Version = itemVersion - // item.Vault.ID = vaultUUID - // item.ID = uuid - // return &item, nil - //} h := &SecretUpdateHandler{ client: cl, opClient: mockOpClient, From aa1b4ba85788e42cc08b71100c682009c11c2a0c Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:12:38 -0500 Subject: [PATCH 10/27] Capitalize 1Password in error --- pkg/onepassword/client/connect/connect.go | 8 ++++---- pkg/onepassword/client/sdk/sdk.go | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/onepassword/client/connect/connect.go b/pkg/onepassword/client/connect/connect.go index e45df48..8dda08b 100644 --- a/pkg/onepassword/client/connect/connect.go +++ b/pkg/onepassword/client/connect/connect.go @@ -30,7 +30,7 @@ func NewClient(config Config) *Connect { func (c *Connect) GetItemByID(vaultID, itemID string) (*model.Item, error) { connectItem, err := c.client.GetItemByUUID(itemID, vaultID) if err != nil { - return nil, fmt.Errorf("1password Connect error: %w", err) + return nil, fmt.Errorf("1Password Connect error: %w", err) } var item model.Item @@ -42,7 +42,7 @@ func (c *Connect) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, erro // Get all items in the vault with the specified title connectItems, err := c.client.GetItemsByTitle(itemTitle, vaultID) if err != nil { - return nil, fmt.Errorf("1password Connect error: %w", err) + return nil, fmt.Errorf("1Password Connect error: %w", err) } var items []model.Item @@ -60,7 +60,7 @@ func (c *Connect) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) ContentPath: fmt.Sprintf("/v1/vaults/%s/items/%s/files/%s/content", vaultID, itemID, fileID), }) if err != nil { - return nil, fmt.Errorf("1password Connect error: %w", err) + return nil, fmt.Errorf("1Password Connect error: %w", err) } return bytes, nil @@ -69,7 +69,7 @@ func (c *Connect) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) func (c *Connect) GetVaultsByTitle(vaultQuery string) ([]model.Vault, error) { connectVaults, err := c.client.GetVaultsByTitle(vaultQuery) if err != nil { - return nil, fmt.Errorf("1password Connect error: %w", err) + return nil, fmt.Errorf("1Password Connect error: %w", err) } var vaults []model.Vault diff --git a/pkg/onepassword/client/sdk/sdk.go b/pkg/onepassword/client/sdk/sdk.go index b6a89ee..dcddda9 100644 --- a/pkg/onepassword/client/sdk/sdk.go +++ b/pkg/onepassword/client/sdk/sdk.go @@ -26,7 +26,7 @@ func NewClient(config Config) (*SDK, error) { sdk.WithIntegrationInfo(config.IntegrationName, config.IntegrationVersion), ) if err != nil { - return nil, fmt.Errorf("1password sdk error: %w", err) + return nil, fmt.Errorf("1Password sdk error: %w", err) } return &SDK{ @@ -37,7 +37,7 @@ func NewClient(config Config) (*SDK, error) { func (s *SDK) GetItemByID(vaultID, itemID string) (*model.Item, error) { sdkItem, err := s.client.Items().Get(context.Background(), vaultID, itemID) if err != nil { - return nil, fmt.Errorf("1password sdk error: %w", err) + return nil, fmt.Errorf("1Password sdk error: %w", err) } var item model.Item @@ -49,7 +49,7 @@ func (s *SDK) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) { // Get all items in the vault sdkItems, err := s.client.Items().List(context.Background(), vaultID) if err != nil { - return nil, fmt.Errorf("1password sdk error: %w", err) + return nil, fmt.Errorf("1Password sdk error: %w", err) } // Filter items by title @@ -70,7 +70,7 @@ func (s *SDK) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) { ID: fileID, }) if err != nil { - return nil, fmt.Errorf("1password sdk error: %w", err) + return nil, fmt.Errorf("1Password sdk error: %w", err) } return bytes, nil @@ -80,7 +80,7 @@ func (s *SDK) GetVaultsByTitle(title string) ([]model.Vault, error) { // List all vaults sdkVaults, err := s.client.Vaults().List(context.Background()) if err != nil { - return nil, fmt.Errorf("1password sdk error: %w", err) + return nil, fmt.Errorf("1Password sdk error: %w", err) } // Filter vaults by title From 9d0736285f39ce546413036bbda7235f775bb27c Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:18:57 -0500 Subject: [PATCH 11/27] Fix type --- pkg/onepassword/client/sdk/sdk_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/onepassword/client/sdk/sdk_test.go b/pkg/onepassword/client/sdk/sdk_test.go index 5455c5b..501fa3c 100644 --- a/pkg/onepassword/client/sdk/sdk_test.go +++ b/pkg/onepassword/client/sdk/sdk_test.go @@ -23,7 +23,7 @@ func TestSDK_GetItemByID(t *testing.T) { mockItemAPI func() *clientmock.ItemAPIMock check func(t *testing.T, item *model.Item, err error) }{ - "should return a single vault": { + "should return a single item": { mockItemAPI: func() *clientmock.ItemAPIMock { m := &clientmock.ItemAPIMock{} m.On("Get", context.Background(), "vault-id", "item-id").Return(*sdkItem, nil) From f164a93b7230ba7b1ebe3124b01700ab0585a5d3 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:51:16 -0500 Subject: [PATCH 12/27] Re-arrange env vars --- config/manager/manager.yaml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 70e65ee..582577b 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -75,25 +75,33 @@ spec: image: 1password/onepassword-operator:latest name: manager env: - - name: WATCH_NAMESPACE - value: "default" + - name: OPERATOR_NAME + value: "onepassword-connect-operator" - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - - name: OPERATOR_NAME - value: "onepassword-connect-operator" - - name: OP_CONNECT_HOST - value: "http://onepassword-connect:8080" + - name: WATCH_NAMESPACE + value: "default" - name: POLLING_INTERVAL value: "10" + - name: AUTO_RESTART + value: "false" + - name: OP_CONNECT_HOST + value: "http://onepassword-connect:8080" - name: OP_CONNECT_TOKEN valueFrom: secretKeyRef: name: onepassword-token key: token - - name: AUTO_RESTART + - name: MANAGE_CONNECT value: "false" +# Uncomment the following lines to enable service account token and comment out the OP_CONNECT_TOKEN and OP_CONNECT_HOST env vars. +# - name: OP_SERVICE_ACCOUNT_TOKEN +# valueFrom: +# secretKeyRef: +# name: onepassword-service-account-token +# key: token securityContext: allowPrivilegeEscalation: false capabilities: From 1aa27fdba0ba4c7ed15aefcbc9ff69a9bddab7cd Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 20:54:45 -0500 Subject: [PATCH 13/27] Sort imports --- internal/controller/suite_test.go | 2 +- pkg/kubernetessecrets/kubernetes_secrets_builder.go | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 8791e6a..f8d1232 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -26,7 +26,6 @@ package controller import ( "context" - "github.com/stretchr/testify/mock" "path/filepath" "regexp" "testing" @@ -34,6 +33,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" diff --git a/pkg/kubernetessecrets/kubernetes_secrets_builder.go b/pkg/kubernetessecrets/kubernetes_secrets_builder.go index d7982fd..5d5b52b 100644 --- a/pkg/kubernetessecrets/kubernetes_secrets_builder.go +++ b/pkg/kubernetessecrets/kubernetes_secrets_builder.go @@ -2,16 +2,13 @@ package kubernetessecrets import ( "context" + errs "errors" "fmt" - "github.com/1Password/onepassword-operator/pkg/onepassword/model" - + "reflect" "regexp" "strings" - "reflect" - - errs "errors" - + "github.com/1Password/onepassword-operator/pkg/onepassword/model" "github.com/1Password/onepassword-operator/pkg/utils" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" From 55b5781d7a9b7e2175f164850db3f5429a84b041 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:04:22 -0500 Subject: [PATCH 14/27] Pass logger to print what what type of client is used Connect or Service Account --- cmd/main.go | 5 ++++- pkg/onepassword/client/client.go | 16 +++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index e096a5f..01304f4 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -152,7 +152,10 @@ func main() { } // Setup One Password Client - opClient, err := opclient.NewFromEnvironment(version.OperatorVersion) + opClient, err := opclient.NewFromEnvironment(opclient.Config{ + Logger: setupLog, + Version: version.OperatorVersion, + }) if err != nil { setupLog.Error(err, "unable to create 1Password client") os.Exit(1) diff --git a/pkg/onepassword/client/client.go b/pkg/onepassword/client/client.go index 52db568..a77867e 100644 --- a/pkg/onepassword/client/client.go +++ b/pkg/onepassword/client/client.go @@ -2,9 +2,10 @@ package client import ( "errors" - "fmt" "os" + "github.com/go-logr/logr" + "github.com/1Password/onepassword-operator/pkg/onepassword/client/connect" "github.com/1Password/onepassword-operator/pkg/onepassword/client/sdk" "github.com/1Password/onepassword-operator/pkg/onepassword/model" @@ -18,8 +19,13 @@ type Client interface { GetVaultsByTitle(title string) ([]model.Vault, error) } +type Config struct { + Logger logr.Logger + Version string +} + // NewFromEnvironment creates a new 1Password client based on the provided configuration. -func NewFromEnvironment(integrationVersion string) (Client, error) { +func NewFromEnvironment(cfg Config) (Client, error) { connectHost, _ := os.LookupEnv("OP_CONNECT_HOST") connectToken, _ := os.LookupEnv("OP_CONNECT_TOKEN") serviceAccountToken, _ := os.LookupEnv("OP_SERVICE_ACCOUNT_TOKEN") @@ -29,16 +35,16 @@ func NewFromEnvironment(integrationVersion string) (Client, error) { } if serviceAccountToken != "" { - fmt.Printf("Using Service Account Token") + cfg.Logger.Info("Using Service Account Token") return sdk.NewClient(sdk.Config{ ServiceAccountToken: serviceAccountToken, IntegrationName: "1password-operator", - IntegrationVersion: integrationVersion, + IntegrationVersion: cfg.Version, }) } if connectHost != "" && connectToken != "" { - fmt.Printf("Using Connect") + cfg.Logger.Info("Using 1Password Connect") return connect.NewClient(connect.Config{ ConnectHost: connectHost, ConnectToken: connectToken, From 704116b855d59f6af0540d2cc4811d2351a68660 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:10:33 -0500 Subject: [PATCH 15/27] Remove user agent from Connect config as it's set automatically when initializing Connect client --- pkg/onepassword/client/connect/connect.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/onepassword/client/connect/connect.go b/pkg/onepassword/client/connect/connect.go index 8dda08b..8cbe7f4 100644 --- a/pkg/onepassword/client/connect/connect.go +++ b/pkg/onepassword/client/connect/connect.go @@ -12,7 +12,6 @@ import ( type Config struct { ConnectHost string ConnectToken string - UserAgent string } // Connect is a client for interacting with 1Password using the Connect API. From 2373fbc87fa44fe12f28fe2ba863c87abe95c377 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:32:00 -0500 Subject: [PATCH 16/27] Updated mapping to be faster --- pkg/onepassword/client/connect/connect.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/onepassword/client/connect/connect.go b/pkg/onepassword/client/connect/connect.go index 8cbe7f4..992fa49 100644 --- a/pkg/onepassword/client/connect/connect.go +++ b/pkg/onepassword/client/connect/connect.go @@ -44,11 +44,11 @@ func (c *Connect) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, erro return nil, fmt.Errorf("1Password Connect error: %w", err) } - var items []model.Item - for _, connectItem := range connectItems { + items := make([]model.Item, len(connectItems)) + for i, connectItem := range connectItems { var item model.Item item.FromConnectItem(&connectItem) - items = append(items, item) + items[i] = item } return items, nil @@ -71,12 +71,12 @@ func (c *Connect) GetVaultsByTitle(vaultQuery string) ([]model.Vault, error) { return nil, fmt.Errorf("1Password Connect error: %w", err) } - var vaults []model.Vault - for _, connectVault := range connectVaults { + vaults := make([]model.Vault, len(connectVaults)) + for i, connectVault := range connectVaults { if vaultQuery == connectVault.Name { var vault model.Vault vault.FromConnectVault(&connectVault) - vaults = append(vaults, vault) + vaults[i] = vault } } From 32360d8a837194f1de317872c77bf6af3c4696df Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:53:46 -0500 Subject: [PATCH 17/27] Remove todos from mocked methods --- .../client/testing/mock/connect.go | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/onepassword/client/testing/mock/connect.go b/pkg/onepassword/client/testing/mock/connect.go index a38c4f6..cd11eae 100644 --- a/pkg/onepassword/client/testing/mock/connect.go +++ b/pkg/onepassword/client/testing/mock/connect.go @@ -12,7 +12,7 @@ type ConnectClientMock struct { } func (c *ConnectClientMock) GetVaults() ([]onepassword.Vault, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } @@ -22,12 +22,12 @@ func (c *ConnectClientMock) GetVault(uuid string) (*onepassword.Vault, error) { } func (c *ConnectClientMock) GetVaultByUUID(uuid string) (*onepassword.Vault, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) GetVaultByTitle(title string) (*onepassword.Vault, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } @@ -37,12 +37,12 @@ func (c *ConnectClientMock) GetVaultsByTitle(title string) ([]onepassword.Vault, } func (c *ConnectClientMock) GetItems(vaultQuery string) ([]onepassword.Item, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) GetItem(itemQuery, vaultQuery string) (*onepassword.Item, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } @@ -52,7 +52,7 @@ func (c *ConnectClientMock) GetItemByUUID(uuid string, vaultQuery string) (*onep } func (c *ConnectClientMock) GetItemByTitle(title string, vaultQuery string) (*onepassword.Item, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } @@ -62,37 +62,37 @@ func (c *ConnectClientMock) GetItemsByTitle(title string, vaultQuery string) ([] } func (c *ConnectClientMock) CreateItem(item *onepassword.Item, vaultQuery string) (*onepassword.Item, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) UpdateItem(item *onepassword.Item, vaultQuery string) (*onepassword.Item, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) DeleteItem(item *onepassword.Item, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) DeleteItemByID(itemUUID string, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) DeleteItemByTitle(title string, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) GetFiles(itemQuery string, vaultQuery string) ([]onepassword.File, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) GetFile(uuid string, itemQuery string, vaultQuery string) (*onepassword.File, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } @@ -105,26 +105,26 @@ func (c *ConnectClientMock) GetFileContent(file *onepassword.File) ([]byte, erro } func (c *ConnectClientMock) DownloadFile(file *onepassword.File, targetDirectory string, overwrite bool) (string, error) { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) LoadStructFromItemByUUID(config interface{}, itemUUID string, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) LoadStructFromItemByTitle(config interface{}, itemTitle string, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) LoadStructFromItem(config interface{}, itemQuery string, vaultQuery string) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } func (c *ConnectClientMock) LoadStruct(config interface{}) error { - //TODO implement me + // implement when need to mock this method panic("implement me") } From 0903bacfbd3946f7854b20cbe2b48af3eaaed090 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:55:32 -0500 Subject: [PATCH 18/27] Check Create_At in the test --- pkg/onepassword/client/sdk/sdk_test.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/pkg/onepassword/client/sdk/sdk_test.go b/pkg/onepassword/client/sdk/sdk_test.go index 501fa3c..bab4755 100644 --- a/pkg/onepassword/client/sdk/sdk_test.go +++ b/pkg/onepassword/client/sdk/sdk_test.go @@ -4,6 +4,7 @@ import ( "context" "errors" "testing" + "time" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -191,8 +192,8 @@ func TestSDK_GetFileContent(t *testing.T) { } } -// TODO: check CreatedAt as soon as a new SDK version returns it func TestSDK_GetVaultsByTitle(t *testing.T) { + now := time.Now() testCases := map[string]struct { mockVaultAPI func() *clientmock.VaultAPIMock check func(t *testing.T, vaults []model.Vault, err error) @@ -202,12 +203,14 @@ func TestSDK_GetVaultsByTitle(t *testing.T) { m := &clientmock.VaultAPIMock{} m.On("List", context.Background()).Return([]sdk.VaultOverview{ { - ID: "test-id", - Title: VaultTitleEmployee, + ID: "test-id", + Title: VaultTitleEmployee, + CreatedAt: now, }, { - ID: "test-id-2", - Title: "Some other vault", + ID: "test-id-2", + Title: "Some other vault", + CreatedAt: now, }, }, nil) return m @@ -216,6 +219,7 @@ func TestSDK_GetVaultsByTitle(t *testing.T) { require.NoError(t, err) require.Len(t, vaults, 1) require.Equal(t, "test-id", vaults[0].ID) + require.Equal(t, now, vaults[0].CreatedAt) }, }, "should return a two vaults": { @@ -223,12 +227,14 @@ func TestSDK_GetVaultsByTitle(t *testing.T) { m := &clientmock.VaultAPIMock{} m.On("List", context.Background()).Return([]sdk.VaultOverview{ { - ID: "test-id", - Title: VaultTitleEmployee, + ID: "test-id", + Title: VaultTitleEmployee, + CreatedAt: now, }, { - ID: "test-id-2", - Title: VaultTitleEmployee, + ID: "test-id-2", + Title: VaultTitleEmployee, + CreatedAt: now, }, }, nil) return m @@ -238,8 +244,10 @@ func TestSDK_GetVaultsByTitle(t *testing.T) { require.Len(t, vaults, 2) // Check the first vault require.Equal(t, "test-id", vaults[0].ID) + require.Equal(t, now, vaults[0].CreatedAt) // Check the second vault require.Equal(t, "test-id-2", vaults[1].ID) + require.Equal(t, now, vaults[1].CreatedAt) }, }, "should return an error": { From 17d44d90bddcf91a648ba88d2b5fbfc5883103a9 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 21:56:51 -0500 Subject: [PATCH 19/27] Check for empty list --- pkg/onepassword/client/sdk/sdk_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pkg/onepassword/client/sdk/sdk_test.go b/pkg/onepassword/client/sdk/sdk_test.go index bab4755..c9f5d68 100644 --- a/pkg/onepassword/client/sdk/sdk_test.go +++ b/pkg/onepassword/client/sdk/sdk_test.go @@ -104,6 +104,17 @@ func TestSDK_GetItemsByTitle(t *testing.T) { clienttesting.CheckSDKItemOverviewMapping(t, sdkItem2, &items[1]) }, }, + "should return empty list": { + mockItemAPI: func() *clientmock.ItemAPIMock { + m := &clientmock.ItemAPIMock{} + m.On("List", context.Background(), "vault-id", mock.Anything).Return([]sdk.ItemOverview{}, nil) + return m + }, + check: func(t *testing.T, items []model.Item, err error) { + require.NoError(t, err) + require.Len(t, items, 0) + }, + }, "should return an error": { mockItemAPI: func() *clientmock.ItemAPIMock { m := &clientmock.ItemAPIMock{} From bb7b565457adfe4fcd942852d7f6ce96c1e10d4b Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 22:04:23 -0500 Subject: [PATCH 20/27] As we check for vault name, we can't initialize the array of exact size as don't know how many items well have ther --- pkg/onepassword/client/connect/connect.go | 7 +++-- .../client/connect/connect_test.go | 26 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/pkg/onepassword/client/connect/connect.go b/pkg/onepassword/client/connect/connect.go index 992fa49..64bd344 100644 --- a/pkg/onepassword/client/connect/connect.go +++ b/pkg/onepassword/client/connect/connect.go @@ -71,14 +71,13 @@ func (c *Connect) GetVaultsByTitle(vaultQuery string) ([]model.Vault, error) { return nil, fmt.Errorf("1Password Connect error: %w", err) } - vaults := make([]model.Vault, len(connectVaults)) - for i, connectVault := range connectVaults { + var vaults []model.Vault + for _, connectVault := range connectVaults { if vaultQuery == connectVault.Name { var vault model.Vault vault.FromConnectVault(&connectVault) - vaults[i] = vault + vaults = append(vaults, vault) } } - return vaults, nil } diff --git a/pkg/onepassword/client/connect/connect_test.go b/pkg/onepassword/client/connect/connect_test.go index ef21b90..0eef3be 100644 --- a/pkg/onepassword/client/connect/connect_test.go +++ b/pkg/onepassword/client/connect/connect_test.go @@ -3,6 +3,7 @@ package connect import ( "errors" "testing" + "time" "github.com/stretchr/testify/require" @@ -159,6 +160,7 @@ func TestConnect_GetFileContent(t *testing.T) { } func TestConnect_GetVaultsByTitle(t *testing.T) { + now := time.Now() testCases := map[string]struct { mockClient func() *mock.ConnectClientMock check func(t *testing.T, vaults []model.Vault, err error) @@ -168,12 +170,14 @@ func TestConnect_GetVaultsByTitle(t *testing.T) { mockConnectClient := &mock.ConnectClientMock{} mockConnectClient.On("GetVaultsByTitle", VaultTitleEmployee).Return([]onepassword.Vault{ { - ID: "test-id", - Name: VaultTitleEmployee, + ID: "test-id", + Name: VaultTitleEmployee, + CreatedAt: now, }, { - ID: "test-id-2", - Name: "Some other vault", + ID: "test-id-2", + Name: "Some other vault", + CreatedAt: now, }, }, nil) return mockConnectClient @@ -182,6 +186,7 @@ func TestConnect_GetVaultsByTitle(t *testing.T) { require.NoError(t, err) require.Len(t, vaults, 1) require.Equal(t, "test-id", vaults[0].ID) + require.Equal(t, now, vaults[0].CreatedAt) }, }, "should return a two vaults": { @@ -189,12 +194,14 @@ func TestConnect_GetVaultsByTitle(t *testing.T) { mockConnectClient := &mock.ConnectClientMock{} mockConnectClient.On("GetVaultsByTitle", VaultTitleEmployee).Return([]onepassword.Vault{ { - ID: "test-id", - Name: VaultTitleEmployee, + ID: "test-id", + Name: VaultTitleEmployee, + CreatedAt: now, }, { - ID: "test-id-2", - Name: VaultTitleEmployee, + ID: "test-id-2", + Name: VaultTitleEmployee, + CreatedAt: now, }, }, nil) return mockConnectClient @@ -204,8 +211,9 @@ func TestConnect_GetVaultsByTitle(t *testing.T) { require.Len(t, vaults, 2) // Check the first vault require.Equal(t, "test-id", vaults[0].ID) + require.Equal(t, now, vaults[0].CreatedAt) // Check the second vault - require.Equal(t, "test-id-2", vaults[1].ID) + require.Equal(t, now, vaults[1].CreatedAt) }, }, "should return an error": { From 458ed24ca3bb8a4dda9e66e93a0fe44fc1b3e5fc Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Mon, 16 Jun 2025 22:05:06 -0500 Subject: [PATCH 21/27] Check second vault ID --- pkg/onepassword/client/connect/connect_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/onepassword/client/connect/connect_test.go b/pkg/onepassword/client/connect/connect_test.go index 0eef3be..be86d0e 100644 --- a/pkg/onepassword/client/connect/connect_test.go +++ b/pkg/onepassword/client/connect/connect_test.go @@ -213,6 +213,7 @@ func TestConnect_GetVaultsByTitle(t *testing.T) { require.Equal(t, "test-id", vaults[0].ID) require.Equal(t, now, vaults[0].CreatedAt) // Check the second vault + require.Equal(t, "test-id-2", vaults[1].ID) require.Equal(t, now, vaults[1].CreatedAt) }, }, From ac646ec56cd509c4cee864d34a87255693f82bb6 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 11:16:57 -0500 Subject: [PATCH 22/27] Rename `vaultIdentifier` and `itemIdentifier` for more clarity --- pkg/onepassword/items.go | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/onepassword/items.go b/pkg/onepassword/items.go index eb121a3..ad42276 100644 --- a/pkg/onepassword/items.go +++ b/pkg/onepassword/items.go @@ -13,18 +13,18 @@ import ( var logger = logf.Log.WithName("retrieve_item") func GetOnePasswordItemByPath(opClient opclient.Client, path string) (*model.Item, error) { - vaultIdentifier, itemIdentifier, err := ParseVaultAndItemFromPath(path) + vaultNameOrID, itemNameOrID, err := ParseVaultAndItemFromPath(path) if err != nil { return nil, err } - vaultID, err := getVaultID(opClient, vaultIdentifier) + vaultID, err := getVaultID(opClient, vaultNameOrID) if err != nil { - return nil, fmt.Errorf("failed to 'getVaultID' for vaultIdentifier='%s': %w", vaultIdentifier, err) + return nil, fmt.Errorf("failed to 'getVaultID' for vaultNameOrID='%s': %w", vaultNameOrID, err) } - itemID, err := getItemID(opClient, vaultID, itemIdentifier) + itemID, err := getItemID(opClient, vaultID, itemNameOrID) if err != nil { - return nil, fmt.Errorf("faild to 'getItemID' for vaultID='%s' and itemIdentifier='%s': %w", vaultID, itemIdentifier, err) + return nil, fmt.Errorf("faild to 'getItemID' for vaultID='%s' and itemNameOrID='%s': %w", vaultID, itemNameOrID, err) } item, err := opClient.GetItemByID(vaultID, itemID) @@ -50,15 +50,15 @@ func ParseVaultAndItemFromPath(path string) (string, string, error) { return "", "", fmt.Errorf("%q is not an acceptable path for One Password item. Must be of the format: `vaults/{vault_id}/items/{item_id}`", path) } -func getVaultID(client opclient.Client, vaultIdentifier string) (string, error) { - if !IsValidClientUUID(vaultIdentifier) { - vaults, err := client.GetVaultsByTitle(vaultIdentifier) +func getVaultID(client opclient.Client, vaultNameOrID string) (string, error) { + if !IsValidClientUUID(vaultNameOrID) { + vaults, err := client.GetVaultsByTitle(vaultNameOrID) if err != nil { return "", err } if len(vaults) == 0 { - return "", fmt.Errorf("No vaults found with identifier %q", vaultIdentifier) + return "", fmt.Errorf("No vaults found with identifier %q", vaultNameOrID) } oldestVault := vaults[0] @@ -68,22 +68,22 @@ func getVaultID(client opclient.Client, vaultIdentifier string) (string, error) oldestVault = returnedVault } } - logger.Info(fmt.Sprintf("%v 1Password vaults found with the title %q. Will use vault %q as it is the oldest.", len(vaults), vaultIdentifier, oldestVault.ID)) + logger.Info(fmt.Sprintf("%v 1Password vaults found with the title %q. Will use vault %q as it is the oldest.", len(vaults), vaultNameOrID, oldestVault.ID)) } - vaultIdentifier = oldestVault.ID + vaultNameOrID = oldestVault.ID } - return vaultIdentifier, nil + return vaultNameOrID, nil } -func getItemID(client opclient.Client, vaultId, itemIdentifier string) (string, error) { - if !IsValidClientUUID(itemIdentifier) { - items, err := client.GetItemsByTitle(vaultId, itemIdentifier) +func getItemID(client opclient.Client, vaultId, itemNameOrID string) (string, error) { + if !IsValidClientUUID(itemNameOrID) { + items, err := client.GetItemsByTitle(vaultId, itemNameOrID) if err != nil { return "", err } if len(items) == 0 { - return "", fmt.Errorf("No items found with identifier %q", itemIdentifier) + return "", fmt.Errorf("No items found with identifier %q", itemNameOrID) } oldestItem := items[0] @@ -93,9 +93,9 @@ func getItemID(client opclient.Client, vaultId, itemIdentifier string) (string, oldestItem = returnedItem } } - logger.Info(fmt.Sprintf("%v 1Password items found with the title %q. Will use item %q as it is the oldest.", len(items), itemIdentifier, oldestItem.ID)) + logger.Info(fmt.Sprintf("%v 1Password items found with the title %q. Will use item %q as it is the oldest.", len(items), itemNameOrID, oldestItem.ID)) } - itemIdentifier = oldestItem.ID + itemNameOrID = oldestItem.ID } - return itemIdentifier, nil + return itemNameOrID, nil } From 49a5e93c44776425f730f84eb7e05021362c0bf9 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 11:19:21 -0500 Subject: [PATCH 23/27] Remove GO111MODULE=on as it set to 'on' by default from Go 1.16 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 385d016..86e2234 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ COPY version/ version/ # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. RUN CGO_ENABLED=0 \ - GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} GO111MODULE=on \ + GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \ go build \ -ldflags "-X \"github.com/1Password/onepassword-operator/version.Version=$operator_version\"" \ -a -o manager cmd/main.go From 842c8febdc89eae510f5efcf6ac488d686592eff Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 11:20:01 -0500 Subject: [PATCH 24/27] Update comment --- config/manager/manager.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 582577b..07a6442 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -96,7 +96,7 @@ spec: key: token - name: MANAGE_CONNECT value: "false" -# Uncomment the following lines to enable service account token and comment out the OP_CONNECT_TOKEN and OP_CONNECT_HOST env vars. +# Uncomment the following lines to enable service account token and comment out the OP_CONNECT_TOKEN, OP_CONNECT_HOST and MANAGE_CONNECT env vars. # - name: OP_SERVICE_ACCOUNT_TOKEN # valueFrom: # secretKeyRef: From fd92ef86aba1ec73827a7f9b17373be67af40db4 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 11:24:43 -0500 Subject: [PATCH 25/27] Revert changelog and version change as will be done in release MR Revert version change as will be dne in release MR --- .VERSION | 2 +- CHANGELOG.md | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.VERSION b/.VERSION index abb1658..b9268da 100644 --- a/.VERSION +++ b/.VERSION @@ -1 +1 @@ -1.9.0 \ No newline at end of file +1.8.1 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d43eb48..090d1f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,14 +12,6 @@ --- -[//]: # (START/v1.9.0) -# v1.9.0 - -## Features - * Support fetching secrets using Service Accounts to authenticate with 1Password. {#160} - ---- - [//]: # (START/v1.8.1) # v1.8.1 From c9b969def1fe53635f4dd6da49b10aa91390d45d Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 11:27:55 -0500 Subject: [PATCH 26/27] Update comments --- .../client/testing/mock/connect.go | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/onepassword/client/testing/mock/connect.go b/pkg/onepassword/client/testing/mock/connect.go index cd11eae..e511c64 100644 --- a/pkg/onepassword/client/testing/mock/connect.go +++ b/pkg/onepassword/client/testing/mock/connect.go @@ -12,7 +12,7 @@ type ConnectClientMock struct { } func (c *ConnectClientMock) GetVaults() ([]onepassword.Vault, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } @@ -22,12 +22,12 @@ func (c *ConnectClientMock) GetVault(uuid string) (*onepassword.Vault, error) { } func (c *ConnectClientMock) GetVaultByUUID(uuid string) (*onepassword.Vault, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) GetVaultByTitle(title string) (*onepassword.Vault, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } @@ -37,12 +37,12 @@ func (c *ConnectClientMock) GetVaultsByTitle(title string) ([]onepassword.Vault, } func (c *ConnectClientMock) GetItems(vaultQuery string) ([]onepassword.Item, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) GetItem(itemQuery, vaultQuery string) (*onepassword.Item, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } @@ -52,7 +52,7 @@ func (c *ConnectClientMock) GetItemByUUID(uuid string, vaultQuery string) (*onep } func (c *ConnectClientMock) GetItemByTitle(title string, vaultQuery string) (*onepassword.Item, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } @@ -62,37 +62,37 @@ func (c *ConnectClientMock) GetItemsByTitle(title string, vaultQuery string) ([] } func (c *ConnectClientMock) CreateItem(item *onepassword.Item, vaultQuery string) (*onepassword.Item, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) UpdateItem(item *onepassword.Item, vaultQuery string) (*onepassword.Item, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) DeleteItem(item *onepassword.Item, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) DeleteItemByID(itemUUID string, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) DeleteItemByTitle(title string, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) GetFiles(itemQuery string, vaultQuery string) ([]onepassword.File, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) GetFile(uuid string, itemQuery string, vaultQuery string) (*onepassword.File, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } @@ -105,26 +105,26 @@ func (c *ConnectClientMock) GetFileContent(file *onepassword.File) ([]byte, erro } func (c *ConnectClientMock) DownloadFile(file *onepassword.File, targetDirectory string, overwrite bool) (string, error) { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) LoadStructFromItemByUUID(config interface{}, itemUUID string, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) LoadStructFromItemByTitle(config interface{}, itemTitle string, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) LoadStructFromItem(config interface{}, itemQuery string, vaultQuery string) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } func (c *ConnectClientMock) LoadStruct(config interface{}) error { - // implement when need to mock this method + // Only implement this if mocking is needed panic("implement me") } From b717823fd07691e2108fd2ec08370d47d0d06c36 Mon Sep 17 00:00:00 2001 From: Volodymyr Zotov Date: Tue, 17 Jun 2025 13:12:58 -0500 Subject: [PATCH 27/27] Update examples section --- USAGEGUIDE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/USAGEGUIDE.md b/USAGEGUIDE.md index b94a9e1..8b155c8 100644 --- a/USAGEGUIDE.md +++ b/USAGEGUIDE.md @@ -107,7 +107,8 @@ containers: --- -## [Usage examples](https://developer.1password.com/docs/k8s/operator/?deployment-type=manual#usage-examples) +## Usage examples +Find usage [examples](https://developer.1password.com/docs/k8s/operator/?deployment-type=manual#usage-examples) on 1Password developer documentation. ---