fix: harden read-only target diagnostics

This commit is contained in:
proxyctl coordinator
2026-07-17 10:42:48 +08:00
parent 0fbaa71e37
commit a5360028ca
8 changed files with 385 additions and 33 deletions
+21 -1
View File
@@ -188,9 +188,12 @@ func (a *Adapter) DiagnosticChecks(_ context.Context, _ *profile.Profile) []targ
} else if proxies, _, err := childObject(config, "proxies"); err != nil {
schemaCheck.OK = false
schemaCheck.Evidence = profile.RedactText(err.Error())
} else if _, _, err := childObject(proxies, "default"); err != nil {
} else if defaults, _, err := childObject(proxies, "default"); err != nil {
schemaCheck.OK = false
schemaCheck.Evidence = profile.RedactText(err.Error())
} else if err := validateManagedProxyStrings(defaults); err != nil {
schemaCheck.OK = false
schemaCheck.Evidence = err.Error()
} else if _, _, err := a.readRecovery(); err != nil && !errors.Is(err, fs.ErrNotExist) {
schemaCheck.OK = false
schemaCheck.Evidence = profile.RedactText("Docker client recovery metadata is invalid or unreadable: " + err.Error())
@@ -305,6 +308,9 @@ func (a *Adapter) enable(active *profile.Profile) error {
if err != nil {
return err
}
if err := validateManagedProxyStrings(defaults); err != nil {
return err
}
if !managed {
metadata = recovery{ConfigPresent: configPresent, ProxiesPresent: proxiesPresent, DefaultPresent: defaultPresent, Original: make(map[string]priorValue)}
for _, key := range managedKeys {
@@ -463,6 +469,20 @@ func childObject(parent map[string]json.RawMessage, key string) (map[string]json
object, err := decodeObject(raw, "Docker client "+key+" setting")
return object, true, err
}
func validateManagedProxyStrings(defaults map[string]json.RawMessage) error {
for _, key := range managedKeys {
raw, present := defaults[key]
if !present {
continue
}
var value string
if err := json.Unmarshal(raw, &value); err != nil {
return fmt.Errorf("Docker client proxies.default.%s must be a JSON string", key)
}
}
return nil
}
func setChildObject(parent map[string]json.RawMessage, key string, child map[string]json.RawMessage) {
data, _ := json.Marshal(child)
parent[key] = data
@@ -67,6 +67,43 @@ func TestDiagnosticChecksCoverSchemaAndAuthorityWithoutMutation(t *testing.T) {
}
}
func TestDiagnosticsAndEnableRejectMalformedManagedProxyTypesWithoutMutation(t *testing.T) {
for _, document := range []string{
`{"proxies":[]}`,
`{"proxies":{"default":[]}}`,
`{"proxies":{"default":{"httpProxy":42}}}`,
`{"proxies":{"default":{"httpsProxy":false}}}`,
`{"proxies":{"default":{"allProxy":{}}}}`,
`{"proxies":{"default":{"noProxy":[]}}}`,
} {
t.Run(document, func(t *testing.T) {
files := &countingFS{FileSystem: dockerclient.OSFileSystem{}}
a := newAdapterWithFS(t, files)
writeConfig(t, a.ConfigPath(), document)
before, err := os.ReadFile(a.ConfigPath())
if err != nil {
t.Fatal(err)
}
checks := a.DiagnosticChecks(context.Background(), activeProfile())
if checks[1].OK {
t.Fatalf("malformed schema passed diagnostics: %#v", checks)
}
writesBefore := files.writes
result := a.SetDesired(context.Background(), true, activeProfile())
if result.Err == nil {
t.Fatalf("enable accepted malformed schema: %#v", result)
}
after, err := os.ReadFile(a.ConfigPath())
if err != nil {
t.Fatal(err)
}
if string(after) != string(before) || files.writes != writesBefore {
t.Fatalf("malformed config was modified: writes %d -> %d", writesBefore, files.writes)
}
})
}
}
func TestDockerClientAdapterRunsReusableTargetContract(t *testing.T) {
targettest.Run(t, func(t *testing.T) targettest.Fixture {
a := newAdapter(t, nil)