Skip to content
Merged
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
33 changes: 20 additions & 13 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@
/sonar-project.properties
/postcss.config.js

# Ignore additional dev/CI/internal files not needed at runtime
/.claude
/.foreman
/.git-hooks
/.gitguardian.yml
/.github_changelog_generator
/.rspec
/.safety-net.json
/.slugignore
/.sonarcloud.properties
/.tool-versions
/app.json
/cliff.toml
/issues.jsonl
/Procfile.dev

# Ignore non-Linux binaries
/bin/vulcan

Expand All @@ -81,20 +97,11 @@
/nginx.conf*
/setup-docker-secrets.sh

# Ignore markdown files not needed at runtime
/CHANGELOG.md
/CODE_OF_CONDUCT.md
/CONTRIBUTING.md
/LICENSE.md
/NOTICE.md
/README.md
/RELEASE_NOTES.md
/SECURITY.md
/ROADMAP.md
/BENCHMARK-VIEWER-DESIGN.md
# Ignore root-level markdown (docs/ is kept — read at runtime by DisaGuideController)
/*.md

# Other root files not needed at runtime
/AGENT-STATUS
/ENVIRONMENT_VARIABLES.md
/CLAUDE.md
/_config.yml
/CNAME
/create_admin.rb
82 changes: 82 additions & 0 deletions .github/actions/setup-ruby-source/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: 'Setup Ruby (source build)'
description: >-
TEMPORARY drop-in replacement for ruby/setup-ruby. Compiles the pinned Ruby
from source (mirroring the Dockerfile's build) because ruby-builder does not
yet publish a prebuilt binary for it. The compiled Ruby and the installed gem
bundle are both cached, so the ~6-minute compile is paid only once per Ruby
version. Revert lint/backend back to ruby/setup-ruby (see git history) once
https://github.com/ruby/ruby-builder ships a binary for the pinned version.

runs:
using: 'composite'
steps:
# Single source of truth: version from .ruby-version (matches Gemfile +
# Dockerfile ARG), checksum from the Dockerfile ARG. A drift between the two
# trips the sha256 check below, loudly.
- name: Resolve Ruby version and checksum
id: ruby
shell: bash
run: |
ver="$(cat .ruby-version)"
sha="$(grep -m1 '^ARG RUBY_SHA256=' Dockerfile | cut -d= -f2)"
echo "version=$ver" >> "$GITHUB_OUTPUT"
echo "sha256=$sha" >> "$GITHUB_OUTPUT"
echo "install_dir=$HOME/.rubies/$ver" >> "$GITHUB_OUTPUT"

- name: Restore compiled Ruby
id: ruby-cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ steps.ruby.outputs.install_dir }}
key: ruby-src-${{ runner.os }}-24.04-${{ steps.ruby.outputs.version }}-${{ steps.ruby.outputs.sha256 }}

# Needed to compile Ruby (rust is for --enable-yjit) and to build native gem
# extensions during bundle install (pg needs libpq-dev, etc.).
- name: Install build dependencies
shell: bash
run: |
sudo apt-get update -qq
sudo apt-get install -yqq --no-install-recommends \
autoconf bison build-essential libffi-dev libgmp-dev libpq-dev \
libreadline-dev libssl-dev libyaml-dev rustc zlib1g-dev

- name: Compile Ruby from source
if: steps.ruby-cache.outputs.cache-hit != 'true'
shell: bash
env:
RUBY_VERSION: ${{ steps.ruby.outputs.version }}
RUBY_SHA256: ${{ steps.ruby.outputs.sha256 }}
INSTALL_DIR: ${{ steps.ruby.outputs.install_dir }}
run: |
set -euo pipefail
curl -fsSL --proto '=https' --proto-redir '=https' "https://cache.ruby-lang.org/pub/ruby/${RUBY_VERSION%.*}/ruby-${RUBY_VERSION}.tar.gz" -o /tmp/ruby.tar.gz
echo "${RUBY_SHA256} /tmp/ruby.tar.gz" | sha256sum -c -
tar -xzf /tmp/ruby.tar.gz -C /tmp
cd "/tmp/ruby-${RUBY_VERSION}"
./configure --prefix="${INSTALL_DIR}" --disable-install-doc --enable-yjit
make -j"$(nproc)"
make install

- name: Add Ruby to PATH
shell: bash
run: echo "${{ steps.ruby.outputs.install_dir }}/bin" >> "$GITHUB_PATH"

- name: Install bundler
shell: bash
run: |
bundler_version="$(awk '/BUNDLED WITH/{getline; gsub(/[[:space:]]/,""); print; exit}' Gemfile.lock)"
gem install bundler -v "$bundler_version" --no-document

- name: Restore gem bundle
id: bundle-cache
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: vendor/bundle
key: bundle-${{ runner.os }}-ruby-${{ steps.ruby.outputs.version }}-${{ hashFiles('Gemfile.lock') }}

- name: Install gems
shell: bash
run: |
bundle config set --local path vendor/bundle
bundle config set --local deployment true
bundle install --jobs 4
25 changes: 13 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@
# ─── LINT + SECURITY ─────────────────────────────────────
lint:
runs-on: ubuntu-24.04
timeout-minutes: 10
# Higher than the usual 10 to absorb a cold Ruby-from-source compile on the
# first run after a version bump; cached runs are back to normal.
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1
with:
ruby-version: '.ruby-version'
bundler-cache: true
# TEMPORARY: source-build Ruby because ruby-builder has no prebuilt binary
# for the pinned version yet. Revert to ruby/setup-ruby once it does.
- uses: ./.github/actions/setup-ruby-source
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: '.nvmrc'
Expand Down Expand Up @@ -81,7 +82,9 @@
# ─── BACKEND TESTS + COVERAGE (6 shards) ─────────────────
backend:
runs-on: ubuntu-24.04
timeout-minutes: 25
# Higher than the usual 25 to absorb a cold Ruby-from-source compile on the
# first run after a version bump; cached runs are back to normal.
timeout-minutes: 35
permissions:
contents: read
strategy:
Expand Down Expand Up @@ -141,17 +144,15 @@
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 1
- uses: ruby/setup-ruby@e65c17d16e57e481586a6a5a0282698790062f92 # v1
with:
ruby-version: '.ruby-version'
bundler-cache: true
# TEMPORARY: source-build Ruby because ruby-builder has no prebuilt binary
# for the pinned version yet. Revert to ruby/setup-ruby once it does.
# (This action also installs libpq-dev and the gem bundle.)
- uses: ./.github/actions/setup-ruby-source
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install --frozen-lockfile
- name: Install system dependencies
run: sudo apt-get -yqq install libpq-dev

- name: Cache JS build
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
Expand Down Expand Up @@ -201,9 +202,9 @@

- name: Build production image with Bake
run: >-
docker buildx bake
--file docker-bake.hcl
--set *.cache-from=type=gha

Check warning on line 207 in .github/workflows/ci.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefix files and paths with "./" or "--" when using glob.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-zcaXOpapJ23NeU9Xi&open=AZ-zcaXOpapJ23NeU9Xi&pullRequest=744
--set *.cache-to=type=gha,mode=max
--set *.output=type=docker
--set *.platform=linux/amd64
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.4.9
3.4.10
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ruby 3.4.9
ruby 3.4.10
nodejs 22.13.1
34 changes: 16 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@
# docker buildx build --platform linux/amd64,linux/arm64 --target production -t vulcan:prod .
# =============================================================================

ARG RUBY_VERSION=3.4.9
ARG RUBY_VERSION=3.4.10
# Upstream SHA256 from https://www.ruby-lang.org/en/news/<release>/
ARG RUBY_SHA256=7bb4d4f5e807cc27251d14d9d6086d182c5b25875191e44ab15b709cd7a7dd9c
# 3.4.10 (2026-06-30) ships default gem erb 4.0.4.1 (CVE-2026-41316) and
# net-imap 0.5.15 (CVE-2026-4224x) — clears the ruby-layer default-gem findings.
ARG RUBY_SHA256=ecee2d072a14f2d14347dd56dfd8fe5c3130abf5117bfaacbda0f4ef9cc429ec
ARG BUNDLER_VERSION=2.7.2
ARG NODE_VERSION=24.14.0
ARG NODE_VERSION=24.18.0

# =============================================================================
# BASE STAGE - Common foundation for all stages
# =============================================================================
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.7 AS base
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.7@sha256:907b68736aa798b2d38255b7aa070b2a70acb90803864a40f05d0ec47556ddd0 AS base

Check warning on line 30 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use either the version tag or the digest for the image instead of both.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_D&open=AZ-nD54j7Nsapz3kwv_D&pullRequest=744

USER 0

Expand Down Expand Up @@ -115,32 +117,32 @@
# findutils, tar, xz are kept here (build-time only) and intentionally
# excluded from the base stage — they're not needed at runtime.

RUN curl -fsSL https://cache.ruby-lang.org/pub/ruby/${RUBY_VERSION%.*}/ruby-${RUBY_VERSION}.tar.gz -o /tmp/ruby.tar.gz && \
RUN curl -fsSL --proto '=https' --proto-redir '=https' https://cache.ruby-lang.org/pub/ruby/${RUBY_VERSION%.*}/ruby-${RUBY_VERSION}.tar.gz -o /tmp/ruby.tar.gz && \

Check warning on line 120 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this invocation of "curl" with the ADD instruction.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_E&open=AZ-nD54j7Nsapz3kwv_E&pullRequest=744

Check warning on line 120 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_G&open=AZ-nD54j7Nsapz3kwv_G&pullRequest=744

Check warning on line 120 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_H&open=AZ-nD54j7Nsapz3kwv_H&pullRequest=744
Comment thread
wdower marked this conversation as resolved.
Dismissed
echo "${RUBY_SHA256} /tmp/ruby.tar.gz" | sha256sum -c - && \
tar -xzf /tmp/ruby.tar.gz -C /tmp && \
tar --no-same-owner -xzf /tmp/ruby.tar.gz -C /tmp && \
cd /tmp/ruby-${RUBY_VERSION} && \

Check warning on line 123 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_I&open=AZ-nD54j7Nsapz3kwv_I&pullRequest=744
./configure --prefix=/usr/local \
--disable-install-doc \
--enable-yjit && \
make -j"$(nproc)" && \
make install && \
gem update --system --no-document && \
gem install bundler:${BUNDLER_VERSION} --no-document && \

Check warning on line 130 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_J&open=AZ-nD54j7Nsapz3kwv_J&pullRequest=744
chown -R 1000:0 /usr/local/bundle && \
chmod -R g=u /usr/local/bundle && \
cd /tmp && \
rm -rf /tmp/ruby-${RUBY_VERSION} /tmp/ruby.tar.gz && \

Check warning on line 134 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_K&open=AZ-nD54j7Nsapz3kwv_K&pullRequest=744
ruby --version && \
bundle --version

# jemalloc — UBI doesn't ship it; compile from source for ~20-30% memory savings.
ARG JEMALLOC_VERSION=5.3.0
ARG JEMALLOC_SHA256=2db82d1e7119df3e71b7640219b6dfe84789bc0537983c3b7ac4f7189aecfeaa
RUN curl -fsSL https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2 \
RUN curl -fsSL --proto '=https' --proto-redir '=https' https://github.com/jemalloc/jemalloc/releases/download/${JEMALLOC_VERSION}/jemalloc-${JEMALLOC_VERSION}.tar.bz2 \

Check warning on line 141 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_O&open=AZ-nD54j7Nsapz3kwv_O&pullRequest=744

Check warning on line 141 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_N&open=AZ-nD54j7Nsapz3kwv_N&pullRequest=744
Comment thread
wdower marked this conversation as resolved.
Dismissed
-o /tmp/jemalloc.tar.bz2 && \

Check warning on line 142 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this invocation of "curl" with the ADD instruction.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_L&open=AZ-nD54j7Nsapz3kwv_L&pullRequest=744
echo "${JEMALLOC_SHA256} /tmp/jemalloc.tar.bz2" | sha256sum -c - && \
tar -xjf /tmp/jemalloc.tar.bz2 -C /tmp && \
tar --no-same-owner -xjf /tmp/jemalloc.tar.bz2 -C /tmp && \
cd /tmp/jemalloc-${JEMALLOC_VERSION} && \

Check warning on line 145 in Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Surround this variable with double quotes; otherwise, it can lead to unexpected behavior.

See more on https://sonarcloud.io/project/issues?id=mitre_vulcan&issues=AZ-nD54j7Nsapz3kwv_P&open=AZ-nD54j7Nsapz3kwv_P&pullRequest=744
./configure --prefix=/usr/local && \
make -j"$(nproc)" && \
make install && \
Expand All @@ -155,11 +157,11 @@
ENV PATH="/opt/node/bin:${PATH}"
RUN ARCH=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "arm64") && \
NODE_TARBALL="node-v${NODE_VERSION}-linux-${ARCH}.tar.xz" && \
curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}" -o /tmp/node.tar.xz && \
curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" -o /tmp/node.sha256 && \
curl -fsSL --proto '=https' --proto-redir '=https' "https://nodejs.org/dist/v${NODE_VERSION}/${NODE_TARBALL}" -o /tmp/node.tar.xz && \
Comment thread
wdower marked this conversation as resolved.
Dismissed
curl -fsSL --proto '=https' --proto-redir '=https' "https://nodejs.org/dist/v${NODE_VERSION}/SHASUMS256.txt" -o /tmp/node.sha256 && \
Comment thread
wdower marked this conversation as resolved.
Dismissed
awk -v t="${NODE_TARBALL}" '$2 == t { print $1 " /tmp/node.tar.xz" }' /tmp/node.sha256 | sha256sum -c - && \
mkdir -p /opt/node && \
tar -xJf /tmp/node.tar.xz -C /opt/node --strip-components=1 && \
tar --no-same-owner -xJf /tmp/node.tar.xz -C /opt/node --strip-components=1 && \
rm -f /tmp/node.tar.xz /tmp/node.sha256 && \
corepack enable

Expand All @@ -176,18 +178,16 @@
BUNDLE_DEPLOYMENT="1" \
BUNDLE_WITHOUT="development:test"

COPY --chown=1000:0 --chmod=440 Gemfile Gemfile.lock ./
COPY --chown=1000:0 . .

RUN --mount=type=cache,target=/usr/local/bundle/cache,uid=1000 \
bundle install && \
rm -rf "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile

COPY --chown=1000:0 --chmod=440 package.json yarn.lock esbuild.config.js ./
RUN --mount=type=cache,target=/tmp/.yarn-cache,uid=1000 \
yarn install --frozen-lockfile --production=false --network-timeout 100000 --cache-folder /tmp/.yarn-cache

COPY --chown=1000:0 . .

RUN bundle exec bootsnap precompile app/ lib/ && \
SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile && \
rm -rf \
Expand Down Expand Up @@ -235,10 +235,8 @@
BUNDLE_DEPLOYMENT="0" \
LD_PRELOAD="/usr/local/lib/libjemalloc.so"

COPY --chown=1000:0 --chmod=440 Gemfile Gemfile.lock ./
COPY --chown=1000:0 Gemfile Gemfile.lock package.json yarn.lock esbuild.config.js ./
RUN bundle install

COPY --chown=1000:0 --chmod=440 package.json yarn.lock esbuild.config.js ./
RUN yarn install --frozen-lockfile

COPY --chown=1000:0 . .
Expand Down
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

source 'https://rubygems.org'

ruby '3.4.9'
ruby '3.4.10'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 8.0.0'
Expand Down Expand Up @@ -156,3 +156,5 @@ gem 'blueprinter', '~> 1.2'
gem 'blueprinter-activerecord', '~> 1.3'

gem 'oj', '~> 3.16'

gem 'faraday', '~> 1.10', '>= 1.10.6'
Loading
Loading