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
12 changes: 8 additions & 4 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
env:
DAPPER_IMAGE: pasturestack/compose-cli-dapper:${{ github.sha }}
TRIVY_IMAGE: aquasec/trivy:0.74.0@sha256:62b1e65e8869bc4b4c6aa4fa2b21595256c7c2f6018a9d9ad61caf87187c1969
VERSION_OVERRIDE: 0.14.35
VERSION_OVERRIDE: 0.14.36
PLATFORM_COMPAT_JAR_URL: https://github.com/PastureStack/orchestration-engine/releases/download/v0.183.281/orchestration-engine-0.183.281.jar
PLATFORM_COMPAT_JAR_SHA256: da2a8a51562ed16e296f7e29e99482bb44042ff0834cca679bbe01d951ba1682

Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:
}

run_ci
artifact="dist/artifacts/compose-executor-0.14.35-linux-amd64.gz"
artifact="dist/artifacts/compose-executor-0.14.36-linux-amd64.gz"
test -s "$artifact"
cp "$artifact" /tmp/compose-executor-first.gz

Expand All @@ -81,8 +81,12 @@ jobs:
mkdir -p evidence/product
gzip -cd "$artifact" > evidence/product/compose-executor
chmod +x evidence/product/compose-executor
evidence/product/compose-executor --version | grep -F '0.14.35' >/dev/null
sha256sum "$artifact" > evidence/compose-executor.gz.sha256
evidence/product/compose-executor --version | grep -F '0.14.36' >/dev/null
cp "$artifact" evidence/
(
cd evidence
sha256sum "$(basename "$artifact")" > compose-executor.gz.sha256
)
docker run --rm --entrypoint go \
--volume "$PWD:/work:ro" \
"$DAPPER_IMAGE" \
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ RUN set -eux; \
| while IFS= read -r certificate; do sed -e '$a\' "${certificate}"; done \
> /etc/ssl/certs/ca-certificates.crt; \
test -s /etc/ssl/certs/ca-certificates.crt; \
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/%s\nSuites: resolute resolute-updates resolute-backports resolute-security\nComponents: main universe restricted multiverse\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
"${UBUNTU_APT_SNAPSHOT}" > /etc/apt/sources.list.d/pasturestack-snapshot.sources; \
printf 'Types: deb\nURIs: https://archive.ubuntu.com/ubuntu\nSuites: resolute resolute-updates resolute-backports\nComponents: main universe restricted multiverse\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n\nTypes: deb\nURIs: https://security.ubuntu.com/ubuntu\nSuites: resolute-security\nComponents: main universe restricted multiverse\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
> /etc/apt/sources.list.d/pasturestack-archive.sources; \
printf 'Acquire::Retries "5";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\nAcquire::http::Pipeline-Depth "0";\nAcquire::https::CaInfo "/etc/ssl/certs/ca-certificates.crt";\nAcquire::https::Verify-Peer "true";\nAcquire::https::Verify-Host "true";\nAcquire::AllowInsecureRepositories "false";\nAPT::Get::AllowUnauthenticated "false";\n' > /etc/apt/apt.conf.d/80pasturestack-retries; \
apt-get update; \
apt-get install -y --no-install-recommends \
Expand All @@ -50,7 +50,7 @@ RUN set -eux; \
xz-utils="${UBUNTU_APT_XZ_UTILS_VERSION}" \
zip="${UBUNTU_APT_ZIP_VERSION}"; \
{ \
printf 'snapshot\t%s\n' "${UBUNTU_APT_SNAPSHOT}"; \
printf 'archive\tubuntu-26.04-supported-pockets\n'; \
dpkg-query -W -f='${binary:Package}\t${Version}\n' | LC_ALL=C sort; \
} > /licenses/COMPOSE-CLI-UBUNTU-APT-PACKAGES.tsv; \
apt-get clean; \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ make test
make package
```

Set `VERSION_OVERRIDE=0.14.33` for the current maintenance candidate. Packaging produces the deterministic, versioned `compose-executor-0.14.33-linux-amd64.gz` asset for a matching future `PastureStack/server` GitHub Release. The Python integration suite must run against an isolated compatible Server before integration; it must never target an operator's live control plane.
Set `VERSION_OVERRIDE=0.14.36` for the current maintenance candidate. Packaging produces the deterministic, versioned `compose-executor-0.14.36-linux-amd64.gz` asset for a matching future `PastureStack/server` GitHub Release. The Python integration suite must run against an isolated compatible Server before integration; it must never target an operator's live control plane.

The compatibility-server test requires an explicitly reviewed artifact URL through `PLATFORM_COMPAT_JAR_URL` and its exact SHA-256 through `PLATFORM_COMPAT_JAR_SHA256`; no artifact is downloaded by default. See [COMPATIBILITY.md](COMPATIBILITY.md), [SECURITY.md](SECURITY.md), and [ORIGIN.md](ORIGIN.md).

Expand Down
20 changes: 20 additions & 0 deletions config/interpolation.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,26 @@ func parseConfig(key string, data *interface{}, mapping func(string) string) err

typedData[k] = v
}
case RawService:
for k, v := range typedData {
err := parseConfig(key, &v, mapping)

if err != nil {
return err
}

typedData[k] = v
}
case map[string]interface{}:
for k, v := range typedData {
err := parseConfig(key, &v, mapping)

if err != nil {
return err
}

typedData[k] = v
}
case map[interface{}]interface{}:
for k, v := range typedData {
err := parseConfig(key, &v, mapping)
Expand Down
30 changes: 30 additions & 0 deletions config/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ func PreprocessServiceMap(serviceMap RawServiceMap) (RawServiceMap, error) {

func Preprocess(item interface{}, replaceTypes bool) interface{} {
switch typedDatas := item.(type) {
case RawService:
newMap := make(map[string]interface{}, len(typedDatas))

for key, value := range typedDatas {
newMap[key] = Preprocess(value, replaceTypes)
}
return newMap

case map[interface{}]interface{}:
newMap := make(map[interface{}]interface{})
Expand All @@ -35,6 +42,14 @@ func Preprocess(item interface{}, replaceTypes bool) interface{} {
}
return newMap

case map[string]interface{}:
newMap := make(map[string]interface{}, len(typedDatas))

for key, value := range typedDatas {
newMap[key] = Preprocess(value, replaceTypes)
}
return newMap

case []interface{}:
newArray := make([]interface{}, 0, len(typedDatas))

Expand Down Expand Up @@ -72,6 +87,13 @@ func TryConvertStringsToInts(serviceMap RawServiceMap, fields map[string]bool) (

func tryConvertStringsToInts(item interface{}, replaceTypes bool) interface{} {
switch typedDatas := item.(type) {
case RawService:
newMap := make(map[string]interface{}, len(typedDatas))

for key, value := range typedDatas {
newMap[key] = tryConvertStringsToInts(value, replaceTypes)
}
return newMap

case map[interface{}]interface{}:
newMap := make(map[interface{}]interface{})
Expand All @@ -81,6 +103,14 @@ func tryConvertStringsToInts(item interface{}, replaceTypes bool) interface{} {
}
return newMap

case map[string]interface{}:
newMap := make(map[string]interface{}, len(typedDatas))

for key, value := range typedDatas {
newMap[key] = tryConvertStringsToInts(value, replaceTypes)
}
return newMap

case []interface{}:
newArray := make([]interface{}, 0, len(typedDatas))

Expand Down
44 changes: 44 additions & 0 deletions config/yaml_v3_mapping_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package config_test

import (
"reflect"
"sort"
"testing"

"github.com/PastureStack/compose-cli/lookup"
)

func TestYAMLV3MappingsRemainStructuredDuringPreprocessing(t *testing.T) {
compose := []byte(`version: '2'
services:
app:
image: example
environment:
ENABLED: true
RETRIES: 3
labels:
io.example.enabled: true
io.example.retries: 3
`)

parsed, err := mergeWithResourceLookup(compose, "", lookup.NewFileResourceLookup())
if err != nil {
t.Fatal(err)
}

app := parsed.Services["app"]
wantEnvironment := []string{"ENABLED=true", "RETRIES=3"}
gotEnvironment := []string(app.Environment)
sort.Strings(gotEnvironment)
if !reflect.DeepEqual(gotEnvironment, wantEnvironment) {
t.Fatalf("unexpected environment: got %#v want %#v", app.Environment, wantEnvironment)
}

wantLabels := map[string]string{
"io.example.enabled": "true",
"io.example.retries": "3",
}
if !reflect.DeepEqual(map[string]string(app.Labels), wantLabels) {
t.Fatalf("unexpected labels: got %#v want %#v", app.Labels, wantLabels)
}
}
10 changes: 10 additions & 0 deletions docs/releases/compose-executor-0.14.36.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Compose Executor v0.14.36

Preserve mapping-style `environment` and `labels` values after the YAML v3
parser migration. Nested service maps are now preprocessed and interpolated as
structured values instead of being flattened into a single Go string.

This restores stack create and upgrade requests that use object-form
environment variables or labels, including the PastureStack infrastructure
catalog templates. List-form values and the hardware options added in v0.14.35
remain unchanged.
4 changes: 2 additions & 2 deletions scripts/check-pasturestack-source
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ require_line Dockerfile.dapper 'ARG GO_SHA256_amd64=675c26c449cbb18fc24b74650de1
require_line Dockerfile.dapper 'ARG GO_SHA256_arm64=51798d2c42d0e1c6ed7fd9f48728b4193abac9e8aad6dbac2fe96a81f5909bda'
require_line Dockerfile.dapper ' GO111MODULE=on \'
require_line Dockerfile.dapper ' GOFLAGS=-mod=vendor \'
require_line Dockerfile.dapper " printf 'Types: deb\\nURIs: https://archive.ubuntu.com/ubuntu\\nSuites: resolute resolute-updates resolute-backports\\nComponents: main universe restricted multiverse\\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\\nSnapshot: no\\n\\nTypes: deb\\nURIs: https://security.ubuntu.com/ubuntu\\nSuites: resolute-security\\nComponents: main universe restricted multiverse\\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\\nSnapshot: no\\n' \\"
require_line go.mod 'go 1.26.0'
require_line go.mod 'toolchain go1.27.0'
require_line go.mod $'\tgithub.com/aws/aws-sdk-go-v2 v1.43.8'
Expand All @@ -54,7 +55,6 @@ require_line vendor/modules.txt '# github.com/aws/aws-sdk-go-v2 v1.43.8'
require_line vendor/modules.txt '# github.com/moby/moby/api v1.55.0'
require_line security/openvex.json ' "name": "GO-2026-5932"'
require_line security/openvex.json ' "justification": "vulnerable_code_not_present",'
require_line ubuntu-apt.lock "UBUNTU_APT_SNAPSHOT='20260825T000000Z'"
require_line ubuntu-apt.lock "UBUNTU_APT_GCC_VERSION='4:15.2.0-5ubuntu1'"
require_line .python-version '3.14.7'
require_line tests/integration/requirements.txt 'pytest==9.1.1'
Expand Down Expand Up @@ -109,4 +109,4 @@ fi
require_line README.md 'PastureStack is an independent community effort to preserve, audit, and modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by Rancher Labs or SUSE.'
require_line ORIGIN.md '- Migration model: unchanged upstream history followed by one PastureStack maintenance commit'

printf 'PASTURESTACK_COMPOSE_SOURCE_GATE_OK modules=vendor aws_sdk=v2 moby_api=1.55.0 archived_go_dependencies=absent system_images=ghcr local_resource_boundary=root_scoped unused_docker_cli=absent ubuntu=26.04 apt_snapshot=20260825 language_floor=1.26.0 toolchain=1.27.0 python=3.14.7\n'
printf 'PASTURESTACK_COMPOSE_SOURCE_GATE_OK modules=vendor aws_sdk=v2 moby_api=1.55.0 archived_go_dependencies=absent system_images=ghcr local_resource_boundary=root_scoped unused_docker_cli=absent ubuntu=26.04 apt_direct_versions=locked language_floor=1.26.0 toolchain=1.27.0 python=3.14.7\n'
6 changes: 2 additions & 4 deletions ubuntu-apt.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Ubuntu 26.04 package lock for reproducible PastureStack builds.
# Refresh the snapshot and every exact direct-package version together.

UBUNTU_APT_SNAPSHOT='20260825T000000Z'
# Ubuntu 26.04 direct-package lock for reproducible PastureStack builds.
# Refresh every exact version together after validating the supported pockets.

UBUNTU_APT_BASH_VERSION='5.3-2ubuntu1'
UBUNTU_APT_CA_CERTIFICATES_VERSION='20260601~26.04.1'
Expand Down
Loading