diff --git a/Makefile b/Makefile index eca57eb1..e5e67f3e 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,10 @@ PROTOC_TYPESCRIPT_IMAGE = protoc-typescript RUST_ACTION ?= run -p sigstore-protobuf-specs-codegen PLATFORM ?= linux/amd64 +UID ?= $(shell id -u) +GID ?= $(shell id -g) +DOCKER_BUILD = docker build --platform ${PLATFORM} --build-arg UID=${UID} +DOCKER_RUN = docker run --platform ${PLATFORM} --user ${UID}:${GID} PROTOS = $(shell find protos/ -iname "*.proto" | sed 's|^|/defs/|') @@ -33,49 +37,49 @@ all: go python typescript ruby jsonschema rust # generate Go protobuf code go: docker-image @echo "Generating go proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_GO_IMAGE} -f Dockerfile.go . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_GO_IMAGE} -f Dockerfile.go . @echo "Generating go protobuf files" - docker run --platform ${PLATFORM} -v ${PWD}:/defs ${PROTOC_GO_IMAGE} \ + ${DOCKER_RUN} -v ${PWD}:/defs ${PROTOC_GO_IMAGE} \ -I/opt/include -I/googleapis -I/defs/protos \ --go_opt=module=github.com/sigstore/protobuf-specs/gen/pb-go --go_out=/defs/gen/pb-go ${PROTOS} python: docker-image @echo "Generating python proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_PYTHON_IMAGE} -f Dockerfile.python . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_PYTHON_IMAGE} -f Dockerfile.python . @echo "Generating python protobuf files" - docker run --platform ${PLATFORM} -v ${PWD}:/defs ${PROTOC_PYTHON_IMAGE} \ + ${DOCKER_RUN} -v ${PWD}:/defs ${PROTOC_PYTHON_IMAGE} \ -I/opt/include -I/googleapis -I/defs/protos \ --python_betterproto_opt=pydantic_dataclasses --python_betterproto_out=/defs/gen/pb-python/sigstore_protobuf_specs ${PROTOS} typescript: docker-image @echo "Generating typescript proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_TYPESCRIPT_IMAGE} -f Dockerfile.typescript . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_TYPESCRIPT_IMAGE} -f Dockerfile.typescript . @echo "Generating javascript protobuf files" - docker run --platform ${PLATFORM} -v ${PWD}:/defs ${PROTOC_TYPESCRIPT_IMAGE} \ + ${DOCKER_RUN} -v ${PWD}:/defs ${PROTOC_TYPESCRIPT_IMAGE} \ -I/opt/include -I/googleapis -I/defs/protos \ --ts_proto_out=/defs/gen/pb-typescript/src/__generated__ --ts_proto_opt=oneof=unions,forceLong=string,env=node,exportCommonSymbols=false,outputPartialMethods=false,outputEncodeMethods=false,unrecognizedEnum=false ${PROTOS} ruby: docker-image @echo "Generating ruby proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_RUBY_IMAGE} -f Dockerfile.ruby . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_RUBY_IMAGE} -f Dockerfile.ruby . @echo "Generating ruby protobuf files" - docker run --platform ${PLATFORM} -v ${PWD}:/defs ${PROTOC_RUBY_IMAGE} \ + ${DOCKER_RUN} -v ${PWD}:/defs ${PROTOC_RUBY_IMAGE} \ -I/opt/include -I/googleapis -I/defs/protos --ruby_out=/defs/gen/pb-ruby/lib ${PROTOS} jsonschema: docker-image @echo "Generating jsonschema proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_JSONSCHEMA_IMAGE} -f Dockerfile.jsonschema . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_JSONSCHEMA_IMAGE} -f Dockerfile.jsonschema . @echo "Generating JSON schema files" mkdir -p gen/jsonschema/schemas - docker run --platform ${PLATFORM} -v ${PWD}:/defs ${PROTOC_JSONSCHEMA_IMAGE} \ + ${DOCKER_RUN} -v ${PWD}:/defs ${PROTOC_JSONSCHEMA_IMAGE} \ -I/opt/include -I/googleapis -I/defs/protos \ --jsonschema_out=/defs/gen/jsonschema/schemas --jsonschema_opt=disallow_additional_properties --jsonschema_opt=enforce_oneof --jsonschema_opt=enums_as_strings_only --jsonschema_opt=file_extension=schema.json --jsonschema_opt=json_fieldnames \ ${PROTOS} rust: docker-image @echo "Generating rust proto Docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_RUST_IMAGE} -f Dockerfile.rust . - docker run --platform ${PLATFORM} -v ${PWD}:/defs \ + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_RUST_IMAGE} -f Dockerfile.rust . + ${DOCKER_RUN} -v ${PWD}:/defs \ -e "RUST_BACKTRACE=1" -e "CARGO_REGISTRY_TOKEN" ${PROTOC_RUST_IMAGE} \ -c "cd /defs/gen/pb-rust && cargo ${RUST_ACTION}" @@ -83,7 +87,7 @@ rust: docker-image .PHONY: docker-image docker-image: @echo "Building base docker image" - cd protoc-builder && docker build --platform ${PLATFORM} -t ${PROTOC_IMAGE} -f Dockerfile.protoc . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_IMAGE} -f Dockerfile.protoc . # to recover from a situation where a stale layer exist, just purging the # docker image via `make clean` is not enough. Re-building without layer @@ -91,13 +95,13 @@ docker-image: .PHONY: docker-image-no-cache docker-image-no-cache: @echo "Building development docker images with disabled cache" - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_IMAGE} -f Dockerfile.protoc . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_GO_IMAGE} -f Dockerfile.go . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_JSONSCHEMA_IMAGE} -f Dockerfile.jsonschema . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_PYTHON_IMAGE} -f Dockerfile.python . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_RUBY_IMAGE} -f Dockerfile.ruby . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_RUST_IMAGE} -f Dockerfile.rust . - cd protoc-builder && docker build --no-cache --platform ${PLATFORM} -t ${PROTOC_TYPESCRIPT_IMAGE} -f Dockerfile.typescript . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_IMAGE} -f Dockerfile.protoc . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_GO_IMAGE} -f Dockerfile.go . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_JSONSCHEMA_IMAGE} -f Dockerfile.jsonschema . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_PYTHON_IMAGE} -f Dockerfile.python . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_RUBY_IMAGE} -f Dockerfile.ruby . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_RUST_IMAGE} -f Dockerfile.rust . + cd protoc-builder && ${DOCKER_BUILD} -t ${PROTOC_TYPESCRIPT_IMAGE} -f Dockerfile.typescript . # clean up generated files (not working? try sudo make clean) clean: diff --git a/protoc-builder/Dockerfile.go b/protoc-builder/Dockerfile.go index d3856848..6227f34a 100644 --- a/protoc-builder/Dockerfile.go +++ b/protoc-builder/Dockerfile.go @@ -6,7 +6,7 @@ ADD hack/go/go.* hack/go/tools.go tools/ RUN cd tools && go build --trimpath google.golang.org/grpc/cmd/protoc-gen-go-grpc RUN cd tools && go build --trimpath google.golang.org/protobuf/cmd/protoc-gen-go -FROM gcr.io/distroless/cc-debian12@sha256:b7550f0b15838de14c564337eef2b804ba593ae55d81ca855421bd52f19bb480 +FROM gcr.io/distroless/cc-debian12:nonroot@sha256:6970a2b2cb07c68f3e15d1b5d2ba857e53da911d5d321f48a842d6b0d26984cf COPY --from=go-builder /go/tools/protoc-* /usr/local/bin/ COPY --from=protoc-base /protobuf/bin/protoc /usr/local/bin/ diff --git a/protoc-builder/Dockerfile.protoc b/protoc-builder/Dockerfile.protoc index 967f5abc..5aefd4ca 100644 --- a/protoc-builder/Dockerfile.protoc +++ b/protoc-builder/Dockerfile.protoc @@ -2,23 +2,35 @@ # This container grabs the protoc compiler and the googleapi includes # /protobuf will contain the extracted protoc # /googleapis will contain the various googleapis proto imports one might need -FROM alpine:3.21@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099 AS protoc-builder +FROM debian:bullseye-slim@sha256:6344a6747740d465bff88e833e43ef881a8c4dd51950dba5b30664c93f74cbef AS protoc-builder # Create output directories RUN mkdir /protobuf /googleapis +# Install needed utilities +RUN apt-get update && apt-get install -y unzip git + +# Set up user and group to match host we're building the container on +ARG UID + +RUN adduser --uid ${UID} --disabled-password myuser + +# Set permissions on the output directories so the user can write to them +RUN chown myuser /protobuf /googleapis + +# Switch to user to execute the remaining commands +USER myuser # Download specific release of protoc # TODO: add dependabot-like feature to check for release updates ARG PROTOC_VERSION=v21.6 ARG PROTOC_CHECKSUM=sha256:6a9fc36363a2d05d73fc363a46cd57d849068d33305db39f77daac8ba073e818 -ADD --checksum=${PROTOC_CHECKSUM} https://github.com/protocolbuffers/protobuf/releases/download/${PROTOC_VERSION}/protoc-${PROTOC_VERSION#v}-linux-x86_64.zip /tmp/protoc.zip +ADD --chown=myuser --checksum=${PROTOC_CHECKSUM} https://github.com/protocolbuffers/protobuf/releases/download/${PROTOC_VERSION}/protoc-${PROTOC_VERSION#v}-linux-x86_64.zip /tmp/protoc.zip RUN unzip -d /protobuf /tmp/protoc.zip RUN chmod 755 /protobuf/bin/protoc # fetch specific commit of googleapis # TODO: add dependabot-like feature to check for release updates -RUN apk add git ARG GOOGLE_APIS_VERSION=6ef9eaea379fc1cc0355e06a5a20b594543ee693 #ARG GOOGLE_APIS_VERSION=95f0f2b2aee51e460646320d6e8f2ce75c463f5a RUN git clone --filter=tree:0 https://github.com/googleapis/googleapis.git /googleapis && \ diff --git a/protoc-builder/Dockerfile.ruby b/protoc-builder/Dockerfile.ruby index bd8d232e..0f44966a 100644 --- a/protoc-builder/Dockerfile.ruby +++ b/protoc-builder/Dockerfile.ruby @@ -1,4 +1,4 @@ -FROM gcr.io/distroless/cc-debian12@sha256:b7550f0b15838de14c564337eef2b804ba593ae55d81ca855421bd52f19bb480 +FROM gcr.io/distroless/cc-debian12:nonroot@sha256:6970a2b2cb07c68f3e15d1b5d2ba857e53da911d5d321f48a842d6b0d26984cf COPY --from=protoc-base /protobuf/bin/protoc /usr/local/bin/ COPY --from=protoc-base /protobuf/include/google /opt/include/google diff --git a/protoc-builder/Dockerfile.typescript b/protoc-builder/Dockerfile.typescript index 0a2b5dae..41b1e278 100644 --- a/protoc-builder/Dockerfile.typescript +++ b/protoc-builder/Dockerfile.typescript @@ -7,9 +7,9 @@ WORKDIR /app RUN npm ci --install-strategy=shallow # /usr/bin/env is called from ts-proto but not in distroless by default; we use busybox for this -FROM gcr.io/distroless/base-debian12:debug@sha256:a6b40812524ed4f6a2e507eb01ed04f867d9b4cb1e20369d62ffef0edd598efd AS env-source +FROM gcr.io/distroless/base-debian12:debug-nonroot@sha256:ee694eefd7685d8c443fec6abd3bff8e30c437faa8fbeacc0ce4c2e847d45501 AS env-source -FROM gcr.io/distroless/nodejs18-debian12@sha256:06ded55200d9a39c71e85117775d1ac63bfcb20104e53e6c6de24832ed2cf015 +FROM gcr.io/distroless/nodejs18-debian12:nonroot@sha256:4a5e24618b1cb8743b7651cb7d91de58a7e71f470e72b879c49e59115f2f5a45 # node is installed in a non-default location in distroless ENV PATH=$PATH:/nodejs/bin