diff --git a/app/controllers/execution_environments_controller.rb b/app/controllers/execution_environments_controller.rb index 0db96e9c..05e58acb 100644 --- a/app/controllers/execution_environments_controller.rb +++ b/app/controllers/execution_environments_controller.rb @@ -113,9 +113,10 @@ class ExecutionEnvironmentsController < ApplicationController [] end - params[:execution_environment].permit(:docker_image, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :cpu_limit, :name, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework).merge( - user_id: current_user.id, user_type: current_user.class.name, exposed_ports: exposed_ports - ) + params[:execution_environment] + .permit(:docker_image, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :cpu_limit, :name, + :network_enabled, :privileged_execution, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework) + .merge(user_id: current_user.id, user_type: current_user.class.name, exposed_ports: exposed_ports) end end private :execution_environment_params diff --git a/app/models/execution_environment.rb b/app/models/execution_environment.rb index 53ff0427..d4138000 100644 --- a/app/models/execution_environment.rb +++ b/app/models/execution_environment.rb @@ -27,6 +27,7 @@ class ExecutionEnvironment < ApplicationRecord validates :memory_limit, numericality: {greater_than_or_equal_to: MINIMUM_MEMORY_LIMIT, only_integer: true}, presence: true validates :network_enabled, boolean_presence: true + validates :privileged_execution, boolean_presence: true validates :name, presence: true validates :permitted_execution_time, numericality: {only_integer: true}, presence: true validates :pool_size, numericality: {only_integer: true}, presence: true diff --git a/app/views/execution_environments/_form.html.slim b/app/views/execution_environments/_form.html.slim index 75bf356c..34d8b2b4 100644 --- a/app/views/execution_environments/_form.html.slim +++ b/app/views/execution_environments/_form.html.slim @@ -28,6 +28,10 @@ label.form-check-label = f.check_box(:network_enabled, class: 'form-check-input') = t('activerecord.attributes.execution_environment.network_enabled') + .form-check.mb-3 + label.form-check-label + = f.check_box(:privileged_execution, class: 'form-check-input') + = t('activerecord.attributes.execution_environment.privileged_execution') .mb-3 = f.label(:permitted_execution_time, class: 'form-label') = f.number_field(:permitted_execution_time, class: 'form-control', min: 1) diff --git a/app/views/execution_environments/index.html.slim b/app/views/execution_environments/index.html.slim index 06247a17..40252d11 100644 --- a/app/views/execution_environments/index.html.slim +++ b/app/views/execution_environments/index.html.slim @@ -15,6 +15,7 @@ h1.d-inline-block = ExecutionEnvironment.model_name.human(count: 2) th = t('activerecord.attributes.execution_environment.memory_limit') th = t('activerecord.attributes.execution_environment.cpu_limit') th = t('activerecord.attributes.execution_environment.network_enabled') + th = t('activerecord.attributes.execution_environment.privileged_execution') th = t('activerecord.attributes.execution_environment.permitted_execution_time') th colspan=5 = t('shared.actions') tbody @@ -26,6 +27,7 @@ h1.d-inline-block = ExecutionEnvironment.model_name.human(count: 2) td = execution_environment.memory_limit td = execution_environment.cpu_limit td = symbol_for(execution_environment.network_enabled) + td = symbol_for(execution_environment.privileged_execution) td = execution_environment.permitted_execution_time td = link_to(t('shared.show'), execution_environment) if policy(execution_environment).show? td = link_to(t('shared.edit'), edit_execution_environment_path(execution_environment)) if policy(execution_environment).edit? diff --git a/app/views/execution_environments/show.html.slim b/app/views/execution_environments/show.html.slim index d29ead06..53537db0 100644 --- a/app/views/execution_environments/show.html.slim +++ b/app/views/execution_environments/show.html.slim @@ -11,7 +11,7 @@ h1.d-inline-block = @execution_environment = row(label: 'execution_environment.name', value: @execution_environment.name) = row(label: 'execution_environment.user', value: link_to_if(policy(@execution_environment.author).show?, @execution_environment.author, @execution_environment.author)) = row(label: 'execution_environment.file_type', value: @execution_environment.file_type.present? ? link_to(@execution_environment.file_type, @execution_environment.file_type) : nil) -- [:docker_image, :exposed_ports_list, :memory_limit, :cpu_limit, :network_enabled, :permitted_execution_time, :pool_size].each do |attribute| +- [:docker_image, :exposed_ports_list, :memory_limit, :cpu_limit, :network_enabled, :privileged_execution, :permitted_execution_time, :pool_size].each do |attribute| = row(label: "execution_environment.#{attribute}", value: @execution_environment.send(attribute)) - [:run_command, :test_command].each do |attribute| = row(label: "execution_environment.#{attribute}") do diff --git a/config/locales/de.yml b/config/locales/de.yml index 10e684c7..532960d4 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -24,6 +24,7 @@ de: test_command: Testbefehl testing_framework: Testing-Framework user: Autor + privileged_execution: Priviligierte Ausführung als "root" exercise: average_score_percentage: "Durchschnittliche Bewertung in Prozent" description: Beschreibung diff --git a/config/locales/en.yml b/config/locales/en.yml index 6ae1fcf7..ffd330c7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -24,6 +24,7 @@ en: test_command: Test Command testing_framework: Testing Framework user: Author + privileged_execution: Privileged Execution as "root" exercise: average_score_percentage: "Average Score Percentage" description: Description diff --git a/db/migrate/20220923214003_add_privileged_execution_to_execution_environment.rb b/db/migrate/20220923214003_add_privileged_execution_to_execution_environment.rb new file mode 100644 index 00000000..a011f855 --- /dev/null +++ b/db/migrate/20220923214003_add_privileged_execution_to_execution_environment.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddPrivilegedExecutionToExecutionEnvironment < ActiveRecord::Migration[6.1] + def change + add_column :execution_environments, :privileged_execution, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index ae647191..8e404563 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_09_06_142603) do +ActiveRecord::Schema.define(version: 2022_09_23_214003) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -163,6 +163,7 @@ ActiveRecord::Schema.define(version: 2022_09_06_142603) do t.boolean "network_enabled" t.integer "cpu_limit", default: 20, null: false t.integer "exposed_ports", default: [], array: true + t.boolean "privileged_execution", default: false, null: false end create_table "exercise_collection_items", id: :serial, force: :cascade do |t| @@ -240,7 +241,7 @@ ActiveRecord::Schema.define(version: 2022_09_06_142603) do t.string "name" t.datetime "created_at" t.datetime "updated_at" - t.boolean "platform_admin", default: false, null: false + t.boolean "platform_admin", default: false end create_table "file_templates", id: :serial, force: :cascade do |t| @@ -305,7 +306,7 @@ ActiveRecord::Schema.define(version: 2022_09_06_142603) do t.string "activation_state" t.string "activation_token" t.datetime "activation_token_expires_at" - t.boolean "platform_admin", default: false, null: false + t.boolean "platform_admin", default: false t.index ["activation_token"], name: "index_internal_users_on_activation_token" t.index ["email"], name: "index_internal_users_on_email", unique: true t.index ["remember_me_token"], name: "index_internal_users_on_remember_me_token" diff --git a/lib/runner/strategy/poseidon.rb b/lib/runner/strategy/poseidon.rb index 799a8974..e65f3384 100644 --- a/lib/runner/strategy/poseidon.rb +++ b/lib/runner/strategy/poseidon.rb @@ -245,7 +245,11 @@ class Runner::Strategy::Poseidon < Runner::Strategy def execute_command(command) url = "#{runner_url}/execute" - body = {command: command, timeLimit: @execution_environment.permitted_execution_time} + body = { + command: command, + timeLimit: @execution_environment.permitted_execution_time, + privilegedExecution: @execution_environment.privileged_execution, + } Rails.logger.debug { "#{Time.zone.now.getutc.inspect}: Preparing command execution at #{url}: #{command}" } response = self.class.http_connection.post url, body.to_json diff --git a/spec/factories/execution_environment.rb b/spec/factories/execution_environment.rb index 26aa002e..018bcc72 100644 --- a/spec/factories/execution_environment.rb +++ b/spec/factories/execution_environment.rb @@ -10,6 +10,7 @@ FactoryBot.define do help name { 'CoffeeScript' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'coffee' } @@ -25,6 +26,7 @@ FactoryBot.define do help name { 'HTML5' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'touch' } @@ -42,6 +44,7 @@ FactoryBot.define do help name { 'Java 8' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'make run' } @@ -59,6 +62,7 @@ FactoryBot.define do help name { 'JRuby 1.7' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'jruby %{filename}' } @@ -76,6 +80,7 @@ FactoryBot.define do help name { 'Node.js' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'node %{filename}' } @@ -91,6 +96,7 @@ FactoryBot.define do help name { 'Python 3.4' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'python3 %{filename}' } @@ -108,6 +114,7 @@ FactoryBot.define do help name { 'Ruby 2.2' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 10.seconds } pool_size { 0 } run_command { 'ruby %{filename}' } @@ -126,6 +133,7 @@ FactoryBot.define do help name { 'Sinatra' } network_enabled { true } + privileged_execution { false } permitted_execution_time { 15.minutes } pool_size { 0 } run_command { 'ruby %{filename}' } @@ -143,6 +151,7 @@ FactoryBot.define do help name { 'SQLite' } network_enabled { false } + privileged_execution { false } permitted_execution_time { 1.minute } pool_size { 0 } run_command { 'sqlite3 /database.db -init %{filename} -html' } diff --git a/spec/lib/runner/strategy/poseidon_spec.rb b/spec/lib/runner/strategy/poseidon_spec.rb index 3369a4d0..f10cbd6e 100644 --- a/spec/lib/runner/strategy/poseidon_spec.rb +++ b/spec/lib/runner/strategy/poseidon_spec.rb @@ -247,7 +247,11 @@ describe Runner::Strategy::Poseidon do WebMock .stub_request(:post, "#{described_class.config[:url]}/runners/#{runner_id}/execute") .with( - body: {command: command, timeLimit: execution_environment.permitted_execution_time}, + body: { + command: command, + timeLimit: execution_environment.permitted_execution_time, + privilegedExecution: execution_environment.privileged_execution, + }, headers: {'Content-Type' => 'application/json'} ) .to_return(body: response_body, status: response_status) diff --git a/spec/models/execution_environment_spec.rb b/spec/models/execution_environment_spec.rb index dc11094d..636cd61f 100644 --- a/spec/models/execution_environment_spec.rb +++ b/spec/models/execution_environment_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe ExecutionEnvironment do - let(:execution_environment) { described_class.create.tap {|execution_environment| execution_environment.update(network_enabled: nil) } } + let(:execution_environment) { described_class.create.tap {|execution_environment| execution_environment.update(network_enabled: nil, privileged_execution: nil) } } it 'validates that the Docker image works' do allow(execution_environment).to receive(:validate_docker_image?).and_return(true) @@ -56,6 +56,12 @@ describe ExecutionEnvironment do expect(execution_environment.errors[:network_enabled]).to be_blank end + it 'validates the presence of the privileged_execution enabled flag' do + expect(execution_environment.errors[:privileged_execution]).to be_present + execution_environment.update(privileged_execution: false) + expect(execution_environment.errors[:privileged_execution]).to be_blank + end + it 'validates the numericality of the permitted run time' do execution_environment.update(permitted_execution_time: Math::PI) expect(execution_environment.errors[:permitted_execution_time]).to be_present