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
65 changes: 65 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Test

on:
pull_request:
push:
branches:
- main

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest-4-cores
timeout-minutes: 15

steps:
- name: Checkout code
uses: actions/checkout@v4

- uses: depot/setup-action@v1

- name: Install logstream
run: |
curl -L https://github.com/codecrafters-io/logstream/releases/download/v0.2.2/v0.2.2_linux_amd64 -o /usr/local/bin/logstream
chmod +x /usr/local/bin/logstream

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: Install Fails: System Write Permission Denied

The logstream installation writes to /usr/local/bin/logstream without sudo, which will fail with a permission denied error on GitHub Actions runners. The runner doesn't have write permissions to /usr/local/bin without elevated privileges.

Fix in Cursor Fix in Web


- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: "1.25"

- name: Set up ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3.5
bundler-cache: true
cache-version: 5
working-directory: builder

- name: Run make refresh_test_fixtures
run: make refresh_test_fixtures
working-directory: builder

# Required for pulling git-api and git-daemon
- name: Authenticate with ghcr.io
run: echo '${{ secrets.CI_DOCKER_AUTH_PAT }}' | docker login ghcr.io -u codecrafters-bot --password-stdin

# Required by build_image
- name: Authenticate with registry.fly.io
run: echo '${{ secrets.FLY_ACCESS_TOKEN }}' | docker login registry.fly.io -u x --password-stdin

- name: Set up Docker
run: docker compose up -d
working-directory: builder

- name: Set up Git
run: |
git config --global user.email "you@example.com"
git config --global user.name "Your Name"

- name: Run tests
run: cp .env.example .env && make test
working-directory: builder
24 changes: 22 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ FROM debian:bookworm-slim
# Install deps
RUN apt-get update && apt-get install -y curl wget jq tar git docker.io

# Install Go
RUN wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz -O /tmp/go.tar.gz && \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: Go Version Format Breaks Docker Builds

The Dockerfile attempts to download go1.25.0.linux-amd64.tar.gz, but Go releases don't use .0 for the initial minor version release. The correct URL should be go1.25.linux-amd64.tar.gz (without the .0). This will cause the download to fail with a 404 error during the Docker build.

Fix in Cursor Fix in Web

rm -rf /usr/local/go && \
tar -C /usr/local -xzf /tmp/go.tar.gz && \
rm /tmp/go.tar.gz

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

# Ensure Go is installed and working
RUN go version

# Install depot
RUN curl -fsSL https://depot.dev/install-cli.sh -o /tmp/install-cli.sh && \
sh /tmp/install-cli.sh 2.100.12 && \
Expand All @@ -14,6 +25,15 @@ ENV PATH="/root/.depot/bin:$PATH"
# Ensure depot is installed and working
RUN depot --version

# Download test runner CLI
COPY builder/ /tmp/builder/
RUN cd /tmp/builder && go build -o /var/opt/test-runner-builder main.go

# Ensure the Go program is installed and working
RUN /var/opt/test-runner-builder --version

# Download test runner to a directory (mounted during docker builds)
COPY download_test_runner.sh /tmp/download_test_runner.sh
RUN --mount=type=secret,id=test_runner_downloader_token,env=GITHUB_TOKEN /tmp/download_test_runner.sh
RUN --mount=type=secret,id=test_runner_downloader_token,env=GITHUB_TOKEN /tmp/download_test_runner.sh

# Ensure the test runner is installed and working
RUN /var/opt/test-runner/test-runner --version
6 changes: 6 additions & 0 deletions builder/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# An access token with access to the image we're pushing to
FLY_ACCESS_TOKEN="FlyV1 fm2_lJPECAAAAAAAAFu1xBDrE74JtpQtL/bs+u0CJiAlwrVodHRwczovL2FwaS5mbHkuaW8vdjGWAJLNzSMfC5O5aHR0cHM6Ly9hcGkuZmx5LmlvL2FhYS92McQ8WBLmZVkPM+bp+MYa59roq4p6RFGZOPyD4t7nrtfytR5QBg98z5akYSJcTjdQTua4QzBDT++kXlJi2W27xEWjm09GHI3BdcjBvMxe2c8jiT8KYneORr3tDZU+4lSvtJPDPaOnMVgNGb7NhJBhbP5sbY3oC93TYOco5L6xYEStTEKq4xUNkpQDkYHOABtQrB8FkYKnYnVpbGRlch+id2cfAcQgU/LVB8aWvqkvnRbRKd42i//Yvd5T73HVF0WxfsZ1Xbk=,fm2_lJPERaObT0YcjcF1yMG8zF7ZzyOJPwpid45Gve0NlT7iVK+0k8M9o6cxWA0Zvs2EkGFs/mxtjegL3dNg5yjkvrFgRK1MQqrjFcQQKZ82IUHac0JAIRLvYvaGEcO5aHR0cHM6Ly9hcGkuZmx5LmlvL2FhYS92MZYEks5lqHCMzwAAAAEhoI6qCpHNTwQMxBDpPM5My6ihVldeuGRWbT4vxCCF+j8afdZU4B5W/rcGBV34Ky0zOuVErci6LlBvm+xgsA=="

# A depot project & token
DEPOT_PROJECT="jlmt2zdb5m" # test-runner-ci
DEPOT_TOKEN="depot_project_e252ea64749beae1c983d2f95c952c892cb211c3a0e4aff1fe9ceb5bd14fc0a5"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: Sensitive Data in Example Environment

The .env.example file contains what appear to be real credentials including FLY_ACCESS_TOKEN and DEPOT_TOKEN with actual token values. Example environment files should contain placeholder values, not real secrets. These credentials should be removed and replaced with dummy placeholders like "your-token-here".

Fix in Cursor Fix in Web

5 changes: 5 additions & 0 deletions builder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.vagrant/

tests/fixtures/
dist
.env
1 change: 1 addition & 0 deletions builder/.ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.3.5
48 changes: 48 additions & 0 deletions builder/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }

# Test Runner
gem "minitest"

# GitHub SDK
gem "octokit"

# Debugging
gem "pry"

# Parallel processing
gem "pmap"

# Formatter
gem "standard"

# Docker SDK
gem "docker-api"

# HTTParty
gem "httparty"
gem "faraday-retry"

# Web Server
gem "sinatra", require: false
gem "puma"

# Database
gem "sqlite3"
gem "activerecord"

# Spawn processes
gem "childprocess"
gem "tty-command"

# .env files
gem "dotenv"

# Autoloading
gem "zeitwerk"

# Ending minitest tests early
gem "minitest-fail-fast"
160 changes: 160 additions & 0 deletions builder/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
GEM
remote: https://rubygems.org/
specs:
activemodel (7.1.1)
activesupport (= 7.1.1)
activerecord (7.1.1)
activemodel (= 7.1.1)
activesupport (= 7.1.1)
timeout (>= 0.4.0)
activesupport (7.1.1)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
base64 (0.1.1)
bigdecimal (3.1.4)
childprocess (4.1.0)
coderay (1.1.3)
concurrent-ruby (1.2.2)
connection_pool (2.4.1)
docker-api (2.2.0)
excon (>= 0.47.0)
multi_json
dotenv (2.8.1)
drb (2.1.1)
ruby2_keywords
excon (0.104.0)
faraday (2.7.11)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
faraday-retry (2.2.0)
faraday (~> 2.0)
httparty (0.21.0)
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
json (2.6.3)
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.8.4)
minitest (5.20.0)
minitest-fail-fast (0.1.0)
minitest (~> 5)
multi_json (1.15.0)
multi_xml (0.6.0)
mustermann (3.0.0)
ruby2_keywords (~> 0.0.1)
mutex_m (0.1.2)
nio4r (2.5.9)
octokit (7.2.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
parallel (1.23.0)
parser (3.2.2.4)
ast (~> 2.4.1)
racc
pastel (0.8.0)
tty-color (~> 0.5)
pmap (1.1.1)
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (5.0.3)
puma (6.4.0)
nio4r (~> 2.0)
racc (1.7.1)
rack (2.2.7)
rack-protection (3.0.6)
rack
rainbow (3.1.1)
regexp_parser (2.8.2)
rexml (3.2.6)
rubocop (1.56.4)
base64 (~> 0.1.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.2.2.3)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
parser (>= 3.2.1.0)
rubocop-performance (1.19.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
sinatra (3.0.6)
mustermann (~> 3.0)
rack (~> 2.2, >= 2.2.4)
rack-protection (= 3.0.6)
tilt (~> 2.0)
sqlite3 (1.6.7)
mini_portile2 (~> 2.8.0)
standard (1.31.2)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.56.4)
standard-custom (~> 1.0.0)
standard-performance (~> 1.2)
standard-custom (1.0.2)
lint_roller (~> 1.0)
rubocop (~> 1.50)
standard-performance (1.2.1)
lint_roller (~> 1.1)
rubocop-performance (~> 1.19.1)
tilt (2.2.0)
timeout (0.4.0)
tty-color (0.6.0)
tty-command (0.10.1)
pastel (~> 0.8)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
zeitwerk (2.6.12)

PLATFORMS
ruby

DEPENDENCIES
activerecord
childprocess
docker-api
dotenv
faraday-retry
httparty
minitest
minitest-fail-fast
octokit
pmap
pry
puma
sinatra
sqlite3
standard
tty-command
zeitwerk

BUNDLED WITH
2.4.20
62 changes: 62 additions & 0 deletions builder/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
current_patch_number := $(shell git tag --list "v0.3.*" | sort -V | tail -n 1 | cut -c 6-)
next_patch_number := $(shell echo $$(($(current_patch_number)+1)))
next_version_tag := v0.3.$(next_patch_number)

# Releases are automatically created on pushes to `main`, but this can be used to manually create a release.
release:
git tag $(next_version_tag)
git push origin main $(next_version_tag)

build_linux:
# -mod=mod is required to ensure that go isn't confused by Ruby's vendor/bundle directory
# CGO_ENABLED=0 ensures that the binary is statically linked and doesn't depend on any shared libraries
GOOS=linux CGO_ENABLED=0 go build -mod=mod -o dist/main-linux.out ./

build_native:
# -mod=mod is required to ensure that go isn't confused by Ruby's vendor/bundle directory
# CGO_ENABLED=0 ensures that the binary is statically linked and doesn't depend on any shared libraries
CGO_ENABLED=0 go build -mod=mod -o dist/main.out ./

build: build_linux build_native

print_next_version_tag:
@echo $(next_version_tag) | tr -d '\n'

refresh_test_fixtures:
rm -rf ./tests/fixtures
mkdir -p ./tests/fixtures
mkdir -p ./tests/fixtures/dockerfiles

rm -rf /tmp/byo-redis
git clone https://github.com/codecrafters-io/build-your-own-redis /tmp/byo-redis
cd /tmp/byo-redis && git checkout 5ce64229f59108851de28c4f083f3459d58eff34

rm -rf /tmp/byo-sqlite
git clone https://github.com/codecrafters-io/build-your-own-sqlite /tmp/byo-sqlite
cd /tmp/byo-sqlite && git checkout 8f419979fb7b3eb95cd2d0547f084032cf9edf39

rm -rf ./tests/fixtures/redis-ruby-pass-stage-1
cp -R /tmp/byo-redis/solutions/ruby/01-jm1/code ./tests/fixtures/redis-ruby-pass-stage-1
cp /tmp/byo-redis/dockerfiles/ruby-3.3.Dockerfile ./tests/fixtures/dockerfiles/redis-ruby-3.3.Dockerfile

rm -rf ./tests/fixtures/redis-rust-pass-stage-1
cp -R /tmp/byo-redis/solutions/rust/01-jm1/code ./tests/fixtures/redis-rust-pass-stage-1
cp /tmp/byo-redis/dockerfiles/rust-1.88.Dockerfile ./tests/fixtures/dockerfiles/redis-rust-1.88.Dockerfile

rm -rf ./tests/fixtures/redis-go-pass-stage-1
cp -R /tmp/byo-redis/solutions/go/01-jm1/code ./tests/fixtures/redis-go-pass-stage-1
cp /tmp/byo-redis/dockerfiles/go-1.24.Dockerfile ./tests/fixtures/dockerfiles/redis-go-1.24.Dockerfile

rm -rf ./tests/fixtures/sqlite-python-pass-stage-1
cp -R /tmp/byo-sqlite/solutions/python/01-dr6/code ./tests/fixtures/sqlite-python-pass-stage-1
cp /tmp/byo-sqlite/dockerfiles/python-3.13.Dockerfile ./tests/fixtures/dockerfiles/sqlite-python-3.13.Dockerfile

test: test_go test_build_image

test_go:
# -mod=mod is required to ensure that go isn't confused by Ruby's vendor/bundle directory
go test -mod=mod ./...

test_build_image: build
bundle exec ruby tests/build_image_test.rb --verbose --fail-fast

Loading
Loading