From a4ec6aaa3ea5bffa2ce687a218220430e292299a Mon Sep 17 00:00:00 2001 From: "Cheng-Chen, Chen" Date: Thu, 15 Oct 2026 11:39:18 +0800 Subject: [PATCH 1/2] fix: offer the maintained CLI through release defaults --- docs/releases/server-1.6.536.md | 23 ++++++++++++ scripts/check-server-api-explorer-patch.sh | 25 +++++++++---- scripts/test-cli-download-defaults536.py | 35 +++++++++++++++++++ .../test-current-server-packaging-contract.py | 26 +++++++------- server/Dockerfile.web-compose-release | 6 +++- server/build-api-explorer-patch-image.sh | 8 +++-- server/security/openvex.json | 2 +- server/security/vendor-pending.json | 2 +- 8 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 docs/releases/server-1.6.536.md create mode 100644 scripts/test-cli-download-defaults536.py diff --git a/docs/releases/server-1.6.536.md b/docs/releases/server-1.6.536.md new file mode 100644 index 0000000000..058be3d2cb --- /dev/null +++ b/docs/releases/server-1.6.536.md @@ -0,0 +1,23 @@ +# Server v1.6.536 candidate + +This packaging update changes the three default external CLI download links and +advertised CLI version to the maintained `v0.6.18` release. It does not replace +the unchanged Web Console `1.6.189` or Engine `v0.183.349`, change API Key policy, +authentication, firewall rules, volumes or operator runtime configuration. + +The old `0.6.14` client swallowed a rejected schema request and exited zero. +The maintained CLI propagates the original failure. CLI publication/security +checks, exact release checksums and native Full/legacy/Closed command acceptance +remain required; this candidate is not a claim that they have passed. + +Explicit URL settings already saved in the database remain authoritative. An +upgrade does not silently replace an operator's mirror or pinned client. If a +saved URL still points to the historical Server `v1.6.278` CLI `0.6.14` asset, +an administrator can update the three `rancher.cli.*.url` settings through the +normal settings API/UI after verifying the new release checksums. Preserve any +intentional custom URLs. No database script or runtime binary patch is required. + +The full Server release and final-image checks must pass before publication. +Existing 535 acceptance is carried only where unchanged. Installation continues +to use a numeric image tag; do not overwrite earlier releases. Keep the previous +container and its configuration for rollback, without restoring an older database. diff --git a/scripts/check-server-api-explorer-patch.sh b/scripts/check-server-api-explorer-patch.sh index 8439db56b5..4a93b106cc 100755 --- a/scripts/check-server-api-explorer-patch.sh +++ b/scripts/check-server-api-explorer-patch.sh @@ -407,6 +407,7 @@ else: PY python3 scripts/test-published-install-gate.py python3 scripts/test-current-server-packaging-contract.py +python3 scripts/test-cli-download-defaults536.py require_marker docs/releases/server-1.6.498.md '# Server v1.6.498' \ SERVER_GENERIC_OBJECT_PATCH_NOTES_MISSING @@ -526,7 +527,7 @@ require_marker "$release_dockerfile" \ 'ARG BASE_IMAGE=ghcr.io/pasturestack/server:v1.6.460@sha256:c855af8aea232dacc5bb6df68e2271d482c68b53c43ab0c108ec19118f5ab403' \ SERVER_INCREMENTAL_RELEASE_BASE_MISSING require_marker "$release_dockerfile" \ - 'ARG SERVER_RELEASE_TAG=v1.6.535' \ + 'ARG SERVER_RELEASE_TAG=v1.6.536' \ SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING require_marker "$release_dockerfile" \ 'org.opencontainers.image.version="${SERVER_RELEASE_TAG}"' \ @@ -540,6 +541,18 @@ require_marker "$release_dockerfile" \ require_marker "$release_dockerfile" \ 'ENV CATTLE_RANCHER_SERVER_VERSION=${SERVER_RELEASE_TAG}' \ SERVER_INCREMENTAL_RELEASE_RUNTIME_VERSION_MISSING +for cli_platform in LINUX DARWIN WINDOWS; do + case "$cli_platform" in + LINUX) cli_suffix=linux-amd64.tar.gz ;; + DARWIN) cli_suffix=darwin-amd64.tar.gz ;; + WINDOWS) cli_suffix=windows-amd64.zip ;; + esac + cli_url="https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-${cli_suffix}" + require_marker "$release_dockerfile" "ENV DEFAULT_CATTLE_RANCHER_CLI_${cli_platform}_URL=${cli_url}" SERVER_CLI_DOWNLOAD_DEFAULT_MISSING + require_marker "$build_script" "DEFAULT_CATTLE_RANCHER_CLI_${cli_platform}_URL=${cli_url}" SERVER_CLI_DOWNLOAD_RUNTIME_READBACK_MISSING +done +require_marker "$release_dockerfile" 'ENV CATTLE_RANCHER_CLI_VERSION=v0.6.18' SERVER_CLI_VERSION_DEFAULT_MISSING +require_marker "$build_script" 'CATTLE_RANCHER_CLI_VERSION=v0.6.18' SERVER_CLI_VERSION_RUNTIME_READBACK_MISSING require_marker "$release_dockerfile" \ 'COPY --from=release_artifacts /out/host-api.tar.gz /usr/share/cattle/artifacts/host-api-${HOST_API_VERSION}.tar.gz' \ SERVER_HOST_API_SHA256_PACKAGE_MISSING @@ -1059,10 +1072,10 @@ require_marker "$build_script" \ '--file server/Dockerfile.web-compose-release' \ SERVER_INCREMENTAL_RELEASE_BUILD_PATH_MISSING require_marker "$build_script" \ - 'image=${IMAGE:-pasturestack-validation/server:v1.6.535}' \ + 'image=${IMAGE:-pasturestack-validation/server:v1.6.536}' \ SERVER_INCREMENTAL_RELEASE_BUILD_VERSION_MISSING require_marker "$build_script" \ - 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.535}' \ + 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.536}' \ SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING require_marker "$build_script" \ 'CATTLE_RANCHER_SERVER_VERSION="${server_release_tag}"' \ @@ -2158,7 +2171,7 @@ done jq -e ' ["CVE-2026-107928","CVE-2026-107929","CVE-2026-86409","CVE-2026-86410","CVE-2026-86412","CVE-2026-86414","CVE-2026-87862","CVE-2026-87863","CVE-2026-87864","CVE-2026-87865","CVE-2026-92386","CVE-2026-92387","CVE-2026-92388","CVE-2026-92389","CVE-2026-92390","CVE-2026-92391","CVE-2026-92392","CVE-2026-94266"] as $curl_fixed_cves | .["@context"] == "https://openvex.dev/ns/v0.2.0" - and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.535" + and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.536" and (.statements | length) == 69 and ([.statements[].vulnerability.name] | length == (unique | length)) and ([.statements[] | select(.status == "fixed") | .vulnerability.name] | sort) @@ -2196,7 +2209,7 @@ jq -r ' | @tsv ' "$runtime_vendor_pending" | LC_ALL=C sort -u >"$vendor_pending_fixture" bash "$vendor_pending_validator" "$runtime_vendor_pending" \ - "$vendor_pending_fixture" v1.6.535 >/dev/null + "$vendor_pending_fixture" v1.6.536 >/dev/null bash scripts/test-vendor-pending-findings.sh >/dev/null rm -f "$vendor_pending_fixture" trap - EXIT @@ -2285,4 +2298,4 @@ for release_readback_contract in \ fi done -printf 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.535 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.8 freemarker=2.3.35 artifact_scan=required vendor_pending=exact-set role_matrix=qa-required locale_layout=qa-required\n' +printf 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.536 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.8 freemarker=2.3.35 artifact_scan=required vendor_pending=exact-set role_matrix=qa-required locale_layout=qa-required\n' diff --git a/scripts/test-cli-download-defaults536.py b/scripts/test-cli-download-defaults536.py new file mode 100644 index 0000000000..8e3199afa3 --- /dev/null +++ b/scripts/test-cli-download-defaults536.py @@ -0,0 +1,35 @@ +"""Focused CLI download defaults and operator override contract, no network IO.""" +import os,pathlib,re,subprocess,sys,unittest +ROOT=pathlib.Path(__file__).resolve().parents[1] +RECIPE=(ROOT/'server/Dockerfile.web-compose-release').read_text() +BUILD=(ROOT/'server/build-api-explorer-patch-image.sh').read_text() +CATTLE=(ROOT/'server/artifacts/cattle.sh').read_text() +FUNCTION=re.search(r'^setup_cli_artifact_overrides\(\)\n\{.*?^\}',CATTLE,re.M|re.S).group() +DEFAULTS=dict(re.findall(r'^ENV ((?:DEFAULT_CATTLE_RANCHER_CLI_[A-Z]+_URL|CATTLE_RANCHER_CLI_VERSION))=(\S+)$',RECIPE,re.M)) +class CliDefaults536(unittest.TestCase): + def evaluate(self,overrides=None): + env={'PATH':os.environ['PATH'],'RC16_ARTIFACT_BASE_URL':'https://legacy.example/releases/v1.6.278',**DEFAULTS,**(overrides or {})} + script=FUNCTION+'\nsetup_cli_artifact_overrides\n'+ '\n'.join('printf "%s\\n" "${'+k+'}"'for k in sorted(DEFAULTS)) + process=subprocess.run(['bash','-c',script],env=env,capture_output=True,text=True,timeout=10) + self.assertEqual(process.returncode,0) + return dict(zip(sorted(DEFAULTS),process.stdout.splitlines())) + def test_numeric_version_and_three_official_default_urls(self): + self.assertEqual(DEFAULTS['CATTLE_RANCHER_CLI_VERSION'],'v0.6.18') + for platform,suffix in [('LINUX','linux-amd64.tar.gz'),('DARWIN','darwin-amd64.tar.gz'),('WINDOWS','windows-amd64.zip')]: + key='DEFAULT_CATTLE_RANCHER_CLI_'+platform+'_URL' + self.assertEqual(DEFAULTS[key],'https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-'+suffix) + self.assertIn(key+'='+DEFAULTS[key],BUILD) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_clean_defaults_do_not_use_legacy_artifact_base(self): + self.assertEqual(self.evaluate(),DEFAULTS) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_operator_default_url_override_is_preserved(self): + custom={'DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL':'https://mirror.example/owned-cli.tar.gz'} + self.assertEqual(self.evaluate(custom),{**DEFAULTS,**custom}) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_operator_active_url_is_not_rewritten(self): + key='CATTLE_RANCHER_CLI_LINUX_URL';custom='https://mirror.example/active-cli.tar.gz' + script=FUNCTION+'\nsetup_cli_artifact_overrides\nprintf "%s" "${'+key+'}"' + p=subprocess.run(['bash','-c',script],env={'PATH':os.environ['PATH'],'RC16_ARTIFACT_BASE_URL':'https://legacy.example',**DEFAULTS,key:custom},capture_output=True,text=True,timeout=10) + self.assertEqual((p.returncode,p.stdout),(0,custom)) +if __name__=='__main__':unittest.main() diff --git a/scripts/test-current-server-packaging-contract.py b/scripts/test-current-server-packaging-contract.py index 309078b67d..963e0c9b6e 100644 --- a/scripts/test-current-server-packaging-contract.py +++ b/scripts/test-current-server-packaging-contract.py @@ -23,7 +23,7 @@ ENGINE_SHA = '6e61f05598c12941c3b07ebfcf81f40e7fb1bd5439ec4c7d9c34484306378f04' ENGINE_SOURCE = '0733430fac11892a17ba53749fe02d99d26b1f52' OLD_COORDINATES = { - 'v1.6.535': 'v1.6.521', + 'v1.6.536': 'v1.6.521', '1.6.189': '1.6.181', WEB_SHA: '9199681f2c4311f3fbe8727fcf0f6fa136c9bafe9fbe9d13878c55df442a7a03', WEB_SOURCE: '7f2bdad0c90a3241693c2ddd4475202ababba550', @@ -31,7 +31,7 @@ } # Engine349 and Web189 use the reviewed component input identities. # Published521 component values remain mutation controls. -# Component coordinates do not establish Server535 artifact/runtime PASS. +# Component coordinates do not establish Server536 artifact/runtime PASS. CATALOG_FIELDS = ( ('VERSION', 'version', '0.20.13'), ('COMMIT', 'commit', '4c39c73a8131ba06e9ff0aaec3b95cc27e049324'), @@ -47,7 +47,7 @@ } EXPECTED = { COMPATIBILITY_CODE: (COMPATIBILITY, PUBLISHED_508), - 'SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING': (DOCKER, 'ARG SERVER_RELEASE_TAG=v1.6.535'), + 'SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING': (DOCKER, 'ARG SERVER_RELEASE_TAG=v1.6.536'), 'SERVER_INCREMENTAL_RELEASE_VERSION_MISSING': (DOCKER, 'org.opencontainers.image.version="${SERVER_RELEASE_TAG}"'), 'SERVER_INCREMENTAL_RELEASE_RUNTIME_VERSION_MISSING': (DOCKER, 'ENV CATTLE_RANCHER_SERVER_VERSION=${SERVER_RELEASE_TAG}'), 'SERVER_INCREMENTAL_WEB_CONSOLE_VERSION_MISSING': (DOCKER, 'ARG WEB_CONSOLE_RELEASE_TAG=1.6.189'), @@ -58,8 +58,8 @@ 'SERVER_INCREMENTAL_WEB_CONSOLE_BUILD_VERSION_MISSING': (BUILD, 'web_console_release_tag=${WEB_CONSOLE_RELEASE_TAG:-1.6.189}'), 'SERVER_INCREMENTAL_WEB_CONSOLE_BUILD_ARTIFACT_MISSING': (BUILD, 'web_console_artifact=${WEB_CONSOLE_ARTIFACT:-web-console-1.6.189.tar.gz}'), 'SERVER_INCREMENTAL_WEB_CONSOLE_BUILD_HASH_MISSING': (BUILD, 'web_console_artifact_sha256=${WEB_CONSOLE_ARTIFACT_SHA256:-' + WEB_SHA + '}'), - 'SERVER_INCREMENTAL_RELEASE_BUILD_VERSION_MISSING': (BUILD, 'image=${IMAGE:-pasturestack-validation/server:v1.6.535}'), - 'SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING': (BUILD, 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.535}'), + 'SERVER_INCREMENTAL_RELEASE_BUILD_VERSION_MISSING': (BUILD, 'image=${IMAGE:-pasturestack-validation/server:v1.6.536}'), + 'SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING': (BUILD, 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.536}'), 'SERVER_INCREMENTAL_RELEASE_BUILD_RUNTIME_VERSION_MISSING': (BUILD, 'CATTLE_RANCHER_SERVER_VERSION="${server_release_tag}"'), 'SERVER_WEB_CONSOLE_RUNTIME_VERSION_GATE_MISSING': (BUILD, 'test "$(cat "${web_root}/VERSION.txt")" = "${WEB_CONSOLE_RELEASE_TAG}"'), 'SERVER_VOLUME_NATIVE_READ_ONLY_BUILD_GATE_MISSING': (DOCKER, 'grep -F \'"volume.isNative" : "r"\' >/dev/null'), @@ -470,15 +470,15 @@ def verify(files, gate=GATE): pipeline = r'(?:^|[;\n])\s*' + re.escape(marker) + r'(?=\s*(?:;|\n|$))' if len(re.findall(pipeline, source)) != 1: raise AssertionError('CURRENT_CATALOG_HASH_BYPASS') - if 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.535"' not in gate: + if 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.536"' not in gate: raise AssertionError('CURRENT_VEX_GATE_PIN_MISMATCH') - if '"$vendor_pending_fixture" v1.6.535 >/dev/null' not in gate: + if '"$vendor_pending_fixture" v1.6.536 >/dev/null' not in gate: raise AssertionError('CURRENT_VENDOR_GATE_PIN_MISMATCH') - if json.loads(files[VEX]).get('@id') != 'https://github.com/PastureStack/server/security/openvex/v1.6.535': + if json.loads(files[VEX]).get('@id') != 'https://github.com/PastureStack/server/security/openvex/v1.6.536': raise AssertionError('CURRENT_VEX_RELEASE_MISMATCH') - if json.loads(files[VENDOR]).get('release') != 'v1.6.535': + if json.loads(files[VENDOR]).get('release') != 'v1.6.536': raise AssertionError('CURRENT_VENDOR_RELEASE_MISMATCH') - if 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.535 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 ' not in gate: + if 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.536 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 ' not in gate: raise AssertionError('CURRENT_SUMMARY_MISMATCH') verify_incremental_contract(files, gate) @@ -492,11 +492,11 @@ def previous_gate(gate=GATE): if stale(marker) != marker: replacements["'" + marker + "' "] = "'" + stale(marker) + "' " replacements.update({ - 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.535"': + 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.536"': 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.521"', - '"$vendor_pending_fixture" v1.6.535 >/dev/null': + '"$vendor_pending_fixture" v1.6.536 >/dev/null': '"$vendor_pending_fixture" v1.6.521 >/dev/null', - 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.535 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 ': + 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.536 base=v1.6.460 engine=0.183.349 web_console=1.6.189 catalog_service=0.20.13 ': 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.521 base=v1.6.460 engine=0.183.340 web_console=1.6.181 catalog_service=0.20.12 ', }) for marker, stale_marker in replacements.items(): diff --git a/server/Dockerfile.web-compose-release b/server/Dockerfile.web-compose-release index 1c752de1b3..f7fe66f078 100644 --- a/server/Dockerfile.web-compose-release +++ b/server/Dockerfile.web-compose-release @@ -574,7 +574,7 @@ FROM ${BASE_IMAGE} ARG SOURCE_DATE_EPOCH ARG PASTURESTACK_SERVER_REVISION -ARG SERVER_RELEASE_TAG=v1.6.535 +ARG SERVER_RELEASE_TAG=v1.6.536 ARG ORCHESTRATION_ENGINE_RELEASE_TAG=v0.183.349 ARG ORCHESTRATION_ENGINE_VERSION=0.183.349 ARG ENGINE_READONLY_SCHEMA_SHA256=7f274219e8dd9c6d750a408a6edec1448b564f4b16ba2204c425c5b45cec2233 @@ -1024,6 +1024,10 @@ LABEL org.opencontainers.image.source="https://github.com/PastureStack/server" \ org.opencontainers.image.base.digest="sha256:c855af8aea232dacc5bb6df68e2271d482c68b53c43ab0c108ec19118f5ab403" ENV CATTLE_RANCHER_SERVER_VERSION=${SERVER_RELEASE_TAG} +ENV CATTLE_RANCHER_CLI_VERSION=v0.6.18 +ENV DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-linux-amd64.tar.gz +ENV DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-darwin-amd64.tar.gz +ENV DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-windows-amd64.zip ENV CATTLE_CATTLE_VERSION=${ORCHESTRATION_ENGINE_RELEASE_TAG} ENV RC16_HOST_API_VERSION=${HOST_API_VERSION} ENV PASTURESTACK_HOST_API_PACKAGE_ID=${HOST_API_PACKAGE_ID} diff --git a/server/build-api-explorer-patch-image.sh b/server/build-api-explorer-patch-image.sh index 33890fb6f5..e5cf0e74d8 100755 --- a/server/build-api-explorer-patch-image.sh +++ b/server/build-api-explorer-patch-image.sh @@ -14,7 +14,7 @@ if [[ -n "$(git status --porcelain --untracked-files=normal)" ]]; then fi revision=${PASTURESTACK_SERVER_REVISION:-$(git rev-parse HEAD)} -server_release_tag=${SERVER_RELEASE_TAG:-v1.6.535} +server_release_tag=${SERVER_RELEASE_TAG:-v1.6.536} source_date_epoch=${SOURCE_DATE_EPOCH:-$(git show -s --format=%ct HEAD)} base_image=${BASE_IMAGE:-ghcr.io/pasturestack/server:v1.6.460@sha256:c855af8aea232dacc5bb6df68e2271d482c68b53c43ab0c108ec19118f5ab403} orchestration_engine_release_base_url=${ORCHESTRATION_ENGINE_RELEASE_BASE_URL:-https://github.com/PastureStack/orchestration-engine/releases/download} @@ -101,7 +101,7 @@ usage_telemetry_agent_archive_sha256=${USAGE_TELEMETRY_AGENT_ARCHIVE_SHA256:-5ce usage_telemetry_agent_binary_sha256=${USAGE_TELEMETRY_AGENT_BINARY_SHA256:-e62a21270142181315293d7e11482288ffe8fc4d91cc8fe07dacc90b461f3709} supported_docker_range='~v1.12.3 || ~v1.13.0 || ~v17.03.0 || ~v17.06.0 || ~v17.09.0 || ~v17.12.0 || ~v18.03.0 || ~v18.06.0 || ~v18.09.0 || ~v19.03.2 || v24.0.9 || >=v29.4.1 <=v29.7.2 || v29.8.0' newest_docker_version=v29.8.0 -image=${IMAGE:-pasturestack-validation/server:v1.6.535} +image=${IMAGE:-pasturestack-validation/server:v1.6.536} build_options=() [[ "$revision" =~ ^[0-9a-f]{40}$ ]] @@ -339,6 +339,10 @@ image_environment=$(docker image inspect "$image" \ --format '{{range .Config.Env}}{{println .}}{{end}}') for marker in \ CATTLE_RANCHER_SERVER_VERSION="${server_release_tag}" \ + CATTLE_RANCHER_CLI_VERSION=v0.6.18 \ + DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-linux-amd64.tar.gz \ + DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-darwin-amd64.tar.gz \ + DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-windows-amd64.zip \ CATTLE_API_UI_VERSION=1.1.18 \ CATTLE_CATTLE_VERSION="${orchestration_engine_release_tag}" \ RC16_GO_AGENT_VERSION="${node_agent_version}" \ diff --git a/server/security/openvex.json b/server/security/openvex.json index 517391dfab..67427545aa 100644 --- a/server/security/openvex.json +++ b/server/security/openvex.json @@ -1,6 +1,6 @@ { "@context": "https://openvex.dev/ns/v0.2.0", - "@id": "https://github.com/PastureStack/server/security/openvex/v1.6.535", + "@id": "https://github.com/PastureStack/server/security/openvex/v1.6.536", "author": "PastureStack Security", "timestamp": "2026-10-15T00:38:08Z", "version": 56, diff --git a/server/security/vendor-pending.json b/server/security/vendor-pending.json index e4e076534b..ab0daf5356 100644 --- a/server/security/vendor-pending.json +++ b/server/security/vendor-pending.json @@ -1,6 +1,6 @@ { "schemaVersion": 1, - "release": "v1.6.535", + "release": "v1.6.536", "generatedAt": "2026-10-15T02:44:00Z", "policy": { "allowedSeverities": [ From 921e7ab83da25fdf739fc5fc53589879170c5cc1 Mon Sep 17 00:00:00 2001 From: "Cheng-Chen, Chen" Date: Thu, 15 Oct 2026 11:49:19 +0800 Subject: [PATCH 2/2] fix: preserve CLI version and operator download overrides --- scripts/check-server-api-explorer-patch.sh | 12 ++------ scripts/test-cli-download-defaults536.py | 34 +++++++++++++++------- server/Dockerfile.web-compose-release | 4 +-- server/artifacts/cattle.sh | 29 +++++++++++++----- server/build-api-explorer-patch-image.sh | 4 +-- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/scripts/check-server-api-explorer-patch.sh b/scripts/check-server-api-explorer-patch.sh index 4a93b106cc..67166b2243 100755 --- a/scripts/check-server-api-explorer-patch.sh +++ b/scripts/check-server-api-explorer-patch.sh @@ -541,16 +541,8 @@ require_marker "$release_dockerfile" \ require_marker "$release_dockerfile" \ 'ENV CATTLE_RANCHER_SERVER_VERSION=${SERVER_RELEASE_TAG}' \ SERVER_INCREMENTAL_RELEASE_RUNTIME_VERSION_MISSING -for cli_platform in LINUX DARWIN WINDOWS; do - case "$cli_platform" in - LINUX) cli_suffix=linux-amd64.tar.gz ;; - DARWIN) cli_suffix=darwin-amd64.tar.gz ;; - WINDOWS) cli_suffix=windows-amd64.zip ;; - esac - cli_url="https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-${cli_suffix}" - require_marker "$release_dockerfile" "ENV DEFAULT_CATTLE_RANCHER_CLI_${cli_platform}_URL=${cli_url}" SERVER_CLI_DOWNLOAD_DEFAULT_MISSING - require_marker "$build_script" "DEFAULT_CATTLE_RANCHER_CLI_${cli_platform}_URL=${cli_url}" SERVER_CLI_DOWNLOAD_RUNTIME_READBACK_MISSING -done +require_marker "$release_dockerfile" 'ENV PASTURESTACK_CLI_RELEASE_BASE_URL=https://github.com/PastureStack/cli/releases/download' SERVER_CLI_DOWNLOAD_DEFAULT_MISSING +require_marker "$build_script" 'PASTURESTACK_CLI_RELEASE_BASE_URL=https://github.com/PastureStack/cli/releases/download' SERVER_CLI_DOWNLOAD_RUNTIME_READBACK_MISSING require_marker "$release_dockerfile" 'ENV CATTLE_RANCHER_CLI_VERSION=v0.6.18' SERVER_CLI_VERSION_DEFAULT_MISSING require_marker "$build_script" 'CATTLE_RANCHER_CLI_VERSION=v0.6.18' SERVER_CLI_VERSION_RUNTIME_READBACK_MISSING require_marker "$release_dockerfile" \ diff --git a/scripts/test-cli-download-defaults536.py b/scripts/test-cli-download-defaults536.py index 8e3199afa3..8ae4d8a49e 100644 --- a/scripts/test-cli-download-defaults536.py +++ b/scripts/test-cli-download-defaults536.py @@ -5,27 +5,41 @@ BUILD=(ROOT/'server/build-api-explorer-patch-image.sh').read_text() CATTLE=(ROOT/'server/artifacts/cattle.sh').read_text() FUNCTION=re.search(r'^setup_cli_artifact_overrides\(\)\n\{.*?^\}',CATTLE,re.M|re.S).group() -DEFAULTS=dict(re.findall(r'^ENV ((?:DEFAULT_CATTLE_RANCHER_CLI_[A-Z]+_URL|CATTLE_RANCHER_CLI_VERSION))=(\S+)$',RECIPE,re.M)) +DEFAULTS=dict(re.findall(r'^ENV ((?:PASTURESTACK_CLI_RELEASE_BASE_URL|CATTLE_RANCHER_CLI_VERSION))=(\S+)$',RECIPE,re.M)) +URLS=['DEFAULT_CATTLE_RANCHER_CLI_'+x+'_URL'for x in ('LINUX','DARWIN','WINDOWS')] +KEYS=['CATTLE_RANCHER_CLI_VERSION',*URLS] +def expected(version='0.6.18',base='https://github.com/PastureStack/cli/releases/download'): + return dict(zip(URLS,[base+'/v'+version+'/pasturestack-cli-'+p+'-'+version+suffix for p,suffix in [('linux-amd64','.tar.gz'),('darwin-amd64','.tar.gz'),('windows-amd64','.zip')]])) class CliDefaults536(unittest.TestCase): - def evaluate(self,overrides=None): + def evaluate(self,overrides=None,*,no_compose=False): env={'PATH':os.environ['PATH'],'RC16_ARTIFACT_BASE_URL':'https://legacy.example/releases/v1.6.278',**DEFAULTS,**(overrides or {})} - script=FUNCTION+'\nsetup_cli_artifact_overrides\n'+ '\n'.join('printf "%s\\n" "${'+k+'}"'for k in sorted(DEFAULTS)) + script='set -eu\n'+FUNCTION+'\nsetup_cli_artifact_overrides\n' + if no_compose:script+='test "${CATTLE_RANCHER_COMPOSE_VERSION+x}" != x\n' + script+='\n'.join('printf "%s\\n" "${'+k+'}"'for k in KEYS) process=subprocess.run(['bash','-c',script],env=env,capture_output=True,text=True,timeout=10) self.assertEqual(process.returncode,0) - return dict(zip(sorted(DEFAULTS),process.stdout.splitlines())) + return dict(zip(KEYS,process.stdout.splitlines())) def test_numeric_version_and_three_official_default_urls(self): self.assertEqual(DEFAULTS['CATTLE_RANCHER_CLI_VERSION'],'v0.6.18') - for platform,suffix in [('LINUX','linux-amd64.tar.gz'),('DARWIN','darwin-amd64.tar.gz'),('WINDOWS','windows-amd64.zip')]: - key='DEFAULT_CATTLE_RANCHER_CLI_'+platform+'_URL' - self.assertEqual(DEFAULTS[key],'https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-'+suffix) - self.assertIn(key+'='+DEFAULTS[key],BUILD) + self.assertEqual(DEFAULTS['PASTURESTACK_CLI_RELEASE_BASE_URL'],'https://github.com/PastureStack/cli/releases/download') + for key,value in DEFAULTS.items():self.assertIn(key+'='+value,BUILD) @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') def test_clean_defaults_do_not_use_legacy_artifact_base(self): - self.assertEqual(self.evaluate(),DEFAULTS) + self.assertEqual(self.evaluate(),{'CATTLE_RANCHER_CLI_VERSION':'v0.6.18',**expected()}) @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') def test_operator_default_url_override_is_preserved(self): custom={'DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL':'https://mirror.example/owned-cli.tar.gz'} - self.assertEqual(self.evaluate(custom),{**DEFAULTS,**custom}) + self.assertEqual(self.evaluate(custom),{'CATTLE_RANCHER_CLI_VERSION':'v0.6.18',**expected(),**custom}) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_version_only_override_changes_all_three_urls(self): + self.assertEqual(self.evaluate({'CATTLE_RANCHER_CLI_VERSION':'v0.6.17'}),{'CATTLE_RANCHER_CLI_VERSION':'v0.6.17',**expected('0.6.17')}) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_legacy_base_without_new_release_base_keeps_historical_layout(self): + result=self.evaluate({'PASTURESTACK_CLI_RELEASE_BASE_URL':'','CATTLE_RANCHER_CLI_VERSION':'v0.6.14'}) + self.assertEqual(result,{'CATTLE_RANCHER_CLI_VERSION':'v0.6.14',**dict(zip(URLS,['https://legacy.example/releases/v1.6.278/pasturestack-cli-0.6.14-'+p for p in ('linux-amd64.tar.gz','darwin-amd64.tar.gz','windows-amd64.zip')]))}) + @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') + def test_modern_release_base_does_not_need_legacy_base(self): + self.assertEqual(self.evaluate({'RC16_ARTIFACT_BASE_URL':''},no_compose=True),{'CATTLE_RANCHER_CLI_VERSION':'v0.6.18',**expected()}) @unittest.skipIf(sys.platform=='win32','Run Bash semantics in the Linux release gate; do not launch WSL') def test_operator_active_url_is_not_rewritten(self): key='CATTLE_RANCHER_CLI_LINUX_URL';custom='https://mirror.example/active-cli.tar.gz' diff --git a/server/Dockerfile.web-compose-release b/server/Dockerfile.web-compose-release index f7fe66f078..dc86b80b86 100644 --- a/server/Dockerfile.web-compose-release +++ b/server/Dockerfile.web-compose-release @@ -1025,9 +1025,7 @@ LABEL org.opencontainers.image.source="https://github.com/PastureStack/server" \ ENV CATTLE_RANCHER_SERVER_VERSION=${SERVER_RELEASE_TAG} ENV CATTLE_RANCHER_CLI_VERSION=v0.6.18 -ENV DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-linux-amd64.tar.gz -ENV DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-darwin-amd64.tar.gz -ENV DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-windows-amd64.zip +ENV PASTURESTACK_CLI_RELEASE_BASE_URL=https://github.com/PastureStack/cli/releases/download ENV CATTLE_CATTLE_VERSION=${ORCHESTRATION_ENGINE_RELEASE_TAG} ENV RC16_HOST_API_VERSION=${HOST_API_VERSION} ENV PASTURESTACK_HOST_API_PACKAGE_ID=${HOST_API_PACKAGE_ID} diff --git a/server/artifacts/cattle.sh b/server/artifacts/cattle.sh index f9ed0d90db..1a59438895 100755 --- a/server/artifacts/cattle.sh +++ b/server/artifacts/cattle.sh @@ -288,7 +288,9 @@ setup_agent_artifact_overrides() setup_cli_artifact_overrides() { local artifact_base="${RC16_ARTIFACT_BASE_URL%/}" - if [ -z "$artifact_base" ]; then + local cli_release_base="${PASTURESTACK_CLI_RELEASE_BASE_URL:-}" + cli_release_base="${cli_release_base%/}" + if [ -z "$artifact_base" ] && [ -z "$cli_release_base" ]; then return 0 fi @@ -297,15 +299,26 @@ setup_cli_artifact_overrides() local compose_asset_version="${compose_version#v}" local cli_asset_version="${cli_version#v}" - export CATTLE_RANCHER_COMPOSE_VERSION="$compose_version" - export DEFAULT_CATTLE_RANCHER_COMPOSE_LINUX_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_LINUX_URL:-${artifact_base}/compose-cli-${compose_asset_version}-linux-amd64.tar.gz}" - export DEFAULT_CATTLE_RANCHER_COMPOSE_DARWIN_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_DARWIN_URL:-${artifact_base}/compose-cli-${compose_asset_version}-darwin-amd64.tar.gz}" - export DEFAULT_CATTLE_RANCHER_COMPOSE_WINDOWS_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_WINDOWS_URL:-${artifact_base}/compose-cli-${compose_asset_version}-windows-amd64.zip}" + if [ -n "$artifact_base" ]; then + export CATTLE_RANCHER_COMPOSE_VERSION="$compose_version" + export DEFAULT_CATTLE_RANCHER_COMPOSE_LINUX_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_LINUX_URL:-${artifact_base}/compose-cli-${compose_asset_version}-linux-amd64.tar.gz}" + export DEFAULT_CATTLE_RANCHER_COMPOSE_DARWIN_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_DARWIN_URL:-${artifact_base}/compose-cli-${compose_asset_version}-darwin-amd64.tar.gz}" + export DEFAULT_CATTLE_RANCHER_COMPOSE_WINDOWS_URL="${DEFAULT_CATTLE_RANCHER_COMPOSE_WINDOWS_URL:-${artifact_base}/compose-cli-${compose_asset_version}-windows-amd64.zip}" + fi + local cli_linux_url="${artifact_base}/pasturestack-cli-${cli_asset_version}-linux-amd64.tar.gz" + local cli_darwin_url="${artifact_base}/pasturestack-cli-${cli_asset_version}-darwin-amd64.tar.gz" + local cli_windows_url="${artifact_base}/pasturestack-cli-${cli_asset_version}-windows-amd64.zip" + if [ -n "$cli_release_base" ]; then + local cli_base="${cli_release_base}/v${cli_asset_version}" + cli_linux_url="${cli_base}/pasturestack-cli-linux-amd64-${cli_asset_version}.tar.gz" + cli_darwin_url="${cli_base}/pasturestack-cli-darwin-amd64-${cli_asset_version}.tar.gz" + cli_windows_url="${cli_base}/pasturestack-cli-windows-amd64-${cli_asset_version}.zip" + fi export CATTLE_RANCHER_CLI_VERSION="$cli_version" - export DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL="${DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL:-${artifact_base}/pasturestack-cli-${cli_asset_version}-linux-amd64.tar.gz}" - export DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL="${DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL:-${artifact_base}/pasturestack-cli-${cli_asset_version}-darwin-amd64.tar.gz}" - export DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL="${DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL:-${artifact_base}/pasturestack-cli-${cli_asset_version}-windows-amd64.zip}" + export DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL="${DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL:-$cli_linux_url}" + export DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL="${DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL:-$cli_darwin_url}" + export DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL="${DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL:-$cli_windows_url}" } setup_default_service_flags() diff --git a/server/build-api-explorer-patch-image.sh b/server/build-api-explorer-patch-image.sh index e5cf0e74d8..4fd050ebed 100755 --- a/server/build-api-explorer-patch-image.sh +++ b/server/build-api-explorer-patch-image.sh @@ -340,9 +340,7 @@ image_environment=$(docker image inspect "$image" \ for marker in \ CATTLE_RANCHER_SERVER_VERSION="${server_release_tag}" \ CATTLE_RANCHER_CLI_VERSION=v0.6.18 \ - DEFAULT_CATTLE_RANCHER_CLI_LINUX_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-linux-amd64.tar.gz \ - DEFAULT_CATTLE_RANCHER_CLI_DARWIN_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-darwin-amd64.tar.gz \ - DEFAULT_CATTLE_RANCHER_CLI_WINDOWS_URL=https://github.com/PastureStack/cli/releases/download/v0.6.18/pasturestack-cli-0.6.18-windows-amd64.zip \ + PASTURESTACK_CLI_RELEASE_BASE_URL=https://github.com/PastureStack/cli/releases/download \ CATTLE_API_UI_VERSION=1.1.18 \ CATTLE_CATTLE_VERSION="${orchestration_engine_release_tag}" \ RC16_GO_AGENT_VERSION="${node_agent_version}" \