diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..58e51bd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,13 @@ +### โœจ Summary + + +### ๐Ÿ”— Resolves: + + +### โœ… Checklist +- [ ] ๐Ÿ–Š๏ธ Commits are signed +- [ ] ๐Ÿงช Tests added/updated +- [ ] ๐Ÿ“š Docs updated (if behavior changed) + +### ๐Ÿ•ต๏ธ Review Notes & โš ๏ธ Risks + diff --git a/.github/workflows/test.yml b/.github/workflows/test-connect.yml similarity index 59% rename from .github/workflows/test.yml rename to .github/workflows/test-connect.yml index bc1de26..7d1e89e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test-connect.yml @@ -1,4 +1,4 @@ -name: Run acceptance tests +name: Run acceptance tests [Connect chart] on: push: @@ -51,33 +51,16 @@ jobs: run: sudo snap install yq if: steps.list-changed.outputs.changed == 'true' - - name: Add fixtures to YAML test cases - env: - OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }} - OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }} - OP_VAULT_ID: ${{ vars.OP_VAULT_ID || 'v5pz6venw4roosmkzdq2nhpv6u' }} - OP_ITEM_ID: ${{ vars.OP_ITEM_ID || 'hrgkzhrlvscomepxlgafb2m3ca' }} - OP_SECRET_VALUE: ${{ vars.OP_SECRET_VALUE || 'RGVhciBzZWN1cml0eSByZXNlYXJjaGVyLCB0aGlzIGlzIGp1c3QgYSBkdW1teSBzZWNyZXQuIFBsZWFzZSBkb24ndCByZXBvcnQgaXQu' }} - run: | - cat > fixtures.yaml << EOF - acceptanceTests: - enabled: true - fixtures: - vaultId: $OP_VAULT_ID - itemId: $OP_ITEM_ID - secretValue: $OP_SECRET_VALUE - EOF - - for values_file in charts/connect/ci/*.yaml; do - # Add secrets - yq eval '.connect.credentials = strenv(OP_CONNECT_CREDENTIALS) | .operator.token.value = strenv(OP_CONNECT_TOKEN)' -i $values_file - - # Add acceptance test fixtures - yq eval-all --inplace 'select(fileIndex == 0) * select(fileIndex == 1)' $values_file fixtures.yaml - done - - name: Spin up local Kubernetes cluster uses: helm/kind-action@v1.2.0 - - name: Deploy and run acceptance tests - run: ct install --config ct.yaml + - name: Run acceptance tests + working-directory: charts/connect + env: + OP_CONNECT_CREDENTIALS: ${{ secrets.OP_CONNECT_CREDENTIALS }} + OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }} + OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }} + OP_VAULT_ID: ${{ secrets.OP_VAULT_ID }} + OP_ITEM_ID: ${{ secrets.OP_ITEM_ID }} + OP_SECRET_VALUE: ${{ secrets.OP_SECRET_VALUE }} + run: make test-e2e diff --git a/charts/connect/Makefile b/charts/connect/Makefile new file mode 100644 index 0000000..e27bc9a --- /dev/null +++ b/charts/connect/Makefile @@ -0,0 +1,195 @@ +# 1Password Connect Helm Chart - Testing + +# Configuration +CHART_NAME := connect +NAMESPACE := default +KIND_CLUSTER_NAME := onepassword-connect-test +HELM_TIMEOUT := 120s + +# Credentials +OP_CONNECT_CREDENTIALS ?= $(shell echo "$$OP_CONNECT_CREDENTIALS") +OP_CONNECT_TOKEN ?= $(shell echo "$$OP_CONNECT_TOKEN") +OP_SERVICE_ACCOUNT_TOKEN ?= $(shell echo "$$OP_SERVICE_ACCOUNT_TOKEN") + +# Test fixture values (must be set as environment variables) +# OP_VAULT_ID - 1Password vault ID for testing +# OP_ITEM_ID - 1Password item ID for testing +# OP_SECRET_VALUE - Expected secret value for testing + +# Colors for output +RED := \033[0;31m +GREEN := \033[0;32m +YELLOW := \033[0;33m +BLUE := \033[0;34m +NC := \033[0m # No Color + +.PHONY: help test-e2e test-e2e-setup test-e2e-run cleanup-test-e2e check-deps revert-ci-files + +test-e2e: check-deps test-e2e-setup test-e2e-run cleanup-test-e2e ## Run end-to-end tests (full workflow) + +test-e2e-setup: ## Setup test environment + @echo "$(BLUE)Setting up test environment...$(NC)" + + # Check if all required environment variables are set + @if [ -z "$(OP_CONNECT_CREDENTIALS)" ]; then \ + echo "$(RED)Error: OP_CONNECT_CREDENTIALS environment variable is required$(NC)"; \ + exit 1; \ + fi + @if [ -z "$(OP_CONNECT_TOKEN)" ]; then \ + echo "$(RED)Error: OP_CONNECT_TOKEN environment variable is required$(NC)"; \ + exit 1; \ + fi + + @if [ -z "$(OP_SERVICE_ACCOUNT_TOKEN)" ]; then \ + echo "$(RED)Error: OP_SERVICE_ACCOUNT_TOKEN environment variable is required$(NC)"; \ + exit 1; \ + fi + + @if [ -z "$(OP_VAULT_ID)" ]; then \ + echo "$(RED)Error: OP_VAULT_ID environment variable is required$(NC)"; \ + echo "$(YELLOW)Set OP_VAULT_ID to your 1Password vault ID for testing$(NC)"; \ + exit 1; \ + fi + @if [ -z "$(OP_ITEM_ID)" ]; then \ + echo "$(RED)Error: OP_ITEM_ID environment variable is required$(NC)"; \ + echo "$(YELLOW)Set OP_ITEM_ID to your 1Password item ID for testing$(NC)"; \ + exit 1; \ + fi + @if [ -z "$(OP_SECRET_VALUE)" ]; then \ + echo "$(RED)Error: OP_SECRET_VALUE environment variable is required$(NC)"; \ + echo "$(YELLOW)Set OP_SECRET_VALUE to the expected secret value for testing$(NC)"; \ + exit 1; \ + fi + + # Create Kind cluster + @echo "$(BLUE)Creating Kind cluster...$(NC)" + @kind create cluster --name $(KIND_CLUSTER_NAME) --wait 60s || true + + # Create namespace + @echo "$(BLUE)Creating namespace...$(NC)" + @kubectl create namespace $(NAMESPACE) --dry-run=client -o yaml | kubectl apply -f - + + # Prepare test fixtures + @echo "$(BLUE)Preparing test fixtures...$(NC)" + @echo "acceptanceTests:" > fixtures.yaml + @echo " enabled: true" >> fixtures.yaml + @echo " fixtures:" >> fixtures.yaml + @echo " vaultId: $(OP_VAULT_ID)" >> fixtures.yaml + @echo " itemId: $(OP_ITEM_ID)" >> fixtures.yaml + @echo " secretValue: $(OP_SECRET_VALUE)" >> fixtures.yaml + + # Process CI values files + @echo "$(BLUE)Processing CI values files...$(NC)" + @for values_file in ci/*.yaml; do \ + echo "$(BLUE)Processing $$values_file...$(NC)"; \ + if echo "$$values_file" | grep -q "service-account"; then \ + yq eval '.connect.create = false | .operator.authMethod = "service-account" | .operator.serviceAccountToken.value = strenv(OP_SERVICE_ACCOUNT_TOKEN)' -i $$values_file; \ + else \ + yq eval '.connect.credentials = strenv(OP_CONNECT_CREDENTIALS) | .operator.authMethod = "connect" | .operator.token.value = strenv(OP_CONNECT_TOKEN)' -i $$values_file; \ + fi; \ + yq eval-all --inplace 'select(fileIndex == 0) * select(fileIndex == 1)' $$values_file fixtures.yaml; \ + done + + @echo "$(GREEN)Test environment setup complete$(NC)" + +test-e2e-run: ## Run the actual tests + @echo "$(BLUE)Running end-to-end tests...$(NC)" + + # Set up Helm repository + @helm repo add stable https://charts.helm.sh/stable || true + @helm repo update + + # Run chart testing + @echo "$(BLUE)Installing chart and running tests...$(NC)" + @cd ../.. && ct install --config ct.yaml --charts charts/connect --namespace $(NAMESPACE) + + @echo "$(GREEN)Tests completed successfully!$(NC)" + +cleanup-test-e2e: revert-ci-files ## Cleanup test environment + @echo "$(BLUE)Cleaning up test environment...$(NC)" + + # Delete Kind cluster + @kind delete cluster --name $(KIND_CLUSTER_NAME) || true + + # Clean up temporary files + @rm -f fixtures.yaml + + @echo "$(GREEN)Cleanup complete$(NC)" + +revert-ci-files: ## Revert all changes to files in the ci/ directory + @echo "$(BLUE)Reverting changes to ci/ directory files...$(NC)" + @cd ../.. && git checkout -- charts/connect/ci/ + @cd ../.. && git clean -f charts/connect/ci/ + @echo "$(GREEN)CI files reverted successfully$(NC)" + +# Utility commands +show-config: ## Show current test configuration + @echo "$(BLUE)Test Configuration:$(NC)" + @echo " Chart Name: $(CHART_NAME)" + @echo " Namespace: $(NAMESPACE)" + @echo " Kind Cluster: $(KIND_CLUSTER_NAME)" + @echo "" + @echo "$(BLUE)Test Fixtures:$(NC)" + @echo " Vault ID: $(if $(OP_VAULT_ID),$(OP_VAULT_ID),Not Set)" + @echo " Item ID: $(if $(OP_ITEM_ID),$(OP_ITEM_ID),Not Set)" + @echo " Secret Value: $(if $(OP_SECRET_VALUE),Set,Not Set)" + @echo "" + @echo "$(BLUE)Credentials:$(NC)" + @echo " Connect Credentials: $(if $(OP_CONNECT_CREDENTIALS),Set,Not Set)" + @echo " Connect Token: $(if $(OP_CONNECT_TOKEN),Set,Not Set)" + @echo " Service Account Token: $(if $(OP_SERVICE_ACCOUNT_TOKEN),Set,Not Set)" + +install: ## Install required dependencies (auto-detect OS) + @echo "$(BLUE)Detecting operating system...$(NC)" + @if [ "$$(uname -s)" = "Darwin" ]; then \ + echo "$(GREEN)Detected macOS$(NC)"; \ + $(MAKE) install-macos; \ + elif [ "$$(uname -s)" = "Linux" ]; then \ + echo "$(GREEN)Detected Linux$(NC)"; \ + $(MAKE) install-linux; \ + else \ + echo "$(RED)Unsupported operating system: $$(uname -s)$(NC)"; \ + echo "$(YELLOW)Please install dependencies manually or add support for your OS$(NC)"; \ + exit 1; \ + fi + +install-macos: ## Install required dependencies (macOS) + @echo "$(BLUE)Installing dependencies for macOS...$(NC)" + @brew install helm kind yq chart-testing + @echo "$(GREEN)macOS dependencies installed$(NC)" + +install-linux: ## Install required dependencies (Linux) + @echo "$(BLUE)Installing dependencies for Linux...$(NC)" + @echo "$(YELLOW)Updating package lists...$(NC)" + @sudo apt update + @echo "$(YELLOW)Installing tools via apt...$(NC)" + @sudo apt install -y helm kind yq chart-testing + @echo "$(GREEN)Linux dependencies installed$(NC)" + +install-windows: ## Install required dependencies (Windows) + @echo "$(BLUE)Installing dependencies for Windows...$(NC)" + @echo "$(YELLOW)Installing tools via Chocolatey...$(NC)" + @choco install kubernetes-helm kind yq chart-testing -y --no-progress + @echo "$(GREEN)Windows dependencies installed$(NC)" + +check-deps: ## Check if required dependencies are installed + @echo "$(BLUE)Checking dependencies...$(NC)" + @command -v helm >/dev/null 2>&1 || { echo "$(RED)helm is required but not installed$(NC)"; exit 1; } + @command -v kind >/dev/null 2>&1 || { echo "$(RED)kind is required but not installed$(NC)"; exit 1; } + @command -v yq >/dev/null 2>&1 || { echo "$(RED)yq is required but not installed$(NC)"; exit 1; } + @command -v ct >/dev/null 2>&1 || { echo "$(RED)ct (chart-testing) is required but not installed$(NC)"; exit 1; } + @echo "$(GREEN)All dependencies are installed$(NC)" + +help: ## Show this help message + @echo "1Password Connect Helm Chart - Testing" + @echo "" + @echo "Available commands:" + @echo "" + @echo "$(BLUE)Installation Commands:$(NC)" + @awk 'BEGIN {FS = ":.*?## "} /^install.*:.*?## / {printf " $(BLUE)%-20s$(NC) %s\n", $$1, $$2}' $(MAKEFILE_LIST) + @echo "" + @echo "$(BLUE)Testing Commands:$(NC)" + @awk 'BEGIN {FS = ":.*?## "} /^test-e2e.*:.*?## / {printf " $(BLUE)%-20s$(NC) %s\n", $$1, $$2}' $(MAKEFILE_LIST) + @echo "" + @echo "$(BLUE)Utility Commands:$(NC)" + @awk 'BEGIN {FS = ":.*?## "} /^(check-deps|show-config|revert-ci-files):.*?## / {printf " $(BLUE)%-20s$(NC) %s\n", $$1, $$2}' $(MAKEFILE_LIST) diff --git a/charts/connect/ci/with-connect-values.yaml b/charts/connect/ci/with-connect-values.yaml new file mode 100644 index 0000000..937fbef --- /dev/null +++ b/charts/connect/ci/with-connect-values.yaml @@ -0,0 +1,8 @@ +# Deploys Operator with default configuration using Connect to authenticate +operator: + create: true + customEnvVars: + - name: CUSTOM_TEST_VAR + value: "test-value-123" + - name: ANOTHER_CUSTOM_VAR + value: "another-value-456" diff --git a/charts/connect/ci/with-operator-values.yaml b/charts/connect/ci/with-operator-values.yaml deleted file mode 100644 index 02cae1a..0000000 --- a/charts/connect/ci/with-operator-values.yaml +++ /dev/null @@ -1,4 +0,0 @@ -operator: - create: true - token: - name: op-operator-connect-token diff --git a/charts/connect/ci/with-service-account-values.yaml b/charts/connect/ci/with-service-account-values.yaml new file mode 100644 index 0000000..7718fcf --- /dev/null +++ b/charts/connect/ci/with-service-account-values.yaml @@ -0,0 +1,6 @@ +# Deploys Operator with default configuration using Service Account to authenticate +operator: + create: true + authMethod: service-account +connect: + create: false diff --git a/charts/connect/docs/fork-pr-testing.md b/charts/connect/docs/fork-pr-testing.md new file mode 100644 index 0000000..fa32ae4 --- /dev/null +++ b/charts/connect/docs/fork-pr-testing.md @@ -0,0 +1,14 @@ +# Fork PR Testing Guide + +This document explains how to test external pull requests using workflow dispatch. + +## How to test external PR + +* Do a sanity check on the submitted PR +* Copy the most recent commit hash of the PR branch +* Go to 'Actions' -> 'Run acceptance tests' -> 'Run workflow' +* Fill in the following: + * `checkout-repo`: `/connect-helm-charts` + * `checkout-ref`: + * `branch`: `acceptance-tests-on-forks` +* After pipeline finishes, drop a comment and in the PR to let the contributor know if there are any issues diff --git a/charts/connect/docs/local-testing.md b/charts/connect/docs/local-testing.md new file mode 100644 index 0000000..4cb8cd9 --- /dev/null +++ b/charts/connect/docs/local-testing.md @@ -0,0 +1,130 @@ +# Local Testing Guide + +This guide explains how to run the same end-to-end tests locally that run in GitHub Actions. + +## Prerequisites + +### Required Tools +- **Helm** (v3.4.1+) +- **Kind** (Kubernetes in Docker) +- **yq** (YAML processor) +- **ct** (chart-testing CLI) + +## Quick Start + +### 1. Install Dependencies +```bash +# Auto-detect OS and install dependencies +make install +``` + +### 2. Set Up Test Environment + +#### Set Environment Variables +```bash +# Set credentials as environment variables +export OP_CONNECT_CREDENTIALS=$(cat ./1password-credentials.json) # your 1password-credentials.json file content +export OP_CONNECT_TOKEN="your-connect-token" +export OP_SERVICE_ACCOUNT_TOKEN="your-service-account-token" + +# Set required test fixture values +export OP_VAULT_ID="your-vault-id" +export OP_ITEM_ID="your-item-id" +export OP_SECRET_VALUE="your-expected-secret-value" +``` + +### 3. Run Tests +```bash +# Run the complete test suite +make test-e2e +``` + +## Available Commands + +### Installation Commands +- `make install` - Auto-detect OS and install dependencies +- `make install-macos` - Install dependencies for macOS (Homebrew) +- `make install-linux` - Install dependencies for Linux +- `make install-windows` - Install dependencies for Windows (WSL/Git Bash) + +### Main Test Commands +- `make test-e2e` - Run complete end-to-end tests (setup โ†’ test โ†’ cleanup) + +### Utility Commands +- `make check-deps` - Check if all dependencies are installed +- `make show-config` - Show current test configuration +- `make cleanup-test-e2e` - Clean up test environment + +## Adding New Test Scenarios +To add a new test scenario: +1. Create a new YAML file in `ci/` directory +2. Configure the desired chart values +3. The workflow will automatically run tests for this configuration + +## Debugging + +### Keep Cluster for Debugging +```bash +make test-e2e +# If tests fail the cluster stays running +kubectl get pods -n onepassword-connect-test +kubectl logs -n onepassword-connect-test +make test-e2e-cleanup # Clean up when done +``` + +### Check Test Logs +```bash +# After running tests, check pod logs +kubectl get pods -n onepassword-connect-test +kubectl logs -n onepassword-connect-test +``` + +### Manual Chart Installation +```bash +# Install chart manually for testing +helm install connect . --namespace onepassword-connect-test \ + --set connect.credentials="$(echo $OP_CONNECT_CREDENTIALS | base64 -d)" \ + --set operator.token.value="$OP_CONNECT_TOKEN" +``` + +## Troubleshooting + +### Common Issues + +1. **Missing Environment Variables** + ```bash + # Check which variables are missing + make show-config + + # Set all required variables + export OP_CONNECT_CREDENTIALS="your-credentials" + export OP_CONNECT_TOKEN="your-token" + export OP_VAULT_ID="your-vault-id" + export OP_ITEM_ID="your-item-id" + export OP_SECRET_VALUE="your-secret-value" + ``` + +2. **Kind Cluster Issues** + ```bash + # Check cluster status + kind get clusters + + # Delete and recreate + kind delete cluster --name onepassword-connect-test + make test-e2e-setup + ``` + +3. **Test Failures** + ```bash + # Run test + make test-e2e + + # Check pod logs + kubectl logs -n onepassword-connect-test + ``` + +## Security Notes + +- Environment variables contain sensitive credentials +- Never commit credentials to git +- Use `1password-cli` for secure credential management when possible diff --git a/charts/connect/templates/tests/custom-env-vars-check.yml b/charts/connect/templates/tests/custom-env-vars-check.yml new file mode 100644 index 0000000..64fba73 --- /dev/null +++ b/charts/connect/templates/tests/custom-env-vars-check.yml @@ -0,0 +1,52 @@ +{{- if and .Values.operator.create .Values.operator.customEnvVars -}} +apiVersion: v1 +kind: Pod +metadata: + name: "{{ .Release.Name }}-custom-env-vars-check" + namespace: {{ .Release.Namespace }} + labels: + {{- include "onepassword-connect.labels" . | nindent 4 }} + annotations: + helm.sh/hook: test + helm.sh/hook-weight: "4" +spec: + serviceAccountName: {{ .Values.operator.serviceAccount.name }} + restartPolicy: Never + containers: + - name: env-check + image: alpine/k8s:1.28.2 + command: ["sh", "-c"] + args: + - | + # Get the operator pod name using the deployment name + OPERATOR_POD=$(kubectl get pods -l name={{ .Values.connect.applicationName }} -o jsonpath='{.items[0].metadata.name}') + + if [ -z "$OPERATOR_POD" ]; then + echo "โŒ Could not find operator pod" + exit 1 + fi + + echo "๐Ÿ” Found operator pod: $OPERATOR_POD" + + # Check if custom environment variables are set in the deployment spec + echo "๐Ÿ” Checking for CUSTOM_TEST_VAR in deployment spec..." + if kubectl get deployment {{ .Values.operator.applicationName }} -o yaml | grep -A 1 "name: CUSTOM_TEST_VAR"; then + echo "โœ… CUSTOM_TEST_VAR found in deployment spec" + else + echo "โŒ CUSTOM_TEST_VAR not found in deployment spec" + exit 1 + fi + + echo "๐Ÿ” Checking for ANOTHER_CUSTOM_VAR in deployment spec..." + if kubectl get deployment {{ .Values.operator.applicationName }} -o yaml | grep -A 1 "name: ANOTHER_CUSTOM_VAR"; then + echo "โœ… ANOTHER_CUSTOM_VAR found in deployment spec" + else + echo "โŒ ANOTHER_CUSTOM_VAR not found in deployment spec" + exit 1 + fi + + echo "๐Ÿ” Showing all custom environment variables in deployment:" + kubectl get deployment {{ .Values.operator.applicationName }} -o yaml | grep -A 2 -B 1 "name: CUSTOM_\|name: ANOTHER_" + + echo "โœ… All custom environment variables are correctly configured in the deployment!" +{{- end }}