-
-
Notifications
You must be signed in to change notification settings - Fork 70
Sync dev to main #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Sync dev to main #182
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
52efa9b
storage/cloud: avoid panic when waitForRetry is unset
tis24dev fbd9aa9
storage: normalize bundle inputs before building bundle and legacy si…
tis24dev 5d049bb
orchestrator: isolate HA restore subtests from shared global state
tis24dev 323abc1
orchestrator: guard decrypt workflow UI entry points against typed-ni…
tis24dev c2cd1cf
orchestrator: make decrypt TUI e2e key injection screen-driven instea…
tis24dev 5cdbf7b
notify/webhook: stabilize retry cancellation test with atomic attempt…
tis24dev fe4240b
config: quote unsafe secondary path values when mutating backup.env
tis24dev e1beabc
config: assert exact final env values in env mutation tests
tis24dev 97a04c0
config: make setBaseDirEnv unset BASE_DIR when empty
tis24dev da617e0
cmd/proxsave: normalize preserved entry slashes in new install output
tis24dev f8d5b60
cmd/proxsave: remove unused clearImmutableAttributes wrapper
tis24dev 3e3884b
cmd/proxsave: respect context cancellation when resolving existing co…
tis24dev 0a1d889
orchestrator: remove redundant stdout cleanup in CLI workflow test he…
tis24dev c8a7044
config: derive invalid migration fixture from base install template
tis24dev fbd1f20
orchestrator: assert context forwarding in restore TUI confirmation t…
tis24dev 7706577
orchestrator: write CLI path validation errors to stderr
tis24dev b74c625
orchestrator: synchronize restore TUI countdown shutdown before readi…
tis24dev a098750
identity: always relock identity file on canceled or failed writes
tis24dev 2bf4e33
fix(notify): validate cloud relay response body on HTTP 200
tis24dev 4f184cc
Improve relay error diagnostics and worker IP whitelist docs
tis24dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,74 +1,112 @@ | ||
| package config | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| func TestApplySecondaryStorageSettingsEnabled(t *testing.T) { | ||
| template := "SECONDARY_ENABLED=false\nSECONDARY_PATH=\nSECONDARY_LOG_PATH=\n" | ||
| func parseMutatedEnvTemplate(t *testing.T, template string) (map[string]string, map[string]int) { | ||
| t.Helper() | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, true, " /mnt/secondary ", " /mnt/secondary/log ") | ||
| values := make(map[string]string) | ||
| counts := make(map[string]int) | ||
|
|
||
| for _, line := range strings.Split(template, "\n") { | ||
| trimmed := strings.TrimSpace(line) | ||
| if trimmed == "" || strings.HasPrefix(trimmed, "#") { | ||
| continue | ||
| } | ||
|
|
||
| for _, needle := range []string{ | ||
| "SECONDARY_ENABLED=true", | ||
| "SECONDARY_PATH=/mnt/secondary", | ||
| "SECONDARY_LOG_PATH=/mnt/secondary/log", | ||
| } { | ||
| if !strings.Contains(got, needle) { | ||
| t.Fatalf("expected %q in template:\n%s", needle, got) | ||
| parts := strings.SplitN(line, "=", 2) | ||
| if len(parts) != 2 { | ||
| t.Fatalf("invalid env line %q in template:\n%s", line, template) | ||
| } | ||
|
|
||
| key := strings.TrimSpace(parts[0]) | ||
| value := parts[1] | ||
| counts[key]++ | ||
| values[key] = value | ||
| } | ||
|
|
||
| return values, counts | ||
| } | ||
|
|
||
| func assertMutatedEnvValue(t *testing.T, values map[string]string, counts map[string]int, key, want string) { | ||
| t.Helper() | ||
|
|
||
| if got := counts[key]; got != 1 { | ||
| t.Fatalf("%s occurrences = %d; want 1", key, got) | ||
| } | ||
| if got := values[key]; got != want { | ||
| t.Fatalf("%s = %q; want %q", key, got, want) | ||
| } | ||
| } | ||
|
|
||
| func TestApplySecondaryStorageSettingsEnabled(t *testing.T) { | ||
| template := "SECONDARY_ENABLED=false\nSECONDARY_PATH=\nSECONDARY_LOG_PATH=\n" | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, true, " /mnt/secondary ", " /mnt/secondary/log ") | ||
| values, counts := parseMutatedEnvTemplate(t, got) | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_ENABLED", "true") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_PATH", "/mnt/secondary") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_LOG_PATH", "/mnt/secondary/log") | ||
| } | ||
|
|
||
| func TestApplySecondaryStorageSettingsEnabledWithEmptyLogPath(t *testing.T) { | ||
| template := "SECONDARY_ENABLED=false\nSECONDARY_PATH=\nSECONDARY_LOG_PATH=/old/log\n" | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, true, "/mnt/secondary", "") | ||
|
|
||
| for _, needle := range []string{ | ||
| "SECONDARY_ENABLED=true", | ||
| "SECONDARY_PATH=/mnt/secondary", | ||
| "SECONDARY_LOG_PATH=", | ||
| } { | ||
| if !strings.Contains(got, needle) { | ||
| t.Fatalf("expected %q in template:\n%s", needle, got) | ||
| } | ||
| } | ||
| values, counts := parseMutatedEnvTemplate(t, got) | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_ENABLED", "true") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_PATH", "/mnt/secondary") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_LOG_PATH", "") | ||
| } | ||
|
|
||
| func TestApplySecondaryStorageSettingsDisabledClearsValues(t *testing.T) { | ||
| template := "SECONDARY_ENABLED=true\nSECONDARY_PATH=/mnt/old-secondary\nSECONDARY_LOG_PATH=/mnt/old-secondary/logs\n" | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, false, "/ignored", "/ignored/logs") | ||
|
|
||
| for _, needle := range []string{ | ||
| "SECONDARY_ENABLED=false", | ||
| "SECONDARY_PATH=", | ||
| "SECONDARY_LOG_PATH=", | ||
| } { | ||
| if !strings.Contains(got, needle) { | ||
| t.Fatalf("expected %q in template:\n%s", needle, got) | ||
| } | ||
| } | ||
| if strings.Contains(got, "/mnt/old-secondary") { | ||
| t.Fatalf("expected old secondary values to be cleared:\n%s", got) | ||
| } | ||
| values, counts := parseMutatedEnvTemplate(t, got) | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_ENABLED", "false") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_PATH", "") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_LOG_PATH", "") | ||
| } | ||
|
|
||
| func TestApplySecondaryStorageSettingsDisabledAppendsCanonicalState(t *testing.T) { | ||
| template := "BACKUP_ENABLED=true\n" | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, false, "", "") | ||
| values, counts := parseMutatedEnvTemplate(t, got) | ||
| assertMutatedEnvValue(t, values, counts, "BACKUP_ENABLED", "true") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_ENABLED", "false") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_PATH", "") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_LOG_PATH", "") | ||
| } | ||
|
|
||
| for _, needle := range []string{ | ||
| "BACKUP_ENABLED=true", | ||
| "SECONDARY_ENABLED=false", | ||
| "SECONDARY_PATH=", | ||
| "SECONDARY_LOG_PATH=", | ||
| } { | ||
| if !strings.Contains(got, needle) { | ||
| t.Fatalf("expected %q in template:\n%s", needle, got) | ||
| } | ||
| func TestApplySecondaryStorageSettingsQuotesUnsafePaths(t *testing.T) { | ||
| template := "SECONDARY_ENABLED=false\nSECONDARY_PATH=\nSECONDARY_LOG_PATH=\n" | ||
|
|
||
| got := ApplySecondaryStorageSettings(template, true, " /mnt/secondary #1 ", " /mnt/secondary/log dir ") | ||
| values, counts := parseMutatedEnvTemplate(t, got) | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_ENABLED", "true") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_PATH", "'/mnt/secondary #1'") | ||
| assertMutatedEnvValue(t, values, counts, "SECONDARY_LOG_PATH", "'/mnt/secondary/log dir'") | ||
|
|
||
| configPath := filepath.Join(t.TempDir(), "backup.env") | ||
| if err := os.WriteFile(configPath, []byte(got), 0o600); err != nil { | ||
| t.Fatalf("write config: %v", err) | ||
| } | ||
|
|
||
| raw, err := parseEnvFile(configPath) | ||
| if err != nil { | ||
| t.Fatalf("parseEnvFile() error = %v", err) | ||
| } | ||
| if gotPath := raw["SECONDARY_PATH"]; gotPath != "/mnt/secondary #1" { | ||
| t.Fatalf("SECONDARY_PATH = %q; want %q", gotPath, "/mnt/secondary #1") | ||
| } | ||
| if gotLogPath := raw["SECONDARY_LOG_PATH"]; gotLogPath != "/mnt/secondary/log dir" { | ||
| t.Fatalf("SECONDARY_LOG_PATH = %q; want %q", gotLogPath, "/mnt/secondary/log dir") | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent newline/CR injection in encoded env values.
"\n"/"\r"currently flow into single- or double-quoted output as literal line breaks, which can break the env file and inject unintended entries. Force escaped encoding for multiline input before quote-branching.💡 Proposed fix
func encodeEnvValue(value string) string { value = strings.TrimSpace(value) if value == "" { return "" } + + if strings.ContainsAny(value, "\r\n") { + return strconv.Quote(value) + } - if !strings.ContainsAny(value, "# \t\r\n\"'") { + if !strings.ContainsAny(value, "# \t\"'") { return value } if !strings.Contains(value, "'") { return "'" + value + "'" }🤖 Prompt for AI Agents