Omit empty fields from bootstrap config output
probod-bootstrap was writing empty strings and stub blocks such as
`esign: {}` into generated YAML. The post-marshal prune pass caused
part of that by stripping empty leaf strings while leaving empty
parent maps behind.
Drop the prune round-trip in WriteConfig and rely on struct-level
omitzero/omitempty tags plus custom IsZero() helpers on probodconfig.
Only include LLM providers when an API key is set, use a nil map for
extra API headers, and extend the dev-config Makefile recipe with the
local dev defaults already documented in .env.example.
Config loading is unchanged: omitted keys still decode to Go zero
values.
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
@@ -19,8 +19,8 @@
|
|||||||
# PROBOD_BASE_URL=http://localhost:8080
|
# PROBOD_BASE_URL=http://localhost:8080
|
||||||
# PROBOD_API_ADDR=:8080
|
# PROBOD_API_ADDR=:8080
|
||||||
# PROBOD_API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174
|
# PROBOD_API_CORS_ALLOWED_ORIGINS=http://localhost:8080,http://localhost:5173,http://localhost:5174
|
||||||
# PROBOD_TRUST_CENTER_HTTP_ADDR=:80
|
# PROBOD_TRUST_CENTER_HTTP_ADDR=:10080
|
||||||
# PROBOD_TRUST_CENTER_HTTPS_ADDR=:443
|
# PROBOD_TRUST_CENTER_HTTPS_ADDR=:10443
|
||||||
|
|
||||||
# ── Observability ─────────────────────────────────────────────────────
|
# ── Observability ─────────────────────────────────────────────────────
|
||||||
# PROBOD_METRICS_ADDR=localhost:8081
|
# PROBOD_METRICS_ADDR=localhost:8081
|
||||||
|
|||||||
19
GNUmakefile
19
GNUmakefile
@@ -201,18 +201,37 @@ $(CFG_DEV_OAUTH2_KEY):
|
|||||||
cfg/dev.yaml: bin/probod-bootstrap $(CFG_DEV_OAUTH2_KEY) compose/pebble/certs/rootCA.pem $(wildcard $(DEV_ENV))
|
cfg/dev.yaml: bin/probod-bootstrap $(CFG_DEV_OAUTH2_KEY) compose/pebble/certs/rootCA.pem $(wildcard $(DEV_ENV))
|
||||||
@$(MKDIR) $(@D)
|
@$(MKDIR) $(@D)
|
||||||
set -a; \
|
set -a; \
|
||||||
|
PROBOD_BASE_URL=http://localhost:8080; \
|
||||||
|
PROBOD_API_ADDR=:8080; \
|
||||||
PROBOD_ENCRYPTION_KEY="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; \
|
PROBOD_ENCRYPTION_KEY="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; \
|
||||||
|
PROBOD_AUTH_COOKIE_NAME=SSID; \
|
||||||
|
PROBOD_AUTH_COOKIE_DOMAIN=localhost; \
|
||||||
PROBOD_AUTH_COOKIE_SECRET="this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes"; \
|
PROBOD_AUTH_COOKIE_SECRET="this-is-a-secure-secret-for-cookie-signing-at-least-32-bytes"; \
|
||||||
PROBOD_AUTH_PASSWORD_PEPPER="this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes"; \
|
PROBOD_AUTH_PASSWORD_PEPPER="this-is-a-secure-pepper-for-password-hashing-at-least-32-bytes"; \
|
||||||
PROBOD_AUTH_COOKIE_SECURE=false; \
|
PROBOD_AUTH_COOKIE_SECURE=false; \
|
||||||
PROBOD_OAUTH2_SERVER_SIGNING_KEY="$$($(CAT) $(CFG_DEV_OAUTH2_KEY))"; \
|
PROBOD_OAUTH2_SERVER_SIGNING_KEY="$$($(CAT) $(CFG_DEV_OAUTH2_KEY))"; \
|
||||||
PROBOD_API_CORS_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:5173,http://localhost:5174"; \
|
PROBOD_API_CORS_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:5173,http://localhost:5174"; \
|
||||||
|
PROBOD_PG_ADDR=localhost:5432; \
|
||||||
|
PROBOD_PG_USERNAME=postgres; \
|
||||||
|
PROBOD_PG_PASSWORD=postgres; \
|
||||||
|
PROBOD_PG_DATABASE=probod; \
|
||||||
|
PROBOD_TRUST_CENTER_HTTP_ADDR=:10080; \
|
||||||
|
PROBOD_TRUST_CENTER_HTTPS_ADDR=:10443; \
|
||||||
|
PROBOD_AWS_REGION=us-east-1; \
|
||||||
|
PROBOD_AWS_BUCKET=probod; \
|
||||||
PROBOD_AWS_ACCESS_KEY_ID=probod; \
|
PROBOD_AWS_ACCESS_KEY_ID=probod; \
|
||||||
PROBOD_AWS_SECRET_ACCESS_KEY=thisisnotasecret; \
|
PROBOD_AWS_SECRET_ACCESS_KEY=thisisnotasecret; \
|
||||||
PROBOD_AWS_ENDPOINT=http://127.0.0.1:8333; \
|
PROBOD_AWS_ENDPOINT=http://127.0.0.1:8333; \
|
||||||
|
PROBOD_SMTP_ADDR=localhost:1025; \
|
||||||
|
PROBOD_MAILER_SENDER_EMAIL=no-reply@notification.getprobo.com; \
|
||||||
|
PROBOD_MAILER_SENDER_NAME=Probo; \
|
||||||
PROBOD_OPENAI_API_KEY=thisisnotasecret; \
|
PROBOD_OPENAI_API_KEY=thisisnotasecret; \
|
||||||
PROBOD_AGENT_THIRD_PARTY_VETTER_PROVIDER=openai; \
|
PROBOD_AGENT_THIRD_PARTY_VETTER_PROVIDER=openai; \
|
||||||
|
PROBOD_AGENT_THIRD_PARTY_VETTER_MODEL_NAME=gpt-4o; \
|
||||||
|
PROBOD_CHROME_DP_ADDR=localhost:9222; \
|
||||||
PROBOD_ACME_DIRECTORY=https://localhost:14000/dir; \
|
PROBOD_ACME_DIRECTORY=https://localhost:14000/dir; \
|
||||||
|
PROBOD_ACME_EMAIL=admin@probo.com; \
|
||||||
|
PROBOD_ACME_ROOT_CA="$$($(CAT) compose/pebble/certs/rootCA.pem)"; \
|
||||||
if [ -f $(DEV_ENV) ]; then . $(DEV_ENV); fi; \
|
if [ -f $(DEV_ENV) ]; then . $(DEV_ENV); fi; \
|
||||||
set +a; \
|
set +a; \
|
||||||
./bin/probod-bootstrap -output $@
|
./bin/probod-bootstrap -output $@
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func (b *Builder) Build() (*probodconfig.FullConfig, error) {
|
|||||||
Cors: probodconfig.CorsConfig{
|
Cors: probodconfig.CorsConfig{
|
||||||
AllowedOrigins: b.parseOriginsList(b.resolver.getEnv("PROBOD_API_CORS_ALLOWED_ORIGINS")),
|
AllowedOrigins: b.parseOriginsList(b.resolver.getEnv("PROBOD_API_CORS_ALLOWED_ORIGINS")),
|
||||||
},
|
},
|
||||||
ExtraHeaderFields: make(map[string]string),
|
ExtraHeaderFields: nil,
|
||||||
GraphQL: probodconfig.GraphQLConfig{
|
GraphQL: probodconfig.GraphQLConfig{
|
||||||
ParserTokenLimit: b.resolver.getEnvIntOrDefault("PROBOD_API_GRAPHQL_PARSER_TOKEN_LIMIT", 15000),
|
ParserTokenLimit: b.resolver.getEnvIntOrDefault("PROBOD_API_GRAPHQL_PARSER_TOKEN_LIMIT", 15000),
|
||||||
ComplexityLimit: b.resolver.getEnvIntOrDefault("PROBOD_API_GRAPHQL_COMPLEXITY_LIMIT", 2000),
|
ComplexityLimit: b.resolver.getEnvIntOrDefault("PROBOD_API_GRAPHQL_COMPLEXITY_LIMIT", 2000),
|
||||||
@@ -191,19 +191,13 @@ func (b *Builder) Build() (*probodconfig.FullConfig, error) {
|
|||||||
ReminderInterval: b.resolver.getEnvIntOrDefault("PROBOD_DOCUMENT_NOTIFICATION_REMINDER_INTERVAL", 86400),
|
ReminderInterval: b.resolver.getEnvIntOrDefault("PROBOD_DOCUMENT_NOTIFICATION_REMINDER_INTERVAL", 86400),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Agents: probodconfig.AgentsConfig{
|
Agents: func() probodconfig.AgentsConfig {
|
||||||
Providers: map[string]probodconfig.LLMProviderConfig{
|
defaultProvider := b.resolver.getEnvOrDefault("PROBOD_AGENT_DEFAULT_PROVIDER", "openai")
|
||||||
"openai": {
|
|
||||||
Type: "openai",
|
return probodconfig.AgentsConfig{
|
||||||
APIKey: b.resolver.getEnv("PROBOD_OPENAI_API_KEY"),
|
Providers: b.buildLLMProviders(),
|
||||||
},
|
|
||||||
"anthropic": {
|
|
||||||
Type: "anthropic",
|
|
||||||
APIKey: b.resolver.getEnv("PROBOD_ANTHROPIC_API_KEY"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Default: probodconfig.LLMAgentConfig{
|
Default: probodconfig.LLMAgentConfig{
|
||||||
Provider: b.resolver.getEnvOrDefault("PROBOD_AGENT_DEFAULT_PROVIDER", "openai"),
|
Provider: defaultProvider,
|
||||||
ModelName: b.resolver.getEnvOrDefault("PROBOD_AGENT_DEFAULT_MODEL_NAME", "gpt-4o"),
|
ModelName: b.resolver.getEnvOrDefault("PROBOD_AGENT_DEFAULT_MODEL_NAME", "gpt-4o"),
|
||||||
Temperature: new(b.resolver.getEnvFloatOrDefault("PROBOD_AGENT_DEFAULT_TEMPERATURE", 0.1)),
|
Temperature: new(b.resolver.getEnvFloatOrDefault("PROBOD_AGENT_DEFAULT_TEMPERATURE", 0.1)),
|
||||||
MaxTokens: new(b.resolver.getEnvIntOrDefault("PROBOD_AGENT_DEFAULT_MAX_TOKENS", 4096)),
|
MaxTokens: new(b.resolver.getEnvIntOrDefault("PROBOD_AGENT_DEFAULT_MAX_TOKENS", 4096)),
|
||||||
@@ -267,7 +261,8 @@ func (b *Builder) Build() (*probodconfig.FullConfig, error) {
|
|||||||
Tools: probodconfig.AgentToolsConfig{
|
Tools: probodconfig.AgentToolsConfig{
|
||||||
FirecrawlAPIKey: b.resolver.getEnv("PROBOD_FIRECRAWL_API_KEY"),
|
FirecrawlAPIKey: b.resolver.getEnv("PROBOD_FIRECRAWL_API_KEY"),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
|
}(),
|
||||||
CustomDomains: probodconfig.CustomDomainsConfig{
|
CustomDomains: probodconfig.CustomDomainsConfig{
|
||||||
RenewalInterval: b.resolver.getEnvIntOrDefault("PROBOD_CUSTOM_DOMAINS_RENEWAL_INTERVAL", 3600),
|
RenewalInterval: b.resolver.getEnvIntOrDefault("PROBOD_CUSTOM_DOMAINS_RENEWAL_INTERVAL", 3600),
|
||||||
ProvisionInterval: b.resolver.getEnvIntOrDefault("PROBOD_CUSTOM_DOMAINS_PROVISION_INTERVAL", 30),
|
ProvisionInterval: b.resolver.getEnvIntOrDefault("PROBOD_CUSTOM_DOMAINS_PROVISION_INTERVAL", 30),
|
||||||
@@ -647,6 +642,30 @@ func (b *Builder) getPgCACertBundle() string {
|
|||||||
return b.resolver.getEnv("PROBOD_PG_CA_BUNDLE")
|
return b.resolver.getEnv("PROBOD_PG_CA_BUNDLE")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) buildLLMProviders() map[string]probodconfig.LLMProviderConfig {
|
||||||
|
providers := map[string]probodconfig.LLMProviderConfig{}
|
||||||
|
|
||||||
|
if apiKey := b.resolver.getEnv("PROBOD_OPENAI_API_KEY"); apiKey != "" {
|
||||||
|
providers["openai"] = probodconfig.LLMProviderConfig{
|
||||||
|
Type: "openai",
|
||||||
|
APIKey: apiKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if apiKey := b.resolver.getEnv("PROBOD_ANTHROPIC_API_KEY"); apiKey != "" {
|
||||||
|
providers["anthropic"] = probodconfig.LLMProviderConfig{
|
||||||
|
Type: "anthropic",
|
||||||
|
APIKey: apiKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(providers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return providers
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Builder) parseOriginsList(s string) []string {
|
func (b *Builder) parseOriginsList(s string) []string {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ func TestBuilder_Build_Defaults(t *testing.T) {
|
|||||||
assert.Equal(t, "gpt-4o", cfg.Probod.Agents.Default.ModelName)
|
assert.Equal(t, "gpt-4o", cfg.Probod.Agents.Default.ModelName)
|
||||||
assert.Equal(t, new(0.1), cfg.Probod.Agents.Default.Temperature)
|
assert.Equal(t, new(0.1), cfg.Probod.Agents.Default.Temperature)
|
||||||
assert.Equal(t, new(4096), cfg.Probod.Agents.Default.MaxTokens)
|
assert.Equal(t, new(4096), cfg.Probod.Agents.Default.MaxTokens)
|
||||||
|
assert.Nil(t, cfg.Probod.Agents.Providers)
|
||||||
// Agents config — per-agent overrides are empty (inherit from default)
|
// Agents config — per-agent overrides are empty (inherit from default)
|
||||||
assert.Empty(t, cfg.Probod.Agents.Probo.Provider)
|
assert.Empty(t, cfg.Probod.Agents.Probo.Provider)
|
||||||
assert.Empty(t, cfg.Probod.Agents.Probo.ModelName)
|
assert.Empty(t, cfg.Probod.Agents.Probo.ModelName)
|
||||||
|
|||||||
@@ -37,28 +37,21 @@ func WriteConfig(cfg *probodconfig.FullConfig, path string, format Format) error
|
|||||||
return fmt.Errorf("create directory %s: %w", dir, err)
|
return fmt.Errorf("create directory %s: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := yaml.Marshal(cfg)
|
var (
|
||||||
if err != nil {
|
data []byte
|
||||||
return fmt.Errorf("marshal config: %w", err)
|
err error
|
||||||
}
|
)
|
||||||
|
|
||||||
var tree any
|
|
||||||
if err := yaml.Unmarshal(data, &tree); err != nil {
|
|
||||||
return fmt.Errorf("unmarshal config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pruned := pruneEmptyStrings(tree)
|
|
||||||
|
|
||||||
switch format {
|
switch format {
|
||||||
case FormatJSON:
|
case FormatJSON:
|
||||||
data, err = json.MarshalIndent(pruned, "", " ")
|
data, err = json.MarshalIndent(cfg, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("marshal pruned config as json: %w", err)
|
return fmt.Errorf("marshal config as json: %w", err)
|
||||||
}
|
}
|
||||||
case FormatYAML:
|
case FormatYAML:
|
||||||
data, err = yaml.Marshal(pruned)
|
data, err = yaml.Marshal(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("marshal pruned config as yaml: %w", err)
|
return fmt.Errorf("marshal config as yaml: %w", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported config format: %q", format)
|
return fmt.Errorf("unsupported config format: %q", format)
|
||||||
@@ -70,28 +63,3 @@ func WriteConfig(cfg *probodconfig.FullConfig, path string, format Format) error
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func pruneEmptyStrings(value any) any {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case map[string]any:
|
|
||||||
for key, child := range v {
|
|
||||||
if s, ok := child.(string); ok && s == "" {
|
|
||||||
delete(v, key)
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v[key] = pruneEmptyStrings(child)
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
case []any:
|
|
||||||
for i, child := range v {
|
|
||||||
v[i] = pruneEmptyStrings(child)
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
default:
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func TestWriteConfig_FilePermissions(t *testing.T) {
|
|||||||
assert.Equal(t, os.FileMode(0600), info.Mode().Perm())
|
assert.Equal(t, os.FileMode(0600), info.Mode().Perm())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteConfig_DropsEmptyStrings(t *testing.T) {
|
func TestWriteConfig_OmitsOptionalFields(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
configPath := filepath.Join(tmpDir, "probod.yml")
|
configPath := filepath.Join(tmpDir, "probod.yml")
|
||||||
|
|
||||||
@@ -97,7 +97,6 @@ func TestWriteConfig_DropsEmptyStrings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Probod: probodconfig.Config{
|
Probod: probodconfig.Config{
|
||||||
BaseURL: "http://localhost:8080",
|
BaseURL: "http://localhost:8080",
|
||||||
EncryptionKey: "",
|
|
||||||
ChromeDPAddr: "",
|
ChromeDPAddr: "",
|
||||||
Pg: probodconfig.PgConfig{
|
Pg: probodconfig.PgConfig{
|
||||||
Addr: "localhost:5432",
|
Addr: "localhost:5432",
|
||||||
@@ -124,8 +123,8 @@ func TestWriteConfig_DropsEmptyStrings(t *testing.T) {
|
|||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
assert.Equal(t, "http://localhost:8080", probod["base-url"])
|
assert.Equal(t, "http://localhost:8080", probod["base-url"])
|
||||||
assert.NotContains(t, probod, "encryption-key")
|
|
||||||
assert.NotContains(t, probod, "chrome-dp-addr")
|
assert.NotContains(t, probod, "chrome-dp-addr")
|
||||||
|
assert.NotContains(t, probod, "esign")
|
||||||
|
|
||||||
pg, ok := probod["pg"].(map[string]any)
|
pg, ok := probod["pg"].(map[string]any)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
@@ -146,12 +145,168 @@ func TestWriteConfig_DropsEmptyStrings(t *testing.T) {
|
|||||||
tracing, ok := unit["tracing"].(map[string]any)
|
tracing, ok := unit["tracing"].(map[string]any)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.NotContains(t, tracing, "addr")
|
assert.NotContains(t, tracing, "addr")
|
||||||
|
}
|
||||||
|
|
||||||
loaded := probodconfig.FullConfig{}
|
func TestWriteConfig_OmitsEmptyOptionalBlocks(t *testing.T) {
|
||||||
err = yaml.Unmarshal(data, &loaded)
|
tmpDir := t.TempDir()
|
||||||
|
configPath := filepath.Join(tmpDir, "probod.yml")
|
||||||
|
|
||||||
|
cfg := &probodconfig.FullConfig{
|
||||||
|
Probod: probodconfig.Config{
|
||||||
|
BaseURL: "http://localhost:8080",
|
||||||
|
EncryptionKey: "test-key",
|
||||||
|
Api: probodconfig.APIConfig{
|
||||||
|
Addr: ":8080",
|
||||||
|
},
|
||||||
|
Auth: probodconfig.AuthConfig{
|
||||||
|
Cookie: probodconfig.CookieConfig{
|
||||||
|
Name: "SSID",
|
||||||
|
Secret: "secret",
|
||||||
|
},
|
||||||
|
Password: probodconfig.PasswordConfig{
|
||||||
|
Pepper: "pepper",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TrustCenter: probodconfig.TrustCenterConfig{
|
||||||
|
HTTPAddr: ":80",
|
||||||
|
},
|
||||||
|
CustomDomains: probodconfig.CustomDomainsConfig{
|
||||||
|
RenewalInterval: 3600,
|
||||||
|
},
|
||||||
|
Agents: probodconfig.AgentsConfig{
|
||||||
|
Default: probodconfig.LLMAgentConfig{
|
||||||
|
Provider: "openai",
|
||||||
|
ModelName: "gpt-4o",
|
||||||
|
},
|
||||||
|
ThirdPartyDisambiguation: probodconfig.LLMAgentConfig{
|
||||||
|
MaxTokens: new(4096),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConfig(cfg, configPath, FormatYAML)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, cfg.Probod.BaseURL, loaded.Probod.BaseURL)
|
|
||||||
assert.Empty(t, loaded.Probod.EncryptionKey)
|
data, err := os.ReadFile(configPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var tree map[string]any
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(data, &tree)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
probod, ok := tree["probod"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
assert.NotContains(t, probod, "esign")
|
||||||
|
|
||||||
|
api, ok := probod["api"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, api, "cors")
|
||||||
|
assert.NotContains(t, api, "proxy-protocol")
|
||||||
|
assert.NotContains(t, api, "extra-header-fields")
|
||||||
|
|
||||||
|
auth, ok := probod["auth"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, auth, "google")
|
||||||
|
assert.NotContains(t, auth, "microsoft")
|
||||||
|
|
||||||
|
customDomains, ok := probod["custom-domains"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, customDomains, "acme")
|
||||||
|
|
||||||
|
trustCenter, ok := probod["trust-center"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, trustCenter, "proxy-protocol")
|
||||||
|
|
||||||
|
llm, ok := probod["llm"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, llm, "probo")
|
||||||
|
assert.NotContains(t, llm, "third-party-disambiguation")
|
||||||
|
assert.NotContains(t, llm, "tools")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteConfig_OmitsEmptyProxyProtocolAndCorsSlices(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
configPath := filepath.Join(tmpDir, "probod.yml")
|
||||||
|
|
||||||
|
cfg := &probodconfig.FullConfig{
|
||||||
|
Probod: probodconfig.Config{
|
||||||
|
BaseURL: "http://localhost:8080",
|
||||||
|
Api: probodconfig.APIConfig{
|
||||||
|
Addr: ":8080",
|
||||||
|
ProxyProtocol: probodconfig.ProxyProtocolConfig{
|
||||||
|
TrustedProxies: []string{},
|
||||||
|
},
|
||||||
|
Cors: probodconfig.CorsConfig{
|
||||||
|
AllowedOrigins: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TrustCenter: probodconfig.TrustCenterConfig{
|
||||||
|
HTTPAddr: ":10080",
|
||||||
|
ProxyProtocol: probodconfig.ProxyProtocolConfig{
|
||||||
|
TrustedProxies: make([]string, 0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConfig(cfg, configPath, FormatYAML)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
data, err := os.ReadFile(configPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var tree map[string]any
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(data, &tree)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
probod, ok := tree["probod"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
api, ok := probod["api"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, api, "proxy-protocol")
|
||||||
|
assert.NotContains(t, api, "cors")
|
||||||
|
|
||||||
|
trustCenter, ok := probod["trust-center"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, trustCenter, "proxy-protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteConfig_OmitsEmptyExtraHeaderFieldsMap(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
configPath := filepath.Join(tmpDir, "probod.yml")
|
||||||
|
|
||||||
|
cfg := &probodconfig.FullConfig{
|
||||||
|
Probod: probodconfig.Config{
|
||||||
|
BaseURL: "http://localhost:8080",
|
||||||
|
Api: probodconfig.APIConfig{
|
||||||
|
Addr: ":8080",
|
||||||
|
ExtraHeaderFields: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConfig(cfg, configPath, FormatYAML)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
data, err := os.ReadFile(configPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var tree map[string]any
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(data, &tree)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
probod, ok := tree["probod"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
api, ok := probod["api"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
|
assert.NotContains(t, api, "extra-header-fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteConfig_CompleteConfig(t *testing.T) {
|
func TestWriteConfig_CompleteConfig(t *testing.T) {
|
||||||
@@ -178,7 +333,6 @@ func TestWriteConfig_CompleteConfig(t *testing.T) {
|
|||||||
Cors: probodconfig.CorsConfig{
|
Cors: probodconfig.CorsConfig{
|
||||||
AllowedOrigins: []string{"http://localhost:8080"},
|
AllowedOrigins: []string{"http://localhost:8080"},
|
||||||
},
|
},
|
||||||
ExtraHeaderFields: map[string]string{},
|
|
||||||
},
|
},
|
||||||
Pg: probodconfig.PgConfig{
|
Pg: probodconfig.PgConfig{
|
||||||
Addr: "localhost:5432",
|
Addr: "localhost:5432",
|
||||||
@@ -256,7 +410,7 @@ func TestWriteConfig_JSON(t *testing.T) {
|
|||||||
probod, ok := tree["probod"].(map[string]any)
|
probod, ok := tree["probod"].(map[string]any)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
assert.Equal(t, "http://localhost:8080", probod["base-url"])
|
assert.Equal(t, "http://localhost:8080", probod["base-url"])
|
||||||
assert.NotContains(t, probod, "encryption-key")
|
assert.Equal(t, "", probod["encryption-key"])
|
||||||
|
|
||||||
var loaded probodconfig.FullConfig
|
var loaded probodconfig.FullConfig
|
||||||
|
|
||||||
|
|||||||
@@ -15,11 +15,19 @@
|
|||||||
package probodconfig
|
package probodconfig
|
||||||
|
|
||||||
type CorsConfig struct {
|
type CorsConfig struct {
|
||||||
AllowedOrigins []string `json:"allowed-origins"`
|
AllowedOrigins []string `json:"allowed-origins,omitzero,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c CorsConfig) IsZero() bool {
|
||||||
|
return len(c.AllowedOrigins) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyProtocolConfig struct {
|
type ProxyProtocolConfig struct {
|
||||||
TrustedProxies []string `json:"trusted-proxies"`
|
TrustedProxies []string `json:"trusted-proxies,omitzero,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ProxyProtocolConfig) IsZero() bool {
|
||||||
|
return len(c.TrustedProxies) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type GraphQLConfig struct {
|
type GraphQLConfig struct {
|
||||||
@@ -30,9 +38,9 @@ type GraphQLConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type APIConfig struct {
|
type APIConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr,omitempty"`
|
||||||
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol"`
|
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol,omitzero"`
|
||||||
Cors CorsConfig `json:"cors"`
|
Cors CorsConfig `json:"cors,omitzero"`
|
||||||
ExtraHeaderFields map[string]string `json:"extra-header-fields"`
|
ExtraHeaderFields map[string]string `json:"extra-header-fields,omitzero,omitempty"`
|
||||||
GraphQL GraphQLConfig `json:"graphql"`
|
GraphQL GraphQLConfig `json:"graphql,omitzero"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ type AuthConfig struct {
|
|||||||
PasswordResetTokenValidity int `json:"password-reset-token-validity"`
|
PasswordResetTokenValidity int `json:"password-reset-token-validity"`
|
||||||
MagicLinkTokenValidity int `json:"magic-link-token-validity"`
|
MagicLinkTokenValidity int `json:"magic-link-token-validity"`
|
||||||
SAML SAMLConfig `json:"saml"`
|
SAML SAMLConfig `json:"saml"`
|
||||||
Google OIDCProviderConfig `json:"google"`
|
Google OIDCProviderConfig `json:"google,omitzero"`
|
||||||
Microsoft OIDCProviderConfig `json:"microsoft"`
|
Microsoft OIDCProviderConfig `json:"microsoft,omitzero"`
|
||||||
OAuth2Server OAuth2ServerConfig `json:"oauth2-server"`
|
OAuth2Server OAuth2ServerConfig `json:"oauth2-server"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ type OAuth2ServerConfig struct {
|
|||||||
RefreshTokenDuration int `json:"refresh-token-duration"`
|
RefreshTokenDuration int `json:"refresh-token-duration"`
|
||||||
AuthorizationCodeDuration int `json:"authorization-code-duration"`
|
AuthorizationCodeDuration int `json:"authorization-code-duration"`
|
||||||
DeviceCodeDuration int `json:"device-code-duration"`
|
DeviceCodeDuration int `json:"device-code-duration"`
|
||||||
CIMDAllowedClientIDs []string `json:"cimd-allowed-client-ids"`
|
CIMDAllowedClientIDs []string `json:"cimd-allowed-client-ids,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OAuth2SigningKeyConfig struct {
|
type OAuth2SigningKeyConfig struct {
|
||||||
@@ -48,10 +48,10 @@ type OAuth2SigningKeyConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CookieConfig struct {
|
type CookieConfig struct {
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain,omitempty"`
|
||||||
Secret string `json:"secret"`
|
Secret string `json:"secret"`
|
||||||
Duration int `json:"duration"`
|
Duration int `json:"duration"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name,omitempty"`
|
||||||
Secure bool `json:"secure"`
|
Secure bool `json:"secure"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
package probodconfig
|
package probodconfig
|
||||||
|
|
||||||
type AWSConfig struct {
|
type AWSConfig struct {
|
||||||
Region string `json:"region"`
|
Region string `json:"region,omitempty"`
|
||||||
Bucket string `json:"bucket"`
|
Bucket string `json:"bucket,omitempty"`
|
||||||
AccessKeyID string `json:"access-key-id"`
|
AccessKeyID string `json:"access-key-id,omitempty"`
|
||||||
SecretAccessKey string `json:"secret-access-key"`
|
SecretAccessKey string `json:"secret-access-key,omitempty"`
|
||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint,omitempty"`
|
||||||
UsePathStyle bool `json:"use-path-style"`
|
UsePathStyle bool `json:"use-path-style"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ type (
|
|||||||
|
|
||||||
// TracingConfig contains tracing configuration.
|
// TracingConfig contains tracing configuration.
|
||||||
TracingConfig struct {
|
TracingConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr,omitempty"`
|
||||||
MaxBatchSize int `json:"max-batch-size"`
|
MaxBatchSize int `json:"max-batch-size"`
|
||||||
BatchTimeout int `json:"batch-timeout"`
|
BatchTimeout int `json:"batch-timeout"`
|
||||||
ExportTimeout int `json:"export-timeout"`
|
ExportTimeout int `json:"export-timeout"`
|
||||||
@@ -44,12 +44,12 @@ type (
|
|||||||
|
|
||||||
// ESignConfig contains electronic signature configuration.
|
// ESignConfig contains electronic signature configuration.
|
||||||
ESignConfig struct {
|
ESignConfig struct {
|
||||||
TSAURL string `json:"tsa-url"`
|
TSAURL string `json:"tsa-url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config represents the probod application configuration.
|
// Config represents the probod application configuration.
|
||||||
Config struct {
|
Config struct {
|
||||||
BaseURL string `json:"base-url"`
|
BaseURL string `json:"base-url,omitempty"`
|
||||||
EncryptionKey string `json:"encryption-key"`
|
EncryptionKey string `json:"encryption-key"`
|
||||||
Pg PgConfig `json:"pg"`
|
Pg PgConfig `json:"pg"`
|
||||||
Api APIConfig `json:"api"`
|
Api APIConfig `json:"api"`
|
||||||
@@ -57,7 +57,7 @@ type (
|
|||||||
TrustCenter TrustCenterConfig `json:"trust-center"`
|
TrustCenter TrustCenterConfig `json:"trust-center"`
|
||||||
AWS AWSConfig `json:"aws"`
|
AWS AWSConfig `json:"aws"`
|
||||||
Notifications NotificationsConfig `json:"notifications"`
|
Notifications NotificationsConfig `json:"notifications"`
|
||||||
Connectors []ConnectorConfig `json:"connectors"`
|
Connectors []ConnectorConfig `json:"connectors,omitempty"`
|
||||||
Agents AgentsConfig `json:"llm"`
|
Agents AgentsConfig `json:"llm"`
|
||||||
EvidenceDescriber EvidenceDescriberConfig `json:"evidence-describer"`
|
EvidenceDescriber EvidenceDescriberConfig `json:"evidence-describer"`
|
||||||
ThirdPartyVetting ThirdPartyVettingWorkerConfig `json:"third-party-vetting-worker"`
|
ThirdPartyVetting ThirdPartyVettingWorkerConfig `json:"third-party-vetting-worker"`
|
||||||
@@ -66,17 +66,17 @@ type (
|
|||||||
CommonPatternEnrichmentWorker CommonPatternEnrichmentWorkerConfig `json:"common-pattern-enrichment-worker"`
|
CommonPatternEnrichmentWorker CommonPatternEnrichmentWorkerConfig `json:"common-pattern-enrichment-worker"`
|
||||||
CommonThirdPartyEnrichmentWorker CommonThirdPartyEnrichmentWorkerConfig `json:"common-third-party-enrichment-worker"`
|
CommonThirdPartyEnrichmentWorker CommonThirdPartyEnrichmentWorkerConfig `json:"common-third-party-enrichment-worker"`
|
||||||
|
|
||||||
ChromeDPAddr string `json:"chrome-dp-addr"`
|
ChromeDPAddr string `json:"chrome-dp-addr,omitempty"`
|
||||||
CustomDomains CustomDomainsConfig `json:"custom-domains"`
|
CustomDomains CustomDomainsConfig `json:"custom-domains"`
|
||||||
SCIMBridge SCIMBridgeConfig `json:"scim-bridge"`
|
SCIMBridge SCIMBridgeConfig `json:"scim-bridge"`
|
||||||
ESign ESignConfig `json:"esign"`
|
ESign ESignConfig `json:"esign,omitzero"`
|
||||||
Branding bool `json:"branding"`
|
Branding bool `json:"branding"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrustCenterConfig contains trust center server configuration.
|
// TrustCenterConfig contains trust center server configuration.
|
||||||
TrustCenterConfig struct {
|
TrustCenterConfig struct {
|
||||||
HTTPAddr string `json:"http-addr"`
|
HTTPAddr string `json:"http-addr,omitempty"`
|
||||||
HTTPSAddr string `json:"https-addr"`
|
HTTPSAddr string `json:"https-addr,omitempty"`
|
||||||
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol"`
|
ProxyProtocol ProxyProtocolConfig `json:"proxy-protocol,omitzero"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,16 +17,16 @@ package probodconfig
|
|||||||
type CustomDomainsConfig struct {
|
type CustomDomainsConfig struct {
|
||||||
RenewalInterval int `json:"renewal-interval"`
|
RenewalInterval int `json:"renewal-interval"`
|
||||||
ProvisionInterval int `json:"provision-interval"`
|
ProvisionInterval int `json:"provision-interval"`
|
||||||
ResolverAddr string `json:"resolver-addr"`
|
ResolverAddr string `json:"resolver-addr,omitempty"`
|
||||||
CnameTarget string `json:"cname-target"`
|
CnameTarget string `json:"cname-target"`
|
||||||
CAAIssuerDomain string `json:"caa-issuer-domain"`
|
CAAIssuerDomain string `json:"caa-issuer-domain"`
|
||||||
ACME ACMEConfig `json:"acme"`
|
ACME ACMEConfig `json:"acme,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ACMEConfig struct {
|
type ACMEConfig struct {
|
||||||
Directory string `json:"directory"`
|
Directory string `json:"directory,omitempty"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email,omitempty"`
|
||||||
KeyType string `json:"key-type"`
|
KeyType string `json:"key-type,omitempty"`
|
||||||
AccountKey string `json:"account-key"`
|
AccountKey string `json:"account-key,omitempty"`
|
||||||
RootCA string `json:"root-ca"`
|
RootCA string `json:"root-ca,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ type (
|
|||||||
// LLM provider (e.g. OpenAI, Anthropic).
|
// LLM provider (e.g. OpenAI, Anthropic).
|
||||||
LLMProviderConfig struct {
|
LLMProviderConfig struct {
|
||||||
Type string `json:"type"` // "openai", "anthropic", "bedrock"
|
Type string `json:"type"` // "openai", "anthropic", "bedrock"
|
||||||
APIKey string `json:"api-key"` // for OpenAI and Anthropic
|
APIKey string `json:"api-key,omitempty"` // for OpenAI and Anthropic
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLMAgentConfig holds model parameters for a single agent. Provider
|
// LLMAgentConfig holds model parameters for a single agent. Provider
|
||||||
// references one of the keys in AgentsConfig.Providers.
|
// references one of the keys in AgentsConfig.Providers.
|
||||||
LLMAgentConfig struct {
|
LLMAgentConfig struct {
|
||||||
Provider string `json:"provider"` // key into AgentsConfig.Providers
|
Provider string `json:"provider,omitempty"` // key into AgentsConfig.Providers
|
||||||
ModelName string `json:"model-name"`
|
ModelName string `json:"model-name,omitempty"`
|
||||||
Temperature *float64 `json:"temperature"`
|
Temperature *float64 `json:"temperature,omitempty"`
|
||||||
MaxTokens *int `json:"max-tokens"`
|
MaxTokens *int `json:"max-tokens,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvidenceDescriberConfig holds worker-side tuning for the evidence
|
// EvidenceDescriberConfig holds worker-side tuning for the evidence
|
||||||
@@ -95,26 +95,38 @@ type (
|
|||||||
// AgentToolsConfig holds API keys and settings for external tools
|
// AgentToolsConfig holds API keys and settings for external tools
|
||||||
// that agents can use (web search, scraping, etc.).
|
// that agents can use (web search, scraping, etc.).
|
||||||
AgentToolsConfig struct {
|
AgentToolsConfig struct {
|
||||||
FirecrawlAPIKey string `json:"firecrawl-api-key"`
|
FirecrawlAPIKey string `json:"firecrawl-api-key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgentsConfig groups LLM provider credentials and per-agent model
|
// AgentsConfig groups LLM provider credentials and per-agent model
|
||||||
// settings. Default is used as a fallback when an agent-specific field
|
// settings. Default is used as a fallback when an agent-specific field
|
||||||
// is zero-valued.
|
// is zero-valued.
|
||||||
AgentsConfig struct {
|
AgentsConfig struct {
|
||||||
Providers map[string]LLMProviderConfig `json:"providers"`
|
Providers map[string]LLMProviderConfig `json:"providers,omitempty"`
|
||||||
Default LLMAgentConfig `json:"defaults"`
|
Default LLMAgentConfig `json:"defaults"`
|
||||||
Probo LLMAgentConfig `json:"probo"`
|
Probo LLMAgentConfig `json:"probo,omitzero"`
|
||||||
EvidenceDescriber LLMAgentConfig `json:"evidence-describer"`
|
EvidenceDescriber LLMAgentConfig `json:"evidence-describer,omitzero"`
|
||||||
ThirdPartyVetter LLMAgentConfig `json:"third-party-vetter"`
|
ThirdPartyVetter LLMAgentConfig `json:"third-party-vetter,omitzero"`
|
||||||
ThirdPartyDisambiguation LLMAgentConfig `json:"third-party-disambiguation"`
|
ThirdPartyDisambiguation LLMAgentConfig `json:"third-party-disambiguation,omitzero"`
|
||||||
TrackerMapping LLMAgentConfig `json:"tracker-mapping"`
|
TrackerMapping LLMAgentConfig `json:"tracker-mapping,omitzero"`
|
||||||
TrackerEnrichment LLMAgentConfig `json:"tracker-enrichment"`
|
TrackerEnrichment LLMAgentConfig `json:"tracker-enrichment,omitzero"`
|
||||||
CommonThirdPartyEnrichment LLMAgentConfig `json:"common-third-party-enrichment"`
|
CommonThirdPartyEnrichment LLMAgentConfig `json:"common-third-party-enrichment,omitzero"`
|
||||||
Tools AgentToolsConfig `json:"tools"`
|
Tools AgentToolsConfig `json:"tools,omitzero"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c LLMProviderConfig) IsZero() bool {
|
||||||
|
return c.APIKey == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c LLMAgentConfig) IsZero() bool {
|
||||||
|
return c.Provider == "" && c.ModelName == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AgentToolsConfig) IsZero() bool {
|
||||||
|
return c.FirecrawlAPIKey == ""
|
||||||
|
}
|
||||||
|
|
||||||
// ResolveAgent returns a fully populated LLMAgentConfig by filling in
|
// ResolveAgent returns a fully populated LLMAgentConfig by filling in
|
||||||
// zero-valued fields from the default config.
|
// zero-valued fields from the default config.
|
||||||
func (c *AgentsConfig) ResolveAgent(agent LLMAgentConfig) LLMAgentConfig {
|
func (c *AgentsConfig) ResolveAgent(agent LLMAgentConfig) LLMAgentConfig {
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ package probodconfig
|
|||||||
|
|
||||||
type MailerConfig struct {
|
type MailerConfig struct {
|
||||||
MailerInterval int `json:"mailer-interval"`
|
MailerInterval int `json:"mailer-interval"`
|
||||||
SenderName string `json:"sender-name"`
|
SenderName string `json:"sender-name,omitempty"`
|
||||||
SenderEmail string `json:"sender-email"`
|
SenderEmail string `json:"sender-email,omitempty"`
|
||||||
SMTP SMTPConfig `json:"smtp"`
|
SMTP SMTPConfig `json:"smtp,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SMTPConfig struct {
|
type SMTPConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr,omitempty"`
|
||||||
User string `json:"user"`
|
User string `json:"user,omitempty"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password,omitempty"`
|
||||||
TLSRequired bool `json:"tls-required"`
|
TLSRequired bool `json:"tls-required"`
|
||||||
HelloName string `json:"hello-name"`
|
HelloName string `json:"hello-name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,11 @@
|
|||||||
package probodconfig
|
package probodconfig
|
||||||
|
|
||||||
type OIDCProviderConfig struct {
|
type OIDCProviderConfig struct {
|
||||||
ClientID string `json:"client-id"`
|
ClientID string `json:"client-id,omitempty"`
|
||||||
ClientSecret string `json:"client-secret"`
|
ClientSecret string `json:"client-secret,omitempty"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c OIDCProviderConfig) IsZero() bool {
|
||||||
|
return c.ClientID == "" && c.ClientSecret == ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,17 +23,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PgConfig struct {
|
type PgConfig struct {
|
||||||
Addr string `json:"addr"`
|
Addr string `json:"addr,omitempty"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username,omitempty"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password,omitempty"`
|
||||||
Database string `json:"database"`
|
Database string `json:"database,omitempty"`
|
||||||
PoolSize int32 `json:"pool-size"`
|
PoolSize int32 `json:"pool-size"`
|
||||||
MinPoolSize int32 `json:"min-pool-size"`
|
MinPoolSize int32 `json:"min-pool-size"`
|
||||||
MaxConnIdleTimeSeconds int `json:"max-conn-idle-time-seconds"`
|
MaxConnIdleTimeSeconds int `json:"max-conn-idle-time-seconds"`
|
||||||
MaxConnLifetimeSeconds int `json:"max-conn-lifetime-seconds"`
|
MaxConnLifetimeSeconds int `json:"max-conn-lifetime-seconds"`
|
||||||
MaxConnLifetimeJitterSeconds int `json:"max-conn-lifetime-jitter-seconds"`
|
MaxConnLifetimeJitterSeconds int `json:"max-conn-lifetime-jitter-seconds"`
|
||||||
HealthCheckPeriodSeconds int `json:"health-check-period-seconds"`
|
HealthCheckPeriodSeconds int `json:"health-check-period-seconds"`
|
||||||
CACertBundle string `json:"ca-cert-bundle"`
|
CACertBundle string `json:"ca-cert-bundle,omitempty"`
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type SAMLConfig struct {
|
|||||||
Certificate string `json:"certificate"`
|
Certificate string `json:"certificate"`
|
||||||
PrivateKey string `json:"private-key"`
|
PrivateKey string `json:"private-key"`
|
||||||
DomainVerificationIntervalSeconds int `json:"domain-verification-interval-seconds"`
|
DomainVerificationIntervalSeconds int `json:"domain-verification-interval-seconds"`
|
||||||
DomainVerificationResolverAddr string `json:"domain-verification-resolver-addr"`
|
DomainVerificationResolverAddr string `json:"domain-verification-resolver-addr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c SAMLConfig) SessionDurationTime() time.Duration {
|
func (c SAMLConfig) SessionDurationTime() time.Duration {
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ package probodconfig
|
|||||||
|
|
||||||
type SlackConfig struct {
|
type SlackConfig struct {
|
||||||
SenderInterval int `json:"sender-interval"`
|
SenderInterval int `json:"sender-interval"`
|
||||||
SigningSecret string `json:"signing-secret"`
|
SigningSecret string `json:"signing-secret,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user