Skip to content

Commit

Permalink
fix: Use 0666 file mode for writing configuration and lock files (#47)
Browse files Browse the repository at this point in the history
Previously, files were written with the 0777 file mode. On most systems with 022 umask they would be written with the execution bits enabled, which is unnecessary for text files.

```console
❯ speakeasy quickstart
❯ ls -la OUTDIR/.speakeasy
total 40
drwxr-xr-x@  6 bflad  staff   192 Jul  5 14:25 .
drwxr-xr-x@ 17 bflad  staff   544 Jul  5 14:32 ..
-rwxr-xr-x@  1 bflad  staff  4801 Jul  5 14:25 gen.lock
-rwxr-xr-x@  1 bflad  staff   584 Jul  5 14:25 gen.yaml
-rw-r--r--@  1 bflad  staff  1062 Jul  5 14:25 workflow.lock
-rw-r--r--@  1 bflad  staff   301 Jul  5 14:26 workflow.yaml
```

This change sets the file mode to 0666 and adds verification unit testing for the final saved file permissions. If the testing ever becomes platform dependently flakey, the umask can be explicitly set in the unit testing.
  • Loading branch information
bflad authored Jul 9, 2024
1 parent dd43ce6 commit b3fa927
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 1 deletion.
2 changes: 1 addition & 1 deletion io.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ func write(path string, cfg any, o *options) ([]byte, error) {
writeFileFunc = o.FS.WriteFile
}

if err := writeFileFunc(path, data, os.ModePerm); err != nil {
if err := writeFileFunc(path, data, 0666); err != nil {
return nil, fmt.Errorf("could not write gen.yaml: %w", err)
}

Expand Down
118 changes: 118 additions & 0 deletions io_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"io/fs"
"os"
"path/filepath"
"testing"
Expand Down Expand Up @@ -630,6 +631,123 @@ func TestLoad_BackwardsCompatibility_Success(t *testing.T) {
assert.NoError(t, err)
}

func TestSaveConfig(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
cfg *Configuration
opts []Option
expected []byte
}{
"no-options": {
cfg: &Configuration{
ConfigVersion: "0.0.0",
},
expected: []byte("configVersion: 0.0.0\ngeneration: {}\n"),
},
"option-dontwrite": {
cfg: &Configuration{
ConfigVersion: Version,
},
opts: []Option{WithDontWrite()},
},
}

for name, testCase := range testCases {
name, testCase := name, testCase

t.Run(name, func(t *testing.T) {
t.Parallel()

tempDir := t.TempDir()
speakeasyPath := filepath.Join(tempDir, ".speakeasy")
configPath := filepath.Join(speakeasyPath, "gen.yaml")

err := os.Mkdir(speakeasyPath, 0755)
assert.NoError(t, err)

err = SaveConfig(tempDir, testCase.cfg, testCase.opts...)
assert.NoError(t, err)

fileInfo, err := os.Stat(configPath)

if len(testCase.expected) == 0 {
assert.ErrorIs(t, err, fs.ErrNotExist)

return
}

assert.NoError(t, err)
assert.Equal(t, false, fileInfo.IsDir())
assert.Equal(t, fs.FileMode(0644), fileInfo.Mode())

contents, err := os.ReadFile(configPath)
assert.NoError(t, err)
assert.Equal(t, testCase.expected, contents)
})
}
}

func TestSaveLockFile(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
lf *LockFile
opts []Option
expected []byte
}{
"no-options": {
lf: &LockFile{
LockVersion: "0.0.0",
},
expected: []byte(`lockVersion: 0.0.0
id: ""
management: {}
`),
},
"option-dontwrite": {
lf: &LockFile{
LockVersion: v2,
},
opts: []Option{WithDontWrite()},
},
}

for name, testCase := range testCases {
name, testCase := name, testCase

t.Run(name, func(t *testing.T) {
t.Parallel()

tempDir := t.TempDir()
speakeasyPath := filepath.Join(tempDir, ".speakeasy")
configPath := filepath.Join(speakeasyPath, "gen.lock")

err := os.Mkdir(speakeasyPath, 0755)
assert.NoError(t, err)

err = SaveLockFile(tempDir, testCase.lf, testCase.opts...)
assert.NoError(t, err)

fileInfo, err := os.Stat(configPath)

if len(testCase.expected) == 0 {
assert.ErrorIs(t, err, fs.ErrNotExist)

return
}

assert.NoError(t, err)
assert.Equal(t, false, fileInfo.IsDir())
assert.Equal(t, fs.FileMode(0644), fileInfo.Mode())

contents, err := os.ReadFile(configPath)
assert.NoError(t, err)
assert.Equal(t, testCase.expected, contents)
})
}
}

func createTempFile(dir string, fileName, contents string) error {
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return err
Expand Down

0 comments on commit b3fa927

Please sign in to comment.