Skip to content

Commit bc1ad12

Browse files
authored
Merge pull request #1 from k5s7s/fix-write
fix: tmp file read after write
2 parents ff8bcdd + a6f1092 commit bc1ad12

3 files changed

Lines changed: 65 additions & 75 deletions

File tree

ioutils.go

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,69 @@ import (
44
"fmt"
55
"io"
66
"os"
7+
"path"
78
)
89

910
type TmpFile struct {
10-
file *os.File
11+
path string
1112
}
1213

13-
func NewTmpFile() (*TmpFile, error) {
14-
file, err := os.CreateTemp(os.TempDir(), "k8s-secret-editor-")
14+
func NewTmpFile(suffix string) (*TmpFile, error) {
15+
name := fmt.Sprintf("k8s-secret-editor-%s", suffix)
16+
p := path.Join(os.TempDir(), name)
17+
f, err := os.Create(p)
1518
if err != nil {
16-
return nil, err
19+
return nil, fmt.Errorf("error creating temp file: %w", err)
20+
}
21+
if err := f.Close(); err != nil {
22+
_ = os.Remove(f.Name())
23+
return nil, fmt.Errorf("error closing temp file: %w", err)
1724
}
18-
1925
// Set restrictive permissions to protect sensitive secret data
20-
if err := os.Chmod(file.Name(), 0600); err != nil {
21-
_ = file.Close()
22-
_ = os.Remove(file.Name())
26+
if err := os.Chmod(p, 0o600); err != nil {
27+
_ = os.Remove(p)
2328
return nil, fmt.Errorf("error setting file permissions: %w", err)
2429
}
2530

26-
return &TmpFile{file: file}, nil
31+
return &TmpFile{path: p}, nil
2732
}
2833

2934
func (t *TmpFile) Write(data []byte) error {
30-
if _, err := t.file.Write(data); err != nil {
35+
f, err := os.OpenFile(t.path, os.O_WRONLY|os.O_TRUNC, 0o600)
36+
if err != nil {
37+
return fmt.Errorf("error opening temp file for writing: %w", err)
38+
}
39+
if _, err := f.Write(data); err != nil {
3140
return fmt.Errorf("error writing to temp file: %w", err)
3241
}
42+
if err := f.Sync(); err != nil {
43+
return fmt.Errorf("error syncing temp file: %w", err)
44+
}
3345
return nil
3446
}
3547

3648
func (t *TmpFile) Read() ([]byte, error) {
37-
// Move the file pointer back to the beginning before reading
38-
if _, err := t.file.Seek(0, io.SeekStart); err != nil {
39-
return nil, fmt.Errorf("error seeking to beginning of temp file: %w", err)
49+
f, err := os.Open(t.path)
50+
if err != nil {
51+
return nil, fmt.Errorf("error opening temp file for reading: %w", err)
4052
}
4153

42-
data, err := io.ReadAll(t.file)
54+
data, err := io.ReadAll(f)
4355
if err != nil {
4456
return nil, fmt.Errorf("error reading from temp file: %w", err)
4557
}
4658
return data, nil
4759
}
4860

4961
func (t *TmpFile) OpenEditor(editor interface{ Open(filePath string) error }) error {
50-
return editor.Open(t.file.Name())
62+
if err := editor.Open(t.path); err != nil {
63+
return fmt.Errorf("error opening editor: %w", err)
64+
}
65+
return nil
5166
}
5267

5368
func (t *TmpFile) Close() error {
54-
name := t.file.Name()
55-
if err := t.file.Close(); err != nil {
56-
return err
57-
}
58-
// Remove temp file after closing to avoid leaking secrets
59-
if err := os.Remove(name); err != nil {
69+
if err := os.Remove(t.path); err != nil {
6070
return fmt.Errorf("error removing temp file: %w", err)
6171
}
6272
return nil

ioutils_test.go

Lines changed: 33 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@ import (
66
)
77

88
func TestNewTmpFile(t *testing.T) {
9-
tmp, err := NewTmpFile()
10-
if err != nil {
11-
t.Fatalf("failed to create temp file: %v", err)
12-
}
13-
defer tmp.file.Close()
14-
defer os.Remove(tmp.file.Name())
9+
tmp := newTestTmpFile(t)
1510

1611
// Verify file exists
17-
fi, err := os.Stat(tmp.file.Name())
12+
fi, err := os.Stat(tmp.path)
1813
if err != nil {
1914
t.Fatalf("failed to stat temp file: %v", err)
2015
}
@@ -26,14 +21,9 @@ func TestNewTmpFile(t *testing.T) {
2621
}
2722

2823
func TestTmpFilePermissions(t *testing.T) {
29-
tmp, err := NewTmpFile()
30-
if err != nil {
31-
t.Fatalf("failed to create temp file: %v", err)
32-
}
33-
defer tmp.file.Close()
34-
defer os.Remove(tmp.file.Name())
24+
tmp := newTestTmpFile(t)
3525

36-
fi, err := os.Stat(tmp.file.Name())
26+
fi, err := os.Stat(tmp.path)
3727
if err != nil {
3828
t.Fatalf("failed to stat temp file: %v", err)
3929
}
@@ -47,28 +37,20 @@ func TestTmpFilePermissions(t *testing.T) {
4737
}
4838

4939
func TestTmpFileWrite(t *testing.T) {
50-
tmp, err := NewTmpFile()
51-
if err != nil {
52-
t.Fatalf("failed to create temp file: %v", err)
53-
}
54-
defer tmp.Close()
40+
tmp := newTestTmpFile(t)
5541

5642
testData := []byte("test data for secret")
57-
err = tmp.Write(testData)
43+
err := tmp.Write(testData)
5844
if err != nil {
5945
t.Fatalf("failed to write to temp file: %v", err)
6046
}
6147
}
6248

6349
func TestTmpFileRead(t *testing.T) {
64-
tmp, err := NewTmpFile()
65-
if err != nil {
66-
t.Fatalf("failed to create temp file: %v", err)
67-
}
68-
defer tmp.Close()
50+
tmp := newTestTmpFile(t)
6951

7052
testData := []byte("test secret data")
71-
err = tmp.Write(testData)
53+
err := tmp.Write(testData)
7254
if err != nil {
7355
t.Fatalf("failed to write to temp file: %v", err)
7456
}
@@ -85,16 +67,12 @@ func TestTmpFileRead(t *testing.T) {
8567
}
8668

8769
func TestTmpFileReadAfterMultipleWrites(t *testing.T) {
88-
tmp, err := NewTmpFile()
89-
if err != nil {
90-
t.Fatalf("failed to create temp file: %v", err)
91-
}
92-
defer tmp.Close()
70+
tmp := newTestTmpFile(t)
9371

9472
// Write multiple times
9573
data1 := []byte("first")
9674
data2 := []byte("second")
97-
err = tmp.Write(data1)
75+
err := tmp.Write(data1)
9876
if err != nil {
9977
t.Fatalf("failed to write first data: %v", err)
10078
}
@@ -104,28 +82,22 @@ func TestTmpFileReadAfterMultipleWrites(t *testing.T) {
10482
t.Fatalf("failed to write second data: %v", err)
10583
}
10684

107-
// Read should return both
10885
readData, err := tmp.Read()
10986
if err != nil {
11087
t.Fatalf("failed to read from temp file: %v", err)
11188
}
11289

113-
expected := "firstsecond"
90+
expected := "second"
11491
if string(readData) != expected {
11592
t.Errorf("expected data %s, got %s", expected, string(readData))
11693
}
11794
}
11895

11996
func TestTmpFileClose(t *testing.T) {
120-
tmp, err := NewTmpFile()
121-
if err != nil {
122-
t.Fatalf("failed to create temp file: %v", err)
123-
}
124-
125-
filePath := tmp.file.Name()
97+
tmp := newTestTmpFile(t)
12698

12799
// Write some data
128-
err = tmp.Write([]byte("test"))
100+
err := tmp.Write([]byte("test"))
129101
if err != nil {
130102
t.Fatalf("failed to write to temp file: %v", err)
131103
}
@@ -137,20 +109,17 @@ func TestTmpFileClose(t *testing.T) {
137109
}
138110

139111
// Verify file is deleted
140-
_, err = os.Stat(filePath)
112+
_, err = os.Stat(tmp.path)
141113
if !os.IsNotExist(err) {
142-
t.Errorf("temp file was not deleted: %s", filePath)
114+
t.Errorf("temp file was not deleted: %s", tmp.path)
143115
}
144116
}
145117

146118
func TestTmpFileCloseMultipleTimes(t *testing.T) {
147-
tmp, err := NewTmpFile()
148-
if err != nil {
149-
t.Fatalf("failed to create temp file: %v", err)
150-
}
119+
tmp := newTestTmpFile(t)
151120

152121
// First close
153-
err = tmp.Close()
122+
err := tmp.Close()
154123
if err != nil {
155124
t.Fatalf("first close failed: %v", err)
156125
}
@@ -163,11 +132,7 @@ func TestTmpFileCloseMultipleTimes(t *testing.T) {
163132
}
164133

165134
func TestTmpFileOpenEditor(t *testing.T) {
166-
tmp, err := NewTmpFile()
167-
if err != nil {
168-
t.Fatalf("failed to create temp file: %v", err)
169-
}
170-
defer tmp.Close()
135+
tmp := newTestTmpFile(t)
171136

172137
editorPath := "/bin/sh"
173138
if _, err := os.Stat(editorPath); os.IsNotExist(err) {
@@ -185,3 +150,18 @@ func TestTmpFileOpenEditor(t *testing.T) {
185150
t.Logf("OpenEditor returned error: %v (expected for sh with no input)", err)
186151
}
187152
}
153+
154+
func newTestTmpFile(t *testing.T) *TmpFile {
155+
t.Helper()
156+
157+
tmp, err := NewTmpFile("test")
158+
if err != nil {
159+
t.Fatalf("failed to create temp file: %v", err)
160+
}
161+
t.Cleanup(func() {
162+
if err := tmp.Close(); err != nil {
163+
t.Logf("failed to clean up temp file: %v", err)
164+
}
165+
})
166+
return tmp
167+
}

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func main() { //nolint:gocyclo
7272
fatalf("Key '%s' not found in secret '%s' in namespace '%s'", selectedKey, selectedSecret, selectedNamespace)
7373
}
7474

75-
tmpFile, err := NewTmpFile()
75+
tmpFile, err := NewTmpFile(selectedKey)
7676
if err != nil {
7777
fatalf("Error creating temp file: %v", err)
7878
}

0 commit comments

Comments
 (0)