Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions .devcontainer/.env.example
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
# Devcontainer configuration
RUBY_VERSION="3.4.9"

RUBY_VERSION=3.4.9

# E2E testing
SENTRY_DSN="http://user:pass@sentry.localhost/project/42"
# SENTRY_DSN_JS="http://user:pass@sentry-js.localhost/project/43"
SENTRY_DSN_JS=""
SENTRY_DSN=http://user:pass@sentry.localhost/project/42
# SENTRY_DSN_JS=http://user:pass@sentry-js.localhost/project/43
SENTRY_DSN_JS=

SENTRY_E2E_RAILS_APP_PORT=4000
SENTRY_E2E_SVELTE_APP_PORT=4001

SENTRY_E2E_RAILS_APP_URL="http://localhost:4000"
SENTRY_E2E_SVELTE_APP_URL="http://localhost:4001"
SENTRY_E2E_RAILS_APP_URL=http://localhost:4000
SENTRY_E2E_SVELTE_APP_URL=http://localhost:4001

# ActiveJob queue adapter under test: async | inline | sidekiq | resque | delayed_job
SENTRY_E2E_ACTIVE_JOB_ADAPTER="async"

# Redis for the sidekiq/resque adapters (the Compose service is named "redis")
REDIS_URL="redis://redis:6379"
SENTRY_E2E_ACTIVE_JOB_ADAPTER=async

# Faster builds with compose
COMPOSE_BAKE=true
# Redis for the sidekiq/resque adapters
REDIS_URL=redis://localhost:6379
38 changes: 6 additions & 32 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ RUN userdel -r ubuntu 2>/dev/null || true \
&& groupadd --gid 1000 sentry \
&& useradd --uid 1000 --gid sentry --shell /bin/bash --create-home sentry

WORKDIR /workspace/sentry
WORKDIR /workspaces/sentry-ruby

RUN chown -R sentry:sentry /workspace/sentry
RUN chown -R sentry:sentry /workspaces/sentry-ruby

ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \
BUNDLE_RETRY=3 \
REDIS_HOST=redis \
REDIS_HOST=localhost \
PATH=/home/sentry/.local/share/mise/shims:/home/sentry/.local/bin:$PATH

USER sentry
Expand All @@ -52,32 +52,6 @@ USER sentry
# directory content when a volume is first attached).
RUN mkdir -p /home/sentry/bundle

RUN curl https://mise.run | sh \
&& echo 'eval "$(/home/sentry/.local/bin/mise activate bash)"' >> /home/sentry/.bashrc \
&& echo 'eval "$(/home/sentry/.local/bin/mise activate zsh)"' >> /home/sentry/.zshenv

# Pre-install Ruby at build time so the container starts immediately without
# downloading it at runtime. Switching Ruby versions requires a rebuild.
ARG RUBY_VERSION=latest

# Java is always installed (required for JRuby). It is listed in .mise.toml so
# it is available for all users regardless of which Ruby flavour they use.
RUN echo "📦 Pre-installing java@temurin-21..." && \
/home/sentry/.local/bin/mise install "java@temurin-21" && \
/home/sentry/.local/bin/mise use --global "java@temurin-21"

RUN echo "📦 Pre-installing ruby@${RUBY_VERSION} (precompiled)..." && \
MISE_RUBY_COMPILE=0 /home/sentry/.local/bin/mise install "ruby@${RUBY_VERSION}" && \
/home/sentry/.local/bin/mise use --global "ruby@${RUBY_VERSION}"

# Node.js is always needed for the svelte-mini e2e app.
RUN echo "📦 Pre-installing node@lts..." && \
/home/sentry/.local/bin/mise install "node@lts" && \
/home/sentry/.local/bin/mise use --global "node@lts"

# Install headless Chromium via Playwright (includes all system dependencies).
# Symlink the binary into ~/.local/bin which is already on PATH.
RUN /home/sentry/.local/share/mise/shims/npx playwright install chromium --with-deps
# Playwright lays out the binary under chrome-linux/ on arm64 and chrome-linux64/
# on x86_64 (since Playwright 1.57), so the glob has to match both.
RUN bash -c 'ln -sf /home/sentry/.cache/ms-playwright/chromium-*/chrome-linux*/chrome /home/sentry/.local/bin/chromium'
# Chromium, ChromeDriver, mise, and the toolchain (Java, Ruby, Node) are
# installed by the local `./features/tools` dev container feature, which runs
# after this Dockerfile — see devcontainer.json.
2 changes: 1 addition & 1 deletion .devcontainer/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.0
2.2.0
12 changes: 12 additions & 0 deletions .devcontainer/ci-run
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

set -euo pipefail

readonly WORKSPACE=/workspaces/sentry-ruby

sudo chown -R sentry:sentry "$WORKSPACE"

cd "$WORKSPACE"
mise trust "$WORKSPACE" >/dev/null

exec "$@"
34 changes: 0 additions & 34 deletions .devcontainer/devcontainer-lock.json

This file was deleted.

32 changes: 27 additions & 5 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
{
"name": "sentry-ruby",
"dockerComposeFile": "docker-compose.yml",
"service": "sentry-dev",
"workspaceFolder": "/workspace/sentry",
"build": {
"dockerfile": "Dockerfile",
"context": "..",
"args": {
"BASE_IMAGE": "${localEnv:BASE_IMAGE:ubuntu:24.04}"
}
},
"runArgs": ["--init"],
"mounts": [
"source=sentry-ruby-bundle,target=/home/sentry/bundle,type=volume"
],
"forwardPorts": [4000, 4001, 6379],
"containerEnv": {
"BUNDLE_PATH": "/home/sentry/bundle",
"SENTRY_DSN": "http://user:pass@sentry.localhost/project/42",
"SENTRY_DSN_JS": "",
"SENTRY_E2E_RAILS_APP_PORT": "4000",
"SENTRY_E2E_SVELTE_APP_PORT": "4001",
"SENTRY_E2E_RAILS_APP_URL": "http://localhost:4000",
"SENTRY_E2E_SVELTE_APP_URL": "http://localhost:4001",
"SENTRY_E2E_ACTIVE_JOB_ADAPTER": "async",
"REDIS_URL": "redis://localhost:6379"
},
"postCreateCommand": "mise trust /workspaces/sentry-ruby",
"features": {
"ghcr.io/devcontainers/features/git:latest": {
"ppa": false,
"version": "2.54.0"
},
"ghcr.io/devcontainers/features/github-cli:latest": {},
"ghcr.io/nils-geistmann/devcontainers-features/zsh:latest": {},
"ghcr.io/devcontainers/features/node:latest": {},
"ghcr.io/devcontainers-extra/features/npm-packages:latest": {},
"./features/tools": {
"rubyVersion": "${localEnv:RUBY_VERSION:4.0}"
},
"ghcr.io/rocker-org/devcontainer-features/apt-packages:latest": {
"packages": "inotify-tools,tzdata"
}
Expand Down
51 changes: 0 additions & 51 deletions .devcontainer/docker-compose.yml

This file was deleted.

19 changes: 19 additions & 0 deletions .devcontainer/features/tools/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "sentry-ruby toolchain",
"id": "tools",
"version": "1.0.0",
"description": "Installs Chromium, ChromeDriver, mise, and the sentry-ruby toolchain (Java, Ruby, Node).",
"installsAfter": [
"ghcr.io/devcontainers/features/git",
"ghcr.io/devcontainers/features/github-cli",
"ghcr.io/nils-geistmann/devcontainers-features/zsh",
"ghcr.io/rocker-org/devcontainer-features/apt-packages"
],
"options": {
"rubyVersion": {
"type": "string",
"default": "4.0",
"description": "Ruby version to pre-install (latest 4.0.x by default). Switching versions requires an image rebuild."
}
}
}
49 changes: 49 additions & 0 deletions .devcontainer/features/tools/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
#
# Installs mise, the sentry-ruby toolchain, and Chromium with ChromeDriver.
#
set -euo pipefail

RUBY_VERSION="${RUBYVERSION:-latest}"
USERNAME="${_REMOTE_USER:-sentry}"
USER_HOME="${_REMOTE_USER_HOME:-/home/${USERNAME}}"

echo "📦 Installing Chromium and ChromeDriver..."
echo "deb http://deb.debian.org/debian sid main" > /etc/apt/sources.list.d/debian.list
wget -qO- https://ftp-master.debian.org/keys/archive-key-12.asc \
| gpg --dearmor > /etc/apt/trusted.gpg.d/debian-archive-keyring.gpg
wget -qO- https://ftp-master.debian.org/keys/archive-key-12-security.asc \
| gpg --dearmor > /etc/apt/trusted.gpg.d/debian-archive-security-keyring.gpg
for directory in bin lib lib32 lib64 libo32 libx32 sbin; do
dpkg-divert --package base-files --no-rename --remove "/${directory}"
done
apt-get update
apt-get install -y --no-install-recommends chromium chromium-driver
rm -rf /var/lib/apt/lists/* /var/cache/apt/* /etc/apt/sources.list.d/debian.list

# Install mise system-wide via the official installer. This downloads a prebuilt
# binary from mise's CDN rather than the GitHub API, avoiding the API rate
# limits the gh-release-based community feature hits on shared CI runners.
echo "📦 Installing mise..."
export MISE_INSTALL_PATH=/usr/local/bin/mise
curl https://mise.run | sh
MISE_BIN=/usr/local/bin/mise
"$MISE_BIN" --version

# Activate mise for the remote user's interactive shells.
echo "eval \"\$(${MISE_BIN} activate bash)\"" >> "${USER_HOME}/.bashrc"
echo "eval \"\$(${MISE_BIN} activate zsh)\"" >> "${USER_HOME}/.zshenv"
chown "${USERNAME}:${USERNAME}" "${USER_HOME}/.bashrc" "${USER_HOME}/.zshenv"

# Feature installers run as root, but the toolchain belongs to the remote user.
as_user() {
sudo -u "${USERNAME}" -H env "PATH=${USER_HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin" "$@"
}

echo "📦 Pre-installing toolchain..."
as_user env MISE_RUBY_COMPILE=0 "$MISE_BIN" install \
"java@temurin-21" \
"ruby@${RUBY_VERSION}" \
"node@lts"

echo "✅ Toolchain pre-install completed!"
35 changes: 0 additions & 35 deletions .devcontainer/run

This file was deleted.

2 changes: 1 addition & 1 deletion .devcontainer/setup
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SetupScript
only_npm: false,
with_foreman: false
}
@workspace_root = '/workspace/sentry'
@workspace_root = '/workspaces/sentry-ruby'
end

def run(args)
Expand Down
24 changes: 14 additions & 10 deletions .github/workflows/build_images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,19 @@
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0

# Build with the dev container CLI (not a plain `docker build`) so the dev
# container features — including the local `tools` feature that bakes the
# Ruby/Node/Java toolchain and browser — are applied to the pushed image.
# BASE_IMAGE and RUBY_VERSION are consumed via ${localEnv:...} in
# devcontainer.json, so they are passed as env vars to the CLI here.
- name: Build and push devcontainer image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
uses: devcontainers/ci@513af61f4de4f75d37e4438f184ba4358f0fc1ca # v0.3.1900000450
env:
BASE_IMAGE: ${{ matrix.base_image }}
RUBY_VERSION: ${{ matrix.ruby_version }}
with:
context: .
file: .devcontainer/Dockerfile
push: true
tags: |
ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.flavor }}:${{ steps.version.outputs.version }}
${{ github.ref == 'refs/heads/master' && format('ghcr.io/getsentry/sentry-ruby-devcontainer-{0}:latest', matrix.flavor) || '' }}
build-args: |
BASE_IMAGE=${{ matrix.base_image }}
RUBY_VERSION=${{ matrix.ruby_version }}
subFolder: .
configFile: .devcontainer/devcontainer.json
imageName: ghcr.io/getsentry/sentry-ruby-devcontainer-${{ matrix.flavor }}
imageTag: ${{ github.ref == 'refs/heads/master' && format('{0},latest', steps.version.outputs.version) || steps.version.outputs.version }}
push: always

Check notice on line 73 in .github/workflows/build_images.yml

View check run for this annotation

@sentry/warden / warden: security-review

Unpinned third-party devcontainer features run in privileged GHCR image-push build

The devcontainer build (`build_images.yml`) runs remote third-party devcontainer features pinned only to `:latest` (no committed lockfile) while it holds `packages: write` and GHCR push credentials, so a rewritten upstream feature tag would execute arbitrary install scripts and poison the published base images consumed by e2e CI. Pin the features by digest or commit `devcontainer-lock.json`.
Comment on lines 63 to +73

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unpinned third-party devcontainer features run in privileged GHCR image-push build

The devcontainer build (build_images.yml) runs remote third-party devcontainer features pinned only to :latest (no committed lockfile) while it holds packages: write and GHCR push credentials, so a rewritten upstream feature tag would execute arbitrary install scripts and poison the published base images consumed by e2e CI. Pin the features by digest or commit devcontainer-lock.json.

Evidence
  • .devcontainer/devcontainer.json (changed) declares third-party features ghcr.io/nils-geistmann/devcontainers-features/zsh:latest and ghcr.io/rocker-org/devcontainer-features/apt-packages:latest using floating :latest tags, plus official ghcr.io/devcontainers/features/*:latest.
  • .gitignore (changed) ignores .devcontainer/devcontainer-lock.json, so no lockfile pins those feature payloads for CI.
  • build_images.yml builds via devcontainers/ci with push: always after docker/login-action to GHCR using secrets.GITHUB_TOKEN, under permissions: packages: write; feature install scripts run in that credentialed build.
  • Published ghcr.io/getsentry/sentry-ruby-devcontainer-* images are pulled and executed by e2e_tests.yml, so a compromised floating feature tag would poison trusted CI base images.
  • Exploit requires upstream feature compromise and the workflow triggers only on push to master/dispatch (not fork PRs), so impact is conditional — hence low severity.

Identified by Warden security-review · GJD-MR6

Loading
Loading