#!/bin/sh
# Attest a completed build only when it is an exact copy of a CCL kernel whose
# source tree contains every required patch.
set -eu
cd "$(dirname "$0")/.."
unset GIT_DIR GIT_WORK_TREE GIT_COMMON_DIR GIT_INDEX_FILE
unset GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES
if ! scripts/build-lock-held; then
    exec scripts/with-build-lock scripts/attest-build "$@"
fi

if [ "$#" -ne 3 ]; then
    echo "usage: scripts/attest-build CCL-SOURCE CCL ATTESTATION" >&2
    exit 2
fi

ccl_source=$(realpath -e "$1")
if ! scripts/ccl-lock-held "$ccl_source"; then
    exec scripts/with-ccl-lock \
        "$ccl_source" scripts/attest-build "$ccl_source" "$2" "$3"
fi
ccl_command=$2
if ! ccl_path=$(command -v "$ccl_command"); then
    echo "cclsh attestation: selected CCL is unavailable: $ccl_command" >&2
    exit 1
fi
ccl_kernel=$(realpath -e "$ccl_path")
attestation_argument=$3
attestation_name=$(basename -- "$attestation_argument")
case "$attestation_name" in
    ''|.|..|/)
        echo "cclsh attestation: invalid attestation path" >&2
        exit 2
        ;;
esac
if ! attestation_parent=$(
    realpath -e -- "$(dirname -- "$attestation_argument")"
) || [ ! -d "$attestation_parent" ]
then
    echo "cclsh attestation: attestation directory does not exist" >&2
    exit 2
fi
attestation=$attestation_parent/$attestation_name
if [ -e "$attestation" ] || [ -L "$attestation" ]; then
    if [ ! -f "$attestation" ] || [ -L "$attestation" ]; then
        echo "cclsh attestation: destination is not a regular file" >&2
        exit 1
    fi
fi
set -- patches/ccl-linux-xstate.patch patches/ccl-cclsh-argv.patch
source_kernel=$(realpath -e "$ccl_source/lx86cl64")
if [ "$ccl_kernel" != "$source_kernel" ]; then
    echo "cclsh attestation: selected CCL is not $source_kernel" >&2
    exit 1
fi
if ! make -q -C "$ccl_source/lisp-kernel/linuxx8664"; then
    echo "cclsh attestation: verified CCL kernel is out of date" >&2
    exit 1
fi
resolved_kernel=$(realpath -e cclsh)
resolved_image=$resolved_kernel.image
if ! cmp -s "$resolved_kernel" "$source_kernel"; then
    echo "cclsh attestation: built kernel differs from the verified CCL" >&2
    exit 1
fi
if [ ! -f "$resolved_image" ] || ! cmp -s cclsh.image "$resolved_image"; then
    echo "cclsh attestation: active image is not adjacent to its kernel" >&2
    exit 1
fi
if ! scripts/verify-argument-boundary "$resolved_kernel" "$resolved_image"; then
    echo "cclsh attestation: kernel failed its argument check" >&2
    exit 1
fi
for patch in "$@"; do
    if ! git -C "$ccl_source" apply --reverse --check "$PWD/$patch" \
         >/dev/null 2>&1
    then
        echo "cclsh attestation: CCL patch is not applied: $patch" >&2
        exit 1
    fi
done

if ! kernel_hash=$(scripts/file-sha256 "$resolved_kernel"); then
    exit 1
fi
if ! image_hash=$(scripts/file-sha256 "$resolved_image"); then
    exit 1
fi
temporary=$(mktemp "$attestation_parent/.cclsh-attestation.XXXXXX")
cleanup()
{
    rm -f -- "$temporary"
}
trap cleanup 0
trap 'exit 129' 1
trap 'exit 130' 2
trap 'exit 143' 15
chmod 600 "$temporary"
{
    printf '%s\n' 'cclsh-login-build-v1'
    printf 'kernel-sha256 %s\n' "$kernel_hash"
    printf 'image-sha256 %s\n' "$image_hash"
    for patch in "$@"; do
        if ! patch_hash=$(scripts/file-sha256 "$patch"); then
            exit 1
        fi
        printf 'patch-sha256 %s %s\n' \
            "$(basename "$patch")" \
            "$patch_hash"
    done
} >"$temporary"
scripts/verify-attestation \
    "$resolved_kernel" "$resolved_image" "$temporary"
mv -Tf -- "$temporary" "$attestation"
temporary=
sync -f "$attestation"
sync -f "$attestation_parent"
printf 'Attested login build in %s\n' "$attestation"
