Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/releases/server-1.6.528.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Server v1.6.528

本版修正自訂 API Key 依 Stack 讀取 Instance Link 時,MariaDB 將相關
EXISTS 最佳化為不支援的 row/IN 查詢、導致 HTTP 409 的問題。
父 Stack 改用主鍵唯一的 scalar marker;精確 ID、同擁有者與存活條件仍保留。
Container/Link 共用的 Stack 比較明確處理雙 NULL 與單側 NULL,不讓
不一致的 managed/upgrade 父層關係漏過檢查。

## 元件與檢查範圍

- Engine:v0.183.346,來源 e250e4a17958216c30c1f5d0d31f7b6418a968d5。
- 正式 cattle.jar:87,874,922 bytes;SHA-256
`9deeda5758b7f04135441a203092dd0308d90b65d25037b62ef4f9361d3cf806`。
- Web Console:1.6.183;其他元件與安全控制沿用既有組合。
- Engine 三項相關測試與 MariaDB 11.8.6 的兩個完整唯讀 SQL 查詢通過。
這些是來源與資料庫相容性證據,不替代組裝映像的業務授權驗收。

Server 仍須通過原有封裝、必要 CodeQL、merged-rootfs 安全/SBOM、
不可變發行與實機檢查。只更新 VEX/待供應商修補清單的數字版本識別;
既有決策、修補條件與期限不變。歷史 344 控制保留,另驗證舊 345
來源與 WAR 不得冒充 346。KVM 與完整矩陣的未驗項目不宣稱通過。

## 升級與回復

使用正式數字版本映像與原有 Compose,保留環境變數、named volumes、
restart、安全設定、HTTPS origin、OIDC 與 nftables 架構。
部署前備份設定與資料庫,並保留最近已驗收版本的回復點。
本次未修改資料庫結構或 HAProxy,也不需要 runtime patch;
回到舊版本仍會帶回其已知的自訂 Key Link 查詢缺口。

實際 Server 發行身分、部署與驗收結果以本版發行資產及目前安裝文件為準。

26 changes: 13 additions & 13 deletions scripts/check-server-api-explorer-patch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,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.527' \
'ARG SERVER_RELEASE_TAG=v1.6.528' \
SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING
require_marker "$release_dockerfile" \
'org.opencontainers.image.version="${SERVER_RELEASE_TAG}"' \
Expand Down Expand Up @@ -1059,21 +1059,21 @@ 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.527}' \
'image=${IMAGE:-pasturestack-validation/server:v1.6.528}' \
SERVER_INCREMENTAL_RELEASE_BUILD_VERSION_MISSING
require_marker "$build_script" \
'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.527}' \
'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.528}' \
SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING
require_marker "$build_script" \
'CATTLE_RANCHER_SERVER_VERSION="${server_release_tag}"' \
SERVER_INCREMENTAL_RELEASE_BUILD_RUNTIME_VERSION_MISSING
for release_engine_marker in \
'ARG ORCHESTRATION_ENGINE_RELEASE_TAG=v0.183.345' \
'ARG ORCHESTRATION_ENGINE_RELEASE_TAG=v0.183.346' \
'ARG ORCHESTRATION_ENGINE_ARTIFACT=cattle.jar' \
'ARG ORCHESTRATION_ENGINE_ARTIFACT_SHA256=780263c4a884527fa80a28b998ad4bda88b9ad6002a687f9f074602ecad46e62' \
'ARG ORCHESTRATION_ENGINE_COMMIT=d27d4ac73fa05ae43b9ae0c32875780e8a3765b1' \
'ARG ORCHESTRATION_ENGINE_ARTIFACT_SHA256=9deeda5758b7f04135441a203092dd0308d90b65d25037b62ef4f9361d3cf806' \
'ARG ORCHESTRATION_ENGINE_COMMIT=e250e4a17958216c30c1f5d0d31f7b6418a968d5' \
'COPY --from=release_artifacts /out/orchestration-engine.jar /tmp/orchestration-engine.jar' \
'ARG ORCHESTRATION_ENGINE_VERSION=0.183.345' \
'ARG ORCHESTRATION_ENGINE_VERSION=0.183.346' \
'grep -Fx "Implementation-Version: ${ORCHESTRATION_ENGINE_VERSION}"' \
'cattle-resources-${ORCHESTRATION_ENGINE_VERSION}.jar' \
'cattle-app-config-${ORCHESTRATION_ENGINE_VERSION}.jar' \
Expand All @@ -1094,10 +1094,10 @@ for release_engine_marker in \
SERVER_INCREMENTAL_ENGINE_REPLACEMENT_MISSING
done
for release_engine_build_marker in \
'orchestration_engine_release_tag=${ORCHESTRATION_ENGINE_RELEASE_TAG:-v0.183.345}' \
'orchestration_engine_release_tag=${ORCHESTRATION_ENGINE_RELEASE_TAG:-v0.183.346}' \
'orchestration_engine_artifact=${ORCHESTRATION_ENGINE_ARTIFACT:-cattle.jar}' \
'orchestration_engine_artifact_sha256=${ORCHESTRATION_ENGINE_ARTIFACT_SHA256:-780263c4a884527fa80a28b998ad4bda88b9ad6002a687f9f074602ecad46e62}' \
'orchestration_engine_commit=${ORCHESTRATION_ENGINE_COMMIT:-d27d4ac73fa05ae43b9ae0c32875780e8a3765b1}' \
'orchestration_engine_artifact_sha256=${ORCHESTRATION_ENGINE_ARTIFACT_SHA256:-9deeda5758b7f04135441a203092dd0308d90b65d25037b62ef4f9361d3cf806}' \
'orchestration_engine_commit=${ORCHESTRATION_ENGINE_COMMIT:-e250e4a17958216c30c1f5d0d31f7b6418a968d5}' \
'CATTLE_CATTLE_VERSION="${orchestration_engine_release_tag}"' \
'cattle-resources-${ORCHESTRATION_ENGINE_VERSION}.jar' \
'test "${hazelcast_entry}" = "WEB-INF/lib/hazelcast-5.7.5.jar"'; do
Expand Down Expand Up @@ -2146,7 +2146,7 @@ done

jq -e '
.["@context"] == "https://openvex.dev/ns/v0.2.0"
and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.527"
and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.528"
and (.statements | length) == 51
and ([.statements[].vulnerability.name] | length == (unique | length))
and ([.statements[] | select(.status == "fixed") | .vulnerability.name] | sort)
Expand All @@ -2172,7 +2172,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.527 >/dev/null
"$vendor_pending_fixture" v1.6.528 >/dev/null
bash scripts/test-vendor-pending-findings.sh >/dev/null
rm -f "$vendor_pending_fixture"
trap - EXIT
Expand Down Expand Up @@ -2261,4 +2261,4 @@ for release_readback_contract in \
fi
done

printf 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.527 base=v1.6.460 engine=0.183.345 web_console=1.6.183 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.7 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.528 base=v1.6.460 engine=0.183.346 web_console=1.6.183 catalog_service=0.20.13 webhook_automation_service=0.10.4 authentication_service=0.4.43 curl=8.18.0-1ubuntu2.7 freemarker=2.3.35 artifact_scan=required vendor_pending=exact-set role_matrix=qa-required locale_layout=qa-required\n'
70 changes: 45 additions & 25 deletions scripts/test-current-server-packaging-contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@
WEB_SHA = '8540758ad4521f901f53fc79473570cf98862add2addcb49271d8dbf125b4217'
WEB_SOURCE = 'e056a0111d20816742eff17a65dfabb5d003dae2'
CATALOG_COMMIT = 'b6b658888fce50d3ec217eb4eba0f26ab0113baf'
ENGINE_SHA = '780263c4a884527fa80a28b998ad4bda88b9ad6002a687f9f074602ecad46e62'
ENGINE_SOURCE = 'd27d4ac73fa05ae43b9ae0c32875780e8a3765b1'
ENGINE_SHA = '9deeda5758b7f04135441a203092dd0308d90b65d25037b62ef4f9361d3cf806'
ENGINE_SOURCE = 'e250e4a17958216c30c1f5d0d31f7b6418a968d5'
OLD_COORDINATES = {
'v1.6.527': 'v1.6.521',
'v1.6.528': 'v1.6.521',
'1.6.183': '1.6.181',
WEB_SHA: '9199681f2c4311f3fbe8727fcf0f6fa136c9bafe9fbe9d13878c55df442a7a03',
WEB_SOURCE: '7f2bdad0c90a3241693c2ddd4475202ababba550',
CATALOG_COMMIT: '7670ffd81d5f0b5570197fb03c7e55b46da45bf3',
}
# Engine345 and Web183 use independently read-back official release identities.
# Engine346 and Web183 use independently read-back official release identities.
# Published521 component values remain mutation controls.
# Component coordinates do not establish Server527 artifact/runtime PASS.
# Component coordinates do not establish Server528 artifact/runtime PASS.
CATALOG_FIELDS = (
('VERSION', 'version', '0.20.13'),
('COMMIT', 'commit', '4c39c73a8131ba06e9ff0aaec3b95cc27e049324'),
Expand All @@ -41,13 +41,13 @@
('LICENSE_SHA256', 'license_sha256', '0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594'),
)
LEGACY_ENGINE_COORDINATES = {
'0.183.345': '0.183.337',
'0.183.346': '0.183.337',
ENGINE_SHA: '7e45189f2b57097efc7929c04ddf7767aebbe027d1b9f90023aa6711522c5c80',
ENGINE_SOURCE: 'ba041fe312dfe97fc1e5144af576ddcf1b573d8e',
}
EXPECTED = {
COMPATIBILITY_CODE: (COMPATIBILITY, PUBLISHED_508),
'SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING': (DOCKER, 'ARG SERVER_RELEASE_TAG=v1.6.527'),
'SERVER_INCREMENTAL_RELEASE_DEFAULT_MISSING': (DOCKER, 'ARG SERVER_RELEASE_TAG=v1.6.528'),
'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.183'),
Expand All @@ -58,8 +58,8 @@
'SERVER_INCREMENTAL_WEB_CONSOLE_BUILD_VERSION_MISSING': (BUILD, 'web_console_release_tag=${WEB_CONSOLE_RELEASE_TAG:-1.6.183}'),
'SERVER_INCREMENTAL_WEB_CONSOLE_BUILD_ARTIFACT_MISSING': (BUILD, 'web_console_artifact=${WEB_CONSOLE_ARTIFACT:-web-console-1.6.183.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.527}'),
'SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING': (BUILD, 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.527}'),
'SERVER_INCREMENTAL_RELEASE_BUILD_VERSION_MISSING': (BUILD, 'image=${IMAGE:-pasturestack-validation/server:v1.6.528}'),
'SERVER_INCREMENTAL_RELEASE_BUILD_DEFAULT_MISSING': (BUILD, 'server_release_tag=${SERVER_RELEASE_TAG:-v1.6.528}'),
'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'),
Expand All @@ -80,18 +80,18 @@
CREATE_RESPONSE_CODES = ['SERVER_WEB_CREATE_IDENTITY_BUILD_GATE_MISSING','SERVER_WEB_CANONICAL_RECORD_BUILD_GATE_MISSING','SERVER_WEB_CREATE_IDENTITY_RUNTIME_GATE_MISSING','SERVER_WEB_CANONICAL_RECORD_RUNTIME_GATE_MISSING']
ENGINE_EXPECTED = {
'SERVER_INCREMENTAL_ENGINE_REPLACEMENT_MISSING': (DOCKER, 'release_engine_marker', (
'ARG ORCHESTRATION_ENGINE_RELEASE_TAG=v0.183.345',
'ARG ORCHESTRATION_ENGINE_RELEASE_TAG=v0.183.346',
'ARG ORCHESTRATION_ENGINE_ARTIFACT=cattle.jar',
'ARG ORCHESTRATION_ENGINE_ARTIFACT_SHA256=' + ENGINE_SHA,
'ARG ORCHESTRATION_ENGINE_COMMIT=' + ENGINE_SOURCE,
'ARG ORCHESTRATION_ENGINE_VERSION=0.183.345',
'ARG ORCHESTRATION_ENGINE_VERSION=0.183.346',
'grep -Fx "Implementation-Version: ${ORCHESTRATION_ENGINE_VERSION}"',
'cattle-resources-${ORCHESTRATION_ENGINE_VERSION}.jar',
'cattle-app-config-${ORCHESTRATION_ENGINE_VERSION}.jar',
'ENV CATTLE_CATTLE_VERSION=${ORCHESTRATION_ENGINE_RELEASE_TAG}',
)),
'SERVER_INCREMENTAL_ENGINE_BUILD_COORDINATE_MISSING': (BUILD, 'release_engine_build_marker', (
'orchestration_engine_release_tag=${ORCHESTRATION_ENGINE_RELEASE_TAG:-v0.183.345}',
'orchestration_engine_release_tag=${ORCHESTRATION_ENGINE_RELEASE_TAG:-v0.183.346}',
'orchestration_engine_artifact=${ORCHESTRATION_ENGINE_ARTIFACT:-cattle.jar}',
'orchestration_engine_artifact_sha256=${ORCHESTRATION_ENGINE_ARTIFACT_SHA256:-' + ENGINE_SHA + '}',
'orchestration_engine_commit=${ORCHESTRATION_ENGINE_COMMIT:-' + ENGINE_SOURCE + '}',
Expand Down Expand Up @@ -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.527"' not in gate:
if 'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.528"' not in gate:
raise AssertionError('CURRENT_VEX_GATE_PIN_MISMATCH')
if '"$vendor_pending_fixture" v1.6.527 >/dev/null' not in gate:
if '"$vendor_pending_fixture" v1.6.528 >/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.527':
if json.loads(files[VEX]).get('@id') != 'https://github.com/PastureStack/server/security/openvex/v1.6.528':
raise AssertionError('CURRENT_VEX_RELEASE_MISMATCH')
if json.loads(files[VENDOR]).get('release') != 'v1.6.527':
if json.loads(files[VENDOR]).get('release') != 'v1.6.528':
raise AssertionError('CURRENT_VENDOR_RELEASE_MISMATCH')
if 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.527 base=v1.6.460 engine=0.183.345 web_console=1.6.183 catalog_service=0.20.13 ' not in gate:
if 'SERVER_API_EXPLORER_PATCH_OK release=v1.6.528 base=v1.6.460 engine=0.183.346 web_console=1.6.183 catalog_service=0.20.13 ' not in gate:
raise AssertionError('CURRENT_SUMMARY_MISMATCH')
verify_incremental_contract(files, gate)

Expand All @@ -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.527"':
'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.528"':
'and .["@id"] == "https://github.com/PastureStack/server/security/openvex/v1.6.521"',
'"$vendor_pending_fixture" v1.6.527 >/dev/null':
'"$vendor_pending_fixture" v1.6.528 >/dev/null':
'"$vendor_pending_fixture" v1.6.521 >/dev/null',
'SERVER_API_EXPLORER_PATCH_OK release=v1.6.527 base=v1.6.460 engine=0.183.345 web_console=1.6.183 catalog_service=0.20.13 ':
'SERVER_API_EXPLORER_PATCH_OK release=v1.6.528 base=v1.6.460 engine=0.183.346 web_console=1.6.183 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():
Expand Down Expand Up @@ -936,7 +936,7 @@ def test_each_old_engine_coordinate_rejected(self):
self.assertGreater(checked, 0)

def test_historical_engine340_cannot_be_packaged(self):
old = {'0.183.345': '0.183.340',
old = {'0.183.346': '0.183.340',
ENGINE_SHA: '5e5a1b908b43bf3824fc3bb2108bd661cd5199ce9bcfd187e0b18b5608a38cea',
ENGINE_SOURCE: 'ff0a41e7676211043eb4f755a306a9e2a19abee1'}
checked = 0
Expand All @@ -957,7 +957,7 @@ def test_historical_engine340_cannot_be_packaged(self):


def test_immediately_previous_engine341_cannot_be_packaged(self):
old = {'0.183.345': '0.183.341',
old = {'0.183.346': '0.183.341',
ENGINE_SHA: '3ede1ad28b7a7e0754c4c953bd486162f7ffe0b2f76ce384ec485632af6b8e6d',
ENGINE_SOURCE: 'b245cf778479445ded0786d3898b03fea153212e'}
checked = 0
Expand All @@ -978,7 +978,7 @@ def test_immediately_previous_engine341_cannot_be_packaged(self):


def test_immediately_previous_engine342_cannot_be_packaged(self):
old = {'0.183.345': '0.183.342',
old = {'0.183.346': '0.183.342',
ENGINE_SHA: '3533f247392795329c92516a7966510aafbe81a52e3f922e5ec657a2071363b5',
ENGINE_SOURCE: 'ddae4bb8e12806f70816f5782cd999eccd0f2ce6'}
checked = 0
Expand All @@ -999,7 +999,7 @@ def test_immediately_previous_engine342_cannot_be_packaged(self):


def test_immediately_previous_engine343_cannot_be_packaged(self):
old = {'0.183.345': '0.183.343',
old = {'0.183.346': '0.183.343',
ENGINE_SHA: 'b29c0057f96dbae38bfe2c663c63bbe4c8b5c755b3090f39414aa51f9813025f',
ENGINE_SOURCE: '5aa9d8978c75a7fe63330453c399a92716d88568'}
checked = 0
Expand All @@ -1020,7 +1020,7 @@ def test_immediately_previous_engine343_cannot_be_packaged(self):


def test_immediately_previous_engine344_cannot_be_packaged(self):
old = {'0.183.345': '0.183.344',
old = {'0.183.346': '0.183.344',
ENGINE_SHA: 'ffafa4700156b74ec11bcae1b830738e49943f1a3b8b0565895ed6d7726eebf1',
ENGINE_SOURCE: '72c42e6f2000301fe03ffd2442fb9ee89aee120c'}
checked = 0
Expand All @@ -1039,6 +1039,26 @@ def test_immediately_previous_engine344_cannot_be_packaged(self):
verify(files)
self.assertGreater(checked, 0)

def test_immediately_previous_engine345_cannot_be_packaged(self):
old = {'0.183.346': '0.183.345',
ENGINE_SHA: '780263c4a884527fa80a28b998ad4bda88b9ad6002a687f9f074602ecad46e62',
ENGINE_SOURCE: 'd27d4ac73fa05ae43b9ae0c32875780e8a3765b1'}
checked = 0
for code, (name, _, markers) in ENGINE_EXPECTED.items():
for marker in markers:
previous = marker
for current, stale_value in old.items():
previous = previous.replace(current, stale_value)
if previous == marker:
continue
checked += 1
with self.subTest(name=name, marker=marker):
files = dict(FILES)
files[name] = files[name].replace(marker, previous)
with self.assertRaisesRegex(AssertionError, code):
verify(files)
self.assertGreater(checked, 0)

def test_previous_fixture_rejects_stale_web179_pins(self):
gate = previous_gate()
for code, (_, marker) in EXPECTED.items():
Expand Down
Loading