kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

run.sh (29225B)


      1 #!/bin/sh
      2 # Driver-level checks for kit pkg distribution formats.
      3 
      4 set -u
      5 
      6 script_dir=$(cd "$(dirname "$0")" && pwd)
      7 repo_root=$(cd "$script_dir/../.." && pwd)
      8 
      9 KIT="${KIT:-$repo_root/build/kit}"
     10 
     11 if [ ! -x "$KIT" ]; then
     12     echo "pkg: kit binary not found at $KIT" >&2
     13     exit 2
     14 fi
     15 
     16 work=$(mktemp -d "${TMPDIR:-/tmp}/kit-pkg-test.XXXXXX")
     17 trap 'rm -rf "$work"' EXIT
     18 
     19 HOME="$work/home"
     20 KIT_TRUSTED_KEYS="$work/trusted_keys"
     21 SOURCE_DATE_EPOCH=1
     22 export HOME KIT_TRUSTED_KEYS SOURCE_DATE_EPOCH
     23 mkdir -p "$HOME" "$work/in" "$work/pkg" "$work/unpack" "$work/cas"
     24 
     25 artifacts="empty.dat one.bin dup-one.bin payload.txt chunk64.bin chunk64-copy.bin chunk64p1.bin chunk3.bin bin/tool.sh"
     26 tree_id=
     27 
     28 # Type-K mode-P kit: shared assert verbs + CAS helpers, all recording through
     29 # the unified kit_* counters over $work. pkg-specific helpers (not_contains,
     30 # same_artifacts, not_same_file, have_cmd) stay below.
     31 KIT_KIT_DIR="$repo_root/test/lib"
     32 . "$repo_root/test/lib/kit_sh_kit.sh"
     33 kit_report_init
     34 
     35 not_contains() {
     36     name=$1
     37     file=$2
     38     needle=$3
     39     if grep -F "$needle" "$file" >/dev/null 2>&1; then
     40         {
     41             printf 'unexpected text: %s\n' "$needle"
     42             sed 's/^/file: /' "$file"
     43         } > "$work/$name.diag"
     44         not_ok "$name" "$work/$name.diag"
     45     else
     46         ok "$name"
     47     fi
     48 }
     49 
     50 same_artifacts() {
     51     name=$1
     52     dir=$2
     53     diag="$work/$name.diag"
     54     : > "$diag"
     55     good=1
     56     for f in $artifacts; do
     57         if ! cmp -s "$work/in/$f" "$dir/$f"; then
     58             printf 'artifact differs or is missing: %s\n' "$f" >> "$diag"
     59             good=0
     60         fi
     61     done
     62     if [ "$good" -eq 1 ]; then
     63         ok "$name"
     64     else
     65         not_ok "$name" "$diag"
     66     fi
     67 }
     68 
     69 not_same_file() {
     70     name=$1
     71     left=$2
     72     right=$3
     73     if cmp -s "$left" "$right"; then
     74         {
     75             printf 'files unexpectedly match:\n'
     76             printf '  left:  %s\n' "$left"
     77             printf '  right: %s\n' "$right"
     78         } > "$work/$name.diag"
     79         not_ok "$name" "$work/$name.diag"
     80     else
     81         ok "$name"
     82     fi
     83 }
     84 
     85 have_cmd() {
     86     command -v "$1" >/dev/null 2>&1
     87 }
     88 
     89 make_fixtures() {
     90     : > "$work/in/empty.dat"
     91     printf x > "$work/in/one.bin"
     92     cp "$work/in/one.bin" "$work/in/dup-one.bin"
     93     printf 'portable package deflate regression payload\n' > "$work/in/payload.txt"
     94     dd if=/dev/zero of="$work/in/chunk64.bin" bs=65536 count=1 >/dev/null 2>&1
     95     cp "$work/in/chunk64.bin" "$work/in/chunk64-copy.bin"
     96     dd if=/dev/zero of="$work/in/chunk64p1.bin" bs=65536 count=1 >/dev/null 2>&1
     97     printf y >> "$work/in/chunk64p1.bin"
     98     dd if=/dev/zero of="$work/in/chunk3.bin" bs=65536 count=3 >/dev/null 2>&1
     99     printf tail >> "$work/in/chunk3.bin"
    100     mkdir -p "$work/in/bin"
    101     {
    102         printf '#!/bin/sh\n'
    103         printf 'printf "tool executed\\n"\n'
    104     } > "$work/in/bin/tool.sh"
    105     chmod +x "$work/in/bin/tool.sh"
    106 }
    107 
    108 keyid_from_keygen() {
    109     sed -n 's/.*key id \([0-9a-fA-F][0-9a-fA-F]*\)).*/\1/p' "$1"
    110 }
    111 
    112 inspect_checks() {
    113     label=$1
    114     out=$2
    115     contains "$label-inspect-magic" "$out" "kit-package 3"
    116     contains "$label-inspect-name" "$out" "name = matrix-test"
    117     contains "$label-inspect-version" "$out" "version = 1.0.0"
    118     contains "$label-inspect-desc" "$out" "description = package test matrix"
    119     contains "$label-inspect-hash" "$out" "hash = blake2b-256"
    120     contains "$label-inspect-tree-format" "$out" "tree = kit-tree-v1"
    121     contains "$label-inspect-blob-format" "$out" "blob = kit-blob-v1"
    122     contains "$label-inspect-output" "$out" "[output]"
    123     contains "$label-inspect-output-tree" "$out" "tree = $tree_id"
    124     contains "$label-inspect-empty" "$out" "path = empty.dat"
    125     contains "$label-inspect-boundary" "$out" "path = chunk64p1.bin"
    126     contains "$label-inspect-exec" "$out" "path = bin/tool.sh"
    127     not_contains "$label-inspect-no-v2-hash" "$out" "blake2b-merkle-v1"
    128     not_contains "$label-inspect-no-sha256" "$out" "sha256"
    129 }
    130 
    131 repack_targz() {
    132     src=$1
    133     out=$2
    134     files=$(cd "$src" && find . -type f -print | sed 's#^\./##' | sort)
    135     (cd "$src" && tar -czf "$out" $files)
    136 }
    137 
    138 extract_targz() {
    139     pkg=$1
    140     dst=$2
    141     mkdir -p "$dst"
    142     gzip -dc "$pkg" | tar -xf - -C "$dst"
    143 }
    144 
    145 flip_byte() {
    146     file=$1
    147     off=$2
    148     printf '\377' | dd of="$file" bs=1 seek="$off" count=1 conv=notrunc >/dev/null 2>&1
    149 }
    150 
    151 kpkg3_field_offset() {
    152     file=$1
    153     idx=$2
    154     perl -e '
    155         use strict;
    156         use warnings;
    157         my ($file, $idx) = @ARGV;
    158         open my $fh, "<:raw", $file or die "$file: $!";
    159         read $fh, my $magic, 7;
    160         die "bad magic" unless $magic eq "kpkg3\0\0";
    161         seek $fh, 16 + 8 * $idx, 0 or die "seek: $!";
    162         read $fh, my $b, 8;
    163         die "short read" unless length($b) == 8;
    164         print unpack("Q<", $b);
    165     ' "$file" "$idx"
    166 }
    167 
    168 extract_kpkg3_descriptor() {
    169     pkg=$1
    170     out=$2
    171     descriptor_off=$(kpkg3_field_offset "$pkg" 4)
    172     descriptor_size=$(kpkg3_field_offset "$pkg" 5)
    173     dd if="$pkg" of="$out" bs=1 skip="$descriptor_off" count="$descriptor_size" >/dev/null 2>&1
    174 }
    175 
    176 extract_kpkg3_manifest() {
    177     pkg=$1
    178     out=$2
    179     manifest_off=$(kpkg3_field_offset "$pkg" 0)
    180     manifest_size=$(kpkg3_field_offset "$pkg" 1)
    181     dd if="$pkg" of="$out" bs=1 skip="$manifest_off" count="$manifest_size" >/dev/null 2>&1
    182 }
    183 
    184 descriptor_value() {
    185     file=$1
    186     key=$2
    187     sed -n "s/^$key = //p" "$file" | sed -n '1p'
    188 }
    189 
    190 check_kpkg3_index() {
    191     label=$1
    192     pkg=$2
    193     descriptor=$3
    194     expected_compression=$4
    195 
    196     index_off=$(descriptor_value "$descriptor" "index-offset")
    197     index_size=$(descriptor_value "$descriptor" "index-size")
    198     content_size=$(descriptor_value "$descriptor" "content-size")
    199     empty_blob=$(tree_blob_for_path "$tree_file" "empty.dat")
    200     one_blob=$(tree_blob_for_path "$tree_file" "one.bin")
    201     dup_one_blob=$(tree_blob_for_path "$tree_file" "dup-one.bin")
    202     chunk64_blob=$(tree_blob_for_path "$tree_file" "chunk64.bin")
    203     chunk64_copy_blob=$(tree_blob_for_path "$tree_file" "chunk64-copy.bin")
    204     chunk64p1_blob=$(tree_blob_for_path "$tree_file" "chunk64p1.bin")
    205     chunk3_blob=$(tree_blob_for_path "$tree_file" "chunk3.bin")
    206     if perl -e '
    207         use strict;
    208         use warnings;
    209         my ($pkg, $index_off, $index_size, $content_size, $expected_comp,
    210             $empty, $one, $dup_one, $chunk64, $chunk64_copy, $chunk64p1,
    211             $chunk3) = @ARGV;
    212         die "duplicate one.bin blob mismatch" unless $one eq $dup_one;
    213         die "duplicate chunk64 blob mismatch" unless $chunk64 eq $chunk64_copy;
    214         die "bad index size" unless $index_size % 168 == 0;
    215         open my $fh, "<:raw", $pkg or die "$pkg: $!";
    216         seek $fh, $index_off, 0 or die "seek: $!";
    217         read $fh, my $index, $index_size;
    218         die "short index" unless length($index) == $index_size;
    219         my %count;
    220         my ($prev_blob, $prev_chunk) = ("", -1);
    221         for (my $off = 0; $off < $index_size; $off += 168) {
    222             my $rec = substr($index, $off, 168);
    223             my $blob = unpack("H64", substr($rec, 0, 32));
    224             my $chunk = unpack("Q<", substr($rec, 32, 8));
    225             my $content_off = unpack("Q<", substr($rec, 40, 8));
    226             my $stored_size = unpack("Q<", substr($rec, 48, 8));
    227             my $raw_size = unpack("Q<", substr($rec, 56, 8));
    228             my $compression = unpack("V", substr($rec, 64, 4));
    229             my $reserved = unpack("V", substr($rec, 68, 4));
    230             die "reserved field is nonzero" if $reserved != 0;
    231             die "wrong compression" if $compression != $expected_comp;
    232             die "raw chunk size out of range" if $raw_size == 0 || $raw_size > 65536;
    233             die "content range out of bounds"
    234                 if $content_off > $content_size || $stored_size > $content_size - $content_off;
    235             if ($prev_blob ne "") {
    236                 my $cmp = $prev_blob cmp $blob;
    237                 die "index not sorted" if $cmp > 0;
    238                 die "chunk index not increasing" if $cmp == 0 && $chunk <= $prev_chunk;
    239                 die "new blob does not start at chunk 0" if $cmp < 0 && $chunk != 0;
    240             } elsif ($chunk != 0) {
    241                 die "first blob does not start at chunk 0";
    242             }
    243             $count{$blob}++;
    244             ($prev_blob, $prev_chunk) = ($blob, $chunk);
    245         }
    246         die "unexpected record count" unless $index_size / 168 == 10;
    247         die "empty blob should have no records" if exists $count{$empty};
    248         die "one-byte duplicate blob count" unless ($count{$one} // 0) == 1;
    249         die "chunk64 duplicate blob count" unless ($count{$chunk64} // 0) == 1;
    250         die "chunk64p1 blob count" unless ($count{$chunk64p1} // 0) == 2;
    251         die "chunk3 blob count" unless ($count{$chunk3} // 0) == 4;
    252     ' "$pkg" "$index_off" "$index_size" "$content_size" "$expected_compression" \
    253         "$empty_blob" "$one_blob" "$dup_one_blob" "$chunk64_blob" \
    254         "$chunk64_copy_blob" "$chunk64p1_blob" "$chunk3_blob" \
    255         > "$work/$label.out" 2> "$work/$label.err"; then
    256         ok "$label"
    257     else
    258         not_ok "$label" "$work/$label.err"
    259     fi
    260 }
    261 
    262 maybe_corrupt_native_region() {
    263     label=$1
    264     pkg=$2
    265     descriptor=$3
    266     key=$4
    267     off=$(descriptor_value "$descriptor" "$key")
    268     case "$off" in
    269         ''|*[!0-9]*|0)
    270             skip_test "$label"
    271             ;;
    272         *)
    273             cp "$pkg" "$work/pkg/bad-$label.kpkg"
    274             flip_byte "$work/pkg/bad-$label.kpkg" "$off"
    275             run_fail "$label" "$KIT" pkg verify -p "$work/key.pub" \
    276                 "$work/pkg/bad-$label.kpkg"
    277             ;;
    278     esac
    279 }
    280 
    281 run_matrix_for_package() {
    282     label=$1
    283     pkg=$2
    284     format=$3
    285 
    286     run_ok "$label-inspect" "$KIT" pkg inspect "$pkg"
    287     inspect_checks "$label" "$work/$label-inspect.out"
    288 
    289     run_ok "$label-verify-pubkey" "$KIT" pkg verify -p "$work/key.pub" "$pkg"
    290     contains "$label-verify-output-name" "$work/$label-verify-pubkey.out" "ok: matrix-test 1.0.0"
    291 
    292     outdir="$work/unpack/$label"
    293     mkdir -p "$outdir"
    294     run_ok "$label-unpack-pubkey" "$KIT" pkg unpack --verify -p "$work/key.pub" "$pkg" -C "$outdir"
    295     contains "$label-unpack-verify-output-name" "$work/$label-unpack-pubkey.out" "ok: matrix-test 1.0.0"
    296     same_artifacts "$label-unpack-content" "$outdir"
    297     is_executable "$label-unpack-exec-mode" "$outdir/bin/tool.sh"
    298 
    299     run_ok "$label-verify-format-override" "$KIT" pkg verify -p "$work/key.pub" --format "$format" "$pkg"
    300 }
    301 
    302 make_fixtures
    303 
    304 run_ok "pkg-keygen" "$KIT" pkg keygen -o "$work/key"
    305 keyid=$(keyid_from_keygen "$work/pkg-keygen.out")
    306 if [ -n "$keyid" ]; then
    307     ok "pkg-keygen-keyid"
    308 else
    309     echo "could not parse key id from keygen output" > "$work/pkg-keygen-keyid.diag"
    310     not_ok "pkg-keygen-keyid" "$work/pkg-keygen-keyid.diag"
    311 fi
    312 
    313 run_ok "pkg-cas-add-tree" "$KIT" cas add-tree --cas "$work/cas" --root "$work/in"
    314 tree_id=$(first_hex_id "$work/pkg-cas-add-tree.out")
    315 if [ -n "$tree_id" ]; then
    316     ok "pkg-cas-tree-id"
    317 else
    318     echo "could not parse tree id from cas add-tree output" > "$work/pkg-cas-tree-id.diag"
    319     not_ok "pkg-cas-tree-id" "$work/pkg-cas-tree-id.diag"
    320 fi
    321 tree_file=$(cas_object_path "$work/cas" tree "$tree_id")
    322 assert_file_exists "pkg-cas-tree-object" "$tree_file"
    323 contains "pkg-cas-tree-magic" "$tree_file" "kit-tree 1"
    324 contains "pkg-cas-tree-exec-mode" "$tree_file" "mode = x"
    325 contains "pkg-cas-tree-file-mode" "$tree_file" "mode = -"
    326 
    327 run_ok "pkg-create-targz-deflate" "$KIT" pkg create \
    328     --name matrix-test --version 1.0.0 --desc "package test matrix" \
    329     --format tar.gz --cas "$work/cas" --tree "$tree_id" \
    330     -s "$work/key.key" -o "$work/pkg/matrix.tar.gz"
    331 
    332 run_ok "pkg-create-kpkg-none" "$KIT" pkg create \
    333     --name matrix-test --version 1.0.0 --desc "package test matrix" \
    334     --format kpkg --compression none --cas "$work/cas" --tree "$tree_id" \
    335     -s "$work/key.key" -o "$work/pkg/matrix-none.kpkg"
    336 
    337 run_ok "pkg-create-kpkg-lz4" "$KIT" pkg create \
    338     --name matrix-test --version 1.0.0 --desc "package test matrix" \
    339     --format kpkg --compression lz4-block-v1 --cas "$work/cas" --tree "$tree_id" \
    340     -s "$work/key.key" -o "$work/pkg/matrix-lz4.kpkg"
    341 
    342 run_ok "pkg-create-root-targz" "$KIT" pkg create \
    343     --name order-test --version 1.0.0 --desc "order independence" \
    344     --format tar.gz --root "$work/in" -s "$work/key.key" \
    345     -o "$work/pkg/order-root.tar.gz"
    346 run_ok "pkg-create-cas-targz" "$KIT" pkg create \
    347     --name order-test --version 1.0.0 --desc "order independence" \
    348     --format tar.gz --cas "$work/cas" --tree "$tree_id" \
    349     -s "$work/key.key" -o "$work/pkg/order-cas.tar.gz"
    350 run_ok "pkg-inspect-order-targz-root" "$KIT" pkg inspect "$work/pkg/order-root.tar.gz"
    351 run_ok "pkg-inspect-order-targz-cas" "$KIT" pkg inspect "$work/pkg/order-cas.tar.gz"
    352 same_file "pkg-root-and-cas-manifest-match" \
    353     "$work/pkg-inspect-order-targz-root.out" \
    354     "$work/pkg-inspect-order-targz-cas.out"
    355 
    356 run_ok "pkg-create-version-alt" "$KIT" pkg create \
    357     --name matrix-test --version 1.0.1 --desc "package test matrix" \
    358     --format tar.gz --cas "$work/cas" --tree "$tree_id" \
    359     -s "$work/key.key" -o "$work/pkg/matrix-alt-version.tar.gz"
    360 run_ok "pkg-inspect-version-alt" "$KIT" pkg inspect "$work/pkg/matrix-alt-version.tar.gz"
    361 contains "pkg-version-alt-tree-same" "$work/pkg-inspect-version-alt.out" "tree = $tree_id"
    362 contains "pkg-version-alt-version" "$work/pkg-inspect-version-alt.out" "version = 1.0.1"
    363 
    364 run_matrix_for_package "targz" "$work/pkg/matrix.tar.gz" "tar.gz"
    365 run_matrix_for_package "kpkg-none" "$work/pkg/matrix-none.kpkg" "kpkg"
    366 run_matrix_for_package "kpkg-lz4" "$work/pkg/matrix-lz4.kpkg" "kpkg"
    367 
    368 if have_cmd perl; then
    369     extract_kpkg3_descriptor "$work/pkg/matrix-none.kpkg" "$work/native-none.descriptor"
    370     contains "native-descriptor-magic" "$work/native-none.descriptor" "kit-encoding 3"
    371     contains "native-descriptor-tree-region" "$work/native-none.descriptor" "tree-offset = "
    372     contains "native-descriptor-index-bytes" "$work/native-none.descriptor" "index-bytes = 1680"
    373     check_kpkg3_index "native-none-index-shape" \
    374         "$work/pkg/matrix-none.kpkg" "$work/native-none.descriptor" 0
    375     extract_kpkg3_descriptor "$work/pkg/matrix-lz4.kpkg" "$work/native-lz4.descriptor"
    376     check_kpkg3_index "native-lz4-index-shape" \
    377         "$work/pkg/matrix-lz4.kpkg" "$work/native-lz4.descriptor" 1
    378     extract_kpkg3_manifest "$work/pkg/matrix-none.kpkg" "$work/native-none.manifest"
    379     contains "native-manifest-v3" "$work/native-none.manifest" "kit-package 3"
    380 else
    381     skip_test "native-descriptor-inspection"
    382 fi
    383 
    384 run_ok "pkg-create-kpkg-thin" "$KIT" pkg create \
    385     --name matrix-test --version 1.0.0 --desc "package test matrix" \
    386     --format kpkg --native-shape thin --external "$work/ext-thin" \
    387     --compression none --cas "$work/cas" --tree "$tree_id" \
    388     -s "$work/key.key" -o "$work/pkg/matrix-thin.kpkg"
    389 run_ok "native-thin-inspect-encoding" "$KIT" pkg inspect --encoding \
    390     "$work/pkg/matrix-thin.kpkg"
    391 contains "native-thin-tree-external" "$work/native-thin-inspect-encoding.out" \
    392     "tree-size = 0"
    393 contains "native-thin-index-external" "$work/native-thin-inspect-encoding.out" \
    394     "index-size = 0"
    395 contains "native-thin-content-external" "$work/native-thin-inspect-encoding.out" \
    396     "content-size = 0"
    397 contains "native-thin-index-url" "$work/native-thin-inspect-encoding.out" \
    398     "index-url = index/"
    399 contains "native-thin-tree-url" "$work/native-thin-inspect-encoding.out" \
    400     "url = tree/"
    401 contains "native-thin-chunk-template" "$work/native-thin-inspect-encoding.out" \
    402     "template = chunk/{blob-prefix}/{blob}/{chunk}"
    403 run_fail "native-thin-verify-without-external-fails" "$KIT" pkg verify \
    404     -p "$work/key.pub" "$work/pkg/matrix-thin.kpkg"
    405 run_ok "native-thin-verify-external" "$KIT" pkg verify \
    406     -p "$work/key.pub" --external "$work/ext-thin" \
    407     "$work/pkg/matrix-thin.kpkg"
    408 mkdir -p "$work/unpack/kpkg-thin"
    409 run_ok "native-thin-unpack-external" "$KIT" pkg unpack --verify \
    410     -p "$work/key.pub" --external "$work/ext-thin" \
    411     "$work/pkg/matrix-thin.kpkg" -C "$work/unpack/kpkg-thin"
    412 same_artifacts "native-thin-unpack-content" "$work/unpack/kpkg-thin"
    413 is_executable "native-thin-unpack-exec-mode" \
    414     "$work/unpack/kpkg-thin/bin/tool.sh"
    415 
    416 run_ok "pkg-create-kpkg-metadata" "$KIT" pkg create \
    417     --name matrix-test --version 1.0.0 --desc "package test matrix" \
    418     --format kpkg --native-shape metadata --external "$work/ext-metadata" \
    419     --compression none --cas "$work/cas" --tree "$tree_id" \
    420     -s "$work/key.key" -o "$work/pkg/matrix-metadata.kpkg"
    421 run_fail "native-metadata-verify-without-external-fails" "$KIT" pkg verify \
    422     -p "$work/key.pub" "$work/pkg/matrix-metadata.kpkg"
    423 run_ok "native-metadata-verify-external" "$KIT" pkg verify \
    424     -p "$work/key.pub" --external "$work/ext-metadata" \
    425     "$work/pkg/matrix-metadata.kpkg"
    426 
    427 payload_blob_for_external=$(tree_blob_for_path "$tree_file" "payload.txt")
    428 payload_blob_prefix=$(id_prefix "$payload_blob_for_external")
    429 cp -R "$work/ext-thin" "$work/ext-thin-bad-chunk"
    430 printf tamper >> "$work/ext-thin-bad-chunk/chunk/$payload_blob_prefix/$payload_blob_for_external/0"
    431 run_fail "native-external-mutated-chunk-fails" "$KIT" pkg verify \
    432     -p "$work/key.pub" --external "$work/ext-thin-bad-chunk" \
    433     "$work/pkg/matrix-thin.kpkg"
    434 
    435 cp -R "$work/ext-thin" "$work/ext-thin-bad-tree"
    436 printf tamper >> "$(cas_object_path "$work/ext-thin-bad-tree" tree "$tree_id")"
    437 run_fail "native-external-mutated-tree-fails" "$KIT" pkg verify \
    438     -p "$work/key.pub" --external "$work/ext-thin-bad-tree" \
    439     "$work/pkg/matrix-thin.kpkg"
    440 
    441 if have_cmd perl; then
    442     extract_kpkg3_descriptor "$work/pkg/matrix-thin.kpkg" "$work/native-thin.descriptor"
    443     thin_index_rel=$(descriptor_value "$work/native-thin.descriptor" "index-url")
    444     cp -R "$work/ext-thin" "$work/ext-thin-bad-index"
    445     printf tamper >> "$work/ext-thin-bad-index/$thin_index_rel"
    446     run_fail "native-external-mutated-index-fails" "$KIT" pkg verify \
    447         -p "$work/key.pub" --external "$work/ext-thin-bad-index" \
    448         "$work/pkg/matrix-thin.kpkg"
    449 else
    450     skip_test "native-external-mutated-index-fails"
    451 fi
    452 
    453 run_ok "host-gzip-accepts-kit-output" gzip -t "$work/pkg/matrix.tar.gz"
    454 if gunzip -c "$work/pkg/matrix.tar.gz" > "$work/pkg/matrix.tar" 2> "$work/gunzip.err" &&
    455    gzip -c "$work/pkg/matrix.tar" > "$work/pkg/host.tar.gz" 2> "$work/regzip.err"; then
    456     run_ok "pkg-inspect-host-gzip" "$KIT" pkg inspect "$work/pkg/host.tar.gz"
    457     run_ok "pkg-verify-host-gzip" "$KIT" pkg verify -p "$work/key.pub" "$work/pkg/host.tar.gz"
    458 else
    459     not_ok "pkg-inspect-host-gzip" "$work/gunzip.err"
    460     not_ok "pkg-verify-host-gzip" "$work/regzip.err"
    461 fi
    462 
    463 run_ok "pkg-create-infer-targz" "$KIT" pkg create \
    464     --name matrix-test --version 1.0.0 --root "$work/in" -s "$work/key.key" \
    465     -o "$work/pkg/infer.tar.gz"
    466 run_ok "pkg-create-infer-kpkg" "$KIT" pkg create \
    467     --name matrix-test --version 1.0.0 --root "$work/in" -s "$work/key.key" \
    468     -o "$work/pkg/infer.kpkg"
    469 run_fail "pkg-create-unknown-extension-needs-format" "$KIT" pkg create \
    470     --name matrix-test --version 1.0.0 -s "$work/key.key" \
    471     --root "$work/in" -o "$work/pkg/unknown.pkg"
    472 run_ok "pkg-create-override-targz-extension" "$KIT" pkg create \
    473     --name matrix-test --version 1.0.0 --format tar.gz -s "$work/key.key" \
    474     --root "$work/in" -o "$work/pkg/override.pkg"
    475 run_ok "pkg-verify-override-targz-extension" "$KIT" pkg verify -p "$work/key.pub" \
    476     --format tar.gz "$work/pkg/override.pkg"
    477 run_fail "pkg-verify-wrong-format-native" "$KIT" pkg verify -p "$work/key.pub" \
    478     --format kpkg "$work/pkg/matrix.tar.gz"
    479 run_fail "pkg-verify-wrong-format-portable" "$KIT" pkg verify -p "$work/key.pub" \
    480     --format tar.gz "$work/pkg/matrix-none.kpkg"
    481 
    482 run_fail "pkg-verify-untrusted-no-key" "$KIT" pkg verify "$work/pkg/matrix.tar.gz"
    483 run_ok "pkg-trust-path" "$KIT" pkg trust path
    484 contains "pkg-trust-path-output" "$work/pkg-trust-path.out" "$KIT_TRUSTED_KEYS"
    485 run_ok "pkg-trust-list-empty" "$KIT" pkg trust list
    486 contains "pkg-trust-list-empty-message" "$work/pkg-trust-list-empty.out" "(no trusted keys"
    487 run_ok "pkg-trust-add" "$KIT" pkg trust add "$work/key.pub" matrix-label
    488 run_ok "pkg-trust-list-added" "$KIT" pkg trust list
    489 contains "pkg-trust-list-added-key" "$work/pkg-trust-list-added.out" "$keyid"
    490 contains "pkg-trust-list-added-label" "$work/pkg-trust-list-added.out" "matrix-label"
    491 run_ok "pkg-verify-trusted-store" "$KIT" pkg verify "$work/pkg/matrix.tar.gz"
    492 run_ok "pkg-trust-remove" "$KIT" pkg trust remove "$keyid"
    493 run_ok "pkg-trust-list-removed" "$KIT" pkg trust list
    494 not_contains "pkg-trust-list-removed-key" "$work/pkg-trust-list-removed.out" "$keyid"
    495 run_fail "pkg-verify-after-trust-remove" "$KIT" pkg verify "$work/pkg/matrix.tar.gz"
    496 
    497 mkdir -p "$work/tofu-home"
    498 run_ok "pkg-verify-tofu-pins" env HOME="$work/tofu-home" KIT_TRUSTED_KEYS="$work/tofu.keys" \
    499     "$KIT" pkg verify --tofu "$work/pkg/matrix.tar.gz"
    500 contains "pkg-tofu-file-key" "$work/tofu.keys" "$keyid"
    501 run_ok "pkg-verify-tofu-store" env HOME="$work/tofu-home" KIT_TRUSTED_KEYS="$work/tofu.keys" \
    502     "$KIT" pkg verify "$work/pkg/matrix.tar.gz"
    503 
    504 run_ok "pkg-keygen-wrong" "$KIT" pkg keygen -o "$work/wrong"
    505 run_fail "pkg-verify-wrong-pubkey" "$KIT" pkg verify -p "$work/wrong.pub" "$work/pkg/matrix.tar.gz"
    506 
    507 if have_cmd tar; then
    508     extract_targz "$work/pkg/matrix.tar.gz" "$work/tar-ok"
    509     tar_tree_file=$(cas_object_path "$work/tar-ok/kit/cas" tree "$tree_id")
    510     for f in kit/package.manifest kit/package.manifest.minisig kit/package.pub; do
    511         safe_f=$(printf '%s\n' "$f" | sed 's#[^A-Za-z0-9_.-]#-#g')
    512         if [ -f "$work/tar-ok/$f" ]; then
    513             ok "portable-member-$f"
    514         else
    515             echo "missing tar member: $f" > "$work/portable-member-$safe_f.diag"
    516             not_ok "portable-member-$f" "$work/portable-member-$safe_f.diag"
    517         fi
    518     done
    519     assert_file_exists "portable-member-tree-object" "$tar_tree_file"
    520     same_file "portable-tree-matches-cas" "$tree_file" "$tar_tree_file"
    521     for f in $artifacts; do
    522         blob=$(tree_blob_for_path "$tar_tree_file" "$f")
    523         blob_file=$(cas_object_path "$work/tar-ok/kit/cas" blob "$blob")
    524         safe_f=$(printf '%s\n' "$f" | sed 's#[^A-Za-z0-9_.-]#-#g')
    525         assert_file_exists "portable-member-blob-$safe_f" "$blob_file"
    526     done
    527     if [ -f "$work/tar-ok/payload.txt" ] || [ -f "$work/tar-ok/bin/tool.sh" ]; then
    528         echo "portable archive stored output files outside kit/cas" > "$work/portable-no-root-files.diag"
    529         not_ok "portable-no-root-files" "$work/portable-no-root-files.diag"
    530     else
    531         ok "portable-no-root-files"
    532     fi
    533 
    534     extract_targz "$work/pkg/matrix-alt-version.tar.gz" "$work/tar-alt-version"
    535     contains "portable-alt-manifest-tree-same" \
    536         "$work/tar-alt-version/kit/package.manifest" "tree = $tree_id"
    537     not_same_file "portable-metadata-changes-manifest" \
    538         "$work/tar-ok/kit/package.manifest" \
    539         "$work/tar-alt-version/kit/package.manifest"
    540     same_file "portable-metadata-keeps-tree-object" \
    541         "$tar_tree_file" \
    542         "$(cas_object_path "$work/tar-alt-version/kit/cas" tree "$tree_id")"
    543 
    544     cp -R "$work/tar-ok" "$work/tar-missing-manifest"
    545     rm -f "$work/tar-missing-manifest/kit/package.manifest"
    546     repack_targz "$work/tar-missing-manifest" "$work/pkg/bad-missing-manifest.tar.gz"
    547     run_fail "portable-missing-manifest-fails" "$KIT" pkg verify -p "$work/key.pub" \
    548         "$work/pkg/bad-missing-manifest.tar.gz"
    549 
    550     cp -R "$work/tar-ok" "$work/tar-missing-signature"
    551     rm -f "$work/tar-missing-signature/kit/package.manifest.minisig"
    552     repack_targz "$work/tar-missing-signature" "$work/pkg/bad-missing-signature.tar.gz"
    553     run_fail "portable-missing-signature-fails" "$KIT" pkg verify -p "$work/key.pub" \
    554         "$work/pkg/bad-missing-signature.tar.gz"
    555 
    556     cp -R "$work/tar-ok" "$work/tar-missing-tree"
    557     rm -f "$(cas_object_path "$work/tar-missing-tree/kit/cas" tree "$tree_id")"
    558     repack_targz "$work/tar-missing-tree" "$work/pkg/bad-missing-tree.tar.gz"
    559     run_fail "portable-missing-tree-fails" "$KIT" pkg verify -p "$work/key.pub" \
    560         "$work/pkg/bad-missing-tree.tar.gz"
    561 
    562     payload_blob=$(tree_blob_for_path "$tar_tree_file" "payload.txt")
    563     cp -R "$work/tar-ok" "$work/tar-missing-blob"
    564     rm -f "$(cas_object_path "$work/tar-missing-blob/kit/cas" blob "$payload_blob")"
    565     repack_targz "$work/tar-missing-blob" "$work/pkg/bad-missing-blob.tar.gz"
    566     run_fail "portable-missing-blob-fails" "$KIT" pkg verify -p "$work/key.pub" \
    567         "$work/pkg/bad-missing-blob.tar.gz"
    568 
    569     cp -R "$work/tar-ok" "$work/tar-mutated-blob"
    570     printf tamper >> "$(cas_object_path "$work/tar-mutated-blob/kit/cas" blob "$payload_blob")"
    571     repack_targz "$work/tar-mutated-blob" "$work/pkg/bad-mutated-blob.tar.gz"
    572     run_fail "portable-mutated-blob-fails" "$KIT" pkg verify -p "$work/key.pub" \
    573         "$work/pkg/bad-mutated-blob.tar.gz"
    574 
    575     cp -R "$work/tar-ok" "$work/tar-mutated-tree"
    576     printf '\n# tamper\n' >> "$(cas_object_path "$work/tar-mutated-tree/kit/cas" tree "$tree_id")"
    577     repack_targz "$work/tar-mutated-tree" "$work/pkg/bad-mutated-tree.tar.gz"
    578     run_fail "portable-mutated-tree-fails" "$KIT" pkg verify -p "$work/key.pub" \
    579         "$work/pkg/bad-mutated-tree.tar.gz"
    580 
    581     cp -R "$work/tar-ok" "$work/tar-mutated-manifest"
    582     printf '\n# tamper\n' >> "$work/tar-mutated-manifest/kit/package.manifest"
    583     repack_targz "$work/tar-mutated-manifest" "$work/pkg/bad-mutated-manifest.tar.gz"
    584     run_fail "portable-mutated-manifest-fails" "$KIT" pkg verify -p "$work/key.pub" \
    585         "$work/pkg/bad-mutated-manifest.tar.gz"
    586 else
    587     skip_test "portable-tar-member-and-repack-tests"
    588 fi
    589 
    590 cp "$work/pkg/matrix.tar.gz" "$work/pkg/bad-gzip-byte.tar.gz"
    591 flip_byte "$work/pkg/bad-gzip-byte.tar.gz" 0
    592 run_fail "portable-corrupt-gzip-fails" "$KIT" pkg verify -p "$work/key.pub" \
    593     "$work/pkg/bad-gzip-byte.tar.gz"
    594 
    595 cp "$work/pkg/matrix-none.kpkg" "$work/pkg/bad-native-magic.kpkg"
    596 flip_byte "$work/pkg/bad-native-magic.kpkg" 0
    597 run_fail "native-bad-magic-fails" "$KIT" pkg verify -p "$work/key.pub" \
    598     "$work/pkg/bad-native-magic.kpkg"
    599 
    600 dd if="$work/pkg/matrix-none.kpkg" of="$work/pkg/bad-native-truncated.kpkg" \
    601     bs=1 count=100 >/dev/null 2>&1
    602 run_fail "native-truncated-fails" "$KIT" pkg verify -p "$work/key.pub" \
    603     "$work/pkg/bad-native-truncated.kpkg"
    604 
    605 cp "$work/pkg/matrix-none.kpkg" "$work/pkg/bad-native-manifest.kpkg"
    606 if have_cmd perl; then
    607     manifest_off=$(kpkg3_field_offset "$work/pkg/matrix-none.kpkg" 0)
    608     flip_byte "$work/pkg/bad-native-manifest.kpkg" "$manifest_off"
    609     run_fail "native-mutated-manifest-fails" "$KIT" pkg verify -p "$work/key.pub" \
    610         "$work/pkg/bad-native-manifest.kpkg"
    611 else
    612     skip_test "native-mutated-manifest-fails"
    613 fi
    614 
    615 if have_cmd perl; then
    616     descriptor_off=$(kpkg3_field_offset "$work/pkg/matrix-none.kpkg" 4)
    617     extract_kpkg3_descriptor "$work/pkg/matrix-none.kpkg" "$work/native-corrupt.descriptor"
    618 
    619     cp "$work/pkg/matrix-none.kpkg" "$work/pkg/bad-native-descriptor.kpkg"
    620     flip_byte "$work/pkg/bad-native-descriptor.kpkg" "$descriptor_off"
    621     run_fail "native-mutated-descriptor-fails" "$KIT" pkg verify -p "$work/key.pub" \
    622         "$work/pkg/bad-native-descriptor.kpkg"
    623 
    624     maybe_corrupt_native_region "native-mutated-tree-region-fails" \
    625         "$work/pkg/matrix-none.kpkg" "$work/native-corrupt.descriptor" "tree-offset"
    626     maybe_corrupt_native_region "native-mutated-index-fails" \
    627         "$work/pkg/matrix-none.kpkg" "$work/native-corrupt.descriptor" "index-offset"
    628     maybe_corrupt_native_region "native-mutated-content-fails" \
    629         "$work/pkg/matrix-none.kpkg" "$work/native-corrupt.descriptor" "content-offset"
    630 else
    631     skip_test "native-region-offset-corruption-tests"
    632 fi
    633 
    634 run_fail "pkg-create-missing-required-fails" "$KIT" pkg create \
    635     --name missing-version -s "$work/key.key" --root "$work/in" -o "$work/pkg/missing.tar.gz"
    636 run_fail "pkg-create-unknown-format-fails" "$KIT" pkg create \
    637     --name matrix-test --version 1.0.0 --format nope -s "$work/key.key" \
    638     --root "$work/in" -o "$work/pkg/badformat.tar.gz"
    639 run_fail "pkg-create-unknown-compression-fails" "$KIT" pkg create \
    640     --name matrix-test --version 1.0.0 --format kpkg --compression nope \
    641     -s "$work/key.key" --root "$work/in" -o "$work/pkg/badcomp.kpkg"
    642 mkdir -p "$work/dup/a" "$work/dup/b"
    643 printf one > "$work/dup/a/same.dat"
    644 printf two > "$work/dup/b/same.dat"
    645 cat > "$work/dup.map" <<EOF
    646 same.dat - $work/dup/a/same.dat
    647 same.dat - $work/dup/b/same.dat
    648 EOF
    649 run_fail "pkg-cas-duplicate-tree-path-fails" "$KIT" cas add-tree \
    650     --cas "$work/cas" --map "$work/dup.map"
    651 printf unsafe > "$work/in/bad\\path.dat"
    652 cat > "$work/unsafe.map" <<EOF
    653 bad\\path.dat - $work/in/bad\\path.dat
    654 EOF
    655 run_fail "pkg-cas-unsafe-tree-path-fails" "$KIT" cas add-tree \
    656     --cas "$work/cas" --map "$work/unsafe.map"
    657 run_fail "pkg-verify-missing-file-fails" "$KIT" pkg verify -p "$work/key.pub" \
    658     "$work/pkg/does-not-exist.tar.gz"
    659 printf not-a-package > "$work/not-a-package.kpkg"
    660 run_fail "pkg-inspect-malformed-fails" "$KIT" pkg inspect "$work/not-a-package.kpkg"
    661 run_fail "pkg-trust-add-missing-pubkey-fails" "$KIT" pkg trust add
    662 run_fail "pkg-trust-remove-bad-keyid-fails" "$KIT" pkg trust remove xyz
    663 
    664 kit_summary pkg
    665 kit_exit