diff --git a/.claude/skills/update-anycable/SKILL.md b/.claude/skills/update-anycable/SKILL.md index 2ec97e64ef..fbf8717ffc 100644 --- a/.claude/skills/update-anycable/SKILL.md +++ b/.claude/skills/update-anycable/SKILL.md @@ -1,13 +1,13 @@ --- name: update-anycable -description: Rebuild the bundled anycable-go binaries (openc3-ruby/anycable-go-linux-amd64 and -arm64). Syncs a local anycable checkout with upstream, bumps the Go toolchain and module dependencies when a newer Go patch release is out, builds with openc3-ruby/build-anycable.sh, and opens a COSMOS PR with the new binaries. Optionally opens a dependency-bump PR against anycable/anycable from the user's fork. Use when asked to update or rebuild anycable or to pick up Go security releases. +description: Rebuild the bundled anycable-go binaries (openc3-anycable/anycable-go-linux-amd64 and -arm64). Syncs a local anycable checkout with upstream, bumps the Go toolchain and module dependencies when a newer Go patch release is out, builds with openc3-anycable/build-anycable.sh, and opens a COSMOS PR with the new binaries. Optionally opens a dependency-bump PR against anycable/anycable from the user's fork. Use when asked to update or rebuild anycable or to pick up Go security releases. argument-hint: "[go-minor, e.g. 1.26] [--force-build]" --- # Update the anycable-go binaries -COSMOS ships prebuilt `anycable-go` binaries in `openc3-ruby/` (installed by -`openc3-ruby/anycable_install.sh` in the Dockerfiles). We build them ourselves +COSMOS ships prebuilt `anycable-go` binaries in `openc3-anycable/` (copied into +the API images by their Dockerfiles). We build them ourselves so they pick up Go security releases faster than upstream anycable does. ## Inputs @@ -144,10 +144,10 @@ git -C "$ANYCABLE_DIR" commit -m "Bump dependencies including toolchain go$NEW" From the cosmos repo root: ```bash -openc3-ruby/build-anycable.sh "$ANYCABLE_DIR" +openc3-anycable/build-anycable.sh "$ANYCABLE_DIR" ``` -This builds linux/amd64 and linux/arm64 straight into `openc3-ruby/` and prints +This builds linux/amd64 and linux/arm64 straight into `openc3-anycable/` and prints `go version` for both, which must show `go$NEW`. Report the new sizes. ### 9. Open the upstream PR (only if `UPSTREAM_PR` = yes) @@ -181,11 +181,11 @@ Work in the cosmos repo root: git status --short # note any unrelated changes; commit only the two binaries git fetch origin git switch -c anycable-go$NEW origin/main -git add openc3-ruby/anycable-go-linux-amd64 openc3-ruby/anycable-go-linux-arm64 -git commit -m "build(openc3-ruby): update anycable-go binaries to go$NEW" # plus attribution footer +git add openc3-anycable/anycable-go-linux-amd64 openc3-anycable/anycable-go-linux-arm64 +git commit -m "build(openc3-anycable): update anycable-go binaries to go$NEW" # plus attribution footer git push -u origin anycable-go$NEW gh pr create --base main --head anycable-go$NEW \ - --title "build(openc3-ruby): update anycable-go binaries to go$NEW" \ + --title "build(openc3-anycable): update anycable-go binaries to go$NEW" \ --body "Rebuilds the anycable-go linux/amd64 and linux/arm64 binaries with toolchain go$NEW and bumped Go dependencies, picking up the security fixes in https://go.dev/doc/devel/release#go1.26.minor. Upstream dependency PR: " # plus attribution footer diff --git a/.github/actions/build-cosmos/action.yml b/.github/actions/build-cosmos/action.yml index 19396e8017..3811323fcc 100644 --- a/.github/actions/build-cosmos/action.yml +++ b/.github/actions/build-cosmos/action.yml @@ -197,8 +197,8 @@ runs: openc3-traefik|openc3-traefik| openc3-base|openc3|openc3-ruby openc3-node|openc3-node|openc3-base - openc3-cosmos-cmd-tlm-api|openc3-cosmos-cmd-tlm-api|openc3-base - openc3-cosmos-script-runner-api|openc3-cosmos-script-runner-api|openc3-base + openc3-cosmos-cmd-tlm-api|openc3-cosmos-cmd-tlm-api openc3-anycable|openc3-base + openc3-cosmos-script-runner-api|openc3-cosmos-script-runner-api openc3-anycable|openc3-base openc3-operator|openc3-operator|openc3-base openc3-cosmos-init|openc3-cosmos-init docs.openc3.com|openc3-node openc3-base EOF diff --git a/compose-build.yaml b/compose-build.yaml index ae82f79b36..a401aafc4d 100644 --- a/compose-build.yaml +++ b/compose-build.yaml @@ -85,6 +85,8 @@ services: openc3-cosmos-cmd-tlm-api: build: context: "openc3-cosmos-cmd-tlm-api" + additional_contexts: + anycable: "openc3-anycable" args: OPENC3_REGISTRY: ${OPENC3_REGISTRY} OPENC3_NAMESPACE: ${OPENC3_NAMESPACE} @@ -97,6 +99,8 @@ services: openc3-cosmos-script-runner-api: build: context: "openc3-cosmos-script-runner-api" + additional_contexts: + anycable: "openc3-anycable" args: OPENC3_REGISTRY: ${OPENC3_REGISTRY} OPENC3_NAMESPACE: ${OPENC3_NAMESPACE} diff --git a/openc3-ruby/anycable-go-linux-amd64 b/openc3-anycable/anycable-go-linux-amd64 similarity index 100% rename from openc3-ruby/anycable-go-linux-amd64 rename to openc3-anycable/anycable-go-linux-amd64 diff --git a/openc3-ruby/anycable-go-linux-arm64 b/openc3-anycable/anycable-go-linux-arm64 similarity index 100% rename from openc3-ruby/anycable-go-linux-arm64 rename to openc3-anycable/anycable-go-linux-arm64 diff --git a/openc3-ruby/build-anycable.sh b/openc3-anycable/build-anycable.sh similarity index 95% rename from openc3-ruby/build-anycable.sh rename to openc3-anycable/build-anycable.sh index 3a827b6dbf..dc915e6c12 100755 --- a/openc3-ruby/build-anycable.sh +++ b/openc3-anycable/build-anycable.sh @@ -10,12 +10,12 @@ # This file may also be used under the terms of a commercial license # if purchased from OpenC3, Inc. -# Build the anycable-go binaries bundled in openc3-ruby/ from an anycable +# Build the anycable-go binaries bundled in openc3-anycable/ from an anycable # checkout. Mirrors anycable's .github/workflows/release-binaries.yml # (plain, non-mruby builds) and copies the results next to this script. # # Usage: -# openc3-ruby/build-anycable.sh [ANYCABLE_DIR] +# openc3-anycable/build-anycable.sh [ANYCABLE_DIR] # # ANYCABLE_DIR defaults to $ANYCABLE_DIR, then ../anycable relative to the # cosmos repo root. It must be a git clone of github.com/anycable/anycable diff --git a/openc3-cosmos-cmd-tlm-api/Dockerfile b/openc3-cosmos-cmd-tlm-api/Dockerfile index f44e7a132b..ef82565488 100644 --- a/openc3-cosmos-cmd-tlm-api/Dockerfile +++ b/openc3-cosmos-cmd-tlm-api/Dockerfile @@ -5,6 +5,15 @@ ARG OPENC3_IMAGE=openc3-base FROM ${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/${OPENC3_IMAGE}:${OPENC3_TAG} +# anycable-go is only run by the API images, so copy it here instead of into +# openc3-ruby. The anycable build context is provided by compose-build.yaml +# (additional_contexts) or by --build-context in the other build scripts. +# TARGETARCH is set by BuildKit and must be amd64 or arm64 to match the +# binaries in openc3-anycable/. Copied before the source so API edits don't +# invalidate this layer. +ARG TARGETARCH +COPY --from=anycable --chmod=755 anycable-go-linux-${TARGETARCH} /usr/bin/anycable-go + WORKDIR /src/ RUN ["chown", "-R", "openc3:openc3", "/src/"] diff --git a/openc3-cosmos-script-runner-api/Dockerfile b/openc3-cosmos-script-runner-api/Dockerfile index 0b4fad3899..715d334fc8 100644 --- a/openc3-cosmos-script-runner-api/Dockerfile +++ b/openc3-cosmos-script-runner-api/Dockerfile @@ -5,6 +5,15 @@ ARG OPENC3_IMAGE=openc3-base FROM ${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/${OPENC3_IMAGE}:${OPENC3_TAG} +# anycable-go is only run by the API images, so copy it here instead of into +# openc3-ruby. The anycable build context is provided by compose-build.yaml +# (additional_contexts) or by --build-context in the other build scripts. +# TARGETARCH is set by BuildKit and must be amd64 or arm64 to match the +# binaries in openc3-anycable/. Copied before the source so API edits don't +# invalidate this layer. +ARG TARGETARCH +COPY --from=anycable --chmod=755 anycable-go-linux-${TARGETARCH} /usr/bin/anycable-go + WORKDIR /src/ RUN ["chown", "-R", "openc3:openc3", "/src/"] diff --git a/openc3-ruby/Dockerfile b/openc3-ruby/Dockerfile index edfeae521b..f2c25ee6cd 100644 --- a/openc3-ruby/Dockerfile +++ b/openc3-ruby/Dockerfile @@ -82,9 +82,6 @@ ENV GEMRC=/etc/gemrc # the apt step below (once bundler is installed). ENV BUNDLE_USER_CONFIG=/etc/bundle/config -COPY anycable* /usr/bin/ -RUN /usr/bin/anycable_install.sh - COPY shoreman.sh /usr/bin/shoreman RUN apt-get update && \ diff --git a/openc3-ruby/Dockerfile-ubi b/openc3-ruby/Dockerfile-ubi index e37dc40163..91397038b3 100644 --- a/openc3-ruby/Dockerfile-ubi +++ b/openc3-ruby/Dockerfile-ubi @@ -50,9 +50,6 @@ ENV GEMRC=/etc/gemrc COPY *.tar.gz /tmp/ -COPY anycable* /usr/bin/ -RUN /usr/bin/anycable_install.sh - COPY shoreman.sh /usr/bin/shoreman ARG PACKAGES="gcc-c++ patch readline zlib zlib-devel libffi-devel libedit \ diff --git a/openc3-ruby/anycable_install.sh b/openc3-ruby/anycable_install.sh deleted file mode 100755 index 9994278810..0000000000 --- a/openc3-ruby/anycable_install.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -ARCH=`uname -m` -if [ "$ARCH" = "aarch64" ]; then - chmod 755 /usr/bin/anycable-go-linux-arm64 - ln -s /usr/bin/anycable-go-linux-arm64 /usr/bin/anycable-go -else - chmod 755 /usr/bin/anycable-go-linux-amd64 - ln -s /usr/bin/anycable-go-linux-amd64 /usr/bin/anycable-go -fi -chmod 755 /usr/bin/anycable-go diff --git a/scripts/linux/openc3_build_ubi.sh b/scripts/linux/openc3_build_ubi.sh index 8c26f44282..dd324de154 100755 --- a/scripts/linux/openc3_build_ubi.sh +++ b/scripts/linux/openc3_build_ubi.sh @@ -365,6 +365,7 @@ if should_build "openc3-cosmos-cmd-tlm-api-ubi"; then rm -rf .bundle build_image \ --network host \ + --build-context anycable=../openc3-anycable \ --build-arg OPENC3_REGISTRY=$OPENC3_REGISTRY \ --build-arg OPENC3_NAMESPACE=$OPENC3_NAMESPACE \ --build-arg OPENC3_TAG=$OPENC3_TAG \ @@ -389,6 +390,7 @@ if should_build "openc3-cosmos-script-runner-api-ubi"; then rm -rf .bundle build_image \ --network host \ + --build-context anycable=../openc3-anycable \ --build-arg OPENC3_REGISTRY=$OPENC3_REGISTRY \ --build-arg OPENC3_NAMESPACE=$OPENC3_NAMESPACE \ --build-arg OPENC3_TAG=$OPENC3_TAG \ diff --git a/scripts/release/build_multi_arch.sh b/scripts/release/build_multi_arch.sh index 7d1fc5bdc9..fb8235efc0 100755 --- a/scripts/release/build_multi_arch.sh +++ b/scripts/release/build_multi_arch.sh @@ -289,6 +289,7 @@ fi cd ../openc3-cosmos-cmd-tlm-api retry_build \ --platform ${OPENC3_PLATFORMS} \ + --build-context anycable=../openc3-anycable \ --progress plain \ --build-arg OPENC3_REGISTRY=${OPENC3_REGISTRY} \ --build-arg OPENC3_NAMESPACE=${OPENC3_NAMESPACE} \ @@ -301,6 +302,7 @@ if [[ $OPENC3_UPDATE_LATEST == true ]] then retry_build \ --platform ${OPENC3_PLATFORMS} \ + --build-context anycable=../openc3-anycable \ --progress plain \ --build-arg OPENC3_REGISTRY=${OPENC3_REGISTRY} \ --build-arg OPENC3_NAMESPACE=${OPENC3_NAMESPACE} \ @@ -313,6 +315,7 @@ fi cd ../openc3-cosmos-script-runner-api retry_build \ --platform ${OPENC3_PLATFORMS} \ + --build-context anycable=../openc3-anycable \ --progress plain \ --build-arg OPENC3_REGISTRY=${OPENC3_REGISTRY} \ --build-arg OPENC3_NAMESPACE=${OPENC3_NAMESPACE} \ @@ -325,6 +328,7 @@ if [[ $OPENC3_UPDATE_LATEST == true ]] then retry_build \ --platform ${OPENC3_PLATFORMS} \ + --build-context anycable=../openc3-anycable \ --progress plain \ --build-arg OPENC3_REGISTRY=${OPENC3_REGISTRY} \ --build-arg OPENC3_NAMESPACE=${OPENC3_NAMESPACE} \ diff --git a/scripts/release/package_audit.rb b/scripts/release/package_audit.rb index ef891976e1..7282274e8d 100644 --- a/scripts/release/package_audit.rb +++ b/scripts/release/package_audit.rb @@ -69,8 +69,8 @@ # writes the new value back into ENV. Using the stale local would audit # Dockerfile-ubi against the old minor line and leave it behind the Debian image. check_ubi_ruby(client, ENV.fetch('RUBY_VERSION', ruby_version)) -ruby_container = containers.find { |c| c[:name].include?('openc3-ruby') } -check_anycable(client, ruby_container[:name]) if ruby_container +anycable_containers = containers.select { |c| c[:name].include?('openc3-cosmos-cmd-tlm-api') || c[:name].include?('openc3-cosmos-script-runner-api') } +check_anycable(client, anycable_containers.map { |c| c[:name] }) unless anycable_containers.empty? # After per-image prompts, ensure the build scripts still match the Dockerfiles. # Re-read the canonical version values in case they just changed. diff --git a/scripts/release/package_audit_lib.rb b/scripts/release/package_audit_lib.rb index c37f482093..aca62d855d 100644 --- a/scripts/release/package_audit_lib.rb +++ b/scripts/release/package_audit_lib.rb @@ -1032,9 +1032,17 @@ def check_container_version(client, containers, image_name) new_version end -def check_anycable(client, container_name) - anycable = `docker run --rm #{container_name} /usr/bin/anycable-go --version`.strip - puts "Raw anycable-go version: #{anycable}" +def check_anycable(client, container_names) + # Both API images install the same binary from openc3-anycable/, so audit the + # first and only warn if another image reports something different. + versions = container_names.map do |name| + [name, `docker run --rm #{name} /usr/bin/anycable-go --version`.strip] + end + versions.each { |name, version| puts "Raw anycable-go version (#{name}): #{version}" } + if versions.map(&:last).uniq.length > 1 + puts "WARNING: anycable-go versions differ between images; rebuild stale images before auditing" + end + anycable = versions.first.last any_cable_version = anycable.split('version:')[-1].split('-')[0].strip # A fourth version component means this is one of our own anycable-go builds, # never an upstream release: every anycable/anycable release back to v0.5.0 is @@ -1062,8 +1070,8 @@ def check_anycable(client, container_name) ver = new_version.sub(/^v/, '') amd_url = "https://github.com/anycable/anycable/releases/download/v#{ver}/anycable-go-linux-amd64" arm_url = "https://github.com/anycable/anycable/releases/download/v#{ver}/anycable-go-linux-arm64" - amd_path = File.join(ROOT_DIR, 'openc3-ruby/anycable-go-linux-amd64') - arm_path = File.join(ROOT_DIR, 'openc3-ruby/anycable-go-linux-arm64') + amd_path = File.join(ROOT_DIR, 'openc3-anycable/anycable-go-linux-amd64') + arm_path = File.join(ROOT_DIR, 'openc3-anycable/anycable-go-linux-arm64') system("curl -fSL #{amd_url} -o #{amd_path}") || (puts("ERROR: failed to download #{amd_url}"); return nil) system("curl -fSL #{arm_url} -o #{arm_path}") || (puts("ERROR: failed to download #{arm_url}"); return nil) if File.size(amd_path) < 1_000_000 || File.size(arm_path) < 1_000_000