Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Docker container action for OTA releases #1

Merged
merged 2 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: 'Test OTA Release'

on:
push:
branches:
- 'main'
pull_request:
branches:
- 'main'

jobs:
test_ota_release:
name: 'Test OTA Release Action'
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout'
uses: 'actions/checkout@v4'

- name: 'Create artifacts for test'
run: |
mkdir -p artifacts
hello_time="$(date +'%Y-%m-%dT%H:%M:%S%z')"
echo "${hello_time}: Hello, World!" > artifacts/hello.txt
sleep 4.2
goodbye_time="$(date +'%Y-%m-%dT%H:%M:%S%z')"
echo "${goodbye_time}: Goodbye, World!" > artifacts/goodbye.txt

- name: 'Test OTA Release'
uses: './' # Use an action in the root directory
with:
release_type: 'file'
persist_dir: '/tmp/persist'
artifacts_dir: 'artifacts'
base_install_path_on_device: '/tmp/ota'
project_access_token: ${{ secrets.TEST_PROJECT_ACCESS_TOKEN }}
signing_key_mangement: 'local'
signing_key: ${{ secrets.TEST_SIGNING_KEY }}
signing_key_password: ${{ secrets.TEST_SIGNING_KEY_PASSWORD }}
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# See https://help.github.com/articles/about-codeowners/
* @thistletech/engineering
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM alpine:3.10

RUN apk add --no-cache bash curl gzip

COPY entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
47 changes: 47 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: 'Create OTA Release'
description: 'Creates OTA update releases'
author: 'Ning Shang (Thistle Technologies)'
inputs:
release_type:
description: 'Release type ("file", "zip_archive", or "rootfs")'
required: true
default: 'file'
persist_dir:
description: 'Path to the directory where the device can persist data'
required: true
default: ''
artifacts_dir:
description: 'Path to the directory where OTA update artifacts are stored'
required: false
default: ''
rootfs_img_path:
description: 'Path to the rootfs image file. Required only if release_type is "rootfs"'
required: false
default: ''
zip_archive_path:
description: 'Path to the zip archive file. Required only if release_type is "archive"'
required: false
default: ''
base_install_path_on_device:
description: 'Path to base directory on device file system where OTA update artifacts will be installed. Required if release_type is "file" or "archive"'
required: false
default: ''
project_access_token:
description: 'Project access token can be obtained from the project settings page in Thistle Control Center'
required: true
default: ''
signing_key_mangement:
description: 'Incidates how the signing key is managed ("local" or "remote")'
required: true
default: 'local'
signing_key:
description: 'Minisign signing key in Thistle format. Required only if signing_key_mangement is "local"'
required: false
default: ''
signing_key_password:
description: 'Password for the signing key. Required only if signing_key_mangement is "local" and the signing key is password protected'
required: false
default: ''
runs:
using: 'docker'
image: 'Dockerfile'
97 changes: 97 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bash
#
# Environment variables:
# They are created from an input in a workflow file or a default value by
# GitHub, with the name INPUT_<VARIABLE_NAME>. Cf.,
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions.
#
# The following environment variables correspond to the input identifiers in
# action.yml.
#
# INPUT_RELEASE_TYPE
# INPUT_PERSIST_DIR
# INPUT_ARTIFACTS_DIR
# INPUT_ROOTFS_IMG_PATH
# INPUT_ZIP_ARCHIVE_PATH
# INPUT_BASE_INSTALL_PATH_ON_DEVICE
# INPUT_PROJECT_ACCESS_TOKEN
# INPUT_SIGNING_KEY_MANAGEMENT
# INPUT_SIGNING_KEY
# INPUT_SIGNING_KEY_PASSWORD
#

set -euxo pipefail

SCRIPT_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
readonly SCRIPT_DIR
TRH_BINARY_PATH="${SCRIPT_DIR}/trh"
readonly TRH_BINARY_PATH
TRH_DOWNLOAD_URL="https://downloads.thistle.tech/embedded-client/1.0.0/trh-1.0.0-x86_64-unknown-linux-musl.gz"
readonly TRH_DOWNLOAD_URL

# Set environment variables
export THISTLE_KEY="${HOME}/.minisign/minisign.key"
export THISTLE_KEY_PASS="${INPUT_SIGNING_KEY_PASSWORD}"
export THISTLE_TOKEN="${INPUT_PROJECT_ACCESS_TOKEN}"

download_trh() {
curl -A "curl (ota_release_action)" -L -o /tmp/trh.gz "${TRH_DOWNLOAD_URL}"
gunzip -c /tmp/trh.gz > "${TRH_BINARY_PATH}"
chmod +x "${TRH_BINARY_PATH}"
"${TRH_BINARY_PATH}" --version
}

file_release() {
# Hack alert: Need to do this to get a manifest template
mkdir -p "$(dirname "${THISTLE_KEY}")"
echo "${INPUT_SIGNING_KEY}" > "${THISTLE_KEY}"
cat "${THISTLE_KEY}"
"${TRH_BINARY_PATH}" init --persist="${INPUT_PERSIST_DIR}"

local artifacts_dir="${INPUT_ARTIFACTS_DIR:-}"
local base_install_path="${INPUT_BASE_INSTALL_PATH_ON_DEVICE:-}"
[ -z "${artifacts_dir}" ] && { echo "No artifacts directory provided"; exit 1; }
[ -z "${base_install_path}" ] && { echo "No base install path provided"; exit 1; }

"${TRH_BINARY_PATH}" prepare --target="${artifacts_dir}" --file-base-path="${base_install_path}"

"${TRH_BINARY_PATH}" release

echo "done"
}

rootfs_release() {
echo "Not implemented"
exit 1
}

zip_archive_release() {
echo "Not implemented"
exit 1
}

do_it() {

local release_type="${INPUT_RELEASE_TYPE:-}"
[ -z "${release_type}" ] && { echo "No release type provided"; exit 1; }

download_trh

case "${INPUT_RELEASE_TYPE}" in
"file")
file_release
;;
"rootfs")
rootfs_release
;;
"zip_archive")
zip_archive_release
;;
*)
echo "Unknown release type: ${INPUT_RELEASE_TYPE}"
exit 1
;;
esac
}

do_it