master
sh 271 lines 11.4 KB
Raw
1 #!/usr/bin/env bash
2 #
3 # Copyright (c) 2015 Henry Bubert
4 # MIT Licensed; see the LICENSE file in this repository.
5 #
6
7 test_description="Test object command"
8
9 . lib/test-lib.sh
10
11 test_init_ipfs
12
13 test_patch_create_path() {
14 root=$1
15 name=$2
16 target=$3
17
18 test_expect_success "object patch --create works" '
19 PCOUT=$(ipfs object patch $root add-link --create $name $target)
20 '
21
22 test_expect_success "output looks good" '
23 ipfs cat "$PCOUT/$name" >tpcp_out &&
24 ipfs cat "$target" >tpcp_exp &&
25 test_cmp tpcp_exp tpcp_out
26 '
27 }
28
29 test_object_cmd() {
30 # Bare dag-pb node with no UnixFS metadata (0 bytes of protobuf data)
31 EMPTY_DIR=$(echo '{"Links":[]}' | ipfs dag put --store-codec dag-pb)
32 # Empty UnixFS directory (equivalent to QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn)
33 EMPTY_UNIXFS_DIR=$(echo '{"Data":{"/":{"bytes":"CAE"}},"Links":[]}' | ipfs dag put --store-codec dag-pb)
34 # Empty UnixFS file (QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH)
35 EMPTY_UNIXFS_FILE=$(echo -n | ipfs add -q)
36 # Empty HAMTShard (Type=HAMTShard, HashType=0x22, Fanout=256)
37 EMPTY_HAMT=$(echo '{"Data":{"/":{"bytes":"CAUoIjCAAg"}},"Links":[]}' | ipfs dag put --store-codec dag-pb)
38
39 # --- UnixFS validation for 'object patch add-link' ---
40 # 'object patch' operates at the dag-pb level via dagutils.Editor, which
41 # only manipulates ProtoNode links without updating UnixFS metadata.
42 # Only plain UnixFS Directory nodes are safe to mutate this way.
43 # https://specs.ipfs.tech/unixfs/#pbnode-links-name
44 # https://github.com/ipfs/kubo/issues/7190
45 #
46 # Four root node types tested below:
47 # 1) bare dag-pb (no UnixFS data) -- rejected
48 # 2) UnixFS File -- rejected (prevents data loss)
49 # 3) HAMTShard -- rejected (corrupts HAMT bitfield)
50 # 4) UnixFS Directory -- allowed
51
52 # Reproduce https://github.com/ipfs/kubo/issues/7190:
53 # adding a named link to a File node must be rejected to prevent data loss.
54 test_expect_success "'ipfs object patch add-link' prevents data loss on File nodes (#7190)" '
55 echo "original content" > original.txt &&
56 ORIGINAL_CID=$(ipfs add -q original.txt) &&
57 CHILD_CID=$(echo "child" | ipfs add -q) &&
58 test_expect_code 1 ipfs object patch $ORIGINAL_CID add-link "child.txt" $CHILD_CID 2>patch_7190_err &&
59 echo "Error: cannot add named links to a UnixFS File node, only Directory nodes support link addition at the dag-pb level (see https://specs.ipfs.tech/unixfs/)" >patch_7190_expected &&
60 test_cmp patch_7190_expected patch_7190_err &&
61 # verify the original file is still intact
62 ipfs cat $ORIGINAL_CID > original_readback.txt &&
63 test_cmp original.txt original_readback.txt
64 '
65
66 # 1) Bare dag-pb (no UnixFS data): rejected by default
67 test_expect_success "'ipfs object patch add-link' rejects non-UnixFS dag-pb nodes" '
68 test_expect_code 1 ipfs object patch $EMPTY_DIR add-link foo $EMPTY_UNIXFS_DIR 2>patch_dagpb_err
69 '
70
71 test_expect_success "add-link error for non-UnixFS dag-pb has expected message" '
72 echo "Error: cannot add named links to a non-UnixFS dag-pb node; pass --allow-non-unixfs to skip validation" >patch_dagpb_expected &&
73 test_cmp patch_dagpb_expected patch_dagpb_err
74 '
75
76 test_expect_success "'ipfs object patch add-link --allow-non-unixfs' works on dag-pb nodes" '
77 OUTPUT=$(ipfs object patch $EMPTY_DIR add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR) &&
78 ipfs dag stat $OUTPUT
79 '
80
81 # 2) UnixFS File (QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH): rejected by default
82 test_expect_success "'ipfs object patch add-link' rejects UnixFS File nodes" '
83 test_expect_code 1 ipfs object patch $EMPTY_UNIXFS_FILE add-link foo $EMPTY_UNIXFS_DIR 2>patch_file_err
84 '
85
86 test_expect_success "add-link error for UnixFS File has expected message" '
87 echo "Error: cannot add named links to a UnixFS File node, only Directory nodes support link addition at the dag-pb level (see https://specs.ipfs.tech/unixfs/)" >patch_file_expected &&
88 test_cmp patch_file_expected patch_file_err
89 '
90
91 test_expect_success "'ipfs object patch add-link --allow-non-unixfs' bypasses check on File nodes" '
92 ipfs object patch $EMPTY_UNIXFS_FILE add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR
93 '
94
95 # 3) HAMTShard: rejected (dag-pb level mutation corrupts HAMT bitfield)
96 test_expect_success "'ipfs object patch add-link' rejects HAMTShard nodes" '
97 test_expect_code 1 ipfs object patch $EMPTY_HAMT add-link foo $EMPTY_UNIXFS_DIR 2>patch_hamt_err
98 '
99
100 test_expect_success "add-link error for HAMTShard has expected message" '
101 echo "Error: cannot add links to a HAMTShard at the dag-pb level (would corrupt the HAMT bitfield); use '"'"'ipfs files'"'"' commands instead, or pass --allow-non-unixfs to override" >patch_hamt_expected &&
102 test_cmp patch_hamt_expected patch_hamt_err
103 '
104
105 test_expect_success "'ipfs object patch add-link --allow-non-unixfs' bypasses check on HAMTShard" '
106 ipfs object patch $EMPTY_HAMT add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR
107 '
108
109 # 4) UnixFS Directory (QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn): allowed
110 test_expect_success "'ipfs object patch add-link' works on UnixFS Directory nodes" '
111 OUTPUT=$(ipfs object patch $EMPTY_UNIXFS_DIR add-link foo $EMPTY_UNIXFS_DIR) &&
112 ipfs dag stat $OUTPUT
113 '
114
115 test_expect_success "'ipfs object patch' check output block size" '
116 DIR=$EMPTY_UNIXFS_DIR
117 for i in {1..14}
118 do
119 DIR=$(ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR")
120 done
121 # Fail when new block goes over the BS limit of 2MiB, but allow manual override
122 test_expect_code 1 ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR" >patch_out 2>&1
123 '
124
125 test_expect_success "ipfs object patch add-link output has the correct error" '
126 grep "produced block is over 2MiB" patch_out
127 '
128
129 test_expect_success "ipfs object patch --allow-big-block=true add-link works" '
130 test_expect_code 0 ipfs object patch --allow-big-block=true "$DIR" add-link "$DIR.jpg" "$DIR"
131 '
132
133 test_expect_success "'ipfs object patch add-link' should work with paths" '
134 N1=$(ipfs object patch $EMPTY_UNIXFS_DIR add-link baz $EMPTY_UNIXFS_DIR) &&
135 N2=$(ipfs object patch $EMPTY_UNIXFS_DIR add-link bar $N1) &&
136 N3=$(ipfs object patch $EMPTY_UNIXFS_DIR add-link foo /ipfs/$N2/bar) &&
137 ipfs dag stat /ipfs/$N3 > /dev/null &&
138 ipfs dag stat $N3/foo > /dev/null &&
139 ipfs dag stat /ipfs/$N3/foo/baz > /dev/null
140 '
141
142 test_expect_success "'ipfs object patch add-link' allow linking IPLD objects" '
143 OBJ=$(echo "123" | ipfs dag put) &&
144 N1=$(ipfs object patch $EMPTY_UNIXFS_DIR add-link foo $OBJ) &&
145
146 ipfs dag stat /ipfs/$N1 > /dev/null &&
147 ipfs resolve /ipfs/$N1/foo > actual &&
148 echo /ipfs/$OBJ > expected &&
149
150 test_cmp expected actual
151 '
152
153 test_expect_success "object patch creation looks right" '
154 echo "bafybeiakusqwohnt7bs75kx6jhmt4oi47l634bmudxfv4qxhpco6xuvgna" > hash_exp &&
155 echo $N3 > hash_actual &&
156 test_cmp hash_exp hash_actual
157 '
158
159 test_expect_success "multilayer ipfs patch works" '
160 echo "hello world" > hwfile &&
161 FILE=$(ipfs add -q hwfile) &&
162 EMPTY=$EMPTY_UNIXFS_DIR &&
163 ONE=$(ipfs object patch $EMPTY add-link b $EMPTY) &&
164 TWO=$(ipfs object patch $EMPTY add-link a $ONE) &&
165 ipfs object patch $TWO add-link a/b/c $FILE > multi_patch
166 '
167
168 test_expect_success "output looks good" '
169 ipfs cat $(cat multi_patch)/a/b/c > hwfile_out &&
170 test_cmp hwfile hwfile_out
171 '
172
173 test_expect_success "can remove the directory" '
174 ipfs object patch $OUTPUT rm-link foo > rmlink_output
175 '
176
177 test_expect_success "output should be empty" '
178 echo bafybeiczsscdsbs7ffqz55asqdf3smv6klcw3gofszvwlyarci47bgf354 > rmlink_exp &&
179 test_cmp rmlink_exp rmlink_output
180 '
181
182 test_expect_success "multilayer rm-link should work" '
183 ipfs object patch $(cat multi_patch) rm-link a/b/c > multi_link_rm_out
184 '
185
186 test_expect_success "output looks good" '
187 echo "bafybeicourxysmtbe5hacxqico4d5hyvh7gqkrwlmqa4ew7zufn3pj3juu" > multi_link_rm_exp &&
188 test_cmp multi_link_rm_exp multi_link_rm_out
189 '
190
191 test_patch_create_path $EMPTY a/b/c $FILE
192
193 test_patch_create_path $EMPTY a $FILE
194
195 test_patch_create_path $EMPTY a/b/b/b/b $FILE
196
197 test_expect_success "'ipfs object patch add-link --create' rejects non-UnixFS roots" '
198 test_must_fail ipfs object patch $EMPTY_DIR add-link --create a $FILE
199 '
200
201 test_expect_success "'ipfs object patch add-link --create --allow-non-unixfs' works on non-UnixFS roots" '
202 PCOUT=$(ipfs object patch $EMPTY_DIR add-link --create --allow-non-unixfs a $FILE) &&
203 ipfs cat "$PCOUT/a" >tpcp_out &&
204 ipfs cat "$FILE" >tpcp_exp &&
205 test_cmp tpcp_exp tpcp_out
206 '
207
208 test_expect_success "create bad path fails" '
209 test_must_fail ipfs object patch $EMPTY add-link --create / $FILE
210 '
211
212 # --- UnixFS validation for 'object patch rm-link' ---
213 # Same rationale as add-link: dagutils.Editor cannot update UnixFS metadata.
214
215 # 1) Bare dag-pb: rejected by default
216 test_expect_success "'ipfs object patch rm-link' rejects non-UnixFS dag-pb nodes" '
217 DAGPB_WITH_LINK=$(ipfs object patch $EMPTY_DIR add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR) &&
218 test_expect_code 1 ipfs object patch $DAGPB_WITH_LINK rm-link foo 2>rmlink_dagpb_err
219 '
220
221 test_expect_success "rm-link error for non-UnixFS dag-pb has expected message" '
222 echo "Error: cannot remove links from a non-UnixFS dag-pb node; pass --allow-non-unixfs to skip validation" >rmlink_dagpb_expected &&
223 test_cmp rmlink_dagpb_expected rmlink_dagpb_err
224 '
225
226 test_expect_success "'ipfs object patch rm-link --allow-non-unixfs' works on dag-pb nodes" '
227 ipfs object patch $DAGPB_WITH_LINK rm-link --allow-non-unixfs foo
228 '
229
230 # 2) UnixFS File: rejected by default
231 test_expect_success "'ipfs object patch rm-link' rejects UnixFS File nodes" '
232 FILE_WITH_LINK=$(ipfs object patch $EMPTY_UNIXFS_FILE add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR) &&
233 test_expect_code 1 ipfs object patch $FILE_WITH_LINK rm-link foo 2>rmlink_file_err
234 '
235
236 test_expect_success "rm-link error for UnixFS File has expected message" '
237 echo "Error: cannot remove links from a UnixFS File node, only Directory nodes support link removal at the dag-pb level (see https://specs.ipfs.tech/unixfs/)" >rmlink_file_expected &&
238 test_cmp rmlink_file_expected rmlink_file_err
239 '
240
241 test_expect_success "'ipfs object patch rm-link --allow-non-unixfs' bypasses check on File nodes" '
242 ipfs object patch $FILE_WITH_LINK rm-link --allow-non-unixfs foo
243 '
244
245 # 3) HAMTShard: rejected by default
246 test_expect_success "'ipfs object patch rm-link' rejects HAMTShard nodes" '
247 HAMT_WITH_LINK=$(ipfs object patch $EMPTY_HAMT add-link --allow-non-unixfs foo $EMPTY_UNIXFS_DIR) &&
248 test_expect_code 1 ipfs object patch $HAMT_WITH_LINK rm-link foo 2>rmlink_hamt_err
249 '
250
251 test_expect_success "rm-link error for HAMTShard has expected message" '
252 echo "Error: cannot remove links from a HAMTShard at the dag-pb level (would corrupt the HAMT bitfield); use '"'"'ipfs files rm'"'"' instead, or pass --allow-non-unixfs to override" >rmlink_hamt_expected &&
253 test_cmp rmlink_hamt_expected rmlink_hamt_err
254 '
255
256 test_expect_success "'ipfs object patch rm-link --allow-non-unixfs' bypasses check on HAMTShard" '
257 ipfs object patch $HAMT_WITH_LINK rm-link --allow-non-unixfs foo
258 '
259
260 # 4) UnixFS Directory: allowed (already tested above in existing rm-link tests)
261 }
262
263 # should work offline
264 test_object_cmd
265
266 # should work online
267 test_launch_ipfs_daemon
268 test_object_cmd
269 test_kill_ipfs_daemon
270
271 test_done