FROM rust:slim AS rust-utils
# Install rust helper programs
# ENV CARGO_NET_GIT_FETCH_WITH_CLI=true
env CARGO_INSTALL_ROOT=/tmp/
RUN cargo install exa bat ripgrep typos-cli watchexec-cli

FROM ubuntu AS go

RUN apt-get update && apt-get install --yes curl gcc
# Install Go manually, so that we can control the version
ARG GO_VERSION=1.19
RUN mkdir --parents /usr/local/go

# Boring Go is needed to build FIPS-compliant binaries.
RUN curl --silent --show-error --location \
  "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
  -o /usr/local/go.tar.gz

RUN tar --extract --gzip --directory=/usr/local/go --file=/usr/local/go.tar.gz --strip-components=1

ENV PATH=$PATH:/usr/local/go/bin

# Install Go utilities.
ARG GOPATH="/tmp/"
RUN mkdir --parents "$GOPATH" && \
    # moq for Go tests.
    go install github.com/matryer/moq@v0.2.3 && \
    # swag for Swagger doc generation
    go install github.com/swaggo/swag/cmd/swag@v1.7.4 && \
    # go-swagger tool to generate the go coder api client
    go install github.com/go-swagger/go-swagger/cmd/swagger@v0.28.0 && \
    # goimports for updating imports
    go install golang.org/x/tools/cmd/goimports@v0.1.7 && \
    # protoc-gen-go is needed to build sysbox from source
    go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 && \
    # drpc support for v2
    go install storj.io/drpc/cmd/protoc-gen-go-drpc@v0.0.26 && \
    # migrate for migration support for v2
    go install github.com/golang-migrate/migrate/v4/cmd/migrate@v4.15.1 && \
    # goreleaser for compiling v2 binaries
    go install github.com/goreleaser/goreleaser@v1.6.1 && \
    # Install the latest version of gopls for editors that support
    # the language server protocol
    go install golang.org/x/tools/gopls@latest && \
    # gotestsum makes test output more readable
    go install gotest.tools/gotestsum@v1.7.0 && \
    # goveralls collects code coverage metrics from tests
    # and sends to Coveralls
    go install github.com/mattn/goveralls@v0.0.11 && \
    # kind for running Kubernetes-in-Docker, needed for tests
    go install sigs.k8s.io/kind@v0.10.0 && \
    # helm-docs generates our Helm README based on a template and the
    # charts and values files
    go install github.com/norwoodj/helm-docs/cmd/helm-docs@v1.5.0 && \
    # sqlc for Go code generation
    go install github.com/kyleconroy/sqlc/cmd/sqlc@v1.10.0 && \
    # gcr-cleaner-cli used by CI to prune unused images
    go install github.com/sethvargo/gcr-cleaner/cmd/gcr-cleaner-cli@v0.5.1 && \
    # ruleguard for checking custom rules, without needing to run all of
    # golangci-lint. Check the go.mod in the release of golangci-lint that
    # we're using for the version of go-critic that it embeds, then check
    # the version of ruleguard in go-critic for that tag.
    go install github.com/quasilyte/go-ruleguard/cmd/ruleguard@v0.3.13 && \
    # go-fuzz for fuzzy testing. they don't publish releases so we rely on latest.
    go install github.com/dvyukov/go-fuzz/go-fuzz@latest && \
    go install github.com/dvyukov/go-fuzz/go-fuzz-build@latest && \
    # go-releaser for building 'fat binaries' that work cross-platform
    go install github.com/goreleaser/goreleaser@v1.6.1 && \
    go install mvdan.cc/sh/v3/cmd/shfmt@latest && \
    # nfpm is used with `make build` to make release packages
    go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.16.0

FROM alpine:3.16 as proto
WORKDIR /tmp
RUN apk add curl unzip
RUN curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v21.5/protoc-21.5-linux-x86_64.zip
RUN unzip protoc.zip

# Ubuntu 20.04 LTS (Focal Fossa)
FROM ubuntu:focal

SHELL ["/bin/bash", "-c"]

# Updated certificates are necessary to use the teraswitch mirror.
# This must be ran before copying in configuration since the config replaces
# the default mirror with teraswitch.
RUN apt-get update && apt-get install --yes ca-certificates

COPY files /

# Install packages from apt repositories
ARG DEBIAN_FRONTEND="noninteractive"

RUN apt-get update --quiet && apt-get install --yes \
      apt-transport-https \
      apt-utils \
      bash \
      bash-completion \
      bats \
      bind9-dnsutils \
      build-essential \
      ca-certificates \
      cmake \
      crypto-policies \
      curl \
      fd-find \
      file \
      git \
      gnupg \
      graphviz \
      htop \
      httpie \
      inetutils-tools \
      iproute2 \
      iputils-ping \
      iputils-tracepath \
      jq \
      language-pack-en \
      less \
      lsb-release \
      man \
      meld \
      net-tools \
      openjdk-11-jdk-headless \
      openssh-server \
      openssl \
      pkg-config \
      python3 \
      python3-pip \
      rsync \
      shellcheck \
      strace \
      sudo \
      tcptraceroute \
      termshark \
      traceroute \
      vim \
      wget \
      xauth \
      zip \
      ncdu \
      cargo \
      asciinema \
      zsh \
      ansible \
      neovim \
      google-cloud-sdk \
      google-cloud-sdk-datastore-emulator \
      kubectl \
      postgresql-11 \
      containerd.io \
      docker-ce \
      docker-ce-cli \
      packer \
      terraform \
      buildah \
      conmon \
      containernetworking-plugins \
      crun \
      podman \
      skopeo \
      fish \
			unzip \
      zstd && \
    # Delete package cache to avoid consuming space in layer
    apt-get clean && \
    # Configure FIPS-compliant policies
    update-crypto-policies --set FIPS

# See https://github.com/cli/cli/issues/6175#issuecomment-1235984381 for proof
# the apt repository is unreliable
RUN curl -L https://github.com/cli/cli/releases/download/v2.14.7/gh_2.14.7_linux_amd64.deb -o gh.deb && \
    dpkg -i gh.deb

# Install frontend utilities
RUN apt-get update && \
    # Node.js (from nodesource) and Yarn (from yarnpkg)
    apt-get install --yes --quiet \
      nodejs yarn \
    # Install browsers for e2e testing
      google-chrome-stable microsoft-edge-beta && \
    # Pre-install system dependencies that Playwright needs. npx doesn't work here
    # for some reason. See https://github.com/microsoft/playwright-cli/issues/136
    npm i -g playwright@1.19.1 && playwright install-deps

# Ensure PostgreSQL binaries are in the users $PATH.
RUN update-alternatives --install /usr/local/bin/initdb initdb /usr/lib/postgresql/11/bin/initdb 100 && \
    update-alternatives --install /usr/local/bin/postgres postgres /usr/lib/postgresql/11/bin/postgres 100

# Create links for injected dependencies
RUN ln --symbolic /var/tmp/coder/coder-cli/coder /usr/local/bin/coder && \
    ln --symbolic /var/tmp/coder/code-server/bin/code-server /usr/local/bin/code-server

# Disable the PostgreSQL systemd service.
# Coder uses a custom timescale container to test the database instead.
RUN systemctl disable \
      postgresql

# Configure systemd services for CVMs
RUN systemctl enable \
      docker \
      ssh

# Install tools with published releases, where that is the
# preferred/recommended installation method.
ARG CLOUD_SQL_PROXY_VERSION=1.26.0 \
    DIVE_VERSION=0.10.0 \
    DOCKER_GCR_VERSION=2.1.0 \
    GOLANGCI_LINT_VERSION=1.48.0 \
    GRYPE_VERSION=0.24.0 \
    HELM_VERSION=3.8.0 \
    KUBE_LINTER_VERSION=0.2.5 \
    KUBECTX_VERSION=0.9.4 \
    STRIPE_VERSION=1.7.4 \
    TERRAGRUNT_VERSION=0.34.1 \
    TRIVY_VERSION=0.23.0

# cloud_sql_proxy, for connecting to cloudsql instances
# the upstream go.mod prevents this from being installed with go install
RUN curl --silent --show-error --location --output /usr/local/bin/cloud_sql_proxy "https://storage.googleapis.com/cloudsql-proxy/v${CLOUD_SQL_PROXY_VERSION}/cloud_sql_proxy.linux.amd64" && \
      chmod a=rx /usr/local/bin/cloud_sql_proxy && \
    # dive for scanning image layer utilization metrics in CI
    curl --silent --show-error --location "https://github.com/wagoodman/dive/releases/download/v${DIVE_VERSION}/dive_${DIVE_VERSION}_linux_amd64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- dive && \
    # docker-credential-gcr is a Docker credential helper for pushing/pulling
    # images from Google Container Registry and Artifact Registry
    curl --silent --show-error --location "https://github.com/GoogleCloudPlatform/docker-credential-gcr/releases/download/v${DOCKER_GCR_VERSION}/docker-credential-gcr_linux_amd64-${DOCKER_GCR_VERSION}.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- docker-credential-gcr && \
    # golangci-lint performs static code analysis for our Go code
    curl --silent --show-error --location "https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-amd64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- --strip-components=1 "golangci-lint-${GOLANGCI_LINT_VERSION}-linux-amd64/golangci-lint" && \
    # Anchore Grype for scanning container images for security issues
    curl --silent --show-error --location "https://github.com/anchore/grype/releases/download/v${GRYPE_VERSION}/grype_${GRYPE_VERSION}_linux_amd64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- grype && \
    # Helm is necessary for deploying Coder
    curl --silent --show-error --location "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- --strip-components=1 linux-amd64/helm && \
    # kube-linter for linting Kubernetes objects, including those
    # that Helm generates from our charts
    curl --silent --show-error --location "https://github.com/stackrox/kube-linter/releases/download/${KUBE_LINTER_VERSION}/kube-linter-linux.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- kube-linter && \
    # kubens and kubectx for managing Kubernetes namespaces and contexts
    curl --silent --show-error --location "https://github.com/ahmetb/kubectx/releases/download/v${KUBECTX_VERSION}/kubectx_v${KUBECTX_VERSION}_linux_x86_64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- kubectx && \
    curl --silent --show-error --location "https://github.com/ahmetb/kubectx/releases/download/v${KUBECTX_VERSION}/kubens_v${KUBECTX_VERSION}_linux_x86_64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- kubens && \
    # stripe for coder.com billing API
    curl --silent --show-error --location "https://github.com/stripe/stripe-cli/releases/download/v${STRIPE_VERSION}/stripe_${STRIPE_VERSION}_linux_x86_64.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- stripe && \
    # terragrunt for running Terraform and Terragrunt files
    curl --silent --show-error --location --output /usr/local/bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/terragrunt_linux_amd64" && \
      chmod a=rx /usr/local/bin/terragrunt && \
    # AquaSec Trivy for scanning container images for security issues
    curl --silent --show-error --location "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/bin --file=- trivy

# Add Vercel globally. We can't install it in packages.json, because it
# includes Go files which make golangci-lint unhappy.
RUN yarn global add --prefix=/usr/local \
      vercel \
      typescript \
      typescript-language-server \
      prettier && \
      yarn cache clean

# We use yq during "make deploy" to manually substitute out fields in
# our helm values.yaml file. See https://github.com/helm/helm/issues/3141
#
# TODO: update to 4.x, we can't do this now because it included breaking
# changes (yq w doesn't work anymore)
# RUN curl --silent --show-error --location "https://github.com/mikefarah/yq/releases/download/v4.9.0/yq_linux_amd64.tar.gz" | \
#       tar --extract --gzip --directory=/usr/local/bin --file=- ./yq_linux_amd64 && \
#     mv /usr/local/bin/yq_linux_amd64 /usr/local/bin/yq

RUN curl --silent --show-error --location --output /usr/local/bin/yq "https://github.com/mikefarah/yq/releases/download/3.3.0/yq_linux_amd64" && \
    chmod a=rx /usr/local/bin/yq

# Install GoLand.
RUN mkdir --parents /usr/local/goland && \
    curl --silent --show-error --location "https://download.jetbrains.com/go/goland-2021.2.tar.gz" | \
      tar --extract --gzip --directory=/usr/local/goland --file=- --strip-components=1 && \
    ln --symbolic /usr/local/goland/bin/goland.sh /usr/local/bin/goland

# Install Antlrv4, needed to generate paramlang lexer/parser
RUN curl --silent --show-error --location --output /usr/local/lib/antlr-4.9.2-complete.jar "https://www.antlr.org/download/antlr-4.9.2-complete.jar"
ENV CLASSPATH="/usr/local/lib/antlr-4.9.2-complete.jar:${PATH}"

# Add coder user and allow use of docker/sudo
RUN useradd coder \
      --create-home \
      --shell=/bin/bash \
      --groups=docker \
      --uid=1000 \
      --user-group

# Adjust OpenSSH config
RUN echo "PermitUserEnvironment yes" >>/etc/ssh/sshd_config && \
    echo "X11Forwarding yes" >>/etc/ssh/sshd_config && \
    echo "X11UseLocalhost no" >>/etc/ssh/sshd_config

# We avoid copying the extracted directory since COPY slows to minutes when there
# are a lot of small files.
COPY --from=go /usr/local/go.tar.gz /usr/local/go.tar.gz
RUN mkdir /usr/local/go && \
    tar --extract --gzip --directory=/usr/local/go --file=/usr/local/go.tar.gz --strip-components=1

ENV PATH=$PATH:/usr/local/go/bin

RUN update-alternatives --install /usr/local/bin/gofmt gofmt /usr/local/go/bin/gofmt 100

COPY --from=go /tmp/bin /usr/local/bin
COPY --from=rust-utils /tmp/bin /usr/local/bin
COPY --from=proto /tmp/bin /usr/local/bin

USER coder

# Ensure go bins are in the 'coder' user's path. Note that no go bins are
# installed in this docker file, as they'd be mounted over by the persistent
# home volume.
ENV PATH="/home/coder/go/bin:${PATH}"

# This setting prevents Go from using the public checksum database for
# our module path prefixes. It is required because these are in private
# repositories that require authentication.
#
# For details, see: https://golang.org/ref/mod#private-modules
ENV GOPRIVATE="coder.com,cdr.dev,go.coder.com,github.com/cdr,github.com/coder"

# Increase memory allocation to NodeJS
ENV NODE_OPTIONS="--max-old-space-size=8192"
