Skip to content

Commit 1b8ed3b

Browse files
committed
Allow passing YAML directly instead of writing to a file
1 parent 6a98b74 commit 1b8ed3b

3 files changed

Lines changed: 113 additions & 8 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ PPB also supports these environment variables for runtime configuration:
107107

108108
| Variable | Description | Default |
109109
|----------------------------------|----------------------------------------------|--------------------------|
110+
| `PPB_YAML` | YAML configuration content (takes priority) | - |
110111
| `PPB_CONFIG_PATH` | Path to YAML configuration file | /app/ppb.yaml |
111112
| `LOG_LEVEL` | Log level (`DEBUG`, `INFO`, `WARN`, `ERROR`) | `INFO` |
112113
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON file | Uses default credentials |

pkg/config/config.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,27 @@ func (i *IPNet) UnmarshalYAML(value *yaml.Node) error {
5252
}
5353

5454
func LoadConfig() (*Config, error) {
55-
filename := os.Getenv("PPB_CONFIG_PATH")
56-
if filename == "" {
57-
filename = "ppb.yaml"
58-
}
59-
slog.Debug("Loading config", "filename", filename)
60-
data, err := os.ReadFile(filename)
61-
if err != nil {
62-
return nil, err
55+
var data []byte
56+
var err error
57+
58+
// Check for PPB_YAML environment variable first (highest priority)
59+
yamlContent := os.Getenv("PPB_YAML")
60+
if yamlContent != "" {
61+
slog.Debug("Loading config from PPB_YAML environment variable")
62+
data = []byte(yamlContent)
63+
} else {
64+
// Fall back to file-based configuration
65+
filename := os.Getenv("PPB_CONFIG_PATH")
66+
if filename == "" {
67+
filename = "ppb.yaml"
68+
}
69+
slog.Debug("Loading config", "filename", filename)
70+
data, err = os.ReadFile(filename)
71+
if err != nil {
72+
return nil, err
73+
}
6374
}
75+
6476
expandedYaml := os.ExpandEnv(string(data))
6577

6678
var config Config

pkg/config/config_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package config
33
import (
44
"net"
55
"net/http"
6+
"os"
67
"testing"
78

89
yaml "gopkg.in/yaml.v3"
@@ -320,6 +321,97 @@ func TestConfig_setProxyTimeoutDefaults(t *testing.T) {
320321
}
321322
}
322323

324+
func TestLoadConfig_WithPPB_YAML(t *testing.T) {
325+
// Save original env vars
326+
originalYAML := os.Getenv("PPB_YAML")
327+
originalPath := os.Getenv("PPB_CONFIG_PATH")
328+
defer func() {
329+
os.Setenv("PPB_YAML", originalYAML)
330+
os.Setenv("PPB_CONFIG_PATH", originalPath)
331+
}()
332+
333+
tests := []struct {
334+
name string
335+
yamlContent string
336+
wantErr bool
337+
wantType string
338+
}{
339+
{
340+
name: "valid YAML via PPB_YAML",
341+
yamlContent: `type: google_compute_engine
342+
scheme: https
343+
port: 443
344+
allowedIps:
345+
- 0.0.0.0/0
346+
machineMetadata:
347+
project_id: test-project
348+
zone: us-central1-a
349+
name: test-instance`,
350+
wantErr: false,
351+
wantType: "google_compute_engine",
352+
},
353+
{
354+
name: "invalid YAML via PPB_YAML",
355+
yamlContent: "invalid: yaml: content: [[[",
356+
wantErr: true,
357+
},
358+
}
359+
360+
for _, tt := range tests {
361+
t.Run(tt.name, func(t *testing.T) {
362+
os.Setenv("PPB_YAML", tt.yamlContent)
363+
os.Unsetenv("PPB_CONFIG_PATH")
364+
365+
config, err := LoadConfig()
366+
367+
if (err != nil) != tt.wantErr {
368+
t.Errorf("LoadConfig() error = %v, wantErr %v", err, tt.wantErr)
369+
return
370+
}
371+
372+
if !tt.wantErr {
373+
if config.Type != tt.wantType {
374+
t.Errorf("LoadConfig() Type = %v, want %v", config.Type, tt.wantType)
375+
}
376+
}
377+
})
378+
}
379+
}
380+
381+
func TestLoadConfig_PriorityOrder(t *testing.T) {
382+
// Save original env vars
383+
originalYAML := os.Getenv("PPB_YAML")
384+
originalPath := os.Getenv("PPB_CONFIG_PATH")
385+
defer func() {
386+
os.Setenv("PPB_YAML", originalYAML)
387+
os.Setenv("PPB_CONFIG_PATH", originalPath)
388+
}()
389+
390+
yamlContent := `type: google_compute_engine
391+
scheme: https
392+
port: 443
393+
allowedIps:
394+
- 0.0.0.0/0
395+
machineMetadata:
396+
project_id: from-env-var
397+
zone: us-central1-a
398+
name: test-instance`
399+
400+
// Test that PPB_YAML takes priority over PPB_CONFIG_PATH
401+
os.Setenv("PPB_YAML", yamlContent)
402+
os.Setenv("PPB_CONFIG_PATH", "/nonexistent/file.yaml")
403+
404+
config, err := LoadConfig()
405+
if err != nil {
406+
t.Errorf("LoadConfig() should succeed with PPB_YAML even if PPB_CONFIG_PATH is invalid, error = %v", err)
407+
return
408+
}
409+
410+
if config.Machine.ProjectId != "from-env-var" {
411+
t.Errorf("LoadConfig() should load from PPB_YAML, got project_id = %v, want from-env-var", config.Machine.ProjectId)
412+
}
413+
}
414+
323415
func TestProxyTimeouts_UnmarshalYAML(t *testing.T) {
324416
tests := []struct {
325417
name string

0 commit comments

Comments
 (0)