Skip to content

Commit 5059862

Browse files
authored
fix: Updating render --write file permissions (#6756)
1 parent 163e04a commit 5059862

3 files changed

Lines changed: 85 additions & 2 deletions

File tree

docs/src/data/changelog/v1.1.4/generated-file-permissions.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ Terragrunt created several files and directories that other users on the same ma
1010
- The CLI config Terragrunt writes for OpenTofu/Terraform when the [Provider Cache Server](/features/caching/provider-cache-server) is enabled, and the directory holding it.
1111
- The JSON plan files written to [`--json-out-dir`](/reference/cli/commands/run#json-out-dir), and that directory.
1212
- The directories holding the plan files written to [`--out-dir`](/reference/cli/commands/run#out-dir).
13+
- The config written by [`render --write`](/reference/cli/commands/render#write), which holds the resolved values of `inputs`, `locals`, and `dependency` outputs.
1314

1415
Terragrunt now creates those files as `0600` and those directories as `0700`.

internal/cli/commands/render/render.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"context"
77
"encoding/json"
88
"fmt"
9+
"io/fs"
910
"path/filepath"
1011

1112
"errors"
@@ -185,8 +186,13 @@ func writeRendered(l log.Logger, fsys vfs.FS, opts *Options, data []byte) error
185186

186187
l.Debugf("Rendering config %s to %s", opts.TerragruntConfigPath, outPath)
187188

188-
const ownerWriteGlobalReadPerms = 0644
189-
if err := vfs.WriteFile(fsys, outPath, data, ownerWriteGlobalReadPerms); err != nil {
189+
if err := fsys.Remove(outPath); err != nil && !errors.Is(err, fs.ErrNotExist) {
190+
return err
191+
}
192+
193+
const ownerReadWritePerms = 0o600
194+
195+
if err := vfs.WriteFile(fsys, outPath, data, ownerReadWritePerms); err != nil {
190196
return err
191197
}
192198

internal/cli/commands/render/render_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,82 @@ func TestRenderWriteWithoutOutputPath(t *testing.T) {
164164
}
165165
}
166166

167+
func TestRenderWriteFilePermissions(t *testing.T) {
168+
t.Parallel()
169+
170+
if helpers.IsWindows() {
171+
t.Skip("Windows does not enforce POSIX file permissions")
172+
}
173+
174+
testCases := []struct {
175+
name string
176+
format string
177+
}{
178+
{
179+
name: "hcl",
180+
format: render.FormatHCL,
181+
},
182+
{
183+
name: "json",
184+
format: render.FormatJSON,
185+
},
186+
}
187+
188+
for _, tc := range testCases {
189+
t.Run(tc.name, func(t *testing.T) {
190+
t.Parallel()
191+
192+
outputPath := filepath.Join(helpers.TmpDirWOSymlinks(t), "rendered")
193+
194+
assert.Equal(t, os.FileMode(0600), renderToFilePerm(t, tc.format, outputPath))
195+
})
196+
}
197+
}
198+
199+
func TestRenderWriteReplacesLooserPermissions(t *testing.T) {
200+
t.Parallel()
201+
202+
if helpers.IsWindows() {
203+
t.Skip("Windows does not enforce POSIX file permissions")
204+
}
205+
206+
outputPath := filepath.Join(helpers.TmpDirWOSymlinks(t), "rendered")
207+
require.NoError(t, os.WriteFile(outputPath, []byte("stale"), 0644))
208+
209+
assert.Equal(t, os.FileMode(0600), renderToFilePerm(t, render.FormatJSON, outputPath))
210+
211+
content, err := os.ReadFile(outputPath)
212+
require.NoError(t, err)
213+
214+
var result map[string]any
215+
216+
require.NoError(t, json.Unmarshal(content, &result))
217+
validateRenderedJSON(t, result, false)
218+
}
219+
220+
// renderToFilePerm renders a config and returns the permissions of the file it writes.
221+
func renderToFilePerm(t *testing.T, format, outputPath string) os.FileMode {
222+
t.Helper()
223+
224+
opts, _ := setupTest(t, testTerragruntConfigFixture)
225+
opts.Format = format
226+
opts.Write = true
227+
opts.OutputPath = outputPath
228+
229+
err := render.Run(
230+
t.Context(),
231+
logger.CreateLogger(),
232+
venvtest.NewOSWithEmptyEnv().WithWriter(io.Discard),
233+
opts,
234+
)
235+
require.NoError(t, err)
236+
237+
info, err := os.Stat(outputPath)
238+
require.NoError(t, err)
239+
240+
return info.Mode().Perm()
241+
}
242+
167243
func TestRenderJSON_InvalidFormat(t *testing.T) {
168244
t.Parallel()
169245

0 commit comments

Comments
 (0)