diff --git a/.github/workflows/build_images.yaml b/.github/workflows/build_images.yaml index c1b4135..ef9c409 100644 --- a/.github/workflows/build_images.yaml +++ b/.github/workflows/build_images.yaml @@ -54,27 +54,27 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Setup QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 - name: Install cosign - uses: sigstore/cosign-installer@v3 + uses: sigstore/cosign-installer@7e8b541eb2e61bf99390e1afd4be13a184e9ebc5 # v3.10.1 - name: Setup Docker Buildx run: | make buildx-init - name: Login to GitHub Container Registry - uses: docker/login-action@v3.4.0 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: '3.x' diff --git a/.github/workflows/pr_test_latest.yaml b/.github/workflows/pr_test_latest.yaml index d125197..802dd0a 100644 --- a/.github/workflows/pr_test_latest.yaml +++ b/.github/workflows/pr_test_latest.yaml @@ -27,10 +27,10 @@ jobs: tags: ${{ steps.get-tags.outputs.tags }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: '3.x' @@ -109,12 +109,12 @@ jobs: matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: - go-version: '1.23' + go-version: '1.25' cache-dependency-path: tests/go.sum - name: Pull image diff --git a/.github/workflows/test_images.yaml b/.github/workflows/test_images.yaml index d3385fc..ff3eab5 100644 --- a/.github/workflows/test_images.yaml +++ b/.github/workflows/test_images.yaml @@ -94,12 +94,12 @@ jobs: matrix: ${{ fromJson(needs.setup.outputs.matrix) }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: - go-version: '1.23' + go-version: '1.25' cache-dependency-path: tests/go.sum - name: Pull image diff --git a/.gitignore b/.gitignore index facf609..44b7acb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,9 @@ .vscode .DS_Store +# Python +__pycache__/ + +# Go binaries +tests/tests + diff --git a/packagelists/amd64/pg16.13-spock5.0.6-standard.txt b/packagelists/amd64/pg16.13-spock5.0.6-standard.txt index d5a4b99..79466cc 100644 --- a/packagelists/amd64/pg16.13-spock5.0.6-standard.txt +++ b/packagelists/amd64/pg16.13-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_16-1.2.2-1.el9 pgedge-pgaudit_16-16.1-1.el9 pgedge-postgis35_16-3.5.5-1.el9 pgedge-pgvector_16-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_16-1.8.0-1.el9 pgedge-pg_cron_16-1.6.7-1.el9 diff --git a/packagelists/amd64/pg17.9-spock5.0.6-standard.txt b/packagelists/amd64/pg17.9-spock5.0.6-standard.txt index 1d2ac26..38156f3 100644 --- a/packagelists/amd64/pg17.9-spock5.0.6-standard.txt +++ b/packagelists/amd64/pg17.9-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_17-1.2.2-1.el9 pgedge-pgaudit_17-17.1-1.el9 pgedge-postgis35_17-3.5.5-1.el9 pgedge-pgvector_17-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_17-1.8.0-1.el9 pgedge-pg_cron_17-1.6.7-1.el9 diff --git a/packagelists/amd64/pg18.3-spock5.0.6-standard.txt b/packagelists/amd64/pg18.3-spock5.0.6-standard.txt index ccb2f1b..be69508 100644 --- a/packagelists/amd64/pg18.3-spock5.0.6-standard.txt +++ b/packagelists/amd64/pg18.3-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_18-1.2.2-1.el9 pgedge-pgaudit_18-18.0-1.el9 pgedge-postgis35_18-3.5.5-1.el9 pgedge-pgvector_18-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_18-1.8.0-1.el9 pgedge-pg_cron_18-1.6.7-1.el9 diff --git a/packagelists/arm64/pg16.13-spock5.0.6-standard.txt b/packagelists/arm64/pg16.13-spock5.0.6-standard.txt index d5a4b99..79466cc 100644 --- a/packagelists/arm64/pg16.13-spock5.0.6-standard.txt +++ b/packagelists/arm64/pg16.13-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_16-1.2.2-1.el9 pgedge-pgaudit_16-16.1-1.el9 pgedge-postgis35_16-3.5.5-1.el9 pgedge-pgvector_16-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_16-1.8.0-1.el9 pgedge-pg_cron_16-1.6.7-1.el9 diff --git a/packagelists/arm64/pg17.9-spock5.0.6-standard.txt b/packagelists/arm64/pg17.9-spock5.0.6-standard.txt index 1d2ac26..38156f3 100644 --- a/packagelists/arm64/pg17.9-spock5.0.6-standard.txt +++ b/packagelists/arm64/pg17.9-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_17-1.2.2-1.el9 pgedge-pgaudit_17-17.1-1.el9 pgedge-postgis35_17-3.5.5-1.el9 pgedge-pgvector_17-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_17-1.8.0-1.el9 pgedge-pg_cron_17-1.6.7-1.el9 diff --git a/packagelists/arm64/pg18.3-spock5.0.6-standard.txt b/packagelists/arm64/pg18.3-spock5.0.6-standard.txt index ccb2f1b..be69508 100644 --- a/packagelists/arm64/pg18.3-spock5.0.6-standard.txt +++ b/packagelists/arm64/pg18.3-spock5.0.6-standard.txt @@ -5,7 +5,7 @@ pgedge-lolor_18-1.2.2-1.el9 pgedge-pgaudit_18-18.0-1.el9 pgedge-postgis35_18-3.5.5-1.el9 pgedge-pgvector_18-0.8.1-1.el9 -pgedge-pgbackrest-2.57.0-1.el9 +pgedge-pgbackrest-2.58.0-1.el9 pgedge-python3-psycopg2-2.9.10-1.el9 pgedge-pgmq_18-1.8.0-1.el9 pgedge-pg_cron_18-1.6.7-1.el9 diff --git a/scripts/build_pgedge_images.py b/scripts/build_pgedge_images.py index b28eaab..6ceb2e7 100755 --- a/scripts/build_pgedge_images.py +++ b/scripts/build_pgedge_images.py @@ -163,7 +163,7 @@ def make_all_flavor_images( *make_all_flavor_images( postgres_version="16.13", spock_version="5.0.6", - epoch=1, + epoch=2, is_latest_for_pg_major=True, is_latest_for_spock_major=True, ), @@ -171,7 +171,7 @@ def make_all_flavor_images( *make_all_flavor_images( postgres_version="17.9", spock_version="5.0.6", - epoch=1, + epoch=2, is_latest_for_pg_major=True, is_latest_for_spock_major=True, ), @@ -179,7 +179,7 @@ def make_all_flavor_images( *make_all_flavor_images( postgres_version="18.3", spock_version="5.0.6", - epoch=1, + epoch=2, is_latest_for_pg_major=True, is_latest_for_spock_major=True, ), @@ -252,10 +252,10 @@ def build( if no_cache: bake_args.append("--no-cache") if only_arch: - bake_args.extend(("--set", f"default.platforms=linux/{only_arch}")) + bake_args.extend(("--set", f"default.platform=linux/{only_arch}")) subprocess.check_output( - bake_cmd("--push"), + bake_cmd(*bake_args), env={ **os.environ.copy(), "PACKAGE_RELEASE_CHANNEL": image.package_release_channel, @@ -297,6 +297,53 @@ def add_tag(repo: str, existing_tag: Tag, new_tag: Tag, dry_run: bool): ) +def _log_config(config: "Config") -> None: + if config.dry_run: + logging.info("dry run enabled. build and publish actions will be skipped.") + if config.republish: + logging.info("republish enabled. images will be republished.") + if config.no_cache: + logging.info("no cache enabled. images will be built without cache.") + if config.only_postgres_version: + logging.info(f"only postgres {config.only_postgres_version} enabled. other images will be skipped.") + if config.only_spock_version: + logging.info(f"only spock {config.only_spock_version} enabled. other images will be skipped.") + if config.only_arch: + logging.info(f"only arch {config.only_arch} enabled. builds will target linux/{config.only_arch} only.") + + +def _should_skip_image(image: "PgEdgeImage", config: "Config") -> bool: + if config.only_postgres_version and image.postgres_version != config.only_postgres_version: + return True + if config.only_spock_version and image.spock_version != config.only_spock_version: + return True + return False + + +def _process_extra_tags(config: "Config", image: "PgEdgeImage", published: set) -> None: + for tag in image.extra_tags: + tag_published = published_digests(config.repo, tag) + if config.republish or tag_published != published: + add_tag(repo=config.repo, existing_tag=image.build_tag, new_tag=tag, dry_run=config.dry_run) + else: + logging.info(f"{tag} is already up-to-date") + + +def _process_image(config: "Config", image: "PgEdgeImage") -> None: + published = published_digests(config.repo, image.build_tag) + if len(published) == 0 or config.republish: + build(repo=config.repo, image=image, dry_run=config.dry_run, no_cache=config.no_cache, only_arch=config.only_arch) + if not config.dry_run: + digest = index_digest(config.repo, image.build_tag) + sign(repo=config.repo, digest=digest, dry_run=config.dry_run) + published = published_digests(config.repo, image.build_tag) + else: + logging.info("dry run enabled; skipping digest lookup and signing") + else: + logging.info(f"{image.build_tag} is already published") + _process_extra_tags(config, image, published) + + def main(): logging.basicConfig( level=logging.INFO, @@ -305,84 +352,18 @@ def main(): config = Config.from_env() - # If list_latest_tags is enabled, output tags and exit if config.list_latest_tags: - tags = get_latest_tags() - # Output as comma-separated list - print(",".join(tags)) + print(",".join(get_latest_tags())) return - if config.dry_run: - logging.info("dry run enabled. build and publish actions will be skipped.") - - if config.republish: - logging.info("republish enabled. images will be republished.") - - if config.no_cache: - logging.info("no cache enabled. images will be built without cache.") - - if config.only_postgres_version: - logging.info( - f"only postgres {config.only_postgres_version} enabled. other images will be skipped." - ) - - if config.only_spock_version: - logging.info( - f"only spock {config.only_spock_version} enabled. other images will be skipped." - ) - - if config.only_arch: - logging.info( - f"only arch {config.only_arch} enabled. other images will be skipped." - ) - + _log_config(config) validate_images(all_images) for image in all_images: - if ( - config.only_postgres_version - and image.postgres_version != config.only_postgres_version - ) or ( - config.only_spock_version - and image.spock_version != config.only_spock_version - ): + if _should_skip_image(image, config): logging.info(f"skipping image {image.build_tag}") continue - - published = published_digests(config.repo, image.build_tag) - if len(published) == 0 or config.republish: - build( - repo=config.repo, - image=image, - dry_run=config.dry_run, - no_cache=config.no_cache, - only_arch=config.only_arch, - ) - - id = index_digest(config.repo, image.build_tag) - sign( - repo=config.repo, - digest=id, - dry_run=config.dry_run, - ) - else: - logging.info(f"{image.build_tag} is already published") - - for tag in image.extra_tags: - tag_published = published_digests(config.repo, tag) - if ( - len(tag_published) == 0 - or not tag_published.issubset(published) - or config.republish - ): - add_tag( - repo=config.repo, - existing_tag=image.build_tag, - new_tag=tag, - dry_run=config.dry_run, - ) - else: - logging.info(f"{tag} is already up-to-date") + _process_image(config, image) def get_latest_tags() -> list[str]: diff --git a/tests/go.mod b/tests/go.mod index e8d1d7e..7a47815 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -1,17 +1,18 @@ module github.com/pgedge/postgres-images/tests -go 1.24.11 +go 1.25.8 require github.com/docker/docker v28.0.0+incompatible require ( github.com/Microsoft/go-winio v0.4.14 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -20,13 +21,14 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/sdk v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect - golang.org/x/sys v0.25.0 // indirect + go.opentelemetry.io/otel v1.40.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect + golang.org/x/sys v0.40.0 // indirect golang.org/x/time v0.14.0 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/tests/go.sum b/tests/go.sum index 04d2f73..36fc2ba 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -2,8 +2,10 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -19,18 +21,18 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -54,26 +56,28 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= +go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -83,8 +87,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -93,12 +97,12 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -109,14 +113,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/tests/main.go b/tests/main.go index d1333f9..71aca27 100644 --- a/tests/main.go +++ b/tests/main.go @@ -493,43 +493,57 @@ func (r *TestRunner) Cleanup() { } } -// parseCommand safely parses a command string into command and arguments -// This prevents command injection by avoiding shell interpretation -func parseCommand(cmd string) []string { - // Simple parser that splits on spaces while respecting single and double quotes - // This is safe for the hardcoded commands we use in tests - var args []string - var current strings.Builder - inSingleQuote := false - inDoubleQuote := false +type commandParser struct { + args []string + current strings.Builder + inSingleQuote bool + inDoubleQuote bool +} - for _, char := range cmd { - switch { - case char == '\'' && !inDoubleQuote: - inSingleQuote = !inSingleQuote - case char == '"' && !inSingleQuote: - inDoubleQuote = !inDoubleQuote - case char == ' ' && !inSingleQuote && !inDoubleQuote: - if current.Len() > 0 { - args = append(args, current.String()) - current.Reset() - } - default: - current.WriteRune(char) - } +func (p *commandParser) flush() { + if p.current.Len() > 0 { + p.args = append(p.args, p.current.String()) + p.current.Reset() } +} - // Add any remaining content after the loop - if current.Len() > 0 { - args = append(args, current.String()) +func (p *commandParser) processChar(char rune) { + switch char { + case '\'': + if !p.inDoubleQuote { + p.inSingleQuote = !p.inSingleQuote + } else { + p.current.WriteRune(char) + } + case '"': + if !p.inSingleQuote { + p.inDoubleQuote = !p.inDoubleQuote + } else { + p.current.WriteRune(char) + } + case ' ': + if p.inSingleQuote || p.inDoubleQuote { + p.current.WriteRune(char) + } else { + p.flush() + } + default: + p.current.WriteRune(char) } +} - // If no arguments were parsed, return the original command as a single argument - if len(args) == 0 { - return []string{cmd} +// parseCommand safely parses a command string into command and arguments. +// This prevents command injection by avoiding shell interpretation. +func parseCommand(cmd string) []string { + p := &commandParser{} + for _, char := range cmd { + p.processChar(char) } - - return args + p.flush() + if len(p.args) == 0 { + return nil + } + return p.args } func (r *TestRunner) exec(cmd string) (int, string, error) { @@ -545,6 +559,9 @@ func (r *TestRunner) exec(cmd string) (int, string, error) { // Parse command string safely to avoid command injection // This prevents shell interpretation of the command string cmdArgs := parseCommand(cmd) + if len(cmdArgs) == 0 { + return -1, "", fmt.Errorf("empty command") + } execID, err := r.cli.ContainerExecCreate(r.ctx, r.containerID, container.ExecOptions{ Cmd: cmdArgs, @@ -707,6 +724,10 @@ func getCommonExtensionTests() []Test { } func getStandardOnlyTests() []Test { + return append(getSystemStatsAndVectorTests(), getPostGISAuditBackrestTests()...) +} + +func getSystemStatsAndVectorTests() []Test { return []Test{ { Name: "system_stats extension can be created", @@ -748,6 +769,11 @@ func getStandardOnlyTests() []Test { return nil }, }, + } +} + +func getPostGISAuditBackrestTests() []Test { + return []Test{ { Name: "PostGIS extension can be created", StandardOnly: true,