feat: integrate OA activation workflows and business migration
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBusinessOAEnvironmentAndRuntimeMerge(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "config.yaml")
|
||||
if err := os.WriteFile(path, []byte("server:\n http:\n addr: ':8000'\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("KRA_BUSINESS_OA_URL", "http://oa.test/api")
|
||||
t.Setenv("KRA_BUSINESS_OA_KEY", "test-only-key")
|
||||
value, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if value.BusinessOA == nil || value.BusinessOA.URL != "http://oa.test/api" || value.BusinessOA.Key != "test-only-key" {
|
||||
t.Fatal("environment-only OA configuration not loaded")
|
||||
}
|
||||
merged := MergeRuntimeConfig(value, &Config{Admin: &Admin{}})
|
||||
merged.BusinessOA.Key = "changed"
|
||||
if value.BusinessOA.Key != "test-only-key" {
|
||||
t.Fatal("configuration snapshot shared a pointer")
|
||||
}
|
||||
serialized, err := json.Marshal(value)
|
||||
if err != nil || strings.Contains(string(serialized), "test-only-key") {
|
||||
t.Fatal("service credential leaked through public configuration")
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ func MergeRuntimeConfig(current, next *Config) *Config {
|
||||
}
|
||||
return merged
|
||||
}
|
||||
if merged.BusinessOA == nil {
|
||||
merged.BusinessOA = clonePtr(current.BusinessOA)
|
||||
}
|
||||
if merged.Server == nil {
|
||||
merged.Server = clonePtr(current.Server)
|
||||
}
|
||||
|
||||
@@ -332,6 +332,8 @@ func newViper(path string) *viper.Viper {
|
||||
v.SetEnvPrefix("KRA")
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
|
||||
v.AutomaticEnv()
|
||||
_ = v.BindEnv("business_oa.url")
|
||||
_ = v.BindEnv("business_oa.key")
|
||||
return v
|
||||
}
|
||||
|
||||
@@ -385,6 +387,7 @@ func cloneConfig(value *Config) *Config {
|
||||
return nil
|
||||
}
|
||||
copied := *value
|
||||
copied.BusinessOA = clonePtr(value.BusinessOA)
|
||||
copied.Server = clonePtr(value.Server)
|
||||
if copied.Server != nil {
|
||||
copied.Server.HTTP = clonePtr(value.Server.HTTP)
|
||||
|
||||
@@ -6,9 +6,10 @@ import "time"
|
||||
// It intentionally uses ordinary Go types so configuration is independent of
|
||||
// protobuf generation and can be consumed by every internal module.
|
||||
type Config struct {
|
||||
Server *Server `mapstructure:"server" yaml:"server" json:"server"`
|
||||
Data *Data `mapstructure:"data" yaml:"data" json:"data"`
|
||||
Admin *Admin `mapstructure:"admin" yaml:"admin" json:"admin"`
|
||||
BusinessOA *BusinessOA `mapstructure:"business_oa" yaml:"business_oa" json:"-"`
|
||||
Server *Server `mapstructure:"server" yaml:"server" json:"server"`
|
||||
Data *Data `mapstructure:"data" yaml:"data" json:"data"`
|
||||
Admin *Admin `mapstructure:"admin" yaml:"admin" json:"admin"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
@@ -224,3 +225,9 @@ type ObjectStore struct {
|
||||
ForcePathStyle bool `mapstructure:"force_path_style" yaml:"force_path_style" json:"force_path_style"`
|
||||
AccountID string `mapstructure:"account_id" yaml:"account_id" json:"account_id"`
|
||||
}
|
||||
|
||||
// BusinessOA.URL 包含 OA 的路由前缀;Key 与 OA 服务间密钥一致。
|
||||
type BusinessOA struct {
|
||||
URL string `mapstructure:"url" yaml:"url" json:"url"`
|
||||
Key string `mapstructure:"key" yaml:"key" json:"-"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user