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

This commit is contained in:
hc-github-team-secure-vault-core 2026-03-30 16:19:10 +00:00
commit ec3496213b
39 changed files with 341 additions and 267 deletions

View File

@ -95,12 +95,6 @@ scenario "plugin" {
ubuntu = provider.enos.ubuntu
}
manage_service = matrix.artifact_type == "bundle"
test_names = {
ldap = ["TestLDAPSecretsEngineComprehensive"]
// database = ["TestDatabaseSecretsEngineComprehensive"] // Future
// ssh = ["TestSSHSecretsEngineComprehensive"] // Future
// pki = ["TestPKISecretsEngineComprehensive"] // Future
}
}
step "build_vault" {
@ -467,9 +461,19 @@ scenario "plugin" {
}
}
locals {
// Determine if filter contains test names (starts with "Test") or package names
is_test_name_filter = length(var.blackbox_test_filter) > 0 && length([for t in var.blackbox_test_filter : t if can(regex("^Test", t))]) > 0
// For plugins, if package filter is provided, convert to paths, otherwise use default plugins path
plugin_test_packages = length(var.blackbox_test_filter) > 0 && !local.is_test_name_filter ? [
for pkg in var.blackbox_test_filter : "./vault/external_tests/blackbox/plugins/${pkg}/..."
] : ["./vault/external_tests/blackbox/plugins/..."]
}
// Run comprehensive plugin blackbox tests
step "run_plugin_blackbox_tests" {
description = "Run comprehensive plugin blackbox tests"
description = local.is_test_name_filter ? "Run specific plugin tests: ${join(", ", var.blackbox_test_filter)}" : "Run plugin blackbox tests from: ${join(", ", length(var.blackbox_test_filter) > 0 && !local.is_test_name_filter ? var.blackbox_test_filter : ["plugins"])}"
module = module.vault_run_blackbox_test
depends_on = [step.get_vault_cluster_ips, step.set_up_plugin_services, step.verify_vault_version]
@ -485,8 +489,8 @@ scenario "plugin" {
leader_host = step.get_vault_cluster_ips.leader_host
leader_public_ip = step.get_vault_cluster_ips.leader_public_ip
vault_root_token = step.create_vault_cluster.root_token
test_names = local.test_names["ldap"] // Update this to select different plugin tests based on scenario configuration
test_package = "./vault/external_tests/blackbox/ldap"
test_names = local.is_test_name_filter ? var.blackbox_test_filter : null
test_package = local.is_test_name_filter ? "./vault/external_tests/blackbox" : join(" ", local.plugin_test_packages)
integration_host_state = step.set_up_plugin_services.state
vault_edition = matrix.edition
}

View File

@ -410,34 +410,24 @@ scenario "smoke_sdk" {
}
}
// Define smoke test suite
locals {
smoke_tests = [
"TestSecretsEngineCreate",
"TestSecretsEngineExternalCreate",
"TestUnsealedStatus",
"TestVaultVersion",
"TestSecretsEngineRead",
"TestSecretsEngineExternalRead",
"TestReplicationStatus",
"TestUIAssets",
"TestSecretsEngineDelete",
"TestSecretsEngineExternalDelete"
]
// Default test packages for smoke_sdk scenario
default_test_packages = ["core", "secrets", "replication", "raft", "integration"]
// Add backend-specific tests
smoke_tests_with_backend = concat(
local.smoke_tests,
matrix.backend == "raft" ? [
"TestRaftVoters",
"TestNodeRemovalAndRejoin"
] : []
)
// Determine if filter contains test names (starts with "Test") or package names
is_test_name_filter = length(var.blackbox_test_filter) > 0 && length([for t in var.blackbox_test_filter : t if can(regex("^Test", t))]) > 0
// Convert package names to directory paths, or use defaults
test_packages = length(var.blackbox_test_filter) > 0 && !local.is_test_name_filter ? [
for pkg in var.blackbox_test_filter : "./vault/external_tests/blackbox/${pkg}/..."
] : [
for pkg in local.default_test_packages : "./vault/external_tests/blackbox/${pkg}/..."
]
}
// Run all blackbox SDK smoke tests
// Run all blackbox SDK smoke tests using directory-based organization
step "run_blackbox_tests" {
description = "Run blackbox SDK smoke tests: ${join(", ", local.smoke_tests_with_backend)}"
description = local.is_test_name_filter ? "Run specific blackbox tests: ${join(", ", var.blackbox_test_filter)}" : "Run blackbox SDK tests from packages: ${join(", ", length(var.blackbox_test_filter) > 0 ? var.blackbox_test_filter : local.default_test_packages)}"
module = module.vault_run_blackbox_test
depends_on = [step.get_vault_cluster_ips, step.set_up_external_integration_target]
@ -449,8 +439,8 @@ scenario "smoke_sdk" {
leader_host = step.get_vault_cluster_ips.leader_host
leader_public_ip = step.get_vault_cluster_ips.leader_public_ip
vault_root_token = step.create_vault_cluster.root_token
test_names = local.smoke_tests_with_backend
test_package = "./vault/external_tests/blackbox"
test_names = local.is_test_name_filter ? var.blackbox_test_filter : null
test_package = local.is_test_name_filter ? "./vault/external_tests/blackbox" : join(" ", local.test_packages)
integration_host_state = step.set_up_external_integration_target.state
vault_edition = matrix.edition
}

View File

@ -62,6 +62,12 @@ variable "backend_log_level" {
default = "trace"
}
variable "blackbox_test_filter" {
type = list(string)
description = "Override list of specific blackbox test packages (e.g., ['core', 'secrets']) or test names (e.g., ['TestUnsealedStatus']). Empty list uses scenario defaults. Package names are converted to directory paths automatically."
default = []
}
variable "distro_version_amzn" {
description = "The version of Amazon Linux 2 to use"
type = string

View File

@ -10,14 +10,18 @@ terraform {
}
# Generate matrix.json for gotestsum from the test list
locals {
test_names = var.test_names != null ? var.test_names : []
}
resource "local_file" "test_matrix" {
filename = "/tmp/vault_test_matrix_${random_string.test_id.result}.json"
content = jsonencode({
include = length(var.test_names) > 0 ? [
for test in var.test_names : {
include = [
for test in local.test_names : {
test = test
}
] : []
]
})
}
@ -33,7 +37,7 @@ resource "enos_local_exec" "run_blackbox_test" {
VAULT_TOKEN = var.vault_root_token
VAULT_ADDR = var.vault_addr != null ? var.vault_addr : "http://${var.leader_public_ip}:8200"
VAULT_TEST_PACKAGE = var.test_package
VAULT_TEST_MATRIX = length(var.test_names) > 0 ? local_file.test_matrix.filename : ""
VAULT_TEST_MATRIX = length(local.test_names) > 0 ? local_file.test_matrix.filename : ""
VAULT_EDITION = var.vault_edition
# PATH and Go-related environment variables are inherited from the calling process
}, var.vault_namespace != null ? {

View File

@ -15,7 +15,7 @@ output "test_results_summary" {
exit_code = local.test_exit_code
timestamp = timestamp()
json_file = local.json_file_path
test_filter = length(var.test_names) > 0 ? join(", ", var.test_names) : "all tests"
test_filter = length(local.test_names) > 0 ? join(", ", local.test_names) : "all tests"
test_package = var.test_package
}
}

View File

@ -90,6 +90,9 @@ case $VAULT_EDITION in
esac
# Build gotestsum command based on whether we have specific tests
# Convert VAULT_TEST_PACKAGE to array to handle multiple package paths properly
IFS=$' ' read -r -d '' -a packages <<< "$VAULT_TEST_PACKAGE" || true
set -x # Show commands being executed
set +e # Temporarily disable exit on error
if [ -n "$VAULT_TEST_MATRIX" ] && [ -f "$VAULT_TEST_MATRIX" ]; then
@ -97,10 +100,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 "${tags}" -run="$test_pattern" "$VAULT_TEST_PACKAGE"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "${tags}" -run="$test_pattern" "${packages[@]}"
else
echo "Running all tests in package"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "${tags}" "$VAULT_TEST_PACKAGE"
gotestsum --junitfile="$junit_output" --format=standard-verbose --jsonfile="$json_output" -- -count=1 "${tags}" "${packages[@]}"
fi
test_exit_code=$?
set -e # Re-enable exit on error

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package auth
import (
"testing"

View File

@ -1,13 +1,14 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package auth
import (
"testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
helpers "github.com/hashicorp/vault/vault/external_tests/blackbox"
)
// testUserpassAuthCreate tests userpass auth engine creation
@ -20,7 +21,7 @@ func testUserpassAuthCreate(t *testing.T, v *blackbox.Session) {
`
// Use common utility to setup userpass auth
userClient := SetupUserpassAuth(v, "testuser", "passtestuser1", "reguser", userPolicy)
userClient := helpers.SetupUserpassAuth(v, "testuser", "passtestuser1", "reguser", userPolicy)
// Verify the auth method was enabled by reading auth mounts
authMounts := v.MustRead("sys/auth")
@ -56,7 +57,7 @@ func testUserpassAuthCreate(t *testing.T, v *blackbox.Session) {
// testUserpassAuthRead tests userpass auth engine read operations
func testUserpassAuthRead(t *testing.T, v *blackbox.Session) {
// Use common utility to setup userpass auth with default policy
userClient := SetupUserpassAuth(v, "readuser", "readpass123", "default", "")
userClient := helpers.SetupUserpassAuth(v, "readuser", "readpass123", "default", "")
// Read the user configuration
userConfig := v.MustRead("auth/userpass/users/readuser")

View File

@ -0,0 +1,25 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package core
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestVaultLicenseStatus verifies Vault license status response
func TestVaultLicenseStatus(t *testing.T) {
v := blackbox.New(t)
// Read the sys/license/status endpoint which should contain license info
licenseStatus := v.MustRead("sys/license/status")
if licenseStatus.Data["autoloaded"] == nil {
t.Fatal("Could not get license details from sys/license/status")
}
autoloaded := licenseStatus.Data["autoloaded"].(map[string]interface{})
if autoloaded["license_id"].(string) == "" {
t.Fatal("Could not retrieve license_id from sys/license/status")
}
}

View File

@ -0,0 +1,24 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package core
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestUIAssets verifies that the Vault UI is accessible
func TestUIAssets(t *testing.T) {
v := blackbox.New(t)
// This is a stub - in a real implementation, you would verify UI assets are accessible
// For now, just verify the UI endpoint is available by checking sys/internal/ui/mounts
uiMounts := v.MustRead("sys/internal/ui/mounts")
if uiMounts == nil || uiMounts.Data == nil {
t.Fatal("Could not access UI mounts endpoint")
}
t.Log("Successfully verified UI assets are accessible")
}

View File

@ -0,0 +1,21 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package core
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestUnsealedStatus verifies that the Vault cluster is unsealed (not sealed).
// This test only checks seal status, not general cluster health.
func TestUnsealedStatus(t *testing.T) {
v := blackbox.New(t)
// Verify the cluster is unsealed
v.AssertUnsealedAny()
t.Log("Successfully verified Vault cluster is unsealed")
}

View File

@ -0,0 +1,23 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package core
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestVaultVersion verifies Vault version endpoint accessibility and response
func TestVaultVersion(t *testing.T) {
v := blackbox.New(t)
// Read the sys/seal-status endpoint which should contain version info
sealStatus := v.MustRead("sys/seal-status")
if sealStatus.Data["version"] == nil {
t.Fatal("Could not retrieve version from sys/seal-status")
}
t.Logf("Vault version: %v", sealStatus.Data["version"])
}

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package integration
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package integration
import (
"testing"

View File

@ -1,31 +1,44 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package integration
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
helpers "github.com/hashicorp/vault/vault/external_tests/blackbox"
)
// TestToken_OrphanedWithPolicy verifies token creation with policy assignment,
// validates token authentication, and tests policy enforcement by attempting
// both allowed and denied operations on KV secrets.
func TestToken_OrphanedWithPolicy(t *testing.T) {
// TestAuthTokenIntegration tests token operations requiring elevated permissions
// These tests are excluded from cloud environments (HCP/Docker) which don't have
// the necessary permissions to create orphaned tokens.
func TestAuthTokenIntegration(t *testing.T) {
v := blackbox.New(t)
// Verify we have a healthy cluster first
v.AssertClusterHealthy()
t.Run("OrphanedWithPolicy", func(t *testing.T) {
testTokenOrphanedWithPolicy(t, v)
})
}
// testTokenOrphanedWithPolicy verifies token creation with policy assignment,
// validates token authentication, and tests policy enforcement by attempting
// both allowed and denied operations on KV secrets.
func testTokenOrphanedWithPolicy(t *testing.T, v *blackbox.Session) {
// Use common utility to create token with read-only policy
policyName := "read-secret-only"
v.MustWritePolicy(policyName, ReadOnlyPolicy)
v.MustWritePolicy(policyName, helpers.ReadOnlyPolicy)
token := CreateTestToken(v, []string{policyName}, "15m")
token := helpers.CreateTestToken(v, []string{policyName}, "15m")
t.Logf("Generated Token: %s...", token[:5])
v.AssertTokenIsValid(token, policyName)
// Setup KV engine and seed test data
SetupKVEngine(v, "secret")
helpers.SetupKVEngine(v, "secret")
v.MustWriteKV2("secret", "allowed/test", map[string]any{"val": "allowed"})
v.MustWriteKV2("secret", "denied/test", map[string]any{"val": "denied"})

View File

@ -1,12 +0,0 @@
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: BUSL-1.1
package plugin
import "testing"
// TestAlwaysPass is a placeholder test that always passes.
// This ensures the test directory has at least one test to run.
func TestAlwaysPass(t *testing.T) {
// This test intentionally does nothing and always passes
}

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"bytes"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"fmt"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package ldap
import (
"testing"

View File

@ -0,0 +1,21 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package raft
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestNodeRemovalAndRejoin tests raft node removal and rejoin capabilities
func TestNodeRemovalAndRejoin(t *testing.T) {
v := blackbox.New(t)
// This is a stub for node removal and rejoin testing
// In a real implementation, you would test raft node removal and rejoin
v.AssertClusterHealthy()
t.Log("Successfully verified raft cluster stability for node operations")
}

View File

@ -0,0 +1,20 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package raft
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestRaftVoters verifies that all nodes in the raft cluster are voters
func TestRaftVoters(t *testing.T) {
v := blackbox.New(t)
// Verify we have a healthy cluster regardless of node count
v.AssertClusterHealthy()
t.Log("Successfully verified raft cluster is healthy with at least one voter")
}

View File

@ -0,0 +1,40 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package replication
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
)
// TestReplicationStatus verifies replication status for both DR and performance replication
func TestReplicationStatus(t *testing.T) {
v := blackbox.New(t)
// Read replication status with proper nil checks
drStatus := v.MustRead("sys/replication/dr/status")
if drStatus == nil || drStatus.Data == nil {
t.Log("DR replication not available or not configured - skipping DR replication check")
} else {
if drMode, ok := drStatus.Data["mode"]; ok {
t.Logf("DR replication mode: %v", drMode)
} else {
t.Log("DR replication mode not available")
}
}
prStatus := v.MustRead("sys/replication/performance/status")
if prStatus == nil || prStatus.Data == nil {
t.Log("Performance replication not available or not configured - skipping performance replication check")
} else {
if prMode, ok := prStatus.Data["mode"]; ok {
t.Logf("Performance replication mode: %v", prMode)
} else {
t.Log("Performance replication mode not available")
}
}
t.Log("Successfully verified replication status endpoints are accessible")
}

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"os"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"os"

View File

@ -1,23 +1,24 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
helpers "github.com/hashicorp/vault/vault/external_tests/blackbox"
)
// testKVSecretsCreate tests KV secrets engine creation
func testKVSecretsCreate(t *testing.T, v *blackbox.Session) {
// KV secrets engine tests are now in kvv2_test.go - just test basic enablement here
SetupKVEngine(v, "kv-create")
helpers.SetupKVEngine(v, "kv-create")
// Write and read test data to verify engine works
v.MustWriteKV2("kv-create", "test/path", StandardKVData)
v.MustWriteKV2("kv-create", "test/path", helpers.StandardKVData)
secret := v.MustReadKV2("kv-create", "test/path")
AssertKVData(t, v, secret, StandardKVData)
helpers.AssertKVData(t, v, secret, helpers.StandardKVData)
t.Log("Successfully created and tested KV secrets engine")
}
@ -25,20 +26,20 @@ func testKVSecretsCreate(t *testing.T, v *blackbox.Session) {
// testKVSecretsRead tests KV secrets engine read operations
func testKVSecretsRead(t *testing.T, v *blackbox.Session) {
// KV read tests are in kvv2_test.go - test basic read functionality here
SetupKVEngine(v, "kv-read")
v.MustWriteKV2("kv-read", "read/test", AltKVData)
helpers.SetupKVEngine(v, "kv-read")
v.MustWriteKV2("kv-read", "read/test", helpers.AltKVData)
secret := v.MustReadKV2("kv-read", "read/test")
AssertKVData(t, v, secret, AltKVData)
helpers.AssertKVData(t, v, secret, helpers.AltKVData)
t.Log("Successfully read KV secrets engine data")
}
// testKVSecretsDelete tests KV secrets engine delete operations
func testKVSecretsDelete(t *testing.T, v *blackbox.Session) {
SetupKVEngine(v, "kv-delete")
v.MustWriteKV2("kv-delete", "delete/test", StandardKVData)
helpers.SetupKVEngine(v, "kv-delete")
v.MustWriteKV2("kv-delete", "delete/test", helpers.StandardKVData)
secret := v.MustReadKV2("kv-delete", "delete/test")
AssertKVData(t, v, secret, StandardKVData)
helpers.AssertKVData(t, v, secret, helpers.StandardKVData)
v.MustWrite("kv-delete/delete/delete/test", map[string]any{
"versions": []int{1},
})

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"net"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"

View File

@ -1,7 +1,7 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
package secrets
import (
"testing"

View File

@ -0,0 +1,65 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package system
import (
"context"
"testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
"github.com/stretchr/testify/require"
)
// TestBillingOverviewNamespaceRestrictions verifies that sys/billing/overview
// returns appropriate errors when called from different namespace levels in HVD.
// In HVD, tests run in admin/bbsdk-xxxxx, and this test verifies:
// - Calling from base namespace (admin) returns "unsupported path"
// - Calling from root namespace (empty) returns "permission denied"
func TestBillingOverviewNamespaceRestrictions(t *testing.T) {
v := blackbox.New(t)
// Verify cluster stability first
v.AssertClusterHealthy()
// Check if we're in HVD (has base namespace from VAULT_NAMESPACE)
baseNS := v.GetParentNamespace()
if baseNS == "" {
t.Skip("Skipping namespace restriction tests - no base namespace configured (not in HVD)")
}
testCases := []struct {
name string
namespaceSwitcher func(func() (*api.Secret, error)) (*api.Secret, error)
expectedError string
}{
{
name: "base_namespace_unsupported",
namespaceSwitcher: v.WithParentNamespace,
expectedError: "unsupported path",
},
{
name: "root_namespace_permission_denied",
namespaceSwitcher: v.WithRootNamespace,
expectedError: "permission denied",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var rawResp *api.Response
var err error
_, err = tc.namespaceSwitcher(func() (*api.Secret, error) {
var readErr error
rawResp, readErr = v.Client.Logical().ReadRawWithContext(context.Background(), "sys/billing/overview")
if readErr != nil {
return nil, readErr
}
// Parse the raw response to get the error
return v.Client.Logical().ParseRawResponseAndCloseBody(rawResp, nil)
})
require.ErrorContains(t, err, tc.expectedError)
})
}
}

View File

@ -1,175 +0,0 @@
// Copyright IBM Corp. 2025, 2026
// SPDX-License-Identifier: BUSL-1.1
package blackbox
import (
"context"
"testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/helper/testcluster/blackbox"
"github.com/stretchr/testify/require"
)
// TestUnsealedStatus verifies that the Vault cluster is unsealed and healthy
func TestUnsealedStatus(t *testing.T) {
v := blackbox.New(t)
// Verify the cluster is unsealed
v.AssertUnsealedAny()
t.Log("Successfully verified Vault cluster is unsealed")
}
// TestVaultVersion verifies Vault version endpoint accessibility and response
func TestVaultVersion(t *testing.T) {
v := blackbox.New(t)
// Read the sys/seal-status endpoint which should contain version info
sealStatus := v.MustRead("sys/seal-status")
if sealStatus.Data["version"] == nil {
t.Fatal("Could not retrieve version from sys/seal-status")
}
t.Logf("Vault version: %v", sealStatus.Data["version"])
}
// TestVaultLicenseStatus verifies Vault license status response
func TestVaultLicenseStatus(t *testing.T) {
v := blackbox.New(t)
// Read the sys/license/status endpoint which should contain license info
licenseStatus := v.MustRead("sys/license/status")
if licenseStatus.Data["autoloaded"] == nil {
t.Fatal("Could not get license details from sys/license/status")
}
autoloaded := licenseStatus.Data["autoloaded"].(map[string]interface{})
if autoloaded["license_id"].(string) == "" {
t.Fatal("Could not retrieve license_id from sys/license/status")
}
}
// TestRaftVoters verifies that all nodes in the raft cluster are voters
func TestRaftVoters(t *testing.T) {
v := blackbox.New(t)
// Verify we have a healthy cluster regardless of node count
v.AssertClusterHealthy()
t.Log("Successfully verified raft cluster is healthy with at least one voter")
}
// TestReplicationStatus verifies replication status for both DR and performance replication
func TestReplicationStatus(t *testing.T) {
v := blackbox.New(t)
// Read replication status with proper nil checks
drStatus := v.MustRead("sys/replication/dr/status")
if drStatus == nil || drStatus.Data == nil {
t.Log("DR replication not available or not configured - skipping DR replication check")
} else {
if drMode, ok := drStatus.Data["mode"]; ok {
t.Logf("DR replication mode: %v", drMode)
} else {
t.Log("DR replication mode not available")
}
}
prStatus := v.MustRead("sys/replication/performance/status")
if prStatus == nil || prStatus.Data == nil {
t.Log("Performance replication not available or not configured - skipping performance replication check")
} else {
if prMode, ok := prStatus.Data["mode"]; ok {
t.Logf("Performance replication mode: %v", prMode)
} else {
t.Log("Performance replication mode not available")
}
}
t.Log("Successfully verified replication status endpoints are accessible")
}
// TestUIAssets verifies that the Vault UI is accessible
func TestUIAssets(t *testing.T) {
v := blackbox.New(t)
// This is a stub - in a real implementation, you would verify UI assets are accessible
// For now, just verify the UI endpoint is available by checking sys/internal/ui/mounts
uiMounts := v.MustRead("sys/internal/ui/mounts")
if uiMounts == nil || uiMounts.Data == nil {
t.Fatal("Could not access UI mounts endpoint")
}
t.Log("Successfully verified UI assets are accessible")
}
// TestLogSecrets is a stub for log secrets verification
func TestLogSecrets(t *testing.T) {
// This is a stub for log secrets verification
// In a real implementation, you would check audit logs for proper secret handling
t.Skip("Log secrets verification - implementation pending")
}
// TestNodeRemovalAndRejoin tests raft node removal and rejoin capabilities
func TestNodeRemovalAndRejoin(t *testing.T) {
v := blackbox.New(t)
// This is a stub for node removal and rejoin testing
// In a real implementation, you would test raft node removal and rejoin
v.AssertClusterHealthy()
t.Log("Successfully verified raft cluster stability for node operations")
}
// TestBillingOverviewNamespaceRestrictions verifies that sys/billing/overview
// returns appropriate errors when called from different namespace levels in HVD.
// In HVD, tests run in admin/bbsdk-xxxxx, and this test verifies:
// - Calling from base namespace (admin) returns "unsupported path"
// - Calling from root namespace (empty) returns "permission denied"
func TestBillingOverviewNamespaceRestrictions(t *testing.T) {
v := blackbox.New(t)
// Verify cluster stability first
v.AssertClusterHealthy()
// Check if we're in HVD (has base namespace from VAULT_NAMESPACE)
baseNS := v.GetParentNamespace()
if baseNS == "" {
t.Skip("Skipping namespace restriction tests - no base namespace configured (not in HVD)")
}
testCases := []struct {
name string
namespaceSwitcher func(func() (*api.Secret, error)) (*api.Secret, error)
expectedError string
}{
{
name: "base_namespace_unsupported",
namespaceSwitcher: v.WithParentNamespace,
expectedError: "unsupported path",
},
{
name: "root_namespace_permission_denied",
namespaceSwitcher: v.WithRootNamespace,
expectedError: "permission denied",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var rawResp *api.Response
var err error
_, err = tc.namespaceSwitcher(func() (*api.Secret, error) {
var readErr error
rawResp, readErr = v.Client.Logical().ReadRawWithContext(context.Background(), "sys/billing/overview")
if readErr != nil {
return nil, readErr
}
// Parse the raw response to get the error
return v.Client.Logical().ParseRawResponseAndCloseBody(rawResp, nil)
})
require.ErrorContains(t, err, tc.expectedError)
})
}
}