From f05385a99e1e5fe149cdf41512e66a1f6de7fdfd Mon Sep 17 00:00:00 2001 From: Milos Jovanovic Date: Mon, 18 May 2026 23:26:08 +0200 Subject: [PATCH 1/4] feat: add runner verify script for app image build Signed-off-by: Milos Jovanovic --- release/superplane-image/build.sh | 12 ++- scripts/ci/runner-verify-app-image-build.sh | 94 +++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) create mode 100755 scripts/ci/runner-verify-app-image-build.sh diff --git a/release/superplane-image/build.sh b/release/superplane-image/build.sh index 8af0474de0..ac7060bb0b 100644 --- a/release/superplane-image/build.sh +++ b/release/superplane-image/build.sh @@ -27,12 +27,20 @@ fi echo "Building SuperPlane image (${IMAGE_REPO})" +push_flag=(--push) +output_ref="${IMAGE_REPO}:${VERSION}-${ARCH}" +if [[ "${PUSH:-1}" == "0" ]]; then + push_flag=(--load) + output_ref="${LOCAL_TAG:-superplane:runner-verify}" + echo "PUSH=0: build only, loading locally as ${output_ref}" +fi + docker buildx build \ --platform "linux/${ARCH}" \ --progress=plain \ --provenance=false \ - --push \ + "${push_flag[@]}" \ --cache-from ghcr.io/superplanehq/superplane-dev-base:app-latest \ - -t "${IMAGE_REPO}:${VERSION}-${ARCH}" \ + -t "${output_ref}" \ -f Dockerfile \ . diff --git a/scripts/ci/runner-verify-app-image-build.sh b/scripts/ci/runner-verify-app-image-build.sh new file mode 100755 index 0000000000..3320fea884 --- /dev/null +++ b/scripts/ci/runner-verify-app-image-build.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash +# Verify SuperPlane app image builds on a runner host (EC2) or locally. +# Full docker buildx (linux/amd64), no registry push — for #4693 / future daily builds. +# +# Env: +# REPO_URL default https://github.com/superplanehq/superplane.git +# GIT_REF branch or SHA to build (default: current HEAD when in-repo) +# ARCH default amd64 +# DEV_BASE_IMAGE default ghcr.io/superplanehq/superplane-dev-base:app-latest +# VERIFY_WORK_DIR use this checkout instead of cloning (local dev) +# SKIP_PROTO_GEN set to 1 to skip (not recommended; generated protos are not in git) +set -euo pipefail +IFS=$'\n\t' + +ARCH="${ARCH:-amd64}" +REPO_URL="${REPO_URL:-https://github.com/superplanehq/superplane.git}" +DEV_BASE_IMAGE="${DEV_BASE_IMAGE:-ghcr.io/superplanehq/superplane-dev-base:app-latest}" +LOCAL_TAG="${LOCAL_TAG:-superplane:runner-verify}" +MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,components,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents,usage" +REST_API_MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents" + +cleanup() { + if [[ -n "${TMP_WORK:-}" && -d "$TMP_WORK" ]]; then + rm -rf "$TMP_WORK" + fi +} +trap cleanup EXIT + +need_proto_gen() { + [[ "${SKIP_PROTO_GEN:-0}" == "1" ]] && return 1 + return 0 +} + +run_proto_gen() { + echo "==> Generating protobuf (dev-base container, no dev.up)" + docker pull "$DEV_BASE_IMAGE" + docker run --rm \ + -v "$(pwd):/app" \ + -w /app \ + -u "$(id -u):$(id -g)" \ + "$DEV_BASE_IMAGE" \ + bash -lc "/app/scripts/protoc.sh ${MODULES} && /app/scripts/protoc_gateway.sh ${REST_API_MODULES}" +} + +run_image_build() { + echo "==> docker buildx build (linux/${ARCH}, no push)" + docker buildx build \ + --platform "linux/${ARCH}" \ + --progress=plain \ + --provenance=false \ + --cache-from "$DEV_BASE_IMAGE" \ + -t "$LOCAL_TAG" \ + --load \ + -f Dockerfile \ + . + echo "==> OK: image loaded locally as ${LOCAL_TAG} (not pushed)" +} + +prepare_workdir() { + if [[ -n "${VERIFY_WORK_DIR:-}" ]]; then + cd "$VERIFY_WORK_DIR" + return + fi + + if [[ -f Dockerfile && -f go.mod ]]; then + echo "==> Using current directory as repo root" + if [[ -n "${GIT_REF:-}" ]]; then + git fetch origin --depth 1 "${GIT_REF}" 2>/dev/null || git fetch origin "${GIT_REF}" + git checkout "${GIT_REF}" + fi + return + fi + + TMP_WORK="$(mktemp -d)" + echo "==> Cloning ${REPO_URL} into ${TMP_WORK}" + git clone --depth 1 "$REPO_URL" "$TMP_WORK/repo" + cd "$TMP_WORK/repo" + if [[ -n "${GIT_REF:-}" ]]; then + git fetch origin --depth 1 "${GIT_REF}" + git checkout "${GIT_REF}" + fi +} + +main() { + prepare_workdir + if need_proto_gen; then + run_proto_gen + else + echo "==> Skipping proto gen (SKIP_PROTO_GEN=1)" + fi + run_image_build +} + +main "$@" From a64cb25f55bf506226fafd6395697219dd3f1d1e Mon Sep 17 00:00:00 2001 From: Milos Jovanovic Date: Tue, 19 May 2026 14:51:23 +0200 Subject: [PATCH 2/4] fix: generate OpenAPI clients in runner image verify script Signed-off-by: Milos Jovanovic --- scripts/ci/runner-verify-app-image-build.sh | 68 ++++++++++++++++++--- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/scripts/ci/runner-verify-app-image-build.sh b/scripts/ci/runner-verify-app-image-build.sh index 3320fea884..46073145c4 100755 --- a/scripts/ci/runner-verify-app-image-build.sh +++ b/scripts/ci/runner-verify-app-image-build.sh @@ -16,6 +16,7 @@ ARCH="${ARCH:-amd64}" REPO_URL="${REPO_URL:-https://github.com/superplanehq/superplane.git}" DEV_BASE_IMAGE="${DEV_BASE_IMAGE:-ghcr.io/superplanehq/superplane-dev-base:app-latest}" LOCAL_TAG="${LOCAL_TAG:-superplane:runner-verify}" + MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,components,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents,usage" REST_API_MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents" @@ -26,7 +27,7 @@ cleanup() { } trap cleanup EXIT -need_proto_gen() { +need_codegen() { [[ "${SKIP_PROTO_GEN:-0}" == "1" ]] && return 1 return 0 } @@ -42,6 +43,52 @@ run_proto_gen() { bash -lc "/app/scripts/protoc.sh ${MODULES} && /app/scripts/protoc_gateway.sh ${REST_API_MODULES}" } +OPENAPI_GENERATOR_IMAGE="openapitools/openapi-generator-cli:v7.13.0" + +run_openapi_spec_gen() { + echo "==> Generating OpenAPI spec (dev-base container)" + docker run --rm \ + -v "$(pwd):/app" \ + -w /app \ + -u "$(id -u):$(id -g)" \ + "$DEV_BASE_IMAGE" \ + bash -lc "/app/scripts/protoc_openapi_spec.sh ${REST_API_MODULES}" +} + +run_openapi_go_client_gen() { + echo "==> Generating OpenAPI Go client (openapi-generator-cli)" + rm -rf pkg/openapi_client + docker run --rm \ + -v "$(pwd):/local" \ + -u "$(id -u):$(id -g)" \ + "$OPENAPI_GENERATOR_IMAGE" generate \ + -i /local/api/swagger/superplane.swagger.json \ + -g go \ + -o /local/pkg/openapi_client \ + --additional-properties=packageName=openapi_client,enumClassPrefix=true,isGoSubmodule=true,withGoMod=false + rm -rf pkg/openapi_client/test pkg/openapi_client/docs pkg/openapi_client/api \ + pkg/openapi_client/.travis.yml pkg/openapi_client/README.md pkg/openapi_client/git_push.sh + docker run --rm \ + -v "$(pwd):/app" \ + -w /app \ + -u "$(id -u):$(id -g)" \ + "$DEV_BASE_IMAGE" \ + bash -lc "find pkg/openapi_client -name '*.go' -print0 | xargs -0 gofmt -s -w" +} + +run_openapi_web_client_gen() { + echo "==> Generating OpenAPI web (TypeScript) client (dev-base container)" + rm -rf web_src/src/api-client + docker run --rm \ + -v "$(pwd):/app" \ + -w /app/web_src \ + -u "$(id -u):$(id -g)" \ + -e HOME=/tmp \ + -e NPM_CONFIG_CACHE=/tmp/.npm \ + "$DEV_BASE_IMAGE" \ + bash -lc "npm install --prefer-offline && npm run generate:api && npx prettier --log-level silent --write 'src/api-client/**/*.{ts,tsx}'" +} + run_image_build() { echo "==> docker buildx build (linux/${ARCH}, no push)" docker buildx build \ @@ -61,7 +108,6 @@ prepare_workdir() { cd "$VERIFY_WORK_DIR" return fi - if [[ -f Dockerfile && -f go.mod ]]; then echo "==> Using current directory as repo root" if [[ -n "${GIT_REF:-}" ]]; then @@ -70,23 +116,25 @@ prepare_workdir() { fi return fi - TMP_WORK="$(mktemp -d)" - echo "==> Cloning ${REPO_URL} into ${TMP_WORK}" - git clone --depth 1 "$REPO_URL" "$TMP_WORK/repo" - cd "$TMP_WORK/repo" + local clone_args=(--depth 1) if [[ -n "${GIT_REF:-}" ]]; then - git fetch origin --depth 1 "${GIT_REF}" - git checkout "${GIT_REF}" + clone_args+=(-b "${GIT_REF}") fi + echo "==> Cloning ${REPO_URL} (ref: ${GIT_REF:-default}) into ${TMP_WORK}" + git clone "${clone_args[@]}" "$REPO_URL" "$TMP_WORK/repo" + cd "$TMP_WORK/repo" } main() { prepare_workdir - if need_proto_gen; then + if need_codegen; then run_proto_gen + run_openapi_spec_gen + run_openapi_go_client_gen + run_openapi_web_client_gen else - echo "==> Skipping proto gen (SKIP_PROTO_GEN=1)" + echo "==> Skipping codegen (SKIP_PROTO_GEN=1)" fi run_image_build } From 87b19287bf2bcf6a184ab5037bd53213b8f0a4e3 Mon Sep 17 00:00:00 2001 From: Milos Jovanovic Date: Tue, 19 May 2026 21:18:22 +0200 Subject: [PATCH 3/4] fix: resolve bugbot comments Signed-off-by: Milos Jovanovic --- scripts/ci/runner-verify-app-image-build.sh | 44 +++++++++++++++------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/scripts/ci/runner-verify-app-image-build.sh b/scripts/ci/runner-verify-app-image-build.sh index 46073145c4..e8b33e1473 100755 --- a/scripts/ci/runner-verify-app-image-build.sh +++ b/scripts/ci/runner-verify-app-image-build.sh @@ -17,9 +17,6 @@ REPO_URL="${REPO_URL:-https://github.com/superplanehq/superplane.git}" DEV_BASE_IMAGE="${DEV_BASE_IMAGE:-ghcr.io/superplanehq/superplane-dev-base:app-latest}" LOCAL_TAG="${LOCAL_TAG:-superplane:runner-verify}" -MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,components,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents,usage" -REST_API_MODULES="authorization,organizations,integrations,secrets,users,groups,roles,me,configuration,actions,triggers,widgets,blueprints,canvases,canvas_folders,service_accounts,agents" - cleanup() { if [[ -n "${TMP_WORK:-}" && -d "$TMP_WORK" ]]; then rm -rf "$TMP_WORK" @@ -32,6 +29,26 @@ need_codegen() { return 0 } +make_var() { + local name="$1" + awk -v name="$name" ' + $1 == name && $2 == ":=" { + sub("^[^:]+:= ?", "") + print + exit + } + ' Makefile +} + +load_codegen_modules() { + MODULES="$(make_var MODULES)" + REST_API_MODULES="$(make_var REST_API_MODULES)" + if [[ -z "$MODULES" || -z "$REST_API_MODULES" ]]; then + echo "Could not read MODULES and REST_API_MODULES from Makefile" >&2 + exit 1 + fi +} + run_proto_gen() { echo "==> Generating protobuf (dev-base container, no dev.up)" docker pull "$DEV_BASE_IMAGE" @@ -103,6 +120,14 @@ run_image_build() { echo "==> OK: image loaded locally as ${LOCAL_TAG} (not pushed)" } +checkout_ref() { + if [[ -z "${GIT_REF:-}" ]]; then + return + fi + git fetch origin --depth 1 "${GIT_REF}" 2>/dev/null || git fetch origin "${GIT_REF}" + git checkout "${GIT_REF}" +} + prepare_workdir() { if [[ -n "${VERIFY_WORK_DIR:-}" ]]; then cd "$VERIFY_WORK_DIR" @@ -110,24 +135,19 @@ prepare_workdir() { fi if [[ -f Dockerfile && -f go.mod ]]; then echo "==> Using current directory as repo root" - if [[ -n "${GIT_REF:-}" ]]; then - git fetch origin --depth 1 "${GIT_REF}" 2>/dev/null || git fetch origin "${GIT_REF}" - git checkout "${GIT_REF}" - fi + checkout_ref return fi TMP_WORK="$(mktemp -d)" - local clone_args=(--depth 1) - if [[ -n "${GIT_REF:-}" ]]; then - clone_args+=(-b "${GIT_REF}") - fi echo "==> Cloning ${REPO_URL} (ref: ${GIT_REF:-default}) into ${TMP_WORK}" - git clone "${clone_args[@]}" "$REPO_URL" "$TMP_WORK/repo" + git clone --depth 1 "$REPO_URL" "$TMP_WORK/repo" cd "$TMP_WORK/repo" + checkout_ref } main() { prepare_workdir + load_codegen_modules if need_codegen; then run_proto_gen run_openapi_spec_gen From 85cf15f7b2d519f83038165f4d474dd44722787d Mon Sep 17 00:00:00 2001 From: Milos Jovanovic Date: Sat, 30 May 2026 14:21:28 +0200 Subject: [PATCH 4/4] fix: resolve bugbot comments Signed-off-by: Milos Jovanovic --- release/superplane-image/build.sh | 2 +- scripts/ci/runner-verify-app-image-build.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/release/superplane-image/build.sh b/release/superplane-image/build.sh index 8e9237f01d..232d0988cf 100644 --- a/release/superplane-image/build.sh +++ b/release/superplane-image/build.sh @@ -39,7 +39,7 @@ docker buildx build \ --platform "linux/${ARCH}" \ --progress=plain \ --provenance=false \ - --push \ + "${push_flag[@]}" \ --target runner \ --cache-from ghcr.io/superplanehq/superplane-dev-base:app-latest \ -t "${output_ref}" \ diff --git a/scripts/ci/runner-verify-app-image-build.sh b/scripts/ci/runner-verify-app-image-build.sh index e8b33e1473..b961c7418e 100755 --- a/scripts/ci/runner-verify-app-image-build.sh +++ b/scripts/ci/runner-verify-app-image-build.sh @@ -112,6 +112,7 @@ run_image_build() { --platform "linux/${ARCH}" \ --progress=plain \ --provenance=false \ + --target runner \ --cache-from "$DEV_BASE_IMAGE" \ -t "$LOCAL_TAG" \ --load \