67 lines
2.6 KiB
Go
67 lines
2.6 KiB
Go
|
|
package config
|
||
|
|
|
||
|
|
import "testing"
|
||
|
|
|
||
|
|
// CROSS-LANGUAGE CONTRACT. The daemon and the web app must derive byte-identical
|
||
|
|
// tokens from the same THERMOGRAPH_AUTH_SECRET, or every callback 401s -- and it
|
||
|
|
// would surface as an auth error, which reads like a bug rather than like the
|
||
|
|
// configuration drift it actually is. The same vector is asserted on the Python
|
||
|
|
// side in backend/tests/api/test_internal_routes.py::test_derived_token_matches_go.
|
||
|
|
// If deriveLabel or the construction changes, BOTH must change together.
|
||
|
|
const (
|
||
|
|
sharedVectorSecret = "test-auth-secret"
|
||
|
|
sharedVectorToken = "4c3830b2158941ff52720d198b65f7924372a3a482b8da52540a4d9be38247ea"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestDeriveInternalTokenMatchesPython(t *testing.T) {
|
||
|
|
if got := deriveInternalToken(sharedVectorSecret); got != sharedVectorToken {
|
||
|
|
t.Fatalf("deriveInternalToken(%q) = %q; want %q (must match internal_routes.py)",
|
||
|
|
sharedVectorSecret, got, sharedVectorToken)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// An empty secret must yield nothing rather than some fixed "empty HMAC" value:
|
||
|
|
// the caller turns "" into a refusal to start, and inventing a token here would
|
||
|
|
// let the daemon run against a web app that computed a different one.
|
||
|
|
func TestDeriveInternalTokenEmptySecretYieldsNothing(t *testing.T) {
|
||
|
|
if got := deriveInternalToken(""); got != "" {
|
||
|
|
t.Fatalf("deriveInternalToken(%q) = %q; want empty so Load refuses to start", "", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadPrefersExplicitTokenOverDerived(t *testing.T) {
|
||
|
|
env := map[string]string{
|
||
|
|
"THERMOGRAPH_INTERNAL_TOKEN": "explicit-wins",
|
||
|
|
"THERMOGRAPH_AUTH_SECRET": sharedVectorSecret,
|
||
|
|
"THERMOGRAPH_API_BASE_INTERNAL": "http://web:8137",
|
||
|
|
}
|
||
|
|
cfg, err := load(func(k string) string { return env[k] })
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("load: %v", err)
|
||
|
|
}
|
||
|
|
if cfg.InternalToken != "explicit-wins" {
|
||
|
|
t.Fatalf("InternalToken = %q; an explicit env var must win over derivation", cfg.InternalToken)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadDerivesTokenWhenOnlyAuthSecretIsSet(t *testing.T) {
|
||
|
|
env := map[string]string{
|
||
|
|
"THERMOGRAPH_AUTH_SECRET": sharedVectorSecret,
|
||
|
|
"THERMOGRAPH_API_BASE_INTERNAL": "http://web:8137",
|
||
|
|
}
|
||
|
|
cfg, err := load(func(k string) string { return env[k] })
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("load: %v", err)
|
||
|
|
}
|
||
|
|
if cfg.InternalToken != sharedVectorToken {
|
||
|
|
t.Fatalf("InternalToken = %q; want the derived %q", cfg.InternalToken, sharedVectorToken)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadRefusesWhenNeitherTokenNorAuthSecretIsSet(t *testing.T) {
|
||
|
|
env := map[string]string{"THERMOGRAPH_API_BASE_INTERNAL": "http://web:8137"}
|
||
|
|
if _, err := load(func(k string) string { return env[k] }); err == nil {
|
||
|
|
t.Fatal("load succeeded with no token and no auth secret; it must refuse to start")
|
||
|
|
}
|
||
|
|
}
|