diff --git a/.github/actions/cloud-slack-e2e/action.yaml b/.github/actions/cloud-slack-e2e/action.yaml new file mode 100644 index 000000000..d47345132 --- /dev/null +++ b/.github/actions/cloud-slack-e2e/action.yaml @@ -0,0 +1,123 @@ +name: Runs e2e Cloud Slack tests +description: Runs e2e Cloud Slack tests + +inputs: + access_token: + description: GitHub personal access token used for cloning private repositories + required: true + + slack_workspace_name: + description: 'Slack Workspace Name' + required: true + slack_email: + description: 'Slack Email' + required: true + slack_password: + description: 'Slack Password' + required: true + slack_tester_bot_token: + description: 'Slack Tester Bot Token' + required: true + slack_bot_display_name: + description: 'Slack Bot Display Name' + required: true + slack_tester_bot_name: + description: 'Slack Tester Bot Name' + required: true + + botkube_cloud_api_base_url: + description: 'BotKube Cloud API Base URL' + required: true + botkube_cloud_email: + description: 'BotKube Cloud Email' + required: true + botkube_cloud_password: + description: 'BotKube Cloud Password' + required: true + botkube_cloud_team_organization_id: + description: 'BotKube Cloud Team Organization ID' + required: true + botkube_cloud_free_organization_id: + description: 'BotKube Cloud Free Organization ID' + required: true + botkube_cloud_plugin_repo_url: + description: 'BotKube Cloud Plugin Repo URL' + required: true + + slack_alerts_webhook: + description: 'Slack Alerts Webhook' + required: true + + e2e_type: + description: "Type of e2e test" + required: true + +runs: + using: "composite" + steps: + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: ${{ env.HELM_VERSION }} + + - name: Download k3d + shell: bash + run: "wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=${K3D_VERSION} bash" + + - name: Create k3d cluster + shell: bash + run: "k3d cluster create cloud-slack-e2e-cluster --wait --timeout=5m" + + - name: Setup Go modules + uses: ./.github/actions/setup-go-mod-private + with: + access_token: ${{ inputs.access_token }} + username: ${{ env.GIT_USER }} + + - name: Run e2e tests + shell: bash + env: + SLACK_WORKSPACE_NAME: ${{ inputs.slack_workspace_name }} + SLACK_EMAIL: ${{ inputs.slack_email }} + SLACK_PASSWORD: ${{ inputs.slack_password }} + SLACK_TESTER_TESTER_BOT_TOKEN: ${{ inputs.slack_tester_bot_token }} + SLACK_BOT_DISPLAY_NAME: ${{ inputs.slack_bot_display_name }} + SLACK_TESTER_BOT_NAME: ${{ inputs.slack_tester_bot_name }} + SLACK_TESTER_MESSAGE_WAIT_TIMEOUT: 90s + + + BOTKUBE_CLOUD_API_BASE_URL: ${{ inputs.botkube_cloud_api_base_url }} + BOTKUBE_CLOUD_EMAIL: ${{ inputs.botkube_cloud_email }} + BOTKUBE_CLOUD_PASSWORD: ${{ inputs.botkube_cloud_password }} + BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID: ${{ inputs.botkube_cloud_team_organization_id }} + BOTKUBE_CLOUD_FREE_ORGANIZATION_ID: ${{ inputs.botkube_cloud_free_organization_id }} + BOTKUBE_CLOUD_PLUGIN_REPO_URL: ${{ inputs.botkube_cloud_plugin_repo_url }} + SCREENSHOTS_DIR: ${{ runner.temp }}/screenshots + DEBUG_MODE: "true" + run: | + KUBECONFIG=$(k3d kubeconfig write cloud-slack-e2e-cluster) make test-cloud-slack-dev-e2e + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + if: ${{ always() }} + with: + name: screenshots_dump_${{github.sha}} + path: ${{ runner.temp }}/screenshots + retention-days: 5 + + - name: Dump cluster state + if: ${{ failure() }} + uses: ./.github/actions/dump-cluster + + - name: Slack Notification + uses: rtCamp/action-slack-notify@v2 + if: ${{ failure() }} + env: + SLACK_USERNAME: Botkube Cloud CI + SLACK_COLOR: 'red' + SLACK_TITLE: 'Message' + SLACK_CHANNEL: 'botkube-cloud-ci-alerts' + SLACK_MESSAGE: 'Cloud Slack {{ inputs.e2e_type }} E2E tests failed :scream:' + SLACK_ICON_EMOJI: ':this-is-fine-fire:' + SLACK_FOOTER: "Fingers crossed it's just an outdated/flaky test..." + SLACK_WEBHOOK: ${{ inputs.slack_alerts_webhook }} diff --git a/.github/workflows/branch-build.yml b/.github/workflows/branch-build.yml index b19fb396f..168035a0f 100644 --- a/.github/workflows/branch-build.yml +++ b/.github/workflows/branch-build.yml @@ -293,62 +293,26 @@ jobs: cancel-in-progress: false steps: - name: Checkout - uses: actions/checkout@v3 - - - name: Install Helm - uses: azure/setup-helm@v3 - with: - version: ${{ env.HELM_VERSION }} - - - name: Download k3d - run: "wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=${K3D_VERSION} bash" - - name: Create k3d cluster - run: "k3d cluster create cloud-slack-dev-e2e-cluster --wait --timeout=5m" - - - name: Setup Go modules - uses: ./.github/actions/setup-go-mod-private + uses: actions/checkout@v4 + - name: Run e2e tests + uses: ./.github/actions/cloud-slack-e2e with: access_token: ${{ secrets.E2E_TEST_GH_DEV_ACCOUNT_PAT }} - username: ${{ env.GIT_USER }} - - - name: Run e2e tests - env: - SLACK_WORKSPACE_NAME: ${{ secrets.E2E_DEV_SLACK_WORKSPACE_NAME }} - SLACK_EMAIL: ${{ secrets.E2E_DEV_SLACK_EMAIL }} - SLACK_PASSWORD: ${{ secrets.E2E_DEV_SLACK_USER_PASSWORD }} - SLACK_TESTER_TESTER_BOT_TOKEN: ${{ secrets.E2E_DEV_SLACK_TESTER_BOT_TOKEN }} - SLACK_TESTER_BOT_NAME: botkubedev - SLACK_TESTER_MESSAGE_WAIT_TIMEOUT: 1m - BOTKUBE_CLOUD_EMAIL: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_EMAIL }} - BOTKUBE_CLOUD_PASSWORD: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_PASSWORD }} - BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID }} - BOTKUBE_CLOUD_FREE_ORGANIZATION_ID: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_FREE_ORGANIZATION_ID }} - SCREENSHOTS_DIR: ${{ runner.temp }}/screenshots - DEBUG_MODE: true - run: | - KUBECONFIG=$(k3d kubeconfig write cli-migration-e2e-cluster) make test-cloud-slack-dev-e2e - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - if: ${{ always() }} - with: - name: screenshots_dump_${{github.sha}} - path: ${{ runner.temp }}/screenshots - retention-days: 5 - - - name: Dump cluster state - if: ${{ failure() }} - uses: ./.github/actions/dump-cluster - - - name: Slack Notification - uses: rtCamp/action-slack-notify@v2 - if: ${{ failure() }} - env: - SLACK_USERNAME: Botkube Cloud CI - SLACK_COLOR: 'red' - SLACK_TITLE: 'Message' - SLACK_CHANNEL: 'botkube-cloud-ci-alerts' - SLACK_MESSAGE: 'Cloud Slack Dev E2E tests failed :scream:' - SLACK_ICON_EMOJI: ':this-is-fine-fire:' - SLACK_FOOTER: "Fingers crossed it's just an outdated/flaky test..." - SLACK_WEBHOOK: ${{ secrets.SLACK_CI_ALERTS_WEBHOOK }} + + slack_workspace_name: ${{ secrets.E2E_DEV_SLACK_WORKSPACE_NAME }} + slack_email: ${{ secrets.E2E_DEV_SLACK_EMAIL }} + slack_password: ${{ secrets.E2E_DEV_SLACK_USER_PASSWORD }} + slack_bot_display_name: "BotkubeDev" + slack_tester_bot_token: ${{ secrets.E2E_DEV_SLACK_TESTER_BOT_TOKEN }} + slack_tester_bot_name: "botkubedev" + + botkube_cloud_api_base_url: "https://api-dev.botkube.io" + botkube_cloud_email: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_EMAIL }} + botkube_cloud_password: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_PASSWORD }} + botkube_cloud_team_organization_id: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID }} + botkube_cloud_free_organization_id: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_FREE_ORGANIZATION_ID }} + botkube_cloud_plugin_repo_url: "https://storage.googleapis.com/botkube-plugins-latest/plugins-dev-index.yaml" + + slack_alerts_webhook: ${{ secrets.SLACK_CI_ALERTS_WEBHOOK }} + + e2e_type: "DEV" diff --git a/.github/workflows/prod-e2e-test.yml b/.github/workflows/prod-e2e-test.yml index 0b03024d3..770c40c18 100644 --- a/.github/workflows/prod-e2e-test.yml +++ b/.github/workflows/prod-e2e-test.yml @@ -11,6 +11,7 @@ env: IMAGE_REGISTRY: "ghcr.io" IMAGE_REPOSITORY: "kubeshop/botkube" IMAGE_TAG: v9.99.9-dev # TODO: Use commit hash tag to make the predictable builds for each commit on branch + GIT_USER: botkube-dev jobs: cloud-slack-prod-e2e: @@ -28,57 +29,25 @@ jobs: with: fetch-depth: 0 - - name: Install Helm - uses: azure/setup-helm@v3 - with: - version: ${{ env.HELM_VERSION }} - - - name: Download k3d - run: "wget -q -O - https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | TAG=${K3D_VERSION} bash" - - name: Create k3d cluster - run: "k3d cluster create cloud-slack-prod-e2e-cluster --wait --timeout=5m" - - name: Run e2e tests - env: - SLACK_WORKSPACE_NAME: ${{ secrets.E2E_DEV_SLACK_WORKSPACE_NAME }} - SLACK_EMAIL: ${{ secrets.E2E_DEV_SLACK_EMAIL }} - SLACK_PASSWORD: ${{ secrets.E2E_DEV_SLACK_USER_PASSWORD }} - SLACK_BOT_DISPLAY_NAME: Botkube - SLACK_TESTER_TESTER_BOT_TOKEN: ${{ secrets.E2E_DEV_SLACK_TESTER_BOT_TOKEN }} - SLACK_TESTER_BOT_NAME: botkube3 - SLACK_TESTER_MESSAGE_WAIT_TIMEOUT: 90s - BOTKUBE_CLOUD_API_BASE_URL: https://api.botkube.io - BOTKUBE_CLOUD_EMAIL: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_EMAIL }} - BOTKUBE_CLOUD_PASSWORD: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_PASSWORD }} - BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID: ${{ secrets.E2E_PROD_BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID }} - BOTKUBE_CLOUD_FREE_ORGANIZATION_ID: ${{ secrets.E2E_PROD_BOTKUBE_CLOUD_FREE_ORGANIZATION_ID }} - BOTKUBE_CLOUD_PLUGIN_REPO_URL: https://storage.googleapis.com/botkube-plugins-latest/plugins-index.yaml - SCREENSHOTS_DIR: ${{ runner.temp }}/screenshots - DEBUG_MODE: true - run: | - KUBECONFIG=$(k3d kubeconfig write cloud-slack-prod-e2e-cluster) make test-cloud-slack-dev-e2e - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - if: ${{ always() }} + uses: ./.github/actions/cloud-slack-e2e with: - name: screenshots_dump_${{github.sha}} - path: ${{ runner.temp }}/screenshots - retention-days: 5 - - - name: Dump cluster state - if: ${{ failure() }} - uses: ./.github/actions/dump-cluster - - - name: Slack Notification - uses: rtCamp/action-slack-notify@v2 - if: ${{ failure() }} - env: - SLACK_USERNAME: Botkube Cloud CI - SLACK_COLOR: 'red' - SLACK_TITLE: 'Message' - SLACK_CHANNEL: 'botkube-cloud-ci-alerts' - SLACK_MESSAGE: 'Cloud Slack Prod E2E tests failed :scream:' - SLACK_ICON_EMOJI: ':this-is-fine-fire:' - SLACK_FOOTER: "Fingers crossed it's just an outdated/flaky test..." - SLACK_WEBHOOK: ${{ secrets.SLACK_PROD_ALERTS_WEBHOOK }} + access_token: ${{ secrets.E2E_TEST_GH_DEV_ACCOUNT_PAT }} + + slack_workspace_name: ${{ secrets.E2E_DEV_SLACK_WORKSPACE_NAME }} + slack_email: ${{ secrets.E2E_DEV_SLACK_EMAIL }} + slack_password: ${{ secrets.E2E_DEV_SLACK_USER_PASSWORD }} + slack_bot_display_name: "Botkube" + slack_tester_bot_token: ${{ secrets.E2E_DEV_SLACK_TESTER_BOT_TOKEN }} + slack_tester_bot_name: "botkube3" + + botkube_cloud_api_base_url: "https://api.botkube.io" + botkube_cloud_email: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_EMAIL }} + botkube_cloud_password: ${{ secrets.E2E_DEV_BOTKUBE_CLOUD_PASSWORD }} + botkube_cloud_team_organization_id: ${{ secrets.E2E_PROD_BOTKUBE_CLOUD_TEAM_ORGANIZATION_ID }} + botkube_cloud_free_organization_id: ${{ secrets.E2E_PROD_BOTKUBE_CLOUD_FREE_ORGANIZATION_ID }} + botkube_cloud_plugin_repo_url: "https://storage.googleapis.com/botkube-plugins-latest/plugins-index.yaml" + + slack_alerts_webhook: ${{ secrets.SLACK_PROD_ALERTS_WEBHOOK }} + + e2e_type: "PROD" diff --git a/test/cloud-slack-dev-e2e/cloud_slack_dev_e2e_test.go b/test/cloud-slack-dev-e2e/cloud_slack_dev_e2e_test.go index f81df1a79..c21237bcc 100644 --- a/test/cloud-slack-dev-e2e/cloud_slack_dev_e2e_test.go +++ b/test/cloud-slack-dev-e2e/cloud_slack_dev_e2e_test.go @@ -148,7 +148,7 @@ func TestCloudSlackE2E(t *testing.T) { page.MustElement("input#email").MustInput(cfg.Slack.Email) page.MustElement("input#password").MustInput(cfg.Slack.Password) screenshotIfShould(t, cfg, page) - page.MustElementR("button", "^Sign In$").MustClick() + page.MustElementR("button", "(^Sign in$)|(^Sign In$)").MustClick() screenshotIfShould(t, cfg, page) t.Log("Installing Slack app...") diff --git a/test/go.mod b/test/go.mod index a7f6e92ba..37e9f4904 100644 --- a/test/go.mod +++ b/test/go.mod @@ -9,7 +9,8 @@ require ( github.com/anthhub/forwarder v1.1.0 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/bwmarrin/discordgo v0.27.1 - github.com/go-rod/rod v0.114.6 + // go-rod version v0.114.6 was causing unstable results on CI thus we stay for now with v0.113.3 + github.com/go-rod/rod v0.113.3 github.com/google/uuid v1.6.0 github.com/hasura/go-graphql-client v0.10.2 github.com/infracloudio/msbotbuilder-go v0.2.6-0.20231130085215-84d2040b3577 diff --git a/test/go.sum b/test/go.sum index fdb377c1d..74d0ca86d 100644 --- a/test/go.sum +++ b/test/go.sum @@ -519,8 +519,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= -github.com/go-rod/rod v0.114.6 h1:NrutWvLGn6Vea+0ZpLSHQ2cT5UMTqk9DeO+V6xeJBxw= -github.com/go-rod/rod v0.114.6/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-rod/rod v0.113.3 h1:oLiKZW721CCMwA5g7977cWfcAKQ+FuosP47Zf1QiDrA= +github.com/go-rod/rod v0.113.3/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= diff --git a/test/helmx/helm_helpers.go b/test/helmx/helm_helpers.go index 41eecfa37..9b6c59802 100644 --- a/test/helmx/helm_helpers.go +++ b/test/helmx/helm_helpers.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/require" ) +var apiKeyRegex = regexp.MustCompile(`(.*)=\s*key:[a-fA-F0-9-]+`) + // InstallChartParams are parameters for InstallChart. type InstallChartParams struct { RepoName string @@ -71,7 +73,7 @@ func InstallChart(t *testing.T, params InstallChartParams) func(t *testing.T) { t.Logf("Found version: %s", latestVersion) helmOpts := params.ToOptions(latestVersion) - t.Logf("Installing chart %s with parameters %+v", params.Name, helmOpts) + t.Logf("Installing chart %s with parameters %+v", params.Name, redactAPIKey(helmOpts)) //nolint:gosec // this is not production code cmd = exec.Command("helm", helmOpts...) installOutput, err := cmd.CombinedOutput() @@ -96,3 +98,13 @@ func latestVersion(t *testing.T, versionsOutput []byte) string { require.NotEmpty(t, versions) return versions[0].Version } + +func redactAPIKey(in []string) []string { + dst := make([]string, len(in)) + copy(dst, in) + + for i := range dst { + dst[i] = apiKeyRegex.ReplaceAllString(dst[i], "$1=REDACTED") + } + return dst +} diff --git a/test/helmx/redact_test.go b/test/helmx/redact_test.go new file mode 100644 index 000000000..14701cfbe --- /dev/null +++ b/test/helmx/redact_test.go @@ -0,0 +1,40 @@ +package helmx + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestRedactAPIKey(t *testing.T) { + + tests := []struct { + name string + input []string + expected []string + }{ + { + name: "redact api key", + input: []string{"config.provider.apiKey=key:12345678-1234-5678-abcd-123456789abc"}, + expected: []string{"config.provider.apiKey=REDACTED"}, + }, + { + name: "redact api key with spaces", + input: []string{"config.provider.apiKey = key:abcdef12-3456-789a-bcde-abcdef123456"}, + expected: []string{"config.provider.apiKey =REDACTED"}, + }, + { + name: "redact api key with multiple keys", + input: []string{"some other text", "another key=value", "config.provider.apiKey=key:98765432-4321-8765-dcba-987654321abc key=test"}, + expected: []string{"some other text", "another key=value", "config.provider.apiKey=REDACTED key=test"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := redactAPIKey(tc.input) + + assert.Equal(t, tc.expected, result) + }) + } +}