Files
member-console/cmd/config_validate_test.go
T
cgalo5758 0b28a9dc29 Remediate security audit findings
- Replace gorilla/csrf with net/http CrossOriginProtection
- Require valkey-password and add TLS options for session store
- End session at /logout and revoke refresh tokens
- Re-derive identity and roles from provider every five minutes
- Process each Stripe webhook event in its own Temporal workflow
- Give each outbox entry its own workflow with Temporal retries
- Guard against stale Stripe events with provider timestamps
- Derive transport security from base-url scheme
2026-09-09 13:25:43 -05:00

120 lines
3.8 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package cmd
import (
"context"
"database/sql"
"os"
"strings"
"testing"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/spf13/viper"
"git.coopcloud.tech/wiki-cafe/member-console/internal/config"
"git.coopcloud.tech/wiki-cafe/member-console/internal/db"
"git.coopcloud.tech/wiki-cafe/member-console/internal/integration"
)
// vcSpec is a brand-neutral fixture spec for validate-config's DB-backed
// tests: one duration key, the shape the maintainer's bogus
// fedwiki-sync-interval save exposed (proposal.md, typed-config-keys).
var vcSpec = []config.ConfigKey{
{Name: "widget-sync-interval", Default: time.Hour, Usage: "widget sync interval"},
}
// validVCConfig resets the global Viper and sets a complete, well-formed
// core configuration pointed at dsn, mirroring internal/config's own
// validConfig() test helper (this package cannot import that unexported
// helper, so it is restated here against the same key set ValidateStart
// checks unconditionally).
func validVCConfig(dsn string) {
viper.Reset()
viper.Set("db-dsn", dsn)
viper.Set("valkey-addr", "localhost:6379")
viper.Set("valkey-password", "test-store-password")
viper.Set("oidc-idp-issuer-url", "https://idp.example.com/realms/main")
viper.Set("oidc-sp-client-id", "member-console")
viper.Set("base-url", "https://console.example.com")
viper.Set("deployment-name", config.DefaultDeploymentName)
}
// TestRunValidateConfig_DB covers validate-config's two failure paths (D10,
// task 2.5) and its clean-exit path against a real (scratch) database: a
// bad stored override row, a bad environment value for the same key, and a
// clean configuration.
func TestRunValidateConfig_DB(t *testing.T) {
dsn := os.Getenv("TEST_DATABASE_URL")
if dsn == "" {
t.Skip("TEST_DATABASE_URL not set, skipping integration test")
}
database, err := sql.Open("pgx", dsn)
if err != nil {
t.Fatalf("open database: %v", err)
}
t.Cleanup(func() { database.Close() })
if err := db.RunMigrations(database, migrationSources()); err != nil {
t.Fatalf("run migrations: %v", err)
}
q := integration.New(database)
clean := func() {
if _, err := q.DeleteConfigOverride(context.Background(), "widget-sync-interval"); err != nil {
t.Fatalf("clear override: %v", err)
}
}
clean()
t.Cleanup(clean)
t.Run("a bad stored row fails naming the key, the parser's sentence, and the remediation", func(t *testing.T) {
validVCConfig(dsn)
if err := q.UpsertConfigOverride(context.Background(), integration.UpsertConfigOverrideParams{
Key: "widget-sync-interval", Value: "hello",
}); err != nil {
t.Fatalf("seed bad override: %v", err)
}
t.Cleanup(clean)
ok, message := runValidateConfig(context.Background(), vcSpec)
if ok {
t.Fatalf("want failure, got ok: %s", message)
}
for _, want := range []string{
"widget-sync-interval",
`is not a duration; for example 30m or 1h30m`,
"clear it: member-console config clear widget-sync-interval",
} {
if !strings.Contains(message, want) {
t.Errorf("message %q missing %q", message, want)
}
}
})
t.Run("a bad environment value fails with the parser's sentence", func(t *testing.T) {
validVCConfig(dsn)
viper.Set("widget-sync-interval", "hello")
ok, message := runValidateConfig(context.Background(), vcSpec)
if ok {
t.Fatalf("want failure, got ok: %s", message)
}
if !strings.Contains(message, `is not a duration; for example 30m or 1h30m`) {
t.Errorf("message %q missing the parser's sentence", message)
}
})
t.Run("a clean configuration exits ok", func(t *testing.T) {
validVCConfig(dsn)
ok, message := runValidateConfig(context.Background(), vcSpec)
if !ok {
t.Fatalf("want ok, got failure: %s", message)
}
if message != "config validate: ok" {
t.Errorf("message = %q", message)
}
})
}