Skip to content

Commit

Permalink
Add support for GitHub Codespaces and port forwarding
Browse files Browse the repository at this point in the history
GitHub Codespaces is a commercial offering for devcontainers. While our setup mostly works out-of-the-box, the host and port forwarding required further adjustments to work as expected.
  • Loading branch information
MrSerth committed Sep 25, 2024
1 parent 9a6d59f commit 3d1f0a3
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 6 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# CodeHarbor

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/openHPI/codeharbor)

[![Build Status](https://github.com/openHPI/codeharbor/workflows/CI/badge.svg)](https://github.com/openHPI/codeharbor/actions?query=workflow%3ACI)
[![codecov](https://codecov.io/gh/openHPI/codeharbor/branch/master/graph/badge.svg?token=lUL0Fq7Uc9)](https://codecov.io/gh/openHPI/codeharbor)

Expand Down
5 changes: 5 additions & 0 deletions bin/shakapacker-dev-server
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ ENV['SHAKAPACKER_USE_PACKAGE_JSON_GEM'] ||= 'true'
require 'bundler/setup'
require 'shakapacker'
require 'shakapacker/dev_server_runner'
require_relative '../config/initializers/github_codespaces'

APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
if GithubCodespaces.active?
ARGV.push('--client-web-socket-url', GithubCodespaces.client_web_socket_url)
end

Shakapacker::DevServerRunner.run(ARGV)
end
11 changes: 9 additions & 2 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# frozen_string_literal: true

require 'active_support/core_ext/integer/time'
require_relative '../initializers/github_codespaces'

Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

# Allowed IPs for the Vagrant setup
config.web_console.allowed_ips = '192.168.0.0/16'
if GithubCodespaces.active? || ENV.fetch('USER', nil) == 'vagrant'
# Allow the webconsole to be used; all traffic is proxied and thus appears to come from a private IP
# By default, GitHub requires an authorization to access a Codespaces domain.
# Vagrant is running locally in a private network and thus not accessible from the outside anyway.
private_ips = %w[10.0.0.0/8 172.16.0.0/12 192.168.0.0/16]
config.web_console.permissions = private_ips
private_ips.each {|ip| BetterErrors::Middleware.allow_ip! ip }
end

# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
Expand Down
15 changes: 12 additions & 3 deletions config/initializers/content_security_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
require_relative 'sentry_csp'
require_relative 'sentry_javascript'
require_relative 'devise'
require_relative 'github_codespaces'

module CSP
def self.apply_yml_settings_for(policy)
Expand All @@ -35,6 +36,13 @@ def self.apply_omniauth_settings_for(policy)
end
end

def self.apply_codespaces_settings_for(policy)
%w[wss https].each do |scheme|
url = GithubCodespaces.url_for(:webpack_dev_server, scheme)
add_policy(policy, :connect_src, [url])
end
end

def self.add_policy(policy, directive, additional_settings)
all_settings = additional_settings
existing_settings = if directive == 'report_uri'
Expand Down Expand Up @@ -98,9 +106,10 @@ def self.get_host_source(url)
# "An iframe which has both allow-scripts and allow-same-origin for its sandbox attribute can escape its sandboxing."
policy.sandbox 'allow-downloads', 'allow-forms', 'allow-modals', 'allow-popups', 'allow-same-origin', 'allow-scripts'

CSP.apply_yml_settings_for policy
CSP.apply_sentry_settings_for policy if SentryJavascript.active?
CSP.apply_omniauth_settings_for policy if Devise.omniauth_configs.present?
CSP.apply_yml_settings_for policy
CSP.apply_sentry_settings_for policy if SentryJavascript.active?
CSP.apply_omniauth_settings_for policy if Devise.omniauth_configs.present?
CSP.apply_codespaces_settings_for policy if GithubCodespaces.active?
end

# Generate session nonces for permitted importmap, inline scripts, and inline styles.
Expand Down
51 changes: 51 additions & 0 deletions config/initializers/github_codespaces.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

class GithubCodespaces
def self.active?
ENV['CODESPACES'] == 'true'
end

def self.client_web_socket_url
"#{url_for(:webpack_dev_server, 'wss')}/ws"
end

def self.url_for(server, scheme = 'https')
"#{scheme}://#{domain_for(server)}"
end

def self.domain_for(server)
port = send(server)
hostname_for(port)
end

class << self
private

def hostname_for(port)
codespace_name = ENV.fetch('CODESPACE_NAME')
forwarding_domain = ENV.fetch('GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN')

"#{codespace_name}-#{port}.#{forwarding_domain}"
end

def rails_server
ENV.fetch('PORT', 7500)
end

def webpack_dev_server
ENV.fetch('SHAKAPACKER_DEV_SERVER_PORT', 3045)
end
end
end

if GithubCodespaces.active? && defined? Rails
Rails.application.configure do
# Allow the Rails server to be accessed from the Codespaces domain
config.hosts << GithubCodespaces.domain_for(:rails_server)

# Disable an additional CSRF protection, where the browser's ORIGIN header is
# checked against the site's request URL. Since the Codespaces proxy is not setting
# all required X-FORWARDED-* headers, we currently need to disable this check.
config.action_controller.forgery_protection_origin_check = false
end
end
12 changes: 11 additions & 1 deletion docs/LOCAL_SETUP_DEVCONTAINER.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Devcontainer setup

With the devcontainer-based setup, you won't need to (manually) install CodeHarbor and all dependencies on your local instance. Instead, a Docker setup containing all requirements will be configured. The development environment is defined in the `.devcontainer` repository folder and will be applied when you open the project in a supported editor or IDE.
With the devcontainer-based setup, you won't need to (manually) install CodeHarbor and all dependencies on your local instance. Instead, a Docker setup containing all requirements will be configured.

You can either run a devcontainer locally (with Docker) or remotely (e.g., with GitHub Codespaces). In both cases, the development environment is defined in the `.devcontainer` repository folder and will be applied when you open the project in a supported editor or IDE.

## Local setup

Expand Down Expand Up @@ -53,6 +55,14 @@ Click on the blue "Reopen in Container" button in the bottom right corner of you
**RubyMine:** / **IntelliJ IDEA:**
Open the file `.devcontainer/devcontainer.json` and click on the blue Docker icon in the top left corner of your editor. More information for [RubyMine](https://www.jetbrains.com/help/ruby/connect-to-devcontainer.html#create_dev_container_inside_ide) or [IntelliJ IDEA](https://www.jetbrains.com/help/idea/connect-to-devcontainer.html#create_dev_container_inside_ide).

## Remote setup with GitHub Codespaces

You can also run the devcontainer remotely with GitHub Codespaces. This way, you can develop CodeHarbor in the cloud without the need to install any dependencies on your local machine.

To get started with GitHub Codespaces, click on the ["Open in GitHub Codespaces"](https://codespaces.new/openHPI/codeharbor) button at the top of the [README.md file](../README.md). This will open the project in a new Codespace. You can find more information on how to set up your project for Codespaces in the [official documentation](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers).

# Start CodeHarbor

When developing with the devcontainer, you can run CodeHarbor in the same way as you would on your local machine. The only difference is that you're running it inside the devcontainer. You can find more information on how to run CodeHarbor in the [LOCAL_SETUP.md](LOCAL_SETUP.md#start-codeharbor). All ports are forwarded to your local machine, so you can access CodeHarbor in your browser as usual.

In GitHub Codespaces, the ports are forwarded automatically, so you can access CodeHarbor in your browser by clicking on the "Open in Browser" button in the Codespaces environment as soon as the Rails server was started. [More information](https://docs.github.com/de/codespaces/developing-in-a-codespace/forwarding-ports-in-your-codespace).

0 comments on commit 3d1f0a3

Please sign in to comment.