fix(files): 编辑器保存和打开也逐跳核对 SHA-256,途中变了的内容不写盘也不打开
This commit is contained in:
18 files changed
+369
-57
No files matched your search
+8
-2
@@ -47,7 +47,7 @@ func cmdFiles(args []string, stdout, stderr io.Writer) int {
|
||||
to := fs.String("to", "", "rename only: the destination path")
|
||||
sourceURL := fs.String("source-url", "", "upload only: felis-api URL to fetch the bytes from")
|
||||
size := fs.Int64("size", -1, "upload only: the byte count the fetched file must have")
|
||||
sum := fs.String("sha256", "", "upload only: the SHA-256 (hex) the fetched file must have")
|
||||
sum := fs.String("sha256", "", "write and upload: the SHA-256 (hex) the content or the fetched file must have")
|
||||
overwrite := fs.Bool("overwrite", false, "upload and unzip: replace files already there")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return 2
|
||||
@@ -70,12 +70,18 @@ func cmdFiles(args []string, stdout, stderr io.Writer) int {
|
||||
// channel that must be a valid string.
|
||||
switch *op {
|
||||
case fileedit.OpWrite:
|
||||
// The content's SHA-256 comes with it, so bytes that changed on the way
|
||||
// to this Job are refused rather than written (Request.ContentSHA256).
|
||||
if *sum == "" {
|
||||
fmt.Fprintln(stderr, "felis files: a write needs --sha256")
|
||||
return 2
|
||||
}
|
||||
content, err := fileedit.ContentFromEnv(os.LookupEnv)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "felis files: %v\n", err)
|
||||
return 2
|
||||
}
|
||||
req.Content = content
|
||||
req.Content, req.ContentSHA256 = content, *sum
|
||||
case fileedit.OpUpload:
|
||||
token := os.Getenv(fileedit.UploadTokenEnv)
|
||||
if *sourceURL == "" || token == "" {
|
||||
|
||||
+33
-3
@@ -238,10 +238,11 @@ func TestCmdFilesUpload(t *testing.T) {
|
||||
|
||||
func TestCmdFilesWrite(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
args := []string{"--op", "write", "--path", "ops.json", "--worlds-root", root}
|
||||
content := []byte("[]\r\n")
|
||||
sum := sha256.Sum256(content)
|
||||
args := []string{"--op", "write", "--path", "ops.json", "--worlds-root", root, "--sha256", hex.EncodeToString(sum[:])}
|
||||
|
||||
t.Run("reassembles the content parts", func(t *testing.T) {
|
||||
content := []byte("[]\r\n")
|
||||
t.Setenv(fileedit.ContentPartsEnv, "1")
|
||||
t.Setenv(fileedit.ContentEnv+"_0", base64.StdEncoding.EncodeToString(content))
|
||||
var stdout, stderr bytes.Buffer
|
||||
@@ -261,13 +262,42 @@ func TestCmdFilesWrite(t *testing.T) {
|
||||
t.Setenv(fileedit.ContentPartsEnv, "2")
|
||||
t.Setenv(fileedit.ContentEnv+"_0", base64.StdEncoding.EncodeToString([]byte("x")))
|
||||
var stdout, stderr bytes.Buffer
|
||||
if code := cmdFiles([]string{"--op", "write", "--path", "new.txt", "--worlds-root", root}, &stdout, &stderr); code != 2 {
|
||||
if code := cmdFiles([]string{"--op", "write", "--path", "new.txt", "--worlds-root", root, "--sha256", hex.EncodeToString(sum[:])}, &stdout, &stderr); code != 2 {
|
||||
t.Fatalf("exit %d, want 2", code)
|
||||
}
|
||||
if _, err := os.Lstat(filepath.Join(root, "new.txt")); !os.IsNotExist(err) {
|
||||
t.Fatalf("an incomplete spec wrote a file: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
// Without the content's SHA-256 the Job could not tell bytes changed on the
|
||||
// way from the bytes felis-api sent.
|
||||
t.Run("a write without its SHA-256 exits 2 and writes nothing", func(t *testing.T) {
|
||||
t.Setenv(fileedit.ContentPartsEnv, "1")
|
||||
t.Setenv(fileedit.ContentEnv+"_0", base64.StdEncoding.EncodeToString(content))
|
||||
var stdout, stderr bytes.Buffer
|
||||
if code := cmdFiles([]string{"--op", "write", "--path", "new.txt", "--worlds-root", root}, &stdout, &stderr); code != 2 {
|
||||
t.Fatalf("exit %d, want 2", code)
|
||||
}
|
||||
if _, err := os.Lstat(filepath.Join(root, "new.txt")); !os.IsNotExist(err) {
|
||||
t.Fatalf("a write without its SHA-256 wrote a file: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("content that changed on the way is a result and writes nothing", func(t *testing.T) {
|
||||
t.Setenv(fileedit.ContentPartsEnv, "1")
|
||||
t.Setenv(fileedit.ContentEnv+"_0", base64.StdEncoding.EncodeToString([]byte("[]\n")))
|
||||
var stdout, stderr bytes.Buffer
|
||||
if code := cmdFiles([]string{"--op", "write", "--path", "new.txt", "--worlds-root", root, "--sha256", hex.EncodeToString(sum[:])}, &stdout, &stderr); code != 0 {
|
||||
t.Fatalf("exit %d, stderr %q", code, stderr.String())
|
||||
}
|
||||
if res := filesResult(t, stdout.String()); res.Code != fileedit.CodeDigestMismatch {
|
||||
t.Fatalf("result = %+v, want %s", res, fileedit.CodeDigestMismatch)
|
||||
}
|
||||
if _, err := os.Lstat(filepath.Join(root, "new.txt")); !os.IsNotExist(err) {
|
||||
t.Fatalf("changed content wrote a file: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// A caller-fault outcome is a successful run carrying a code, so felis-api can
|
||||
|
||||
Reference in new issue
Block a user