fix: harden operations and configuration recovery
This commit is contained in:
+13
-2
@@ -323,8 +323,19 @@ func (a *Adapter) disable() error {
|
||||
if metadata.OriginalScript != nil {
|
||||
restored = []byte(*metadata.OriginalScript)
|
||||
}
|
||||
if err := a.writeOwned(a.configuration.EnvironmentFile, restored); err != nil {
|
||||
return fmt.Errorf("restore Shell environment: %w", err)
|
||||
current, err := a.files.ReadFile(a.configuration.EnvironmentFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read managed Shell environment before restore: %w", err)
|
||||
}
|
||||
switch currentFingerprint := fingerprint(current); currentFingerprint {
|
||||
case fingerprint(restored):
|
||||
// A previous recovery completed the file write but not metadata cleanup.
|
||||
case metadata.Fingerprint:
|
||||
if err := a.writeOwned(a.configuration.EnvironmentFile, restored); err != nil {
|
||||
return fmt.Errorf("restore Shell environment: %w", err)
|
||||
}
|
||||
default:
|
||||
return errors.New("Shell environment changed after proxyctl applied it; refusing to overwrite current configuration or discard recovery metadata")
|
||||
}
|
||||
if err := a.files.Remove(a.configuration.RecoveryFile); err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
return fmt.Errorf("remove Shell recovery metadata after environment changed: %w", err)
|
||||
|
||||
@@ -296,6 +296,27 @@ func TestShellTargetContract(t *testing.T) {
|
||||
assertState(t, a, activeProfile(), target.Drifted)
|
||||
})
|
||||
|
||||
t.Run("drifted-environment-refuses-destructive-restore", func(t *testing.T) {
|
||||
a := newAdapter(t, shellName, nil)
|
||||
if result := a.SetDesired(context.Background(), true, activeProfile()); result.Err != nil {
|
||||
t.Fatal(result.Err)
|
||||
}
|
||||
changed := "export HTTP_PROXY='http://user-change.example:8080'\n"
|
||||
if err := os.WriteFile(a.EnvironmentPath(), []byte(changed), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result := a.SetDesired(context.Background(), false, nil)
|
||||
if result.Err == nil || result.Inspection.State != target.Drifted {
|
||||
t.Fatalf("unsafe restore = %#v", result)
|
||||
}
|
||||
if got := readFile(t, a.EnvironmentPath()); got != changed {
|
||||
t.Fatalf("drifted environment overwritten:\n%s", got)
|
||||
}
|
||||
if _, err := os.Stat(a.RecoveryPath()); err != nil {
|
||||
t.Fatalf("recovery metadata removed after refused restore: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("validation-and-redaction", func(t *testing.T) {
|
||||
fs := &failingFS{FileSystem: shell.OSFileSystem{}, failWrite: true}
|
||||
a := newAdapterWithFS(t, shellName, nil, fs)
|
||||
|
||||
Reference in New Issue
Block a user