From f8a2fe5ee1957888144ce104e99ffa505188a5c0 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Thu, 6 Feb 2025 10:51:02 +0530 Subject: [PATCH 01/22] fix::> Added checks for UnixFS + added force flag Signed-off-by: Abhinav Prakash --- core/commands/files.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/core/commands/files.go b/core/commands/files.go index a9c876d78fd..5732914558b 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -440,6 +440,7 @@ being GC'ed. }, Options: []cmds.Option{ cmds.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."), + cmds.BoolOption(forceOptionName, "f", "Force copy even if the node is not a valid UnixFS node."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { mkParents, _ := req.Options[filesParentsOptionName].(bool) @@ -480,6 +481,22 @@ being GC'ed. return fmt.Errorf("cp: cannot get node from path %s: %s", src, err) } + force, _ := req.Options[forceOptionName].(bool) + if !force { + // Check if it's a raw node + if _, ok := node.(*dag.RawNode); !ok { + // If not raw, must be ProtoNode with valid UnixFS data + if protoNode, ok := node.(*dag.ProtoNode); ok { + _, err := ft.FSNodeFromBytes(protoNode.Data()) + if err != nil { + return fmt.Errorf("cp: source must be a UnixFS node or raw data: %s", err) + } + } else { + return fmt.Errorf("cp: source must be a UnixFS node or raw data") + } + } + } + if mkParents { err := ensureContainingDirectoryExists(nd.FilesRoot, dst, prefix) if err != nil { From 9db46b1cafd111278fae67c70fd88da19620d35e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 5 Feb 2025 22:26:33 +0100 Subject: [PATCH 02/22] docs: update min requirements (#10687) https://docs.ipfs.tech/install/command-line/#system-requirements states 6 GiB, updating readme to match that --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 40abd8fe675..2d3c661e9db 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,10 @@ Please follow [`SECURITY.md`](SECURITY.md). ### Minimal System Requirements -IPFS can run on most Linux, macOS, and Windows systems. We recommend running it on a machine with at least 4 GB of RAM and 2 CPU cores (kubo is highly parallel). On systems with less memory, it may not be completely stable, and you run on your own risk. +IPFS can run on most Linux, macOS, and Windows systems. We recommend running it on a machine with at least 6 GB of RAM and 2 CPU cores (ideally more, Kubo is highly parallel). + +> [!CAUTION] +> On systems with less memory, it may not be completely stable, and you run on your own risk. ## Install From 3031cf379a683d66aee0f2704d0d320ac84dd070 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 6 Feb 2025 00:52:16 +0100 Subject: [PATCH 03/22] docs(release): update RELEASE_CHECKLIST.md after v0.33.1 (#10697) --- docs/RELEASE_CHECKLIST.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/RELEASE_CHECKLIST.md b/docs/RELEASE_CHECKLIST.md index 4e9000ba305..423e9663271 100644 --- a/docs/RELEASE_CHECKLIST.md +++ b/docs/RELEASE_CHECKLIST.md @@ -35,7 +35,7 @@ This section covers tasks to be done during each release. - use `master` as base if `Z == 0` - use `release` as base if `Z > 0` - [ ] ![](https://img.shields.io/badge/only-RC1-blue?style=flat-square) update the `CurrentVersionNumber` in [version.go](version.go) in the `master` branch to `vX.Y+1.0-dev` ([example](https://github.com/ipfs/kubo/pull/9305)) - - [ ] update the `CurrentVersionNumber` in [version.go](version.go) in the `release-vX.Y` branch to `vX.Y.Z(-rcN)` ([example](https://github.com/ipfs/kubo/pull/9394)) + - [ ] update the `CurrentVersionNumber` in [version.go](version.go) in the `release-vX.Y.Z` branch to `vX.Y.Z(-rcN)` ([example](https://github.com/ipfs/kubo/pull/9394)) - [ ] create a draft PR from `release-vX.Y.Z` to `release` ([example](https://github.com/ipfs/kubo/pull/9306)) - [ ] Cherry-pick commits from `master` to the `release-vX.Y.Z` using `git cherry-pick -x ` ([example](https://github.com/ipfs/kubo/pull/10636/commits/033de22e3bc6191dbb024ad6472f5b96b34e3ccf)) - **NOTE:** cherry-picking with `-x` is important From e922ef0cc72b3206d200e7519c5e5e4d705100ba Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sat, 15 Feb 2025 22:55:09 +0530 Subject: [PATCH 04/22] fix::> Removed confusing shorthand Signed-off-by: Abhinav Prakash --- core/commands/files.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/files.go b/core/commands/files.go index 5732914558b..f51c31f71c2 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -440,7 +440,7 @@ being GC'ed. }, Options: []cmds.Option{ cmds.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."), - cmds.BoolOption(forceOptionName, "f", "Force copy even if the node is not a valid UnixFS node."), + cmds.BoolOption(forceOptionName, "force", "Force copy even if the node is not a valid UnixFS node."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { mkParents, _ := req.Options[filesParentsOptionName].(bool) From 329730846f2cfded9be1a3a23a66c57bde5048f1 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sat, 15 Feb 2025 23:03:11 +0530 Subject: [PATCH 05/22] fix::> impl changes Signed-off-by: Abhinav Prakash --- core/commands/files.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index f51c31f71c2..4c5e07fb75e 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -485,15 +485,12 @@ being GC'ed. if !force { // Check if it's a raw node if _, ok := node.(*dag.RawNode); !ok { - // If not raw, must be ProtoNode with valid UnixFS data - if protoNode, ok := node.(*dag.ProtoNode); ok { - _, err := ft.FSNodeFromBytes(protoNode.Data()) - if err != nil { - return fmt.Errorf("cp: source must be a UnixFS node or raw data: %s", err) - } - } else { + if _, ok := node.(*dag.ProtoNode); !ok { return fmt.Errorf("cp: source must be a UnixFS node or raw data") } + if _, err = ft.FSNodeFromBytes(node.(*dag.ProtoNode).Data()); err != nil { + return fmt.Errorf("cp: source must be a UnixFS node or raw data: %s", err) + } } } From 4a8bb629928b13f690c00e859eb26f8047d82640 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sat, 15 Feb 2025 23:20:24 +0530 Subject: [PATCH 06/22] fix::> Basic Setup of Tests Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 core/commands/file_test.go diff --git a/core/commands/file_test.go b/core/commands/file_test.go new file mode 100644 index 00000000000..7ad9f2b2800 --- /dev/null +++ b/core/commands/file_test.go @@ -0,0 +1,39 @@ +package commands + +import ( + "context" + "testing" + + cmds "github.com/ipfs/go-ipfs-cmds" + "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/stretchr/testify/require" +) + +func TestCopyCBORtoMFS(t *testing.T) { + ctx := context.Background() + + cborCid := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" + + req := &cmds.Request{ + Context: ctx, + Arguments: []string{ + "/ipfs/" + cborCid, + "/test-cbor", + }, + Options: map[string]interface{}{ + filesFlushOptionName: true, + }, + } + + // mock response emitter + res := new(cmds.EmptyResponse) + + // mock environment creation + env := &cmdenv.Environment{} + + err := filesCpCmd.Run(req, res, env) + + require.Error(t, err, "copying dag-cbor should fail") + require.Contains(t, err.Error(), "dag-cbor not supported", "must be a UnixFS node or raw data", + "error should indicate invalid node type") +} From a687b2b329ffa9291ee611003748c67807b8da5c Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sat, 15 Feb 2025 23:36:14 +0530 Subject: [PATCH 07/22] fix::> test 1 Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index 7ad9f2b2800..f992b79bc17 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -5,10 +5,29 @@ import ( "testing" cmds "github.com/ipfs/go-ipfs-cmds" - "github.com/ipfs/kubo/core/commands/cmdenv" + "github.com/ipfs/kubo/core" "github.com/stretchr/testify/require" ) +type testenv struct { + ctx context.Context + node *core.IpfsNode +} + +func createTestEnvironment(t *testing.T) cmds.Environment { + // Create a new IPFS node for testing + node, err := core.NewNode(context.Background(), &core.BuildCfg{ + Online: false, + Repo: nil, + }) + require.NoError(t, err) + + return &testenv{ + ctx: context.Background(), + node: node, + } +} + func TestCopyCBORtoMFS(t *testing.T) { ctx := context.Background() @@ -26,12 +45,13 @@ func TestCopyCBORtoMFS(t *testing.T) { } // mock response emitter - res := new(cmds.EmptyResponse) + res, err := cmds.NewWriterResponseEmitter(nil, nil) + require.NoError(t, err, "creating response emitter should not fail") // mock environment creation - env := &cmdenv.Environment{} + env := createTestEnvironment(t) - err := filesCpCmd.Run(req, res, env) + err = filesCpCmd.Run(req, res, env) require.Error(t, err, "copying dag-cbor should fail") require.Contains(t, err.Error(), "dag-cbor not supported", "must be a UnixFS node or raw data", From de94ec6b637ce059c2cc2d7a45fb4df10520e5a7 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sun, 16 Feb 2025 00:48:06 +0530 Subject: [PATCH 08/22] fix::> test passing Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 43 ++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index f992b79bc17..6e09082f2a7 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -1,6 +1,7 @@ package commands import ( + "bytes" "context" "testing" @@ -14,27 +15,51 @@ type testenv struct { node *core.IpfsNode } -func createTestEnvironment(t *testing.T) cmds.Environment { +type writeCloser struct { + *bytes.Buffer +} + +func (w writeCloser) Close() error { return nil } + +// func createTestEnvironment(t *testing.T) cmds.Environment { +// // Create a new IPFS node for testing +// ctx := context.Background() + +// node, err := core.NewNode(ctx, &core.BuildCfg{ +// Online: false, +// Repo: nil, +// }) +// require.NoError(t, err) + +// return &testenv{ +// ctx: ctx, +// node: node, +// } +// } + +func createTestEnv(t *testing.T) cmds.Environment { // Create a new IPFS node for testing - node, err := core.NewNode(context.Background(), &core.BuildCfg{ + ctx := context.Background() + node, err := core.NewNode(ctx, &core.BuildCfg{ Online: false, Repo: nil, }) require.NoError(t, err) return &testenv{ - ctx: context.Background(), + ctx: ctx, node: node, } } func TestCopyCBORtoMFS(t *testing.T) { - ctx := context.Background() + // mock environment creation + env := createTestEnv(t) cborCid := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" req := &cmds.Request{ - Context: ctx, + Context: context.Background(), Arguments: []string{ "/ipfs/" + cborCid, "/test-cbor", @@ -45,15 +70,11 @@ func TestCopyCBORtoMFS(t *testing.T) { } // mock response emitter - res, err := cmds.NewWriterResponseEmitter(nil, nil) + w := writeCloser{new(bytes.Buffer)} + res, err := cmds.NewWriterResponseEmitter(w, req) require.NoError(t, err, "creating response emitter should not fail") - // mock environment creation - env := createTestEnvironment(t) - err = filesCpCmd.Run(req, res, env) require.Error(t, err, "copying dag-cbor should fail") - require.Contains(t, err.Error(), "dag-cbor not supported", "must be a UnixFS node or raw data", - "error should indicate invalid node type") } From 58e4c90b4cd27be440eeae3dccfa13a28b2a8ebb Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sun, 16 Feb 2025 08:33:21 +0530 Subject: [PATCH 09/22] fix::> formatting Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index 6e09082f2a7..ef620c8dadc 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -3,6 +3,7 @@ package commands import ( "bytes" "context" + "fmt" "testing" cmds "github.com/ipfs/go-ipfs-cmds" @@ -21,22 +22,6 @@ type writeCloser struct { func (w writeCloser) Close() error { return nil } -// func createTestEnvironment(t *testing.T) cmds.Environment { -// // Create a new IPFS node for testing -// ctx := context.Background() - -// node, err := core.NewNode(ctx, &core.BuildCfg{ -// Online: false, -// Repo: nil, -// }) -// require.NoError(t, err) - -// return &testenv{ -// ctx: ctx, -// node: node, -// } -// } - func createTestEnv(t *testing.T) cmds.Environment { // Create a new IPFS node for testing ctx := context.Background() @@ -75,6 +60,12 @@ func TestCopyCBORtoMFS(t *testing.T) { require.NoError(t, err, "creating response emitter should not fail") err = filesCpCmd.Run(req, res, env) + if err != nil { + t.Logf("Error during file copy: %v", err) // Print actual error + fmt.Println("Error:", err) // Alternative direct print + } require.Error(t, err, "copying dag-cbor should fail") + // require.Contains(t, err.Error(), "must be a UnixFS node or raw data") + // return fmt.Errorf("cp: source must be a UnixFS node or raw data") } From 8e6796f2a0ee8dba4d8a19d1e2e0923be534e062 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sun, 16 Feb 2025 19:03:41 +0530 Subject: [PATCH 10/22] fix::> Proper test env ready Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 143 +++++++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 44 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index ef620c8dadc..8552192bb86 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -1,71 +1,126 @@ package commands import ( - "bytes" "context" - "fmt" + "io" + "strings" "testing" cmds "github.com/ipfs/go-ipfs-cmds" - "github.com/ipfs/kubo/core" - "github.com/stretchr/testify/require" + coremock "github.com/ipfs/kubo/core/mock" ) -type testenv struct { - ctx context.Context - node *core.IpfsNode -} +// type testenv struct { +// ctx context.Context +// node *core.IpfsNode +// reqchan chan<- string +// } -type writeCloser struct { - *bytes.Buffer -} +// type writeCloser struct { +// *bytes.Buffer +// } -func (w writeCloser) Close() error { return nil } +// func (w writeCloser) Close() error { return nil } -func createTestEnv(t *testing.T) cmds.Environment { - // Create a new IPFS node for testing - ctx := context.Background() - node, err := core.NewNode(ctx, &core.BuildCfg{ - Online: false, - Repo: nil, - }) - require.NoError(t, err) +// func createTestEnv(t *testing.T, ctx context.Context) cmds.Environment { +// ds := sync.MutexWrap(datastore.NewMapDatastore()) +// node, err := core.NewNode(ctx, &core.BuildCfg{ +// Online: false, +// Repo: &repo.Mock{ +// C: config.Config{ +// Identity: config.Identity{ +// PeerID: "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe", +// }, +// }, +// D: ds, +// }, +// }) +// require.NoError(t, err) - return &testenv{ - ctx: ctx, - node: node, - } -} +// return &testenv{ +// ctx: ctx, +// node: node, +// } + +// } + +// func TestCopyCBORtoMFS(t *testing.T) { +// // mock environment creation +// ctx := context.Background() +// env := createTestEnv(t, ctx) + +// cborCid := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" + +// req := &cmds.Request{ +// Context: ctx, +// Arguments: []string{ +// "/ipfs/" + cborCid, +// "/test-cbor", +// }, +// Options: map[string]interface{}{ +// filesFlushOptionName: true, +// }, +// } + +// // mock response emitter +// w := writeCloser{new(bytes.Buffer)} +// require.NoError(t, err, "creating response emitter should not fail") + +// err = filesCpCmd.Run(req, res, env) +// if err != nil { +// t.Logf("Error during file copy: %v", err) // Print actual error +// fmt.Println("Error:", err) // Alternative direct print +// } -func TestCopyCBORtoMFS(t *testing.T) { - // mock environment creation - env := createTestEnv(t) +// require.Error(t, err, "copying dag-cbor should fail") +// require.Contains(t, err.Error(), "must be a UnixFS node or raw data") +// // return fmt.Errorf("cp: source must be a UnixFS node or raw data") +// } - cborCid := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" +func TestFilesCp_DagCborNodeFails(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + // _, err := coremock.NewMockNode() + // if err != nil { + // t.Fatal(err) + // } + + cmdCtx, err := coremock.MockCmdsCtx() + if err != nil { + t.Fatal(err) + } + + // env := cmdenv.Environment{ + // Node: node, + // CoreAPI: coreapi.NewCoreAPI(node), + // } + + cborCID := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" req := &cmds.Request{ - Context: context.Background(), + Context: ctx, Arguments: []string{ - "/ipfs/" + cborCid, - "/test-cbor", + "/ipfs/" + cborCID, + "/test-destination", }, Options: map[string]interface{}{ - filesFlushOptionName: true, + "force": false, }, } - // mock response emitter - w := writeCloser{new(bytes.Buffer)} - res, err := cmds.NewWriterResponseEmitter(w, req) - require.NoError(t, err, "creating response emitter should not fail") - - err = filesCpCmd.Run(req, res, env) + _, pw := io.Pipe() + res, err := cmds.NewWriterResponseEmitter(pw, req) if err != nil { - t.Logf("Error during file copy: %v", err) // Print actual error - fmt.Println("Error:", err) // Alternative direct print + t.Fatal(err) + } + err = filesCpCmd.Run(req, res, &cmdCtx) + + if err == nil { + t.Fatal("expected error but got nil") } - require.Error(t, err, "copying dag-cbor should fail") - // require.Contains(t, err.Error(), "must be a UnixFS node or raw data") - // return fmt.Errorf("cp: source must be a UnixFS node or raw data") + expectedErr := "cp: source must be a UnixFS node or raw data" + if !strings.Contains(err.Error(), expectedErr) { + t.Errorf("got error %q, want %q", err.Error(), expectedErr) + } } From fa7c7695df9f88f01a4bfc87b77ca26c80f2712c Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sun, 16 Feb 2025 19:12:02 +0530 Subject: [PATCH 11/22] fix::> Proper test ready Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 92 ++++++-------------------------------- 1 file changed, 14 insertions(+), 78 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index 8552192bb86..40a507f4ec1 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -6,101 +6,36 @@ import ( "strings" "testing" + dag "github.com/ipfs/boxo/ipld/merkledag" cmds "github.com/ipfs/go-ipfs-cmds" coremock "github.com/ipfs/kubo/core/mock" ) -// type testenv struct { -// ctx context.Context -// node *core.IpfsNode -// reqchan chan<- string -// } - -// type writeCloser struct { -// *bytes.Buffer -// } - -// func (w writeCloser) Close() error { return nil } - -// func createTestEnv(t *testing.T, ctx context.Context) cmds.Environment { -// ds := sync.MutexWrap(datastore.NewMapDatastore()) -// node, err := core.NewNode(ctx, &core.BuildCfg{ -// Online: false, -// Repo: &repo.Mock{ -// C: config.Config{ -// Identity: config.Identity{ -// PeerID: "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe", -// }, -// }, -// D: ds, -// }, -// }) -// require.NoError(t, err) - -// return &testenv{ -// ctx: ctx, -// node: node, -// } - -// } - -// func TestCopyCBORtoMFS(t *testing.T) { -// // mock environment creation -// ctx := context.Background() -// env := createTestEnv(t, ctx) - -// cborCid := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" - -// req := &cmds.Request{ -// Context: ctx, -// Arguments: []string{ -// "/ipfs/" + cborCid, -// "/test-cbor", -// }, -// Options: map[string]interface{}{ -// filesFlushOptionName: true, -// }, -// } - -// // mock response emitter -// w := writeCloser{new(bytes.Buffer)} -// require.NoError(t, err, "creating response emitter should not fail") - -// err = filesCpCmd.Run(req, res, env) -// if err != nil { -// t.Logf("Error during file copy: %v", err) // Print actual error -// fmt.Println("Error:", err) // Alternative direct print -// } - -// require.Error(t, err, "copying dag-cbor should fail") -// require.Contains(t, err.Error(), "must be a UnixFS node or raw data") -// // return fmt.Errorf("cp: source must be a UnixFS node or raw data") -// } - func TestFilesCp_DagCborNodeFails(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - // _, err := coremock.NewMockNode() - // if err != nil { - // t.Fatal(err) - // } - cmdCtx, err := coremock.MockCmdsCtx() if err != nil { t.Fatal(err) } - // env := cmdenv.Environment{ - // Node: node, - // CoreAPI: coreapi.NewCoreAPI(node), - // } + node, err := cmdCtx.ConstructNode() + if err != nil { + t.Fatal(err) + } + + cborData := []byte{0x80} + cborNode := dag.NewRawNode(cborData) + err = node.DAG.Add(ctx, cborNode) + if err != nil { + t.Fatal(err) + } - cborCID := "bafyreigbtj4x7ip5legnfznufuopl4sg4knzc2cof6duas4b3q2fy6swua" req := &cmds.Request{ Context: ctx, Arguments: []string{ - "/ipfs/" + cborCID, + "/ipfs/" + cborNode.Cid().String(), "/test-destination", }, Options: map[string]interface{}{ @@ -113,6 +48,7 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { if err != nil { t.Fatal(err) } + err = filesCpCmd.Run(req, res, &cmdCtx) if err == nil { From 1296054147e7b0adb447fa0d78a47d50a52657a8 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Wed, 19 Feb 2025 16:18:24 +0530 Subject: [PATCH 12/22] fix::> Test Passing Signed-off-by: Abhinav Prakash --- core/commands/file_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index 40a507f4ec1..596725cc0fc 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -25,9 +25,9 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { t.Fatal(err) } - cborData := []byte{0x80} - cborNode := dag.NewRawNode(cborData) - err = node.DAG.Add(ctx, cborNode) + invalidData := []byte{0x00} + protoNode := dag.NodeWithData(invalidData) + err = node.DAG.Add(ctx, protoNode) if err != nil { t.Fatal(err) } @@ -35,7 +35,7 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { req := &cmds.Request{ Context: ctx, Arguments: []string{ - "/ipfs/" + cborNode.Cid().String(), + "/ipfs/" + protoNode.Cid().String(), "/test-destination", }, Options: map[string]interface{}{ From 8ab8a83dd1460b58a2e9a3472aec3ee6f7f6a673 Mon Sep 17 00:00:00 2001 From: gammazero <11790789+gammazero@users.noreply.github.com> Date: Wed, 19 Feb 2025 22:35:55 -1000 Subject: [PATCH 13/22] Rename files cp "force" option to "no-validate" This is necessary because a "force" option is already used elsewhere, and its use in multiple places is causing CI to report the error: `Error: option name "force" used multiple times` --- core/commands/files.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index 4c5e07fb75e..c26a27a684b 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -94,6 +94,7 @@ cache, free memory and speed up read operations.`, const ( filesCidVersionOptionName = "cid-version" filesHashOptionName = "hash" + filesNoValidateOptionName = "no-validate" ) var ( @@ -440,7 +441,7 @@ being GC'ed. }, Options: []cmds.Option{ cmds.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."), - cmds.BoolOption(forceOptionName, "force", "Force copy even if the node is not a valid UnixFS node."), + cmds.BoolOption(filesNoValidateOptionName, "Copy even if the node is not a valid UnixFS node."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { mkParents, _ := req.Options[filesParentsOptionName].(bool) @@ -481,7 +482,7 @@ being GC'ed. return fmt.Errorf("cp: cannot get node from path %s: %s", src, err) } - force, _ := req.Options[forceOptionName].(bool) + force, _ := req.Options[filesNoValidateOptionName].(bool) if !force { // Check if it's a raw node if _, ok := node.(*dag.RawNode); !ok { From d94504907cde556402bcd7700ee9f621e9f4e392 Mon Sep 17 00:00:00 2001 From: gammazero <11790789+gammazero@users.noreply.github.com> Date: Wed, 19 Feb 2025 22:42:51 -1000 Subject: [PATCH 14/22] Use require package for more compact test code --- core/commands/file_test.go | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/core/commands/file_test.go b/core/commands/file_test.go index 596725cc0fc..e40987a09f7 100644 --- a/core/commands/file_test.go +++ b/core/commands/file_test.go @@ -3,12 +3,12 @@ package commands import ( "context" "io" - "strings" "testing" dag "github.com/ipfs/boxo/ipld/merkledag" cmds "github.com/ipfs/go-ipfs-cmds" coremock "github.com/ipfs/kubo/core/mock" + "github.com/stretchr/testify/require" ) func TestFilesCp_DagCborNodeFails(t *testing.T) { @@ -16,21 +16,15 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { defer cancel() cmdCtx, err := coremock.MockCmdsCtx() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) node, err := cmdCtx.ConstructNode() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) invalidData := []byte{0x00} protoNode := dag.NodeWithData(invalidData) err = node.DAG.Add(ctx, protoNode) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) req := &cmds.Request{ Context: ctx, @@ -45,18 +39,9 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { _, pw := io.Pipe() res, err := cmds.NewWriterResponseEmitter(pw, req) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = filesCpCmd.Run(req, res, &cmdCtx) - - if err == nil { - t.Fatal("expected error but got nil") - } - - expectedErr := "cp: source must be a UnixFS node or raw data" - if !strings.Contains(err.Error(), expectedErr) { - t.Errorf("got error %q, want %q", err.Error(), expectedErr) - } + require.Error(t, err) + require.ErrorContains(t, err, "cp: source must be a UnixFS node or raw data") } From 34f05a25e337a53135529dfa4e863d40bdc03491 Mon Sep 17 00:00:00 2001 From: gammazero <11790789+gammazero@users.noreply.github.com> Date: Wed, 19 Feb 2025 22:43:34 -1000 Subject: [PATCH 15/22] Rename file_test.go to files_test.go to match the files command --- core/commands/{file_test.go => files_test.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/commands/{file_test.go => files_test.go} (100%) diff --git a/core/commands/file_test.go b/core/commands/files_test.go similarity index 100% rename from core/commands/file_test.go rename to core/commands/files_test.go From b77142d9a1d43cc09bad29d765e1d58cf0c0bdef Mon Sep 17 00:00:00 2001 From: Abhinav Prakash <95116715+PsychoPunkSage@users.noreply.github.com> Date: Thu, 27 Feb 2025 23:51:05 +0530 Subject: [PATCH 16/22] Update core/commands/files.go Co-authored-by: Marcin Rataj --- core/commands/files.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/files.go b/core/commands/files.go index c26a27a684b..9878b6ebc89 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -94,7 +94,7 @@ cache, free memory and speed up read operations.`, const ( filesCidVersionOptionName = "cid-version" filesHashOptionName = "hash" - filesNoValidateOptionName = "no-validate" + filesForceOptionName = "force ) var ( From 9f7f8b6516a6b846cf50816d7f15a77834c75927 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash <95116715+PsychoPunkSage@users.noreply.github.com> Date: Thu, 27 Feb 2025 23:51:43 +0530 Subject: [PATCH 17/22] Update core/commands/files.go Co-authored-by: Marcin Rataj --- core/commands/files.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/files.go b/core/commands/files.go index 9878b6ebc89..536ce21e3bc 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -441,7 +441,7 @@ being GC'ed. }, Options: []cmds.Option{ cmds.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."), - cmds.BoolOption(filesNoValidateOptionName, "Copy even if the node is not a valid UnixFS node."), + cmds.BoolOption(filesForceOptionName, "f", "Force operation: ignore format validation errors and UnixFS safety checks."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { mkParents, _ := req.Options[filesParentsOptionName].(bool) From 9a59b8da97e89e3e59deb2b373969c03bd1bf35e Mon Sep 17 00:00:00 2001 From: Abhinav Prakash <95116715+PsychoPunkSage@users.noreply.github.com> Date: Thu, 27 Feb 2025 23:52:09 +0530 Subject: [PATCH 18/22] Update core/commands/files.go Co-authored-by: Marcin Rataj --- core/commands/files.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index 536ce21e3bc..2df08dd2552 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -487,10 +487,10 @@ being GC'ed. // Check if it's a raw node if _, ok := node.(*dag.RawNode); !ok { if _, ok := node.(*dag.ProtoNode); !ok { - return fmt.Errorf("cp: source must be a UnixFS node or raw data") + return fmt.Errorf("cp: source must be a valid UnixFS (dag-pb or raw codec)") } if _, err = ft.FSNodeFromBytes(node.(*dag.ProtoNode).Data()); err != nil { - return fmt.Errorf("cp: source must be a UnixFS node or raw data: %s", err) + return fmt.Errorf("cp: source must be a valid UnixFS (dag-pb or raw codec): %s", err) } } } From 7ad6847580cc4d6c9d95d9e9bca7c4648681b6d0 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Fri, 28 Feb 2025 01:30:24 +0530 Subject: [PATCH 19/22] fix::> Added dedicated tests.... Signed-off-by: Abhinav Prakash --- core/commands/files.go | 4 +-- test/cli/files_test.go | 74 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 test/cli/files_test.go diff --git a/core/commands/files.go b/core/commands/files.go index 2df08dd2552..96ac425cada 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -94,7 +94,7 @@ cache, free memory and speed up read operations.`, const ( filesCidVersionOptionName = "cid-version" filesHashOptionName = "hash" - filesForceOptionName = "force + filesForceOptionName = "force" ) var ( @@ -482,7 +482,7 @@ being GC'ed. return fmt.Errorf("cp: cannot get node from path %s: %s", src, err) } - force, _ := req.Options[filesNoValidateOptionName].(bool) + force, _ := req.Options[filesForceOptionName].(bool) if !force { // Check if it's a raw node if _, ok := node.(*dag.RawNode); !ok { diff --git a/test/cli/files_test.go b/test/cli/files_test.go new file mode 100644 index 00000000000..961c3e36b05 --- /dev/null +++ b/test/cli/files_test.go @@ -0,0 +1,74 @@ +package cli + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/ipfs/kubo/test/cli/harness" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFilesCp(t *testing.T) { + t.Parallel() + + t.Run("files cp with valid UnixFS", func(t *testing.T) { + t.Parallel() + + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // Create simple text file + data := "testing files cp command" + cid := node.IPFSAddStr(data) + + // Copy form IPFS => MFS + res := node.IPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/valid-file") + assert.NoError(t, res.Err) + + // verification + catRes := node.IPFS("files", "read", "/valid-file") + assert.Equal(t, data, catRes.Stdout.Trimmed()) + }) + + t.Run("files cp with invalid DAG node fails without force", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // create a dag-cbor node + jsonData := `{"data": "not a UnixFS node"}` + tempFile := filepath.Join(node.Dir, "test.json") + err := os.WriteFile(tempFile, []byte(jsonData), 0644) + require.NoError(t, err) + cid := node.IPFS("dag", "put", "--input-codec=json", "--store-codec=dag-cbor", tempFile).Stdout.Trimmed() + + // copy without --force + res := node.RunIPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/invalid-file") + assert.NotEqual(t, 0, res.ExitErr.ExitCode()) + assert.Contains(t, res.Stderr.String(), "source must be a UnixFS") + }) + + t.Run("files cp with invalid DAG node succeeds with force", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // create dag-bor node + jsonData := `{"data": "not a UnixFS node"}` + tempFile := filepath.Join(node.Dir, "test.json") + err := os.WriteFile(tempFile, []byte(jsonData), 0644) + require.NoError(t, err) + cid := node.IPFS("dag", "put", "--input-codec=json", "--store-codec=dag-cbor", tempFile).Stdout.Trimmed() + + // copy with --force + resWithForce := node.RunIPFS("files", "cp", "--force", fmt.Sprintf("/ipfs/%s", cid), "/forced-file") + assert.NotEqual(t, 0, resWithForce.ExitErr.ExitCode()) + + // Verification + // Should NOT contain the validation error + assert.NotContains(t, resWithForce.Stderr.String(), "source must be a valid UnixFS") + + // But should contain flush error instead + assert.Contains(t, resWithForce.Stderr.String(), "cannot flush the created file") + }) +} From 548f630a1fc4db6de77fca99343c9a6532732b67 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Fri, 28 Feb 2025 02:03:13 +0530 Subject: [PATCH 20/22] fix::> more random tests Signed-off-by: Abhinav Prakash --- test/cli/files_test.go | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/cli/files_test.go b/test/cli/files_test.go index 961c3e36b05..da0140876e3 100644 --- a/test/cli/files_test.go +++ b/test/cli/files_test.go @@ -71,4 +71,83 @@ func TestFilesCp(t *testing.T) { // But should contain flush error instead assert.Contains(t, resWithForce.Stderr.String(), "cannot flush the created file") }) + + t.Run("files cp with invalid UnixFS data structure validation", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // Create an invalid proto file + data := []byte{0xDE, 0xAD, 0xBE, 0xEF} // Invalid protobuf data + tempFile := filepath.Join(node.Dir, "invalid-proto.bin") + err := os.WriteFile(tempFile, data, 0644) + require.NoError(t, err) + + res := node.IPFS("block", "put", "--format=raw", tempFile) + require.NoError(t, res.Err) + cid := res.Stdout.Trimmed() + + // Without force - should fail with validation error + // cpResNoForce := node.RunIPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/invalid-proto") + // assert.NotEqual(t, 0, cpResNoForce.ExitErr.ExitCode()) + // assert.Contains(t, cpResNoForce.Stderr.String(), "source must be a valid UnixFS") + + // With force - should succeed since raw blocks can be handled by MFS + cpResWithForce := node.IPFS("files", "cp", "--force", fmt.Sprintf("/ipfs/%s", cid), "/forced-proto") + assert.NoError(t, cpResWithForce.Err) + + // Verify the node was copied + lsRes := node.IPFS("files", "ls", "/") + assert.Contains(t, lsRes.Stdout.String(), "forced-proto") + + // Read back the content to verify + readRes := node.IPFS("files", "read", "/forced-proto") + assert.Equal(t, string(data), readRes.Stdout.Trimmed()) + }) + + t.Run("files cp with raw node", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // Create a raw node + data := "raw data" + tempFile := filepath.Join(node.Dir, "raw.bin") + err := os.WriteFile(tempFile, []byte(data), 0644) + require.NoError(t, err) + + res := node.IPFS("block", "put", "--format=raw", tempFile) + require.NoError(t, res.Err) + cid := res.Stdout.Trimmed() + + // Copy from IPFS to MFS (raw nodes should work without --force) + cpRes := node.IPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/raw-file") + assert.NoError(t, cpRes.Err) + + // Verify the file was copied correctly + catRes := node.IPFS("files", "read", "/raw-file") + assert.Equal(t, data, catRes.Stdout.Trimmed()) + }) + + t.Run("files cp creates intermediate directories with -p", func(t *testing.T) { + t.Parallel() + node := harness.NewT(t).NewNode().Init().StartDaemon() + + // Create a simple text file and add it to IPFS + data := "hello parent directories" + tempFile := filepath.Join(node.Dir, "parent-test.txt") + err := os.WriteFile(tempFile, []byte(data), 0644) + require.NoError(t, err) + + cid := node.IPFS("add", "-Q", tempFile).Stdout.Trimmed() + + // Copy from IPFS to MFS with parent flag + res := node.IPFS("files", "cp", "-p", fmt.Sprintf("/ipfs/%s", cid), "/parent/dir/file") + assert.NoError(t, res.Err) + + // Verify the file and directories were created + lsRes := node.IPFS("files", "ls", "/parent/dir") + assert.Contains(t, lsRes.Stdout.String(), "file") + + catRes := node.IPFS("files", "read", "/parent/dir/file") + assert.Equal(t, data, catRes.Stdout.Trimmed()) + }) } From 5c9313247e1e3d2bafcc947495f24f145cff24fc Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 5 Mar 2025 19:49:19 +0100 Subject: [PATCH 21/22] refactor: remove --force, simplify checks --- core/commands/files.go | 27 ++++++++++++-------- test/cli/files_test.go | 57 +++++++++--------------------------------- 2 files changed, 28 insertions(+), 56 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index 96ac425cada..5c32312ffa6 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -94,7 +94,6 @@ cache, free memory and speed up read operations.`, const ( filesCidVersionOptionName = "cid-version" filesHashOptionName = "hash" - filesForceOptionName = "force" ) var ( @@ -403,6 +402,7 @@ func walkBlock(ctx context.Context, dagserv ipld.DAGService, nd ipld.Node) (bool return local, sizeLocal, nil } +var errFilesCpInvalidUnixFS = errors.New("cp: source must be a valid UnixFS (dag-pb or raw codec)") var filesCpCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Add references to IPFS files and directories in MFS (or copy within MFS).", @@ -441,7 +441,6 @@ being GC'ed. }, Options: []cmds.Option{ cmds.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."), - cmds.BoolOption(filesForceOptionName, "f", "Force operation: ignore format validation errors and UnixFS safety checks."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { mkParents, _ := req.Options[filesParentsOptionName].(bool) @@ -482,17 +481,23 @@ being GC'ed. return fmt.Errorf("cp: cannot get node from path %s: %s", src, err) } - force, _ := req.Options[filesForceOptionName].(bool) - if !force { - // Check if it's a raw node + // Sanity-check: ensure root CID is a valid UnixFS (dag-pb or raw block) + // Context: https://github.com/ipfs/kubo/issues/10331 + srcCidType := node.Cid().Type() + switch srcCidType { + case cid.Raw: if _, ok := node.(*dag.RawNode); !ok { - if _, ok := node.(*dag.ProtoNode); !ok { - return fmt.Errorf("cp: source must be a valid UnixFS (dag-pb or raw codec)") - } - if _, err = ft.FSNodeFromBytes(node.(*dag.ProtoNode).Data()); err != nil { - return fmt.Errorf("cp: source must be a valid UnixFS (dag-pb or raw codec): %s", err) - } + return errFilesCpInvalidUnixFS + } + case cid.DagProtobuf: + if _, ok := node.(*dag.ProtoNode); !ok { + return errFilesCpInvalidUnixFS } + if _, err = ft.FSNodeFromBytes(node.(*dag.ProtoNode).Data()); err != nil { + return fmt.Errorf("%w: %v", errFilesCpInvalidUnixFS, err) + } + default: + return errFilesCpInvalidUnixFS } if mkParents { diff --git a/test/cli/files_test.go b/test/cli/files_test.go index da0140876e3..109c7ab9b50 100644 --- a/test/cli/files_test.go +++ b/test/cli/files_test.go @@ -14,7 +14,7 @@ import ( func TestFilesCp(t *testing.T) { t.Parallel() - t.Run("files cp with valid UnixFS", func(t *testing.T) { + t.Run("files cp with valid UnixFS succeeds", func(t *testing.T) { t.Parallel() node := harness.NewT(t).NewNode().Init().StartDaemon() @@ -32,11 +32,11 @@ func TestFilesCp(t *testing.T) { assert.Equal(t, data, catRes.Stdout.Trimmed()) }) - t.Run("files cp with invalid DAG node fails without force", func(t *testing.T) { + t.Run("files cp with unsupported DAG node type fails", func(t *testing.T) { t.Parallel() node := harness.NewT(t).NewNode().Init().StartDaemon() - // create a dag-cbor node + // MFS UnixFS is limited to dag-pb or raw, so we create a dag-cbor node to test this jsonData := `{"data": "not a UnixFS node"}` tempFile := filepath.Join(node.Dir, "test.json") err := os.WriteFile(tempFile, []byte(jsonData), 0644) @@ -46,33 +46,10 @@ func TestFilesCp(t *testing.T) { // copy without --force res := node.RunIPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/invalid-file") assert.NotEqual(t, 0, res.ExitErr.ExitCode()) - assert.Contains(t, res.Stderr.String(), "source must be a UnixFS") + assert.Contains(t, res.Stderr.String(), "Error: cp: source must be a valid UnixFS (dag-pb or raw codec)") }) - t.Run("files cp with invalid DAG node succeeds with force", func(t *testing.T) { - t.Parallel() - node := harness.NewT(t).NewNode().Init().StartDaemon() - - // create dag-bor node - jsonData := `{"data": "not a UnixFS node"}` - tempFile := filepath.Join(node.Dir, "test.json") - err := os.WriteFile(tempFile, []byte(jsonData), 0644) - require.NoError(t, err) - cid := node.IPFS("dag", "put", "--input-codec=json", "--store-codec=dag-cbor", tempFile).Stdout.Trimmed() - - // copy with --force - resWithForce := node.RunIPFS("files", "cp", "--force", fmt.Sprintf("/ipfs/%s", cid), "/forced-file") - assert.NotEqual(t, 0, resWithForce.ExitErr.ExitCode()) - - // Verification - // Should NOT contain the validation error - assert.NotContains(t, resWithForce.Stderr.String(), "source must be a valid UnixFS") - - // But should contain flush error instead - assert.Contains(t, resWithForce.Stderr.String(), "cannot flush the created file") - }) - - t.Run("files cp with invalid UnixFS data structure validation", func(t *testing.T) { + t.Run("files cp with invalid UnixFS data structure fails", func(t *testing.T) { t.Parallel() node := harness.NewT(t).NewNode().Init().StartDaemon() @@ -84,27 +61,17 @@ func TestFilesCp(t *testing.T) { res := node.IPFS("block", "put", "--format=raw", tempFile) require.NoError(t, res.Err) - cid := res.Stdout.Trimmed() - - // Without force - should fail with validation error - // cpResNoForce := node.RunIPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/invalid-proto") - // assert.NotEqual(t, 0, cpResNoForce.ExitErr.ExitCode()) - // assert.Contains(t, cpResNoForce.Stderr.String(), "source must be a valid UnixFS") - - // With force - should succeed since raw blocks can be handled by MFS - cpResWithForce := node.IPFS("files", "cp", "--force", fmt.Sprintf("/ipfs/%s", cid), "/forced-proto") - assert.NoError(t, cpResWithForce.Err) - // Verify the node was copied - lsRes := node.IPFS("files", "ls", "/") - assert.Contains(t, lsRes.Stdout.String(), "forced-proto") + // we manually changed codec from raw to dag-pb to test "bad dag-pb" scenario + cid := "bafybeic7pdbte5heh6u54vszezob3el6exadoiw4wc4ne7ny2x7kvajzkm" - // Read back the content to verify - readRes := node.IPFS("files", "read", "/forced-proto") - assert.Equal(t, string(data), readRes.Stdout.Trimmed()) + // should fail because node cant be read as a valid dag-pb + cpResNoForce := node.RunIPFS("files", "cp", fmt.Sprintf("/ipfs/%s", cid), "/invalid-proto") + assert.NotEqual(t, 0, cpResNoForce.ExitErr.ExitCode()) + assert.Contains(t, cpResNoForce.Stderr.String(), "Error") }) - t.Run("files cp with raw node", func(t *testing.T) { + t.Run("files cp with raw node succeeds", func(t *testing.T) { t.Parallel() node := harness.NewT(t).NewNode().Init().StartDaemon() From 23c8b6e089706a57a81ff441bdabde481c99be08 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 5 Mar 2025 20:09:59 +0100 Subject: [PATCH 22/22] docs: changelog --- core/commands/files_test.go | 2 +- docs/changelogs/v0.34.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/commands/files_test.go b/core/commands/files_test.go index e40987a09f7..bcd73bd3b17 100644 --- a/core/commands/files_test.go +++ b/core/commands/files_test.go @@ -43,5 +43,5 @@ func TestFilesCp_DagCborNodeFails(t *testing.T) { err = filesCpCmd.Run(req, res, &cmdCtx) require.Error(t, err) - require.ErrorContains(t, err, "cp: source must be a UnixFS node or raw data") + require.ErrorContains(t, err, "cp: source must be a valid UnixFS (dag-pb or raw codec)") } diff --git a/docs/changelogs/v0.34.md b/docs/changelogs/v0.34.md index bb741504342..b11ec3699e3 100644 --- a/docs/changelogs/v0.34.md +++ b/docs/changelogs/v0.34.md @@ -12,8 +12,8 @@ - [`IPFS_LOG_LEVEL` deprecated](#ipfs_log_level-deprecated) - [Pebble datastore format update](#pebble-datastore-format-update) - [Badger datastore update](#badger-datastore-update) - - [Datastore Implementation updates](#datastore-implementation-updates) - - [One multi-error package](#one-multi-error-package) + - [Datastore Implementation Updates](#datastore-implementation-updates) + - [One Multi-error Package](#one-multi-error-package) - [๐Ÿ“ฆ๏ธ Important dependency updates](#-important-dependency-updates) - [๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors](#-contributors) @@ -48,6 +48,7 @@ For more details, check out the [`AutoTLS` configuration documentation](https:// - `ipfs config` is now validating json fields ([#10679](https://github.com/ipfs/kubo/pull/10679)). - Deprecated the `bitswap reprovide` command. Make sure to switch to modern `routing reprovide`. ([#10677](https://github.com/ipfs/kubo/pull/10677)) - The `stats reprovide` command now shows additional stats for [`Routing.AcceleratedDHTClient`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingaccelerateddhtclient), indicating the last and next `reprovide` times. ([#10677](https://github.com/ipfs/kubo/pull/10677)) +- `ipfs files cp` now performs basic codec check and will error when source is not a valid UnixFS (only `dag-pb` and `raw` codecs are allowed in MFS) #### Bitswap improvements from Boxo