feat: OpenBao 应用凭据安全存储切片 #12
@@ -41,13 +41,15 @@ import (
|
|||||||
// 只连接本测试创建的无持久卷 dev server,不接受生产地址或环境 token。
|
// 只连接本测试创建的无持久卷 dev server,不接受生产地址或环境 token。
|
||||||
func baoFixture(t *testing.T) *bao.Client {
|
func baoFixture(t *testing.T) *bao.Client {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
const image = "openbao/openbao@sha256:5b2486ab0fb90bbc788cc345b0a08616dfb375873ee8be5df3a2fd4d378a67e0"
|
||||||
|
prepareBaoImage(t, image)
|
||||||
|
// 冷缓存拉取不占用容器启动和健康检查的一分钟预算。
|
||||||
ctx, cancel := context.WithTimeout(t.Context(), time.Minute)
|
ctx, cancel := context.WithTimeout(t.Context(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
const image = "openbao/openbao@sha256:5b2486ab0fb90bbc788cc345b0a08616dfb375873ee8be5df3a2fd4d378a67e0"
|
output, err := exec.CommandContext(ctx, "docker", "run", "--pull=never", "--rm", "-d", "-p", "127.0.0.1::8200",
|
||||||
output, err := exec.CommandContext(ctx, "docker", "run", "--rm", "-d", "-p", "127.0.0.1::8200",
|
|
||||||
image, "server", "-dev", "-dev-root-token-id="+fixtureToken, "-dev-listen-address=0.0.0.0:8200").Output()
|
image, "server", "-dev", "-dev-root-token-id="+fixtureToken, "-dev-listen-address=0.0.0.0:8200").Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cannot start isolated OpenBao fixture")
|
t.Fatalf("cannot start isolated OpenBao fixture: %s", baoCommandError(ctx, err))
|
||||||
}
|
}
|
||||||
id := strings.TrimSpace(string(output))
|
id := strings.TrimSpace(string(output))
|
||||||
if !regexp.MustCompile(`^[a-f0-9]{64}$`).MatchString(id) {
|
if !regexp.MustCompile(`^[a-f0-9]{64}$`).MatchString(id) {
|
||||||
@@ -63,7 +65,7 @@ func baoFixture(t *testing.T) *bao.Client {
|
|||||||
output, err = exec.CommandContext(ctx, "docker", "inspect", "--format",
|
output, err = exec.CommandContext(ctx, "docker", "inspect", "--format",
|
||||||
`{{(index (index .NetworkSettings.Ports "8200/tcp") 0).HostPort}}`, id).Output()
|
`{{(index (index .NetworkSettings.Ports "8200/tcp") 0).HostPort}}`, id).Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("cannot inspect fixture port")
|
t.Fatalf("cannot inspect fixture port: %s", baoCommandError(ctx, err))
|
||||||
}
|
}
|
||||||
client := fixtureClient(t, "http://127.0.0.1:"+strings.TrimSpace(string(output)))
|
client := fixtureClient(t, "http://127.0.0.1:"+strings.TrimSpace(string(output)))
|
||||||
client.SetMaxRetries(0)
|
client.SetMaxRetries(0)
|
||||||
@@ -79,6 +81,44 @@ func baoFixture(t *testing.T) *bao.Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareBaoImage(t *testing.T, image string) {
|
||||||
|
t.Helper()
|
||||||
|
ctx, cancel := context.WithTimeout(t.Context(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
if exec.CommandContext(ctx, "docker", "image", "inspect", image).Run() == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Log("pulling isolated OpenBao fixture image (timeout: 5m)")
|
||||||
|
if _, err := exec.CommandContext(ctx, "docker", "pull", image).Output(); err != nil {
|
||||||
|
t.Fatalf("cannot pull OpenBao fixture image: %s", baoCommandError(ctx, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留 Docker stderr 与超时原因,但不泄露测试 token/password 或完整命令参数。
|
||||||
|
func baoCommandError(ctx context.Context, err error) string {
|
||||||
|
detail := err.Error()
|
||||||
|
if exitErr, ok := errors.AsType[*exec.ExitError](err); ok {
|
||||||
|
detail += ": " + strings.TrimSpace(string(exitErr.Stderr))
|
||||||
|
}
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
detail += ": " + ctx.Err().Error()
|
||||||
|
}
|
||||||
|
return strings.NewReplacer(fixtureToken, "[REDACTED]", fixturePassword, "[REDACTED]").Replace(detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBaoCommandError(t *testing.T) {
|
||||||
|
err := &exec.ExitError{Stderr: []byte("registry unavailable " + fixtureToken + " " + fixturePassword)}
|
||||||
|
ctx, cancel := context.WithCancel(t.Context())
|
||||||
|
cancel()
|
||||||
|
detail := baoCommandError(ctx, err)
|
||||||
|
if !strings.Contains(detail, "registry unavailable") || !strings.Contains(detail, "context canceled") {
|
||||||
|
t.Fatal("Docker diagnostic or context failure was lost")
|
||||||
|
}
|
||||||
|
if strings.Contains(detail, fixtureToken) || strings.Contains(detail, fixturePassword) {
|
||||||
|
t.Fatal("Docker diagnostic exposed fixture credentials")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCredentialConcurrentCreateWithRealOpenBao(t *testing.T) {
|
func TestCredentialConcurrentCreateWithRealOpenBao(t *testing.T) {
|
||||||
root := baoFixture(t)
|
root := baoFixture(t)
|
||||||
store := fixtureStore(t, root)
|
store := fixtureStore(t, root)
|
||||||
|
|||||||
Reference in New Issue
Block a user