Record file mode in the manifest, 0000 unless asked (closes #161)
check / check (push) Failing after 8s
check / check (push) Failing after 8s
MFFilePath gains mode (field 304): a file's permission bits, 0777 at most, or 0000, meaning none recorded. gen and freshen record real modes only with --include-permissions (ScannerOptions.IncludePermissions); the builder keeps only mode.Perm(), so setuid, setgid and sticky are never written. list -l and export show the mode in octal. check reports MODE_MISMATCH for a recorded mode other than 0000 the file lacks. fetch refuses a manifest with a mode above 0777 before requesting any file, sets each recorded mode on the files it writes, and downloads again a present file whose mode differs. The decoding-cost bound counts a file entry at 176 bytes, up from 160. Model: opus-5-5
This commit is contained in:
@@ -3,6 +3,7 @@ package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -374,6 +375,98 @@ func TestGenerateAndCheckCommand(t *testing.T) {
|
||||
assert.Equal(t, 0, exitCode, "check failed: %s", testStderr(t, opts))
|
||||
}
|
||||
|
||||
// TestGenerateRecordsModeOnlyWhenAsked runs gen with and without
|
||||
// --include-permissions: without it every mode is recorded as 0000, with
|
||||
// it each file's permission bits. list -l and export show the recorded
|
||||
// modes.
|
||||
func TestGenerateRecordsModeOnlyWhenAsked(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll(testDir, 0o755))
|
||||
writeTestFile(t, fs, "/testdir/notes.txt", "hello world")
|
||||
writeTestFile(t, fs, "/testdir/run.sh", "#!/bin/sh\n")
|
||||
require.NoError(t, fs.Chmod("/testdir/run.sh", 0o755))
|
||||
|
||||
for _, tc := range []struct {
|
||||
flags []string
|
||||
want map[string]string // recorded mode by path
|
||||
}{
|
||||
{nil, map[string]string{"notes.txt": "0000", "run.sh": "0000"}},
|
||||
{
|
||||
[]string{"--" + flagIncludePermissions},
|
||||
map[string]string{"notes.txt": "0644", "run.sh": "0755"},
|
||||
},
|
||||
} {
|
||||
opts := testOpts(slices.Concat(
|
||||
[]string{testApp, cmdGenerate, "-q", "-f", "-o", testOutput}, tc.flags,
|
||||
[]string{testDir},
|
||||
), fs)
|
||||
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
|
||||
|
||||
opts = testOpts([]string{testApp, cmdList, "-l", testOutput}, fs)
|
||||
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
|
||||
|
||||
listed := map[string]string{}
|
||||
out := strings.TrimSuffix(testStdout(t, opts), "\n")
|
||||
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
fields := strings.Split(line, "\t") // mode, size, mtime, path
|
||||
require.Len(t, fields, 4, line)
|
||||
listed[fields[3]] = fields[0]
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.want, listed, "list -l %v", tc.flags)
|
||||
|
||||
opts = testOpts([]string{testApp, cmdExport, testOutput}, fs)
|
||||
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
|
||||
|
||||
var entries []ExportEntry
|
||||
require.NoError(t, json.Unmarshal([]byte(testStdout(t, opts)), &entries))
|
||||
|
||||
exported := map[string]string{}
|
||||
for _, e := range entries {
|
||||
exported[e.Path] = e.Mode
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.want, exported, "export %v", tc.flags)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCheckComparesRecordedMode changes a file's mode after gen: check
|
||||
// must fail on it when gen recorded the file's mode, and pass when gen
|
||||
// recorded 0000.
|
||||
func TestCheckComparesRecordedMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
flags []string
|
||||
exitCode int
|
||||
}{
|
||||
{nil, 0},
|
||||
{[]string{"--" + flagIncludePermissions}, 1},
|
||||
} {
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll(testDir, 0o755))
|
||||
writeTestFile(t, fs, testFile1, "hello world")
|
||||
|
||||
opts := testOpts(slices.Concat(
|
||||
[]string{testApp, cmdGenerate, "-q", "-o", testMF}, tc.flags,
|
||||
[]string{testDir},
|
||||
), fs)
|
||||
require.Equal(t, 0, runCLI(opts), "stderr: %s", testStderr(t, opts))
|
||||
|
||||
require.NoError(t, fs.Chmod(testFile1, 0o600))
|
||||
|
||||
opts = testOpts([]string{testApp, cmdCheck, testFlagBase, testDir, testMF}, fs)
|
||||
assert.Equal(t, tc.exitCode, runCLI(opts), "%v: %s", tc.flags, testStderr(t, opts))
|
||||
|
||||
if tc.exitCode != 0 {
|
||||
assert.Contains(t, testStderr(t, opts), "MODE_MISMATCH: file1.txt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sharedWriter appends to a buffer shared with other sharedWriters, so
|
||||
// output written to stdout and stderr is kept in the order it was written.
|
||||
// Each write first waits for delay.
|
||||
|
||||
Reference in New Issue
Block a user