Merge remote-tracking branch 'remotes/from/ce/main'

This commit is contained in:
hc-github-team-secure-vault-core 2026-03-25 18:15:40 +00:00
commit 9c5d1a5cc6
12 changed files with 339 additions and 145 deletions

View File

@ -517,7 +517,8 @@ scenario "agent" {
module = module.vault_verify_secrets_engines_create
depends_on = [
step.verify_vault_unsealed,
step.get_vault_cluster_ips
step.get_vault_cluster_ips,
step.set_up_external_integration_target,
]
providers = {

View File

@ -472,7 +472,8 @@ scenario "seal_ha" {
depends_on = [
step.create_vault_cluster,
step.get_vault_cluster_ips,
step.verify_vault_unsealed
step.verify_vault_unsealed,
step.set_up_external_integration_target,
]
providers = {
@ -862,34 +863,6 @@ scenario "seal_ha" {
}
}
step "verify_log_secrets" {
skip_step = !var.vault_enable_audit_devices || !var.verify_log_secrets
description = global.description.verify_log_secrets
module = module.verify_log_secrets
depends_on = [
step.verify_secrets_engines_read,
]
providers = {
enos = local.enos_provider[matrix.distro]
}
verifies = [
quality.vault_audit_log_secrets,
quality.vault_journal_secrets,
quality.vault_radar_index_create,
quality.vault_radar_scan_file,
]
variables {
audit_log_file_path = step.create_vault_cluster.audit_device_file_path
leader_host = step.get_updated_cluster_ips.leader_host
vault_addr = step.create_vault_cluster.api_addr_localhost
vault_root_token = step.create_vault_cluster.root_token
}
}
step "verify_ui" {
description = global.description.verify_ui
module = module.vault_verify_ui
@ -937,7 +910,6 @@ scenario "seal_ha" {
depends_on = [
step.wait_for_seal_rewrap,
step.verify_secrets_engines_read,
step.verify_log_secrets,
]
providers = {
@ -1140,6 +1112,34 @@ scenario "seal_ha" {
}
}
step "verify_log_secrets" {
skip_step = !var.vault_enable_audit_devices || !var.verify_log_secrets
description = global.description.verify_log_secrets
module = module.verify_log_secrets
depends_on = [
step.verify_secrets_engines_read_after_migration
]
providers = {
enos = local.enos_provider[matrix.distro]
}
verifies = [
quality.vault_audit_log_secrets,
quality.vault_journal_secrets,
quality.vault_radar_index_create,
quality.vault_radar_scan_file,
]
variables {
audit_log_file_path = step.create_vault_cluster.audit_device_file_path
leader_host = step.get_updated_cluster_ips.leader_host
vault_addr = step.create_vault_cluster.api_addr_localhost
vault_root_token = step.create_vault_cluster.root_token
}
}
output "audit_device_file_path" {
description = "The file path for the file audit device, if enabled"
value = step.create_vault_cluster.audit_device_file_path

View File

@ -0,0 +1,89 @@
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: BUSL-1.1
terraform {
required_providers {
enos = {
source = "registry.terraform.io/hashicorp-forge/enos"
}
}
}
variable "hosts" {
description = "The target machines to run the test query from"
type = map(object({
ipv6 = string
private_ip = string
public_ip = string
}))
}
variable "ldap_base_dn" {
type = string
description = "The LDAP base dn to search from"
}
variable "ldap_bind_dn" {
type = string
description = "The LDAP bind dn"
}
variable "ldap_host" {
type = object({
ipv6 = string
private_ip = string
public_ip = string
})
description = "The LDAP host"
}
variable "ldap_password" {
type = string
description = "The LDAP password"
}
variable "ldap_port" {
type = string
description = "The LDAP port"
}
variable "ldap_query" {
type = string
description = "The LDAP query to use when testing the connection"
default = null
}
variable "retry_interval" {
type = number
description = "How many seconds to wait between each retry"
default = 2
}
variable "timeout" {
type = number
description = "The max number of seconds to wait before timing out"
default = 60
}
# Wait for the search to succeed
resource "enos_remote_exec" "wait_for_search" {
for_each = var.hosts
environment = {
LDAP_BASE_DN = var.ldap_base_dn
LDAP_BIND_DN = var.ldap_bind_dn
LDAP_HOST = var.ldap_host.public_ip
LDAP_PASSWORD = var.ldap_password
LDAP_PORT = var.ldap_port
LDAP_QUERY = var.ldap_query == null ? "" : var.ldap_query
RETRY_INTERVAL = var.retry_interval
TIMEOUT_SECONDS = var.timeout
}
scripts = [abspath("${path.module}/scripts/wait-for-search.sh")]
transport = {
ssh = {
host = each.value.public_ip
}
}
}

View File

@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2026
# SPDX-License-Identifier: BUSL-1.1
fail() {
echo "$1" 1>&2
exit 1
}
[[ -z "$LDAP_BASE_DN" ]] && fail "LDAP_BASE_DN env variable has not been set"
[[ -z "$LDAP_BIND_DN" ]] && fail "LDAP_BIND_DN env variable has not been set"
[[ -z "$LDAP_HOST" ]] && fail "LDAP_HOST env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_PASSWORD" ]] && fail "LDAP_PASSWORD env variable has not been set"
[[ -z "$RETRY_INTERVAL" ]] && fail "RETRY_INTERVAL env variable has not been set"
[[ -z "$TIMEOUT_SECONDS" ]] && fail "TIMEOUT_SECONDS env variable has not been set"
# NOTE: An LDAP_QUERY is not technically required here as long as we have a base
# DN and bind DN to search and bind to.
search="ldap://${LDAP_HOST}:${LDAP_PORT} -b ${LDAP_BASE_DN} -D ${LDAP_BIND_DN} -w ${LDAP_PASSWORD} -s base ${LDAP_QUERY}"
safe_search="ldap://${LDAP_HOST}:${LDAP_PORT} -b ${LDAP_BASE_DN} -D ${LDAP_BIND_DN} -s base ${LDAP_QUERY}"
echo "Running test search: ${safe_search}"
begin_time=$(date +%s)
end_time=$((begin_time + TIMEOUT_SECONDS))
test_search_out=""
test_search_res=""
declare -i tries=0
while [ "$(date +%s)" -lt "$end_time" ]; do
tries+=1
if test_search_out=$(eval "ldapsearch -x -H ${search}" 2>&1); then
test_search_res=0
break
fi
test_search_res=$?
echo "Test search failed!, search: ${safe_search}, attempt: ${tries}, exit code: ${test_search_res}, error: ${test_search_out}, retrying..."
sleep "$RETRY_INTERVAL"
done
if [ "$test_search_res" -ne 0 ]; then
echo "Timed out waiting for search!, search: ${safe_search}, attempt: ${tries}, exit code: ${test_search_res}, error: ${test_search_out}" 2>&1
# Exit with the ldapsearch exit code so we bubble that up to error diagnostic
exit "$test_search_res"
fi

View File

@ -11,8 +11,10 @@ terraform {
locals {
test_server_address = var.ip_version == "6" ? var.hosts[0].ipv6 : var.hosts[0].public_ip
ldap_base_dn = join(",", formatlist("dc=%s", split(".", var.ldap_domain)))
ldap_server = {
domain = "enos.com"
domain = var.ldap_domain
base_dn = local.ldap_base_dn
org = "hashicorp"
admin_pw = "password1"
version = var.ldap_version
@ -66,19 +68,30 @@ resource "enos_remote_exec" "setup_openldap" {
}
}
// Wait for the base DN to be available before we populate it
module "wait_for_ldap_base_dn" {
depends_on = [enos_remote_exec.setup_openldap]
source = "../ldap_wait_for_search"
hosts = var.hosts
ldap_base_dn = local.ldap_base_dn
ldap_bind_dn = "cn=admin,${local.ldap_base_dn}"
ldap_host = local.ldap_server.host
ldap_password = local.ldap_server.admin_pw
ldap_port = local.ldap_server.port
}
# Populate LDAP server with required users and organizational units
resource "enos_remote_exec" "populate_ldap" {
depends_on = [enos_remote_exec.setup_openldap]
depends_on = [module.wait_for_ldap_base_dn]
scripts = [abspath("${path.module}/scripts/populate-ldap.sh")]
environment = {
LDAP_SERVER = local.ldap_server.host.private_ip
LDAP_PORT = local.ldap_server.port
LDAP_ADMIN_PW = local.ldap_server.admin_pw
LDAP_DOMAIN = local.ldap_server.domain
RETRY_INTERVAL = var.retry_interval
TIMEOUT_SECONDS = var.timeout
LDAP_SERVER = local.ldap_server.host.private_ip
LDAP_PORT = local.ldap_server.port
LDAP_ADMIN_PW = local.ldap_server.admin_pw
LDAP_BASE_DN = local.ldap_server.base_dn
}
transport = {

View File

@ -12,68 +12,32 @@ fail() {
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_ADMIN_PW" ]] && fail "LDAP_ADMIN_PW env variable has not been set"
[[ -z "$LDAP_DOMAIN" ]] && fail "LDAP_DOMAIN env variable has not been set"
[[ -z "$RETRY_INTERVAL" ]] && fail "RETRY_INTERVAL env variable has not been set"
[[ -z "$TIMEOUT_SECONDS" ]] && fail "TIMEOUT_SECONDS env variable has not been set"
# Extract domain components from LDAP_DOMAIN (e.g., "enos.com" -> "dc=enos,dc=com")
IFS='.' read -ra DOMAIN_PARTS <<< "$LDAP_DOMAIN"
DOMAIN_DN=""
for part in "${DOMAIN_PARTS[@]}"; do
if [[ -n "$DOMAIN_DN" ]]; then
DOMAIN_DN="${DOMAIN_DN},dc=${part}"
else
DOMAIN_DN="dc=${part}"
fi
done
[[ -z "$LDAP_BASE_DN" ]] && fail "LDAP_BASE_DN env variable has not been set"
echo "OpenLDAP: Checking for OpenLDAP Server Connection: ${LDAP_SERVER}:${LDAP_PORT}"
echo "OpenLDAP: Using domain DN: ${DOMAIN_DN}"
echo "OpenLDAP: Using base DN: ${LDAP_BASE_DN}"
echo "OpenLDAP: Testing connection with admin credentials"
begin_time=$(date +%s)
end_time=$((begin_time + TIMEOUT_SECONDS))
test_conn_out=""
test_conn_res=""
declare -i tries=0
while [ "$(date +%s)" -lt "$end_time" ]; do
# Test connection
tries+=1
if test_conn_out=$(ldapsearch -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -b "${DOMAIN_DN}" -D "cn=admin,${DOMAIN_DN}" -w "${LDAP_ADMIN_PW}" -s base 2>&1); then
test_conn_res=0
break
fi
test_conn_res=$?
echo "Unable to connect to ldap://${LDAP_SERVER}:${LDAP_PORT} cn=admin,${DOMAIN_DN}, attempt: ${tries}, exit code: ${test_conn_res}, error: ${test_conn_out}, retrying..."
sleep "$RETRY_INTERVAL"
done
if [ "$test_conn_res" -ne 0 ]; then
echo "Timed out waiting to connect to ldap://${LDAP_SERVER}:${LDAP_PORT} cn=admin,${DOMAIN_DN}, attempt: ${tries}, exit code: ${test_conn_res}, error: ${test_conn_out}" 2>&1
exit "$test_conn_res"
fi
echo "OpenLDAP: Creating organizational units"
# Creating Users and Groups Org Units LDIF file
OU_LDIF="ou.ldif"
cat << EOF > "${OU_LDIF}"
dn: ou=users,${DOMAIN_DN}
dn: ou=users,${LDAP_BASE_DN}
objectClass: organizationalUnit
ou: users
dn: ou=groups,${DOMAIN_DN}
dn: ou=groups,${LDAP_BASE_DN}
objectClass: organizationalUnit
ou: groups
EOF
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,${DOMAIN_DN}" -w "${LDAP_ADMIN_PW}" -f "${OU_LDIF}" || echo "OUs may already exist"
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,${LDAP_BASE_DN}" -w "${LDAP_ADMIN_PW}" -f "${OU_LDIF}" || echo "OUs may already exist"
echo "OpenLDAP: Creating test users"
USER_LDIF="users.ldif"
cat << EOF > "${USER_LDIF}"
# User: enos
dn: uid=enos,ou=users,${DOMAIN_DN}
dn: uid=enos,ou=users,${LDAP_BASE_DN}
objectClass: inetOrgPerson
sn: enos
cn: enos user
@ -81,7 +45,7 @@ uid: enos
userPassword: ${LDAP_ADMIN_PW}
# Static-role test user (for LDAP verification tests)
dn: uid=vault-static-user,ou=users,${DOMAIN_DN}
dn: uid=vault-static-user,ou=users,${LDAP_BASE_DN}
objectClass: inetOrgPerson
sn: vault-static-user
cn: Vault Static User
@ -89,21 +53,21 @@ uid: vault-static-user
userPassword: ${LDAP_ADMIN_PW}
# Service accounts for library tests
dn: uid=svc-account-1,ou=users,${DOMAIN_DN}
dn: uid=svc-account-1,ou=users,${LDAP_BASE_DN}
objectClass: inetOrgPerson
sn: svc-account-1
cn: Service Account 1
uid: svc-account-1
userPassword: ${LDAP_ADMIN_PW}
dn: uid=svc-account-2,ou=users,${DOMAIN_DN}
dn: uid=svc-account-2,ou=users,${LDAP_BASE_DN}
objectClass: inetOrgPerson
sn: svc-account-2
cn: Service Account 2
uid: svc-account-2
userPassword: ${LDAP_ADMIN_PW}
dn: uid=svc-delete,ou=users,${DOMAIN_DN}
dn: uid=svc-delete,ou=users,${LDAP_BASE_DN}
objectClass: inetOrgPerson
sn: svc-delete
cn: Service Account Delete
@ -111,6 +75,6 @@ uid: svc-delete
userPassword: ${LDAP_ADMIN_PW}
EOF
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,${DOMAIN_DN}" -w "${LDAP_ADMIN_PW}" -f "${USER_LDIF}" || echo "Users may already exist"
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,${LDAP_BASE_DN}" -w "${LDAP_ADMIN_PW}" -f "${USER_LDIF}" || echo "Users may already exist"
echo "LDAP population completed successfully."

View File

@ -16,6 +16,12 @@ variable "ip_version" {
default = "4"
}
variable "ldap_domain" {
type = string
description = "The name of the domain"
default = "enos.com"
}
variable "ldap_version" {
type = string
description = "OpenLDAP Server Version to use"
@ -35,15 +41,3 @@ variable "ports" {
description = string
}))
}
variable "retry_interval" {
type = number
description = "How many seconds to wait between each retry"
default = 2
}
variable "timeout" {
type = number
description = "The max number of seconds to wait before timing out"
default = 60
}

View File

@ -52,14 +52,10 @@ locals {
domain_dn = try(local.ldap_config.domain, "") != "" ? join(",", [for part in split(".", local.ldap_config.domain) : "dc=${part}"]) : ""
# Set up LDAP environment variables when LDAP integration is available
# LDAP_SERVER uses private_ip for Vault operations (runs on Vault leader host)
# LDAP_SERVER_PUBLIC uses public_ip for test setup operations (runs from GitHub runner)
ldap_environment = try(local.ldap_config.domain, "") != "" ? {
LDAP_SERVER = local.ldap_config.host.private_ip
LDAP_SERVER_PUBLIC = local.ldap_config.host.public_ip
LDAP_PORT = tostring(local.ldap_config.port)
LDAP_BIND_DN = "cn=admin,${local.domain_dn}"
LDAP_BIND_PASS = local.ldap_config.admin_pw
LDAP_SERVER = "ldap://${local.ldap_config.host.private_ip}:${local.ldap_config.port}"
LDAP_BIND_DN = "cn=admin,${local.domain_dn}"
LDAP_BIND_PASS = local.ldap_config.admin_pw
} : {}
}

View File

@ -13,6 +13,7 @@ fail() {
[[ -z "${VAULT_TOKEN}" ]] && fail "VAULT_TOKEN env variable has not been set"
[[ -z "${VAULT_ADDR}" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "${VAULT_TEST_PACKAGE}" ]] && fail "VAULT_TEST_PACKAGE env variable has not been set"
[[ -z "${VAULT_EDITION}" ]] && fail "VAULT_EDITION env variable has not been set"
# Check required dependencies
echo "Checking required dependencies..."
@ -76,6 +77,18 @@ echo "Running tests..."
echo "Vault environment variables:"
env | grep VAULT | sed 's/VAULT_TOKEN=.*/VAULT_TOKEN=***REDACTED***/'
case $VAULT_EDITION in
ent | ent.hsm | ent.hsm.fips1402 | ent.hsm.fips1403 | ent.fips1403 | ent.fips1402)
tags="-tags=ent,enterprise"
;;
ce)
tags=""
;;
*)
fail "unknown VAULT_EDITION: $VAULT_EDITION"
;;
esac
# Build gotestsum command based on whether we have specific tests
set -x # Show commands being executed
set +e # Temporarily disable exit on error
@ -84,10 +97,10 @@ if [ -n "$VAULT_TEST_MATRIX" ] && [ -f "$VAULT_TEST_MATRIX" ]; then
# Extract test names from matrix and create regex pattern
test_pattern=$(jq -r '.include[].test' "$VAULT_TEST_MATRIX" | paste -sd '|' -)
echo "Running specific tests: $test_pattern"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 -run="$test_pattern" "$VAULT_TEST_PACKAGE"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "${tags}" -run="$test_pattern" "$VAULT_TEST_PACKAGE"
else
echo "Running all tests in package"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "$VAULT_TEST_PACKAGE"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "${tags}" "$VAULT_TEST_PACKAGE"
fi
test_exit_code=$?
set -e # Re-enable exit on error

View File

@ -79,8 +79,25 @@ output "ldap" {
value = local.ldap_output
}
# Ensure that our base DN is available on the LDAP server before we attempt to
# to mount the engine.
module "wait_for_ldap_base_dn" {
source = "../../../../ldap_wait_for_search"
hosts = { 0 : var.leader_host }
ldap_base_dn = var.integration_host_state.ldap.base_dn
ldap_bind_dn = "cn=admin,${var.integration_host_state.ldap.base_dn}"
ldap_host = var.integration_host_state.ldap.host
ldap_password = var.integration_host_state.ldap.admin_pw
ldap_port = var.integration_host_state.ldap.port
}
# Enable LDAP secrets engine
resource "enos_remote_exec" "secrets_enable_ldap_secret" {
depends_on = [
module.wait_for_ldap_base_dn,
]
environment = {
ENGINE = local.ldap_output.ldap_mount
MOUNT = local.ldap_output.ldap_mount
@ -98,7 +115,7 @@ resource "enos_remote_exec" "secrets_enable_ldap_secret" {
}
}
# Setup OpenLDAP infrastructure
# Setup OpenLDAP infrastructure
resource "enos_remote_exec" "ldap_setup" {
depends_on = [
enos_remote_exec.secrets_enable_ldap_secret
@ -151,11 +168,38 @@ resource "enos_remote_exec" "ldap_secrets_config" {
}
}
resource "enos_remote_exec" "ldap_password_policy" {
depends_on = [
enos_remote_exec.secrets_enable_ldap_secret,
enos_remote_exec.ldap_setup
]
environment = {
MOUNT = local.ldap_output.ldap_mount
LDAP_SERVER = local.ldap_output.host.private_ip
LDAP_PORT = local.ldap_output.port
LDAP_USERNAME = local.ldap_output.username
LDAP_ADMIN_PW = local.ldap_output.pw
VAULT_ADDR = var.vault_addr
VAULT_INSTALL_DIR = var.vault_install_dir
VAULT_TOKEN = var.vault_root_token
}
scripts = [abspath("${path.module}/../../../scripts/ldap/add-ldap-password-policy.sh")]
transport = {
ssh = {
host = var.leader_host.public_ip
}
}
}
# Create a new Library set of service accounts
# Test Case: Service Account Library - Create a new Library set of service accounts
resource "enos_remote_exec" "ldap_library_set_create" {
depends_on = [
enos_remote_exec.ldap_secrets_config,
enos_remote_exec.ldap_password_policy,
]
environment = {
@ -352,28 +396,3 @@ resource "enos_remote_exec" "ldap_library_self_checkin" {
}
}
}
resource "enos_remote_exec" "ldap_password_policy" {
depends_on = [
enos_remote_exec.secrets_enable_ldap_secret
]
environment = {
MOUNT = local.ldap_output.ldap_mount
LDAP_SERVER = local.ldap_output.host.private_ip
LDAP_PORT = local.ldap_output.port
LDAP_USERNAME = local.ldap_output.username
LDAP_ADMIN_PW = local.ldap_output.pw
VAULT_ADDR = var.vault_addr
VAULT_INSTALL_DIR = var.vault_install_dir
VAULT_TOKEN = var.vault_root_token
}
scripts = [abspath("${path.module}/../../../scripts/ldap/add-ldap-password-policy.sh")]
transport = {
ssh = {
host = var.leader_host.public_ip
}
}
}

View File

@ -9,6 +9,7 @@ import (
"fmt"
"os"
"path"
"slices"
"testing"
"time"
@ -19,11 +20,24 @@ import (
// Session holds the test context and Vault client
type Session struct {
t *testing.T
NoCleanup bool
Client *api.Client
Namespace string
}
func New(t *testing.T) *Session {
func (s *Session) T() *testing.T {
return s.t
}
type SessionOpts func(s *Session)
func WithNoCleanup() SessionOpts {
return func(s *Session) {
s.NoCleanup = true
}
}
func New(t *testing.T, opts ...SessionOpts) *Session {
t.Helper()
addr := os.Getenv("VAULT_ADDR")
@ -50,12 +64,6 @@ func New(t *testing.T) *Session {
_, err = privClient.Logical().Write(nsURLPath, nil)
require.NoError(t, err)
t.Cleanup(func() {
_, err = privClient.Logical().Delete(nsURLPath)
require.NoError(t, err)
t.Logf("Cleaned up namespace %s", nsName)
})
// session client should get the full namespace of parent + test
fullNSPath := nsName
if parentNS != "" {
@ -74,6 +82,20 @@ func New(t *testing.T) *Session {
Namespace: nsName,
}
for opt := range slices.Values(opts) {
opt(session)
}
t.Cleanup(func() {
if session.NoCleanup {
t.Logf("WARN: NoDebug has been set, not cleaning up namespace")
return
}
_, err = privClient.Logical().Delete(nsURLPath)
require.NoError(t, err)
t.Logf("Cleaned up namespace %s", nsName)
})
// make sure the namespace has been created
session.Eventually(func() error {
// this runs inside the new namespace, so if it succeeds, we're good

View File

@ -4,17 +4,43 @@
package blackbox
import (
"net"
"net/url"
"os"
"testing"
"time"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// requireLDAPAvailable verifies LDAP server connectivity using testify Eventually
func requireLDAPAvailable(t *testing.T, timeout, interval time.Duration) {
t.Helper()
// Use public IP for external connectivity testing
ldapServerPublic := os.Getenv("LDAP_URL_PUBLIC")
require.NotEmpty(t, ldapServerPublic, "LDAP_URL_PUBLIC environment variable not set")
u, err := url.Parse(ldapServerPublic)
require.NoError(t, err, "Failed to parse LDAP URL: %s", ldapServerPublic)
require.EventuallyWithT(t, func(ct *assert.CollectT) {
d := &net.Dialer{}
conn, err := d.DialContext(t.Context(), "tcp", u.Host)
require.NoError(ct, err)
require.NoError(ct, conn.Close())
}, timeout, interval, "LDAP server not available at %s", u.Host)
t.Logf("LDAP server connectivity verified at %s", u.Host)
}
// testLDAPSecretsCreate tests LDAP secrets engine creation
func testLDAPSecretsCreate(t *testing.T, v *blackbox.Session) {
// Check if LDAP server configuration is available from integration host
ldapServer := os.Getenv("LDAP_SERVER")
ldapServer := os.Getenv("LDAP_URL_PRIVATE")
ldapBindDN := os.Getenv("LDAP_BIND_DN")
ldapBindPass := os.Getenv("LDAP_BIND_PASS")
@ -22,6 +48,9 @@ func testLDAPSecretsCreate(t *testing.T, v *blackbox.Session) {
t.Skip("LDAP server configuration not available - skipping LDAP secrets engine test")
}
// Verify LDAP server is ready before proceeding
requireLDAPAvailable(t, 1*time.Minute, 2*time.Second)
// Enable LDAP secrets engine
v.MustEnableSecretsEngine("ldap-create", &api.MountInput{Type: "ldap"})
@ -53,7 +82,7 @@ func testLDAPSecretsCreate(t *testing.T, v *blackbox.Session) {
// testLDAPSecretsRead tests LDAP secrets engine read operations
func testLDAPSecretsRead(t *testing.T, v *blackbox.Session) {
// Check if LDAP server configuration is available from integration host
ldapServer := os.Getenv("LDAP_SERVER")
ldapServer := os.Getenv("LDAP_URL_PRIVATE")
ldapBindDN := os.Getenv("LDAP_BIND_DN")
ldapBindPass := os.Getenv("LDAP_BIND_PASS")
@ -61,6 +90,10 @@ func testLDAPSecretsRead(t *testing.T, v *blackbox.Session) {
t.Skip("LDAP server configuration not available - skipping LDAP secrets engine test")
}
// Verify LDAP server is ready before proceeding
requireLDAPAvailable(t, 1*time.Minute, 2*time.Second)
serviceAccounts := []string{"svc-account-1", "svc-account-2"}
// Enable LDAP secrets engine
v.MustEnableSecretsEngine("ldap-read", &api.MountInput{Type: "ldap"})
@ -75,7 +108,7 @@ func testLDAPSecretsRead(t *testing.T, v *blackbox.Session) {
// Create a library set for service account management
v.MustWrite("ldap-read/library/test-set", map[string]any{
"service_account_names": []string{"svc-account-1", "svc-account-2"},
"service_account_names": serviceAccounts,
"ttl": "10h",
"max_ttl": "20h",
"disable_check_in_enforcement": false,
@ -106,7 +139,7 @@ func testLDAPSecretsRead(t *testing.T, v *blackbox.Session) {
// testLDAPSecretsDelete tests LDAP secrets engine delete operations
func testLDAPSecretsDelete(t *testing.T, v *blackbox.Session) {
// Check if LDAP server configuration is available from integration host
ldapServer := os.Getenv("LDAP_SERVER")
ldapServer := os.Getenv("LDAP_URL_PRIVATE")
ldapBindDN := os.Getenv("LDAP_BIND_DN")
ldapBindPass := os.Getenv("LDAP_BIND_PASS")
@ -114,6 +147,10 @@ func testLDAPSecretsDelete(t *testing.T, v *blackbox.Session) {
t.Skip("LDAP server configuration not available - skipping LDAP secrets engine test")
}
// Verify LDAP server is ready before proceeding
requireLDAPAvailable(t, 1*time.Minute, 2*time.Second)
serviceAccounts := []string{"svc-delete"}
// Enable LDAP secrets engine
v.MustEnableSecretsEngine("ldap-delete", &api.MountInput{Type: "ldap"})
@ -128,7 +165,7 @@ func testLDAPSecretsDelete(t *testing.T, v *blackbox.Session) {
// Create a library set
v.MustWrite("ldap-delete/library/delete-set", map[string]any{
"service_account_names": []string{"svc-delete"},
"service_account_names": serviceAccounts,
"ttl": "1h",
})