From ceccf7be41b8007d5e89ff49d8bd78d147bc70a5 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Mon, 6 Jul 2026 12:57:26 +0200 Subject: [PATCH 01/54] Add upstream integration workflow for toolkit updates This workflow automates the process of updating the toolkit from an internal release archive, including authorization, downloading, extracting, and building the toolkit. --- .github/workflows/upstream_integration.yml | 167 +++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 .github/workflows/upstream_integration.yml diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml new file mode 100644 index 0000000..01efa89 --- /dev/null +++ b/.github/workflows/upstream_integration.yml @@ -0,0 +1,167 @@ +name: Update Toolkit from Internal Release Archive + +on: + workflow_dispatch: + inputs: + artifact_url: + description: "URL for the toolkit tar.gz archive" + required: true + type: string + artifactory_token: + description: "Authentication bearer token" + required: true + type: string + +permissions: + contents: read + +jobs: + build-from-archive: + runs-on: ubuntu-latest + + steps: + - name: Authorize triggering actor + env: + ALLOWED_ACTORS: ${{ vars.WORKFLOW_ALLOWED_ACTORS }} + shell: bash + run: | + set -euo pipefail + + if [[ -z "${ALLOWED_ACTORS:-}" ]]; then + echo "::error::Repository variable WORKFLOW_ALLOWED_ACTORS is not set." + echo "::error::Set it to a comma-separated list of GitHub usernames allowed to run this workflow." + exit 1 + fi + + normalized="${ALLOWED_ACTORS// /}" + if [[ ",${normalized}," != *",${GITHUB_ACTOR},"* ]]; then + echo "::error::Actor is not authorized to run this workflow." + exit 1 + fi + + echo "Actor authorization succeeded." + + - name: Verify runner prerequisites + shell: bash + run: | + set -euo pipefail + command -v curl >/dev/null + command -v tar >/dev/null + command -v docker >/dev/null + command -v jq >/dev/null + + - name: Download and unpack archive + shell: bash + run: | + set -euo pipefail + + ARTIFACT_URL="$(jq -r '.inputs.artifact_url // empty' "${GITHUB_EVENT_PATH}")" + ARTIFACTORY_TOKEN="$(jq -r '.inputs.artifactory_token // empty' "${GITHUB_EVENT_PATH}")" + + if [[ -z "${ARTIFACTORY_TOKEN:-}" ]]; then + echo "::error::Required workflow input artifactory_token is not set." + exit 1 + fi + + if [[ -z "${ARTIFACT_URL:-}" ]]; then + echo "::error::Required workflow input artifact_url is not set." + exit 1 + fi + + # Treat the manual input URL as sensitive operational data. + echo "::add-mask::${ARTIFACT_URL}" + echo "::add-mask::${ARTIFACTORY_TOKEN}" + + tmp_dir="$(mktemp -d)" + archive_path="${tmp_dir}/toolkit.tar.gz" + extract_root="${tmp_dir}/extracted" + + mkdir -p "${extract_root}" + + echo "Starting archive download (this may take a while for large files)..." + echo "Download target: ${archive_path}" + + curl \ + --fail \ + --progress-bar \ + --show-error \ + --location \ + --header "Authorization: Bearer ${ARTIFACTORY_TOKEN}" \ + --output "${archive_path}" \ + --url "${ARTIFACT_URL}" + + archive_size_bytes="$(wc -c < "${archive_path}")" + archive_size_mib="$(awk "BEGIN { printf \"%.2f\", ${archive_size_bytes}/1024/1024 }")" + echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." + + echo "Starting archive extraction into ${extract_root}..." + + tar -xzf "${archive_path}" -C "${extract_root}" + + echo "Extraction complete." + + echo "TMP_WORK_DIR=${tmp_dir}" >> "${GITHUB_ENV}" + echo "EXTRACT_ROOT=${extract_root}" >> "${GITHUB_ENV}" + + - name: Validate extracted layout + shell: bash + run: | + set -euo pipefail + + image_archive="${EXTRACT_ROOT}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst" + run_script="${EXTRACT_ROOT}/eb_corbos_toolkit/workspace/scripts/run.sh" + + if [[ ! -f "${image_archive}" ]]; then + echo "::error::Expected container archive path not found in extracted payload." + exit 1 + fi + + if [[ ! -f "${run_script}" ]]; then + echo "::error::Expected eb_corbos_toolkit/workspace/scripts/run.sh not found in extracted payload." + exit 1 + fi + + chmod +x "${run_script}" + + - name: Load container image + shell: bash + run: | + set -euo pipefail + docker load -i "${EXTRACT_ROOT}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst" + + - name: "Fix BitBake execution issue on Ubuntu 23.10+" + shell: bash + run: | + set -euo pipefail + sudo tee /etc/apparmor.d/bitbake > /dev/null <, + include + profile bitbake /**/bitbake/bin/bitbake flags=(unconfined) { + userns, + } + EOF + sudo apparmor_parser -r /etc/apparmor.d/bitbake + + - name: Run kas build from extracted run.sh + shell: bash + run: | + set -euo pipefail + workspace_root="${EXTRACT_ROOT}/eb_corbos_toolkit/workspace" + run_script="${workspace_root}/scripts/run.sh" + + cd "${workspace_root}" + "${run_script}" -d -- kas build --target fastdev kas/public.yml + + - name: Cleanup temporary files + # not really needed as the runner is ephemeral + if: false + shell: bash + run: | + set -euo pipefail + if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then + sudo rm -rf "${TMP_WORK_DIR}" + fi + + # Future extension point: + # - Create/update branch with generated content + # - Open pull request against this repository From 96d204a115527bca12b113bffc66872460c8a878 Mon Sep 17 00:00:00 2001 From: vzeissler Date: Wed, 12 Aug 2026 16:25:45 +0200 Subject: [PATCH 02/54] Add a test step for fastdev image --- .github/workflows/upstream_integration.yml | 80 +++++++++++++++++----- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 01efa89..ae093dd 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -100,39 +100,37 @@ jobs: echo "Extraction complete." - echo "TMP_WORK_DIR=${tmp_dir}" >> "${GITHUB_ENV}" - echo "EXTRACT_ROOT=${extract_root}" >> "${GITHUB_ENV}" + cat >> "${GITHUB_ENV}" << EOF + TMP_WORK_DIR=${tmp_dir} + EXTRACT_ROOT=${extract_root} + WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace + IMAGE_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst + RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh + EOF - name: Validate extracted layout shell: bash run: | - set -euo pipefail - - image_archive="${EXTRACT_ROOT}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst" - run_script="${EXTRACT_ROOT}/eb_corbos_toolkit/workspace/scripts/run.sh" - - if [[ ! -f "${image_archive}" ]]; then + if [[ ! -f "${IMAGE_ARCHIVE}" ]]; then echo "::error::Expected container archive path not found in extracted payload." exit 1 fi - if [[ ! -f "${run_script}" ]]; then + if [[ ! -f "${RUN_SCRIPT}" ]]; then echo "::error::Expected eb_corbos_toolkit/workspace/scripts/run.sh not found in extracted payload." exit 1 fi - chmod +x "${run_script}" + chmod +x "${RUN_SCRIPT}" - name: Load container image shell: bash run: | - set -euo pipefail - docker load -i "${EXTRACT_ROOT}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst" + docker load -i "${IMAGE_ARCHIVE}" - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash run: | - set -euo pipefail sudo tee /etc/apparmor.d/bitbake > /dev/null <, include @@ -144,20 +142,64 @@ jobs: - name: Run kas build from extracted run.sh shell: bash + working-directory: ${{ env.WORKSPACE_ROOT }} run: | - set -euo pipefail - workspace_root="${EXTRACT_ROOT}/eb_corbos_toolkit/workspace" - run_script="${workspace_root}/scripts/run.sh" + "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml + + - name: Test the fastdev image in qemu + shell: bash + working-directory: ${{ env.WORKSPACE_ROOT }} + run: | + # run dev container in detached mode and keep it running + export EXTRA_DOCKER_OPTIONS="-d --log-driver local" + LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ + LOG_FILE="/tmp/ebcl_run_devcontainer.log" + + echo "Starting devcontainer in the background" + DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') + if [[ -z "${DEV_CONTAINER_ID}" ]]; then + echo "::error::Failed to start devcontainer. Log output:" + cat "$LOG_FILE" + exit 1 + fi + sleep 10 + + devcontainer_exec() + { + docker exec "$DEV_CONTAINER_ID" "$@" + } + + echo "Running fastdev in qemu in background, logging to qemu.log" + devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" + devcontainer_exec bash -c \ + "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" + + echo "Terminating fastdev" + devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true + + echo "Waiting for fastdev to power down" + max_tries=20 + msg="Power down" + log="$WORKSPACE_ROOT/qemu.log" + + for i in $(seq 1 "$max_tries"); do + if grep -q "${msg}" "${log}" 2>/dev/null; then + echo "Waiting for \"$msg\" message in $log succeeded" + exit 0 + fi + echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" + sleep 1 + done + echo "Error: Waiting for \"$msg\" message in $log timed out!" + cat "${log}" + exit 1 - cd "${workspace_root}" - "${run_script}" -d -- kas build --target fastdev kas/public.yml - name: Cleanup temporary files # not really needed as the runner is ephemeral if: false shell: bash run: | - set -euo pipefail if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then sudo rm -rf "${TMP_WORK_DIR}" fi From e99817c09655332a095f388a2f38564599d3b58c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 14:57:12 +0200 Subject: [PATCH 03/54] Refactor BitBake execution fix to use the dedicated script --- .github/workflows/upstream_integration.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index ae093dd..853dbf3 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -106,6 +106,7 @@ jobs: WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace IMAGE_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh + BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh EOF - name: Validate extracted layout @@ -131,14 +132,7 @@ jobs: - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash run: | - sudo tee /etc/apparmor.d/bitbake > /dev/null <, - include - profile bitbake /**/bitbake/bin/bitbake flags=(unconfined) { - userns, - } - EOF - sudo apparmor_parser -r /etc/apparmor.d/bitbake + "${{ env.BITBAKE_EXECUTION_FIXER }}" --yes - name: Run kas build from extracted run.sh shell: bash From fd73e46ed9e93ed0c210a2c9287e38c7b146057e Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 15:33:36 +0200 Subject: [PATCH 04/54] Enhance upstream integration workflow --- .github/workflows/upstream_integration.yml | 132 +++++++++++++++++++-- 1 file changed, 123 insertions(+), 9 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 853dbf3..ea49ca1 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -11,9 +11,13 @@ on: description: "Authentication bearer token" required: true type: string + release_version: + description: "Release version string (e.g. v2.0.0-beta2)" + required: true + type: string permissions: - contents: read + contents: write # create the tag + Release, upload assets jobs: build-from-archive: @@ -188,16 +192,126 @@ jobs: cat "${log}" exit 1 + - name: Remove prebuilt assets from workspace before branch update + shell: bash + run: | + rm -rf "${{ env.WORKSPACE_ROOT }}/prebuilt" + + - name: Checkout repository for integration + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: main + path: integration-repo + + - name: Create or checkout integration branch + working-directory: integration-repo + shell: bash + run: | + set -euo pipefail + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + BRANCH="integration" + echo "INTEGRATION_BRANCH=${BRANCH}" >> "${GITHUB_ENV}" + + if git ls-remote --exit-code --heads origin "${BRANCH}" >/dev/null 2>&1; then + echo "Integration branch '${BRANCH}' already exists; checking out its state." + git fetch origin "${BRANCH}" + git checkout -B "${BRANCH}" "origin/${BRANCH}" + else + echo "Integration branch '${BRANCH}' does not exist; creating it from main." + git checkout -B "${BRANCH}" origin/main + fi - - name: Cleanup temporary files - # not really needed as the runner is ephemeral - if: false + - name: Replace working copy with upstream workspace + working-directory: integration-repo shell: bash run: | - if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then - sudo rm -rf "${TMP_WORK_DIR}" + set -euo pipefail + + if [[ ! -d "${WORKSPACE_ROOT}" ]]; then + echo "::error::WORKSPACE_ROOT '${WORKSPACE_ROOT}' does not exist." + exit 1 + fi + + # Remove all tracked and untracked content except the .git folder. + find . -mindepth 1 -maxdepth 1 -name '.git' -prune -o -exec rm -rf {} + + + # Copy the upstream workspace on top, preserving flags, mtimes, ownership. + cp -a "${WORKSPACE_ROOT}/." . + + - name: Commit integrated upstream content + working-directory: integration-repo + env: + RELEASE_VERSION: ${{ inputs.release_version }} + shell: bash + run: | + set -euo pipefail + + git add -A + if git diff --cached --quiet; then + echo "No changes to commit; working copy already matches upstream." + else + git commit -m "Integrate upstream version ${RELEASE_VERSION}" fi - # Future extension point: - # - Create/update branch with generated content - # - Open pull request against this repository + git push origin "HEAD:${INTEGRATION_BRANCH}" + + - name: Package user manual assets + shell: bash + run: | + set -euo pipefail + + command -v zip >/dev/null || { echo "::error::zip is required but not installed."; exit 1; } + + pdf_src="${EXTRACT_ROOT}/doc/user_manual.pdf" + html_src="${EXTRACT_ROOT}/doc/html" + + if [[ ! -f "${pdf_src}" ]]; then + echo "::error::Expected user manual PDF not found at ${pdf_src}." + exit 1 + fi + + if [[ ! -d "${html_src}" ]]; then + echo "::error::Expected HTML user manual directory not found at ${html_src}." + exit 1 + fi + + assets_dir="${TMP_WORK_DIR}/release-assets" + mkdir -p "${assets_dir}" + + cp "${pdf_src}" "${assets_dir}/user_manual.pdf" + ( cd "${html_src}" && zip -r "${assets_dir}/user_manual_html.zip" . ) + + echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" + + - name: Create or update draft release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_VERSION: ${{ inputs.release_version }} + shell: bash + run: | + set -euo pipefail + + pdf_asset="${RELEASE_ASSETS_DIR}/user_manual.pdf" + html_asset="${RELEASE_ASSETS_DIR}/user_manual_html.zip" + + if gh release view "${RELEASE_VERSION}" >/dev/null 2>&1; then + is_draft="$(gh release view "${RELEASE_VERSION}" --json isDraft --jq '.isDraft')" + if [[ "${is_draft}" != "true" ]]; then + echo "::error::Release '${RELEASE_VERSION}' already exists and is published (not a draft); refusing to modify it." + exit 1 + fi + echo "Draft release '${RELEASE_VERSION}' already exists; updating assets." + gh release upload "${RELEASE_VERSION}" "${pdf_asset}" "${html_asset}" --clobber + else + echo "Creating draft release '${RELEASE_VERSION}'." + # A draft release with a not-yet-existing tag does not create the tag + # or point at any commit/branch until it is published. + gh release create "${RELEASE_VERSION}" \ + --draft \ + --title "${RELEASE_VERSION}" \ + "${pdf_asset}" "${html_asset}" + fi From 67013cdd58a768f737e35940f447b41583760e56 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 15:58:06 +0200 Subject: [PATCH 05/54] file does not yet have the refactoring --- .github/workflows/upstream_integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index ea49ca1..7d661e9 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -110,7 +110,7 @@ jobs: WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace IMAGE_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh - BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh + BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/check_userns_restriction.sh EOF - name: Validate extracted layout From 1084fdfccb02cd4607431dd8d7440cf5bc65a9eb Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 16:14:48 +0200 Subject: [PATCH 06/54] Fix path to BitBake execution fixer script in upstream integration workflow --- .github/workflows/upstream_integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 7d661e9..ea49ca1 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -110,7 +110,7 @@ jobs: WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace IMAGE_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh - BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/check_userns_restriction.sh + BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh EOF - name: Validate extracted layout From caa68559c8867d9273aae17921148bd4ebce0c08 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 16:41:31 +0200 Subject: [PATCH 07/54] remove build output as well --- .github/workflows/upstream_integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index ea49ca1..662a602 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -196,6 +196,7 @@ jobs: shell: bash run: | rm -rf "${{ env.WORKSPACE_ROOT }}/prebuilt" + rm -rf "${{ env.WORKSPACE_ROOT }}/build" - name: Checkout repository for integration uses: actions/checkout@v4 From c476acbda09f0d25f6502346fcf43cd36e31b6d6 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 16:41:52 +0200 Subject: [PATCH 08/54] keep github.com specific files / folders --- .github/workflows/upstream_integration.yml | 27 ++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 662a602..b4767b1 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -237,8 +237,31 @@ jobs: exit 1 fi - # Remove all tracked and untracked content except the .git folder. - find . -mindepth 1 -maxdepth 1 -name '.git' -prune -o -exec rm -rf {} + + # Remove all tracked and untracked content except the repository metadata + # and files that must remain in the integration repository. Add entries to + # this list when additional repository-owned content should be preserved. + preserve_paths=( + '.git' + '.github' + '.gitignore' + 'CODE_OF_CONDUCT.md' + 'README.md' + ) + + while IFS= read -r -d '' path; do + name="${path#./}" + preserve=false + for preserve_path in "${preserve_paths[@]}"; do + if [[ "${name}" == "${preserve_path}" ]]; then + preserve=true + break + fi + done + + if [[ "${preserve}" != true ]]; then + rm -rf -- "${path}" + fi + done < <(find . -mindepth 1 -maxdepth 1 -print0) # Copy the upstream workspace on top, preserving flags, mtimes, ownership. cp -a "${WORKSPACE_ROOT}/." . From dae13c2c6be21437798a5bbd1d103801486779c0 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 17:02:51 +0200 Subject: [PATCH 09/54] temporarily disable image building --- .github/workflows/upstream_integration.yml | 112 ++++++++++----------- 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index b4767b1..8e3cde6 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -138,65 +138,59 @@ jobs: run: | "${{ env.BITBAKE_EXECUTION_FIXER }}" --yes - - name: Run kas build from extracted run.sh - shell: bash - working-directory: ${{ env.WORKSPACE_ROOT }} - run: | - "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml - - - name: Test the fastdev image in qemu - shell: bash - working-directory: ${{ env.WORKSPACE_ROOT }} - run: | - # run dev container in detached mode and keep it running - export EXTRA_DOCKER_OPTIONS="-d --log-driver local" - LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ - LOG_FILE="/tmp/ebcl_run_devcontainer.log" - - echo "Starting devcontainer in the background" - DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') - if [[ -z "${DEV_CONTAINER_ID}" ]]; then - echo "::error::Failed to start devcontainer. Log output:" - cat "$LOG_FILE" - exit 1 - fi - sleep 10 - - devcontainer_exec() - { - docker exec "$DEV_CONTAINER_ID" "$@" - } - - echo "Running fastdev in qemu in background, logging to qemu.log" - devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" - devcontainer_exec bash -c \ - "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" - - echo "Terminating fastdev" - devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true - - echo "Waiting for fastdev to power down" - max_tries=20 - msg="Power down" - log="$WORKSPACE_ROOT/qemu.log" - - for i in $(seq 1 "$max_tries"); do - if grep -q "${msg}" "${log}" 2>/dev/null; then - echo "Waiting for \"$msg\" message in $log succeeded" - exit 0 - fi - echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" - sleep 1 - done - echo "Error: Waiting for \"$msg\" message in $log timed out!" - cat "${log}" - exit 1 - - - name: Remove prebuilt assets from workspace before branch update - shell: bash - run: | - rm -rf "${{ env.WORKSPACE_ROOT }}/prebuilt" - rm -rf "${{ env.WORKSPACE_ROOT }}/build" + # - name: Run kas build from extracted run.sh + # shell: bash + # working-directory: ${{ env.WORKSPACE_ROOT }} + # run: | + # "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml + + # - name: Test the fastdev image in qemu + # shell: bash + # working-directory: ${{ env.WORKSPACE_ROOT }} + # run: | + # # run dev container in detached mode and keep it running + # export EXTRA_DOCKER_OPTIONS="-d --log-driver local" + # LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ + # LOG_FILE="/tmp/ebcl_run_devcontainer.log" + + # echo "Starting devcontainer in the background" + # DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') + # if [[ -z "${DEV_CONTAINER_ID}" ]]; then + # echo "::error::Failed to start devcontainer. Log output:" + # cat "$LOG_FILE" + # exit 1 + # fi + # sleep 10 + + # devcontainer_exec() + # { + # docker exec "$DEV_CONTAINER_ID" "$@" + # } + + # echo "Running fastdev in qemu in background, logging to qemu.log" + # devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" + # devcontainer_exec bash -c \ + # "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" + + # echo "Terminating fastdev" + # devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true + + # echo "Waiting for fastdev to power down" + # max_tries=20 + # msg="Power down" + # log="$WORKSPACE_ROOT/qemu.log" + + # for i in $(seq 1 "$max_tries"); do + # if grep -q "${msg}" "${log}" 2>/dev/null; then + # echo "Waiting for \"$msg\" message in $log succeeded" + # exit 0 + # fi + # echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" + # sleep 1 + # done + # echo "Error: Waiting for \"$msg\" message in $log timed out!" + # cat "${log}" + # exit 1 - name: Checkout repository for integration uses: actions/checkout@v4 From cb7cf6ca403705792bbb472a101e4eefb81f8eb3 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 17:03:09 +0200 Subject: [PATCH 10/54] do not copy prebuilt and build --- .github/workflows/upstream_integration.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 8e3cde6..cf184fb 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -258,7 +258,8 @@ jobs: done < <(find . -mindepth 1 -maxdepth 1 -print0) # Copy the upstream workspace on top, preserving flags, mtimes, ownership. - cp -a "${WORKSPACE_ROOT}/." . + # Ignore the "prebuilt" and "build" sub-folders. + rsync -a --exclude='prebuilt' --exclude='build' "${WORKSPACE_ROOT}/." . - name: Commit integrated upstream content working-directory: integration-repo From 3cc8e7ca68080e5328508f4e3a584969dbda5dd8 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 17:03:41 +0200 Subject: [PATCH 11/54] package also prebuilt as asset --- .github/workflows/upstream_integration.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index cf184fb..cb0e684 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -278,7 +278,7 @@ jobs: git push origin "HEAD:${INTEGRATION_BRANCH}" - - name: Package user manual assets + - name: Package assets shell: bash run: | set -euo pipefail @@ -287,6 +287,7 @@ jobs: pdf_src="${EXTRACT_ROOT}/doc/user_manual.pdf" html_src="${EXTRACT_ROOT}/doc/html" + prebuilt_src="${EXTRACT_ROOT}/prebuilt" if [[ ! -f "${pdf_src}" ]]; then echo "::error::Expected user manual PDF not found at ${pdf_src}." @@ -298,11 +299,17 @@ jobs: exit 1 fi + if [[ ! -d "${prebuilt_src}" ]]; then + echo "::error::Expected prebuilt directory not found at ${prebuilt_src}." + exit 1 + fi + assets_dir="${TMP_WORK_DIR}/release-assets" mkdir -p "${assets_dir}" cp "${pdf_src}" "${assets_dir}/user_manual.pdf" ( cd "${html_src}" && zip -r "${assets_dir}/user_manual_html.zip" . ) + ( cd "${prebuilt_src}" && zip -r "${assets_dir}/prebuilt.zip" . ) echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" @@ -316,6 +323,7 @@ jobs: pdf_asset="${RELEASE_ASSETS_DIR}/user_manual.pdf" html_asset="${RELEASE_ASSETS_DIR}/user_manual_html.zip" + prebuilt_asset="${RELEASE_ASSETS_DIR}/prebuilt.zip" if gh release view "${RELEASE_VERSION}" >/dev/null 2>&1; then is_draft="$(gh release view "${RELEASE_VERSION}" --json isDraft --jq '.isDraft')" @@ -324,7 +332,7 @@ jobs: exit 1 fi echo "Draft release '${RELEASE_VERSION}' already exists; updating assets." - gh release upload "${RELEASE_VERSION}" "${pdf_asset}" "${html_asset}" --clobber + gh release upload "${RELEASE_VERSION}" "${pdf_asset}" "${html_asset}" "${prebuilt_asset}" --clobber else echo "Creating draft release '${RELEASE_VERSION}'." # A draft release with a not-yet-existing tag does not create the tag @@ -332,5 +340,5 @@ jobs: gh release create "${RELEASE_VERSION}" \ --draft \ --title "${RELEASE_VERSION}" \ - "${pdf_asset}" "${html_asset}" + "${pdf_asset}" "${html_asset}" "${prebuilt_asset}" fi From 76138dc17012af618ffcd777de6f198d022e4325 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 17:11:25 +0200 Subject: [PATCH 12/54] update paths for user manual and prebuilt assets in workflow --- .github/workflows/upstream_integration.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index cb0e684..334e876 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -285,9 +285,9 @@ jobs: command -v zip >/dev/null || { echo "::error::zip is required but not installed."; exit 1; } - pdf_src="${EXTRACT_ROOT}/doc/user_manual.pdf" - html_src="${EXTRACT_ROOT}/doc/html" - prebuilt_src="${EXTRACT_ROOT}/prebuilt" + pdf_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/user_manual.pdf" + html_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/html" + prebuilt_src="${WORKSPACE_ROOT}/prebuilt" if [[ ! -f "${pdf_src}" ]]; then echo "::error::Expected user manual PDF not found at ${pdf_src}." From a717207d9ae79c5c450d67fc0bf538419351dcdd Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Thu, 13 Aug 2026 17:20:42 +0200 Subject: [PATCH 13/54] set working directory for draft release creation step --- .github/workflows/upstream_integration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 334e876..71c1549 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -314,6 +314,7 @@ jobs: echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" - name: Create or update draft release + working-directory: integration-repo env: GH_TOKEN: ${{ github.token }} RELEASE_VERSION: ${{ inputs.release_version }} From c4b5c2fdaa957b40992ad2b8933abcec8fea600f Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 17:57:09 +0200 Subject: [PATCH 14/54] create PR, update container tags and populate containers --- .github/workflows/upstream_integration.yml | 84 +++++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 71c1549..82954ee 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -18,6 +18,7 @@ on: permissions: contents: write # create the tag + Release, upload assets + packages: write # push containers to ghcr.io jobs: build-from-archive: @@ -108,7 +109,10 @@ jobs: TMP_WORK_DIR=${tmp_dir} EXTRACT_ROOT=${extract_root} WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace - IMAGE_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst + DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst + BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst + DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd6 + BUILDCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-buildcontainer-amd64 RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh EOF @@ -116,11 +120,16 @@ jobs: - name: Validate extracted layout shell: bash run: | - if [[ ! -f "${IMAGE_ARCHIVE}" ]]; then + if [[ ! -f "${DEVCONTAINER_ARCHIVE}" ]]; then echo "::error::Expected container archive path not found in extracted payload." exit 1 fi + if [[ ! -f "${BUILDCONTAINER_ARCHIVE}" ]]; then + echo "::error::Expected build container archive path not found in extracted payload." + exit 1 + fi + if [[ ! -f "${RUN_SCRIPT}" ]]; then echo "::error::Expected eb_corbos_toolkit/workspace/scripts/run.sh not found in extracted payload." exit 1 @@ -131,7 +140,8 @@ jobs: - name: Load container image shell: bash run: | - docker load -i "${IMAGE_ARCHIVE}" + docker load -i "${DEVCONTAINER_ARCHIVE}" + docker load -i "${BUILDCONTAINER_ARCHIVE}" - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash @@ -278,6 +288,74 @@ jobs: git push origin "HEAD:${INTEGRATION_BRANCH}" + - name: Create or update integration pull request + id: integration-pr + working-directory: integration-repo + env: + GH_TOKEN: ${{ github.token }} + RELEASE_VERSION: ${{ inputs.release_version }} + shell: bash + run: | + set -euo pipefail + + existing_pr="$(gh pr list --head "${INTEGRATION_BRANCH}" --base main --state open --json number --jq '.[0].number // empty')" + + if [[ -n "${existing_pr}" ]]; then + echo "Pull request #${existing_pr} already exists for ${INTEGRATION_BRANCH} → main." + echo "pr_number=${existing_pr}" >> "${GITHUB_OUTPUT}" + else + pr_url="$(gh pr create \ + --head "${INTEGRATION_BRANCH}" \ + --base main \ + --title "Integrate upstream version ${RELEASE_VERSION}" \ + --body "Automated PR created by the upstream integration workflow for release ${RELEASE_VERSION}.")" + pr_number="$(echo "${pr_url}" | grep -oE '[0-9]+$')" + echo "Created pull request #${pr_number}." + echo "pr_tag=pr-${pr_number}" >> "${GITHUB_OUTPUT}" + fi + + - name: Rewrite devcontainer image tag for PR + id: rewrite-tag + working-directory: integration-repo + shell: bash + run: | + set -euo pipefail + + devcontainer_json=".devcontainer/devcontainer.json" + run_sh="./scripts/run.sh" + rfi_tag="$(grep -oP '(?<="image":\s*".+:)[^"]+' "${devcontainer_json}")" + + if [[ -z "${rfi_tag}" ]]; then + echo "::error::Could not extract image tag from ${devcontainer_json}." + exit 1 + fi + + echo "Original tag: ${rfi_tag}" + echo "rfi_tag=${rfi_tag}" >> "${GITHUB_OUTPUT}" + + new_tag="${{ steps.integration-pr.outputs.pr_tag }}" + sed -i "s|:\${rfi_tag}\"|:${new_tag}\"|" "${devcontainer_json}" + sed -i "s|:\${rfi_tag}\"|:${new_tag}\"|" "${run_sh}" + echo "Rewrote image tag to: ${new_tag}" + + git add "${devcontainer_json}" "${run_sh}" + git commit -am "Rewrite devcontainer image tag for PR" + git push origin "HEAD:${INTEGRATION_BRANCH}" + + - name: Update container tags and push to registry + working-directory: integration-repo + shell: bash + run: | + set -euo pipefail + + new_tag="${{ steps.integration-pr.outputs.pr_tag }}" + docker tag "${DEVCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${DEVCONTAINER_IMAGE}:${new_tag}" + docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" + + echo "Pushing updated container images to registry..." + docker push "${DEVCONTAINER_IMAGE}:${new_tag}" + docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" + - name: Package assets shell: bash run: | From 72157d0d36fa79f6609cef30e34147dbe8b6e626 Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 18:42:44 +0200 Subject: [PATCH 15/54] added PR permission --- .github/workflows/upstream_integration.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 82954ee..1002bde 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -17,8 +17,9 @@ on: type: string permissions: - contents: write # create the tag + Release, upload assets - packages: write # push containers to ghcr.io + contents: write # create the tag + Release, upload assets + packages: write # push containers to ghcr.io + pull-requests: write # create integration PR jobs: build-from-archive: From bcaea3132ba5a2eff122efe4dce4db0238f5e9f4 Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 18:58:45 +0200 Subject: [PATCH 16/54] fixed grep error --- .github/workflows/upstream_integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 1002bde..a89bbfb 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -324,7 +324,7 @@ jobs: devcontainer_json=".devcontainer/devcontainer.json" run_sh="./scripts/run.sh" - rfi_tag="$(grep -oP '(?<="image":\s*".+:)[^"]+' "${devcontainer_json}")" + rfi_tag="$(sed -n 's/.*"image":.*:\([^"]*\)".*/\1/p' "${devcontainer_json}" | head -1)" if [[ -z "${rfi_tag}" ]]; then echo "::error::Could not extract image tag from ${devcontainer_json}." From 42a74e50ca121061b99403d3a16d51b960333eb6 Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 20:17:54 +0200 Subject: [PATCH 17/54] fixed broken variable --- .github/workflows/upstream_integration.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index a89bbfb..ab34d1f 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -300,10 +300,11 @@ jobs: set -euo pipefail existing_pr="$(gh pr list --head "${INTEGRATION_BRANCH}" --base main --state open --json number --jq '.[0].number // empty')" + tag_prefix="pr-" if [[ -n "${existing_pr}" ]]; then echo "Pull request #${existing_pr} already exists for ${INTEGRATION_BRANCH} → main." - echo "pr_number=${existing_pr}" >> "${GITHUB_OUTPUT}" + echo "pr_tag=${tag_prefix}${existing_pr}" >> "${GITHUB_OUTPUT}" else pr_url="$(gh pr create \ --head "${INTEGRATION_BRANCH}" \ @@ -312,7 +313,7 @@ jobs: --body "Automated PR created by the upstream integration workflow for release ${RELEASE_VERSION}.")" pr_number="$(echo "${pr_url}" | grep -oE '[0-9]+$')" echo "Created pull request #${pr_number}." - echo "pr_tag=pr-${pr_number}" >> "${GITHUB_OUTPUT}" + echo "pr_tag=${tag_prefix}${pr_number}" >> "${GITHUB_OUTPUT}" fi - name: Rewrite devcontainer image tag for PR From 00b5470191eec9b6bec669805c84eb471272615f Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 20:26:40 +0200 Subject: [PATCH 18/54] fixed broken escape sequence --- .github/workflows/upstream_integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index ab34d1f..bdf1bf9 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -336,8 +336,8 @@ jobs: echo "rfi_tag=${rfi_tag}" >> "${GITHUB_OUTPUT}" new_tag="${{ steps.integration-pr.outputs.pr_tag }}" - sed -i "s|:\${rfi_tag}\"|:${new_tag}\"|" "${devcontainer_json}" - sed -i "s|:\${rfi_tag}\"|:${new_tag}\"|" "${run_sh}" + sed -i "s|:${rfi_tag}\"|:${new_tag}\"|" "${devcontainer_json}" + sed -i "s|:${rfi_tag}\"|:${new_tag}\"|" "${run_sh}" echo "Rewrote image tag to: ${new_tag}" git add "${devcontainer_json}" "${run_sh}" From 7d925d35190e88c30afc3cd6bbe71ff5362e250b Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 20:41:08 +0200 Subject: [PATCH 19/54] fix container name and exclude build container due to broken name --- .github/workflows/upstream_integration.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index bdf1bf9..30442f0 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -112,7 +112,7 @@ jobs: WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst - DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd6 + DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd64 BUILDCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-buildcontainer-amd64 RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh @@ -352,11 +352,11 @@ jobs: new_tag="${{ steps.integration-pr.outputs.pr_tag }}" docker tag "${DEVCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${DEVCONTAINER_IMAGE}:${new_tag}" - docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" + # docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" echo "Pushing updated container images to registry..." docker push "${DEVCONTAINER_IMAGE}:${new_tag}" - docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" + # docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" - name: Package assets shell: bash From 4b35d32bc25bcb3bbee997667233171097f1d3ee Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 20:43:35 +0200 Subject: [PATCH 20/54] only update the branch when we have changes --- .github/workflows/upstream_integration.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 30442f0..6f457ce 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -341,8 +341,12 @@ jobs: echo "Rewrote image tag to: ${new_tag}" git add "${devcontainer_json}" "${run_sh}" - git commit -am "Rewrite devcontainer image tag for PR" - git push origin "HEAD:${INTEGRATION_BRANCH}" + if git diff --cached --quiet; then + echo "Tags already match; nothing to commit." + else + git commit -m "Rewrite devcontainer image tag for PR" + git push origin "HEAD:${INTEGRATION_BRANCH}" + fi - name: Update container tags and push to registry working-directory: integration-repo From 06323e6a7010b8c8d59808f8ebe55b6b22a15c46 Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 20:54:29 +0200 Subject: [PATCH 21/54] added login in order to push the docker images --- .github/workflows/upstream_integration.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 6f457ce..06f0b60 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -354,6 +354,8 @@ jobs: run: | set -euo pipefail + echo "${{ github.token }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + new_tag="${{ steps.integration-pr.outputs.pr_tag }}" docker tag "${DEVCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${DEVCONTAINER_IMAGE}:${new_tag}" # docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" From f39ff07b19ac0af6aa4d684312a5c7e4b56c4d7f Mon Sep 17 00:00:00 2001 From: Matthias Beckert Date: Thu, 13 Aug 2026 23:30:09 +0200 Subject: [PATCH 22/54] also push buildcontainer --- .github/workflows/upstream_integration.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 06f0b60..2f5b393 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -358,11 +358,11 @@ jobs: new_tag="${{ steps.integration-pr.outputs.pr_tag }}" docker tag "${DEVCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${DEVCONTAINER_IMAGE}:${new_tag}" - # docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" + docker tag "${BUILDCONTAINER_IMAGE}:${{ steps.rewrite-tag.outputs.rfi_tag }}" "${BUILDCONTAINER_IMAGE}:${new_tag}" echo "Pushing updated container images to registry..." docker push "${DEVCONTAINER_IMAGE}:${new_tag}" - # docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" + docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" - name: Package assets shell: bash From dd9ba756898f6d8d27bb4678dcc3d1ec70e8073a Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 07:34:50 +0200 Subject: [PATCH 23/54] use "v" as prefix for container tags pr- seems a bit "weird" --- .github/workflows/upstream_integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 2f5b393..e0c9ca0 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -300,7 +300,7 @@ jobs: set -euo pipefail existing_pr="$(gh pr list --head "${INTEGRATION_BRANCH}" --base main --state open --json number --jq '.[0].number // empty')" - tag_prefix="pr-" + tag_prefix="v" if [[ -n "${existing_pr}" ]]; then echo "Pull request #${existing_pr} already exists for ${INTEGRATION_BRANCH} → main." From 13930e2cf76dad0d7e0729766584b53b1d85d550 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 08:00:36 +0200 Subject: [PATCH 24/54] add also individual assets per target, use tgz instead of ZIP --- .github/workflows/upstream_integration.yml | 46 +++++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index e0c9ca0..ff2a57a 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -395,7 +395,36 @@ jobs: cp "${pdf_src}" "${assets_dir}/user_manual.pdf" ( cd "${html_src}" && zip -r "${assets_dir}/user_manual_html.zip" . ) - ( cd "${prebuilt_src}" && zip -r "${assets_dir}/prebuilt.zip" . ) + + # Full prebuilt tree as a single archive. + tar -czf "${assets_dir}/prebuilt.tgz" -C "${prebuilt_src}" . + + # Per-target assets: one image archive (named after its .wic file), the + # SDK sysroot tarball and the SSH target key for every target directory. + for target_dir in "${prebuilt_src}"/*/; do + [[ -d "${target_dir}" ]] || continue + + image_dir="${target_dir}image" + if [[ -d "${image_dir}" ]]; then + wic_file="$(find "${image_dir}" -maxdepth 1 -name '*.wic' -print -quit)" + if [[ -z "${wic_file}" ]]; then + echo "::error::No .wic file found in ${image_dir}." + exit 1 + fi + image_base="$(basename "${wic_file}" .wic)" + tar -czf "${assets_dir}/${image_base}.tgz" -C "${image_dir}" . + fi + + sdk_dir="${target_dir}sysroot" + if [[ -d "${sdk_dir}" ]]; then + find "${sdk_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; + fi + + key_dir="${target_dir}ssh_keys" + if [[ -d "${key_dir}" ]]; then + find "${key_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; + fi + done echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" @@ -408,9 +437,14 @@ jobs: run: | set -euo pipefail - pdf_asset="${RELEASE_ASSETS_DIR}/user_manual.pdf" - html_asset="${RELEASE_ASSETS_DIR}/user_manual_html.zip" - prebuilt_asset="${RELEASE_ASSETS_DIR}/prebuilt.zip" + shopt -s nullglob + assets=( "${RELEASE_ASSETS_DIR}"/* ) + shopt -u nullglob + + if [[ ${#assets[@]} -eq 0 ]]; then + echo "::error::No release assets found in ${RELEASE_ASSETS_DIR}." + exit 1 + fi if gh release view "${RELEASE_VERSION}" >/dev/null 2>&1; then is_draft="$(gh release view "${RELEASE_VERSION}" --json isDraft --jq '.isDraft')" @@ -419,7 +453,7 @@ jobs: exit 1 fi echo "Draft release '${RELEASE_VERSION}' already exists; updating assets." - gh release upload "${RELEASE_VERSION}" "${pdf_asset}" "${html_asset}" "${prebuilt_asset}" --clobber + gh release upload "${RELEASE_VERSION}" "${assets[@]}" --clobber else echo "Creating draft release '${RELEASE_VERSION}'." # A draft release with a not-yet-existing tag does not create the tag @@ -427,5 +461,5 @@ jobs: gh release create "${RELEASE_VERSION}" \ --draft \ --title "${RELEASE_VERSION}" \ - "${pdf_asset}" "${html_asset}" "${prebuilt_asset}" + "${assets[@]}" fi From 6b3583f9cd29681d57b96abf51eb5a2466877cde Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 08:00:59 +0200 Subject: [PATCH 25/54] replace zip with tgz for user manual HTML assets --- .github/workflows/upstream_integration.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index ff2a57a..90d96c3 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -369,8 +369,6 @@ jobs: run: | set -euo pipefail - command -v zip >/dev/null || { echo "::error::zip is required but not installed."; exit 1; } - pdf_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/user_manual.pdf" html_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/html" prebuilt_src="${WORKSPACE_ROOT}/prebuilt" @@ -394,7 +392,7 @@ jobs: mkdir -p "${assets_dir}" cp "${pdf_src}" "${assets_dir}/user_manual.pdf" - ( cd "${html_src}" && zip -r "${assets_dir}/user_manual_html.zip" . ) + tar -czf "${assets_dir}/user_manual_html.tgz" -C "${html_src}" . # Full prebuilt tree as a single archive. tar -czf "${assets_dir}/prebuilt.tgz" -C "${prebuilt_src}" . From 25a340a2ef9e789ff8a08c0ea00376eebc4ff29d Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 08:12:29 +0200 Subject: [PATCH 26/54] change file extensions from .tgz to .tar.gz for user manual and prebuilt assets --- .github/workflows/upstream_integration.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 90d96c3..137122b 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -392,10 +392,10 @@ jobs: mkdir -p "${assets_dir}" cp "${pdf_src}" "${assets_dir}/user_manual.pdf" - tar -czf "${assets_dir}/user_manual_html.tgz" -C "${html_src}" . + tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${html_src}" . # Full prebuilt tree as a single archive. - tar -czf "${assets_dir}/prebuilt.tgz" -C "${prebuilt_src}" . + tar -czf "${assets_dir}/prebuilt.tar.gz" -C "${prebuilt_src}" . # Per-target assets: one image archive (named after its .wic file), the # SDK sysroot tarball and the SSH target key for every target directory. @@ -410,7 +410,7 @@ jobs: exit 1 fi image_base="$(basename "${wic_file}" .wic)" - tar -czf "${assets_dir}/${image_base}.tgz" -C "${image_dir}" . + tar -czf "${assets_dir}/${image_base}.tar.gz" -C "${image_dir}" . fi sdk_dir="${target_dir}sysroot" From d3be42dbc6c6114c524606e3f3ce6ffed39f78d7 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 08:29:08 +0200 Subject: [PATCH 27/54] add release workflow to publish user guide asset to GitHub Pages --- .github/workflows/release.yml | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c66c14a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,103 @@ +name: Execute Release Activities + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: "Release tag to publish (e.g. v2.0.0-beta2)" + required: true + type: string + +# Only one release should run at a time. +concurrency: + group: release + cancel-in-progress: false + +permissions: + contents: read # read the release + download its assets + pages: write # publish to GitHub Pages + id-token: write # required by the Pages deployment + +env: + USER_GUIDE_ASSET: user_guide.tar.gz + # Tag from the manual input when dispatched, otherwise the pushed tag. + RELEASE_TAG: ${{ inputs.tag || github.ref_name }} + +jobs: + publish-user-guide: + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Verify runner prerequisites + shell: bash + run: | + set -euo pipefail + command -v gh >/dev/null + command -v jq >/dev/null + command -v tar >/dev/null + + - name: Verify published release contains the user guide asset + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + + tag="${RELEASE_TAG}" + echo "Checking release for tag '${tag}'." + + if ! release_json="$(gh release view "${tag}" \ + --repo "${GITHUB_REPOSITORY}" \ + --json isDraft,assets 2>/dev/null)"; then + echo "::error::No release is associated with tag '${tag}'." + exit 1 + fi + + is_draft="$(jq -r '.isDraft' <<<"${release_json}")" + if [[ "${is_draft}" != "false" ]]; then + echo "::error::Release for tag '${tag}' is a draft, not a published release." + exit 1 + fi + + has_asset="$(jq -r --arg a "${USER_GUIDE_ASSET}" \ + '[.assets[].name] | index($a) != null' <<<"${release_json}")" + if [[ "${has_asset}" != "true" ]]; then + echo "::error::Published release for tag '${tag}' does not contain asset '${USER_GUIDE_ASSET}'." + exit 1 + fi + + echo "Published release for tag '${tag}' contains '${USER_GUIDE_ASSET}'." + + - name: Download and extract the user guide asset + env: + GH_TOKEN: ${{ github.token }} + shell: bash + run: | + set -euo pipefail + + tag="${RELEASE_TAG}" + tmp_dir="$(mktemp -d)" + + gh release download "${tag}" \ + --repo "${GITHUB_REPOSITORY}" \ + --pattern "${USER_GUIDE_ASSET}" \ + --dir "${tmp_dir}" + + rm -rf _site + mkdir -p _site + tar -xzf "${tmp_dir}/${USER_GUIDE_ASSET}" -C _site + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: _site + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From 22a2fda4f6783e2a06ab528d5599eebb68690418 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:04:59 +0200 Subject: [PATCH 28/54] update user guide asset filename to user_manual_html.tar.gz --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c66c14a..d00ffb6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,7 +22,7 @@ permissions: id-token: write # required by the Pages deployment env: - USER_GUIDE_ASSET: user_guide.tar.gz + USER_GUIDE_ASSET: user_manual_html.tar.gz # Tag from the manual input when dispatched, otherwise the pushed tag. RELEASE_TAG: ${{ inputs.tag || github.ref_name }} From 84df91725d3f0b70359d7715ee66d250e7ef615c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:19:30 +0200 Subject: [PATCH 29/54] add GitHub Actions workflow for release activities and user guide asset deployment --- .github/workflows/{release.yml => blourb.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{release.yml => blourb.yml} (100%) diff --git a/.github/workflows/release.yml b/.github/workflows/blourb.yml similarity index 100% rename from .github/workflows/release.yml rename to .github/workflows/blourb.yml From d2f6faf6b659620d2917b97819e1e17cc069443c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:20:18 +0200 Subject: [PATCH 30/54] add GitHub Actions workflow for executing release activities and publishing user guide asset --- .github/workflows/{blourb.yml => release.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{blourb.yml => release.yml} (100%) diff --git a/.github/workflows/blourb.yml b/.github/workflows/release.yml similarity index 100% rename from .github/workflows/blourb.yml rename to .github/workflows/release.yml From 91d01613de0d215b7ea9a22b70258e43ab15413c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:21:33 +0200 Subject: [PATCH 31/54] test --- .github/workflows/hello-world.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/hello-world.yml diff --git a/.github/workflows/hello-world.yml b/.github/workflows/hello-world.yml new file mode 100644 index 0000000..cc419db --- /dev/null +++ b/.github/workflows/hello-world.yml @@ -0,0 +1,11 @@ +name: Hello World Echo + +on: + workflow_dispatch: + +jobs: + echo: + runs-on: ubuntu-latest + steps: + - name: Echo hello world + run: echo "Hello, World!" From a8d18b632af84cb45a81ea2a4d3909c6bd6a2362 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:22:28 +0200 Subject: [PATCH 32/54] add push trigger to Hello World Echo workflow --- .github/workflows/hello-world.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/hello-world.yml b/.github/workflows/hello-world.yml index cc419db..41c8726 100644 --- a/.github/workflows/hello-world.yml +++ b/.github/workflows/hello-world.yml @@ -2,6 +2,7 @@ name: Hello World Echo on: workflow_dispatch: + push: jobs: echo: From d419d3d6cd39a3f80e009f8486b4035373b72283 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:24:42 +0200 Subject: [PATCH 33/54] prevent workflow execution on push events; require manual dispatch instead --- .github/workflows/release.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d00ffb6..6fc7dc5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,8 @@ on: push: tags: - 'v*' + branches: + - upstream-integration-workflow workflow_dispatch: inputs: tag: @@ -34,6 +36,13 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: + - name: Abort when triggered on push + if: ${{ github.event_name == 'push' }} + shell: bash + run: | + echo "::error::This workflow must not be triggered on push. Use workflow_dispatch instead." + exit 1 + - name: Verify runner prerequisites shell: bash run: | From 53cfda944e580ef8b3b890c3549a4c77ca4eea4f Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:25:31 +0200 Subject: [PATCH 34/54] remove Hello World Echo workflow file --- .github/workflows/hello-world.yml | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .github/workflows/hello-world.yml diff --git a/.github/workflows/hello-world.yml b/.github/workflows/hello-world.yml deleted file mode 100644 index 41c8726..0000000 --- a/.github/workflows/hello-world.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Hello World Echo - -on: - workflow_dispatch: - push: - -jobs: - echo: - runs-on: ubuntu-latest - steps: - - name: Echo hello world - run: echo "Hello, World!" From 5491524cf3a26cff9c7c5b1a456fd3c8325f88ef Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 09:25:48 +0200 Subject: [PATCH 35/54] remove branch trigger from release workflow and clean up abort step --- .github/workflows/release.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6fc7dc5..d00ffb6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,6 @@ on: push: tags: - 'v*' - branches: - - upstream-integration-workflow workflow_dispatch: inputs: tag: @@ -36,13 +34,6 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} steps: - - name: Abort when triggered on push - if: ${{ github.event_name == 'push' }} - shell: bash - run: | - echo "::error::This workflow must not be triggered on push. Use workflow_dispatch instead." - exit 1 - - name: Verify runner prerequisites shell: bash run: | From f0a4c2e0664188cc034aea1e9b4af65b203091fa Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 10:10:09 +0200 Subject: [PATCH 36/54] update archive path and environment variables in upstream integration workflow --- .github/workflows/upstream_integration.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 137122b..9003e79 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -79,7 +79,7 @@ jobs: echo "::add-mask::${ARTIFACTORY_TOKEN}" tmp_dir="$(mktemp -d)" - archive_path="${tmp_dir}/toolkit.tar.gz" + archive_path="${tmp_dir}/eb_corbos_toolkit.tar.gz" extract_root="${tmp_dir}/extracted" mkdir -p "${extract_root}" @@ -109,6 +109,7 @@ jobs: cat >> "${GITHUB_ENV}" << EOF TMP_WORK_DIR=${tmp_dir} EXTRACT_ROOT=${extract_root} + ARCHIVE_PATH=${archive_path} WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst @@ -391,12 +392,11 @@ jobs: assets_dir="${TMP_WORK_DIR}/release-assets" mkdir -p "${assets_dir}" + mv "${ARCHIVE_PATH}" "${assets_dir}/eb_corbos_toolkit.tar.gz" + cp "${pdf_src}" "${assets_dir}/user_manual.pdf" tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${html_src}" . - # Full prebuilt tree as a single archive. - tar -czf "${assets_dir}/prebuilt.tar.gz" -C "${prebuilt_src}" . - # Per-target assets: one image archive (named after its .wic file), the # SDK sysroot tarball and the SSH target key for every target directory. for target_dir in "${prebuilt_src}"/*/; do From 1482f3995d5ad605e180009210085d2f425cfb83 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 10:12:22 +0200 Subject: [PATCH 37/54] update README to enhance getting started instructions and clarify usage options --- README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8ed8c99..6d72ec9 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,24 @@ You can explore this car software platform and develop applications, build image ## Getting Started -Detailed documentation, including setup instructions and user guides, is available as part of the release assets. -Check the [Releases](../../releases) page and download the archive attached to the latest release. -Currently, this is [`eb_corbos_toolkit_2.0.0-beta1.tar.gz`](https://github.com/Elektrobit/eb_corbos_toolkit/releases/download/v2.0.0-beta1/eb_corbos_toolkit_2.0.0-beta1.tar.gz). +Detailed documentation, including setup instructions and a User's Manual, is available as part of the GitHub Release Assets. +The [latest User's Manual](https://elektrobit.github.io/eb_corbos_toolkit/) is also available via GitHub Pages. +Check the [Releases](../../releases) page and download any required asset from the latest release. + +You have two options to start using the EB corbos Toolkit. + +### Start with self-contained delivery archive + +- open user manual, follow the instructions from the start +- the DELIVERY_TARBALL_URL is the url pointing to the `eb_corbos_toolkit.tar.gz` asset of the latest GitHub Relase. + You can use the stable "latest release" URL: `https://github.com/elektrobit/eb_corbos_toolkit/releases/latest/download/eb_corbos_toolkit.tar.gz` + +### Start with GitHub repository + +- clone the repository +- open in vscode, re-open in devcontainer, ... +- open user manual, follow the instructions starting with section "Rebuild and Run Target Image". + (the instructions "Obtain EB corbos Toolkit", "Enter Development Container", "Run Prebuilt Target Image" do only work with the self-contained delivery archive ) ## Reporting Issues From ac02cc3f9412dd8e5ae8e6149925b18fa01028e5 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 10:29:09 +0200 Subject: [PATCH 38/54] refactor release workflow to trigger on published releases only and remove draft checks --- .github/workflows/release.yml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d00ffb6..982b6cd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,8 @@ name: Execute Release Activities on: - push: - tags: - - 'v*' + release: + types: [published] workflow_dispatch: inputs: tag: @@ -52,19 +51,6 @@ jobs: tag="${RELEASE_TAG}" echo "Checking release for tag '${tag}'." - if ! release_json="$(gh release view "${tag}" \ - --repo "${GITHUB_REPOSITORY}" \ - --json isDraft,assets 2>/dev/null)"; then - echo "::error::No release is associated with tag '${tag}'." - exit 1 - fi - - is_draft="$(jq -r '.isDraft' <<<"${release_json}")" - if [[ "${is_draft}" != "false" ]]; then - echo "::error::Release for tag '${tag}' is a draft, not a published release." - exit 1 - fi - has_asset="$(jq -r --arg a "${USER_GUIDE_ASSET}" \ '[.assets[].name] | index($a) != null' <<<"${release_json}")" if [[ "${has_asset}" != "true" ]]; then From 6a0c2692d7418bd364c3c3840794f9758e569cb4 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 10:35:36 +0200 Subject: [PATCH 39/54] add error handling for missing release in user guide asset verification --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 982b6cd..932cfa7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -51,6 +51,13 @@ jobs: tag="${RELEASE_TAG}" echo "Checking release for tag '${tag}'." + if ! release_json="$(gh release view "${tag}" \ + --repo "${GITHUB_REPOSITORY}" \ + --json isDraft,assets 2>/dev/null)"; then + echo "::error::No release is associated with tag '${tag}'." + exit 1 + fi + has_asset="$(jq -r --arg a "${USER_GUIDE_ASSET}" \ '[.assets[].name] | index($a) != null' <<<"${release_json}")" if [[ "${has_asset}" != "true" ]]; then From 35a41dd4cac35d480395ac5e49a5a580df87339c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 11:30:32 +0200 Subject: [PATCH 40/54] update README for clarity and consistency in getting started instructions --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6d72ec9..581ee46 100644 --- a/README.md +++ b/README.md @@ -8,22 +8,23 @@ You can explore this car software platform and develop applications, build image Detailed documentation, including setup instructions and a User's Manual, is available as part of the GitHub Release Assets. The [latest User's Manual](https://elektrobit.github.io/eb_corbos_toolkit/) is also available via GitHub Pages. -Check the [Releases](../../releases) page and download any required asset from the latest release. +Check the [GitHub Release](../../releases) page and download any required asset from the latest release. You have two options to start using the EB corbos Toolkit. -### Start with self-contained delivery archive +### Start with Self-Contained Delivery Archive -- open user manual, follow the instructions from the start -- the DELIVERY_TARBALL_URL is the url pointing to the `eb_corbos_toolkit.tar.gz` asset of the latest GitHub Relase. - You can use the stable "latest release" URL: `https://github.com/elektrobit/eb_corbos_toolkit/releases/latest/download/eb_corbos_toolkit.tar.gz` +Open the User's Manual and follow the instructions from the start. +The `DELIVERY_TARBALL_URL` [mentioned in the User's Manual](https://elektrobit.github.io/eb_corbos_toolkit/#_obtain_eb_corbos_toolkit) must be the URL pointing to the `eb_corbos_toolkit.tar.gz` Asset of the latest [GitHub Release](../../releases). -### Start with GitHub repository +### Start with GitHub Repository -- clone the repository -- open in vscode, re-open in devcontainer, ... -- open user manual, follow the instructions starting with section "Rebuild and Run Target Image". - (the instructions "Obtain EB corbos Toolkit", "Enter Development Container", "Run Prebuilt Target Image" do only work with the self-contained delivery archive ) +Clone the repository and open it in a [devcontainer](https://containers.dev/)-capable IDE, e.g [Visual Studio Code](https://code.visualstudio.com/). +Re-open it in the devcontainer. +Open the [User's Manual](https://elektrobit.github.io/eb_corbos_toolkit/) and follow the instructions, starting with the section [Rebuild and Run Target Image](https://elektrobit.github.io/eb_corbos_toolkit/#_rebuild_and_run_target_image). + +> [!NOTE] +> The instructions "Obtain EB corbos Toolkit", "Enter Development Container", and "Run Prebuilt Target Image" only work with the self-contained delivery archive. ## Reporting Issues From 7976991c0681f01423271a6a292f0fae4a3ad14a Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 12:04:14 +0200 Subject: [PATCH 41/54] re-renable test builds and streamline workflow --- .github/workflows/upstream_integration.yml | 149 ++++++++++----------- 1 file changed, 71 insertions(+), 78 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 9003e79..833a9ad 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -56,7 +56,7 @@ jobs: command -v docker >/dev/null command -v jq >/dev/null - - name: Download and unpack archive + - name: Download and unpack upstream delivery archive shell: bash run: | set -euo pipefail @@ -106,6 +106,7 @@ jobs: echo "Extraction complete." + # prepare environment variables for subsequent steps cat >> "${GITHUB_ENV}" << EOF TMP_WORK_DIR=${tmp_dir} EXTRACT_ROOT=${extract_root} @@ -122,24 +123,14 @@ jobs: - name: Validate extracted layout shell: bash run: | - if [[ ! -f "${DEVCONTAINER_ARCHIVE}" ]]; then - echo "::error::Expected container archive path not found in extracted payload." - exit 1 - fi - - if [[ ! -f "${BUILDCONTAINER_ARCHIVE}" ]]; then - echo "::error::Expected build container archive path not found in extracted payload." - exit 1 - fi - - if [[ ! -f "${RUN_SCRIPT}" ]]; then - echo "::error::Expected eb_corbos_toolkit/workspace/scripts/run.sh not found in extracted payload." - exit 1 - fi - - chmod +x "${RUN_SCRIPT}" + for f in "${DEVCONTAINER_ARCHIVE}" "${BUILDCONTAINER_ARCHIVE}" "${RUN_SCRIPT}" "${BITBAKE_EXECUTION_FIXER}"; do + if [[ ! -f "${f}" ]]; then + echo "::error::Expected file not found in extracted payload: ${f}" + exit 1 + fi + done - - name: Load container image + - name: Load container image archives into Docker shell: bash run: | docker load -i "${DEVCONTAINER_ARCHIVE}" @@ -148,61 +139,62 @@ jobs: - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash run: | - "${{ env.BITBAKE_EXECUTION_FIXER }}" --yes - - # - name: Run kas build from extracted run.sh - # shell: bash - # working-directory: ${{ env.WORKSPACE_ROOT }} - # run: | - # "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml - - # - name: Test the fastdev image in qemu - # shell: bash - # working-directory: ${{ env.WORKSPACE_ROOT }} - # run: | - # # run dev container in detached mode and keep it running - # export EXTRA_DOCKER_OPTIONS="-d --log-driver local" - # LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ - # LOG_FILE="/tmp/ebcl_run_devcontainer.log" - - # echo "Starting devcontainer in the background" - # DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') - # if [[ -z "${DEV_CONTAINER_ID}" ]]; then - # echo "::error::Failed to start devcontainer. Log output:" - # cat "$LOG_FILE" - # exit 1 - # fi - # sleep 10 - - # devcontainer_exec() - # { - # docker exec "$DEV_CONTAINER_ID" "$@" - # } - - # echo "Running fastdev in qemu in background, logging to qemu.log" - # devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" - # devcontainer_exec bash -c \ - # "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" - - # echo "Terminating fastdev" - # devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true - - # echo "Waiting for fastdev to power down" - # max_tries=20 - # msg="Power down" - # log="$WORKSPACE_ROOT/qemu.log" - - # for i in $(seq 1 "$max_tries"); do - # if grep -q "${msg}" "${log}" 2>/dev/null; then - # echo "Waiting for \"$msg\" message in $log succeeded" - # exit 0 - # fi - # echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" - # sleep 1 - # done - # echo "Error: Waiting for \"$msg\" message in $log timed out!" - # cat "${log}" - # exit 1 + "${BITBAKE_EXECUTION_FIXER}" --yes + + - name: "Test: Run kas build using extracted run.sh" + shell: bash + run: | + cd "${WORKSPACE_ROOT}" + "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml + + - name: "Test: Boot fastdev image in QEMU" + shell: bash + run: | + cd "${WORKSPACE_ROOT}" + # run dev container in detached mode and keep it running + export EXTRA_DOCKER_OPTIONS="-d --log-driver local" + LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ + LOG_FILE="/tmp/ebcl_run_devcontainer.log" + + echo "Starting devcontainer in the background" + DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') + if [[ -z "${DEV_CONTAINER_ID}" ]]; then + echo "::error::Failed to start devcontainer. Log output:" + cat "$LOG_FILE" + exit 1 + fi + sleep 10 + + devcontainer_exec() + { + docker exec "$DEV_CONTAINER_ID" "$@" + } + + echo "Running fastdev in qemu in background, logging to qemu.log" + devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" + devcontainer_exec bash -c \ + "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" + + echo "Terminating fastdev" + devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true + + echo "Waiting for fastdev to power down" + max_tries=20 + msg="Power down" + log="$WORKSPACE_ROOT/qemu.log" + + for i in $(seq 1 "$max_tries"); do + if grep -q "${msg}" "${log}" 2>/dev/null; then + echo "Waiting for \"$msg\" message in $log succeeded" + rm -f "${log}" + exit 0 + fi + echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" + sleep 1 + done + echo "Error: Waiting for \"$msg\" message in $log timed out!" + cat "${log}" + exit 1 - name: Checkout repository for integration uses: actions/checkout@v4 @@ -220,7 +212,7 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - BRANCH="integration" + BRANCH="upstream-integration" echo "INTEGRATION_BRANCH=${BRANCH}" >> "${GITHUB_ENV}" if git ls-remote --exit-code --heads origin "${BRANCH}" >/dev/null 2>&1; then @@ -232,7 +224,7 @@ jobs: git checkout -B "${BRANCH}" origin/main fi - - name: Replace working copy with upstream workspace + - name: Integrate upstream workspace working-directory: integration-repo shell: bash run: | @@ -273,7 +265,7 @@ jobs: # Ignore the "prebuilt" and "build" sub-folders. rsync -a --exclude='prebuilt' --exclude='build' "${WORKSPACE_ROOT}/." . - - name: Commit integrated upstream content + - name: Commit integrated upstream workspace and push to integration branch working-directory: integration-repo env: RELEASE_VERSION: ${{ inputs.release_version }} @@ -345,8 +337,9 @@ jobs: if git diff --cached --quiet; then echo "Tags already match; nothing to commit." else - git commit -m "Rewrite devcontainer image tag for PR" - git push origin "HEAD:${INTEGRATION_BRANCH}" + # Amend the previous commit to include the tag rewrite, so that the previous container tag is not left in the integration branch history. + git commit --amend --no-edit + git push --force origin "HEAD:${INTEGRATION_BRANCH}" fi - name: Update container tags and push to registry From b60aa53eb8f810c5311caf0fe0426fd4ec14f6fc Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 12:06:35 +0200 Subject: [PATCH 42/54] update workflow name for clarity on upstream integration process --- .github/workflows/upstream_integration.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 833a9ad..cc39f0d 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -1,4 +1,4 @@ -name: Update Toolkit from Internal Release Archive +name: Update Toolkit from Upstream Release Archive on: workflow_dispatch: @@ -23,6 +23,7 @@ permissions: jobs: build-from-archive: + name: Integrate Upstream Release Archive runs-on: ubuntu-latest steps: From 26bf505f51cb8786853637d9d952d10a0deefe29 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 12:07:53 +0200 Subject: [PATCH 43/54] refactor workflow steps for clarity in tagging and asset packaging --- .github/workflows/upstream_integration.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index cc39f0d..84c113f 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -310,7 +310,7 @@ jobs: echo "pr_tag=${tag_prefix}${pr_number}" >> "${GITHUB_OUTPUT}" fi - - name: Rewrite devcontainer image tag for PR + - name: Rewrite devcontainer image tag to pull request number id: rewrite-tag working-directory: integration-repo shell: bash @@ -359,7 +359,7 @@ jobs: docker push "${DEVCONTAINER_IMAGE}:${new_tag}" docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" - - name: Package assets + - name: Package release assets shell: bash run: | set -euo pipefail @@ -420,7 +420,7 @@ jobs: echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" - - name: Create or update draft release + - name: Create or update draft release and upload assets working-directory: integration-repo env: GH_TOKEN: ${{ github.token }} From f817d7464c009db9f960cf7275b50e68e5ef6398 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 12:12:01 +0200 Subject: [PATCH 44/54] refactor release workflow for clarity and consistency in asset verification --- .github/workflows/release.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 932cfa7..9eada85 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,8 @@ env: RELEASE_TAG: ${{ inputs.tag || github.ref_name }} jobs: - publish-user-guide: + execute-release-activities: + name: Execute Release Activities runs-on: ubuntu-latest environment: name: github-pages @@ -41,7 +42,7 @@ jobs: command -v jq >/dev/null command -v tar >/dev/null - - name: Verify published release contains the user guide asset + - name: Verify published release contains the User's Manual asset env: GH_TOKEN: ${{ github.token }} shell: bash @@ -53,7 +54,7 @@ jobs: if ! release_json="$(gh release view "${tag}" \ --repo "${GITHUB_REPOSITORY}" \ - --json isDraft,assets 2>/dev/null)"; then + --json assets 2>/dev/null)"; then echo "::error::No release is associated with tag '${tag}'." exit 1 fi @@ -67,7 +68,7 @@ jobs: echo "Published release for tag '${tag}' contains '${USER_GUIDE_ASSET}'." - - name: Download and extract the user guide asset + - name: Download and extract the User's Manual asset env: GH_TOKEN: ${{ github.token }} shell: bash @@ -91,6 +92,6 @@ jobs: with: path: _site - - name: Deploy to GitHub Pages + - name: Deploy User's Manual to GitHub Pages id: deployment uses: actions/deploy-pages@v4 From ed72017ccb6d7f18c88fbbc1890f08d42fa7f0a4 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 12:36:37 +0200 Subject: [PATCH 45/54] refactor upstream integration workflow for improved error handling and resource cleanup --- .github/workflows/upstream_integration.yml | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 84c113f..b214bb6 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -21,10 +21,17 @@ permissions: packages: write # push containers to ghcr.io pull-requests: write # create integration PR +# Serialize runs so overlapping executions cannot force-push over each other's +# integration branch. Do not cancel an in-progress run mid-integration. +concurrency: + group: upstream-integration + cancel-in-progress: false + jobs: build-from-archive: name: Integrate Upstream Release Archive runs-on: ubuntu-latest + timeout-minutes: 120 steps: - name: Authorize triggering actor @@ -124,6 +131,7 @@ jobs: - name: Validate extracted layout shell: bash run: | + set -euo pipefail for f in "${DEVCONTAINER_ARCHIVE}" "${BUILDCONTAINER_ARCHIVE}" "${RUN_SCRIPT}" "${BITBAKE_EXECUTION_FIXER}"; do if [[ ! -f "${f}" ]]; then echo "::error::Expected file not found in extracted payload: ${f}" @@ -134,17 +142,20 @@ jobs: - name: Load container image archives into Docker shell: bash run: | + set -euo pipefail docker load -i "${DEVCONTAINER_ARCHIVE}" docker load -i "${BUILDCONTAINER_ARCHIVE}" - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash run: | + set -euo pipefail "${BITBAKE_EXECUTION_FIXER}" --yes - name: "Test: Run kas build using extracted run.sh" shell: bash run: | + set -euo pipefail cd "${WORKSPACE_ROOT}" "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml @@ -164,6 +175,8 @@ jobs: cat "$LOG_FILE" exit 1 fi + # Expose the container ID so the always() cleanup step can tear it down. + echo "DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" >> "${GITHUB_ENV}" sleep 10 devcontainer_exec() @@ -455,3 +468,30 @@ jobs: --title "${RELEASE_VERSION}" \ "${assets[@]}" fi + + - name: Clean up runner resources + if: always() + shell: bash + run: | + set +e + + # Stop and remove the detached devcontainer, if it was started. + if [[ -n "${DEV_CONTAINER_ID:-}" ]]; then + echo "Removing devcontainer ${DEV_CONTAINER_ID}" + docker rm -f "${DEV_CONTAINER_ID}" + fi + + # Kill any lingering QEMU processes started by the smoke test. + pkill -f qemu-system || true + + # Drop registry credentials written by docker login. + docker logout ghcr.io || true + + # Remove the temporary working directory used for download/extraction. + if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then + echo "Removing temporary work directory ${TMP_WORK_DIR}" + rm -rf -- "${TMP_WORK_DIR}" + fi + + exit 0 + From 9fcf3842576e0d7ff3bc059829f0b0b174af7cae Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 13:11:06 +0200 Subject: [PATCH 46/54] add scripts for downloading, integrating, and packaging release assets in the workflow --- .github/scripts/download_archive.sh | 73 +++++++ .github/scripts/integrate_workspace.sh | 45 +++++ .github/scripts/package_release_assets.sh | 70 +++++++ .github/scripts/qemu_smoke_test.sh | 62 ++++++ .github/workflows/release.yml | 1 + .github/workflows/upstream_integration.yml | 217 ++------------------- 6 files changed, 264 insertions(+), 204 deletions(-) create mode 100755 .github/scripts/download_archive.sh create mode 100755 .github/scripts/integrate_workspace.sh create mode 100755 .github/scripts/package_release_assets.sh create mode 100755 .github/scripts/qemu_smoke_test.sh diff --git a/.github/scripts/download_archive.sh b/.github/scripts/download_archive.sh new file mode 100755 index 0000000..3f884e8 --- /dev/null +++ b/.github/scripts/download_archive.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Copyright 2026 Elektrobit. All rights reserved. +# +# Download the upstream toolkit archive referenced by the workflow_dispatch +# inputs, extract it into a temporary directory and export the resulting paths +# to GITHUB_ENV for subsequent steps. +# +# Required environment: +# GITHUB_EVENT_PATH Path to the event payload holding the dispatch inputs. +# GITHUB_ENV Path to the environment file for downstream steps. +set -euo pipefail + +ARTIFACT_URL="$(jq -r '.inputs.artifact_url // empty' "${GITHUB_EVENT_PATH}")" +ARTIFACTORY_TOKEN="$(jq -r '.inputs.artifactory_token // empty' "${GITHUB_EVENT_PATH}")" + +if [[ -z "${ARTIFACTORY_TOKEN}" ]]; then + echo "::error::Required workflow input artifactory_token is not set." + exit 1 +fi + +if [[ -z "${ARTIFACT_URL}" ]]; then + echo "::error::Required workflow input artifact_url is not set." + exit 1 +fi + +# Treat the manual input URL as sensitive operational data. +echo "::add-mask::${ARTIFACT_URL}" +echo "::add-mask::${ARTIFACTORY_TOKEN}" + +tmp_dir="$(mktemp -d)" +archive_path="${tmp_dir}/eb_corbos_toolkit.tar.gz" +extract_root="${tmp_dir}/extracted" + +mkdir -p "${extract_root}" + +echo "Starting archive download (this may take a while for large files)..." +echo "Download target: ${archive_path}" + +curl \ + --fail \ + --progress-bar \ + --show-error \ + --location \ + --retry 3 \ + --retry-delay 5 \ + --retry-all-errors \ + --header "Authorization: Bearer ${ARTIFACTORY_TOKEN}" \ + --output "${archive_path}" \ + --url "${ARTIFACT_URL}" + +archive_size_bytes="$(wc -c < "${archive_path}")" +archive_size_mib="$(awk "BEGIN { printf \"%.2f\", ${archive_size_bytes}/1024/1024 }")" +echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." + +echo "Starting archive extraction into ${extract_root}..." + +tar -xzf "${archive_path}" -C "${extract_root}" + +echo "Extraction complete." + +# Prepare environment variables for subsequent steps. +cat >> "${GITHUB_ENV}" << EOF +TMP_WORK_DIR=${tmp_dir} +EXTRACT_ROOT=${extract_root} +ARCHIVE_PATH=${archive_path} +WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace +DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst +BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst +DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd64 +BUILDCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-buildcontainer-amd64 +RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh +BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh +EOF diff --git a/.github/scripts/integrate_workspace.sh b/.github/scripts/integrate_workspace.sh new file mode 100755 index 0000000..7d8a58c --- /dev/null +++ b/.github/scripts/integrate_workspace.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Copyright 2026 Elektrobit. All rights reserved. +# +# Replace the integration repository's working tree with the upstream workspace, +# preserving repository-owned metadata files. Must be run from the root of the +# integration repository checkout. +# +# Required environment: +# WORKSPACE_ROOT Extracted upstream workspace directory to copy in. +set -euo pipefail + +if [[ ! -d "${WORKSPACE_ROOT}" ]]; then + echo "::error::WORKSPACE_ROOT '${WORKSPACE_ROOT}' does not exist." + exit 1 +fi + +# Remove all tracked and untracked content except the repository metadata and +# files that must remain in the integration repository. Add entries to this list +# when additional repository-owned content should be preserved. +preserve_paths=( + '.git' + '.github' + '.gitignore' + 'CODE_OF_CONDUCT.md' + 'README.md' +) + +while IFS= read -r -d '' path; do + name="${path#./}" + preserve=false + for preserve_path in "${preserve_paths[@]}"; do + if [[ "${name}" == "${preserve_path}" ]]; then + preserve=true + break + fi + done + + if [[ "${preserve}" != true ]]; then + rm -rf -- "${path}" + fi +done < <(find . -mindepth 1 -maxdepth 1 -print0) + +# Copy the upstream workspace on top, preserving flags, mtimes, ownership. +# Ignore the "prebuilt" and "build" sub-folders. +rsync -a --exclude='prebuilt' --exclude='build' "${WORKSPACE_ROOT}/." . diff --git a/.github/scripts/package_release_assets.sh b/.github/scripts/package_release_assets.sh new file mode 100755 index 0000000..f12d3f1 --- /dev/null +++ b/.github/scripts/package_release_assets.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +# Copyright 2026 Elektrobit. All rights reserved. +# +# Collect the release assets (toolkit archive, user manual, prebuilt per-target +# images, SDK sysroots and SSH keys) into a single directory and export its path +# to GITHUB_ENV. +# +# Required environment: +# EXTRACT_ROOT Root of the extracted upstream delivery. +# WORKSPACE_ROOT Extracted upstream workspace directory. +# TMP_WORK_DIR Temporary working directory for staging assets. +# ARCHIVE_PATH Path to the downloaded toolkit archive. +# GITHUB_ENV Path to the environment file for downstream steps. +set -euo pipefail + +pdf_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/user_manual.pdf" +html_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/html" +prebuilt_src="${WORKSPACE_ROOT}/prebuilt" + +if [[ ! -f "${pdf_src}" ]]; then + echo "::error::Expected user manual PDF not found at ${pdf_src}." + exit 1 +fi + +if [[ ! -d "${html_src}" ]]; then + echo "::error::Expected HTML user manual directory not found at ${html_src}." + exit 1 +fi + +if [[ ! -d "${prebuilt_src}" ]]; then + echo "::error::Expected prebuilt directory not found at ${prebuilt_src}." + exit 1 +fi + +assets_dir="${TMP_WORK_DIR}/release-assets" +mkdir -p "${assets_dir}" + +mv "${ARCHIVE_PATH}" "${assets_dir}/eb_corbos_toolkit.tar.gz" + +cp "${pdf_src}" "${assets_dir}/user_manual.pdf" +tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${html_src}" . + +# Per-target assets: one image archive (named after its .wic file), the SDK +# sysroot tarball and the SSH target key for every target directory. +for target_dir in "${prebuilt_src}"/*/; do + [[ -d "${target_dir}" ]] || continue + + image_dir="${target_dir}image" + if [[ -d "${image_dir}" ]]; then + wic_file="$(find "${image_dir}" -maxdepth 1 -name '*.wic' -print -quit)" + if [[ -z "${wic_file}" ]]; then + echo "::error::No .wic file found in ${image_dir}." + exit 1 + fi + image_base="$(basename "${wic_file}" .wic)" + tar -czf "${assets_dir}/${image_base}.tar.gz" -C "${image_dir}" . + fi + + sdk_dir="${target_dir}sysroot" + if [[ -d "${sdk_dir}" ]]; then + find "${sdk_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; + fi + + key_dir="${target_dir}ssh_keys" + if [[ -d "${key_dir}" ]]; then + find "${key_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; + fi +done + +echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" diff --git a/.github/scripts/qemu_smoke_test.sh b/.github/scripts/qemu_smoke_test.sh new file mode 100755 index 0000000..10a7dca --- /dev/null +++ b/.github/scripts/qemu_smoke_test.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# Copyright 2026 Elektrobit. All rights reserved. +# +# Smoke test: boot the freshly built "fastdev" image in QEMU inside the +# devcontainer, wait for SSH availability, power it down cleanly and confirm the +# shutdown message appears in the QEMU log. +# +# Required environment: +# WORKSPACE_ROOT Extracted upstream workspace directory. +# RUN_SCRIPT Path to the workspace run.sh helper. +# GITHUB_ENV Path to the environment file for downstream steps. +set -euo pipefail + +cd "${WORKSPACE_ROOT}" + +# Run the dev container in detached mode and keep it running. +export EXTRA_DOCKER_OPTIONS="-d --log-driver local" +LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || + LOG_FILE="/tmp/ebcl_run_devcontainer.log" + +echo "Starting devcontainer in the background" +DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "${LOG_FILE}" | grep -oE '^[0-9a-f]{64}$') +if [[ -z "${DEV_CONTAINER_ID}" ]]; then + echo "::error::Failed to start devcontainer. Log output:" + cat "${LOG_FILE}" + exit 1 +fi + +# Expose the container ID so the always() cleanup step can tear it down. +echo "DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" >> "${GITHUB_ENV}" +sleep 10 + +devcontainer_exec() { + docker exec "${DEV_CONTAINER_ID}" "$@" +} + +echo "Running fastdev in qemu in background, logging to qemu.log" +devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" +devcontainer_exec bash -c \ + "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" + +echo "Terminating fastdev" +devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true + +echo "Waiting for fastdev to power down" +max_tries=20 +msg="Power down" +log="${WORKSPACE_ROOT}/qemu.log" + +for i in $(seq 1 "${max_tries}"); do + if grep -q "${msg}" "${log}" 2>/dev/null; then + echo "Waiting for \"${msg}\" message in ${log} succeeded" + rm -f "${log}" + exit 0 + fi + echo "Waiting for \"${msg}\" message in ${log} ... (${i}/${max_tries})" + sleep 1 +done + +echo "Error: Waiting for \"${msg}\" message in ${log} timed out!" +cat "${log}" +exit 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9eada85..4e8be0c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,4 @@ +# Copyright 2026 Elektrobit. All rights reserved. name: Execute Release Activities on: diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index b214bb6..7fa1bcf 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -1,3 +1,4 @@ +# Copyright 2026 Elektrobit. All rights reserved. name: Update Toolkit from Upstream Release Archive on: @@ -32,6 +33,8 @@ jobs: name: Integrate Upstream Release Archive runs-on: ubuntu-latest timeout-minutes: 120 + env: + SCRIPTS_DIR: ${{ github.workspace }}/.github/scripts steps: - name: Authorize triggering actor @@ -64,69 +67,15 @@ jobs: command -v docker >/dev/null command -v jq >/dev/null + - name: Checkout workflow scripts + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github/scripts + - name: Download and unpack upstream delivery archive shell: bash - run: | - set -euo pipefail - - ARTIFACT_URL="$(jq -r '.inputs.artifact_url // empty' "${GITHUB_EVENT_PATH}")" - ARTIFACTORY_TOKEN="$(jq -r '.inputs.artifactory_token // empty' "${GITHUB_EVENT_PATH}")" - - if [[ -z "${ARTIFACTORY_TOKEN:-}" ]]; then - echo "::error::Required workflow input artifactory_token is not set." - exit 1 - fi - - if [[ -z "${ARTIFACT_URL:-}" ]]; then - echo "::error::Required workflow input artifact_url is not set." - exit 1 - fi - - # Treat the manual input URL as sensitive operational data. - echo "::add-mask::${ARTIFACT_URL}" - echo "::add-mask::${ARTIFACTORY_TOKEN}" - - tmp_dir="$(mktemp -d)" - archive_path="${tmp_dir}/eb_corbos_toolkit.tar.gz" - extract_root="${tmp_dir}/extracted" - - mkdir -p "${extract_root}" - - echo "Starting archive download (this may take a while for large files)..." - echo "Download target: ${archive_path}" - - curl \ - --fail \ - --progress-bar \ - --show-error \ - --location \ - --header "Authorization: Bearer ${ARTIFACTORY_TOKEN}" \ - --output "${archive_path}" \ - --url "${ARTIFACT_URL}" - - archive_size_bytes="$(wc -c < "${archive_path}")" - archive_size_mib="$(awk "BEGIN { printf \"%.2f\", ${archive_size_bytes}/1024/1024 }")" - echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." - - echo "Starting archive extraction into ${extract_root}..." - - tar -xzf "${archive_path}" -C "${extract_root}" - - echo "Extraction complete." - - # prepare environment variables for subsequent steps - cat >> "${GITHUB_ENV}" << EOF - TMP_WORK_DIR=${tmp_dir} - EXTRACT_ROOT=${extract_root} - ARCHIVE_PATH=${archive_path} - WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace - DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst - BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst - DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd64 - BUILDCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-buildcontainer-amd64 - RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh - BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh - EOF + run: bash "${SCRIPTS_DIR}/download_archive.sh" - name: Validate extracted layout shell: bash @@ -161,54 +110,7 @@ jobs: - name: "Test: Boot fastdev image in QEMU" shell: bash - run: | - cd "${WORKSPACE_ROOT}" - # run dev container in detached mode and keep it running - export EXTRA_DOCKER_OPTIONS="-d --log-driver local" - LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || \ - LOG_FILE="/tmp/ebcl_run_devcontainer.log" - - echo "Starting devcontainer in the background" - DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "$LOG_FILE" | grep -oE '^[0-9a-f]{64}$') - if [[ -z "${DEV_CONTAINER_ID}" ]]; then - echo "::error::Failed to start devcontainer. Log output:" - cat "$LOG_FILE" - exit 1 - fi - # Expose the container ID so the always() cleanup step can tear it down. - echo "DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" >> "${GITHUB_ENV}" - sleep 10 - - devcontainer_exec() - { - docker exec "$DEV_CONTAINER_ID" "$@" - } - - echo "Running fastdev in qemu in background, logging to qemu.log" - devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" - devcontainer_exec bash -c \ - "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" - - echo "Terminating fastdev" - devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true - - echo "Waiting for fastdev to power down" - max_tries=20 - msg="Power down" - log="$WORKSPACE_ROOT/qemu.log" - - for i in $(seq 1 "$max_tries"); do - if grep -q "${msg}" "${log}" 2>/dev/null; then - echo "Waiting for \"$msg\" message in $log succeeded" - rm -f "${log}" - exit 0 - fi - echo "Waiting for \"$msg\" message in $log ... ($i/$max_tries)" - sleep 1 - done - echo "Error: Waiting for \"$msg\" message in $log timed out!" - cat "${log}" - exit 1 + run: bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" - name: Checkout repository for integration uses: actions/checkout@v4 @@ -241,43 +143,7 @@ jobs: - name: Integrate upstream workspace working-directory: integration-repo shell: bash - run: | - set -euo pipefail - - if [[ ! -d "${WORKSPACE_ROOT}" ]]; then - echo "::error::WORKSPACE_ROOT '${WORKSPACE_ROOT}' does not exist." - exit 1 - fi - - # Remove all tracked and untracked content except the repository metadata - # and files that must remain in the integration repository. Add entries to - # this list when additional repository-owned content should be preserved. - preserve_paths=( - '.git' - '.github' - '.gitignore' - 'CODE_OF_CONDUCT.md' - 'README.md' - ) - - while IFS= read -r -d '' path; do - name="${path#./}" - preserve=false - for preserve_path in "${preserve_paths[@]}"; do - if [[ "${name}" == "${preserve_path}" ]]; then - preserve=true - break - fi - done - - if [[ "${preserve}" != true ]]; then - rm -rf -- "${path}" - fi - done < <(find . -mindepth 1 -maxdepth 1 -print0) - - # Copy the upstream workspace on top, preserving flags, mtimes, ownership. - # Ignore the "prebuilt" and "build" sub-folders. - rsync -a --exclude='prebuilt' --exclude='build' "${WORKSPACE_ROOT}/." . + run: bash "${SCRIPTS_DIR}/integrate_workspace.sh" - name: Commit integrated upstream workspace and push to integration branch working-directory: integration-repo @@ -374,64 +240,7 @@ jobs: - name: Package release assets shell: bash - run: | - set -euo pipefail - - pdf_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/user_manual.pdf" - html_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/html" - prebuilt_src="${WORKSPACE_ROOT}/prebuilt" - - if [[ ! -f "${pdf_src}" ]]; then - echo "::error::Expected user manual PDF not found at ${pdf_src}." - exit 1 - fi - - if [[ ! -d "${html_src}" ]]; then - echo "::error::Expected HTML user manual directory not found at ${html_src}." - exit 1 - fi - - if [[ ! -d "${prebuilt_src}" ]]; then - echo "::error::Expected prebuilt directory not found at ${prebuilt_src}." - exit 1 - fi - - assets_dir="${TMP_WORK_DIR}/release-assets" - mkdir -p "${assets_dir}" - - mv "${ARCHIVE_PATH}" "${assets_dir}/eb_corbos_toolkit.tar.gz" - - cp "${pdf_src}" "${assets_dir}/user_manual.pdf" - tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${html_src}" . - - # Per-target assets: one image archive (named after its .wic file), the - # SDK sysroot tarball and the SSH target key for every target directory. - for target_dir in "${prebuilt_src}"/*/; do - [[ -d "${target_dir}" ]] || continue - - image_dir="${target_dir}image" - if [[ -d "${image_dir}" ]]; then - wic_file="$(find "${image_dir}" -maxdepth 1 -name '*.wic' -print -quit)" - if [[ -z "${wic_file}" ]]; then - echo "::error::No .wic file found in ${image_dir}." - exit 1 - fi - image_base="$(basename "${wic_file}" .wic)" - tar -czf "${assets_dir}/${image_base}.tar.gz" -C "${image_dir}" . - fi - - sdk_dir="${target_dir}sysroot" - if [[ -d "${sdk_dir}" ]]; then - find "${sdk_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; - fi - - key_dir="${target_dir}ssh_keys" - if [[ -d "${key_dir}" ]]; then - find "${key_dir}" -maxdepth 1 -type f -exec cp {} "${assets_dir}/" \; - fi - done - - echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" + run: bash "${SCRIPTS_DIR}/package_release_assets.sh" - name: Create or update draft release and upload assets working-directory: integration-repo From e58bce10ebe315de27e44bc444b955910fd8401f Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 13:52:37 +0200 Subject: [PATCH 47/54] integrate all validation to the earliest possible location (fail fast) --- .github/scripts/download_archive.sh | 44 ++++++++++++++++++---- .github/scripts/package_release_assets.sh | 31 +++------------ .github/workflows/upstream_integration.yml | 15 +------- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/.github/scripts/download_archive.sh b/.github/scripts/download_archive.sh index 3f884e8..e3b9b51 100755 --- a/.github/scripts/download_archive.sh +++ b/.github/scripts/download_archive.sh @@ -23,7 +23,7 @@ if [[ -z "${ARTIFACT_URL}" ]]; then exit 1 fi -# Treat the manual input URL as sensitive operational data. +# Treat the manual input URL and token as sensitive operational data. echo "::add-mask::${ARTIFACT_URL}" echo "::add-mask::${ARTIFACTORY_TOKEN}" @@ -33,7 +33,7 @@ extract_root="${tmp_dir}/extracted" mkdir -p "${extract_root}" -echo "Starting archive download (this may take a while for large files)..." +echo "Starting upstream delivery archive download (this may take a while for large files)..." echo "Download target: ${archive_path}" curl \ @@ -52,22 +52,50 @@ archive_size_bytes="$(wc -c < "${archive_path}")" archive_size_mib="$(awk "BEGIN { printf \"%.2f\", ${archive_size_bytes}/1024/1024 }")" echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." -echo "Starting archive extraction into ${extract_root}..." +echo "Starting upstream delivery archive extraction into ${extract_root}..." tar -xzf "${archive_path}" -C "${extract_root}" echo "Extraction complete." +toolkit_root="${extract_root}/eb_corbos_toolkit" +workspace_root="${toolkit_root}/workspace" +devcontainer_archive="${toolkit_root}/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst" +buildcontainer_archive="${toolkit_root}/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst" +run_script="${workspace_root}/scripts/run.sh" +bitbake_execution_fixer="${workspace_root}/.devcontainer/scripts/check_userns_restriction.sh" +manual_pdf="${toolkit_root}/doc/user_manual.pdf" +manual_html_dir="${toolkit_root}/doc/html" +prebuilt_dir="${workspace_root}/prebuilt" + +echo "Validating extracted layout..." +for f in "${devcontainer_archive}" "${buildcontainer_archive}" "${run_script}" "${bitbake_execution_fixer}" "${manual_pdf}"; do + if [[ ! -f "${f}" ]]; then + echo "::error::Expected file not found in extracted upstream delivery archive: ${f}" + exit 1 + fi +done +for d in "${manual_html_dir}" "${prebuilt_dir}"; do + if [[ ! -d "${d}" ]]; then + echo "::error::Expected directory not found in extracted upstream delivery archive: ${d}" + exit 1 + fi +done +echo "Extracted layout looks good." + # Prepare environment variables for subsequent steps. cat >> "${GITHUB_ENV}" << EOF TMP_WORK_DIR=${tmp_dir} EXTRACT_ROOT=${extract_root} ARCHIVE_PATH=${archive_path} -WORKSPACE_ROOT=${extract_root}/eb_corbos_toolkit/workspace -DEVCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/devcontainer-trixie-ebclfsa-amd64.docker-archive.zst -BUILDCONTAINER_ARCHIVE=${extract_root}/eb_corbos_toolkit/containers/buildcontainer-trixie-ebclfsa-amd64.docker-archive.zst +WORKSPACE_ROOT=${workspace_root} +DEVCONTAINER_ARCHIVE=${devcontainer_archive} +BUILDCONTAINER_ARCHIVE=${buildcontainer_archive} DEVCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-devcontainer-amd64 BUILDCONTAINER_IMAGE=ghcr.io/elektrobit/eb-corbos-toolkit-buildcontainer-amd64 -RUN_SCRIPT=${extract_root}/eb_corbos_toolkit/workspace/scripts/run.sh -BITBAKE_EXECUTION_FIXER=${extract_root}/eb_corbos_toolkit/workspace/.devcontainer/scripts/check_userns_restriction.sh +RUN_SCRIPT=${run_script} +BITBAKE_EXECUTION_FIXER=${bitbake_execution_fixer} +MANUAL_PDF=${manual_pdf} +MANUAL_HTML_DIR=${manual_html_dir} +PREBUILT_DIR=${prebuilt_dir} EOF diff --git a/.github/scripts/package_release_assets.sh b/.github/scripts/package_release_assets.sh index f12d3f1..9c04696 100755 --- a/.github/scripts/package_release_assets.sh +++ b/.github/scripts/package_release_assets.sh @@ -6,43 +6,24 @@ # to GITHUB_ENV. # # Required environment: -# EXTRACT_ROOT Root of the extracted upstream delivery. -# WORKSPACE_ROOT Extracted upstream workspace directory. # TMP_WORK_DIR Temporary working directory for staging assets. # ARCHIVE_PATH Path to the downloaded toolkit archive. +# MANUAL_PDF Path to the user manual PDF. +# MANUAL_HTML_DIR Directory holding the HTML user manual. +# PREBUILT_DIR Directory holding the per-target prebuilt artifacts. # GITHUB_ENV Path to the environment file for downstream steps. set -euo pipefail -pdf_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/user_manual.pdf" -html_src="${EXTRACT_ROOT}/eb_corbos_toolkit/doc/html" -prebuilt_src="${WORKSPACE_ROOT}/prebuilt" - -if [[ ! -f "${pdf_src}" ]]; then - echo "::error::Expected user manual PDF not found at ${pdf_src}." - exit 1 -fi - -if [[ ! -d "${html_src}" ]]; then - echo "::error::Expected HTML user manual directory not found at ${html_src}." - exit 1 -fi - -if [[ ! -d "${prebuilt_src}" ]]; then - echo "::error::Expected prebuilt directory not found at ${prebuilt_src}." - exit 1 -fi - assets_dir="${TMP_WORK_DIR}/release-assets" mkdir -p "${assets_dir}" mv "${ARCHIVE_PATH}" "${assets_dir}/eb_corbos_toolkit.tar.gz" - -cp "${pdf_src}" "${assets_dir}/user_manual.pdf" -tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${html_src}" . +cp "${MANUAL_PDF}" "${assets_dir}/user_manual.pdf" +tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${MANUAL_HTML_DIR}" . # Per-target assets: one image archive (named after its .wic file), the SDK # sysroot tarball and the SSH target key for every target directory. -for target_dir in "${prebuilt_src}"/*/; do +for target_dir in "${PREBUILT_DIR}"/*/; do [[ -d "${target_dir}" ]] || continue image_dir="${target_dir}image" diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 7fa1bcf..727943e 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -73,21 +73,10 @@ jobs: sparse-checkout: | .github/scripts - - name: Download and unpack upstream delivery archive + - name: Download, unpack, and validate upstream delivery archive shell: bash run: bash "${SCRIPTS_DIR}/download_archive.sh" - - name: Validate extracted layout - shell: bash - run: | - set -euo pipefail - for f in "${DEVCONTAINER_ARCHIVE}" "${BUILDCONTAINER_ARCHIVE}" "${RUN_SCRIPT}" "${BITBAKE_EXECUTION_FIXER}"; do - if [[ ! -f "${f}" ]]; then - echo "::error::Expected file not found in extracted payload: ${f}" - exit 1 - fi - done - - name: Load container image archives into Docker shell: bash run: | @@ -299,7 +288,7 @@ jobs: # Remove the temporary working directory used for download/extraction. if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then echo "Removing temporary work directory ${TMP_WORK_DIR}" - rm -rf -- "${TMP_WORK_DIR}" + sudo rm -rf -- "${TMP_WORK_DIR}" fi exit 0 From 679fc63ba689a2094d9a08faf0c8788bd78b6d3c Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 13:57:07 +0200 Subject: [PATCH 48/54] enhance workflow documentation for release and upstream integration processes --- .github/workflows/release.yml | 10 ++++++++++ .github/workflows/upstream_integration.yml | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4e8be0c..2373944 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,14 @@ # Copyright 2026 Elektrobit. All rights reserved. +# +# Execute Release Activities +# +# This workflow shall execute all on-release activities for the EB corbos Toolkit. +# For now, this only publishes the User's Manual to GitHub Pages when a release is created. +# The workflow runs automatically when a release is published, or manually +# via workflow_dispatch by supplying the target release tag. It verifies that +# the release contains the expected User's Manual asset, downloads and extracts +# it, then deploys the contents to GitHub Pages. + name: Execute Release Activities on: diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 727943e..a3be78d 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -1,6 +1,18 @@ # Copyright 2026 Elektrobit. All rights reserved. name: Update Toolkit from Upstream Release Archive +# Integrates an upstream EB corbos toolkit release archive into this repository. +# The workflow downloads and unpacks the delivery archive, loads and smoke-tests +# the container images (kas build + QEMU boot of the fastdev image), opens or +# updates an integration pull request, retags and pushes the container images to +# ghcr.io, and creates/updates a draft GitHub release with the collected assets. +# +# Access control: this workflow is manually triggered (workflow_dispatch) and may +# only be run by a small set of trusted actors. The first job step aborts unless +# the triggering actor is listed in the WORKFLOW_ALLOWED_ACTORS repository +# variable (a comma-separated list of GitHub usernames). It also requires a +# privileged token input, so it must not be exposed to untrusted contributors. + on: workflow_dispatch: inputs: From f4232d4afb9d4e18bd31a93015fb683f8e7c11eb Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 14:21:30 +0200 Subject: [PATCH 49/54] Apply suggestions from code review Co-authored-by: Viktor Zeissler <58266231+vzeissler@users.noreply.github.com> --- .github/workflows/upstream_integration.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index a3be78d..3e71347 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -86,20 +86,17 @@ jobs: .github/scripts - name: Download, unpack, and validate upstream delivery archive - shell: bash - run: bash "${SCRIPTS_DIR}/download_archive.sh" + run: "${SCRIPTS_DIR}/download_archive.sh" - name: Load container image archives into Docker shell: bash run: | - set -euo pipefail docker load -i "${DEVCONTAINER_ARCHIVE}" docker load -i "${BUILDCONTAINER_ARCHIVE}" - name: "Fix BitBake execution issue on Ubuntu 23.10+" shell: bash run: | - set -euo pipefail "${BITBAKE_EXECUTION_FIXER}" --yes - name: "Test: Run kas build using extracted run.sh" @@ -143,8 +140,7 @@ jobs: - name: Integrate upstream workspace working-directory: integration-repo - shell: bash - run: bash "${SCRIPTS_DIR}/integrate_workspace.sh" + run: "${SCRIPTS_DIR}/integrate_workspace.sh" - name: Commit integrated upstream workspace and push to integration branch working-directory: integration-repo From 16407edf4d44089753cf242b1157bdc1909c2b5d Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 14:22:53 +0200 Subject: [PATCH 50/54] Update after review, add notes about env vars --- .github/workflows/upstream_integration.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 3e71347..cc369bc 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -1,7 +1,7 @@ # Copyright 2026 Elektrobit. All rights reserved. name: Update Toolkit from Upstream Release Archive -# Integrates an upstream EB corbos toolkit release archive into this repository. +# Integrates an upstream EB corbos Toolkit release archive into this repository. # The workflow downloads and unpacks the delivery archive, loads and smoke-tests # the container images (kas build + QEMU boot of the fastdev image), opens or # updates an integration pull request, retags and pushes the container images to @@ -86,7 +86,7 @@ jobs: .github/scripts - name: Download, unpack, and validate upstream delivery archive - run: "${SCRIPTS_DIR}/download_archive.sh" + run: "${SCRIPTS_DIR}/download_archive.sh" # ATTENTION: this script sets environment variables for later steps - name: Load container image archives into Docker shell: bash @@ -108,7 +108,7 @@ jobs: - name: "Test: Boot fastdev image in QEMU" shell: bash - run: bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" + run: bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" # ATTENTION: this script sets environment variables for later steps - name: Checkout repository for integration uses: actions/checkout@v4 @@ -237,7 +237,7 @@ jobs: - name: Package release assets shell: bash - run: bash "${SCRIPTS_DIR}/package_release_assets.sh" + run: bash "${SCRIPTS_DIR}/package_release_assets.sh" # ATTENTION: this script sets environment variables for later steps - name: Create or update draft release and upload assets working-directory: integration-repo @@ -288,10 +288,10 @@ jobs: fi # Kill any lingering QEMU processes started by the smoke test. - pkill -f qemu-system || true + pkill -f qemu-system # Drop registry credentials written by docker login. - docker logout ghcr.io || true + docker logout ghcr.io # Remove the temporary working directory used for download/extraction. if [[ -n "${TMP_WORK_DIR:-}" && -d "${TMP_WORK_DIR}" ]]; then @@ -299,5 +299,3 @@ jobs: sudo rm -rf -- "${TMP_WORK_DIR}" fi - exit 0 - From 1a2b3e073a67ced3b1ad3514414d21a1e1c0ba36 Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 14:38:54 +0200 Subject: [PATCH 51/54] Refactor scripts to use command-line arguments and improve error handling --- .github/scripts/download_archive.sh | 58 +++++++++++----------- .github/scripts/integrate_workspace.sh | 23 +++++++-- .github/scripts/package_release_assets.sh | 51 +++++++++++++------ .github/scripts/qemu_smoke_test.sh | 55 +++++++++++++------- .github/workflows/upstream_integration.yml | 34 +++++++++++-- 5 files changed, 147 insertions(+), 74 deletions(-) diff --git a/.github/scripts/download_archive.sh b/.github/scripts/download_archive.sh index e3b9b51..a73e751 100755 --- a/.github/scripts/download_archive.sh +++ b/.github/scripts/download_archive.sh @@ -1,40 +1,41 @@ #!/usr/bin/env bash # Copyright 2026 Elektrobit. All rights reserved. # -# Download the upstream toolkit archive referenced by the workflow_dispatch -# inputs, extract it into a temporary directory and export the resulting paths -# to GITHUB_ENV for subsequent steps. +# Download the upstream toolkit archive, extract it into a temporary directory +# and print the resulting paths as KEY=VALUE lines on stdout. # -# Required environment: -# GITHUB_EVENT_PATH Path to the event payload holding the dispatch inputs. -# GITHUB_ENV Path to the environment file for downstream steps. +# Usage: download_archive.sh --url --token set -euo pipefail -ARTIFACT_URL="$(jq -r '.inputs.artifact_url // empty' "${GITHUB_EVENT_PATH}")" -ARTIFACTORY_TOKEN="$(jq -r '.inputs.artifactory_token // empty' "${GITHUB_EVENT_PATH}")" +url="" +token="" -if [[ -z "${ARTIFACTORY_TOKEN}" ]]; then - echo "::error::Required workflow input artifactory_token is not set." +while [[ $# -gt 0 ]]; do + case "$1" in + --url) url="$2"; shift 2 ;; + --token) token="$2"; shift 2 ;; + *) echo "Unknown argument: $1" >&2; exit 1 ;; + esac +done + +if [[ -z "${url}" ]]; then + echo "ERROR: Required argument --url is not set." >&2 exit 1 fi -if [[ -z "${ARTIFACT_URL}" ]]; then - echo "::error::Required workflow input artifact_url is not set." +if [[ -z "${token}" ]]; then + echo "ERROR: Required argument --token is not set." >&2 exit 1 fi -# Treat the manual input URL and token as sensitive operational data. -echo "::add-mask::${ARTIFACT_URL}" -echo "::add-mask::${ARTIFACTORY_TOKEN}" - tmp_dir="$(mktemp -d)" archive_path="${tmp_dir}/eb_corbos_toolkit.tar.gz" extract_root="${tmp_dir}/extracted" mkdir -p "${extract_root}" -echo "Starting upstream delivery archive download (this may take a while for large files)..." -echo "Download target: ${archive_path}" +echo "Starting upstream delivery archive download (this may take a while for large files)..." >&2 +echo "Download target: ${archive_path}" >&2 curl \ --fail \ @@ -44,19 +45,19 @@ curl \ --retry 3 \ --retry-delay 5 \ --retry-all-errors \ - --header "Authorization: Bearer ${ARTIFACTORY_TOKEN}" \ + --header "Authorization: Bearer ${token}" \ --output "${archive_path}" \ - --url "${ARTIFACT_URL}" + --url "${url}" archive_size_bytes="$(wc -c < "${archive_path}")" archive_size_mib="$(awk "BEGIN { printf \"%.2f\", ${archive_size_bytes}/1024/1024 }")" -echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." +echo "Download complete: ${archive_size_bytes} bytes (${archive_size_mib} MiB)." >&2 -echo "Starting upstream delivery archive extraction into ${extract_root}..." +echo "Starting upstream delivery archive extraction into ${extract_root}..." >&2 tar -xzf "${archive_path}" -C "${extract_root}" -echo "Extraction complete." +echo "Extraction complete." >&2 toolkit_root="${extract_root}/eb_corbos_toolkit" workspace_root="${toolkit_root}/workspace" @@ -68,23 +69,22 @@ manual_pdf="${toolkit_root}/doc/user_manual.pdf" manual_html_dir="${toolkit_root}/doc/html" prebuilt_dir="${workspace_root}/prebuilt" -echo "Validating extracted layout..." +echo "Validating extracted layout..." >&2 for f in "${devcontainer_archive}" "${buildcontainer_archive}" "${run_script}" "${bitbake_execution_fixer}" "${manual_pdf}"; do if [[ ! -f "${f}" ]]; then - echo "::error::Expected file not found in extracted upstream delivery archive: ${f}" + echo "ERROR: Expected file not found in extracted upstream delivery archive: ${f}" >&2 exit 1 fi done for d in "${manual_html_dir}" "${prebuilt_dir}"; do if [[ ! -d "${d}" ]]; then - echo "::error::Expected directory not found in extracted upstream delivery archive: ${d}" + echo "ERROR: Expected directory not found in extracted upstream delivery archive: ${d}" >&2 exit 1 fi done -echo "Extracted layout looks good." +echo "Extracted layout looks good." >&2 -# Prepare environment variables for subsequent steps. -cat >> "${GITHUB_ENV}" << EOF +cat << EOF TMP_WORK_DIR=${tmp_dir} EXTRACT_ROOT=${extract_root} ARCHIVE_PATH=${archive_path} diff --git a/.github/scripts/integrate_workspace.sh b/.github/scripts/integrate_workspace.sh index 7d8a58c..d76760a 100755 --- a/.github/scripts/integrate_workspace.sh +++ b/.github/scripts/integrate_workspace.sh @@ -5,12 +5,25 @@ # preserving repository-owned metadata files. Must be run from the root of the # integration repository checkout. # -# Required environment: -# WORKSPACE_ROOT Extracted upstream workspace directory to copy in. +# Usage: integrate_workspace.sh --workspace-root set -euo pipefail -if [[ ! -d "${WORKSPACE_ROOT}" ]]; then - echo "::error::WORKSPACE_ROOT '${WORKSPACE_ROOT}' does not exist." +workspace_root="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workspace-root) workspace_root="$2"; shift 2 ;; + *) echo "Unknown argument: $1" >&2; exit 1 ;; + esac +done + +if [[ -z "${workspace_root}" ]]; then + echo "ERROR: Required argument --workspace-root is not set." >&2 + exit 1 +fi + +if [[ ! -d "${workspace_root}" ]]; then + echo "ERROR: Workspace root '${workspace_root}' does not exist." >&2 exit 1 fi @@ -42,4 +55,4 @@ done < <(find . -mindepth 1 -maxdepth 1 -print0) # Copy the upstream workspace on top, preserving flags, mtimes, ownership. # Ignore the "prebuilt" and "build" sub-folders. -rsync -a --exclude='prebuilt' --exclude='build' "${WORKSPACE_ROOT}/." . +rsync -a --exclude='prebuilt' --exclude='build' "${workspace_root}/." . diff --git a/.github/scripts/package_release_assets.sh b/.github/scripts/package_release_assets.sh index 9c04696..16738f0 100755 --- a/.github/scripts/package_release_assets.sh +++ b/.github/scripts/package_release_assets.sh @@ -2,35 +2,54 @@ # Copyright 2026 Elektrobit. All rights reserved. # # Collect the release assets (toolkit archive, user manual, prebuilt per-target -# images, SDK sysroots and SSH keys) into a single directory and export its path -# to GITHUB_ENV. +# images, SDK sysroots and SSH keys) into a single directory and print its path +# as a KEY=VALUE line on stdout. # -# Required environment: -# TMP_WORK_DIR Temporary working directory for staging assets. -# ARCHIVE_PATH Path to the downloaded toolkit archive. -# MANUAL_PDF Path to the user manual PDF. -# MANUAL_HTML_DIR Directory holding the HTML user manual. -# PREBUILT_DIR Directory holding the per-target prebuilt artifacts. -# GITHUB_ENV Path to the environment file for downstream steps. +# Usage: package_release_assets.sh --tmp-work-dir --archive-path \ +# --manual-pdf --manual-html-dir --prebuilt-dir set -euo pipefail -assets_dir="${TMP_WORK_DIR}/release-assets" +tmp_work_dir="" +archive_path="" +manual_pdf="" +manual_html_dir="" +prebuilt_dir="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --tmp-work-dir) tmp_work_dir="$2"; shift 2 ;; + --archive-path) archive_path="$2"; shift 2 ;; + --manual-pdf) manual_pdf="$2"; shift 2 ;; + --manual-html-dir) manual_html_dir="$2"; shift 2 ;; + --prebuilt-dir) prebuilt_dir="$2"; shift 2 ;; + *) echo "Unknown argument: $1" >&2; exit 1 ;; + esac +done + +for arg_name in tmp_work_dir archive_path manual_pdf manual_html_dir prebuilt_dir; do + if [[ -z "${!arg_name}" ]]; then + echo "ERROR: Required argument --${arg_name//_/-} is not set." >&2 + exit 1 + fi +done + +assets_dir="${tmp_work_dir}/release-assets" mkdir -p "${assets_dir}" -mv "${ARCHIVE_PATH}" "${assets_dir}/eb_corbos_toolkit.tar.gz" -cp "${MANUAL_PDF}" "${assets_dir}/user_manual.pdf" -tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${MANUAL_HTML_DIR}" . +mv "${archive_path}" "${assets_dir}/eb_corbos_toolkit.tar.gz" +cp "${manual_pdf}" "${assets_dir}/user_manual.pdf" +tar -czf "${assets_dir}/user_manual_html.tar.gz" -C "${manual_html_dir}" . # Per-target assets: one image archive (named after its .wic file), the SDK # sysroot tarball and the SSH target key for every target directory. -for target_dir in "${PREBUILT_DIR}"/*/; do +for target_dir in "${prebuilt_dir}"/*/; do [[ -d "${target_dir}" ]] || continue image_dir="${target_dir}image" if [[ -d "${image_dir}" ]]; then wic_file="$(find "${image_dir}" -maxdepth 1 -name '*.wic' -print -quit)" if [[ -z "${wic_file}" ]]; then - echo "::error::No .wic file found in ${image_dir}." + echo "ERROR: No .wic file found in ${image_dir}." >&2 exit 1 fi image_base="$(basename "${wic_file}" .wic)" @@ -48,4 +67,4 @@ for target_dir in "${PREBUILT_DIR}"/*/; do fi done -echo "RELEASE_ASSETS_DIR=${assets_dir}" >> "${GITHUB_ENV}" +echo "RELEASE_ASSETS_DIR=${assets_dir}" diff --git a/.github/scripts/qemu_smoke_test.sh b/.github/scripts/qemu_smoke_test.sh index 10a7dca..54997dc 100755 --- a/.github/scripts/qemu_smoke_test.sh +++ b/.github/scripts/qemu_smoke_test.sh @@ -5,58 +5,75 @@ # devcontainer, wait for SSH availability, power it down cleanly and confirm the # shutdown message appears in the QEMU log. # -# Required environment: -# WORKSPACE_ROOT Extracted upstream workspace directory. -# RUN_SCRIPT Path to the workspace run.sh helper. -# GITHUB_ENV Path to the environment file for downstream steps. +# Usage: qemu_smoke_test.sh --workspace-root --run-script set -euo pipefail -cd "${WORKSPACE_ROOT}" +workspace_root="" +run_script="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workspace-root) workspace_root="$2"; shift 2 ;; + --run-script) run_script="$2"; shift 2 ;; + *) echo "Unknown argument: $1" >&2; exit 1 ;; + esac +done + +if [[ -z "${workspace_root}" ]]; then + echo "ERROR: Required argument --workspace-root is not set." >&2 + exit 1 +fi + +if [[ -z "${run_script}" ]]; then + echo "ERROR: Required argument --run-script is not set." >&2 + exit 1 +fi + +cd "${workspace_root}" # Run the dev container in detached mode and keep it running. export EXTRA_DOCKER_OPTIONS="-d --log-driver local" LOG_FILE=$(mktemp -t ebcl_run_devcontainer-XXXXXX.log 2>/dev/null) || LOG_FILE="/tmp/ebcl_run_devcontainer.log" -echo "Starting devcontainer in the background" -DEV_CONTAINER_ID=$("${RUN_SCRIPT}" -d -- bash -c "sleep infinity" 2>&1 | tee "${LOG_FILE}" | grep -oE '^[0-9a-f]{64}$') +echo "Starting devcontainer in the background" >&2 +DEV_CONTAINER_ID=$("${run_script}" -d -- bash -c "sleep infinity" 2>&1 | tee "${LOG_FILE}" | grep -oE '^[0-9a-f]{64}$') if [[ -z "${DEV_CONTAINER_ID}" ]]; then - echo "::error::Failed to start devcontainer. Log output:" - cat "${LOG_FILE}" + echo "ERROR: Failed to start devcontainer. Log output:" >&2 + cat "${LOG_FILE}" >&2 exit 1 fi -# Expose the container ID so the always() cleanup step can tear it down. -echo "DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" >> "${GITHUB_ENV}" +echo "DEV_CONTAINER_ID=${DEV_CONTAINER_ID}" sleep 10 devcontainer_exec() { docker exec "${DEV_CONTAINER_ID}" "$@" } -echo "Running fastdev in qemu in background, logging to qemu.log" +echo "Running fastdev in qemu in background, logging to qemu.log" >&2 devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" devcontainer_exec bash -c \ "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" -echo "Terminating fastdev" +echo "Terminating fastdev" >&2 devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true -echo "Waiting for fastdev to power down" +echo "Waiting for fastdev to power down" >&2 max_tries=20 msg="Power down" -log="${WORKSPACE_ROOT}/qemu.log" +log="${workspace_root}/qemu.log" for i in $(seq 1 "${max_tries}"); do if grep -q "${msg}" "${log}" 2>/dev/null; then - echo "Waiting for \"${msg}\" message in ${log} succeeded" + echo "Waiting for \"${msg}\" message in ${log} succeeded" >&2 rm -f "${log}" exit 0 fi - echo "Waiting for \"${msg}\" message in ${log} ... (${i}/${max_tries})" + echo "Waiting for \"${msg}\" message in ${log} ... (${i}/${max_tries})" >&2 sleep 1 done -echo "Error: Waiting for \"${msg}\" message in ${log} timed out!" -cat "${log}" +echo "ERROR: Waiting for \"${msg}\" message in ${log} timed out!" >&2 +cat "${log}" >&2 exit 1 diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index cc369bc..dd76f7b 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -86,7 +86,15 @@ jobs: .github/scripts - name: Download, unpack, and validate upstream delivery archive - run: "${SCRIPTS_DIR}/download_archive.sh" # ATTENTION: this script sets environment variables for later steps + shell: bash + run: | + set -euo pipefail + echo "::add-mask::${{ inputs.artifact_url }}" + echo "::add-mask::${{ inputs.artifactory_token }}" + "${SCRIPTS_DIR}/download_archive.sh" \ + --url "${{ inputs.artifact_url }}" \ + --token "${{ inputs.artifactory_token }}" \ + >> "${GITHUB_ENV}" - name: Load container image archives into Docker shell: bash @@ -108,7 +116,12 @@ jobs: - name: "Test: Boot fastdev image in QEMU" shell: bash - run: bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" # ATTENTION: this script sets environment variables for later steps + run: | + set -euo pipefail + bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" \ + --workspace-root "${WORKSPACE_ROOT}" \ + --run-script "${RUN_SCRIPT}" \ + >> "${GITHUB_ENV}" - name: Checkout repository for integration uses: actions/checkout@v4 @@ -140,7 +153,11 @@ jobs: - name: Integrate upstream workspace working-directory: integration-repo - run: "${SCRIPTS_DIR}/integrate_workspace.sh" + shell: bash + run: | + set -euo pipefail + "${SCRIPTS_DIR}/integrate_workspace.sh" \ + --workspace-root "${WORKSPACE_ROOT}" - name: Commit integrated upstream workspace and push to integration branch working-directory: integration-repo @@ -237,7 +254,15 @@ jobs: - name: Package release assets shell: bash - run: bash "${SCRIPTS_DIR}/package_release_assets.sh" # ATTENTION: this script sets environment variables for later steps + run: | + set -euo pipefail + bash "${SCRIPTS_DIR}/package_release_assets.sh" \ + --tmp-work-dir "${TMP_WORK_DIR}" \ + --archive-path "${ARCHIVE_PATH}" \ + --manual-pdf "${MANUAL_PDF}" \ + --manual-html-dir "${MANUAL_HTML_DIR}" \ + --prebuilt-dir "${PREBUILT_DIR}" \ + >> "${GITHUB_ENV}" - name: Create or update draft release and upload assets working-directory: integration-repo @@ -298,4 +323,3 @@ jobs: echo "Removing temporary work directory ${TMP_WORK_DIR}" sudo rm -rf -- "${TMP_WORK_DIR}" fi - From 51945311e56f82295bfe725088ed43d35fb66a6f Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 15:50:00 +0200 Subject: [PATCH 52/54] Enhance QEMU smoke test logging and update integration workflow to capture DEV_CONTAINER_ID --- .github/scripts/qemu_smoke_test.sh | 6 +++--- .github/workflows/upstream_integration.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/scripts/qemu_smoke_test.sh b/.github/scripts/qemu_smoke_test.sh index 54997dc..571509c 100755 --- a/.github/scripts/qemu_smoke_test.sh +++ b/.github/scripts/qemu_smoke_test.sh @@ -52,12 +52,12 @@ devcontainer_exec() { } echo "Running fastdev in qemu in background, logging to qemu.log" >&2 -devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" +devcontainer_exec bash -c "./scripts/qemu.sh -t fastdev < /dev/null > qemu.log 2>&1 &" >&2 devcontainer_exec bash -c \ - "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" + "log=/workspace/qemu.log; source /workspace/scripts/includes/common/common.inc; wait_for_ssh fastdev-qemuarm64 70 1" >&2 echo "Terminating fastdev" >&2 -devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff || true +devcontainer_exec ssh fastdev-qemuarm64 crinit-ctl poweroff >&2 || true echo "Waiting for fastdev to power down" >&2 max_tries=20 diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index dd76f7b..b0da96b 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -121,7 +121,7 @@ jobs: bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" \ --workspace-root "${WORKSPACE_ROOT}" \ --run-script "${RUN_SCRIPT}" \ - >> "${GITHUB_ENV}" + | grep -E '^DEV_CONTAINER_ID=[0-9a-f]{64}$' >> "${GITHUB_ENV}" - name: Checkout repository for integration uses: actions/checkout@v4 From bef5534108f342bc19fee7ccd119df306b00871b Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 16:19:15 +0200 Subject: [PATCH 53/54] Refactor workflows to use default shell settings for improved error handling --- .github/workflows/release.yml | 11 ++---- .github/workflows/upstream_integration.yml | 41 +++------------------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2373944..24a2511 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,12 +43,13 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} + defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} steps: - name: Verify runner prerequisites - shell: bash run: | - set -euo pipefail command -v gh >/dev/null command -v jq >/dev/null command -v tar >/dev/null @@ -56,10 +57,7 @@ jobs: - name: Verify published release contains the User's Manual asset env: GH_TOKEN: ${{ github.token }} - shell: bash run: | - set -euo pipefail - tag="${RELEASE_TAG}" echo "Checking release for tag '${tag}'." @@ -82,10 +80,7 @@ jobs: - name: Download and extract the User's Manual asset env: GH_TOKEN: ${{ github.token }} - shell: bash run: | - set -euo pipefail - tag="${RELEASE_TAG}" tmp_dir="$(mktemp -d)" diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index b0da96b..45ebb5e 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -47,15 +47,15 @@ jobs: timeout-minutes: 120 env: SCRIPTS_DIR: ${{ github.workspace }}/.github/scripts + defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} steps: - name: Authorize triggering actor env: ALLOWED_ACTORS: ${{ vars.WORKFLOW_ALLOWED_ACTORS }} - shell: bash run: | - set -euo pipefail - if [[ -z "${ALLOWED_ACTORS:-}" ]]; then echo "::error::Repository variable WORKFLOW_ALLOWED_ACTORS is not set." echo "::error::Set it to a comma-separated list of GitHub usernames allowed to run this workflow." @@ -71,9 +71,7 @@ jobs: echo "Actor authorization succeeded." - name: Verify runner prerequisites - shell: bash run: | - set -euo pipefail command -v curl >/dev/null command -v tar >/dev/null command -v docker >/dev/null @@ -86,9 +84,7 @@ jobs: .github/scripts - name: Download, unpack, and validate upstream delivery archive - shell: bash run: | - set -euo pipefail echo "::add-mask::${{ inputs.artifact_url }}" echo "::add-mask::${{ inputs.artifactory_token }}" "${SCRIPTS_DIR}/download_archive.sh" \ @@ -97,27 +93,21 @@ jobs: >> "${GITHUB_ENV}" - name: Load container image archives into Docker - shell: bash run: | docker load -i "${DEVCONTAINER_ARCHIVE}" docker load -i "${BUILDCONTAINER_ARCHIVE}" - name: "Fix BitBake execution issue on Ubuntu 23.10+" - shell: bash run: | "${BITBAKE_EXECUTION_FIXER}" --yes - name: "Test: Run kas build using extracted run.sh" - shell: bash run: | - set -euo pipefail cd "${WORKSPACE_ROOT}" "${RUN_SCRIPT}" -d -- kas build --target fastdev kas/public.yml - name: "Test: Boot fastdev image in QEMU" - shell: bash run: | - set -euo pipefail bash "${SCRIPTS_DIR}/qemu_smoke_test.sh" \ --workspace-root "${WORKSPACE_ROOT}" \ --run-script "${RUN_SCRIPT}" \ @@ -132,10 +122,7 @@ jobs: - name: Create or checkout integration branch working-directory: integration-repo - shell: bash run: | - set -euo pipefail - git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" @@ -153,9 +140,7 @@ jobs: - name: Integrate upstream workspace working-directory: integration-repo - shell: bash run: | - set -euo pipefail "${SCRIPTS_DIR}/integrate_workspace.sh" \ --workspace-root "${WORKSPACE_ROOT}" @@ -163,10 +148,7 @@ jobs: working-directory: integration-repo env: RELEASE_VERSION: ${{ inputs.release_version }} - shell: bash run: | - set -euo pipefail - git add -A if git diff --cached --quiet; then echo "No changes to commit; working copy already matches upstream." @@ -182,10 +164,7 @@ jobs: env: GH_TOKEN: ${{ github.token }} RELEASE_VERSION: ${{ inputs.release_version }} - shell: bash run: | - set -euo pipefail - existing_pr="$(gh pr list --head "${INTEGRATION_BRANCH}" --base main --state open --json number --jq '.[0].number // empty')" tag_prefix="v" @@ -206,10 +185,7 @@ jobs: - name: Rewrite devcontainer image tag to pull request number id: rewrite-tag working-directory: integration-repo - shell: bash run: | - set -euo pipefail - devcontainer_json=".devcontainer/devcontainer.json" run_sh="./scripts/run.sh" rfi_tag="$(sed -n 's/.*"image":.*:\([^"]*\)".*/\1/p' "${devcontainer_json}" | head -1)" @@ -233,15 +209,12 @@ jobs: else # Amend the previous commit to include the tag rewrite, so that the previous container tag is not left in the integration branch history. git commit --amend --no-edit - git push --force origin "HEAD:${INTEGRATION_BRANCH}" + git push --force-with-lease origin "HEAD:${INTEGRATION_BRANCH}" fi - name: Update container tags and push to registry working-directory: integration-repo - shell: bash run: | - set -euo pipefail - echo "${{ github.token }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin new_tag="${{ steps.integration-pr.outputs.pr_tag }}" @@ -253,9 +226,7 @@ jobs: docker push "${BUILDCONTAINER_IMAGE}:${new_tag}" - name: Package release assets - shell: bash run: | - set -euo pipefail bash "${SCRIPTS_DIR}/package_release_assets.sh" \ --tmp-work-dir "${TMP_WORK_DIR}" \ --archive-path "${ARCHIVE_PATH}" \ @@ -269,10 +240,7 @@ jobs: env: GH_TOKEN: ${{ github.token }} RELEASE_VERSION: ${{ inputs.release_version }} - shell: bash run: | - set -euo pipefail - shopt -s nullglob assets=( "${RELEASE_ASSETS_DIR}"/* ) shopt -u nullglob @@ -302,7 +270,6 @@ jobs: - name: Clean up runner resources if: always() - shell: bash run: | set +e From 3eeb9b2c7dcaf2a6353a82eb76107be903a8dbfa Mon Sep 17 00:00:00 2001 From: Oliver Pajonk Date: Fri, 14 Aug 2026 16:20:14 +0200 Subject: [PATCH 54/54] push only in case of changes --- .github/workflows/upstream_integration.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/upstream_integration.yml b/.github/workflows/upstream_integration.yml index 45ebb5e..f2a1eb7 100644 --- a/.github/workflows/upstream_integration.yml +++ b/.github/workflows/upstream_integration.yml @@ -154,10 +154,9 @@ jobs: echo "No changes to commit; working copy already matches upstream." else git commit -m "Integrate upstream version ${RELEASE_VERSION}" + git push origin "HEAD:${INTEGRATION_BRANCH}" fi - git push origin "HEAD:${INTEGRATION_BRANCH}" - - name: Create or update integration pull request id: integration-pr working-directory: integration-repo