mirror of
https://github.com/1Password/onepassword-operator.git
synced 2025-10-21 23:18:06 +00:00
Compare commits
24 Commits
03b093ac17
...
vzt/fix-ok
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d403a29fdc | ||
![]() |
d30ed0b9d7 | ||
![]() |
db2053fde4 | ||
![]() |
316f605680 | ||
![]() |
7135f439a5 | ||
![]() |
625297c1fb | ||
![]() |
e967f7ce1e | ||
![]() |
5199e9f350 | ||
![]() |
878b38deac | ||
![]() |
1a40b4fb95 | ||
![]() |
4b5d3c5f1a | ||
![]() |
8d4908fb72 | ||
![]() |
6cf52a7bfc | ||
![]() |
7ef9ec6de7 | ||
![]() |
3f52bb2840 | ||
![]() |
63e3f29be9 | ||
![]() |
49bc9cb329 | ||
![]() |
de62e07bcf | ||
![]() |
3ebc536dd7 | ||
![]() |
6769e25a98 | ||
![]() |
d8734c9ae3 | ||
![]() |
460742869b | ||
![]() |
35e476230c | ||
![]() |
3a9691576a |
17
.github/pull_request_template.md
vendored
17
.github/pull_request_template.md
vendored
@@ -1,17 +0,0 @@
|
||||
### ✨ Summary
|
||||
<!-- What does this change do? -->
|
||||
|
||||
<!-- What issue does it resolve? -->
|
||||
### 🔗 Resolves:
|
||||
|
||||
### ✅ Checklist
|
||||
- [ ] 🖊️ Commits are signed
|
||||
- [ ] 🧪 Tests added/updated: _(See the [Testing Guide](docs/testing.md) for when to use each type and how to run them)_
|
||||
- [ ] 🔹 Unit
|
||||
- [ ] 🔸 Integration
|
||||
- [ ] 🌐 E2E (Connect)
|
||||
- [ ] 🔑 E2E (Service Account)
|
||||
- [ ] 📚 Docs updated (if behavior changed)
|
||||
|
||||
### 🕵️ Review Notes & ⚠️ Risks
|
||||
<!-- Notes for reviewers, flags, feature gates, rollout considerations, etc. -->
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -11,10 +11,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone the code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
52
.github/workflows/e2e-tests.yml
vendored
Normal file
52
.github/workflows/e2e-tests.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
name: E2E Tests [reusable]
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
OP_CONNECT_CREDENTIALS:
|
||||
description: '1Password Connect credentials'
|
||||
required: true
|
||||
OP_CONNECT_TOKEN:
|
||||
description: '1Password Connect token'
|
||||
required: true
|
||||
OP_SERVICE_ACCOUNT_TOKEN:
|
||||
description: '1Password service account token'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
e2e-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Install dependencies
|
||||
run: go mod tidy
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@v1
|
||||
with:
|
||||
cluster_name: onepassword-operator-test-e2e
|
||||
|
||||
# install cli to interact with item in 1Password to update/read using `testhelper/op` package
|
||||
- name: Install 1Password CLI
|
||||
uses: 1password/install-cli-action@v2
|
||||
with:
|
||||
version: 2.32.0
|
||||
|
||||
- name: Create '1password-credentials.json' file
|
||||
env:
|
||||
OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
|
||||
run: |
|
||||
echo "$OP_CONNECT_CREDENTIALS" > 1password-credentials.json
|
||||
|
||||
- name: Run E2E tests
|
||||
run: make test-e2e
|
||||
env:
|
||||
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -11,10 +11,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone the code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
25
.github/workflows/ok-to-test.yml
vendored
Normal file
25
.github/workflows/ok-to-test.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# Write comments "/ok-to-test sha=<hash>" on a pull request. This will emit a repository_dispatch event.
|
||||
name: Ok To Test
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
ok-to-test:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write # For adding reactions to the pull request comments
|
||||
contents: write # For executing the repository_dispatch event
|
||||
# Only run for PRs, not issue comments
|
||||
if: ${{ github.event.issue.pull_request }}
|
||||
steps:
|
||||
- name: Slash Command Dispatch
|
||||
uses: volodymyrZotov/slash-command-dispatch@7c1b623a2b0eba93f684c34f689a441f0be84cf1 # TODO: use peter-evans/slash-command-dispatch when fix for team permissions is released https://github.com/peter-evans/slash-command-dispatch/pull/424
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
reaction-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-type: pull-request
|
||||
commands: ok-to-test
|
||||
# The repository permission level required by the user to dispatch commands. Only allows 1Password collaborators to run this.
|
||||
permission: write
|
2
.github/workflows/release-pr.yml
vendored
2
.github/workflows/release-pr.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
name: Create Release Pull Request
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Parse release version
|
||||
id: get_version
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
DOCKER_CLI_EXPERIMENTAL: "enabled"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
67
.github/workflows/test-e2e-fork.yml
vendored
Normal file
67
.github/workflows/test-e2e-fork.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: E2E tests [fork]
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [ ok-to-test-command ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
concurrency:
|
||||
group: e2e-fork-${{ github.event.client_payload.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: true # cancel previous job runs for the same branch
|
||||
|
||||
jobs:
|
||||
run-e2e-tests:
|
||||
uses: ./.github/workflows/e2e-tests.yml
|
||||
if: |
|
||||
github.event_name == 'repository_dispatch' &&
|
||||
github.event.client_payload.slash_command.args.named.sha != '' &&
|
||||
contains(
|
||||
github.event.client_payload.pull_request.head.sha,
|
||||
github.event.client_payload.slash_command.args.named.sha
|
||||
)
|
||||
secrets:
|
||||
OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
|
||||
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
||||
|
||||
update-check-status:
|
||||
needs: run-e2e-tests
|
||||
runs-on: ubuntu-latest
|
||||
if: always() && github.event_name == 'repository_dispatch'
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
env:
|
||||
ref: ${{ github.event.client_payload.pull_request.head.sha }}
|
||||
conclusion: ${{ needs.run-e2e-tests.result }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const { data: checks } = await github.rest.checks.listForRef({
|
||||
...context.repo,
|
||||
ref: process.env.ref
|
||||
});
|
||||
|
||||
// update the 'check-external-pr' check run
|
||||
const check = checks.check_runs.filter(c => c.name === 'check-external-pr');
|
||||
|
||||
const { data: result } = await github.rest.checks.update({
|
||||
...context.repo,
|
||||
check_run_id: check[0].id,
|
||||
status: 'completed',
|
||||
conclusion: process.env.conclusion
|
||||
});
|
||||
|
||||
// update the 'run-e2e-tests' check run from 'test-e2e.yml' workflow
|
||||
const check = checks.check_runs.filter(c => c.name === 'run-e2e-tests');
|
||||
|
||||
const { data: result } = await github.rest.checks.update({
|
||||
...context.repo,
|
||||
check_run_id: check[0].id,
|
||||
status: 'completed',
|
||||
conclusion: process.env.conclusion
|
||||
});
|
||||
|
||||
return null;
|
63
.github/workflows/test-e2e.yml
vendored
63
.github/workflows/test-e2e.yml
vendored
@@ -1,48 +1,43 @@
|
||||
name: Test E2E
|
||||
name: E2E Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches: ['**'] # run for PRs targeting any branch (main and others)
|
||||
paths-ignore: &ignore_paths
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- '.golangci.yml'
|
||||
- '.gitignore'
|
||||
- '.dockerignore'
|
||||
- 'LICENSE'
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore: *ignore_paths
|
||||
|
||||
concurrency:
|
||||
group: e2e-${{ github.event.pull_request.head.ref }}
|
||||
cancel-in-progress: true # cancel previous job runs for the same branch
|
||||
cancel-in-progress: true # cancel previous job runs for the same branch
|
||||
|
||||
jobs:
|
||||
e2e-test:
|
||||
check-external-pr:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Install dependencies
|
||||
run: go mod tidy
|
||||
|
||||
- name: Create kind cluster
|
||||
uses: helm/kind-action@v1
|
||||
with:
|
||||
cluster_name: onepassword-operator-test-e2e
|
||||
|
||||
# install cli to interact with item in 1Password to update/read using `testhelper/op` package
|
||||
- name: Install 1Password CLI
|
||||
uses: 1password/install-cli-action@v2
|
||||
with:
|
||||
version: 2.32.0
|
||||
|
||||
- name: Create '1password-credentials.json' file
|
||||
env:
|
||||
OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
|
||||
- name: Check if PR is from external contributor
|
||||
run: |
|
||||
echo "$OP_CONNECT_CREDENTIALS" > 1password-credentials.json
|
||||
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
|
||||
echo "❌ External PR detected. This workflow requires approval from a maintainer."
|
||||
echo "Please ask a maintainer to run '/ok-to-test' command to trigger the fork workflow."
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Internal PR detected. Proceeding with tests."
|
||||
|
||||
- name: Run E2E tests
|
||||
run: make test-e2e
|
||||
env:
|
||||
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
||||
run-e2e-tests:
|
||||
needs: check-external-pr
|
||||
if: always() && (needs.check-external-pr.result == 'success' || github.event_name != 'pull_request')
|
||||
uses: ./.github/workflows/e2e-tests.yml
|
||||
secrets:
|
||||
OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }}
|
||||
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
|
||||
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
|
||||
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@@ -11,10 +11,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone the code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
@@ -8,9 +8,6 @@ WORKDIR /workspace
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
# Copy the testhelper module (needed for replace directive)
|
||||
COPY pkg/testhelper/ pkg/testhelper/
|
||||
|
||||
# Download dependencies
|
||||
RUN go mod download
|
||||
|
||||
|
109
docs/fork-pr-testing.md
Normal file
109
docs/fork-pr-testing.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Fork PR Testing Guide
|
||||
|
||||
This document explains how to test external pull requests using the dispatch action workflow system.
|
||||
|
||||
## Overview
|
||||
|
||||
The testing system consists of three main workflows:
|
||||
|
||||
1. **E2E Tests** (`test-e2e.yml`) - Runs automatically for internal PRs, requires approval for external PRs
|
||||
2. **Ok To Test** (`ok-to-test.yml`) - Processes slash commands to trigger fork testing
|
||||
3. **E2E tests [fork]** (`test-e2e-fork.yml`) - Triggered manually via slash commands for external PRs
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Initial PR State
|
||||
When a PR is created or updated:
|
||||
- The `test-e2e.yml` workflow automatically runs
|
||||
- For **external PRs**: The `check-external-pr` job detects it's from a fork and **fails intentionally**
|
||||
- For **internal PRs**: The workflow proceeds normally with e2e tests
|
||||
- External PRs show ❌ for the check-external-pr job with a message asking for maintainer approval
|
||||
|
||||
### 2. Manual Approval Required
|
||||
**Important**: External PRs require manual approval before workflows can run.
|
||||
|
||||
**Steps for maintainers:**
|
||||
1. Go to the PR page
|
||||
2. Click **"Approve workflow to run"** button
|
||||
3. The workflow will then execute
|
||||
|
||||
**Note**: The `test-e2e.yml` workflow will still fail for external PRs even after approval, as it's designed to prevent automatic execution. Need to use the slash command instead.
|
||||
|
||||
### 3. Testing External PRs
|
||||
Once the initial checks have run (and failed), maintainers can test the PR using slash commands:
|
||||
|
||||
#### Step-by-Step Process:
|
||||
|
||||
1. **Navigate to the PR**
|
||||
- Go to the pull request you want to test
|
||||
|
||||
2. **Add a comment with slash command**
|
||||
```
|
||||
/ok-to-test sha=<commit-sha>
|
||||
```
|
||||
Replace `<commit-sha>` with the actual commit SHA from the PR.
|
||||
|
||||
**Note**: Use the short SHA.
|
||||
|
||||
3. **Dispatch Action Triggers**
|
||||
- The `ok-to-test.yml` workflow processes the slash command
|
||||
- It triggers a `repository_dispatch` event with type `ok-to-test-command`
|
||||
- The `test-e2e-fork.yml` workflow starts
|
||||
|
||||
4. **Workflow Execution**
|
||||
The fork workflow runs two jobs:
|
||||
|
||||
**a) `run-e2e-tests` job** (conditional)
|
||||
- Only runs if:
|
||||
- Event is `repository_dispatch`
|
||||
- SHA parameter is not empty
|
||||
- PR head SHA contains the provided SHA
|
||||
- Calls the reusable `run-e2e-tests.yml` workflow
|
||||
- Runs the actual E2E tests if conditions are met
|
||||
|
||||
**b) `update-check-status` job** (conditional)
|
||||
- Runs after `e2e-tests` completes
|
||||
- Updates the existing check for job named "run-e2e-tests" from 'test-e2e.yml' workflow
|
||||
- Sets the conclusion based on `run-e2e-tests` result:
|
||||
- ✅ **Success** if tests pass
|
||||
- ❌ **Failure** if tests fail
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Workflow Not Running
|
||||
- **Check**: Ensure you've approved the workflow to run
|
||||
- **Action**: Click "Approve workflow to run" in the PR checks tab
|
||||
|
||||
### SHA Not Found
|
||||
- **Check**: Verify the SHA exists in the PR commits
|
||||
- **Action**: Use `git log --oneline` to find valid commit SHAs
|
||||
|
||||
### Dispatch Not Triggering
|
||||
- **Check**: Ensure the slash command format is correct
|
||||
- **Action**: Use exact format: `/ok-to-test sha=<sha>`
|
||||
|
||||
### Check Runs Not Updating
|
||||
- **Note**: The fork workflow updates the existing "E2E Tests [reusable]" check run
|
||||
- **Behavior**: The same check run is updated with new results rather than creating a new one
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Only users with **write** permissions can trigger dispatch commands
|
||||
- The fork workflow runs in the main repository context, allowing it to update check runs
|
||||
- Manual approval is required for external PR workflows
|
||||
- External PRs are automatically detected and prevented from running tests automatically
|
||||
|
||||
## Workflow Files
|
||||
|
||||
- **`.github/workflows/ok-to-test.yml`** - Ok To Test - Slash command processor
|
||||
- **`.github/workflows/test-e2e.yml`** - E2E Tests - Initial PR checks
|
||||
- **`.github/workflows/test-e2e-fork.yml`** - E2E tests [fork] - Dispatch action handler
|
||||
- **`.github/workflows/e2e-tests.yml`** - E2E Tests [reusable] - Reusable workflow for actual testing
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] PR created with failing check-external-pr check (for external PRs)
|
||||
- [ ] Workflow approved to run (if required)
|
||||
- [ ] Slash command posted with valid SHA
|
||||
- [ ] Dispatch action triggered successfully
|
||||
- [ ] `check-external-pr` check run updated with correct conclusion
|
@@ -16,5 +16,7 @@
|
||||
1. [Install `kind`](https://kind.sigs.k8s.io/docs/user/quick-start/#installing-with-a-package-manager) to spin up local Kubernetes cluster.
|
||||
2. `export OP_CONNECT_TOKEN=<token>`
|
||||
3. `export OP_SERVICE_ACCOUNT_TOKEN=<token>`
|
||||
4. Put `1password-credentials.json` into project root.
|
||||
5. `make test-e2e`
|
||||
4. `make test-e2e`
|
||||
5. Put `1password-credentials.json` into project root.
|
||||
|
||||
**Run**: `make test-e2e`
|
||||
|
6
go.mod
6
go.mod
@@ -4,18 +4,15 @@ go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
// In main go.mod, add this replace directive:
|
||||
replace github.com/1Password/onepassword-operator/pkg/testhelper => ./pkg/testhelper
|
||||
|
||||
require (
|
||||
github.com/1Password/connect-sdk-go v1.5.3
|
||||
github.com/1Password/onepassword-operator/pkg/testhelper v0.0.0-00010101000000-000000000000
|
||||
github.com/1password/onepassword-sdk-go v0.3.1
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/onsi/ginkgo/v2 v2.22.0
|
||||
github.com/onsi/gomega v1.36.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
k8s.io/api v0.33.0
|
||||
k8s.io/apiextensions-apiserver v0.33.0
|
||||
k8s.io/apimachinery v0.33.0
|
||||
k8s.io/client-go v0.33.0
|
||||
k8s.io/kubectl v0.29.0
|
||||
@@ -106,7 +103,6 @@ require (
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.0 // indirect
|
||||
k8s.io/apiserver v0.33.0 // indirect
|
||||
k8s.io/component-base v0.33.0 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
|
@@ -1,115 +0,0 @@
|
||||
# OnePassword Operator Test Helper
|
||||
|
||||
This is a standalone Go module that provides testing utilities for Kubernetes operators, specifically designed for testing OnePassword operators but can be used for any Kubernetes operator testing.
|
||||
|
||||
## Installation
|
||||
|
||||
To use this module in your project, add it as a dependency:
|
||||
|
||||
```bash
|
||||
go get github.com/1Password/onepassword-operator/pkg/testhelper@<commit-hash>
|
||||
```
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/1Password/onepassword-operator/pkg/testhelper/kube"
|
||||
"github.com/1Password/onepassword-operator/pkg/testhelper/defaults"
|
||||
)
|
||||
|
||||
// Create a kube client for testing
|
||||
kubeClient := kube.NewKubeClient(&kube.Config{
|
||||
Namespace: "default",
|
||||
ManifestsDir: "manifests",
|
||||
TestConfig: &kube.TestConfig{
|
||||
Timeout: defaults.E2ETimeout,
|
||||
Interval: defaults.E2EInterval,
|
||||
},
|
||||
CRDs: []string{
|
||||
"path/to/your/crd.yaml",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Working with Secrets
|
||||
|
||||
```go
|
||||
// Create a secret from environment variable
|
||||
secret := kubeClient.Secret("my-secret")
|
||||
secret.CreateFromEnvVar(ctx, "MY_ENV_VAR")
|
||||
|
||||
// Create a secret from file
|
||||
data := []byte("secret content")
|
||||
secret.CreateFromFile(ctx, "filename", data)
|
||||
|
||||
// Check if secret exists
|
||||
secret.CheckIfExists(ctx)
|
||||
|
||||
// Get secret
|
||||
secretObj := secret.Get(ctx)
|
||||
```
|
||||
|
||||
### Working with Deployments
|
||||
|
||||
```go
|
||||
deployment := kubeClient.Deployment("my-deployment")
|
||||
|
||||
// Read environment variable from deployment
|
||||
envVar := deployment.ReadEnvVar(ctx, "MY_ENV_VAR")
|
||||
|
||||
// Patch environment variables
|
||||
deployment.PatchEnvVars(ctx,
|
||||
[]corev1.EnvVar{
|
||||
{Name: "NEW_VAR", Value: "new_value"},
|
||||
},
|
||||
[]string{"OLD_VAR"}, // variables to remove
|
||||
)
|
||||
|
||||
// Wait for deployment rollout
|
||||
deployment.WaitDeploymentRolledOut(ctx)
|
||||
```
|
||||
|
||||
### Working with Pods
|
||||
|
||||
```go
|
||||
pod := kubeClient.Pod(map[string]string{"app": "my-app"})
|
||||
pod.WaitingForRunningPod(ctx)
|
||||
```
|
||||
|
||||
### Working with Namespaces
|
||||
|
||||
```go
|
||||
namespace := kubeClient.Namespace("my-namespace")
|
||||
namespace.LabelNamespace(ctx, map[string]string{
|
||||
"environment": "test",
|
||||
})
|
||||
```
|
||||
|
||||
### System Utilities
|
||||
|
||||
```go
|
||||
import "github.com/1Password/onepassword-operator/pkg/testhelper/system"
|
||||
|
||||
// Run shell commands
|
||||
output, err := system.Run("kubectl", "get", "pods")
|
||||
|
||||
// Get project root directory
|
||||
rootDir, err := system.GetProjectRoot()
|
||||
|
||||
// Replace files
|
||||
err := system.ReplaceFile("source.yaml", "dest.yaml")
|
||||
```
|
||||
|
||||
### Kind Integration
|
||||
|
||||
```go
|
||||
import "github.com/1Password/onepassword-operator/pkg/testhelper/kind"
|
||||
|
||||
// Load Docker image to Kind cluster
|
||||
kind.LoadImageToKind("my-image:latest")
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see the main project LICENSE file for details.
|
@@ -1,59 +0,0 @@
|
||||
module github.com/1Password/onepassword-operator/pkg/testhelper
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/onsi/ginkgo/v2 v2.22.0
|
||||
github.com/onsi/gomega v1.36.1
|
||||
k8s.io/api v0.33.0
|
||||
k8s.io/apiextensions-apiserver v0.33.0
|
||||
k8s.io/apimachinery v0.33.0
|
||||
k8s.io/client-go v0.33.0
|
||||
sigs.k8s.io/controller-runtime v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/term v0.32.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/time v0.9.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
@@ -1,156 +0,0 @@
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk=
|
||||
github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
|
||||
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
|
||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
|
||||
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
|
||||
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU=
|
||||
k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM=
|
||||
k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs=
|
||||
k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc=
|
||||
k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ=
|
||||
k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98=
|
||||
k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
|
||||
sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
@@ -11,7 +11,6 @@ import (
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
//nolint:staticcheck // ST1001
|
||||
. "github.com/onsi/gomega"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
@@ -23,12 +22,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
|
||||
apiv1 "github.com/1Password/onepassword-operator/api/v1"
|
||||
"github.com/1Password/onepassword-operator/pkg/testhelper/defaults"
|
||||
)
|
||||
|
||||
@@ -45,10 +44,9 @@ type Config struct {
|
||||
}
|
||||
|
||||
type Kube struct {
|
||||
Config *Config
|
||||
Client client.Client
|
||||
Clientset kubernetes.Interface
|
||||
Mapper meta.RESTMapper
|
||||
Config *Config
|
||||
Client client.Client
|
||||
Mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
func NewKubeClient(config *Config) *Kube {
|
||||
@@ -75,7 +73,7 @@ func NewKubeClient(config *Config) *Kube {
|
||||
scheme := runtime.NewScheme()
|
||||
utilruntime.Must(corev1.AddToScheme(scheme))
|
||||
utilruntime.Must(appsv1.AddToScheme(scheme))
|
||||
utilruntime.Must(admissionregistrationv1.AddToScheme(scheme))
|
||||
utilruntime.Must(apiv1.AddToScheme(scheme)) // add OnePasswordItem to scheme
|
||||
|
||||
kubernetesClient, err := client.New(restConfig, client.Options{
|
||||
Scheme: scheme,
|
||||
@@ -83,10 +81,6 @@ func NewKubeClient(config *Config) *Kube {
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Create Kubernetes clientset for logs and other operations
|
||||
clientset, err := kubernetes.NewForConfig(restConfig)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// update the current context’s namespace in kubeconfig
|
||||
pathOpts := clientcmd.NewDefaultPathOptions()
|
||||
cfg, err := pathOpts.GetStartingConfig()
|
||||
@@ -103,10 +97,9 @@ func NewKubeClient(config *Config) *Kube {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return &Kube{
|
||||
Config: config,
|
||||
Client: kubernetesClient,
|
||||
Clientset: clientset,
|
||||
Mapper: rm,
|
||||
Config: config,
|
||||
Client: kubernetesClient,
|
||||
Mapper: rm,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +121,9 @@ func (k *Kube) Deployment(name string) *Deployment {
|
||||
|
||||
func (k *Kube) Pod(selector map[string]string) *Pod {
|
||||
return &Pod{
|
||||
client: k.Client,
|
||||
clientset: k.Clientset,
|
||||
config: k.Config,
|
||||
selector: selector,
|
||||
client: k.Client,
|
||||
config: k.Config,
|
||||
selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,16 +135,8 @@ func (k *Kube) Namespace(name string) *Namespace {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Kube) Webhook(name string) *Webhook {
|
||||
return &Webhook{
|
||||
client: k.Client,
|
||||
config: k.Config,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply applies a Kubernetes manifest file using server-side apply.
|
||||
func (k *Kube) Apply(ctx context.Context, fileName string) {
|
||||
// ApplyOnePasswordItem applies a OnePasswordItem manifest.
|
||||
func (k *Kube) ApplyOnePasswordItem(ctx context.Context, fileName string) {
|
||||
By("Applying " + fileName)
|
||||
|
||||
// Derive a short-lived context so this API call won't hang indefinitely.
|
||||
|
@@ -2,7 +2,6 @@ package kube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // ST1001
|
||||
@@ -11,15 +10,13 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type Pod struct {
|
||||
client client.Client
|
||||
clientset kubernetes.Interface
|
||||
config *Config
|
||||
selector map[string]string
|
||||
client client.Client
|
||||
config *Config
|
||||
selector map[string]string
|
||||
}
|
||||
|
||||
func (p *Pod) WaitingForRunningPod(ctx context.Context) {
|
||||
@@ -48,90 +45,3 @@ func (p *Pod) WaitingForRunningPod(ctx context.Context) {
|
||||
g.Expect(foundRunning).To(BeTrue(), "pod not Running yet")
|
||||
}, p.config.TestConfig.Timeout, p.config.TestConfig.Interval).Should(Succeed())
|
||||
}
|
||||
|
||||
func (p *Pod) GetPodLogs(ctx context.Context) string {
|
||||
// First find the pod by label selector
|
||||
var pods corev1.PodList
|
||||
listOpts := []client.ListOption{
|
||||
client.InNamespace(p.config.Namespace),
|
||||
client.MatchingLabels(p.selector),
|
||||
}
|
||||
err := p.client.List(ctx, &pods, listOpts...)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(pods.Items).NotTo(BeEmpty(), "no pods found with selector %q", labels.Set(p.selector).String())
|
||||
|
||||
// Use the first pod found
|
||||
pod := pods.Items[0]
|
||||
podName := pod.Name
|
||||
|
||||
// Verify pod is running before getting logs
|
||||
Expect(pod.Status.Phase).To(Equal(corev1.PodRunning), "pod %s is not running (status: %s)", podName, pod.Status.Phase)
|
||||
|
||||
// Get logs using the Kubernetes clientset
|
||||
req := p.clientset.CoreV1().Pods(p.config.Namespace).GetLogs(podName, &corev1.PodLogOptions{})
|
||||
stream, err := req.Stream(context.TODO())
|
||||
Expect(err).NotTo(HaveOccurred(), "failed to stream logs for pod %s", podName)
|
||||
defer stream.Close()
|
||||
|
||||
// Read all logs from the stream
|
||||
logs, err := io.ReadAll(stream)
|
||||
Expect(err).NotTo(HaveOccurred(), "failed to read logs for pod %s", podName)
|
||||
|
||||
return string(logs)
|
||||
}
|
||||
|
||||
func (p *Pod) VerifyWebhookInjection(ctx context.Context) {
|
||||
By("Verifying webhook injection for pod with selector " + labels.Set(p.selector).String())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
// short per-attempt timeout to avoid hanging calls while Eventually polls
|
||||
attemptCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// First find the pod by label selector
|
||||
var pods corev1.PodList
|
||||
listOpts := []client.ListOption{
|
||||
client.InNamespace(p.config.Namespace),
|
||||
client.MatchingLabels(p.selector),
|
||||
}
|
||||
g.Expect(p.client.List(attemptCtx, &pods, listOpts...)).To(Succeed())
|
||||
g.Expect(pods.Items).NotTo(BeEmpty(), "no pods found with selector %q", labels.Set(p.selector).String())
|
||||
|
||||
// Use the first pod found
|
||||
pod := pods.Items[0]
|
||||
|
||||
// Check injection status annotation
|
||||
g.Expect(pod.Annotations).To(HaveKey("operator.1password.io/status"))
|
||||
g.Expect(pod.Annotations["operator.1password.io/status"]).To(Equal("injected"))
|
||||
|
||||
// Check command was modified to use op run
|
||||
if len(pod.Spec.Containers) > 0 {
|
||||
container := pod.Spec.Containers[0]
|
||||
g.Expect(container.Command).To(HaveLen(4))
|
||||
g.Expect(container.Command[0]).To(Equal("/op/bin/op"))
|
||||
g.Expect(container.Command[1]).To(Equal("run"))
|
||||
g.Expect(container.Command[2]).To(Equal("--"))
|
||||
}
|
||||
|
||||
// Check init container was added
|
||||
g.Expect(pod.Spec.InitContainers).To(HaveLen(1))
|
||||
g.Expect(pod.Spec.InitContainers[0].Name).To(Equal("copy-op-bin"))
|
||||
|
||||
// Check volume mount was added
|
||||
g.Expect(pod.Spec.Containers[0].VolumeMounts).To(ContainElement(HaveField("Name", "op-bin")))
|
||||
}, p.config.TestConfig.Timeout, p.config.TestConfig.Interval).Should(Succeed())
|
||||
}
|
||||
|
||||
func (p *Pod) VerifySecretsInjected(ctx context.Context) {
|
||||
By("Verifying secrets are injected and concealed in pod with selector " + labels.Set(p.selector).String())
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
// short per-attempt timeout to avoid hanging calls while Eventually polls
|
||||
attemptCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
logs := p.GetPodLogs(attemptCtx)
|
||||
// Check that secrets are concealed in the application logs
|
||||
g.Expect(logs).To(ContainSubstring("SECRET: '<concealed by 1Password>'"))
|
||||
}, p.config.TestConfig.Timeout, p.config.TestConfig.Interval).Should(Succeed())
|
||||
}
|
||||
|
@@ -1,33 +0,0 @@
|
||||
package kube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
//nolint:staticcheck // ST1001
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
//nolint:staticcheck // ST1001
|
||||
. "github.com/onsi/gomega"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
type Webhook struct {
|
||||
client client.Client
|
||||
config *Config
|
||||
name string
|
||||
}
|
||||
|
||||
func (w *Webhook) WaitForWebhookToBeRegistered(ctx context.Context) {
|
||||
By("Waiting for webhook " + w.name + " to be registered")
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
// short per-attempt timeout to avoid hanging calls while Eventually polls
|
||||
attemptCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
webhookConfig := &admissionregistrationv1.MutatingWebhookConfiguration{}
|
||||
err := w.client.Get(attemptCtx, client.ObjectKey{Name: w.name}, webhookConfig)
|
||||
g.Expect(err).ToNot(HaveOccurred())
|
||||
}, w.config.TestConfig.Timeout, w.config.TestConfig.Interval).Should(Succeed())
|
||||
}
|
@@ -106,7 +106,7 @@ var _ = Describe("Onepassword Operator e2e", Ordered, func() {
|
||||
func runCommonTestCases(ctx context.Context) {
|
||||
It("Should create kubernetes secret from manifest file", func() {
|
||||
By("Creating secret `login` from 1Password item")
|
||||
kubeClient.Apply(ctx, "secret.yaml")
|
||||
kubeClient.ApplyOnePasswordItem(ctx, "secret.yaml")
|
||||
kubeClient.Secret("login").CheckIfExists(ctx)
|
||||
})
|
||||
|
||||
@@ -115,7 +115,7 @@ func runCommonTestCases(ctx context.Context) {
|
||||
secretName := itemName
|
||||
|
||||
By("Creating secret `" + secretName + "` from 1Password item")
|
||||
kubeClient.Apply(ctx, secretName+".yaml")
|
||||
kubeClient.ApplyOnePasswordItem(ctx, secretName+".yaml")
|
||||
kubeClient.Secret(secretName).CheckIfExists(ctx)
|
||||
|
||||
By("Reading old password")
|
||||
@@ -147,7 +147,7 @@ func runCommonTestCases(ctx context.Context) {
|
||||
secretName := itemName
|
||||
|
||||
By("Creating secret `" + secretName + "` from 1Password item")
|
||||
kubeClient.Apply(ctx, secretName+".yaml")
|
||||
kubeClient.ApplyOnePasswordItem(ctx, secretName+".yaml")
|
||||
kubeClient.Secret(secretName).CheckIfExists(ctx)
|
||||
|
||||
By("Reading old password")
|
||||
@@ -205,7 +205,7 @@ func runCommonTestCases(ctx context.Context) {
|
||||
})
|
||||
|
||||
// Ensure the secret exists (created in earlier test), but apply again safely just in case
|
||||
kubeClient.Apply(ctx, "secret-for-update.yaml")
|
||||
kubeClient.ApplyOnePasswordItem(ctx, "secret-for-update.yaml")
|
||||
kubeClient.Secret("secret-for-update").CheckIfExists(ctx)
|
||||
|
||||
// add custom secret to the operator
|
||||
|
Reference in New Issue
Block a user