diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ea284a3641..49c17b8c8d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,15 +5,47 @@ on: - dasharo jobs: - build_novacustom: +# build_novacustom: +# runs-on: ubuntu-22.04 +# container: +# image: coreboot/coreboot-sdk:2021-09-23_b0d87f753c +# options: --user 1001 +# strategy: +# matrix: +# vendor: [ novacustom ] +# model: [ nv4x_adl, ns5x_adl, nv4x_tgl, ns5x_tgl ] +# steps: +# - name: Checkout repository +# uses: actions/checkout@v3 +# with: +# # Checkout pull request HEAD commit instead of merge commit +# # See: https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit +# ref: ${{ github.event.pull_request.head.sha }} +# # Fetch complete history +# fetch-depth: 0 +# - name: Checkout all submodules +# run: git submodule update --init --recursive --checkout +# - name: Build Dasharo +# run: | +# cp configs/config.${{ matrix.vendor }}_${{ matrix.model }} .config +# make olddefconfig +# make +# - name: Save artifacts +# uses: actions/upload-artifact@v2 +# with: +# name: "dasharo-${{ matrix.vendor }}-${{ matrix.model }}-${{ matrix.build }}" +# path: | +# build/coreboot.rom +# retention-days: 30 + build_msi: runs-on: ubuntu-22.04 container: image: coreboot/coreboot-sdk:2021-09-23_b0d87f753c options: --user 1001 strategy: matrix: - vendor: [ novacustom ] - model: [ nv4x_adl, ns5x_adl, nv4x_tgl, ns5x_tgl ] + vendor: [ msi ] + model: [ ms7d25_ddr5 ] steps: - name: Checkout repository uses: actions/checkout@v3 @@ -30,73 +62,95 @@ jobs: cp configs/config.${{ matrix.vendor }}_${{ matrix.model }} .config make olddefconfig make + - name: Create patched binary with pre-enabled serial output + run: | + cp build/coreboot.rom build/coreboot_serial_enabled.rom + build/util/cbfstool/cbfstool build/coreboot_serial_enabled.rom write -r SMMSTORE -f ci/smmstore-serial-enabled - name: Save artifacts uses: actions/upload-artifact@v2 with: name: "dasharo-${{ matrix.vendor }}-${{ matrix.model }}-${{ matrix.build }}" path: | build/coreboot.rom + build/coreboot_serial_enabled.rom retention-days: 30 - build_msi: - runs-on: ubuntu-22.04 - container: - image: coreboot/coreboot-sdk:2021-09-23_b0d87f753c - options: --user 1001 +# build_protectli: +# environment: Protectli +# runs-on: ubuntu-22.04 +# strategy: +# matrix: +# vendor: [ protectli ] +# model: [ vp46xx ] +# steps: +# - name: Checkout repository +# uses: actions/checkout@v3 +# with: +# # Checkout pull request HEAD commit instead of merge commit +# # See: https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit +# ref: ${{ github.event.pull_request.head.sha }} +# # Fetch complete history +# fetch-depth: 0 +# - name: Checkout all submodules +# run: git submodule update --init --recursive --checkout +# - name: Obtain Blobs +# shell: bash +# env: +# SSH_KEY: ${{secrets.PROTECTLI_BLOBS_KEY}} +# BLOB_REPO: ${{secrets.PROTECTLI_BLOBS_REPO}} +# run: | +# eval `ssh-agent -s` +# echo "${SSH_KEY}" | ssh-add - +# git clone $BLOB_REPO +# cp -r protectli-blobs/protectli/ 3rdparty/blobs/mainboard/ +# - name: Build Dasharo +# run: | +# ./build.sh ${{ matrix.model }} + test_msi: + runs-on: self-hosted strategy: matrix: vendor: [ msi ] - model: [ ms7d25_ddr4, ms7d25_ddr5, ms7e06_ddr4, ms7e06_ddr5 ] + model: [ ms7d25_ddr5 ] + needs: [build_msi] steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v2 with: - # Checkout pull request HEAD commit instead of merge commit - # See: https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit - ref: ${{ github.event.pull_request.head.sha }} - # Fetch complete history - fetch-depth: 0 - - name: Checkout all submodules - run: git submodule update --init --recursive --checkout - - name: Build Dasharo - run: | - cp configs/config.${{ matrix.vendor }}_${{ matrix.model }} .config - make olddefconfig - make - - name: Save artifacts - uses: actions/upload-artifact@v2 + python-version: '3.11' + + - name: Fetch CI script + uses: actions/checkout@v4 with: - name: "dasharo-${{ matrix.vendor }}-${{ matrix.model }}-${{ matrix.build }}" - path: | - build/coreboot.rom - retention-days: 30 - build_protectli: - environment: Protectli - runs-on: ubuntu-22.04 - strategy: - matrix: - vendor: [ protectli ] - model: [ vp46xx ] - steps: - - name: Checkout repository - uses: actions/checkout@v3 + sparse-checkout: ci + sparse-checkout-cone-mode: false + + - name: Checkout test repository + uses: actions/checkout@v4 with: - # Checkout pull request HEAD commit instead of merge commit - # See: https://github.com/actions/checkout#checkout-pull-request-head-commit-instead-of-merge-commit - ref: ${{ github.event.pull_request.head.sha }} - # Fetch complete history - fetch-depth: 0 - - name: Checkout all submodules - run: git submodule update --init --recursive --checkout - - name: Obtain Blobs - shell: bash - env: - SSH_KEY: ${{secrets.PROTECTLI_BLOBS_KEY}} - BLOB_REPO: ${{secrets.PROTECTLI_BLOBS_REPO}} - run: | - eval `ssh-agent -s` - echo "${SSH_KEY}" | ssh-add - - git clone $BLOB_REPO - cp -r protectli-blobs/protectli/ 3rdparty/blobs/mainboard/ - - name: Build Dasharo + repository: Dasharo/open-source-firmware-validation + path: validation + submodules: true + + - name: Install dependencies run: | - ./build.sh ${{ matrix.model }} + python -m pip install --upgrade pip + pip install -r validation/requirements.txt + + - name: Fetch latest firmware + uses: actions/download-artifact@v3 + with: + name: dasharo-${{ matrix.vendor }}-${{ matrix.model }}-${{ matrix.build }} + path: firmware + + - name: Flash firmware + shell: bash + run: ./ci/ci.sh -r validation -v "${{ matrix.vendor }}" -m "${{ matrix.model }}" -f firmware/coreboot_serial_enabled.rom flash + + - name: Run tests + shell: bash + run: ./ci/ci.sh -r validation -v "${{ matrix.vendor }}" -m "${{ matrix.model }}" -f firmware/coreboot_serial_enabled.rom test + + - name: Upload test results + uses: actions/upload-artifact@v3 + with: + name: test-results-${{ matrix.vendor }}-${{ matrix.model }} diff --git a/ci/ci.sh b/ci/ci.sh new file mode 100755 index 00000000000..05d65a4b032 --- /dev/null +++ b/ci/ci.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash + +set -euo pipefail + +script_dir="$(dirname "${BASH_SOURCE[0]}")" + +vendor="" +model="" + +usage() { + echo "Usage: ci.sh -v vendor -m model -f firmware command" 1>&2 + exit 1 +} + +while getopts "r:v:m:f:" o; do + case "${o}" in + r) root="${OPTARG}" ;; + v) vendor="${OPTARG}" ;; + m) model="${OPTARG}" ;; + f) fw_file="${OPTARG}" ;; + *) usage ;; + esac +done +shift $((OPTIND-1)) + +[ -n "$vendor" ] || usage +[ -n "$model" ] || usage +[ $# -eq 1 ] || usage + +command="$1" +[[ "$command" =~ ^(flash|test)$ ]] || usage +shift 1 + +options=( + -L TRACE + -v snipeit:none +) + +compatibility_tests=() +performance_tests=() +security_tests=() +stability_tests=() + +case "$vendor" in + msi) + case "$model" in + ms7d25_ddr5) + device_ip="192.168.10.93" + rte_ip="192.168.10.188" + pikvm_ip="192.168.10.45" + config="msi-pro-z690-a-ddr5" + ;; + *) + echo unknown board: $model + exit 1 + ;; + esac + ;; + *) + echo unknown vendor: $vendor + exit 1 + ;; +esac + +options+=( + -v device_ip:$device_ip + -v rte_ip:$rte_ip + -v pikvm_ip:$pikvm_ip + -v config:$config + -v snipeit:no +) + +if [ "$command" == "flash" ]; then + "$script_dir/scp.py" "$rte_ip" "$fw_file" /tmp/dasharo.rom + "$script_dir/ssh.py" "$rte_ip" /home/root/flash.sh /tmp/dasharo.rom + exit 0 +fi + +case "$vendor" in + msi) + case "$model" in + ms7d25_ddr5) + compatibility_tests+=( + custom-boot-menu-key + ) + + security_tests+=( + me-neuter + ) + ;; + *) + echo unknown board: $model + exit 1 + ;; + esac + ;; + *) + echo unknown vendor: $vendor + exit 1 + ;; +esac + +mkdir -p "test-results-$vendor-$model" + +run_robot() { + local category="$1" + local test="$2" + + robot -l "test-results-$vendor-$model/dasharo-${category}.log.html" \ + -r "test-results-$vendor-$model/dasharo-${category}.html" \ + -o "test-results-$vendor-$model/dasharo-${category}.xml" \ + ${options[@]} "$root/dasharo-${category}/$test.robot" +} + +if [ "$command" == "test" ]; then + for test in "${compatibility_tests[@]}"; do + run_robot compatibility "$test" + done + + for test in "${performance_tests[@]}"; do + run_robot performance "$test" + done + + for test in "${security_tests[@]}"; do + run_robot security "$test" + done + + for test in "${stability_tests[@]}"; do + run_robot stability "$test" + done +fi diff --git a/ci/scp.py b/ci/scp.py new file mode 100755 index 00000000000..1c57d7484b2 --- /dev/null +++ b/ci/scp.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +from argparse import ArgumentParser +import paramiko + +def main(): + parser = ArgumentParser() + parser.add_argument("host") + parser.add_argument("local") + parser.add_argument("remote") + args = parser.parse_args() + + client = paramiko.client.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(args.host, username="root", password="meta-rte") + + ftp = client.open_sftp() + ftp.put(args.local, args.remote) + ftp.close() + +if __name__ == '__main__': + main() diff --git a/ci/smmstore-serial-enabled b/ci/smmstore-serial-enabled new file mode 100644 index 00000000000..76eefc9d761 Binary files /dev/null and b/ci/smmstore-serial-enabled differ diff --git a/ci/ssh.py b/ci/ssh.py new file mode 100755 index 00000000000..4dc30d75142 --- /dev/null +++ b/ci/ssh.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +from argparse import ArgumentParser, REMAINDER +from select import select +import paramiko +import sys +import os + +def main(): + parser = ArgumentParser() + parser.add_argument("host") + parser.add_argument("command") + parser.add_argument("args", nargs=REMAINDER) + args = parser.parse_args() + + client = paramiko.client.SSHClient() + client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + client.connect(args.host, username="root", password="meta-rte") + + cmd = f"{args.command} " + for arg in args.args: + cmd += f'\'{arg}\' ' + + transport = client.get_transport() + channel = transport.open_session() + channel.exec_command(cmd) + + while True: + if channel.exit_status_ready(): + break + rl, _wl, _xl = select([channel], [], []) + if len(rl) > 0: + if channel.recv_ready(): + data = channel.recv(1024) + os.write(sys.stdout.fileno(), data) + + if channel.recv_stderr_ready(): + data = channel.recv_stderr(1024) + os.write(sys.stderr.fileno(), data) + +if __name__ == '__main__': + main()