From 4d3949c1f2c4322c80f8b3898bef8e57e91f71ef Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 22 Sep 2026 11:20:37 +0000 Subject: [PATCH] Scrub example config of real credentials and internal hosts (closes #172) config.example.yml carried a real-looking 20-char S3 access key id and 40-char secret, a private-address http:// endpoint, and a storage_url naming an internal rclone remote and pool path. Replace them with the same neutral placeholders the `config init` template uses: YOUR_ACCESS_KEY / YOUR_SECRET_KEY, a https://s3.example.com endpoint, a mybucket bucket, and rclone://myremote/path/to/backups. No behavior or other keys change. The credentials live in the commented-out s3 block, which the loader never parses, so the new test reads the file's raw text to assert the placeholders are present and no http:// endpoint remains, and also loads it to confirm the active storage_url still parses. Model: opus-4-8 --- config.example.yml | 10 ++++---- internal/config/config_test.go | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/config.example.yml b/config.example.yml index b023b5a..a3ed69b 100644 --- a/config.example.yml +++ b/config.example.yml @@ -257,16 +257,16 @@ exclude: # Storage URL - use either this OR the s3 section below # Supports: s3://bucket/prefix, file:///path, rclone://remote/path -storage_url: "rclone://las1stor1//srv/pool.2024.04/backups/heraklion" +storage_url: "rclone://myremote/path/to/backups" # S3-compatible storage configuration #s3: # # S3-compatible endpoint URL # # Examples: https://s3.amazonaws.com, https://storage.googleapis.com -# endpoint: http://10.100.205.122:8333 +# endpoint: https://s3.example.com # # # Bucket name where backups will be stored -# bucket: testbucket +# bucket: mybucket # # # Prefix (folder) within the bucket for this host's backups # # Useful for organizing backups from multiple hosts @@ -274,8 +274,8 @@ storage_url: "rclone://las1stor1//srv/pool.2024.04/backups/heraklion" # #prefix: "hosts/myserver/" # # # S3 access credentials -# access_key_id: Z9GT22M9YFU08WRMC5D4 -# secret_access_key: Pi0tPKjFbN4rZlRhcA4zBtEkib04yy2WcIzI+AXk +# access_key_id: YOUR_ACCESS_KEY +# secret_access_key: YOUR_SECRET_KEY # # # S3 region # # Default: us-east-1 diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 823a5bc..591ac86 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -87,6 +87,48 @@ func TestConfigLoad(t *testing.T) { } } +// TestExampleConfigIsScrubbedAndLoads checks that the shipped +// config.example.yml carries only neutral placeholders (no real credentials, +// private addresses, or internal host names) and still parses. +func TestExampleConfigIsScrubbedAndLoads(t *testing.T) { + t.Parallel() + + examplePath := filepath.Join("..", "..", "config.example.yml") + + cfg, err := Load(examplePath) + if err != nil { + t.Fatalf("Failed to load config.example.yml: %v", err) + } + + if cfg.StorageURL != "rclone://myremote/path/to/backups" { + t.Errorf("Expected neutral storage_url, got '%s'", cfg.StorageURL) + } + + //nolint:gosec // G304: examplePath is a fixed in-repo path, not user input + raw, err := os.ReadFile(examplePath) + if err != nil { + t.Fatalf("Failed to read config.example.yml: %v", err) + } + + text := string(raw) + + wantSubstrings := []string{ + "YOUR_ACCESS_KEY", + "YOUR_SECRET_KEY", + "endpoint: https://", + } + for _, want := range wantSubstrings { + if !strings.Contains(text, want) { + t.Errorf("Expected config.example.yml to contain %q", want) + } + } + + // A raw "http://" scheme would mean a plaintext, likely private endpoint. + if strings.Contains(text, "http://") { + t.Error("config.example.yml should not contain an http:// endpoint") + } +} + // TestConfigFromEnv tests loading config path from environment variable func TestConfigFromEnv(t *testing.T) { t.Parallel()