chore(e2e): Add workflow for running admin ui tests

moduli-e2e-admin-ui
Michael Li 2 months ago
parent cb8edfc926
commit cc30659f5c

@ -414,6 +414,30 @@ jobs:
edition: ${{ needs.product-metadata.outputs.product-edition }}
docker-image-file: "boundary_default_linux_amd64_${{ needs.set-product-version.outputs.product-version }}_${{ github.sha }}.docker.dev.tar"
secrets: inherit
e2e-admin-ui:
name: e2e-admin-ui
# Only run this workflow on pull requests that have been originated from
# the hashicorp/boundary repository. As Enos scenarios require access to
# Github Actions secrets, it only makes sense to run this workflow when those
# secrets are available. Any pull requests from forks will not trigger the
# workflow.
if: |
github.event.pull_request.head.repo.fork != 'true' && (
(github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release/')) ||
(github.event_name == 'pull_request' && startsWith(github.base_ref, 'release/'))
)
needs:
- set-product-version
- product-metadata
- build-docker
uses: ./.github/workflows/enos-run-admin-ui.yml
with:
artifact-name: "boundary_${{ needs.set-product-version.outputs.product-version }}_linux_amd64.zip"
edition: ${{ needs.product-metadata.outputs.product-edition }}
docker-image-file: "boundary_default_linux_amd64_${{ needs.set-product-version.outputs.product-version }}_${{ github.sha }}.docker.dev.tar"
secrets: inherit
bats:
uses: ./.github/workflows/test-cli-ui_oss.yml
if: github.event.pull_request.head.repo.fork != 'true'

@ -0,0 +1,244 @@
---
name: Run Admin UI E2E Tests
on:
# Only trigger this working using workflow_call. It assumes that secrets are
# being inherited from the caller.
workflow_call:
inputs:
artifact-name:
required: true
type: string
edition:
required: true
type: string
docker-image-file:
required: false
type: string
jobs:
test:
runs-on: ${{ fromJSON(vars.RUNNER_LARGE) }}
continue-on-error: true
strategy:
fail-fast: false # don't fail as that can skip required cleanup steps for jobs
matrix:
include:
- filter: 'e2e_ui_aws builder:crt protocol:http'
infra: 'aws'
- filter: 'e2e_ui_docker builder:crt'
infra: 'docker'
env:
GITHUB_TOKEN: ${{ secrets.SERVICE_USER_GITHUB_TOKEN }}
# Scenario variables
ENOS_VAR_aws_region: us-east-1
ENOS_VAR_aws_ssh_keypair_name: ${{ github.event.repository.name }}-ci-ssh-key
ENOS_VAR_aws_ssh_private_key_path: ./support/private_key.pem
ENOS_VAR_crt_bundle_path: ./support/boundary.zip
ENOS_VAR_test_email: ${{ secrets.SERVICE_USER_EMAIL }}
ENOS_VAR_boundary_edition: ${{ inputs.edition }}
ENOS_VAR_boundary_docker_image_file: ./support/boundary_docker_image.tar
steps:
- name: Set git config
run: |
git config --global url."https://oauth2:${{ secrets.SERVICE_USER_GITHUB_TOKEN }}@github.com".insteadOf "https://github.com"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: '0'
- name: Set up Node
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 20
package-manager-cache: false
- name: Set up Terraform
uses: hashicorp/setup-terraform@5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85 # v4.0.0
- name: Set up Enos
uses: hashicorp/action-setup-enos@v1
with:
github-token: ${{ secrets.SERVICE_USER_GITHUB_TOKEN }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID_CI }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY_CI }}
aws-region: us-east-1
role-to-assume: ${{ secrets.AWS_ROLE_ARN_CI }}
role-skip-session-tagging: true
role-duration-seconds: 3600
- name: Install Vault CLI
run: |
wget https://releases.hashicorp.com/vault/1.17.6/vault_1.17.6_linux_amd64.zip -O /tmp/vault.zip
unzip -o -q /tmp/vault.zip -d "/usr/local/bin"
- name: Download Boundary Linux AMD64 bundle
id: download
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.1
with:
name: ${{ inputs.artifact-name }}
path: ./enos/support/downloads
- name: Unzip and rename Boundary bundle
run: |
unzip -o -q ${{steps.download.outputs.download-path}}/*.zip -d "/usr/local/bin"
mv ${{steps.download.outputs.download-path}}/*.zip enos/support/boundary.zip
- name: Download Boundary Linux AMD64 docker image
if: contains(matrix.filter, 'docker')
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
id: download-docker
with:
name: ${{ inputs.docker-image-file }}
path: ./enos/support/downloads
- name: Rename docker image file
if: contains(matrix.filter, 'docker')
run: |
mv ${{ steps.download-docker.outputs.download-path }}/*.tar enos/support/boundary_docker_image.tar
- name: GPG setup
run: |
# Create a GPG key
KEY_PW=boundary
export KEY_PW
gpg --generate-key --batch <<eoGpgConf
%echo Started!
Key-Type: RSA
Key-Length: default
Subkey-Type: RSA
Name-Real: boundary
Name-Comment: default
Name-Email: default
Expire-Date: 0
Passphrase: $KEY_PW
%commit
%echo Done.
eoGpgConf
# Enable gpg-preset-passphrase so that key passwords can be saved
echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
gpg-connect-agent reloadagent /bye &>/dev/null
# Get information about the created keys
lines="$(gpg --list-secret-keys --with-colons --with-keygrip)"
KEY_ID=""
while read -r line
do
# Save the first key id to be used later
if [[ $line =~ "fpr"* ]]; then
if [[ $KEY_ID == "" ]]; then
KEY_ID="$(echo "$line" | sed -r 's/fpr|://g')"
fi
fi
# Cache the passphrases for the keys so passwords do not need to be entered
if [[ $line =~ "grp"* ]]; then
KEYGRIP_ID="$(echo "$line" | sed -r 's/grp|://g')"
/usr/lib/gnupg/gpg-preset-passphrase --preset -P "$KEY_PW" "$KEYGRIP_ID"
fi
done <<< "$lines"
# Trust the key
touch /tmp/test.txt
gpg -a --encrypt -r "$KEY_ID" --trust-model always --batch --yes /tmp/test.txt
echo "trusted-key $KEY_ID" >> ~/.gnupg/gpg.conf
# Initialize the password store
sudo apt-get update
sudo apt-get install -y pass
pass init "$KEY_ID" &>/dev/null
- name: Prepare scenario dependencies
id: prepare_scenario
run: |
mkdir -p ./enos/support
echo "${{ secrets.SSH_KEY_PRIVATE_CI }}" > ./enos/support/private_key.pem
chmod 600 ./enos/support/private_key.pem
- name: Set up test infra
id: infra
run: |
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
export ENOS_VAR_boundary_license="${{ secrets.BOUNDARY_ENT_LICENSE }}" && \
enos scenario launch --timeout 60m0s --chdir ./enos ${{matrix.filter}}
- name: Get SHA of UI version
id: get-ui-version
run: |
echo "Using UI Version $(cat ./internal/ui/VERSION)"
echo "sha=$(head -n 1 ./internal/ui/VERSION)" >> "$GITHUB_OUTPUT"
echo "repo=boundary-ui" >> "$GITHUB_OUTPUT"
- name: Checkout UI repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: hashicorp/${{ steps.get-ui-version.outputs.repo }}
ref: ${{ steps.get-ui-version.outputs.sha }}
path: support/src/ui
token: ${{ secrets.SERVICE_USER_GITHUB_TOKEN }}
- name: Set up pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with:
run_install: false
package_json_file: ./support/src/ui/package.json
- name: Install node dependencies
run: |
cd ./support/src/ui
pnpm install --frozen-lockfile
cd e2e-tests
pnpm playwright install --with-deps
- name: GH fix for localhost resolution
run: |
cat /etc/hosts && echo "-----------"
sudo sed -i 's/::1 *localhost ip6-localhost ip6-loopback/::1 ip6 -localhost ip6-loopback/g' /etc/hosts
cat /etc/hosts
ssh -V
- name: Run Tests
id: run-tests
run: |
# shellcheck disable=SC1090
source <(bash ./enos/scripts/test_e2e_env.sh)
cd ./support/src/ui/e2e-tests
pnpm run admin:ce:${{matrix.infra}} --reporter=html
- name: Split scenario name
if: ${{ failure() && steps.run-tests.outcome == 'failure' }}
id: split
run: |
SCENARIO=$(echo "${{ matrix.filter }}" | cut -d' ' -f1,3 | sed 's/:/_/g')
echo fragment="${SCENARIO}" >> "$GITHUB_OUTPUT"
- name: Upload Playwright report
if: ${{ failure() && steps.run-tests.outcome == 'failure' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: playwright-report-${{ steps.split.outputs.fragment }}
path: ./support/src/ui/e2e-tests/playwright-report
- name: Clean up test infra
if: ${{ always() }}
continue-on-error: true
run: |
export ENOS_VAR_enos_user=$GITHUB_ACTOR && \
enos scenario destroy --timeout 60m0s --chdir ./enos ${{matrix.filter}}
- name: Send Slack message on failure
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
if: failure() && github.repository == 'hashicorp/boundary'
with:
method: chat.postMessage
token: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_TOKEN }}
payload: |
channel: ${{ secrets.SLACK_BOUNDARY_TEST_BOT_CHANNEL_ID }}
text: ":x: admin ui tests failed (${{ matrix.filter }}): ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n*Branch:* ${{ github.repository }}:${{ github.head_ref || github.ref_name }}"

@ -15,11 +15,9 @@ scenario "e2e_ui_aws" {
}
locals {
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
boundary_install_dir = abspath(var.boundary_install_dir)
license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic"))
local_boundary_dir = var.local_boundary_dir != null ? abspath(var.local_boundary_dir) : null
local_boundary_ui_src_dir = var.local_boundary_ui_src_dir != null ? abspath(var.local_boundary_ui_src_dir) : null
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
boundary_install_dir = abspath(var.boundary_install_dir)
license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic"))
build_path = {
"local" = "/tmp",
"crt" = var.crt_bundle_path == null ? null : abspath(var.crt_bundle_path)
@ -194,27 +192,24 @@ scenario "e2e_ui_aws" {
]
variables {
debug_no_run = var.e2e_debug_no_run
alb_boundary_api_addr = step.create_boundary_cluster.alb_boundary_api_addr
auth_method_id = step.create_boundary_cluster.auth_method_id
auth_login_name = step.create_boundary_cluster.auth_login_name
auth_password = step.create_boundary_cluster.auth_password
local_boundary_dir = local.local_boundary_dir
local_boundary_ui_src_dir = local.local_boundary_ui_src_dir
aws_ssh_private_key_path = local.aws_ssh_private_key_path
target_address = step.create_targets_with_tag.target_private_ips[0]
target_user = "ubuntu"
target_port = "22"
vault_addr_public = step.create_vault_cluster.instance_addresses[0]
vault_addr_private = step.create_vault_cluster.instance_addresses_private[0]
vault_root_token = step.create_vault_cluster.vault_root_token
aws_access_key_id = step.iam_setup.access_key_id
aws_secret_access_key = step.iam_setup.secret_access_key
aws_host_set_filter = step.create_tag_inputs.tag_string
aws_host_set_ips = step.create_targets_with_tag.target_private_ips
worker_tag_egress = local.egress_tag
aws_region = var.aws_region
alb_cert = matrix.protocol == "https" ? step.create_boundary_cluster.alb_cert : ""
alb_boundary_api_addr = step.create_boundary_cluster.alb_boundary_api_addr
auth_method_id = step.create_boundary_cluster.auth_method_id
auth_login_name = step.create_boundary_cluster.auth_login_name
auth_password = step.create_boundary_cluster.auth_password
aws_ssh_private_key_path = local.aws_ssh_private_key_path
target_address = step.create_targets_with_tag.target_private_ips[0]
target_user = "ubuntu"
target_port = "22"
vault_addr_public = step.create_vault_cluster.instance_addresses[0]
vault_addr_private = step.create_vault_cluster.instance_addresses_private[0]
vault_root_token = step.create_vault_cluster.vault_root_token
aws_access_key_id = step.iam_setup.access_key_id
aws_secret_access_key = step.iam_setup.secret_access_key
aws_host_set_filter = step.create_tag_inputs.tag_string
aws_host_set_ips = step.create_targets_with_tag.target_private_ips
worker_tag_egress = local.egress_tag
aws_region = var.aws_region
alb_cert = matrix.protocol == "https" ? step.create_boundary_cluster.alb_cert : ""
}
}

@ -14,8 +14,6 @@ scenario "e2e_ui_docker" {
locals {
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
local_boundary_dir = var.local_boundary_dir != null ? abspath(var.local_boundary_dir) : null
local_boundary_ui_src_dir = var.local_boundary_ui_src_dir != null ? abspath(var.local_boundary_ui_src_dir) : null
boundary_docker_image_file = abspath(var.boundary_docker_image_file)
license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic"))
@ -154,32 +152,29 @@ scenario "e2e_ui_docker" {
step.create_ldap_server,
]
variables {
debug_no_run = var.e2e_debug_no_run
alb_boundary_api_addr = step.create_boundary.address
auth_method_id = step.create_boundary.auth_method_id
auth_login_name = step.create_boundary.login_name
auth_password = step.create_boundary.password
local_boundary_dir = local.local_boundary_dir
local_boundary_ui_src_dir = local.local_boundary_ui_src_dir
aws_ssh_private_key_path = local.aws_ssh_private_key_path
target_address = step.create_host.address
target_port = step.create_host.port
target_user = "ubuntu"
target_ca_key = step.create_host.ca_key_private
target_ca_key_public = step.create_host.ca_key_public
vault_addr_public = step.create_vault.address_public
vault_addr_private = step.create_vault.address_private
vault_addr_unified = step.create_vault.address_unified
vault_root_token = step.create_vault.token
vault_port = step.create_vault.port
ldap_address = step.create_ldap_server.address
ldap_domain_dn = step.create_ldap_server.domain_dn
ldap_admin_dn = step.create_ldap_server.admin_dn
ldap_admin_password = step.create_ldap_server.admin_password
ldap_user_name = step.create_ldap_server.user_name
ldap_user_password = step.create_ldap_server.user_password
ldap_group_name = step.create_ldap_server.group_name
worker_tag_egress = local.egress_tag
alb_boundary_api_addr = step.create_boundary.address
auth_method_id = step.create_boundary.auth_method_id
auth_login_name = step.create_boundary.login_name
auth_password = step.create_boundary.password
aws_ssh_private_key_path = local.aws_ssh_private_key_path
target_address = step.create_host.address
target_port = step.create_host.port
target_user = "ubuntu"
target_ca_key = step.create_host.ca_key_private
target_ca_key_public = step.create_host.ca_key_public
vault_addr_public = step.create_vault.address_public
vault_addr_private = step.create_vault.address_private
vault_addr_unified = step.create_vault.address_unified
vault_root_token = step.create_vault.token
vault_port = step.create_vault.port
ldap_address = step.create_ldap_server.address
ldap_domain_dn = step.create_ldap_server.domain_dn
ldap_admin_dn = step.create_ldap_server.admin_dn
ldap_admin_password = step.create_ldap_server.admin_password
ldap_user_name = step.create_ldap_server.user_name
ldap_user_password = step.create_ldap_server.user_password
ldap_group_name = step.create_ldap_server.group_name
worker_tag_egress = local.egress_tag
}
}
}

@ -9,11 +9,6 @@ terraform {
}
}
variable "debug_no_run" {
description = "If set, this module will not execute the tests so that you can still access environment variables"
type = bool
default = true
}
variable "alb_boundary_api_addr" {
description = "URL of the Boundary instance"
type = string
@ -34,15 +29,6 @@ variable "auth_password" {
type = string
default = ""
}
variable "local_boundary_dir" {
description = "Local Path to boundary executable"
type = string
}
variable "local_boundary_ui_src_dir" {
description = "Local Path to boundary-ui directory"
type = string
}
variable "aws_ssh_private_key_path" {
description = "Local Path to key used to SSH onto created hosts"
type = string
@ -250,7 +236,7 @@ resource "enos_local_exec" "run_e2e_test" {
E2E_ALB_CERT = var.alb_cert
}
inline = var.debug_no_run ? [""] : ["set -o pipefail; PATH=\"${var.local_boundary_dir}:$PATH\" pnpm --cwd ${var.local_boundary_ui_src_dir}/ui/admin run e2e 2>&1 | tee ${path.module}/../../test-e2e-ui.log"]
inline = [""]
}
output "test_results" {

@ -1,4 +1,4 @@
2766be2c2e941020878f837af6188eb500579e31
28b185bec89e021e8d660b5d3095fcd114955431
# This file determines the version of the UI to embed in the boundary binary.
# Update this file by running 'make update-ui-version' from the root of this repo.
# Set UI_COMMITISH when running the above target to update to a specific version.

Loading…
Cancel
Save