Skip to content

Commit

Permalink
Add Docker container action for OTA releases (#1)
Browse files Browse the repository at this point in the history
* Add Docker container action for OTA releases

Create a Docker container action (cf.
https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action)
for OTA releases. In this initial version, we support file updates with
a locally managed minisign key.

Add a test workflow to exercise the action.

* Add code owners

Add CODEOWNERS file.
  • Loading branch information
syncom authored May 3, 2024
1 parent 0288a35 commit 1e43fb1
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 0 deletions.
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

0 comments on commit 1e43fb1

Please sign in to comment.