diff --git a/deploy/.terraform.lock.hcl b/deploy/.terraform.lock.hcl index adc6db3f4..ba3d6b82a 100644 --- a/deploy/.terraform.lock.hcl +++ b/deploy/.terraform.lock.hcl @@ -6,6 +6,7 @@ provider "registry.terraform.io/hashicorp/google" { constraints = ">= 3.53.0, < 5.0.0" hashes = [ "h1:ZVDZuhYSIWhCkSuDkwFeSIJjn0/DcCxak2W/cHW4OQQ=", + "h1:aSRZcEKF2wOi/v24IA+k9J2Y7aKVV1cHi/R0V3EhxXQ=", "zh:17d60a6a6c1741cf1e09ac6731433a30950285eac88236e623ab4cbf23832ca3", "zh:1c70254c016439dbb75cab646b4beace6ceeff117c75d81f2cc27d41c312f752", "zh:35e2aa2cc7ac84ce55e05bb4de7b461b169d3582e56d3262e249ff09d64fe008", @@ -26,6 +27,7 @@ provider "registry.terraform.io/hashicorp/google-beta" { constraints = ">= 3.53.0, < 5.0.0" hashes = [ "h1:CSE8cBR85sVefrE2Kg6KT5vOb7855t158oMo+iDfL0M=", + "h1:YkCDGkP0AUZoNobLoxRnM52Pi4alYE9EFXalEu8p8E8=", "zh:40e9c7ec46955b4d79065a14185043a4ad6af8d0246715853fc5c99208b66980", "zh:5950a9ba2f96420ea5335b543e315b1a47a705f9a9abfc53c6fec52d084eddcb", "zh:5dfa98d32246a5d97e018f2b91b0e921cc6f061bc8591884f3b144f0d62f1c20", @@ -44,6 +46,7 @@ provider "registry.terraform.io/hashicorp/google-beta" { provider "registry.terraform.io/hashicorp/null" { version = "3.2.3" hashes = [ + "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", @@ -63,6 +66,7 @@ provider "registry.terraform.io/hashicorp/null" { provider "registry.terraform.io/hashicorp/random" { version = "3.7.1" hashes = [ + "h1:/qtweZW2sk0kBNiQM02RvBXmlVdI9oYqRMCyBZ8XA98=", "h1:t152MY0tQH4a8fLzTtEWx70ITd3azVOrFDn/pQblbto=", "zh:3193b89b43bf5805493e290374cdda5132578de6535f8009547c8b5d7a351585", "zh:3218320de4be943e5812ed3de995946056db86eb8d03aa3f074e0c7316599bef", @@ -82,6 +86,7 @@ provider "registry.terraform.io/hashicorp/random" { provider "registry.terraform.io/hashicorp/tls" { version = "4.0.6" hashes = [ + "h1:dYSb3V94K5dDMtrBRLPzBpkMTPn+3cXZ/kIJdtFL+2M=", "h1:n3M50qfWfRSpQV9Pwcvuse03pEizqrmYEryxKky4so4=", "zh:10de0d8af02f2e578101688fd334da3849f56ea91b0d9bd5b1f7a243417fdda8", "zh:37fc01f8b2bc9d5b055dc3e78bfd1beb7c42cfb776a4c81106e19c8911366297", diff --git a/deploy/saturn/main.tf b/deploy/saturn/main.tf index f999527c4..e5a312a1d 100644 --- a/deploy/saturn/main.tf +++ b/deploy/saturn/main.tf @@ -87,7 +87,53 @@ module "container" { "-subscription=${google_pubsub_subscription.queue.name}", "-parallel=${var.parallelism}", ] + + # Environment variables for Docker-in-Docker path translation + env = [ + { + name = "SCAFFOLD_HOST_PATH" + value = "/var/lib/saturn/scaffolds" + }, + { + name = "SCAFFOLD_CONTAINER_PATH" + value = "/scaffolds" + }, + { + name = "EXECUTION_IMAGE" + value = "${var.image}" + } + ] + + # Mount Docker socket and scaffolds directory from host + volumeMounts = [ + { + mountPath = "/var/run/docker.sock" + name = "docker-socket" + readOnly = false + }, + { + mountPath = "/scaffolds" + name = "scaffolds" + readOnly = false + } + ] } + + # Mount host Docker socket and scaffolds directory + volumes = [ + { + name = "docker-socket" + hostPath = { + path = "/var/run/docker.sock" + } + }, + { + name = "scaffolds" + hostPath = { + path = "/var/lib/saturn/scaffolds" + } + } + ] } resource "google_compute_instance_template" "this" { diff --git a/saturn/Dockerfile b/saturn/Dockerfile index 1ee15a2a5..c7e8eee15 100644 --- a/saturn/Dockerfile +++ b/saturn/Dockerfile @@ -1,5 +1,5 @@ # Build go app -FROM golang:1.23.4-bookworm AS go +FROM golang:1.25-bookworm AS go ENV BUILD_HOME /build WORKDIR $BUILD_HOME @@ -18,12 +18,12 @@ FROM eclipse-temurin:21-jdk # Setup - Install JDK8 (base image provides JDK21) # Add Ubuntu universe repository for openjdk-8 RUN apt-get update && \ - apt-get install -y software-properties-common && \ - add-apt-repository ppa:openjdk-r/ppa -y && \ - apt-get update && \ - apt-get install -y openjdk-8-jdk && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* + apt-get install -y software-properties-common && \ + add-apt-repository ppa:openjdk-r/ppa -y && \ + apt-get update && \ + apt-get install -y openjdk-8-jdk && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* # Copy Python executable, libraries, standard library, site-packages, include files, binary files, and Python path COPY --from=python /usr/local/bin/python3.12 /usr/local/bin/python3.12 @@ -36,6 +36,28 @@ ENV PYTHONPATH=/usr/local/lib/python3.12:/usr/local/lib/python3.12/site-packages # Install google cloud package for use in the scaffold RUN python3.12 -m pip install google-cloud-storage +# Install Docker CLI for containerized execution +# Note: We only install the CLI, not the daemon. Saturn will use the host's Docker daemon via socket mounting. +RUN apt-get update && \ + apt-get install -y \ + ca-certificates \ + curl \ + gnupg && \ + install -m 0755 -d /etc/apt/keyrings && \ + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \ + chmod a+r /etc/apt/keyrings/docker.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null && \ + apt-get update && \ + apt-get install -y docker-ce-cli && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# Create battlecode user for running containerized tasks +# Use UID/GID 10000 to avoid conflicts with existing system users +RUN groupadd -g 10000 battlecode && \ + useradd -u 10000 -g battlecode -m -s /bin/bash battlecode + ENV APP_HOME /app WORKDIR $APP_HOME diff --git a/saturn/Makefile b/saturn/Makefile index 3fe2800b4..dbaf1bb8c 100644 --- a/saturn/Makefile +++ b/saturn/Makefile @@ -1,4 +1,4 @@ -.PHONY: dev-fetch-secret dev-build dev-compile dev-execute dev-shell dev-shell-saturn dev-clean help +.PHONY: dev-fetch-secret dev-build dev-compile-py dev-compile-java dev-execute-py dev-execute-java dev-shell dev-shell-saturn dev-clean help .PHONY: dev-docker-up dev-docker-down dev-docker-logs dev-docker-rebuild dev-pubsub-interactive .PHONY: dev-list-runs dev-clean-runs dev-view-run @@ -9,8 +9,10 @@ help: ## Show this help message @echo ' make dev-fetch-secret # Fetch secrets from GCP' @echo ' make dev-build # Build Docker images' @echo ' make dev-docker-up # Start all services (creates new run)' - @echo ' make dev-compile # Test compilation' - @echo ' make dev-execute # Test execution' + @echo ' make dev-compile-py # Test Python compilation' + @echo ' make dev-compile-java # Test Java compilation' + @echo ' make dev-execute-py # Test Python execution' + @echo ' make dev-execute-java # Test Java execution' @echo ' make dev-pubsub-interactive # Interactive Pub/Sub client' @echo '' @echo 'Run Management:' @@ -49,7 +51,9 @@ dev-build: ## Build all Docker images @cd development && docker-compose build @echo "✓ Docker images built" -dev-compile: ## Send a compile message +# Template for compile operations +# Usage: $(call run-compile,language) +define run-compile @# Check if a run is active @if [ ! -f development/runs/latest ]; then \ echo "Error: No active run found. Start services with 'make dev-docker-up' first."; \ @@ -60,12 +64,12 @@ dev-compile: ## Send a compile message $(eval REQUEST_ID := $(shell date +%Y%m%d_%H%M%S)) @# Create request directory structure @mkdir -p development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID) - @echo "Creating compile request: compile_$(REQUEST_ID)" + @echo "Creating compile request for $(1): compile_$(REQUEST_ID)" @# Generate config from template @sed \ -e 's|{{REPORT_PATH}}|/development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID)/report.txt|g' \ -e 's|{{BINARY_PATH}}|/development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID)/binary.zip|g' \ - development/configs/compile.template.json \ + development/configs/compile-$(1).template.json \ > development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID)/config.json @echo "✓ Config generated: development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID)/config.json" @# Send compile message with generated config @@ -73,8 +77,11 @@ dev-compile: ## Send a compile message @echo "✓ Compile message sent" @echo "✓ Request ID: compile_$(REQUEST_ID)" @echo "✓ Output directory: development/runs/$(RUN_ID)/requests/compile_$(REQUEST_ID)/" +endef -dev-execute: ## Send an execute message +# Template for execute operations +# Usage: $(call run-execute,language) +define run-execute @# Check if a run is active @if [ ! -f development/runs/latest ]; then \ echo "Error: No active run found. Start services with 'make dev-docker-up' first."; \ @@ -85,12 +92,12 @@ dev-execute: ## Send an execute message $(eval REQUEST_ID := $(shell date +%Y%m%d_%H%M%S)) @# Create request directory structure @mkdir -p development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID) - @echo "Creating execute request: execute_$(REQUEST_ID)" + @echo "Creating execute request for $(1): execute_$(REQUEST_ID)" @# Generate config from template @sed \ -e 's|{{REPORT_PATH}}|/development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID)/report.txt|g' \ -e 's|{{REPLAY_PATH}}|/development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID)/replay.bc25java|g' \ - development/configs/execute.template.json \ + development/configs/execute-$(1).template.json \ > development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID)/config.json @echo "✓ Config generated: development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID)/config.json" @# Send execute message with generated config @@ -98,6 +105,19 @@ dev-execute: ## Send an execute message @echo "✓ Execute message sent" @echo "✓ Request ID: execute_$(REQUEST_ID)" @echo "✓ Output directory: development/runs/$(RUN_ID)/requests/execute_$(REQUEST_ID)/" +endef + +dev-compile-py: + $(call run-compile,py3) + +dev-compile-java: + $(call run-compile,java21) + +dev-execute-py: + $(call run-execute,py3) + +dev-execute-java: + $(call run-execute,java21) dev-shell-pubsub: ## Open shell in Pub/Sub container @docker exec -it saturn-pubsub-dev bash diff --git a/saturn/cmd/saturn/main.go b/saturn/cmd/saturn/main.go index cfd44a457..1c36e3e47 100644 --- a/saturn/cmd/saturn/main.go +++ b/saturn/cmd/saturn/main.go @@ -28,6 +28,7 @@ var ( scaffoldRoot *string = flag.String("scaffold", "/scaffolds", "the root directory for saving scaffolds") parallelism *uint = flag.Uint("parallel", 1, "the number of scaffolds to run in parallel") onSaturn *bool = flag.Bool("onsaturn", true, "run on saturn") + executionImage *string = flag.String("execution-image", os.Getenv("EXECUTION_IMAGE"), "the docker image to isolate compile/execution tasks") ) func main() { @@ -58,7 +59,7 @@ func main() { ) for i = 0; i < *parallelism; i++ { root := filepath.Join(*scaffoldRoot, strconv.FormatUint(uint64(i), 10)) - multiplexer, err := run.NewScaffoldMultiplexer(root, secret, *onSaturn) + multiplexer, err := run.NewScaffoldMultiplexer(root, secret, *onSaturn, *executionImage) if err != nil { log.Ctx(ctx).Fatal().Err(err).Msg("Could not initialize scaffold multiplexer.") } diff --git a/saturn/development/configs/bc25/compile-java21.template.json b/saturn/development/configs/bc25/compile-java21.template.json new file mode 100644 index 000000000..21c2a8d08 --- /dev/null +++ b/saturn/development/configs/bc25/compile-java21.template.json @@ -0,0 +1,23 @@ +{ + "episode": { + "name": "bc25java", + "language": "java21", + "scaffold": "https://github.com/battlecode/battlecode25-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "compile" + }, + "details": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/java21.zip" + }, + "binary": { + "bucket": "local", + "name": "{{BINARY_PATH}}" + }, + "team-name": "test", + "package": "examplefuncsplayer" + } +} diff --git a/saturn/development/configs/bc25/compile-py3.template.json b/saturn/development/configs/bc25/compile-py3.template.json new file mode 100644 index 000000000..1d3622367 --- /dev/null +++ b/saturn/development/configs/bc25/compile-py3.template.json @@ -0,0 +1,23 @@ +{ + "episode": { + "name": "bc25python", + "language": "py3", + "scaffold": "https://github.com/battlecode/battlecode25-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "compile" + }, + "details": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "{{BINARY_PATH}}" + }, + "team-name": "test", + "package": "examplefuncsplayer" + } +} diff --git a/saturn/development/configs/bc25/execute-java21.template.json b/saturn/development/configs/bc25/execute-java21.template.json new file mode 100644 index 000000000..cae1bcb18 --- /dev/null +++ b/saturn/development/configs/bc25/execute-java21.template.json @@ -0,0 +1,43 @@ +{ + "episode": { + "name": "bc25", + "language": "java21", + "scaffold": "https://github.com/battlecode/battlecode25-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "execute" + }, + "details": { + "maps": ["fix", "galaxy", "gridworld", "quack", "sierpinski"], + "replay": { + "bucket": "local", + "name": "{{REPLAY_PATH}}" + }, + "alternate-order": true, + "a": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/bc25-java21.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/bc25-java21.zip" + }, + "team-name": "test1", + "package": "examplefuncsplayer" + }, + "b": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/bc25-java21.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/bc25-java21.zip" + }, + "team-name": "test2", + "package": "examplefuncsplayer" + } + } +} diff --git a/saturn/development/configs/bc25/execute-py3.template.json b/saturn/development/configs/bc25/execute-py3.template.json new file mode 100644 index 000000000..b2c121b9e --- /dev/null +++ b/saturn/development/configs/bc25/execute-py3.template.json @@ -0,0 +1,43 @@ +{ + "episode": { + "name": "bc25python", + "language": "py3", + "scaffold": "https://github.com/battlecode/battlecode25-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "execute" + }, + "details": { + "maps": ["fix", "galaxy", "gridworld", "quack", "sierpinski"], + "replay": { + "bucket": "local", + "name": "{{REPLAY_PATH}}" + }, + "alternate-order": true, + "a": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/py3.zip" + }, + "team-name": "test1", + "package": "examplefuncsplayer" + }, + "b": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/py3.zip" + }, + "team-name": "test2", + "package": "examplefuncsplayer" + } + } +} diff --git a/saturn/development/configs/compile.template.json b/saturn/development/configs/compile-java21.template.json similarity index 87% rename from saturn/development/configs/compile.template.json rename to saturn/development/configs/compile-java21.template.json index 4a36beef6..d13a41d5b 100644 --- a/saturn/development/configs/compile.template.json +++ b/saturn/development/configs/compile-java21.template.json @@ -11,7 +11,7 @@ "details": { "source": { "bucket": "local", - "name": "/development/test-data/source/bc26-java21.zip" + "name": "/development/test-data/source/java21.zip" }, "binary": { "bucket": "local", diff --git a/saturn/development/configs/compile-py3.template.json b/saturn/development/configs/compile-py3.template.json new file mode 100644 index 000000000..24951052a --- /dev/null +++ b/saturn/development/configs/compile-py3.template.json @@ -0,0 +1,23 @@ +{ + "episode": { + "name": "bc26", + "language": "py3", + "scaffold": "https://github.com/battlecode/battlecode26-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "compile" + }, + "details": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "{{BINARY_PATH}}" + }, + "team-name": "test", + "package": "examplefuncsplayer" + } +} diff --git a/saturn/development/configs/execute.template.json b/saturn/development/configs/execute-java21.template.json similarity index 100% rename from saturn/development/configs/execute.template.json rename to saturn/development/configs/execute-java21.template.json diff --git a/saturn/development/configs/execute-py3.template.json b/saturn/development/configs/execute-py3.template.json new file mode 100644 index 000000000..1545ffba4 --- /dev/null +++ b/saturn/development/configs/execute-py3.template.json @@ -0,0 +1,43 @@ +{ + "episode": { + "name": "bc26", + "language": "py3", + "scaffold": "https://github.com/battlecode/battlecode26-scaffold" + }, + "metadata": { + "report-url": "{{REPORT_PATH}}", + "task-type": "execute" + }, + "details": { + "maps": ["DefaultSmall", "DefaultMedium", "DefaultLarge"], + "replay": { + "bucket": "local", + "name": "{{REPLAY_PATH}}" + }, + "alternate-order": true, + "a": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/py3.zip" + }, + "team-name": "test1", + "package": "examplefuncsplayer" + }, + "b": { + "source": { + "bucket": "local", + "name": "/development/test-data/source/py3.zip" + }, + "binary": { + "bucket": "local", + "name": "/development/test-data/binary/py3.zip" + }, + "team-name": "test2", + "package": "examplefuncsplayer" + } + } +} diff --git a/saturn/development/docker-compose.yml b/saturn/development/docker-compose.yml index 74fe07a5d..a5b1da5cf 100644 --- a/saturn/development/docker-compose.yml +++ b/saturn/development/docker-compose.yml @@ -30,9 +30,14 @@ services: environment: - PUBSUB_EMULATOR_HOST=pubsub-emulator:8514 - RUN_ID=${RUN_ID:-default} + - SCAFFOLD_HOST_PATH=${PWD}/${SCAFFOLD_DIR:-scaffolds} + - SCAFFOLD_CONTAINER_PATH=/scaffolds + - EXECUTION_IMAGE=development-saturn volumes: - ./:/development - ${SCAFFOLD_DIR:-./scaffolds}:/scaffolds + # Mount Docker socket for containerized execution + - /var/run/docker.sock:/var/run/docker.sock command: > -subscription=test -project=mitbattlecode diff --git a/saturn/go.mod b/saturn/go.mod index 8f6fab7b3..9f9c9c98f 100644 --- a/saturn/go.mod +++ b/saturn/go.mod @@ -1,57 +1,101 @@ module github.com/battlecode/galaxy/saturn -go 1.18 +go 1.25 require ( - cloud.google.com/go/pubsub v1.30.0 - cloud.google.com/go/secretmanager v1.10.0 - cloud.google.com/go/storage v1.28.1 + cloud.google.com/go/pubsub v1.49.0 + cloud.google.com/go/secretmanager v1.14.7 + cloud.google.com/go/storage v1.50.0 + github.com/docker/docker v27.3.1+incompatible github.com/go-git/go-git/v5 v5.11.0 github.com/mitchellh/mapstructure v1.5.0 github.com/rs/zerolog v1.28.0 - golang.org/x/sys v0.15.0 - google.golang.org/api v0.114.0 + golang.org/x/sys v0.39.0 + google.golang.org/api v0.258.0 ) require ( - cloud.google.com/go v0.110.0 // indirect - cloud.google.com/go/compute v1.19.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v0.13.0 // indirect + cel.dev/expr v0.24.0 // indirect + cloud.google.com/go v0.120.0 // indirect + cloud.google.com/go/auth v0.17.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.5.2 // indirect + cloud.google.com/go/monitoring v1.24.2 // indirect dario.cat/mergo v1.0.0 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect + github.com/containerd/log v0.1.0 // indirect + github.com/cyphar/filepath-securejoin v0.5.1 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/go-connections v0.6.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // 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/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect - github.com/googleapis/gax-go/v2 v2.7.1 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.4.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect + github.com/moby/term v0.5.2 // indirect + github.com/morikuni/aec v1.1.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/sergi/go-diff v1.1.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.2.1 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/tools v0.13.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.56.3 // indirect - google.golang.org/protobuf v1.33.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/grpc v1.77.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gotest.tools/v3 v3.5.2 // indirect ) diff --git a/saturn/go.sum b/saturn/go.sum index deb58977f..ccff6a65d 100644 --- a/saturn/go.sum +++ b/saturn/go.sum @@ -1,66 +1,130 @@ +cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= +cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/kms v1.10.1 h1:7hm1bRqGCA1GBRQUrp831TwJ9TWhP+tvLuP497CQS2g= -cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= -cloud.google.com/go/pubsub v1.30.0 h1:vCge8m7aUKBJYOgrZp7EsNDf6QMd2CAlXZqWTn3yq6s= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/secretmanager v1.10.0 h1:pu03bha7ukxF8otyPKTFdDz+rr9sE3YauS5PliDXK60= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/storage v1.28.1 h1:F5QDG5ChchaAVQhINh24U99OWHURqrW8OmQcGKXcbgI= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA= +cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= +cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= +cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= +cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= +cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk= +cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8= +cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= +cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= +cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= +cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= +cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= +cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= +cloud.google.com/go/pubsub v1.49.0 h1:5054IkbslnrMCgA2MAEPcsN3Ky+AyMpEZcii/DoySPo= +cloud.google.com/go/pubsub v1.49.0/go.mod h1:K1FswTWP+C1tI/nfi3HQecoVeFvL4HUOB1tdaNXKhUY= +cloud.google.com/go/secretmanager v1.14.7 h1:VkscIRzj7GcmZyO4z9y1EH7Xf81PcoiAo7MtlD+0O80= +cloud.google.com/go/secretmanager v1.14.7/go.mod h1:uRuB4F6NTFbg0vLQ6HsT7PSsfbY7FqHbtJP1J94qxGc= +cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs= +cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= +cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= +cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0 h1:5IT7xOdq17MtcdtL/vtl6mGfzhaq4m4vpollPRmlsBQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0 h1:nNMpRpnkWDAaqcpxMJvxa/Ud98gjbYwayJY4/9bdjiU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.50.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0 h1:ig/FpDD2JofP/NExKQUbn7uOSZzJAQqogfqluZK4ed4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.5.1 h1:eYgfMq5yryL4fbWfkLpFFy2ukSELzaJOTaUTuh+oF48= +github.com/cyphar/filepath-securejoin v0.5.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= +github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= +github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= +github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -69,95 +133,165 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +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/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/gax-go/v2 v2.7.1 h1:gF4c0zjUP2H/s/hEGyLA3I0fA2ZWjzYiONAD6cvPr8A= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +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/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +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/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= +github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= +github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= +github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +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/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ= +go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +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/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +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= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -165,18 +299,20 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -195,56 +331,62 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +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= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.114.0 h1:1xQPji6cO2E2vLiI+C/XiFAnsn1WV3mjaEwGLhi3grE= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.258.0 h1:IKo1j5FBlN74fe5isA2PVozN3Y5pwNKriEgAXPOkDAc= +google.golang.org/api v0.258.0/go.mod h1:qhOMTQEZ6lUps63ZNq9jhODswwjkjYYguA7fA3TBFww= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= +google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -254,13 +396,12 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -268,5 +409,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/saturn/pkg/run/container.go b/saturn/pkg/run/container.go new file mode 100644 index 000000000..663c16daa --- /dev/null +++ b/saturn/pkg/run/container.go @@ -0,0 +1,318 @@ +package run + +import ( + "context" + "fmt" + "io" + "strings" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/api/types/mount" + "github.com/docker/docker/client" + "github.com/rs/zerolog/log" +) + +type ContainerRuntime interface { + CreateContainer(ctx context.Context, config *ContainerConfig) (string, error) + + StartContainer(ctx context.Context, containerID string) error + + ExecCommand(ctx context.Context, containerID string, env []string, name string, args ...string) (string, error) + + StopContainer(ctx context.Context, containerID string, timeoutSeconds int) error + + RemoveContainer(ctx context.Context, containerID string) error + + GetLogs(ctx context.Context, containerID string) (io.ReadCloser, error) +} + +type ContainerConfig struct { + Image string + + onSaturn bool + + WorkDir string + + NetworkMode string + + CPULimit float64 + + MemoryLimit int64 + + ReadOnlyRootFS bool + + // Mounts specifies volume mounts as host:container:mode + Mounts []string + + CapabilitiesToDrop []string + + CapabilitiesToAdd []string + + User string + + Env []string + + // Entrypoint overrides the image's ENTRYPOINT + // Use empty slice to clear the image's entrypoint + Entrypoint []string +} + +// DockerRuntime implements ContainerRuntime using the Docker API +type DockerRuntime struct { + client *client.Client +} + +func NewDockerRuntime(ctx context.Context) (*DockerRuntime, error) { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return nil, fmt.Errorf("failed to create Docker client: %w", err) + } + + // Verify Docker is accessible + _, err = cli.Ping(ctx) + if err != nil { + return nil, fmt.Errorf("failed to ping Docker daemon: %w", err) + } + + log.Ctx(ctx).Debug().Msg("Docker runtime initialized") + return &DockerRuntime{client: cli}, nil +} + +func (d *DockerRuntime) CreateContainer(ctx context.Context, config *ContainerConfig) (string, error) { + log.Ctx(ctx).Debug(). + Str("image", config.Image). + Str("network", config.NetworkMode). + Msg("Creating container") + + if err := d.ensureImage(ctx, config.Image, config.onSaturn); err != nil { + return "", fmt.Errorf("failed to ensure image: %w", err) + } + + mounts := make([]mount.Mount, 0, len(config.Mounts)) + tmpfsMounts := make(map[string]string) + for _, m := range config.Mounts { + parts := strings.Split(m, ":") + if len(parts) < 2 { + return "", fmt.Errorf("invalid mount format: %s", m) + } + + // Handle tmpfs mounts + if parts[0] == "tmpfs" { + // Format: tmpfs:/path:options + path := parts[1] + opts := "" + if len(parts) >= 3 { + opts = parts[2] + } + tmpfsMounts[path] = opts + continue + } + + // Handle bind mounts + readOnly := false + if len(parts) >= 3 && parts[2] == "ro" { + readOnly = true + } + + mounts = append(mounts, mount.Mount{ + Type: mount.TypeBind, + Source: parts[0], + Target: parts[1], + ReadOnly: readOnly, + }) + } + + containerConfig := &container.Config{ + Image: config.Image, + WorkingDir: config.WorkDir, + User: config.User, + Env: config.Env, + // Keep container running (we'll exec commands into it) + Cmd: []string{"/bin/sh", "-c", "sleep infinity"}, + Entrypoint: config.Entrypoint, + Tty: false, + OpenStdin: false, + } + + hostConfig := &container.HostConfig{ + NetworkMode: container.NetworkMode(config.NetworkMode), + Mounts: mounts, + ReadonlyRootfs: config.ReadOnlyRootFS, + SecurityOpt: []string{"no-new-privileges"}, + Resources: container.Resources{ + NanoCPUs: int64(config.CPULimit * 1e9), + Memory: config.MemoryLimit, + }, + CapDrop: config.CapabilitiesToDrop, + CapAdd: config.CapabilitiesToAdd, + } + + // Merge tmpfs mounts + if len(tmpfsMounts) > 0 || config.ReadOnlyRootFS { + if hostConfig.Tmpfs == nil { + hostConfig.Tmpfs = make(map[string]string) + } + for path, opts := range tmpfsMounts { + hostConfig.Tmpfs[path] = opts + } + } + + resp, err := d.client.ContainerCreate(ctx, containerConfig, hostConfig, nil, nil, "") + if err != nil { + return "", fmt.Errorf("failed to create container: %w", err) + } + + log.Ctx(ctx).Debug(). + Str("container_id", resp.ID[:12]). + Msg("Container created") + + return resp.ID, nil +} + +func (d *DockerRuntime) StartContainer(ctx context.Context, containerID string) error { + log.Ctx(ctx).Debug(). + Str("container_id", containerID[:12]). + Msg("Starting container") + + if err := d.client.ContainerStart(ctx, containerID, container.StartOptions{}); err != nil { + return fmt.Errorf("failed to start container: %w", err) + } + + return nil +} + +func (d *DockerRuntime) ExecCommand(ctx context.Context, containerID string, env []string, name string, args ...string) (string, error) { + cmd := append([]string{name}, args...) + + log.Ctx(ctx).Debug(). + Str("container_id", containerID[:12]). + Str("command", strings.Join(cmd, " ")). + Msg("Executing command in container") + + execConfig := container.ExecOptions{ + Cmd: cmd, + Env: env, + AttachStdout: true, + AttachStderr: true, + WorkingDir: "", // Use container's working dir + } + + execResp, err := d.client.ContainerExecCreate(ctx, containerID, execConfig) + if err != nil { + return "", fmt.Errorf("failed to create exec: %w", err) + } + + // Attach to exec to capture output + attachResp, err := d.client.ContainerExecAttach(ctx, execResp.ID, container.ExecAttachOptions{}) + if err != nil { + return "", fmt.Errorf("failed to attach to exec: %w", err) + } + defer attachResp.Close() + + // Read all output + output, err := io.ReadAll(attachResp.Reader) + if err != nil { + return "", fmt.Errorf("failed to read exec output: %w", err) + } + + // Check exit code + inspectResp, err := d.client.ContainerExecInspect(ctx, execResp.ID) + if err != nil { + return "", fmt.Errorf("failed to inspect exec: %w", err) + } + + if inspectResp.ExitCode != 0 { + return string(output), fmt.Errorf("command exited with code %d", inspectResp.ExitCode) + } + + return string(output), nil +} + +func (d *DockerRuntime) StopContainer(ctx context.Context, containerID string, timeoutSeconds int) error { + log.Ctx(ctx).Debug(). + Str("container_id", containerID[:12]). + Int("timeout", timeoutSeconds). + Msg("Stopping container") + + timeout := timeoutSeconds + if err := d.client.ContainerStop(ctx, containerID, container.StopOptions{Timeout: &timeout}); err != nil { + return fmt.Errorf("failed to stop container: %w", err) + } + + return nil +} + +func (d *DockerRuntime) RemoveContainer(ctx context.Context, containerID string) error { + log.Ctx(ctx).Debug(). + Str("container_id", containerID[:12]). + Msg("Removing container") + + if err := d.client.ContainerRemove(ctx, containerID, container.RemoveOptions{Force: true}); err != nil { + return fmt.Errorf("failed to remove container: %w", err) + } + + return nil +} + +func (d *DockerRuntime) GetLogs(ctx context.Context, containerID string) (io.ReadCloser, error) { + options := container.LogsOptions{ + ShowStdout: true, + ShowStderr: true, + Follow: false, + } + + logs, err := d.client.ContainerLogs(ctx, containerID, options) + if err != nil { + return nil, fmt.Errorf("failed to get container logs: %w", err) + } + + return logs, nil +} + +// ensureImage handles ensuring the container image is available, either by pulling or building. +func (d *DockerRuntime) ensureImage(ctx context.Context, imageName string, onSaturn bool) error { + // First, check if the image already exists locally + _, _, err := d.client.ImageInspectWithRaw(ctx, imageName) + if err == nil { + log.Ctx(ctx).Debug().Str("image", imageName).Msg("Image already exists locally") + return nil + } + + if !onSaturn { + // For local development, the imageName should be a pre-built image name + log.Ctx(ctx).Error(). + Str("image", imageName). + Msg("Image not found locally. Please run 'make dev-build' first.") + return fmt.Errorf("image %s not found locally - run 'make dev-build' to build it", imageName) + } + + // On Saturn (production), pull the image from registry + log.Ctx(ctx).Info(). + Str("image", imageName). + Msg("Pulling container image") + + reader, err := d.client.ImagePull(ctx, imageName, image.PullOptions{}) + if err != nil { + return fmt.Errorf("failed to pull image: %w", err) + } + defer reader.Close() + + // Wait for pull to complete. + if _, err := io.Copy(io.Discard, reader); err != nil { + return fmt.Errorf("failed to wait for image pull: %w", err) + } + + log.Ctx(ctx).Info(). + Str("image", imageName). + Msg("Image pulled successfully") + + return nil +} + +func (d *DockerRuntime) Close() error { + if d.client != nil { + return d.client.Close() + } + return nil +} diff --git a/saturn/pkg/run/java.go b/saturn/pkg/run/java.go index f88037a37..3f2f45559 100644 --- a/saturn/pkg/run/java.go +++ b/saturn/pkg/run/java.go @@ -21,7 +21,7 @@ type JavaScaffold struct { javaEnv []string } -func NewJavaScaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, javaPath string, onSaturn bool) (*JavaScaffold, error) { +func NewJavaScaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, javaPath string, onSaturn bool, executionImage string) (*JavaScaffold, error) { s := new(JavaScaffold) s.root = root s.repo = repo @@ -44,6 +44,7 @@ func NewJavaScaffold(ctx context.Context, episode saturn.Episode, repo *git.Repo } s.matchOutputs = make(map[*StepArguments]string) s.onSaturn = onSaturn + s.executionImage = executionImage return s, nil } @@ -64,6 +65,7 @@ func (s *JavaScaffold) Prepare() *Step { out, err := s.Scaffold.RunCommand( ctx, s.javaEnv, + "sh", "./gradlew", "update", fmt.Sprintf("-PonSaturn=%t", s.onSaturn), @@ -133,6 +135,7 @@ func (s *JavaScaffold) VerifySubmission() *Step { return &Step{ Name: "Build source code", Callable: func(ctx context.Context, arg *StepArguments) error { + defer s.cleanupContainer(ctx) pkg := arg.Details.(CompileRequest).Package if pkg == "" { log.Ctx(ctx).Debug().Msg("Package name must not be empty.") @@ -140,9 +143,10 @@ func (s *JavaScaffold) VerifySubmission() *Step { "accepted": false, }) } - out, err := s.Scaffold.RunCommand( + out, err := s.Scaffold.RunIsolatedCommand( ctx, s.javaEnv, + "sh", "./gradlew", "verify", fmt.Sprintf("-Pteam=%s", pkg), @@ -175,9 +179,11 @@ func (s *JavaScaffold) RunMatch() *Step { return &Step{ Name: "Run match", Callable: func(ctx context.Context, arg *StepArguments) error { - out, err := s.Scaffold.RunCommand( + defer s.cleanupContainer(ctx) + out, err := s.Scaffold.RunIsolatedCommand( ctx, s.javaEnv, + "sh", "./gradlew", "run", fmt.Sprintf("-PonSaturn=%t", s.onSaturn), @@ -195,7 +201,7 @@ func (s *JavaScaffold) RunMatch() *Step { ) log.Ctx(ctx).Debug().Msg(out) if err != nil { - return fmt.Errorf("RunCommand: %v", err) + return fmt.Errorf("RunIsolatedCommand: %v", err) } s.matchOutputs[arg] = out return nil diff --git a/saturn/pkg/run/python3.go b/saturn/pkg/run/python3.go index 54677c452..e95612936 100644 --- a/saturn/pkg/run/python3.go +++ b/saturn/pkg/run/python3.go @@ -21,7 +21,7 @@ type Python3Scaffold struct { var pyWinnerRegex = regexp.MustCompile(`(?m)^\[server\]\s*.*\(([AB])\) wins \(round [0-9]+\)$`) -func NewPython3Scaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, pyVersion string, onSaturn bool) (*Python3Scaffold, error) { +func NewPython3Scaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, pyVersion string, onSaturn bool, executionImage string) (*Python3Scaffold, error) { s := new(Python3Scaffold) s.root = root s.repo = repo @@ -43,6 +43,7 @@ func NewPython3Scaffold(ctx context.Context, episode saturn.Episode, repo *git.R } s.matchOutputs = make(map[*StepArguments]string) s.onSaturn = onSaturn + s.executionImage = executionImage return s, nil } @@ -119,6 +120,7 @@ func (s *Python3Scaffold) VerifySubmission() *Step { return &Step{ Name: "Build source code", Callable: func(ctx context.Context, arg *StepArguments) error { + defer s.cleanupContainer(ctx) pkg := arg.Details.(CompileRequest).Package if pkg == "" { log.Ctx(ctx).Debug().Msg("Package name must not be empty.") @@ -126,7 +128,7 @@ func (s *Python3Scaffold) VerifySubmission() *Step { "accepted": false, }) } - out, err := s.Scaffold.RunCommand( + out, err := s.Scaffold.RunIsolatedCommand( ctx, []string{}, s.pyVersion, @@ -162,7 +164,8 @@ func (s *Python3Scaffold) RunMatch() *Step { return &Step{ Name: "Run match", Callable: func(ctx context.Context, arg *StepArguments) error { - out, err := s.Scaffold.RunCommand( + defer s.cleanupContainer(ctx) + out, err := s.Scaffold.RunIsolatedCommand( ctx, []string{}, s.pyVersion, @@ -183,7 +186,7 @@ func (s *Python3Scaffold) RunMatch() *Step { ) log.Ctx(ctx).Debug().Msg(out) if err != nil { - return fmt.Errorf("RunCommand: %v", err) + return fmt.Errorf("RunIsolatedCommand: %v", err) } s.matchOutputs[arg] = out return nil diff --git a/saturn/pkg/run/scaffold.go b/saturn/pkg/run/scaffold.go index dd1acd75b..d94210d4f 100644 --- a/saturn/pkg/run/scaffold.go +++ b/saturn/pkg/run/scaffold.go @@ -19,22 +19,24 @@ import ( ) type ScaffoldMultiplexer struct { - Root string - scaffolds map[string]*Scaffold - gitAuth transport.AuthMethod - onSaturn bool + Root string + scaffolds map[string]*Scaffold + gitAuth transport.AuthMethod + onSaturn bool + executionImage string } -func NewScaffoldMultiplexer(root string, secret *saturn.Secret, onSaturn bool) (*ScaffoldMultiplexer, error) { +func NewScaffoldMultiplexer(root string, secret *saturn.Secret, onSaturn bool, executionImage string) (*ScaffoldMultiplexer, error) { gitAuth := &transportHttp.BasicAuth{ Username: "ignored", Password: secret.GitToken, } return &ScaffoldMultiplexer{ - Root: root, - scaffolds: make(map[string]*Scaffold), - gitAuth: gitAuth, - onSaturn: onSaturn, + Root: root, + scaffolds: make(map[string]*Scaffold), + gitAuth: gitAuth, + onSaturn: onSaturn, + executionImage: executionImage, }, nil } @@ -51,7 +53,7 @@ func (m *ScaffoldMultiplexer) runTask( if err != nil { return fmt.Errorf("cloneGit: %v", err) } - scaffold, err = NewScaffold(ctx, payload.Episode, repo, root, m.onSaturn) + scaffold, err = NewScaffold(ctx, payload.Episode, repo, root, m.onSaturn, m.executionImage) if err != nil { return fmt.Errorf("NewScaffold: %v", err) } @@ -114,39 +116,61 @@ type Scaffold struct { compile Recipe execute Recipe onSaturn bool + + // Container fields for isolated execution + containerRuntime ContainerRuntime + containerID string + executionImage string } -func NewScaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, onSaturn bool) (*Scaffold, error) { +func NewScaffold(ctx context.Context, episode saturn.Episode, repo *git.Repository, root string, onSaturn bool, executionImage string) (*Scaffold, error) { + var scaffold *Scaffold + switch episode.Language { case saturn.Java8: // Kept for compatibility running old episodes - s, err := NewJavaScaffold(ctx, episode, repo, root, "/usr/lib/jvm/java-8-openjdk-amd64", onSaturn) + s, err := NewJavaScaffold(ctx, episode, repo, root, "/usr/lib/jvm/java-8-openjdk-amd64", onSaturn, executionImage) if err != nil { return nil, fmt.Errorf("NewJavaScaffold (Java8): %v", err) } - return &s.Scaffold, nil + scaffold = &s.Scaffold case saturn.Java21: // Modern java21 scaffolds store java in the 'java' subdirectory of the scaffold // javaRoot := filepath.Join(root, "java") javaRoot := root - s, err := NewJavaScaffold(ctx, episode, repo, javaRoot, "/opt/java/openjdk", onSaturn) + s, err := NewJavaScaffold(ctx, episode, repo, javaRoot, "/opt/java/openjdk", onSaturn, executionImage) if err != nil { return nil, fmt.Errorf("NewJavaScaffold (Java21): %v", err) } - return &s.Scaffold, nil + scaffold = &s.Scaffold case saturn.Python3: // pyRoot := filepath.Join(root, "python") pyRoot := root - s, err := NewPython3Scaffold(ctx, episode, repo, pyRoot, "python3.12", onSaturn) + s, err := NewPython3Scaffold(ctx, episode, repo, pyRoot, "python3.12", onSaturn, executionImage) if err != nil { return nil, fmt.Errorf("NewPython3Scaffold: %v", err) } - return &s.Scaffold, nil + scaffold = &s.Scaffold default: return nil, fmt.Errorf("no such language: %v", episode.Language) } + + scaffold.executionImage = executionImage + + log.Ctx(ctx).Info().Msg("Initializing Docker runtime for containerized execution") + runtime, err := NewDockerRuntime(ctx) + if err != nil { + log.Ctx(ctx).Error().Err(err).Msg("Failed to initialize Docker runtime - containerized execution is required") + return nil, fmt.Errorf("failed to initialize Docker runtime: %w", err) + } + + scaffold.containerRuntime = runtime + log.Ctx(ctx).Info().Msg("Docker runtime initialized successfully") + + return scaffold, nil } +// RunCommand runs a command directly on the host func (s *Scaffold) RunCommand(ctx context.Context, extra_env []string, name string, arg ...string) (string, error) { log.Ctx(ctx).Debug().Msgf("Running command: %s %s", name, strings.Join(arg, " ")) procOutput := new(bytes.Buffer) @@ -159,6 +183,111 @@ func (s *Scaffold) RunCommand(ctx context.Context, extra_env []string, name stri return procOutput.String(), err } +// RunIsolatedCommand runs a command in an isolated container +func (s *Scaffold) RunIsolatedCommand(ctx context.Context, extra_env []string, name string, arg ...string) (string, error) { + if s.containerID == "" { + if err := s.initContainer(ctx); err != nil { + return "", fmt.Errorf("failed to initialize container: %w", err) + } + } + + output, err := s.containerRuntime.ExecCommand(ctx, s.containerID, extra_env, name, arg...) + return output, err +} + +func (s *Scaffold) initContainer(ctx context.Context) error { + if s.containerID != "" { + return nil + } + + log.Ctx(ctx).Info().Msg("Initializing execution container") + + // When Saturn runs in Docker, it sees container paths that need to be translated to host paths + scaffoldHostPath := s.translateToHostPath(s.root) + + config := &ContainerConfig{ + Image: s.executionImage, + onSaturn: s.onSaturn, + WorkDir: "/workspace", + NetworkMode: "host", + CPULimit: 2.0, + MemoryLimit: 4 * 1024 * 1024 * 1024, // 4GB + ReadOnlyRootFS: true, + Mounts: []string{ + fmt.Sprintf("%s:/workspace:rw", scaffoldHostPath), + "tmpfs:/tmp:noexec,nosuid,size=1g", // Writable temp directory + "tmpfs:/workspace/.gradle:noexec,nosuid,size=512m", // Gradle cache + }, + CapabilitiesToDrop: []string{"ALL"}, + CapabilitiesToAdd: []string{"CHOWN", "SETUID", "SETGID", "DAC_OVERRIDE"}, + User: "battlecode", // Run as non-root user + Env: append(os.Environ(), "GRADLE_USER_HOME=/tmp/.gradle"), + Entrypoint: []string{}, // Override image's ENTRYPOINT (./saturn) to allow exec commands + } + + containerID, err := s.containerRuntime.CreateContainer(ctx, config) + if err != nil { + return fmt.Errorf("failed to create container: %w", err) + } + s.containerID = containerID + + if err := s.containerRuntime.StartContainer(ctx, containerID); err != nil { + s.cleanupContainer(ctx) + return fmt.Errorf("failed to start container: %w", err) + } + + log.Ctx(ctx).Info(). + Str("container_id", containerID[:12]). + Str("scaffold_root", s.root). + Str("host_path", scaffoldHostPath). + Msg("Execution container started") + + return nil +} + +// translateToHostPath translates container paths to host paths for Docker-in-Docker. +func (s *Scaffold) translateToHostPath(containerPath string) string { + containerBasePath := os.Getenv("SCAFFOLD_CONTAINER_PATH") + hostBasePath := os.Getenv("SCAFFOLD_HOST_PATH") + + if containerBasePath == "" || hostBasePath == "" { + log.Fatal(). + Str("SCAFFOLD_CONTAINER_PATH", containerBasePath). + Str("SCAFFOLD_HOST_PATH", hostBasePath). + Msg("Missing required environment variables for Docker-in-Docker path translation") + } + + relativePath := strings.TrimPrefix(containerPath, containerBasePath) + hostPath := filepath.Join(hostBasePath, relativePath) + + log.Debug(). + Str("container_path", containerPath). + Str("host_path", hostPath). + Msg("Translated path for Docker-in-Docker") + + return hostPath +} + +func (s *Scaffold) cleanupContainer(ctx context.Context) { + if s.containerID == "" { + return + } + + log.Ctx(ctx).Debug(). + Str("container_id", s.containerID[:12]). + Msg("Cleaning up container") + + if err := s.containerRuntime.StopContainer(ctx, s.containerID, 10); err != nil { + log.Ctx(ctx).Warn().Err(err).Msg("Failed to stop container") + } + + if err := s.containerRuntime.RemoveContainer(ctx, s.containerID); err != nil { + log.Ctx(ctx).Warn().Err(err).Msg("Failed to remove container") + } + + s.containerID = "" +} + func (s *Scaffold) Refresh(ctx context.Context) error { wt, err := s.repo.Worktree() if err != nil {