Skip to content

Commit 9c2dcad

Browse files
committed
chore(docs): Refactor configuration requirements and descriptions
- Updated the required status of several configuration fields in the Config struct to improve clarity and flexibility. - Adjusted descriptions for various fields to provide clearer guidance on their usage and requirements. - Removed default values from descriptions where applicable to avoid confusion. - Ensured consistency in required fields across different configuration types, including Redis, MQ, and Portal configurations. - Enhanced webhook and AWS Kinesis configurations by refining descriptions and removing unnecessary defaults.
1 parent 8512d9a commit 9c2dcad

File tree

8 files changed

+191
-173
lines changed

8 files changed

+191
-173
lines changed

cmd/configdocsgen/main.go

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// Known Limitations/Further Improvements:
2+
// Embedded Structs (AST): Fields from anonymously embedded structs are not fully resolved during AST parsing for documentation as part of the parent struct.
3+
// Complex Slice/Map YAML Formatting: Default value formatting for slices is basic. Maps are not explicitly formatted for YAML beyond their default string representation.
4+
15
package main
26

37
import (
@@ -58,22 +62,22 @@ func main() {
5862
log.Printf("Found config struct: %s in file %s", cfg.Name, cfg.FileName)
5963
}
6064

61-
err = generateDocs(parsedConfigs, outputFile) // Corrected: use outputFile
62-
if err != nil {
63-
log.Fatalf("Error generating docs: %v", err)
64-
}
65-
66-
// Attempt to get and print default values
67-
// This is a preliminary step to verify type loading and reflection.
65+
// Attempt to get default values and integrate them BEFORE generating docs
6866
log.Println("Attempting to load and reflect on config.Config for default values...")
6967
defaults, err := getConfigDefaults()
7068
if err != nil {
7169
log.Printf("Warning: Could not get config defaults: %v", err)
72-
log.Println("Default values will be missing from the generated documentation.")
70+
log.Println("Default values will be missing or incorrect in the generated documentation.")
7371
} else {
7472
log.Printf("Successfully reflected on config.Config. Total default keys found: %d", len(defaults))
7573
// Integrate defaults into parsedConfigs
76-
integrateDefaults(parsedConfigs, defaults) // Call the integration function
74+
integrateDefaults(parsedConfigs, defaults) // This modifies parsedConfigs in place
75+
}
76+
77+
// Now generate docs with populated defaults
78+
err = generateDocs(parsedConfigs, outputFile)
79+
if err != nil {
80+
log.Fatalf("Error generating docs: %v", err)
7781
}
7882

7983
fmt.Printf("Successfully generated documentation to %s\n", outputFile)
@@ -411,9 +415,9 @@ func integrateDefaults(parsedConfigs []ParsedConfig, defaults map[string]interfa
411415
// The path prefix for fields of RedisConfig would be "Redis".
412416

413417
if nestedStructInfo, isStruct := otherConfigs[field.Type]; isStruct {
414-
log.Printf("Recursing for nested struct field %s (type %s) with path prefix %s", field.Name, field.Type, field.Name)
415-
// The prefix for the children of this field is the field's own name.
416-
assignDefaults(&nestedStructInfo.Fields, field.Name)
418+
log.Printf("Recursing for nested struct field %s (type %s) with path prefix %s", field.Name, field.Type, defaultPathKey)
419+
// The prefix for the children of this field is the full path to this field.
420+
assignDefaults(&nestedStructInfo.Fields, defaultPathKey)
417421
} else {
418422
log.Printf("No direct default found for %s (path key: %s)", field.Name, defaultPathKey)
419423
}
@@ -451,9 +455,20 @@ func generateDocs(parsedConfigs []ParsedConfig, outputPath string) error {
451455
defaultValueText := field.DefaultValue
452456
if defaultValueText == "" || defaultValueText == "<nil>" { // Handle <nil> from Sprintf as well
453457
defaultValueText = "`nil`"
458+
} else {
459+
// Escape special characters for Markdown table cells
460+
defaultValueText = strings.ReplaceAll(defaultValueText, "|", "\\|")
461+
// defaultValueText = strings.ReplaceAll(defaultValueText, "{", "\\{")
462+
// defaultValueText = strings.ReplaceAll(defaultValueText, "}", "\\}")
463+
// Enclose in backticks if not already `nil`
464+
defaultValueText = fmt.Sprintf("`%s`", defaultValueText)
454465
}
466+
455467
descriptionText := strings.ReplaceAll(field.Description, "|", "\\|")
456468
descriptionText = strings.ReplaceAll(descriptionText, "\n", " ") // Ensure description is single line for table
469+
// Escape curly braces for MDX in descriptions
470+
descriptionText = strings.ReplaceAll(descriptionText, "{", "\\{")
471+
descriptionText = strings.ReplaceAll(descriptionText, "}", "\\}")
457472

458473
envVarsBuilder.WriteString(fmt.Sprintf("| `%s` | %s | %s | %s |\n",
459474
field.EnvName,
@@ -463,7 +478,6 @@ func generateDocs(parsedConfigs []ParsedConfig, outputPath string) error {
463478
))
464479
}
465480
envVarsContent := strings.TrimRight(envVarsBuilder.String(), "\n")
466-
467481
// --- Generate YAML Content (including fences) ---
468482
var yamlBuilder strings.Builder
469483
// The "## YAML" header should be manually placed in the MDX file.

docs/pages/references/configuration.mdx

Lines changed: 119 additions & 119 deletions
Large diffs are not rendered by default.

internal/config/config.go

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,21 @@ type Config struct {
4141
configPath string // stores the path of the config file used
4242

4343
Service string `yaml:"service" env:"SERVICE" desc:"Specifies the service type to run. Valid values: 'api', 'log', 'delivery', or empty/all for singular mode (runs all services)." required:"N"`
44-
LogLevel string `yaml:"log_level" env:"LOG_LEVEL" desc:"Defines the verbosity of application logs. Common values: 'trace', 'debug', 'info', 'warn', 'error'." required:"Y"`
45-
AuditLog bool `yaml:"audit_log" env:"AUDIT_LOG" desc:"Enables or disables audit logging for significant events." required:"Y"`
44+
LogLevel string `yaml:"log_level" env:"LOG_LEVEL" desc:"Defines the verbosity of application logs. Common values: 'trace', 'debug', 'info', 'warn', 'error'." required:"N"`
45+
AuditLog bool `yaml:"audit_log" env:"AUDIT_LOG" desc:"Enables or disables audit logging for significant events." required:"N"`
4646
OpenTelemetry OpenTelemetryConfig `yaml:"otel"`
4747
Telemetry TelemetryConfig `yaml:"telemetry"`
4848

4949
// API
50-
APIPort int `yaml:"api_port" env:"API_PORT" desc:"Port number for the API server to listen on." required:"Y"`
50+
APIPort int `yaml:"api_port" env:"API_PORT" desc:"Port number for the API server to listen on." required:"N"`
5151
APIKey string `yaml:"api_key" env:"API_KEY" desc:"API key for authenticating requests to the Outpost API." required:"Y"`
52-
APIJWTSecret string `yaml:"api_jwt_secret" env:"API_JWT_SECRET" desc:"Secret key for signing and verifying JWTs if JWT authentication is used for the API. Required only if JWT authentication is enabled for the API." required:"C"`
52+
APIJWTSecret string `yaml:"api_jwt_secret" env:"API_JWT_SECRET" desc:"Secret key for signing and verifying JWTs if JWT authentication is used for the API." required:"Y"`
5353
GinMode string `yaml:"gin_mode" env:"GIN_MODE" desc:"Sets the Gin framework mode (e.g., 'debug', 'release', 'test'). See Gin documentation for details." required:"N"`
5454

5555
// Application
5656
AESEncryptionSecret string `yaml:"aes_encryption_secret" env:"AES_ENCRYPTION_SECRET" desc:"A 16, 24, or 32 byte secret key used for AES encryption of sensitive data at rest." required:"Y"`
5757
Topics []string `yaml:"topics" env:"TOPICS" envSeparator:"," desc:"Comma-separated list of topics that this Outpost instance should subscribe to for event processing." required:"N"`
58-
OrganizationName string `yaml:"organization_name" env:"ORGANIZATION_NAME" desc:"Name of the organization, used for display purposes and potentially in user agent strings." required:"Y"`
58+
OrganizationName string `yaml:"organization_name" env:"ORGANIZATION_NAME" desc:"Name of the organization, used for display purposes and potentially in user agent strings." required:"N"`
5959
HTTPUserAgent string `yaml:"http_user_agent" env:"HTTP_USER_AGENT" desc:"Custom HTTP User-Agent string for outgoing webhook deliveries. If unset, a default (OrganizationName/Version) is used." required:"N"`
6060

6161
// Infrastructure
@@ -69,23 +69,23 @@ type Config struct {
6969

7070
// Consumers
7171
PublishMaxConcurrency int `yaml:"publish_max_concurrency" env:"PUBLISH_MAX_CONCURRENCY" desc:"Maximum number of messages to process concurrently from the publish queue." required:"N"`
72-
DeliveryMaxConcurrency int `yaml:"delivery_max_concurrency" env:"DELIVERY_MAX_CONCURRENCY" desc:"Maximum number of delivery attempts to process concurrently." required:"Y"`
73-
LogMaxConcurrency int `yaml:"log_max_concurrency" env:"LOG_MAX_CONCURRENCY" desc:"Maximum number of log writing operations to process concurrently." required:"Y"`
72+
DeliveryMaxConcurrency int `yaml:"delivery_max_concurrency" env:"DELIVERY_MAX_CONCURRENCY" desc:"Maximum number of delivery attempts to process concurrently." required:"N"`
73+
LogMaxConcurrency int `yaml:"log_max_concurrency" env:"LOG_MAX_CONCURRENCY" desc:"Maximum number of log writing operations to process concurrently." required:"N"`
7474

7575
// Delivery Retry
76-
RetryIntervalSeconds int `yaml:"retry_interval_seconds" env:"RETRY_INTERVAL_SECONDS" desc:"Interval in seconds between delivery retry attempts for failed webhooks." required:"Y"`
77-
RetryMaxLimit int `yaml:"retry_max_limit" env:"MAX_RETRY_LIMIT" desc:"Maximum number of retry attempts for a single event delivery before giving up." required:"Y"`
76+
RetryIntervalSeconds int `yaml:"retry_interval_seconds" env:"RETRY_INTERVAL_SECONDS" desc:"Interval in seconds between delivery retry attempts for failed webhooks." required:"N"`
77+
RetryMaxLimit int `yaml:"retry_max_limit" env:"MAX_RETRY_LIMIT" desc:"Maximum number of retry attempts for a single event delivery before giving up." required:"N"`
7878

7979
// Event Delivery
80-
MaxDestinationsPerTenant int `yaml:"max_destinations_per_tenant" env:"MAX_DESTINATIONS_PER_TENANT" desc:"Maximum number of destinations allowed per tenant/organization." required:"Y"`
81-
DeliveryTimeoutSeconds int `yaml:"delivery_timeout_seconds" env:"DELIVERY_TIMEOUT_SECONDS" desc:"Timeout in seconds for HTTP requests made during event delivery to webhook destinations." required:"Y"`
80+
MaxDestinationsPerTenant int `yaml:"max_destinations_per_tenant" env:"MAX_DESTINATIONS_PER_TENANT" desc:"Maximum number of destinations allowed per tenant/organization." required:"N"`
81+
DeliveryTimeoutSeconds int `yaml:"delivery_timeout_seconds" env:"DELIVERY_TIMEOUT_SECONDS" desc:"Timeout in seconds for HTTP requests made during event delivery to webhook destinations." required:"N"`
8282

8383
// Destination Registry
8484
DestinationMetadataPath string `yaml:"destination_metadata_path" env:"DESTINATION_METADATA_PATH" desc:"Path to the directory containing custom destination type definitions. Overrides 'destinations.metadata_path' if set." required:"N"`
8585

8686
// Log batcher configuration
87-
LogBatchThresholdSeconds int `yaml:"log_batch_threshold_seconds" env:"LOG_BATCH_THRESHOLD_SECONDS" desc:"Maximum time in seconds to buffer logs before flushing them to storage, if batch size is not reached." required:"Y"`
88-
LogBatchSize int `yaml:"log_batch_size" env:"LOG_BATCH_SIZE" desc:"Maximum number of log entries to batch together before writing to storage." required:"Y"`
87+
LogBatchThresholdSeconds int `yaml:"log_batch_threshold_seconds" env:"LOG_BATCH_THRESHOLD_SECONDS" desc:"Maximum time in seconds to buffer logs before flushing them to storage, if batch size is not reached." required:"N"`
88+
LogBatchSize int `yaml:"log_batch_size" env:"LOG_BATCH_SIZE" desc:"Maximum number of log entries to batch together before writing to storage." required:"N"`
8989

9090
DisableTelemetry bool `yaml:"disable_telemetry" env:"DISABLE_TELEMETRY" desc:"Global flag to disable all telemetry (anonymous usage statistics to Hookdeck and error reporting to Sentry). If true, overrides 'telemetry.disabled'." required:"N"`
9191

@@ -153,7 +153,11 @@ func (c *Config) InitDefaults() {
153153
c.Destinations = DestinationsConfig{
154154
MetadataPath: "config/outpost/destinations",
155155
Webhook: DestinationWebhookConfig{
156-
HeaderPrefix: "x-outpost-",
156+
HeaderPrefix: "x-outpost-",
157+
SignatureContentTemplate: "{{.Timestamp.Unix}}.{{.Body}}",
158+
SignatureHeaderTemplate: "t={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}",
159+
SignatureEncoding: "hex",
160+
SignatureAlgorithm: "hmac-sha256",
157161
},
158162
AWSKinesis: DestinationAWSKinesisConfig{
159163
MetadataInPayload: true,
@@ -305,8 +309,8 @@ func ParseWithOS(flags Flags, osInterface OSInterface) (*Config, error) {
305309
type RedisConfig struct {
306310
Host string `yaml:"host" env:"REDIS_HOST" desc:"Hostname or IP address of the Redis server." required:"Y"`
307311
Port int `yaml:"port" env:"REDIS_PORT" desc:"Port number for the Redis server." required:"Y"`
308-
Password string `yaml:"password" env:"REDIS_PASSWORD" desc:"Password for Redis authentication, if required by the server." required:"N"`
309-
Database int `yaml:"database" env:"REDIS_DATABASE" desc:"Redis database number to select after connecting." required:"N"`
312+
Password string `yaml:"password" env:"REDIS_PASSWORD" desc:"Password for Redis authentication, if required by the server." required:"Y"`
313+
Database int `yaml:"database" env:"REDIS_DATABASE" desc:"Redis database number to select after connecting." required:"Y"`
310314
}
311315

312316
func (c *RedisConfig) ToConfig() *redis.RedisConfig {

internal/config/destinations.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
// DestinationsConfig is the main configuration for all destination types
1111
type DestinationsConfig struct {
12-
MetadataPath string `yaml:"metadata_path" env:"DESTINATIONS_METADATA_PATH" desc:"Path to the directory containing custom destination type definitions. If not set, defaults to 'config/outpost/destinations' as per InitDefaults. This can be overridden by the root-level 'destination_metadata_path' if also set." required:"N"`
12+
MetadataPath string `yaml:"metadata_path" env:"DESTINATIONS_METADATA_PATH" desc:"Path to the directory containing custom destination type definitions. This can be overridden by the root-level 'destination_metadata_path' if also set." required:"N"`
1313
Webhook DestinationWebhookConfig `yaml:"webhook" desc:"Configuration specific to webhook destinations."`
1414
AWSKinesis DestinationAWSKinesisConfig `yaml:"aws_kinesis" desc:"Configuration specific to AWS Kinesis destinations."`
1515
}
@@ -33,15 +33,15 @@ func (c *DestinationsConfig) ToConfig(cfg *Config) destregistrydefault.RegisterD
3333

3434
// Webhook configuration
3535
type DestinationWebhookConfig struct {
36-
HeaderPrefix string `yaml:"header_prefix" env:"DESTINATIONS_WEBHOOK_HEADER_PREFIX" desc:"Prefix for custom headers added to webhook requests (e.g., 'X-MyOrg-'). Defaults to 'x-outpost-'." required:"N"`
37-
DisableDefaultEventIDHeader bool `yaml:"disable_default_event_id_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER" desc:"If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests. Defaults to false." required:"N"`
38-
DisableDefaultSignatureHeader bool `yaml:"disable_default_signature_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER" desc:"If true, disables adding the default 'X-Outpost-Signature' header to webhook requests. Defaults to false." required:"N"`
39-
DisableDefaultTimestampHeader bool `yaml:"disable_default_timestamp_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER" desc:"If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests. Defaults to false." required:"N"`
40-
DisableDefaultTopicHeader bool `yaml:"disable_default_topic_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER" desc:"If true, disables adding the default 'X-Outpost-Topic' header to webhook requests. Defaults to false." required:"N"`
41-
SignatureContentTemplate string `yaml:"signature_content_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE" desc:"Go template for constructing the content to be signed for webhook requests. Defaults to '{{.Timestamp.Unix}}.{{.Body}}'." required:"N"`
42-
SignatureHeaderTemplate string `yaml:"signature_header_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE" desc:"Go template for the value of the signature header. Defaults to 't={{.Timestamp.Unix}},v0={{.Signatures | join \",\"}}'." required:"N"`
43-
SignatureEncoding string `yaml:"signature_encoding" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING" desc:"Encoding for the signature (e.g., 'hex', 'base64'). Defaults to 'hex'." required:"N"`
44-
SignatureAlgorithm string `yaml:"signature_algorithm" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM" desc:"Algorithm used for signing webhook requests (e.g., 'hmac-sha256'). Defaults to 'hmac-sha256'." required:"N"`
36+
HeaderPrefix string `yaml:"header_prefix" env:"DESTINATIONS_WEBHOOK_HEADER_PREFIX" desc:"Prefix for custom headers added to webhook requests (e.g., 'X-MyOrg-')." required:"N"`
37+
DisableDefaultEventIDHeader bool `yaml:"disable_default_event_id_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_EVENT_ID_HEADER" desc:"If true, disables adding the default 'X-Outpost-Event-Id' header to webhook requests." required:"N"`
38+
DisableDefaultSignatureHeader bool `yaml:"disable_default_signature_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_SIGNATURE_HEADER" desc:"If true, disables adding the default 'X-Outpost-Signature' header to webhook requests." required:"N"`
39+
DisableDefaultTimestampHeader bool `yaml:"disable_default_timestamp_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TIMESTAMP_HEADER" desc:"If true, disables adding the default 'X-Outpost-Timestamp' header to webhook requests." required:"N"`
40+
DisableDefaultTopicHeader bool `yaml:"disable_default_topic_header" env:"DESTINATIONS_WEBHOOK_DISABLE_DEFAULT_TOPIC_HEADER" desc:"If true, disables adding the default 'X-Outpost-Topic' header to webhook requests." required:"N"`
41+
SignatureContentTemplate string `yaml:"signature_content_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_CONTENT_TEMPLATE" desc:"Go template for constructing the content to be signed for webhook requests." required:"N"`
42+
SignatureHeaderTemplate string `yaml:"signature_header_template" env:"DESTINATIONS_WEBHOOK_SIGNATURE_HEADER_TEMPLATE" desc:"Go template for the value of the signature header." required:"N"`
43+
SignatureEncoding string `yaml:"signature_encoding" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ENCODING" desc:"Encoding for the signature (e.g., 'hex', 'base64')." required:"N"`
44+
SignatureAlgorithm string `yaml:"signature_algorithm" env:"DESTINATIONS_WEBHOOK_SIGNATURE_ALGORITHM" desc:"Algorithm used for signing webhook requests (e.g., 'hmac-sha256')." required:"N"`
4545
}
4646

4747
// toConfig converts WebhookConfig to the provider config - private since it's only used internally
@@ -61,7 +61,7 @@ func (c *DestinationWebhookConfig) toConfig() *destregistrydefault.DestWebhookCo
6161

6262
// AWS Kinesis configuration
6363
type DestinationAWSKinesisConfig struct {
64-
MetadataInPayload bool `yaml:"metadata_in_payload" env:"DESTINATIONS_AWS_KINESIS_METADATA_IN_PAYLOAD" desc:"If true, includes Outpost metadata (event ID, topic, etc.) within the Kinesis record payload. Defaults to true." required:"N"`
64+
MetadataInPayload bool `yaml:"metadata_in_payload" env:"DESTINATIONS_AWS_KINESIS_METADATA_IN_PAYLOAD" desc:"If true, includes Outpost metadata (event ID, topic, etc.) within the Kinesis record payload." required:"N"`
6565
}
6666

6767
// toConfig converts AWSKinesisConfig to the provider config

0 commit comments

Comments
 (0)