├── .dockerignore ├── .github ├── FUNDING.yml ├── judge0-colored.png ├── sequence-diagram.png ├── sequence-diagram.svg ├── sequence-diagram.txt └── wallpaper.png ├── .gitignore ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── PRIVACY_POLICY.md ├── README.md ├── Rakefile ├── SPONSORSHIP.md ├── TELEMETRY.md ├── agricius ├── app ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── health_controller.rb │ ├── home_controller.rb │ ├── info_controller.rb │ ├── languages_controller.rb │ ├── sessions_controller.rb │ ├── statuses_controller.rb │ └── submissions_controller.rb ├── enumerations │ └── status.rb ├── helpers │ ├── config.rb │ ├── isolate_runner.rb │ ├── nil_value.rb │ └── system_info.rb ├── jobs │ ├── application_job.rb │ └── isolate_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── application_record.rb │ ├── concerns │ │ └── .keep │ ├── language.rb │ └── submission.rb ├── serializers │ ├── language_serializer.rb │ ├── status_serializer.rb │ └── submission_serializer.rb ├── services │ ├── base64_service.rb │ └── fields │ │ └── submission.rb └── views │ └── layouts │ ├── mailer.html.erb │ └── mailer.text.erb ├── bin ├── bundle ├── rails ├── rake ├── setup ├── spring ├── telemetry └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── backtrace_silencers.rb │ ├── cors.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── new_framework_defaults.rb │ ├── resque.rb │ └── wrap_parameters.rb ├── puma.rb ├── routes.rb └── secrets.yml ├── cron ├── clear_cache └── telemetry ├── db ├── languages │ ├── active.rb │ └── archived.rb ├── migrate │ ├── 20160903140859_create_languages.rb │ ├── 20160903211542_create_submissions.rb │ ├── 20160905015919_add_source_file_to_language.rb │ ├── 20160905030833_add_time_to_submission.rb │ ├── 20160907052244_add_memory_to_submission.rb │ ├── 20170131231840_rename_actual_output_in_submissions_to_stdout.rb │ ├── 20170131233631_add_stderr_to_submissions.rb │ ├── 20170201000546_add_token_to_submission.rb │ ├── 20170203021217_add_index_to_submission.rb │ ├── 20170203023903_add_number_of_runs_to_submission.rb │ ├── 20170203215830_add_configuration_to_submission.rb │ ├── 20170422122148_change_encode_all_submissions.rb │ ├── 20170919210318_add_compile_output_to_submissions.rb │ ├── 20170919215014_add_exit_code_exit_signal_and_message_to_submissions.rb │ ├── 20170928174721_add_wall_time_to_submissions.rb │ ├── 20170929175654_rename_input_to_stdin_in_submissions.rb │ ├── 20190921115544_add_compiler_options_to_submission.rb │ ├── 20190921193416_add_command_line_arguments_to_submission.rb │ ├── 20191230001624_add_is_archived_to_languages.rb │ ├── 20200113231131_add_redirect_stderr_to_stdout_to_submission.rb │ ├── 20200114220437_add_callback_url_to_submissions.rb │ ├── 20200115205044_add_additional_files_to_submissions.rb │ ├── 20200327224155_create_clients.rb │ ├── 20210308152656_add_enable_network_to_submissions.rb │ ├── 20220528122710_add_started_at_to_submission.rb │ ├── 20220528131626_add_updated_at_to_submission.rb │ └── 20220528155848_add_hosts_to_submission.rb ├── schema.rb └── seeds.rb ├── docker-compose.dev.yml ├── docker-compose.https.yml ├── docker-compose.server.yml ├── docker-compose.standalone.yml ├── docker-compose.workers.yml ├── docker-compose.yml ├── docker-entrypoint.sh ├── docs ├── api │ ├── _unauthenticated.md │ ├── _unauthorized.md │ ├── authentication │ │ └── authentication.md │ ├── authorization │ │ └── authorization.md │ ├── docs.md │ ├── health_check │ │ ├── health_check.md │ │ └── workers.md │ ├── hostname.html │ ├── information │ │ ├── about.md │ │ ├── information.md │ │ ├── isolate.md │ │ ├── license.md │ │ └── version.md │ ├── statistics │ │ └── statistics.md │ ├── statuses_and_languages │ │ ├── get_a_language.md │ │ ├── get_active_and_archived_languages.md │ │ ├── get_languages.md │ │ ├── get_statuses.md │ │ ├── languages.md │ │ └── statuses_and_languages.md │ ├── style.html │ ├── submissions │ │ ├── create_a_submission.md │ │ ├── create_a_submission_batch.md │ │ ├── delete_a_submission.md │ │ ├── get_a_submission.md │ │ ├── get_a_submission_batch.md │ │ ├── get_submissions.md │ │ └── submissions.md │ └── system_and_configuration │ │ ├── configuration_info.md │ │ ├── system_and_configuration.md │ │ └── system_info.md └── maintainers │ ├── README.md │ └── RELEASE_NOTES_TEMPLATE.md ├── judge0.conf ├── lib └── tasks │ ├── .keep │ ├── auto_annotate_models.rake │ ├── clear_cache.rake │ └── run_submissions_in_queue.rake ├── log └── .keep ├── public ├── docs.html ├── dummy-client.html ├── favicon.ico └── robots.txt ├── scripts ├── dev │ ├── bundle │ ├── clean │ ├── generate-docs │ ├── serve-docs │ └── shell ├── load-config ├── server └── workers ├── spec ├── controllers │ ├── languages_controller_spec.rb │ ├── statuses_controller_spec.rb │ └── submissions_controller_spec.rb ├── factories │ ├── languages.rb │ └── submissions.rb ├── jobs │ └── isolate_job_spec.rb ├── models │ ├── language_spec.rb │ └── submission_spec.rb ├── rails_helper.rb ├── requests │ ├── languages_spec.rb │ └── submissions_spec.rb ├── routing │ ├── languages_routing_spec.rb │ └── submissions_routing_spec.rb ├── spec_helper.rb └── support │ ├── active_model_serializer_matcher.rb │ ├── database_cleaner.rb │ ├── factory_girl.rb │ └── shoulda_matchers.rb ├── tmp └── .keep └── vendor └── .keep /.dockerignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.md 3 | agricius 4 | Dockerfile* 5 | docker-compose* 6 | docs/maintainers/ 7 | judge0.conf 8 | log/* 9 | scripts/dev/ 10 | srv/ 11 | tmp/* -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: hermanzdosilovic 2 | -------------------------------------------------------------------------------- /.github/judge0-colored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/.github/judge0-colored.png -------------------------------------------------------------------------------- /.github/sequence-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/.github/sequence-diagram.png -------------------------------------------------------------------------------- /.github/sequence-diagram.txt: -------------------------------------------------------------------------------- 1 | # https://bramp.github.io/js-sequence-diagrams/ 2 | User->Rails API: createNewSubmission(source_code, language_id, input, expected_output) 3 | Rails API->PostgreSQL: Submission := createSubmission(source_code, language_id, input, expected_output) 4 | PostgreSQL-->>Rails API: created 5 | Rails API->>Redis: createNewJob(submission) 6 | Rails API-->>User: created(id) 7 | Worker->Redis: * IsolateJob := getNextJob() 8 | Worker->Worker: runInSandbox(submission.source_code) 9 | Worker->Worker: determineStatus() 10 | Worker->PostgreSQL: updateSubmission(submission) 11 | User->Rails API: getSubmission(id) 12 | Rails API->PostgreSQL: Submission := findSubmission(id) 13 | PostgreSQL-->>Rails API: 14 | Rails API-->>User: 15 | -------------------------------------------------------------------------------- /.github/wallpaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/.github/wallpaper.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | log/* 2 | tmp/* 3 | !/log/.keep 4 | !/tmp/.keep 5 | .bundle/ 6 | .byebug_history 7 | coverage/ 8 | srv/ 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at hermanz.dosilovic@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM judge0/basewithpythonpackages:latest AS production 2 | 3 | ENV JUDGE0_HOMEPAGE "https://judge0.com" 4 | LABEL homepage=$JUDGE0_HOMEPAGE 5 | 6 | ENV JUDGE0_SOURCE_CODE "https://github.com/judge0/judge0" 7 | LABEL source_code=$JUDGE0_SOURCE_CODE 8 | 9 | ENV JUDGE0_MAINTAINER "Herman Zvonimir Došilović " 10 | LABEL maintainer=$JUDGE0_MAINTAINER 11 | 12 | ENV PATH "/usr/local/ruby-2.7.0/bin:/opt/.gem/bin:$PATH" 13 | ENV GEM_HOME "/opt/.gem/" 14 | 15 | RUN echo "deb http://deb.debian.org/debian buster main" > /etc/apt/sources.list && \ 16 | apt-get update && \ 17 | apt-get install -y --no-install-recommends \ 18 | cron \ 19 | libpq-dev \ 20 | sudo && \ 21 | rm -rf /var/lib/apt/lists/* && \ 22 | echo "gem: --no-document" > /root/.gemrc && \ 23 | gem install bundler:2.1.4 && \ 24 | npm install -g --unsafe-perm aglio@2.3.0 25 | 26 | ENV VIRTUAL_PORT 2358 27 | EXPOSE $VIRTUAL_PORT 28 | 29 | WORKDIR /api 30 | 31 | COPY Gemfile* ./ 32 | RUN RAILS_ENV=production bundle 33 | 34 | COPY cron /etc/cron.d 35 | RUN cat /etc/cron.d/* | crontab - 36 | 37 | COPY . . 38 | 39 | ENTRYPOINT ["/api/docker-entrypoint.sh"] 40 | CMD ["/api/scripts/server"] 41 | 42 | ENV JUDGE0_VERSION "1.13.0" 43 | LABEL version=$JUDGE0_VERSION 44 | 45 | 46 | FROM production AS development 47 | 48 | ARG DEV_USER=judge0 49 | ARG DEV_USER_ID=1000 50 | 51 | RUN apt-get update && \ 52 | apt-get install -y --no-install-recommends \ 53 | tmux \ 54 | vim && \ 55 | useradd -u $DEV_USER_ID -m -r $DEV_USER && \ 56 | echo "$DEV_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers 57 | 58 | USER $DEV_USER 59 | 60 | CMD ["sleep", "infinity"] 61 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '~> 5.0' 4 | gem 'pg', '~> 1.2' 5 | 6 | gem 'active_model_serializers', '~> 0.10' 7 | gem 'enumerations', '~> 2.3' 8 | gem 'httparty', '~> 0.21' 9 | gem 'pry-byebug', '~> 3.9' 10 | gem 'pry-rails', '~> 0.3' 11 | gem 'puma', '~> 5.6' 12 | gem 'rack-cors', '~> 1.1' 13 | gem 'redis', '< 4.6' 14 | gem 'resque', '~> 2.6' 15 | gem 'resque-scheduler', '~> 4.10' 16 | gem 'will_paginate', '~> 3.2' 17 | 18 | group :development do 19 | gem 'annotate', '~> 3.0' 20 | gem 'listen', '~> 3.2' 21 | end 22 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (5.2.8) 5 | actionpack (= 5.2.8) 6 | nio4r (~> 2.0) 7 | websocket-driver (>= 0.6.1) 8 | actionmailer (5.2.8) 9 | actionpack (= 5.2.8) 10 | actionview (= 5.2.8) 11 | activejob (= 5.2.8) 12 | mail (~> 2.5, >= 2.5.4) 13 | rails-dom-testing (~> 2.0) 14 | actionpack (5.2.8) 15 | actionview (= 5.2.8) 16 | activesupport (= 5.2.8) 17 | rack (~> 2.0, >= 2.0.8) 18 | rack-test (>= 0.6.3) 19 | rails-dom-testing (~> 2.0) 20 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 21 | actionview (5.2.8) 22 | activesupport (= 5.2.8) 23 | builder (~> 3.1) 24 | erubi (~> 1.4) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 27 | active_model_serializers (0.10.13) 28 | actionpack (>= 4.1, < 7.1) 29 | activemodel (>= 4.1, < 7.1) 30 | case_transform (>= 0.2) 31 | jsonapi-renderer (>= 0.1.1.beta1, < 0.3) 32 | activejob (5.2.8) 33 | activesupport (= 5.2.8) 34 | globalid (>= 0.3.6) 35 | activemodel (5.2.8) 36 | activesupport (= 5.2.8) 37 | activerecord (5.2.8) 38 | activemodel (= 5.2.8) 39 | activesupport (= 5.2.8) 40 | arel (>= 9.0) 41 | activestorage (5.2.8) 42 | actionpack (= 5.2.8) 43 | activerecord (= 5.2.8) 44 | marcel (~> 1.0.0) 45 | activesupport (5.2.8) 46 | concurrent-ruby (~> 1.0, >= 1.0.2) 47 | i18n (>= 0.7, < 2) 48 | minitest (~> 5.1) 49 | tzinfo (~> 1.1) 50 | annotate (3.2.0) 51 | activerecord (>= 3.2, < 8.0) 52 | rake (>= 10.4, < 14.0) 53 | arel (9.0.0) 54 | builder (3.2.4) 55 | byebug (11.1.3) 56 | case_transform (0.2) 57 | activesupport 58 | coderay (1.1.3) 59 | concurrent-ruby (1.1.10) 60 | crass (1.0.6) 61 | enumerations (2.5.3) 62 | activerecord 63 | activesupport 64 | i18n 65 | erubi (1.10.0) 66 | et-orbi (1.2.7) 67 | tzinfo 68 | ffi (1.15.5) 69 | fugit (1.9.0) 70 | et-orbi (~> 1, >= 1.2.7) 71 | raabro (~> 1.4) 72 | globalid (1.0.1) 73 | activesupport (>= 5.0) 74 | httparty (0.21.0) 75 | mini_mime (>= 1.0.0) 76 | multi_xml (>= 0.5.2) 77 | i18n (1.12.0) 78 | concurrent-ruby (~> 1.0) 79 | jsonapi-renderer (0.2.2) 80 | listen (3.7.1) 81 | rb-fsevent (~> 0.10, >= 0.10.3) 82 | rb-inotify (~> 0.9, >= 0.9.10) 83 | loofah (2.19.1) 84 | crass (~> 1.0.2) 85 | nokogiri (>= 1.5.9) 86 | mail (2.7.1) 87 | mini_mime (>= 0.1.1) 88 | marcel (1.0.2) 89 | method_source (1.0.0) 90 | mini_mime (1.1.2) 91 | mini_portile2 (2.8.1) 92 | minitest (5.17.0) 93 | mono_logger (1.1.2) 94 | multi_json (1.15.0) 95 | multi_xml (0.6.0) 96 | mustermann (3.0.0) 97 | ruby2_keywords (~> 0.0.1) 98 | nio4r (2.5.9) 99 | nokogiri (1.14.3) 100 | mini_portile2 (~> 2.8.0) 101 | racc (~> 1.4) 102 | pg (1.3.5) 103 | pry (0.13.1) 104 | coderay (~> 1.1) 105 | method_source (~> 1.0) 106 | pry-byebug (3.9.0) 107 | byebug (~> 11.0) 108 | pry (~> 0.13.0) 109 | pry-rails (0.3.9) 110 | pry (>= 0.10.4) 111 | puma (5.6.7) 112 | nio4r (~> 2.0) 113 | raabro (1.4.0) 114 | racc (1.6.2) 115 | rack (2.2.8) 116 | rack-cors (1.1.1) 117 | rack (>= 2.0.0) 118 | rack-protection (3.1.0) 119 | rack (~> 2.2, >= 2.2.4) 120 | rack-test (1.1.0) 121 | rack (>= 1.0, < 3) 122 | rails (5.2.8) 123 | actioncable (= 5.2.8) 124 | actionmailer (= 5.2.8) 125 | actionpack (= 5.2.8) 126 | actionview (= 5.2.8) 127 | activejob (= 5.2.8) 128 | activemodel (= 5.2.8) 129 | activerecord (= 5.2.8) 130 | activestorage (= 5.2.8) 131 | activesupport (= 5.2.8) 132 | bundler (>= 1.3.0) 133 | railties (= 5.2.8) 134 | sprockets-rails (>= 2.0.0) 135 | rails-dom-testing (2.0.3) 136 | activesupport (>= 4.2.0) 137 | nokogiri (>= 1.6) 138 | rails-html-sanitizer (1.4.4) 139 | loofah (~> 2.19, >= 2.19.1) 140 | railties (5.2.8) 141 | actionpack (= 5.2.8) 142 | activesupport (= 5.2.8) 143 | method_source 144 | rake (>= 0.8.7) 145 | thor (>= 0.19.0, < 2.0) 146 | rake (13.0.6) 147 | rb-fsevent (0.11.1) 148 | rb-inotify (0.10.1) 149 | ffi (~> 1.0) 150 | redis (4.5.1) 151 | redis-namespace (1.11.0) 152 | redis (>= 4) 153 | resque (2.6.0) 154 | mono_logger (~> 1.0) 155 | multi_json (~> 1.0) 156 | redis-namespace (~> 1.6) 157 | sinatra (>= 0.9.2) 158 | resque-scheduler (4.10.2) 159 | mono_logger (~> 1.0) 160 | redis (>= 3.3) 161 | resque (>= 1.27) 162 | rufus-scheduler (~> 3.2, != 3.3) 163 | ruby2_keywords (0.0.5) 164 | rufus-scheduler (3.9.1) 165 | fugit (~> 1.1, >= 1.1.6) 166 | sinatra (3.1.0) 167 | mustermann (~> 3.0) 168 | rack (~> 2.2, >= 2.2.4) 169 | rack-protection (= 3.1.0) 170 | tilt (~> 2.0) 171 | sprockets (4.0.3) 172 | concurrent-ruby (~> 1.0) 173 | rack (> 1, < 3) 174 | sprockets-rails (3.4.2) 175 | actionpack (>= 5.2) 176 | activesupport (>= 5.2) 177 | sprockets (>= 3.0.0) 178 | thor (1.2.1) 179 | thread_safe (0.3.6) 180 | tilt (2.3.0) 181 | tzinfo (1.2.11) 182 | thread_safe (~> 0.1) 183 | websocket-driver (0.7.5) 184 | websocket-extensions (>= 0.1.0) 185 | websocket-extensions (0.1.5) 186 | will_paginate (3.3.1) 187 | 188 | PLATFORMS 189 | ruby 190 | 191 | DEPENDENCIES 192 | active_model_serializers (~> 0.10) 193 | annotate (~> 3.0) 194 | enumerations (~> 2.3) 195 | httparty (~> 0.21) 196 | listen (~> 3.2) 197 | pg (~> 1.2) 198 | pry-byebug (~> 3.9) 199 | pry-rails (~> 0.3) 200 | puma (~> 5.6) 201 | rack-cors (~> 1.1) 202 | rails (~> 5.0) 203 | redis (< 4.6) 204 | resque (~> 2.6) 205 | resque-scheduler (~> 4.10) 206 | will_paginate (~> 3.2) 207 | 208 | BUNDLED WITH 209 | 2.1.4 210 | -------------------------------------------------------------------------------- /PRIVACY_POLICY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | This document is for those who consume Judge0 and not for those who deploy Judge0 to their own infrastructure. 3 | 4 | If you deploy Judge0 to your own infrastructure then you should read about [telemetry](TELEMETRY.md). 5 | 6 | ## Collected Data 7 | Judge0 does **not** store any personal information. 8 | 9 | For every submission Judge0 stores the data that has been well documented [here](https://api.judge0.com/#submissions-submission). -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require_relative 'config/application' 2 | require 'resque/tasks' 3 | require 'resque/scheduler/tasks' 4 | 5 | task 'resque:setup' => :environment 6 | 7 | Rails.application.load_tasks 8 | -------------------------------------------------------------------------------- /SPONSORSHIP.md: -------------------------------------------------------------------------------- 1 | # Sponsorship 2 | Thank you for considering supporting this project and thus [me](https://github.com/hermanzdosilovic) and my work. There are many ways you can support this project and you might have different motivation or reason to do so. Whatever your reason or motivation is, thank you! 3 | 4 | Every donation is valuable and helps me keep this project free and open-source for everybody. 5 | 6 | ## Common Support 7 | You can support this project by becoming a [Patron](https://www.patreon.com/hermanzdosilovic) or by donating via [PayPal](https://www.patreon.com/hermanzdosilovic) or [Revolut](https://pay.revolut.com/profile/hermancy5). 8 | 9 | This is the simplest yet very welcome and significant way for you to express your appreciation and support the project with your monthly or one-time donation. 10 | 11 | Thank you! 12 | 13 | ## Development Sponsorship 14 | You can directly sponsor the development of the features, bug fixes or anything that is important to you, your organization or company. For the sake of simplicity in the following text I will just reffer to "features", but remember that it can be anything that you want to see in the project. 15 | 16 | Sponsored features are put on the top of the [priority list](https://github.com/judge0/judge0/projects) for one of the next releases and push the development forward by reducing the release cycles. 17 | 18 | ### Sponsorship Protocol 19 | The protocol for development sponsorship is described below. Described protocol is based on two assumptions: 20 | 1. You trust me. I will do the work in the agreed deadline. 21 | 2. I trust you. You will donate agreed amount after the work is done. 22 | 23 | Moreover, with the following protocol I want to keep everything transparent as possible and in the spirit of the open-source values. 24 | 25 | #### 1. Issue Creation 26 | Create a new or choose an existing issue on the [Issues](https://github.com/judge0/judge0/issues) page. It can be anything from feature request, bug fix or documentation update. It can be anything that you would like to see in one of the next releases as soon as possible. 27 | 28 | #### 2. Declare Sponsorship 29 | Add a comment that you, your organization or company is willing to sponsor the development of this feature: 30 | 31 | ``` 32 | This feature will be sponsored by [me|ORGANIZATION NAME](URL). 33 | ``` 34 | 35 | It is important to note who is sponsoring the feature because the name of the sponsor (with the given URL) will be written in the release notes. 36 | 37 | If you, however, want to stay anonymous then comment: 38 | ``` 39 | This feature will be anonymously sponsored. 40 | ``` 41 | 42 | Even though the feature is anonymously sponsored it will be noted as such in the release notes. 43 | 44 | #### 3. (Optional) Specify Your Deadline 45 | If you have a deadline you want me to meet, please specify it. It can be anything from 1 day to 1 year. 46 | 47 | #### 4. Review and Validation 48 | I will then review the feature request and iteratate further with you on its specification before we agree on what exactly will be developed. 49 | 50 | This step is important because I want to develop exactly what you are asking for, so we need to be on the same page. 51 | 52 | I have a full right to reject and close the issue at any point if it does not match my vision of the direction in which the project should go. 53 | 54 | #### 5. Deadline and Offer 55 | I will then tell you in what release this feature can be included and when it can be released. I will also specify the donation amount required for this feature to be developed and released by specified deadline. 56 | 57 | Note that even one sponsored feature can make me do a new release. 58 | 59 | #### 6. Accept or Reject 60 | You can then accept or reject my donation request: 61 | ``` 62 | I [accept|reject] your donation request and deadline. 63 | ``` 64 | 65 | Note that if you reject my donation request it doesn't mean that the issue won't be resolved. It just means that it won't be put on the priority list for the next release. It will be treated as any other issue (non sponsored). 66 | 67 | If you accept my donation request I will add a label `sponsored` on the issue and forward it for the next stage on [Projects](https://github.com/judge0/judge0/projects) page. 68 | 69 | #### 7. Development and Testing 70 | In the development and testing phase I will sometimes send you links to where you can try the new feature. 71 | 72 | For some issues this might not be necessary. 73 | 74 | #### 8. Release 75 | After the development the issue will be closed and the feature will be released in the specified release cycle within agreed deadline. 76 | 77 | After the release I expect you to send the agreed donation amount via [PayPal](https://www.patreon.com/hermanzdosilovic) or [Revolut](https://pay.revolut.com/profile/hermancy5). You can also do this after sixth step. 78 | 79 | ### Notes 80 | 1. Sponsored features **must** stay open-source. 81 | 2. One feature can be sponsored by many sponsors. 82 | 3. One sponsor can sponsor many features. 83 | 84 | ## Other Types of Sponsorships 85 | If you have any other suggestions on how you would like to collaborate or support this project, please send me an [email](https://github.com/hermanzdosilovic) or schedule a [meeting](https://judge0.appointlet.com) with me. -------------------------------------------------------------------------------- /TELEMETRY.md: -------------------------------------------------------------------------------- 1 | # Telemetry 2 | This document is for those who deploy Judge0 to their own infrastructure and not for those who consume Judge0. 3 | 4 | If you just consume Judge0 then you should read the [privacy policy](PRIVACY_POLICY.md). 5 | 6 | ## Introduction 7 | Since version v1.6.0 Judge0 is collecting telemetry data which is used to help understand how to improve the product and to better understand how Judge0 is used in various production environments. 8 | 9 | Our close-source [telemetry client](bin/telemetry) periodically sends telemetry data to our central telemetry server. 10 | 11 | Telemetry reporting is **enabled** by default. 12 | 13 | This document describes how to disable telemetry reporting and what data is collected. 14 | 15 | ## Disabling Telemetry Reporting 16 | To disable telemetry reporting set variable `JUDGE0_TELEMETRY_ENABLE` to `false` in [judge0.conf](judge0.conf). 17 | 18 | ## Collected Data 19 | Every deployed instance of Judge0 with enabled telemetry reporting has its own ID that is used to identify the instance. 20 | 21 | ### The Data Telemetry Client Sends 22 | Your instance of Judge0 will send the new telemetry report to our central telemetry server every 12 hours. Following data is send in the report: 23 | - the ID of your instance and 24 | - the version of your Judge0 instance 25 | 26 | ### The Data Telemetry Server Stores 27 | When the new telemetry report arrives our telemetry server stores the following data: 28 | - all the data that telemetry clients sends and 29 | - timestamp when the report was send 30 | 31 | IP address of your instance is **not** sent or stored. 32 | 33 | Note that only the last report is stored on telemetry server, i.e. the new report overwrites the last report. 34 | 35 | ## Other Notes and Information 36 | 1. You can disable telemetry reporting at any time but the data from the last report stays stored on the telemetry server. -------------------------------------------------------------------------------- /agricius: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Agricius - build tool for Judge0. 4 | # 5 | # Named after Saint Agricius of Trier - protector of carpenters, builders, confectioners, blacksmiths, tailors and butchers. 6 | 7 | _err() { 8 | echo >&2 "Error: $*" 9 | } 10 | 11 | _die() { 12 | _err "$*" 13 | exit 1 14 | } 15 | 16 | __get_argument() { 17 | if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then 18 | echo "$2" 19 | else 20 | _err "Argument for $1 is missing." 21 | fi 22 | } 23 | 24 | _positional_params="" 25 | while [[ $# -gt 0 ]]; do 26 | case "$1" in 27 | --cache-from) 28 | _cache="$(__get_argument $1 $2)"; [[ "$_cache" == "" ]] && exit 1 29 | shift 2 30 | ;; 31 | -*|--*) 32 | _die "Unknown option $1. 33 | Usage: $0 [--cache-from image] command 34 | 35 | Available commands: 36 | build Build Docker images. 37 | publish Push Docker images to repository. Implies build." 38 | ;; 39 | *) 40 | _positional_params="$_positional_params $1" 41 | shift 42 | ;; 43 | esac 44 | done 45 | eval set -- "$_positional_params" 46 | 47 | if [[ "$_cache" != "" ]]; then 48 | docker pull $_cache 49 | _cache="--cache-from $_cache" 50 | fi 51 | 52 | JUDGE0_DOCKER_REPOSITORY=judge0/judge0 53 | 54 | JUDGE0_PROJECT_ROOT="$(git rev-parse --show-toplevel)" 55 | JUDGE0_COMMIT="$(git log -1 --format=%h --abbrev=8)" 56 | JUDGE0_BRANCH="$(git rev-parse --abbrev-ref HEAD)" 57 | 58 | JUDGE0_EDITION="$JUDGE0_BRANCH" 59 | if [[ "$JUDGE0_BRANCH" == "master" ]]; then 60 | JUDGE0_EDITION="standard" 61 | fi 62 | 63 | JUDGE0_EDITION_SLUG="-$JUDGE0_EDITION" 64 | if [[ "$JUDGE0_EDITION" == "standard" ]]; then 65 | JUDGE0_EDITION_SLUG="" 66 | fi 67 | 68 | JUDGE0_VERSION_TAG="$(git tag --points-at HEAD)" 69 | JUDGE0_VERSION="${JUDGE0_VERSION_TAG:1}" # Remove the "v" the beginning. 70 | JUDGE0_VERSION="${JUDGE0_VERSION%-*}" # Remove everything else after "-". 71 | 72 | JUDGE0_PRODUCTION_IMAGES="$JUDGE0_DOCKER_REPOSITORY:$JUDGE0_COMMIT$JUDGE0_EDITION_SLUG" 73 | if [[ "$JUDGE0_VERSION" != "" ]]; then 74 | JUDGE0_PRODUCTION_IMAGES="$JUDGE0_PRODUCTION_IMAGES $JUDGE0_DOCKER_REPOSITORY:latest$JUDGE0_EDITION_SLUG" 75 | JUDGE0_PRODUCTION_IMAGES="$JUDGE0_PRODUCTION_IMAGES $JUDGE0_DOCKER_REPOSITORY:$JUDGE0_VERSION$JUDGE0_EDITION_SLUG" 76 | fi 77 | 78 | JUDGE0_DEVELOPMENT_IMAGES="$JUDGE0_DOCKER_REPOSITORY:$JUDGE0_COMMIT-dev$JUDGE0_EDITION_SLUG" 79 | if [[ "$JUDGE0_VERSION" != "" ]]; then 80 | JUDGE0_DEVELOPMENT_IMAGES="$JUDGE0_DEVELOPMENT_IMAGES $JUDGE0_DOCKER_REPOSITORY:latest$JUDGE0_EDITION_SLUG-dev" 81 | JUDGE0_DEVELOPMENT_IMAGES="$JUDGE0_DEVELOPMENT_IMAGES $JUDGE0_DOCKER_REPOSITORY:$JUDGE0_VERSION$JUDGE0_EDITION_SLUG-dev" 82 | fi 83 | 84 | env | grep JUDGE0_ | sort 85 | 86 | pushd "$JUDGE0_PROJECT_ROOT" 87 | 88 | function build_and_tag() { 89 | local _target=$1 90 | local _images=($2) 91 | local _main_image=${_images[0]} 92 | 93 | set -xe 94 | docker build -t $_main_image $_cache --target $_target . 95 | set +xe 96 | 97 | for (( i=0; i<${#_images[@]}; i++ )) do 98 | docker tag $_main_image ${_images[i]} 99 | done 100 | } 101 | build_and_tag production "$JUDGE0_PRODUCTION_IMAGES" 102 | build_and_tag development "$JUDGE0_DEVELOPMENT_IMAGES" 103 | 104 | _command="$1" 105 | if [[ "$_command" == "publish" ]]; then 106 | if [[ "$JUDGE0_VERSION" == "" ]]; then 107 | _die "Cannot publish untagged version." 108 | fi 109 | _push_images() { 110 | local _images=($1) 111 | for (( i=1; i<${#_images[@]}; i++ )) do 112 | docker push ${_images[i]} 113 | done 114 | } 115 | _push_images "$JUDGE0_PRODUCTION_IMAGES" 116 | _push_images "$JUDGE0_DEVELOPMENT_IMAGES" 117 | fi 118 | 119 | _untag() { 120 | local _images=($1) 121 | for (( i=0; i<${#_images[@]}-1; i++ )) do 122 | docker rmi ${_images[i]} 123 | done 124 | } 125 | _untag "$JUDGE0_PRODUCTION_IMAGES" 126 | _untag "$JUDGE0_DEVELOPMENT_IMAGES" 127 | 128 | popd 129 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < SessionsController 2 | private 3 | 4 | def pagination_dict(collection) 5 | { 6 | current_page: collection.current_page, 7 | next_page: collection.next_page, 8 | prev_page: collection.previous_page, 9 | total_pages: collection.total_pages, 10 | total_count: collection.total_entries 11 | } 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/health_controller.rb: -------------------------------------------------------------------------------- 1 | class HealthController < ApplicationController 2 | def workers 3 | Resque.workers.first.try(:prune_dead_workers) if params[:prune_dead_workers] == "true" 4 | 5 | queues = Hash.new { |h, k| h[k] = [] } 6 | Resque.workers.each do |worker| 7 | worker.queues.each do |queue| 8 | queues[queue] << worker 9 | end 10 | end 11 | 12 | json = [] 13 | Resque.queues.each do |queue| 14 | workers = queues[queue] 15 | json << { 16 | queue: queue, 17 | size: Resque.size(queue), 18 | available: workers.count, 19 | idle: workers.count { |w| w.idle? }, 20 | working: workers.count { |w| w.working? }, 21 | paused: workers.count { |w| w.paused? } 22 | } 23 | end 24 | 25 | render json: json 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ActionController::API 2 | include ActionView::Layouts 3 | 4 | def index 5 | if Config::USE_DOCS_AS_HOMEPAGE 6 | render file: Rails.root.join('public/docs.html') 7 | else 8 | head :ok 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/info_controller.rb: -------------------------------------------------------------------------------- 1 | class InfoController < ApplicationController 2 | @@license ||= File.read("LICENSE") 3 | @@isolate ||= `isolate --version` 4 | 5 | def system_info 6 | render json: SystemInfo.sys_info 7 | end 8 | 9 | def config_info 10 | render json: Config.config_info 11 | end 12 | 13 | def about 14 | render json: { 15 | version: ENV["JUDGE0_VERSION"], 16 | homepage: ENV["JUDGE0_HOMEPAGE"], 17 | source_code: ENV["JUDGE0_SOURCE_CODE"], 18 | maintainer: ENV["JUDGE0_MAINTAINER"] 19 | } 20 | end 21 | 22 | def version 23 | render plain: ENV["JUDGE0_VERSION"] 24 | end 25 | 26 | def license 27 | render plain: @@license 28 | end 29 | 30 | def isolate 31 | render plain: @@isolate 32 | end 33 | 34 | def statistics 35 | Rails.cache.delete("statistics") if params[:invalidate_cache] == "true" 36 | @@cache_duration ||= 10.minutes 37 | render json: Rails.cache.fetch("statistics", expires_in: @@cache_duration) { 38 | @@language_name ||= Hash[Language.unscoped.pluck(:id, :name)] 39 | 40 | count_by_language = [] 41 | Submission.unscoped.group(:language_id).count.each do |language_id, count| 42 | count_by_language << { 43 | language: { 44 | id: language_id, 45 | name: @@language_name[language_id] 46 | }, 47 | count: count 48 | } 49 | end 50 | count_by_language = count_by_language.sort_by { |x| x[:count] }.reverse 51 | 52 | count_by_status = [] 53 | Submission.unscoped.group(:status_id).count.each do |status_id, count| 54 | count_by_status << { 55 | status: { 56 | id: status_id, 57 | name: Status.find_by(id: status_id).name # Not a SQL query! 58 | }, 59 | count: count 60 | } 61 | end 62 | count_by_status = count_by_status.sort_by{ |x| x[:count] }.reverse 63 | 64 | now = DateTime.now 65 | today = DateTime.now.beginning_of_day.to_date 66 | last_30_days = Submission.unscoped.group("created_at::DATE").where("created_at::DATE >= ?", today - 30).count 67 | last_30_days[today] ||= 0 68 | last_30_days_result = {} 69 | (today-30...today).each do |day| 70 | last_30_days_result[day.to_date] = last_30_days[day] || 0 71 | end 72 | last_30_days_result = last_30_days_result.sort.reverse.to_h 73 | 74 | database_size = ActiveRecord::Base.connection.execute( 75 | "SELECT 76 | pg_size_pretty(pg_database_size('#{ENV['POSTGRES_DB']}')) AS size_pretty, 77 | pg_database_size('#{ENV['POSTGRES_DB']}') AS size_in_bytes 78 | " 79 | ).to_a[0] 80 | 81 | { 82 | created_at: now, 83 | cached_until: now + @@cache_duration, 84 | submissions: { 85 | total: Submission.count, 86 | today: last_30_days[today], 87 | last_30_days: last_30_days_result 88 | }, 89 | languages: count_by_language, 90 | statuses: count_by_status, 91 | database: { 92 | size_pretty: database_size["size_pretty"], 93 | size_in_bytes: database_size["size_in_bytes"] 94 | } 95 | } 96 | } 97 | end 98 | end -------------------------------------------------------------------------------- /app/controllers/languages_controller.rb: -------------------------------------------------------------------------------- 1 | class LanguagesController < ApplicationController 2 | def index 3 | render json: Language.all, each_serializer: LanguageSerializer, fields: [:id, :name] 4 | end 5 | 6 | def all 7 | render json: Language.unscoped.order(name: :asc), each_serializer: LanguageSerializer, fields: [:id, :name, :is_archived] 8 | end 9 | 10 | def show 11 | render json: Language.unscoped.find(params[:id]) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ActionController::API 2 | before_action :verify_ip_address 3 | before_action :authenticate_request 4 | before_action :authorize_request, only: [:authorize] 5 | 6 | def authenticate 7 | head :ok 8 | end 9 | 10 | def authorize 11 | head :ok 12 | end 13 | 14 | private 15 | 16 | def verify_ip_address 17 | @@disallowed_ip_addresses ||= ENV['DISALLOW_IP'].to_s.split - ENV['ALLOW_IP'].to_s.split 18 | @@allowed_ip_addresses ||= ENV['ALLOW_IP'].to_s.split - ENV['DISALLOW_IP'].to_s.split 19 | head :forbidden if @@disallowed_ip_addresses.include?(request.remote_ip) 20 | head :forbidden if @@allowed_ip_addresses.present? && !@@allowed_ip_addresses.include?(request.remote_ip) 21 | end 22 | 23 | def authenticate_request 24 | head :unauthorized if safe_compare(Rails.application.secrets.authn_token, Rails.application.secrets.authn_header) 25 | end 26 | 27 | def authorize_request 28 | head :forbidden unless Rails.application.secrets.authz_token.present? 29 | head :forbidden if safe_compare(Rails.application.secrets.authz_token, Rails.application.secrets.authz_header) 30 | end 31 | 32 | def check_maintenance 33 | @@maintenance_message ||= ENV['MAINTENANCE_MESSAGE'] 34 | if Config::MAINTENANCE_MODE 35 | render json: { 36 | error: @@maintenance_message 37 | }, status: :service_unavailable 38 | end 39 | end 40 | 41 | def safe_compare(token, header) 42 | token = token.to_s 43 | header = header.to_s 44 | return false unless token.present? 45 | provided_token = (request.headers[header] || params[header]).to_s 46 | token.split.each do |value| 47 | return false if ActiveSupport::SecurityUtils.secure_compare(value, provided_token) 48 | end 49 | true 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /app/controllers/statuses_controller.rb: -------------------------------------------------------------------------------- 1 | class StatusesController < ApplicationController 2 | def index 3 | render json: Status.all, each_serializer: StatusSerializer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/submissions_controller.rb: -------------------------------------------------------------------------------- 1 | class SubmissionsController < ApplicationController 2 | before_action :authorize_request, only: [:index, :destroy] 3 | before_action :check_maintenance, only: [:create, :destroy] 4 | before_action :check_wait, only: [:create] # Wait in batch_create is not allowed 5 | before_action :check_batched_submissions, only: [:batch_create, :batch_show] 6 | before_action :check_queue_size, only: [:create, :batch_create] 7 | before_action :check_requested_fields, except: [:batch_create] # Fields are ignored in batch_create 8 | before_action :set_base64_encoded 9 | 10 | def index 11 | page = params[:page].try(:to_i) || 1 12 | per_page = params[:per_page].try(:to_i) || Submission.per_page 13 | 14 | if page <= 0 15 | render json: { error: "invalid page: #{page}" }, status: :bad_request 16 | return 17 | elsif per_page < 0 18 | render json: { error: "invalid per_page: #{per_page}" }, status: :bad_request 19 | return 20 | end 21 | 22 | submissions = Submission.paginate(page: page, per_page: per_page) 23 | serializable_submissions = ActiveModelSerializers::SerializableResource.new( 24 | submissions, { each_serializer: SubmissionSerializer, base64_encoded: @base64_encoded, fields: @requested_fields } 25 | ) 26 | 27 | render json: { 28 | submissions: serializable_submissions.as_json, 29 | meta: pagination_dict(submissions) 30 | } 31 | rescue Encoding::UndefinedConversionError => e 32 | render json: { 33 | error: "some attributes for one or more submissions cannot be converted to UTF-8, use base64_encoded=true query parameter" 34 | }, status: :bad_request 35 | end 36 | 37 | def destroy 38 | if !Config::ENABLE_SUBMISSION_DELETE 39 | render json: { error: "delete not allowed" }, status: :bad_request 40 | return 41 | end 42 | 43 | submission = Submission.find_by!(token: params[:token]) 44 | if submission.status == Status.queue || submission.status == Status.process 45 | render json: { 46 | error: "submission cannot be deleted because its status is #{submission.status.id} (#{submission.status.name})" 47 | }, status: :bad_request 48 | return 49 | end 50 | 51 | submission.delete 52 | 53 | # Forcing base64_encoded=true because it guarantees user will get requested data after delete. 54 | render json: submission, base64_encoded: true, fields: @requested_fields 55 | end 56 | 57 | def show 58 | token = params[:token] 59 | render json: Rails.cache.fetch("#{token}", expires_in: Config::SUBMISSION_CACHE_DURATION, race_condition_ttl: 0.1*Config::SUBMISSION_CACHE_DURATION) { 60 | Submission.find_by!(token: token) 61 | }, base64_encoded: @base64_encoded, fields: @requested_fields 62 | rescue Encoding::UndefinedConversionError 63 | render_conversion_error(:bad_request) 64 | end 65 | 66 | def batch_show 67 | tokens = (request.headers[:tokens] || params[:tokens]).to_s.strip.split(",") 68 | 69 | if tokens.length > Config::MAX_SUBMISSION_BATCH_SIZE 70 | render json: { 71 | error: "number of submissions in a batch should be less than or equal to #{Config::MAX_SUBMISSION_BATCH_SIZE}" 72 | }, status: :bad_request 73 | return 74 | elsif tokens.length == 0 75 | render json: { 76 | error: "there should be at least one submission in a batch" 77 | }, status: :bad_request 78 | return 79 | end 80 | 81 | existing_submissions = Hash[Submission.where(token: tokens).collect{ |s| [s.token, s] }] 82 | 83 | submissions = [] 84 | tokens.each do |token| 85 | if existing_submissions.has_key?(token) 86 | serialized_submission = ActiveModelSerializers::SerializableResource.new( 87 | existing_submissions[token], { serializer: SubmissionSerializer, base64_encoded: @base64_encoded, fields: @requested_fields } 88 | ) 89 | submissions << serialized_submission.as_json 90 | else 91 | submissions << nil 92 | end 93 | end 94 | 95 | render json: { submissions: submissions } 96 | rescue Encoding::UndefinedConversionError => e 97 | render json: { 98 | error: "some attributes for one or more submissions cannot be converted to UTF-8, use base64_encoded=true query parameter" 99 | }, status: :bad_request 100 | end 101 | 102 | def create 103 | submission = Submission.new(submission_params(params)) 104 | 105 | if submission.save 106 | if @wait 107 | begin 108 | IsolateRunner.perform_now(submission) 109 | submission.reload 110 | render json: submission, status: :created, base64_encoded: @base64_encoded, fields: @requested_fields 111 | rescue Encoding::UndefinedConversionError => e 112 | render_conversion_error(:created, submission.token) 113 | end 114 | else 115 | IsolateRunner.perform_later(submission) 116 | render json: submission, status: :created, fields: [:token] 117 | end 118 | else 119 | render json: submission.errors, status: :unprocessable_entity 120 | end 121 | end 122 | 123 | # Batch Create does not support sync (wait=true) mode. 124 | def batch_create 125 | number_of_submissions = params[:submissions].try(:size).to_i 126 | 127 | if number_of_submissions > Config::MAX_SUBMISSION_BATCH_SIZE 128 | render json: { 129 | error: "number of submissions in a batch should be less than or equal to #{Config::MAX_SUBMISSION_BATCH_SIZE}" 130 | }, status: :bad_request 131 | return 132 | elsif number_of_submissions == 0 133 | render json: { 134 | error: "there should be at least one submission in a batch" 135 | }, status: :bad_request 136 | return 137 | end 138 | 139 | submissions = params[:submissions].each.collect{ |p| Submission.new(submission_params(p)) } 140 | 141 | response = [] 142 | has_valid_submission = false 143 | 144 | submissions.each do |submission| 145 | if submission.save 146 | IsolateRunner.perform_later(submission) 147 | response << { token: submission.token } 148 | has_valid_submission = true 149 | else 150 | response << submission.errors 151 | end 152 | end 153 | 154 | render json: response, status: has_valid_submission ? :created : :unprocessable_entity 155 | end 156 | 157 | private 158 | 159 | def submission_params(params) 160 | submission_params = params.permit( 161 | :source_code, 162 | :language_id, 163 | :compiler_options, 164 | :command_line_arguments, 165 | :number_of_runs, 166 | :stdin, 167 | :expected_output, 168 | :cpu_time_limit, 169 | :cpu_extra_time, 170 | :wall_time_limit, 171 | :memory_limit, 172 | :stack_limit, 173 | :max_processes_and_or_threads, 174 | :enable_per_process_and_thread_time_limit, 175 | :enable_per_process_and_thread_memory_limit, 176 | :max_file_size, 177 | :redirect_stderr_to_stdout, 178 | :callback_url, 179 | :additional_files, 180 | :enable_network 181 | ) 182 | 183 | submission_params[:additional_files] = Base64Service.decode(submission_params[:additional_files]) 184 | 185 | if @base64_encoded 186 | submission_params[:source_code] = Base64Service.decode(submission_params[:source_code]) 187 | submission_params[:stdin] = Base64Service.decode(submission_params[:stdin]) 188 | submission_params[:expected_output] = Base64Service.decode(submission_params[:expected_output]) 189 | end 190 | 191 | submission_params 192 | end 193 | 194 | def check_wait 195 | @wait = params[:wait] == "true" 196 | if @wait && !Config::ENABLE_WAIT_RESULT 197 | render json: { error: "wait not allowed" }, status: :bad_request 198 | end 199 | end 200 | 201 | def check_batched_submissions 202 | unless Config::ENABLE_BATCHED_SUBMISSIONS 203 | render json: { error: "batched submissions are not allowed" }, status: :bad_request 204 | end 205 | end 206 | 207 | def check_queue_size 208 | number_of_submissions = params[:submissions].try(:size).presence || 1 209 | if Resque.size(ENV["JUDGE0_VERSION"]) + number_of_submissions > Config::MAX_QUEUE_SIZE 210 | render json: { error: "queue is full" }, status: :service_unavailable 211 | end 212 | end 213 | 214 | def check_requested_fields 215 | fields_service = Fields::Submission.new(params[:fields]) 216 | render json: { error: "invalid fields: [#{fields_service.invalid_fields.join(", ")}]" }, status: :bad_request if fields_service.has_invalid_fields? 217 | @requested_fields = fields_service.requested_fields 218 | end 219 | 220 | def set_base64_encoded 221 | if Config::DISABLE_IMPLICIT_BASE64_ENCODING 222 | @base64_encoded = params[:base64_encoded] == "true" 223 | else 224 | @base64_encoded = params[:base64_encoded] != "false" 225 | end 226 | end 227 | 228 | def render_conversion_error(status, token = nil) 229 | response_json = { 230 | error: "some attributes for this submission cannot be converted to UTF-8, use base64_encoded=true query parameter", 231 | } 232 | response_json[:token] = token if token 233 | 234 | render json: response_json, status: status 235 | end 236 | end 237 | -------------------------------------------------------------------------------- /app/enumerations/status.rb: -------------------------------------------------------------------------------- 1 | class Status < Enumerations::Base 2 | values queue: { id: 1, name: 'In Queue' }, 3 | process: { id: 2, name: 'Processing' }, 4 | ac: { id: 3, name: 'Accepted' }, 5 | wa: { id: 4, name: 'Wrong Answer' }, 6 | tle: { id: 5, name: 'Time Limit Exceeded' }, 7 | ce: { id: 6, name: 'Compilation Error' }, 8 | sigsegv: { id: 7, name: 'Runtime Error (SIGSEGV)' }, 9 | sigxfsz: { id: 8, name: 'Runtime Error (SIGXFSZ)' }, 10 | sigfpe: { id: 9, name: 'Runtime Error (SIGFPE)' }, 11 | sigabrt: { id: 10, name: 'Runtime Error (SIGABRT)' }, 12 | nzec: { id: 11, name: 'Runtime Error (NZEC)' }, 13 | other: { id: 12, name: 'Runtime Error (Other)' }, 14 | boxerr: { id: 13, name: 'Internal Error' }, 15 | exeerr: { id: 14, name: 'Exec Format Error' } 16 | 17 | def self.find_runtime_error_by_status_code(status_code) 18 | case status_code.to_i 19 | when 11 then Status.sigsegv 20 | when 25 then Status.sigxfsz 21 | when 8 then Status.sigfpe 22 | when 6 then Status.sigabrt 23 | else Status.other 24 | end 25 | end 26 | 27 | def self.model_name 28 | @@model_name ||= ActiveModel::Name.new(self) 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /app/helpers/config.rb: -------------------------------------------------------------------------------- 1 | module Config 2 | # For more info read: 3 | # https://github.com/judge0/judge0/blob/master/judge0.conf 4 | 5 | MAINTENANCE_MODE = ENV["MAINTENANCE_MODE"] == "true" 6 | ENABLE_WAIT_RESULT = ENV["ENABLE_WAIT_RESULT"] != "false" 7 | ENABLE_COMPILER_OPTIONS = ENV["ENABLE_COMPILER_OPTIONS"] != "false" 8 | ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS = ENV["ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS"].to_s.strip.split 9 | ENABLE_COMMAND_LINE_ARGUMENTS = ENV["ENABLE_COMMAND_LINE_ARGUMENTS"] != "false" 10 | ENABLE_SUBMISSION_DELETE = ENV["ENABLE_SUBMISSION_DELETE"] == "true" 11 | ENABLE_CALLBACKS = ENV["ENABLE_CALLBACKS"] != "false" 12 | CALLBACKS_MAX_TRIES = (ENV["CALLBACKS_MAX_TRIES"].presence || 3).to_i 13 | CALLBACKS_TIMEOUT = (ENV["CALLBACKS_TIMEOUT"].presence || 5).to_f 14 | ENABLE_ADDITIONAL_FILES = ENV["ENABLE_ADDITIONAL_FILES"] != "false" 15 | MAX_QUEUE_SIZE = (ENV["MAX_QUEUE_SIZE"].presence || 100).to_i 16 | CPU_TIME_LIMIT = (ENV["CPU_TIME_LIMIT"].presence || 5).to_f 17 | MAX_CPU_TIME_LIMIT = (ENV["MAX_CPU_TIME_LIMIT"].presence || 15).to_f 18 | CPU_EXTRA_TIME = (ENV["CPU_EXTRA_TIME"].presence || 1).to_f 19 | MAX_CPU_EXTRA_TIME = (ENV["MAX_CPU_EXTRA_TIME"].presence || 5).to_f 20 | WALL_TIME_LIMIT = (ENV["WALL_TIME_LIMIT"].presence || 10).to_f 21 | MAX_WALL_TIME_LIMIT = (ENV["MAX_WALL_TIME_LIMIT"].presence || 20).to_f 22 | MEMORY_LIMIT = (ENV["MEMORY_LIMIT"].presence || 128000).to_i # in KB 23 | MAX_MEMORY_LIMIT = (ENV["MAX_MEMORY_LIMIT"].presence || 512000).to_i 24 | STACK_LIMIT = (ENV["STACK_LIMIT"].presence || 64000).to_i # in KB 25 | MAX_STACK_LIMIT = (ENV["MAX_STACK_LIMIT"].presence || 128000).to_i 26 | MAX_PROCESSES_AND_OR_THREADS = (ENV["MAX_PROCESSES_AND_OR_THREADS"].presence || 60).to_i 27 | MAX_MAX_PROCESSES_AND_OR_THREADS = (ENV["MAX_MAX_PROCESSES_AND_OR_THREADS"].presence || 120).to_i 28 | ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT = ENV["ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT"] == "true" 29 | ALLOW_ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT = ENV["ALLOW_ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT"] != "false" 30 | ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT = ENV["ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT"] == "true" 31 | ALLOW_ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT = ENV["ALLOW_ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT"] != "false" 32 | MAX_FILE_SIZE = (ENV["MAX_FILE_SIZE"].presence || 1024).to_i 33 | MAX_MAX_FILE_SIZE = (ENV["MAX_MAX_FILE_SIZE"].presence || 4096).to_i 34 | NUMBER_OF_RUNS = (ENV["NUMBER_OF_RUNS"].presence || 1).to_i 35 | MAX_NUMBER_OF_RUNS = (ENV["MAX_NUMBER_OF_RUNS"].presence || 20).to_i 36 | REDIRECT_STDERR_TO_STDOUT = ENV["REDIRECT_STDERR_TO_STDOUT"] == "true" 37 | MAX_EXTRACT_SIZE = (ENV["MAX_EXTRACT_SIZE"].presence || 10240).to_i 38 | ENABLE_BATCHED_SUBMISSIONS = ENV["ENABLE_BATCHED_SUBMISSIONS"] != "false" 39 | MAX_SUBMISSION_BATCH_SIZE = (ENV["MAX_SUBMISSION_BATCH_SIZE"].presence || 20).to_i 40 | SUBMISSION_CACHE_DURATION = (ENV["SUBMISSION_CACHE_DURATION"].presence || 1).to_f 41 | USE_DOCS_AS_HOMEPAGE = ENV["USE_DOCS_AS_HOMEPAGE"] == "true" 42 | ALLOW_ENABLE_NETWORK = ENV["ALLOW_ENABLE_NETWORK"] != "false" 43 | ENABLE_NETWORK = ENV["ENABLE_NETWORK"] == "true" 44 | DISABLE_IMPLICIT_BASE64_ENCODING = ENV["DISABLE_IMPLICIT_BASE64_ENCODING"] == "true" 45 | 46 | def self.config_info 47 | @@default_confg ||= { 48 | "maintenance_mode": MAINTENANCE_MODE, 49 | "enable_wait_result": ENABLE_WAIT_RESULT, 50 | "enable_compiler_options": ENABLE_COMPILER_OPTIONS, 51 | "allowed_languages_for_compile_options": ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS, 52 | "enable_command_line_arguments": ENABLE_COMMAND_LINE_ARGUMENTS, 53 | "enable_submission_delete": ENABLE_SUBMISSION_DELETE, 54 | "enable_callbacks": ENABLE_CALLBACKS, 55 | "callbacks_max_tries": CALLBACKS_MAX_TRIES, 56 | "callbacks_timeout": CALLBACKS_TIMEOUT, 57 | "enable_additional_files": ENABLE_ADDITIONAL_FILES, 58 | "max_queue_size": MAX_QUEUE_SIZE, 59 | "cpu_time_limit": CPU_TIME_LIMIT, 60 | "max_cpu_time_limit": MAX_CPU_TIME_LIMIT, 61 | "cpu_extra_time": CPU_EXTRA_TIME, 62 | "max_cpu_extra_time": MAX_CPU_EXTRA_TIME, 63 | "wall_time_limit": WALL_TIME_LIMIT, 64 | "max_wall_time_limit": MAX_WALL_TIME_LIMIT, 65 | "memory_limit": MEMORY_LIMIT, 66 | "max_memory_limit": MAX_MEMORY_LIMIT, 67 | "stack_limit": STACK_LIMIT, 68 | "max_stack_limit": MAX_STACK_LIMIT, 69 | "max_processes_and_or_threads": MAX_PROCESSES_AND_OR_THREADS, 70 | "max_max_processes_and_or_threads": MAX_MAX_PROCESSES_AND_OR_THREADS, 71 | "enable_per_process_and_thread_time_limit": ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT, 72 | "allow_enable_per_process_and_thread_time_limit": ALLOW_ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT, 73 | "enable_per_process_and_thread_memory_limit": ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT, 74 | "allow_enable_per_process_and_thread_memory_limit": ALLOW_ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT, 75 | "max_file_size": MAX_FILE_SIZE, 76 | "max_max_file_size": MAX_MAX_FILE_SIZE, 77 | "number_of_runs": NUMBER_OF_RUNS, 78 | "max_number_of_runs": MAX_NUMBER_OF_RUNS, 79 | "redirect_stderr_to_stdout": REDIRECT_STDERR_TO_STDOUT, 80 | "max_extract_size": MAX_EXTRACT_SIZE, 81 | "enable_batched_submissions": ENABLE_BATCHED_SUBMISSIONS, 82 | "max_submission_batch_size": MAX_SUBMISSION_BATCH_SIZE, 83 | "submission_cache_duration": SUBMISSION_CACHE_DURATION, 84 | "use_docs_as_homepage": USE_DOCS_AS_HOMEPAGE, 85 | "allow_enable_network": ALLOW_ENABLE_NETWORK, 86 | "enable_network": ENABLE_NETWORK, 87 | "disable_implicit_base64_encoding": DISABLE_IMPLICIT_BASE64_ENCODING 88 | } 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /app/helpers/isolate_runner.rb: -------------------------------------------------------------------------------- 1 | module IsolateRunner 2 | MAX_WAIT_TIME_S = 600 3 | 4 | INITIAL_WAIT_TIME_S = 2 5 | NEXT_WAIT_TIME_S = 1 6 | WAIT_TIME_FACTOR_S = 0.5 7 | 8 | WAITING_STATUSES = [Status.queue.id, Status.process.id, nil] 9 | 10 | def self.perform_now(submission) 11 | IsolateRunner.perform_later(submission) 12 | 13 | submission_id = submission.id 14 | 15 | total_wait_time = 0 16 | (0..).each do |i| 17 | break if total_wait_time >= MAX_WAIT_TIME_S 18 | 19 | if i == 0 then 20 | wait_time = INITIAL_WAIT_TIME_S 21 | elsif i == 1 then 22 | wait_time = NEXT_WAIT_TIME_S 23 | else 24 | wait_time = WAIT_TIME_FACTOR_S * i 25 | end 26 | 27 | sleep(wait_time) 28 | 29 | total_wait_time += wait_time 30 | 31 | break if !WAITING_STATUSES.include?(Submission.where(id: submission_id).pluck(:status_id).first) 32 | end 33 | end 34 | 35 | def self.perform_later(submission) 36 | submission.update(status: Status.queue, queued_at: DateTime.now, queue_host: ENV["HOSTNAME"]) 37 | IsolateJob.perform_later(submission.id) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/helpers/nil_value.rb: -------------------------------------------------------------------------------- 1 | module NilValue 2 | def self.value_or_default(value, default) 3 | return value unless value == nil 4 | return default 5 | end 6 | end -------------------------------------------------------------------------------- /app/helpers/system_info.rb: -------------------------------------------------------------------------------- 1 | module SystemInfo 2 | def self.sys_info 3 | @@sys_info ||= self.cpu_info.merge(self.mem_info) 4 | end 5 | 6 | def self.cpu_info #sorryforthisline 7 | @@cpu_info ||= Hash[`lscpu`.split("\n").collect{|l| l = l.split(":"); [l[0].strip, l[1].strip]}] 8 | end 9 | 10 | def self.mem_info #sorryagain #itjustworks 11 | @@mem_info ||= Hash[`free -h`.split("\n")[1..-1].collect{|l| l = l.split(":"); [l[0].strip, l[1].split(" ")[0].strip]}].without("-/+ buffers/cache") 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/language.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: languages 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # compile_cmd :string 8 | # run_cmd :string 9 | # source_file :string 10 | # is_archived :boolean default(FALSE) 11 | # 12 | 13 | class Language < ApplicationRecord 14 | validates :name, presence: true 15 | validates :source_file, :run_cmd, presence: true, unless: -> { is_project } 16 | default_scope { where(is_archived: false).order(name: :asc) } 17 | 18 | def is_project 19 | name == "Multi-file program" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/models/submission.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: submissions 4 | # 5 | # id :integer not null, primary key 6 | # source_code :text 7 | # language_id :integer 8 | # stdin :text 9 | # expected_output :text 10 | # stdout :text 11 | # status_id :integer 12 | # created_at :datetime 13 | # finished_at :datetime 14 | # time :decimal(, ) 15 | # memory :integer 16 | # stderr :text 17 | # token :string 18 | # number_of_runs :integer 19 | # cpu_time_limit :decimal(, ) 20 | # cpu_extra_time :decimal(, ) 21 | # wall_time_limit :decimal(, ) 22 | # memory_limit :integer 23 | # stack_limit :integer 24 | # max_processes_and_or_threads :integer 25 | # enable_per_process_and_thread_time_limit :boolean 26 | # enable_per_process_and_thread_memory_limit :boolean 27 | # max_file_size :integer 28 | # compile_output :text 29 | # exit_code :integer 30 | # exit_signal :integer 31 | # message :text 32 | # wall_time :decimal(, ) 33 | # compiler_options :string 34 | # command_line_arguments :string 35 | # redirect_stderr_to_stdout :boolean 36 | # callback_url :string 37 | # additional_files :binary 38 | # enable_network :boolean 39 | # started_at :datetime 40 | # queued_at :datetime 41 | # updated_at :datetime 42 | # queue_host :string 43 | # execution_host :string 44 | # 45 | 46 | class Submission < ApplicationRecord 47 | validates :source_code, presence: true, unless: -> { is_project } 48 | validates :source_code, absence: true, if: -> { is_project } 49 | validates :additional_files, presence: true, if: -> { is_project } 50 | validates :language_id, presence: true 51 | validates :number_of_runs, 52 | numericality: { greater_than: 0, less_than_or_equal_to: Config::MAX_NUMBER_OF_RUNS } 53 | validates :cpu_time_limit, 54 | numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: Config::MAX_CPU_TIME_LIMIT } 55 | validates :cpu_extra_time, 56 | numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: Config::MAX_CPU_EXTRA_TIME } 57 | validates :wall_time_limit, 58 | numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: Config::MAX_WALL_TIME_LIMIT } 59 | validates :memory_limit, 60 | numericality: { greater_than_or_equal_to: 2048, less_than_or_equal_to: Config::MAX_MEMORY_LIMIT } 61 | validates :stack_limit, 62 | numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: Config::MAX_STACK_LIMIT } 63 | validates :max_processes_and_or_threads, 64 | numericality: { greater_than: 0, less_than_or_equal_to: Config::MAX_MAX_PROCESSES_AND_OR_THREADS } 65 | validates :enable_per_process_and_thread_time_limit, 66 | inclusion: { in: [false], message: "this option cannot be enabled" }, 67 | unless: -> { Config::ALLOW_ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT } 68 | validates :enable_per_process_and_thread_memory_limit, 69 | inclusion: { in: [false], message: "this option cannot be enabled" }, 70 | unless: -> { Config::ALLOW_ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT } 71 | validates :max_file_size, 72 | numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: Config::MAX_MAX_FILE_SIZE } 73 | validates :compiler_options, length: { maximum: 512 } 74 | validates :command_line_arguments, length: { maximum: 512 } 75 | validate :language_existence, :compiler_options_allowed, 76 | :command_line_arguments_allowed, :callbacks_allowed, 77 | :additional_files_allowed, :network_allowed 78 | 79 | before_create :generate_token 80 | before_validation :set_defaults 81 | 82 | enumeration :status 83 | 84 | default_scope { order(created_at: :desc) } 85 | 86 | self.per_page = 20 87 | 88 | def source_code 89 | @decoded_source_code ||= Base64Service.decode(self[:source_code]) 90 | end 91 | 92 | def source_code=(value) 93 | super(value) 94 | self[:source_code] = Base64Service.encode(self[:source_code]) 95 | end 96 | 97 | 98 | def stdin 99 | @decoded_stdin ||= Base64Service.decode(self[:stdin]) 100 | end 101 | 102 | def stdin=(value) 103 | super(value) 104 | self[:stdin] = Base64Service.encode(self[:stdin]) 105 | end 106 | 107 | 108 | def stdout 109 | @decoded_stdout ||= Base64Service.decode(self[:stdout]) 110 | end 111 | 112 | def stdout=(value) 113 | super(value) 114 | self[:stdout] = Base64Service.encode(self[:stdout]) 115 | end 116 | 117 | 118 | def expected_output 119 | @decoded_expected_output ||= Base64Service.decode(self[:expected_output]) 120 | end 121 | 122 | def expected_output=(value) 123 | super(value) 124 | self[:expected_output] = Base64Service.encode(self[:expected_output]) 125 | end 126 | 127 | 128 | def stderr 129 | @decoded_stderr ||= Base64Service.decode(self[:stderr]) 130 | end 131 | 132 | def stderr=(value) 133 | super(value) 134 | self[:stderr] = Base64Service.encode(self[:stderr]) 135 | end 136 | 137 | 138 | def compile_output 139 | @decoded_compile_output ||= Base64Service.decode(self[:compile_output]) 140 | end 141 | 142 | def compile_output=(value) 143 | super(value) 144 | self[:compile_output] = Base64Service.encode(self[:compile_output]) 145 | end 146 | 147 | 148 | def language 149 | @language ||= Language.unscoped.find_by(id: language_id) 150 | end 151 | 152 | 153 | def status 154 | Status.find_by(id: status_id) 155 | end 156 | 157 | def status=(status) 158 | self.status_id = status.id 159 | end 160 | 161 | 162 | def is_project 163 | language.try(:is_project) || false 164 | end 165 | 166 | private 167 | 168 | def language_existence 169 | if not language 170 | errors.add(:language_id, "language with id #{language_id} doesn't exist") 171 | elsif language.is_archived 172 | errors.add(:language_id, "language with id #{language_id} is archived and cannot be used anymore") 173 | end 174 | end 175 | 176 | def compiler_options_allowed 177 | return if compiler_options.blank? 178 | 179 | unless Config::ENABLE_COMPILER_OPTIONS 180 | errors.add(:compiler_options, "setting compiler options is not allowed") 181 | return 182 | end 183 | 184 | if language && language.compile_cmd.nil? 185 | errors.add(:compiler_options, "setting compiler options is only allowed for compiled languages") 186 | return 187 | end 188 | 189 | @@allowed_languages ||= Config::ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS.collect{ |s| s + " " } 190 | if language && @@allowed_languages.present? && !language.name.starts_with?(*@@allowed_languages) 191 | @@allowed_languages_message ||= @@allowed_languages.size > 1 ? @@allowed_languages[0..-2].collect{ |s| s.strip }.join(", ") + " and " + @@allowed_languages[-1].strip : @@allowed_languages[0].strip 192 | errors.add(:compiler_options, "setting compiler options is only allowed for #{@@allowed_languages_message}") 193 | end 194 | end 195 | 196 | def command_line_arguments_allowed 197 | return if command_line_arguments.blank? 198 | 199 | unless Config::ENABLE_COMMAND_LINE_ARGUMENTS 200 | errors.add(:command_line_arguments, "setting command line arguments is not allowed") 201 | end 202 | end 203 | 204 | def callbacks_allowed 205 | return if callback_url.blank? 206 | 207 | unless Config::ENABLE_CALLBACKS 208 | errors.add(:callback_url, "setting callback is not allowed") 209 | end 210 | end 211 | 212 | def additional_files_allowed 213 | return if additional_files.blank? 214 | 215 | unless Config::ENABLE_ADDITIONAL_FILES 216 | errors.add(:additional_files, "setting additional files is not allowed") 217 | end 218 | end 219 | 220 | def network_allowed 221 | return if enable_network.blank? 222 | 223 | unless Config::ALLOW_ENABLE_NETWORK 224 | errors.add(:enable_network, "enabling network is not allowed") 225 | end 226 | end 227 | 228 | def generate_token 229 | begin 230 | self.token = SecureRandom.uuid 231 | end while self.class.exists?(token: token) 232 | end 233 | 234 | def set_defaults 235 | self.status ||= Status.queue 236 | self.number_of_runs ||= Config::NUMBER_OF_RUNS 237 | self.cpu_time_limit ||= Config::CPU_TIME_LIMIT 238 | self.cpu_extra_time ||= Config::CPU_EXTRA_TIME 239 | self.wall_time_limit ||= Config::WALL_TIME_LIMIT 240 | self.memory_limit ||= Config::MEMORY_LIMIT 241 | self.stack_limit ||= Config::STACK_LIMIT 242 | self.max_processes_and_or_threads ||= Config::MAX_PROCESSES_AND_OR_THREADS 243 | self.enable_per_process_and_thread_time_limit = NilValue.value_or_default( 244 | self.enable_per_process_and_thread_time_limit, 245 | Config::ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT 246 | ) 247 | self.enable_per_process_and_thread_memory_limit = NilValue.value_or_default( 248 | self.enable_per_process_and_thread_memory_limit, 249 | Config::ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT 250 | ) 251 | self.max_file_size ||= Config::MAX_FILE_SIZE 252 | self.redirect_stderr_to_stdout = NilValue.value_or_default( 253 | self.redirect_stderr_to_stdout, 254 | Config::REDIRECT_STDERR_TO_STDOUT 255 | ) 256 | self.enable_network = NilValue.value_or_default( 257 | self.enable_network, 258 | Config::ENABLE_NETWORK 259 | ) 260 | end 261 | end 262 | -------------------------------------------------------------------------------- /app/serializers/language_serializer.rb: -------------------------------------------------------------------------------- 1 | class LanguageSerializer < ActiveModel::Serializer 2 | attributes :id, :name, :is_archived, :source_file, :compile_cmd, :run_cmd 3 | end 4 | -------------------------------------------------------------------------------- /app/serializers/status_serializer.rb: -------------------------------------------------------------------------------- 1 | class StatusSerializer < ActiveModel::Serializer 2 | attribute(:id) { object.id } 3 | attribute(:description) { object.name } 4 | end 5 | -------------------------------------------------------------------------------- /app/serializers/submission_serializer.rb: -------------------------------------------------------------------------------- 1 | class SubmissionSerializer < ActiveModel::Serializer 2 | attributes((Submission.column_names + ["status", "language"] - ["id"]).collect(&:to_sym)) 3 | 4 | def self.default_fields 5 | @@default_fields ||= [ 6 | :token, 7 | :time, 8 | :memory, 9 | :stdout, 10 | :stderr, 11 | :compile_output, 12 | :message, 13 | :status 14 | ] 15 | end 16 | 17 | def source_code 18 | object_decoder(:source_code) 19 | end 20 | 21 | def stdin 22 | object_decoder(:stdin) 23 | end 24 | 25 | def expected_output 26 | object_decoder(:expected_output) 27 | end 28 | 29 | def stdout 30 | object_decoder(:stdout) 31 | end 32 | 33 | def stderr 34 | object_decoder(:stderr) 35 | end 36 | 37 | def compile_output 38 | object_decoder(:compile_output) 39 | end 40 | 41 | def message 42 | if instance_options[:base64_encoded] and object.message 43 | return Base64Service.encode(object.message) 44 | end 45 | object.message 46 | end 47 | 48 | def status 49 | { id: object.status_id, description: object.status.name } 50 | end 51 | 52 | def language 53 | ActiveModelSerializers::SerializableResource.new(object.language, { serializer: LanguageSerializer, fields: [:id, :name] }) 54 | end 55 | 56 | def additional_files 57 | Base64Service.encode(object.additional_files) 58 | end 59 | 60 | private 61 | 62 | def object_decoder(method) 63 | instance_options[:base64_encoded] ? object[method] : object.send(method) 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /app/services/base64_service.rb: -------------------------------------------------------------------------------- 1 | module Base64Service 2 | def self.encode(text) 3 | return nil unless text 4 | Base64.encode64(text) 5 | end 6 | 7 | def self.decode(text) 8 | return nil unless text 9 | Base64.decode64(text) #.force_encoding("UTF-8").encode 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/services/fields/submission.rb: -------------------------------------------------------------------------------- 1 | module Fields 2 | class Submission 3 | UNIVERSAL_FIELD = :* 4 | 5 | attr_reader :requested_fields, :invalid_fields 6 | 7 | def initialize(fields) 8 | @invalid_fields = [] 9 | 10 | fields = fields.to_s.split(",").collect(&:to_sym) 11 | 12 | fields.each do |field| 13 | if field != UNIVERSAL_FIELD && !available_fields.include?(field) 14 | @invalid_fields << field 15 | end 16 | end 17 | 18 | if fields.include?(UNIVERSAL_FIELD) 19 | @requested_fields = available_fields 20 | else 21 | @requested_fields = (fields - @invalid_fields).presence || default_fields 22 | end 23 | end 24 | 25 | def has_invalid_fields? 26 | !@invalid_fields.empty? 27 | end 28 | 29 | def available_fields 30 | serializer._attributes 31 | end 32 | 33 | def default_fields 34 | serializer.default_fields 35 | end 36 | 37 | def serializer 38 | SubmissionSerializer 39 | end 40 | end 41 | end -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # puts "\n== Copying sample files ==" 22 | # unless File.exist?('config/database.yml') 23 | # cp 'config/database.yml.sample', 'config/database.yml' 24 | # end 25 | 26 | puts "\n== Preparing database ==" 27 | system! 'bin/rails db:setup' 28 | 29 | puts "\n== Removing old logs and tempfiles ==" 30 | system! 'bin/rails log:clear tmp:clear' 31 | 32 | puts "\n== Restarting application server ==" 33 | system! 'bin/rails restart' 34 | end 35 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) 11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } 12 | gem 'spring', match[1] 13 | require 'spring/binstub' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/telemetry: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/bin/telemetry -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require_relative 'config/environment' 2 | 3 | run Rails.application 4 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require "rails" 4 | require "active_model/railtie" 5 | require "active_job/railtie" 6 | require "active_record/railtie" 7 | require "action_controller/railtie" 8 | require "action_mailer/railtie" 9 | require "action_view/railtie" 10 | require "action_cable/engine" 11 | 12 | require "rails/test_unit/railtie" 13 | 14 | Bundler.require(*Rails.groups) 15 | 16 | module Judge0API 17 | class Application < Rails::Application 18 | config.api_only = true 19 | config.generators do |g| 20 | g.factory_girl test_framework: :rspec 21 | end 22 | 23 | config.active_job.queue_adapter = :resque 24 | 25 | config.middleware.insert_before 0, Rack::Cors do 26 | origins = [] 27 | 28 | disallowed_origins = (ENV['DISALLOW_ORIGIN'].to_s.split - ENV['ALLOW_ORIGIN'].to_s.split).collect{ |s| s.gsub(".", "\\.") }.join("|") 29 | if disallowed_origins.present? 30 | origins.append(Regexp.new("^(?:(?!#{disallowed_origins}).)*$")) 31 | end 32 | 33 | # ALLOW_ORIGIN and DISALLOW_ORIGIN are mutually exclusive so this doesn't have any effect. 34 | origins += (ENV['ALLOW_ORIGIN'].presence || (origins.present? ? '' : '*')).split 35 | 36 | allow do 37 | origins origins 38 | resource '*', headers: :any, methods: :any 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | host: <%= ENV["POSTGRES_HOST"] %> 5 | port: <%= ENV["POSTGRES_PORT"] %> 6 | database: <%= ENV["POSTGRES_DB"] %> 7 | username: <%= ENV["POSTGRES_USER"] %> 8 | password: <%= ENV["POSTGRES_PASSWORD"] %> 9 | pool: <%= [1, ENV["RAILS_SERVER_PROCESSES"].to_i * ENV["RAILS_MAX_THREADS"].to_i].max %> 10 | 11 | development: 12 | <<: *default 13 | 14 | test: 15 | <<: *default 16 | 17 | production: 18 | <<: *default 19 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | require_relative 'application' 2 | 3 | Rails.application.initialize! 4 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | if Rails.root.join('tmp/caching-dev.txt').exist? 17 | config.action_controller.perform_caching = true 18 | 19 | config.cache_store = :memory_store 20 | config.public_file_server.headers = { 21 | 'Cache-Control' => 'public, max-age=172800' 22 | } 23 | else 24 | config.action_controller.perform_caching = false 25 | 26 | config.cache_store = :null_store 27 | end 28 | 29 | # Don't care if the mailer can't send. 30 | config.action_mailer.raise_delivery_errors = false 31 | 32 | config.action_mailer.perform_caching = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | 41 | # Raises error for missing translations 42 | # config.action_view.raise_on_missing_translations = true 43 | 44 | # Use an evented file watcher to asynchronously detect changes in source code, 45 | # routes, locales, etc. This feature depends on the listen gem. 46 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 47 | end 48 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Disable serving static files from the `/public` folder by default since 18 | # Apache or NGINX already handles this. 19 | config.public_file_server.enabled = true 20 | 21 | 22 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 23 | # config.action_controller.asset_host = 'http://assets.example.com' 24 | 25 | # Specifies the header that your server uses for sending files. 26 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 27 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 28 | 29 | # Mount Action Cable outside main process or domain 30 | # config.action_cable.mount_path = nil 31 | # config.action_cable.url = 'wss://example.com/cable' 32 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 33 | 34 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 35 | # config.force_ssl = true 36 | 37 | # Use the lowest log level to ensure availability of diagnostic information 38 | # when problems arise. 39 | config.log_level = :warn 40 | 41 | # Prepend all log lines with the following tags. 42 | config.log_tags = [ :request_id ] 43 | 44 | # Use a different cache store in production. 45 | # config.cache_store = :mem_cache_store 46 | 47 | # Use a real queuing backend for Active Job (and separate queues per environment) 48 | # config.active_job.queue_adapter = :resque 49 | # config.active_job.queue_name_prefix = "Judge0API_#{Rails.env}" 50 | config.action_mailer.perform_caching = false 51 | 52 | # Ignore bad email addresses and do not raise email delivery errors. 53 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 54 | # config.action_mailer.raise_delivery_errors = false 55 | 56 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 57 | # the I18n.default_locale when a translation cannot be found). 58 | config.i18n.fallbacks = [I18n.default_locale] 59 | 60 | # Send deprecation notices to registered listeners. 61 | config.active_support.deprecation = :notify 62 | 63 | # Use default logging formatter so that PID and timestamp are not suppressed. 64 | config.log_formatter = ::Logger::Formatter.new 65 | 66 | # Use a different logger for distributed setups. 67 | # require 'syslog/logger' 68 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 69 | 70 | if ENV["RAILS_LOG_TO_STDOUT"].present? 71 | logger = ActiveSupport::Logger.new(STDOUT) 72 | logger.formatter = config.log_formatter 73 | config.logger = ActiveSupport::TaggedLogging.new(logger) 74 | end 75 | 76 | # Do not dump schema after migrations. 77 | config.active_record.dump_schema_after_migration = false 78 | end 79 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => 'public, max-age=3600' 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | config.action_mailer.perform_caching = false 31 | 32 | # Tell Action Mailer not to deliver emails to the real world. 33 | # The :test delivery method accumulates sent emails in the 34 | # ActionMailer::Base.deliveries array. 35 | config.action_mailer.delivery_method = :test 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cors.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Avoid CORS issues when API is called from the frontend app. 4 | # Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests. 5 | 6 | # Read more: https://github.com/cyu/rack-cors 7 | 8 | # Rails.application.config.middleware.insert_before 0, Rack::Cors do 9 | # allow do 10 | # origins 'example.com' 11 | # 12 | # resource '*', 13 | # headers: :any, 14 | # methods: [:get, :post, :put, :patch, :delete, :options, :head] 15 | # end 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Read the Rails 5.0 release notes for more info on each option. 6 | 7 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 8 | # Previous versions had false. 9 | ActiveSupport.to_time_preserves_timezone = true 10 | 11 | # Require `belongs_to` associations by default. Previous versions had false. 12 | Rails.application.config.active_record.belongs_to_required_by_default = true 13 | 14 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false. 15 | Rails.application.config.ssl_options = { hsts: { subdomains: true } } 16 | -------------------------------------------------------------------------------- /config/initializers/resque.rb: -------------------------------------------------------------------------------- 1 | Resque.redis = Redis.new( 2 | host: ENV["REDIS_HOST"], 3 | port: ENV["REDIS_PORT"], 4 | password: ENV["REDIS_PASSWORD"], 5 | thread_safe: true 6 | ) 7 | 8 | if ENV["RESQUE_NAMESPACE"].present? 9 | Resque.redis.namespace = ENV["RESQUE_NAMESPACE"].to_sym 10 | end 11 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | threads_count = Integer(ENV['RAILS_MAX_THREADS']) 2 | process_count = Integer(ENV['RAILS_SERVER_PROCESSES']) 3 | threads threads_count, threads_count 4 | workers process_count 5 | 6 | port ENV['PORT'] 7 | environment ENV['RAILS_ENV'] 8 | 9 | plugin :tmp_restart -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | root 'home#index' 3 | 4 | resources :submissions, only: [:index, :show, :create, :destroy], param: :token do 5 | post 'batch', to: 'submissions#batch_create', on: :collection 6 | get 'batch', to: 'submissions#batch_show', on: :collection 7 | end 8 | 9 | resources :languages, only: [:index, :show] do 10 | get 'all', to: 'languages#all', on: :collection 11 | end 12 | 13 | resources :statuses, only: [:index] 14 | 15 | get 'system_info', to: 'info#system_info' 16 | get 'config_info', to: 'info#config_info' 17 | get 'isolate', to: 'info#isolate' 18 | get 'about', to: 'info#about' 19 | get 'version', to: 'info#version' 20 | get 'license', to: 'info#license' 21 | get 'statistics', to: 'info#statistics' 22 | 23 | post 'authenticate', to: 'sessions#authenticate' 24 | post 'authorize', to: 'sessions#authorize' 25 | 26 | get 'workers', to: 'health#workers' 27 | end 28 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | authn_header: <%= ENV["AUTHN_HEADER"] %> 3 | authn_token: <%= ENV["AUTHN_TOKEN"].to_s.strip %> 4 | authz_header: <%= ENV["AUTHZ_HEADER"] %> 5 | authz_token: <%= ENV["AUTHZ_TOKEN"].to_s.strip %> 6 | 7 | development: 8 | <<: *default 9 | secret_key_base: 54663e3c477de43bd117ddbf1798951ba5cf692dbf8327bb21f341048f04ea95344eed6c8763625a39648bfc2583f128b296bcb3a4756ef8160e483664efcb0b 10 | 11 | test: 12 | secret_key_base: 334f81f95f09f01e58b950ff5e5f9cd914cc151c186358d509d44520d4a1fb46c5af2dea39ed06a897c7cfe58b9c93316fa6c81081b7a30f5e43d271ca2aec0d 13 | 14 | production: 15 | <<: *default -------------------------------------------------------------------------------- /cron/clear_cache: -------------------------------------------------------------------------------- 1 | 0 0 * * * bash -c "source /api/tmp/environment; cd /api; rake judge0:clear_cache &> /api/log/clear_cache.log" 2 | -------------------------------------------------------------------------------- /cron/telemetry: -------------------------------------------------------------------------------- 1 | 0 */12 * * * bash -c "source /api/tmp/environment; /api/bin/telemetry &> /api/log/telemetry.log" 2 | -------------------------------------------------------------------------------- /db/languages/active.rb: -------------------------------------------------------------------------------- 1 | @languages ||= [] 2 | @languages += 3 | [ 4 | { 5 | id: 43, 6 | name: "Plain Text", 7 | is_archived: false, 8 | source_file: "text.txt", 9 | run_cmd: "/bin/cat text.txt" 10 | }, 11 | { 12 | id: 44, 13 | name: "Executable", 14 | is_archived: false, 15 | source_file: "a.out", 16 | run_cmd: "/bin/chmod +x a.out && ./a.out" 17 | }, 18 | { 19 | id: 45, 20 | name: "Assembly (NASM 2.14.02)", 21 | is_archived: false, 22 | source_file: "main.asm", 23 | compile_cmd: "/usr/local/nasm-2.14.02/bin/nasmld -f elf64 %s main.asm", 24 | run_cmd: "./a.out" 25 | }, 26 | { 27 | id: 46, 28 | name: "Bash (5.0.0)", 29 | is_archived: false, 30 | source_file: "script.sh", 31 | run_cmd: "/usr/local/bash-5.0/bin/bash script.sh" 32 | }, 33 | { 34 | id: 47, 35 | name: "Basic (FBC 1.07.1)", 36 | is_archived: false, 37 | source_file: "main.bas", 38 | compile_cmd: "/usr/local/fbc-1.07.1/bin/fbc %s main.bas", 39 | run_cmd: "./main" 40 | }, 41 | { 42 | id: 48, 43 | name: "C (GCC 7.4.0)", 44 | is_archived: false, 45 | source_file: "main.c", 46 | compile_cmd: "/usr/local/gcc-7.4.0/bin/gcc %s main.c", 47 | run_cmd: "./a.out" 48 | }, 49 | { 50 | id: 49, 51 | name: "C (GCC 8.3.0)", 52 | is_archived: false, 53 | source_file: "main.c", 54 | compile_cmd: "/usr/local/gcc-8.3.0/bin/gcc %s main.c", 55 | run_cmd: "./a.out" 56 | }, 57 | { 58 | id: 50, 59 | name: "C (GCC 9.2.0)", 60 | is_archived: false, 61 | source_file: "main.c", 62 | compile_cmd: "/usr/local/gcc-9.2.0/bin/gcc %s main.c", 63 | run_cmd: "./a.out" 64 | }, 65 | { 66 | id: 51, 67 | name: "C# (Mono 6.6.0.161)", 68 | is_archived: false, 69 | source_file: "Main.cs", 70 | compile_cmd: "/usr/bin/mcs %s Main.cs", 71 | run_cmd: "/usr/bin/mono Main.exe" 72 | }, 73 | { 74 | id: 52, 75 | name: "C++ (GCC 7.4.0)", 76 | is_archived: false, 77 | source_file: "main.cpp", 78 | compile_cmd: "/usr/local/gcc-7.4.0/bin/g++ %s main.cpp", 79 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-7.4.0/lib64 ./a.out" 80 | }, 81 | { 82 | id: 53, 83 | name: "C++ (GCC 8.3.0)", 84 | is_archived: false, 85 | source_file: "main.cpp", 86 | compile_cmd: "/usr/local/gcc-8.3.0/bin/g++ %s main.cpp", 87 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-8.3.0/lib64 ./a.out" 88 | }, 89 | { 90 | id: 54, 91 | name: "C++ (GCC 9.2.0)", 92 | is_archived: false, 93 | source_file: "main.cpp", 94 | compile_cmd: "/usr/local/gcc-9.2.0/bin/g++ %s main.cpp", 95 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-9.2.0/lib64 ./a.out" 96 | }, 97 | { 98 | id: 55, 99 | name: "Common Lisp (SBCL 2.0.0)", 100 | is_archived: false, 101 | source_file: "script.lisp", 102 | run_cmd: "SBCL_HOME=/usr/local/sbcl-2.0.0/lib/sbcl /usr/local/sbcl-2.0.0/bin/sbcl --script script.lisp" 103 | }, 104 | { 105 | id: 56, 106 | name: "D (DMD 2.089.1)", 107 | is_archived: false, 108 | source_file: "main.d", 109 | compile_cmd: "/usr/local/d-2.089.1/linux/bin64/dmd %s main.d", 110 | run_cmd: "./main" 111 | }, 112 | { 113 | id: 57, 114 | name: "Elixir (1.9.4)", 115 | is_archived: false, 116 | source_file: "script.exs", 117 | run_cmd: "/usr/local/elixir-1.9.4/bin/elixir script.exs" 118 | }, 119 | { 120 | id: 58, 121 | name: "Erlang (OTP 22.2)", 122 | is_archived: false, 123 | source_file: "main.erl", 124 | run_cmd: "/bin/sed -i '1s/^/\\n/' main.erl && /usr/local/erlang-22.2/bin/escript main.erl" 125 | }, 126 | { 127 | id: 59, 128 | name: "Fortran (GFortran 9.2.0)", 129 | is_archived: false, 130 | source_file: "main.f90", 131 | compile_cmd: "/usr/local/gcc-9.2.0/bin/gfortran %s main.f90", 132 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-9.2.0/lib64 ./a.out" 133 | }, 134 | { 135 | id: 60, 136 | name: "Go (1.13.5)", 137 | is_archived: false, 138 | source_file: "main.go", 139 | compile_cmd: "GOCACHE=/tmp/.cache/go-build /usr/local/go-1.13.5/bin/go build %s main.go", 140 | run_cmd: "./main" 141 | }, 142 | { 143 | id: 61, 144 | name: "Haskell (GHC 8.8.1)", 145 | is_archived: false, 146 | source_file: "main.hs", 147 | compile_cmd: "/usr/local/ghc-8.8.1/bin/ghc %s main.hs", 148 | run_cmd: "./main" 149 | }, 150 | { 151 | id: 62, 152 | name: "Java (OpenJDK 14.0.1+7)", 153 | is_archived: false, 154 | source_file: "Main.java", 155 | compile_cmd: "/usr/local/openjdk14/bin/javac %s Main.java", 156 | run_cmd: "/usr/local/openjdk14/bin/java Main" 157 | }, 158 | { 159 | id: 63, 160 | name: "JavaScript (Node.js 12.16.3)", 161 | is_archived: false, 162 | source_file: "script.js", 163 | run_cmd: "/usr/local/node/bin/node script.js" 164 | }, 165 | { 166 | id: 64, 167 | name: "Lua (5.3.5)", 168 | is_archived: false, 169 | source_file: "script.lua", 170 | compile_cmd: "/usr/local/lua-5.3.5/luac53 %s script.lua", 171 | run_cmd: "/usr/local/lua-5.3.5/lua53 ./luac.out" 172 | }, 173 | { 174 | id: 65, 175 | name: "OCaml (4.09.0)", 176 | is_archived: false, 177 | source_file: "main.ml", 178 | compile_cmd: "/usr/local/ocaml-4.09.0/bin/ocamlc %s main.ml", 179 | run_cmd: "./a.out" 180 | }, 181 | { 182 | id: 66, 183 | name: "Octave (5.1.0)", 184 | is_archived: false, 185 | source_file: "script.m", 186 | run_cmd: "/usr/local/octave-5.1.0/bin/octave-cli -q --no-gui --no-history script.m" 187 | }, 188 | { 189 | id: 67, 190 | name: "Pascal (FPC 3.0.4)", 191 | is_archived: false, 192 | source_file: "main.pas", 193 | compile_cmd: "/usr/local/fpc-3.0.4/bin/fpc %s main.pas", 194 | run_cmd: "./main" 195 | }, 196 | { 197 | id: 68, 198 | name: "PHP (7.4.1)", 199 | is_archived: false, 200 | source_file: "script.php", 201 | run_cmd: "/usr/local/php-7.4.1/bin/php script.php" 202 | }, 203 | { 204 | id: 69, 205 | name: "Prolog (GNU Prolog 1.4.5)", 206 | is_archived: false, 207 | source_file: "main.pro", 208 | compile_cmd: "PATH=\"/usr/local/gprolog-1.4.5/gprolog-1.4.5/bin:$PATH\" /usr/local/gprolog-1.4.5/gprolog-1.4.5/bin/gplc --no-top-level %s main.pro", 209 | run_cmd: "./main" 210 | }, 211 | { 212 | id: 70, 213 | name: "Python (2.7.17)", 214 | is_archived: false, 215 | source_file: "script.py", 216 | run_cmd: "/usr/local/python-2.7.17/bin/python2 script.py" 217 | }, 218 | { 219 | id: 71, 220 | name: "Python (3.7.7)", 221 | is_archived: false, 222 | source_file: "script.py", 223 | run_cmd: "/usr/bin/python3 script.py" 224 | }, 225 | { 226 | id: 72, 227 | name: "Ruby (2.7.0)", 228 | is_archived: false, 229 | source_file: "script.rb", 230 | run_cmd: "/usr/local/ruby-2.7.0/bin/ruby script.rb" 231 | }, 232 | { 233 | id: 73, 234 | name: "Rust (1.40.0)", 235 | is_archived: false, 236 | source_file: "main.rs", 237 | compile_cmd: "/usr/local/rust-1.40.0/bin/rustc %s main.rs", 238 | run_cmd: "./main" 239 | }, 240 | { 241 | id: 74, 242 | name: "TypeScript (3.7.4)", 243 | is_archived: false, 244 | source_file: "script.ts", 245 | compile_cmd: "/usr/bin/tsc %s script.ts", 246 | run_cmd: "/usr/local/node-12.14.0/bin/node script.js" 247 | }, 248 | { 249 | id: 75, 250 | name: "C (Clang 7.0.1)", 251 | is_archived: false, 252 | source_file: "main.c", 253 | compile_cmd: "/usr/bin/clang-7 %s main.c", 254 | run_cmd: "./a.out" 255 | }, 256 | { 257 | id: 76, 258 | name: "C++ (Clang 7.0.1)", 259 | is_archived: false, 260 | source_file: "main.cpp", 261 | compile_cmd: "/usr/bin/clang++-7 %s main.cpp", 262 | run_cmd: "./a.out" 263 | }, 264 | { 265 | id: 77, 266 | name: "COBOL (GnuCOBOL 2.2)", 267 | is_archived: false, 268 | source_file: "main.cob", 269 | compile_cmd: "/usr/local/gnucobol-2.2/bin/cobc -free -x %s main.cob", 270 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gnucobol-2.2/lib ./main" 271 | }, 272 | { 273 | id: 78, 274 | name: "Kotlin (1.3.70)", 275 | is_archived: false, 276 | source_file: "Main.kt", 277 | compile_cmd: "/usr/local/kotlin-1.3.70/bin/kotlinc %s Main.kt", 278 | run_cmd: "/usr/local/kotlin-1.3.70/bin/kotlin MainKt" 279 | }, 280 | { 281 | id: 79, 282 | name: "Objective-C (Clang 7.0.1)", 283 | is_archived: false, 284 | source_file: "main.m", 285 | compile_cmd: "/usr/bin/clang-7 `gnustep-config --objc-flags | sed 's/-W[^ ]* //g'` `gnustep-config --base-libs | sed 's/-shared-libgcc//'` -I/usr/lib/gcc/x86_64-linux-gnu/8/include main.m %s", 286 | run_cmd: "./a.out" 287 | }, 288 | { 289 | id: 80, 290 | name: "R (4.0.0)", 291 | is_archived: false, 292 | source_file: "script.r", 293 | run_cmd: "/usr/local/r-4.0.0/bin/Rscript script.r" 294 | }, 295 | { 296 | id: 81, 297 | name: "Scala (2.13.2)", 298 | is_archived: false, 299 | source_file: "Main.scala", 300 | compile_cmd: "/usr/local/scala-2.13.2/bin/scalac %s Main.scala", 301 | run_cmd: "/usr/local/scala-2.13.2/bin/scala Main" 302 | }, 303 | { 304 | id: 82, 305 | name: "SQL (SQLite 3.27.2)", 306 | is_archived: false, 307 | source_file: "script.sql", 308 | run_cmd: "/bin/cat script.sql | /usr/bin/sqlite3 db.sqlite" 309 | }, 310 | { 311 | id: 83, 312 | name: "Swift (5.2.3)", 313 | is_archived: false, 314 | source_file: "Main.swift", 315 | compile_cmd: "/usr/local/swift-5.2.3/bin/swiftc %s Main.swift", 316 | run_cmd: "./Main" 317 | }, 318 | { 319 | id: 84, 320 | name: "Visual Basic.Net (vbnc 0.0.0.5943)", 321 | is_archived: false, 322 | source_file: "Main.vb", 323 | compile_cmd: "/usr/bin/vbnc %s Main.vb", 324 | run_cmd: "/usr/bin/mono Main.exe" 325 | }, 326 | { 327 | id: 85, 328 | name: "Perl (5.28.1)", 329 | is_archived: false, 330 | source_file: "script.pl", 331 | run_cmd: "/usr/bin/perl script.pl" 332 | }, 333 | { 334 | id: 86, 335 | name: "Clojure (1.10.1)", 336 | is_archived: false, 337 | source_file: "main.clj", 338 | run_cmd: "/usr/local/bin/java -jar /usr/local/clojure-1.10.1/clojure.jar main.clj" 339 | }, 340 | { 341 | id: 87, 342 | name: "F# (.NET Core SDK 3.1.202)", 343 | is_archived: false, 344 | source_file: "script.fsx", 345 | run_cmd: "mkdir -p ~/.dotnet && touch ~/.dotnet/3.1.202.dotnetFirstUseSentinel && /usr/local/dotnet-sdk/dotnet fsi script.fsx" 346 | }, 347 | { 348 | id: 88, 349 | name: "Groovy (3.0.3)", 350 | is_archived: false, 351 | source_file: "script.groovy", 352 | compile_cmd: "/usr/local/groovy-3.0.3/bin/groovyc %s script.groovy", 353 | run_cmd: "/usr/local/bin/java -cp \".:/usr/local/groovy-3.0.3/lib/*\" script" 354 | }, 355 | { 356 | id: 89, 357 | name: "Multi-file program", 358 | is_archived: false, 359 | } 360 | ] -------------------------------------------------------------------------------- /db/languages/archived.rb: -------------------------------------------------------------------------------- 1 | @languages ||= [] 2 | @languages += 3 | [ 4 | { 5 | id: 1, 6 | name: "Bash (4.4)", 7 | is_archived: true, 8 | source_file: "script.sh", 9 | run_cmd: "/usr/local/bash-4.4/bin/bash script.sh" 10 | }, 11 | { 12 | id: 2, 13 | name: "Bash (4.0)", 14 | is_archived: true, 15 | source_file: "script.sh", 16 | run_cmd: "/usr/local/bash-4.0/bin/bash script.sh" 17 | }, 18 | { 19 | id: 3, 20 | name: "Basic (fbc 1.05.0)", 21 | is_archived: true, 22 | source_file: "main.bas", 23 | compile_cmd: "/usr/local/fbc-1.05.0/bin/fbc %s main.bas", 24 | run_cmd: "./main" 25 | }, 26 | { 27 | id: 4, 28 | name: "C (gcc 7.2.0)", 29 | is_archived: true, 30 | source_file: "main.c", 31 | compile_cmd: "/usr/local/gcc-7.2.0/bin/gcc %s main.c", 32 | run_cmd: "./a.out" 33 | }, 34 | { 35 | id: 5, 36 | name: "C (gcc 6.4.0)", 37 | is_archived: true, 38 | source_file: "main.c", 39 | compile_cmd: "/usr/local/gcc-6.4.0/bin/gcc %s main.c", 40 | run_cmd: "./a.out" 41 | }, 42 | { 43 | id: 6, 44 | name: "C (gcc 6.3.0)", 45 | is_archived: true, 46 | source_file: "main.c", 47 | compile_cmd: "/usr/local/gcc-6.3.0/bin/gcc %s main.c", 48 | run_cmd: "./a.out" 49 | }, 50 | { 51 | id: 7, 52 | name: "C (gcc 5.4.0)", 53 | is_archived: true, 54 | source_file: "main.c", 55 | compile_cmd: "/usr/local/gcc-5.4.0/bin/gcc %s main.c", 56 | run_cmd: "./a.out" 57 | }, 58 | { 59 | id: 8, 60 | name: "C (gcc 4.9.4)", 61 | is_archived: true, 62 | source_file: "main.c", 63 | compile_cmd: "/usr/local/gcc-4.9.4/bin/gcc %s main.c", 64 | run_cmd: "./a.out" 65 | }, 66 | { 67 | id: 9, 68 | name: "C (gcc 4.8.5)", 69 | is_archived: true, 70 | source_file: "main.c", 71 | compile_cmd: "/usr/local/gcc-4.8.5/bin/gcc %s main.c", 72 | run_cmd: "./a.out" 73 | }, 74 | 75 | { 76 | id: 10, 77 | name: "C++ (g++ 7.2.0)", 78 | is_archived: true, 79 | source_file: "main.cpp", 80 | compile_cmd: "/usr/local/gcc-7.2.0/bin/g++ %s main.cpp", 81 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-7.2.0/lib64 ./a.out" 82 | }, 83 | { 84 | id: 11, 85 | name: "C++ (g++ 6.4.0)", 86 | is_archived: true, 87 | source_file: "main.cpp", 88 | compile_cmd: "/usr/local/gcc-6.4.0/bin/g++ %s main.cpp", 89 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-6.4.0/lib64 ./a.out" 90 | }, 91 | { 92 | id: 12, 93 | name: "C++ (g++ 6.3.0)", 94 | is_archived: true, 95 | source_file: "main.cpp", 96 | compile_cmd: "/usr/local/gcc-6.3.0/bin/g++ %s main.cpp", 97 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-6.3.0/lib64 ./a.out" 98 | }, 99 | { 100 | id: 13, 101 | name: "C++ (g++ 5.4.0)", 102 | is_archived: true, 103 | source_file: "main.cpp", 104 | compile_cmd: "/usr/local/gcc-5.4.0/bin/g++ %s main.cpp", 105 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-5.4.0/lib64 ./a.out" 106 | }, 107 | { 108 | id: 14, 109 | name: "C++ (g++ 4.9.4)", 110 | is_archived: true, 111 | source_file: "main.cpp", 112 | compile_cmd: "/usr/local/gcc-4.9.4/bin/g++ %s main.cpp", 113 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-4.9.4/lib64 ./a.out" 114 | }, 115 | { 116 | id: 15, 117 | name: "C++ (g++ 4.8.5)", 118 | is_archived: true, 119 | source_file: "main.cpp", 120 | compile_cmd: "/usr/local/gcc-4.8.5/bin/g++ %s main.cpp", 121 | run_cmd: "LD_LIBRARY_PATH=/usr/local/gcc-4.8.5/lib64 ./a.out" 122 | }, 123 | { 124 | id: 16, 125 | name: "C# (mono 5.4.0.167)", 126 | is_archived: true, 127 | source_file: "Main.cs", 128 | compile_cmd: "/usr/local/mono-5.4.0.167/bin/mcs %s Main.cs", 129 | run_cmd: "/usr/local/mono-5.4.0.167/bin/mono Main.exe" 130 | }, 131 | { 132 | id: 17, 133 | name: "C# (mono 5.2.0.224)", 134 | is_archived: true, 135 | source_file: "Main.cs", 136 | compile_cmd: "/usr/local/mono-5.2.0.224/bin/mcs %s Main.cs", 137 | run_cmd: "/usr/local/mono-5.2.0.224/bin/mono Main.exe" 138 | }, 139 | { 140 | id: 18, 141 | name: "Clojure (1.8.0)", 142 | is_archived: true, 143 | source_file: "main.clj", 144 | run_cmd: "/usr/bin/java -cp /usr/local/clojure-1.8.0/clojure-1.8.0.jar clojure.main main.clj" 145 | }, 146 | { 147 | id: 19, 148 | name: "Crystal (0.23.1)", 149 | is_archived: true, 150 | source_file: "main.cr", 151 | compile_cmd: "/usr/local/crystal-0.23.1-3/bin/crystal build %s main.cr", 152 | run_cmd: "./main" 153 | }, 154 | { 155 | id: 20, 156 | name: "Elixir (1.5.1)", 157 | is_archived: true, 158 | source_file: "main.exs", 159 | run_cmd: "/usr/local/elixir-1.5.1/bin/elixir main.exs" 160 | }, 161 | { 162 | id: 21, 163 | name: "Erlang (OTP 20.0)", 164 | is_archived: true, 165 | source_file: "main.erl", 166 | run_cmd: "/bin/sed -i \"s/^/\\n/\" main.erl && /usr/local/erlang-20.0/bin/escript main.erl" 167 | }, 168 | { 169 | id: 22, 170 | name: "Go (1.9)", 171 | is_archived: true, 172 | source_file: "main.go", 173 | compile_cmd: "/usr/local/go-1.9/bin/go build %s main.go", 174 | run_cmd: "./main" 175 | }, 176 | { 177 | id: 23, 178 | name: "Haskell (ghc 8.2.1)", 179 | is_archived: true, 180 | source_file: "main.hs", 181 | compile_cmd: "/usr/local/ghc-8.2.1/bin/ghc %s main.hs", 182 | run_cmd: "./main" 183 | }, 184 | { 185 | id: 24, 186 | name: "Haskell (ghc 8.0.2)", 187 | is_archived: true, 188 | source_file: "main.hs", 189 | compile_cmd: "/usr/local/ghc-8.0.2/bin/ghc %s main.hs", 190 | run_cmd: "./main" 191 | }, 192 | { 193 | id: 25, 194 | name: "Insect (5.0.0)", 195 | is_archived: true, 196 | source_file: "main.ins", 197 | run_cmd: "/usr/local/insect-5.0.0/insect main.ins" 198 | }, 199 | { 200 | id: 26, 201 | name: "Java (OpenJDK 9 with Eclipse OpenJ9)", 202 | is_archived: true, 203 | source_file: "Main.java", 204 | compile_cmd: "/usr/local/openjdk9-openj9/bin/javac %s Main.java", 205 | run_cmd: "/usr/local/openjdk9-openj9/bin/java Main" 206 | }, 207 | { 208 | id: 27, 209 | name: "Java (OpenJDK 8)", 210 | is_archived: true, 211 | source_file: "Main.java", 212 | compile_cmd: "/usr/lib/jvm/java-8-openjdk-amd64/bin/javac %s Main.java", 213 | run_cmd: "/usr/lib/jvm/java-8-openjdk-amd64/bin/java Main", 214 | }, 215 | { 216 | id: 28, 217 | name: "Java (OpenJDK 7)", 218 | is_archived: true, 219 | source_file: "Main.java", 220 | compile_cmd: "/usr/lib/jvm/java-7-openjdk-amd64/bin/javac %s Main.java", 221 | run_cmd: "/usr/lib/jvm/java-7-openjdk-amd64/bin/java Main", 222 | }, 223 | { 224 | id: 29, 225 | name: "JavaScript (nodejs 8.5.0)", 226 | is_archived: true, 227 | source_file: "main.js", 228 | run_cmd: "/usr/local/node-8.5.0/bin/node main.js" 229 | }, 230 | { 231 | id: 30, 232 | name: "JavaScript (nodejs 7.10.1)", 233 | is_archived: true, 234 | source_file: "main.js", 235 | run_cmd: "/usr/local/node-7.10.1/bin/node main.js" 236 | }, 237 | { 238 | id: 31, 239 | name: "OCaml (4.05.0)", 240 | is_archived: true, 241 | source_file: "main.ml", 242 | compile_cmd: "/usr/local/ocaml-4.05.0/bin/ocamlc %s main.ml", 243 | run_cmd: "./a.out" 244 | }, 245 | { 246 | id: 32, 247 | name: "Octave (4.2.0)", 248 | is_archived: true, 249 | source_file: "file.m", 250 | run_cmd: "/usr/local/octave-4.2.0/bin/octave-cli -q --no-gui --no-history file.m" 251 | }, 252 | { 253 | id: 33, 254 | name: "Pascal (fpc 3.0.0)", 255 | is_archived: true, 256 | source_file: "main.pas", 257 | compile_cmd: "/usr/local/fpc-3.0.0/bin/fpc %s main.pas", 258 | run_cmd: "./main" 259 | }, 260 | { 261 | id: 34, 262 | name: "Python (3.6.0)", 263 | is_archived: true, 264 | source_file: "main.py", 265 | run_cmd: "/usr/local/python-3.6.0/bin/python3 main.py" 266 | }, 267 | { 268 | id: 35, 269 | name: "Python (3.5.3)", 270 | is_archived: true, 271 | source_file: "main.py", 272 | run_cmd: "/usr/local/python-3.5.3/bin/python3 main.py" 273 | }, 274 | { 275 | id: 36, 276 | name: "Python (2.7.9)", 277 | is_archived: true, 278 | source_file: "main.py", 279 | run_cmd: "/usr/local/python-2.7.9/bin/python main.py" 280 | }, 281 | { 282 | id: 37, 283 | name: "Python (2.6.9)", 284 | is_archived: true, 285 | source_file: "main.py", 286 | run_cmd: "/usr/local/python-2.6.9/bin/python main.py" 287 | }, 288 | { 289 | id: 38, 290 | name: "Ruby (2.4.0)", 291 | is_archived: true, 292 | source_file: "main.rb", 293 | run_cmd: "/usr/local/ruby-2.4.0/bin/ruby main.rb" 294 | }, 295 | { 296 | id: 39, 297 | name: "Ruby (2.3.3)", 298 | is_archived: true, 299 | source_file: "main.rb", 300 | run_cmd: "/usr/local/ruby-2.3.3/bin/ruby main.rb" 301 | }, 302 | { 303 | id: 40, 304 | name: "Ruby (2.2.6)", 305 | is_archived: true, 306 | source_file: "main.rb", 307 | run_cmd: "/usr/local/ruby-2.2.6/bin/ruby main.rb" 308 | }, 309 | { 310 | id: 41, 311 | name: "Ruby (2.1.9)", 312 | is_archived: true, 313 | source_file: "main.rb", 314 | run_cmd: "/usr/local/ruby-2.1.9/bin/ruby main.rb" 315 | }, 316 | { 317 | id: 42, 318 | name: "Rust (1.20.0)", 319 | is_archived: true, 320 | source_file: "main.rs", 321 | compile_cmd: "/usr/local/rust-1.20.0/bin/rustc %s main.rs", 322 | run_cmd: "./main" 323 | } 324 | ] -------------------------------------------------------------------------------- /db/migrate/20160903140859_create_languages.rb: -------------------------------------------------------------------------------- 1 | class CreateLanguages < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :languages do |t| 4 | t.string :name 5 | t.string :compile_cmd 6 | t.string :run_cmd 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20160903211542_create_submissions.rb: -------------------------------------------------------------------------------- 1 | class CreateSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :submissions do |t| 4 | t.text :source_code 5 | t.integer :language_id 6 | t.text :input 7 | t.text :expected_output 8 | t.text :actual_output 9 | t.integer :status_id 10 | t.datetime :created_at 11 | t.datetime :finished_at 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20160905015919_add_source_file_to_language.rb: -------------------------------------------------------------------------------- 1 | class AddSourceFileToLanguage < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :languages, :source_file, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160905030833_add_time_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddTimeToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :time, :decimal 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160907052244_add_memory_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddMemoryToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :memory, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170131231840_rename_actual_output_in_submissions_to_stdout.rb: -------------------------------------------------------------------------------- 1 | class RenameActualOutputInSubmissionsToStdout < ActiveRecord::Migration[5.0] 2 | def change 3 | rename_column :submissions, :actual_output, :stdout 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170131233631_add_stderr_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddStderrToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :stderr, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170201000546_add_token_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddTokenToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :token, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170203021217_add_index_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :submissions, :token 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170203023903_add_number_of_runs_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddNumberOfRunsToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :number_of_runs, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170203215830_add_configuration_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddConfigurationToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :cpu_time_limit, :decimal 4 | add_column :submissions, :cpu_extra_time, :decimal 5 | add_column :submissions, :wall_time_limit, :decimal 6 | add_column :submissions, :memory_limit, :integer 7 | add_column :submissions, :stack_limit, :integer 8 | add_column :submissions, :max_processes_and_or_threads, :integer 9 | add_column :submissions, :enable_per_process_and_thread_time_limit, :boolean 10 | add_column :submissions, :enable_per_process_and_thread_memory_limit, :boolean 11 | add_column :submissions, :max_file_size, :integer 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170422122148_change_encode_all_submissions.rb: -------------------------------------------------------------------------------- 1 | class ChangeEncodeAllSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | Submission.all.each do |submission| 4 | submission.source_code = submission[:source_code] 5 | submission.input = submission[:input] 6 | submission.stdout = submission[:stdout] 7 | submission.expected_output = submission[:expected_output] 8 | submission.stderr = submission[:stderr] 9 | submission.save 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20170919210318_add_compile_output_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddCompileOutputToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :compile_output, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170919215014_add_exit_code_exit_signal_and_message_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddExitCodeExitSignalAndMessageToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :exit_code, :integer 4 | add_column :submissions, :exit_signal, :integer 5 | add_column :submissions, :message, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170928174721_add_wall_time_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddWallTimeToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :wall_time, :decimal 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170929175654_rename_input_to_stdin_in_submissions.rb: -------------------------------------------------------------------------------- 1 | class RenameInputToStdinInSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | rename_column :submissions, :input, :stdin 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190921115544_add_compiler_options_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddCompilerOptionsToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :compiler_options, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190921193416_add_command_line_arguments_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddCommandLineArgumentsToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :command_line_arguments, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20191230001624_add_is_archived_to_languages.rb: -------------------------------------------------------------------------------- 1 | class AddIsArchivedToLanguages < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :languages, :is_archived, :bool, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200113231131_add_redirect_stderr_to_stdout_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddRedirectStderrToStdoutToSubmission < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :redirect_stderr_to_stdout, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200114220437_add_callback_url_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddCallbackUrlToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :callback_url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200115205044_add_additional_files_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddAdditionalFilesToSubmissions < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :submissions, :additional_files, :binary 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20200327224155_create_clients.rb: -------------------------------------------------------------------------------- 1 | class CreateClients < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :clients, id: :string do |t| 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20210308152656_add_enable_network_to_submissions.rb: -------------------------------------------------------------------------------- 1 | class AddEnableNetworkToSubmissions < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :submissions, :enable_network, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20220528122710_add_started_at_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddStartedAtToSubmission < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :submissions, :started_at, :datetime 4 | add_column :submissions, :queued_at, :datetime 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20220528131626_add_updated_at_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddUpdatedAtToSubmission < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :submissions, :updated_at, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20220528155848_add_hosts_to_submission.rb: -------------------------------------------------------------------------------- 1 | class AddHostsToSubmission < ActiveRecord::Migration[5.2] 2 | def change 3 | add_column :submissions, :queue_host, :string 4 | add_column :submissions, :execution_host, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 2022_05_28_155848) do 14 | 15 | # These are extensions that must be enabled in order to support this database 16 | enable_extension "plpgsql" 17 | 18 | create_table "clients", id: :string, force: :cascade do |t| 19 | end 20 | 21 | create_table "languages", id: :serial, force: :cascade do |t| 22 | t.string "name" 23 | t.string "compile_cmd" 24 | t.string "run_cmd" 25 | t.string "source_file" 26 | t.boolean "is_archived", default: false 27 | end 28 | 29 | create_table "submissions", id: :serial, force: :cascade do |t| 30 | t.text "source_code" 31 | t.integer "language_id" 32 | t.text "stdin" 33 | t.text "expected_output" 34 | t.text "stdout" 35 | t.integer "status_id" 36 | t.datetime "created_at" 37 | t.datetime "finished_at" 38 | t.decimal "time" 39 | t.integer "memory" 40 | t.text "stderr" 41 | t.string "token" 42 | t.integer "number_of_runs" 43 | t.decimal "cpu_time_limit" 44 | t.decimal "cpu_extra_time" 45 | t.decimal "wall_time_limit" 46 | t.integer "memory_limit" 47 | t.integer "stack_limit" 48 | t.integer "max_processes_and_or_threads" 49 | t.boolean "enable_per_process_and_thread_time_limit" 50 | t.boolean "enable_per_process_and_thread_memory_limit" 51 | t.integer "max_file_size" 52 | t.text "compile_output" 53 | t.integer "exit_code" 54 | t.integer "exit_signal" 55 | t.text "message" 56 | t.decimal "wall_time" 57 | t.string "compiler_options" 58 | t.string "command_line_arguments" 59 | t.boolean "redirect_stderr_to_stdout" 60 | t.string "callback_url" 61 | t.binary "additional_files" 62 | t.boolean "enable_network" 63 | t.datetime "started_at" 64 | t.datetime "queued_at" 65 | t.datetime "updated_at" 66 | t.string "queue_host" 67 | t.string "execution_host" 68 | t.index ["token"], name: "index_submissions_on_token" 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | require_relative 'languages/archived' 2 | require_relative 'languages/active' 3 | 4 | ActiveRecord::Base.transaction do 5 | Language.unscoped.delete_all 6 | @languages.each_with_index do |language, index| 7 | Language.create( 8 | id: language[:id], 9 | name: language[:name], 10 | is_archived: language[:is_archived], 11 | source_file: language[:source_file], 12 | compile_cmd: language[:compile_cmd], 13 | run_cmd: language[:run_cmd], 14 | ) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | judge0: 4 | image: judge0/judge0:latest-dev 5 | build: 6 | context: . 7 | target: development 8 | volumes: 9 | - .:/api 10 | ports: 11 | - "2358:2358" 12 | - "3001:3001" # For ./scripts/dev/serve-docs 13 | privileged: true 14 | 15 | db: 16 | image: postgres:14.3 17 | env_file: judge0.conf 18 | volumes: 19 | - postgres-data:/var/lib/postgresql/data/ 20 | restart: always 21 | 22 | # Not actually currently used. Just for testing purposes in development. 23 | pgbouncer: 24 | image: pgbouncer/pgbouncer:1.15.0 25 | environment: # DATABASES_* are the same as from judge0.conf 26 | DATABASES_HOST: db 27 | DATABASES_PORT: 5432 28 | DATABASES_DBNAME: judge0 29 | DATABASES_USER: judge0 30 | DATABASES_PASSWORD: YourPasswordHere1234 31 | PGBOUNCER_LISTEN_PORT: 5432 # Set the same as Postgres 32 | restart: always 33 | 34 | redis: 35 | image: redis:6.2.7 36 | command: [ 37 | "bash", "-c", 38 | 'docker-entrypoint.sh --appendonly yes --requirepass "$$REDIS_PASSWORD"' 39 | ] 40 | env_file: judge0.conf 41 | volumes: 42 | - redis-data:/data 43 | restart: always 44 | 45 | resque: 46 | image: ennexa/resque-web:latest 47 | entrypoint: "" 48 | command: [ 49 | "bash", "-c", 50 | 'resque-web -FL -r redis://:$$REDIS_PASSWORD@$$REDIS_HOST:$$REDIS_PORT' 51 | ] 52 | env_file: judge0.conf 53 | ports: 54 | - "5678:5678" 55 | restart: always 56 | 57 | volumes: 58 | postgres-data: 59 | redis-data: 60 | -------------------------------------------------------------------------------- /docker-compose.https.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | x-logging: 4 | &default-logging 5 | logging: 6 | driver: json-file 7 | options: 8 | max-size: 100M 9 | 10 | services: 11 | nginx: 12 | image: judge0/nginxproxy-nginx-proxy:latest-2021-04-26 13 | environment: 14 | HTTPS_METHOD: noredirect 15 | volumes: 16 | - ./srv/nginx/certs:/etc/nginx/certs:ro 17 | - ./srv/nginx/conf.d:/etc/nginx/conf.d 18 | - ./srv/nginx/dhparam:/etc/nginx/dhparam 19 | - ./srv/nginx/html:/usr/share/nginx/html 20 | - ./srv/nginx/htpasswd:/etc/nginx/htpasswd 21 | - ./srv/nginx/vhost.d:/etc/nginx/vhost.d 22 | - /var/run/docker.sock:/tmp/docker.sock:ro 23 | ports: 24 | - "80:80" 25 | - "443:443" 26 | <<: *default-logging 27 | restart: always 28 | 29 | acme: 30 | image: judge0/nginxproxy-acme-companion:2.1.0 31 | environment: 32 | DEFAULT_EMAIL: mail@yourdomain.tld 33 | volumes: 34 | - ./srv/acme/acme.sh:/etc/acme.sh 35 | - ./srv/nginx/certs:/etc/nginx/certs:rw 36 | - /var/run/docker.sock:/var/run/docker.sock:ro 37 | volumes_from: 38 | - nginx 39 | <<: *default-logging 40 | restart: always 41 | 42 | server: 43 | image: judge0/judge0:latest 44 | environment: 45 | - VIRTUAL_HOST=subdomain.yourdomain.tld 46 | - LETSENCRYPT_HOST=subdomain.yourdomain.tld 47 | volumes: 48 | - ./judge0.conf:/judge0.conf:ro 49 | privileged: true 50 | <<: *default-logging 51 | restart: always 52 | 53 | worker: 54 | image: judge0/judge0:latest 55 | command: ["./scripts/workers"] 56 | volumes: 57 | - ./judge0.conf:/judge0.conf:ro 58 | privileged: true 59 | <<: *default-logging 60 | restart: always 61 | 62 | db: 63 | image: postgres:13.0 64 | env_file: judge0.conf 65 | volumes: 66 | - postgres-data:/var/lib/postgresql/data/ 67 | <<: *default-logging 68 | restart: always 69 | 70 | redis: 71 | image: redis:6.0 72 | command: [ 73 | "bash", "-c", 74 | 'docker-entrypoint.sh --appendonly yes --requirepass "$$REDIS_PASSWORD"' 75 | ] 76 | env_file: judge0.conf 77 | volumes: 78 | - redis-data:/data 79 | <<: *default-logging 80 | restart: always 81 | 82 | volumes: 83 | postgres-data: 84 | redis-data: 85 | -------------------------------------------------------------------------------- /docker-compose.server.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | x-logging: 4 | &default-logging 5 | logging: 6 | driver: json-file 7 | options: 8 | max-size: 100M 9 | 10 | services: 11 | server: 12 | image: judge0/judge0:latest 13 | volumes: 14 | - ./judge0.conf:/judge0.conf:ro 15 | ports: 16 | - "2358:2358" 17 | privileged: true 18 | <<: *default-logging 19 | restart: always 20 | 21 | db: 22 | image: postgres:13.0 23 | env_file: judge0.conf 24 | volumes: 25 | - postgres-data:/var/lib/postgresql/data/ 26 | ports: 27 | - "5432:5432" 28 | <<: *default-logging 29 | restart: always 30 | 31 | redis: 32 | image: redis:6.0 33 | command: [ 34 | "bash", "-c", 35 | 'docker-entrypoint.sh --appendonly yes --requirepass "$$REDIS_PASSWORD"' 36 | ] 37 | env_file: judge0.conf 38 | volumes: 39 | - redis-data:/data 40 | ports: 41 | - "6379:6379" 42 | <<: *default-logging 43 | restart: always 44 | 45 | volumes: 46 | postgres-data: 47 | redis-data: 48 | -------------------------------------------------------------------------------- /docker-compose.standalone.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | x-logging: &logging 4 | logging: 5 | driver: json-file 6 | options: 7 | max-size: 100M 8 | 9 | x-db: &db 10 | POSTGRES_HOST: db 11 | POSTGRES_PORT: 5432 12 | POSTGRES_DB: judge0 13 | POSTGRES_USER: judge0 14 | POSTGRES_PASSWORD: YourPasswordHere1234 15 | 16 | x-redis: &redis 17 | REDIS_HOST: redis 18 | REDIS_PORT: 6379 19 | REDIS_PASSWORD: YourPasswordHere1234 20 | 21 | x-config: &config 22 | JUDGE0_CONFIGURATION_OPTIONS_HELP: https://github.com/judge0/judge0/blob/master/judge0.conf 23 | 24 | services: 25 | server: 26 | image: judge0/judge0:latest 27 | environment: 28 | <<: *config 29 | <<: *db 30 | <<: *redis 31 | ports: 32 | - "2358:2358" 33 | privileged: true 34 | <<: *logging 35 | restart: always 36 | 37 | worker: 38 | image: judge0/judge0:latest 39 | command: ["./scripts/workers"] 40 | environment: 41 | <<: *config 42 | <<: *db 43 | <<: *redis 44 | privileged: true 45 | <<: *logging 46 | restart: always 47 | 48 | db: 49 | image: postgres:13.0 50 | environment: *db 51 | volumes: 52 | - postgres-data:/var/lib/postgresql/data/ 53 | <<: *logging 54 | restart: always 55 | 56 | redis: 57 | image: redis:6.0 58 | command: [ 59 | "bash", "-c", 60 | 'docker-entrypoint.sh --appendonly yes --requirepass "$$REDIS_PASSWORD"' 61 | ] 62 | environment: *redis 63 | volumes: 64 | - redis-data:/data 65 | <<: *logging 66 | restart: always 67 | 68 | volumes: 69 | postgres-data: 70 | redis-data: 71 | -------------------------------------------------------------------------------- /docker-compose.workers.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | x-logging: 4 | &default-logging 5 | logging: 6 | driver: json-file 7 | options: 8 | max-size: 100M 9 | 10 | services: 11 | worker: 12 | image: judge0/judge0:latest 13 | command: ["./scripts/workers"] 14 | volumes: 15 | - ./judge0.conf:/judge0.conf:ro 16 | privileged: true 17 | <<: *default-logging 18 | restart: always 19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | 3 | x-logging: 4 | &default-logging 5 | logging: 6 | driver: json-file 7 | options: 8 | max-size: 100M 9 | 10 | services: 11 | server: 12 | image: us-central1-docker.pkg.dev/neetcode-dd170/judge0/judge0withpythonpackages:latest 13 | volumes: 14 | - ./judge0.conf:/judge0.conf:ro 15 | ports: 16 | - "2358:2358" 17 | privileged: true 18 | <<: *default-logging 19 | restart: always 20 | 21 | worker: 22 | image: us-central1-docker.pkg.dev/neetcode-dd170/judge0/judge0withpythonpackages:latest 23 | command: ["./scripts/workers"] 24 | volumes: 25 | - ./judge0.conf:/judge0.conf:ro 26 | privileged: true 27 | <<: *default-logging 28 | restart: always 29 | 30 | db: 31 | image: postgres:13.0 32 | env_file: judge0.conf 33 | volumes: 34 | - postgres-data:/var/lib/postgresql/data/ 35 | <<: *default-logging 36 | restart: always 37 | 38 | redis: 39 | image: redis:6.0 40 | command: [ 41 | "bash", "-c", 42 | 'docker-entrypoint.sh --appendonly yes --requirepass "$$REDIS_PASSWORD"' 43 | ] 44 | env_file: judge0.conf 45 | volumes: 46 | - redis-data:/data 47 | <<: *default-logging 48 | restart: always 49 | 50 | volumes: 51 | postgres-data: 52 | redis-data: 53 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cron 3 | exec "$@" -------------------------------------------------------------------------------- /docs/api/_unauthenticated.md: -------------------------------------------------------------------------------- 1 | + Response 401 2 | Authentication failed. Please read about [authentication](#authentication) process. 3 | + Body -------------------------------------------------------------------------------- /docs/api/_unauthorized.md: -------------------------------------------------------------------------------- 1 | + Response 403 2 | Authorization failed. Please read about [authorization](#authorization) process. 3 | + Body -------------------------------------------------------------------------------- /docs/api/authentication/authentication.md: -------------------------------------------------------------------------------- 1 | # Group Authentication 2 | Administrators of Judge0 can configure Judge0 to require you to have an authentication token (a.k.a. API key). 3 | If that is the case with the instance of Judge0 you are using, then you 4 | should provide `X-Auth-Token` header field in **every** API request. 5 | 6 | ## Authenticate [/authenticate] 7 | ### Authenticate [POST] 8 | Check if your authentication token is valid. 9 | 10 | ::: note 11 |

Note

12 | * `X-Auth-Token` is default header field name, but administrators of Judge0 instance you are using 13 | can change this default field name. 14 | * Contact administrator of Judge0 instance you are using to get your authentication token. 15 | ::: 16 | 17 | ::: warning 18 |

Security Warning

19 | * Although you can send authentication token as URI parameter, **always** send authentication token through headers. 20 | ::: 21 | 22 | + Request 23 | + Headers 24 | ``` 25 | X-Auth-Token: f6583e60-b13b-4228-b554-2eb332ca64e7 26 | ``` 27 | 28 | + Response 200 29 | If your authentication token is valid or authentication is disabled. 30 | If authentication is disabled you do not need an authentication token. 31 | + Body 32 | 33 | + Response 401 34 | Authentication failed because your authentication token is invalid. 35 | + Body -------------------------------------------------------------------------------- /docs/api/authorization/authorization.md: -------------------------------------------------------------------------------- 1 | # Group Authorization 2 | To issue some API calls you need to be authorized. For example, you need to be authorized to 3 | [list all submissions](#submissions-submission-get-1) on Judge0. 4 | 5 | ## Authorize [/authorize{?X-Auth-User}] 6 | ### Authorize [POST] 7 | With this API call you can check if your authorization token is valid. If authentication is enabled you should also 8 | authenticate in this API call. 9 | 10 | ::: note 11 |

Note

12 | * `X-Auth-User` is default header field name, but administrators of Judge0 instance you are using 13 | can change this default field name. 14 | * Contact administrator of Judge0 instance you are using to get your authorization token. 15 | ::: 16 | 17 | ::: warning 18 |

Security Warning

19 | * Although you can send authorization token as URI parameter, **always** send authorization token through headers. 20 | ::: 21 | 22 | + Request 23 | + Headers 24 | ``` 25 | X-Auth-User: a1133bc6-a0f6-46bf-a2d8-6157418c6fe2 26 | ``` 27 | 28 | 29 | + Response 200 30 | If your authorization token is valid. 31 | + Body 32 | 33 | 34 | 35 | + Response 403 36 | Authorization failed because your authorization token is invalid. 37 | + Body -------------------------------------------------------------------------------- /docs/api/docs.md: -------------------------------------------------------------------------------- 1 | FORMAT: 1A 2 | HOST: https://ce.judge0.com 3 | 4 | # Judge0 CE - API Docs 5 | 6 | 7 | 8 | ## About 9 | [Judge0](https://ce.judge0.com) is a robust, scalable, and [open-source](https://github.com/judge0/judge0) **online code execution system**. You can use it to build a wide range of applications that need online code execution features. Some examples include competitive programming platforms, e-learning platforms, candidate assessment and recruitment platforms, online code editors, online IDEs, and many more. 10 | 11 | In our research paper [Robust and Scalable Online Code Execution System](https://paper.judge0.com), we present Judge0's modern modular architecture that can be easily deployed and scaled. We study its design, comment on the various challenges in building such systems, and compare it with other available online code execution systems and online judge systems. 12 | 13 | To see Judge0 in action, try [Judge0 IDE](https://ide.judge0.com) - our free and open-source online code editor. You can also try using a [dummy client](/dummy-client.html) that can help you explore and test most of the features of Judge0. 14 | 15 | Easily integrate online code editor with code execution (a.k.a. online compiler) to your website with our [**embeddable web widgets**](https://judge0.com/#judge0-widgets). 16 | 17 | ## Features 18 | 30 | 31 | ## Get Started 32 | Feel free to start with the [**FREE Basic Plan**](https://judge0.com/ce) on RapidAPI or [host it yourself](https://github.com/judge0/judge0/blob/master/CHANGELOG.md#deployment-procedure). 33 | 34 | You can find our detailed plans and pricing [here](https://judge0.com/#pricing). 35 | 36 | **Why should you use Judge0 on RapidAPI?** 37 | 38 | Our infrastructure allows you to **focus on building your product** and forget about the know-how of maintaining and scaling Judge0. 39 | 40 | **RapidAPI plans are not (good) enough for you?** 41 | 42 | Let's talk. [Contact us](mailto:contact@judge0.com). 43 | 44 | ## Flavors 45 | Judge0 comes in two flavors: [Judge0 CE](https://judge0.com/ce) and [Judge0 Extra CE](https://judge0.com/extra-ce). They differ mostly in the [supported languages](https://github.com/judge0/judge0#supported-languages). 46 | 47 | You can find the source code for Judge0 CE on the [`master`](https://github.com/judge0/judge0/tree/master) branch, while you can find the source code for Judge0 Extra CE on the [`extra`](https://github.com/judge0/judge0/tree/extra) branch. 48 | 49 | Judge0 Extra CE is also available on [RapidAPI](https://judge0.com/extra-ce). 50 | 51 | ## Version 52 | This document describes Judge0 CE [v1.13.0](https://github.com/judge0/judge0/tree/v1.13.0). 53 | 54 | ## Date and time formats 55 | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard is used. 56 | 57 | Example: `2016-09-11T10:19:35Z` 58 | 59 | ## License 60 | Judge0 is licensed under the [GNU General Public License v3.0](https://github.com/judge0/judge0/blob/master/LICENSE). 61 | 62 | ## Donate 63 | Your are more than welcome to support Judge0 development on [Patreon](https://www.patreon.com/hermanzdosilovic), via [PayPal](https://paypal.me/hermanzdosilovic) or [Revolut](https://pay.revolut.com/profile/hermancy5). Thank you. 64 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /docs/api/health_check/health_check.md: -------------------------------------------------------------------------------- 1 | # Group Health Check 2 | -------------------------------------------------------------------------------- /docs/api/health_check/workers.md: -------------------------------------------------------------------------------- 1 | ## Workers [/workers] 2 | ### Workers [GET] 3 | For each queue you will get: 4 | - `queue` name 5 | - queue `size`, i.e. number of submissions that are currently waiting to be processed 6 | - `available` number of workers 7 | - how many workers are `idle` 8 | - how many workers are currently `working` 9 | - how many workers are `paused` 10 | - how many jobs `failed` 11 | 12 | + Response 200 (application/json) 13 | [ 14 | { 15 | "queue": "default", 16 | "size": 0, 17 | "available": 1, 18 | "idle": 1, 19 | "working": 0, 20 | "paused": 0, 21 | "failed": 0 22 | } 23 | ] -------------------------------------------------------------------------------- /docs/api/hostname.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 22 | -------------------------------------------------------------------------------- /docs/api/information/about.md: -------------------------------------------------------------------------------- 1 | ## About [/about] 2 | ## About [GET] 3 | Returns general information. 4 | 5 | + Response 200 (application/json) 6 | + Body 7 | { 8 | "version": "1.5.0", 9 | "homepage": "https://judge0.com", 10 | "source_code": "https://github.com/judge0/judge0", 11 | "maintainer": "Herman Zvonimir Došilović " 12 | } -------------------------------------------------------------------------------- /docs/api/information/information.md: -------------------------------------------------------------------------------- 1 | # Group Information 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /docs/api/information/isolate.md: -------------------------------------------------------------------------------- 1 | ## Isolate [/isolate] 2 | ## Isolate [GET] 3 | Returns result of [`isolate --version`](https://github.com/ioi/isolate). -------------------------------------------------------------------------------- /docs/api/information/license.md: -------------------------------------------------------------------------------- 1 | ## License [/license] 2 | ## License [GET] 3 | Returns a license. -------------------------------------------------------------------------------- /docs/api/information/version.md: -------------------------------------------------------------------------------- 1 | ## Version [/version] 2 | ## Version [GET] 3 | Returns current version. -------------------------------------------------------------------------------- /docs/api/statistics/statistics.md: -------------------------------------------------------------------------------- 1 | # Group Statistics 2 | ## Statistics [/statistics] 3 | ### Statistics [GET] 4 | 5 | Get some statistics from current instance. Result is cached for 10 minutes. 6 | 7 | + Parameters 8 | + invalidate_cache (optional, boolean, `false`) ... Set to `true` if you want to invalidate current cache and fetch new statistics. 9 | -------------------------------------------------------------------------------- /docs/api/statuses_and_languages/get_a_language.md: -------------------------------------------------------------------------------- 1 | ## Get a Language [GET] 2 | + Parameters 3 | + id (required, integer, `1`) ... Language ID. 4 | 5 | + Response 200 (application/json) 6 | + Body 7 | { 8 | "id": 1, 9 | "name": "Bash (4.4)", 10 | "is_archived": true, 11 | "source_file": "script.sh", 12 | "compile_cmd": null, 13 | "run_cmd": "/usr/local/bash-4.4/bin/bash script.sh" 14 | } -------------------------------------------------------------------------------- /docs/api/statuses_and_languages/get_languages.md: -------------------------------------------------------------------------------- 1 | ### Get Languages [GET] 2 | Get active languages. 3 | 4 | + Response 200 (application/json) 5 | [ 6 | { 7 | "id": 45, 8 | "name": "Assembly (NASM 2.14.02)" 9 | }, 10 | { 11 | "id": 46, 12 | "name": "Bash (5.0.0)" 13 | }, 14 | { 15 | "id": 47, 16 | "name": "Basic (FBC 1.07.1)" 17 | }, 18 | { 19 | "id": 48, 20 | "name": "C (GCC 7.4.0)" 21 | }, 22 | { 23 | "id": 52, 24 | "name": "C++ (GCC 7.4.0)" 25 | }, 26 | { 27 | "id": 49, 28 | "name": "C (GCC 8.3.0)" 29 | }, 30 | { 31 | "id": 53, 32 | "name": "C++ (GCC 8.3.0)" 33 | }, 34 | { 35 | "id": 50, 36 | "name": "C (GCC 9.2.0)" 37 | }, 38 | { 39 | "id": 54, 40 | "name": "C++ (GCC 9.2.0)" 41 | }, 42 | { 43 | "id": 51, 44 | "name": "C# (Mono 6.6.0.161)" 45 | }, 46 | { 47 | "id": 55, 48 | "name": "Common Lisp (SBCL 2.0.0)" 49 | }, 50 | { 51 | "id": 56, 52 | "name": "D (DMD 2.089.1)" 53 | }, 54 | { 55 | "id": 57, 56 | "name": "Elixir (1.9.4)" 57 | }, 58 | { 59 | "id": 58, 60 | "name": "Erlang (OTP 22.2)" 61 | }, 62 | { 63 | "id": 44, 64 | "name": "Executable" 65 | }, 66 | { 67 | "id": 59, 68 | "name": "Fortran (GFortran 9.2.0)" 69 | }, 70 | { 71 | "id": 60, 72 | "name": "Go (1.13.5)" 73 | }, 74 | { 75 | "id": 61, 76 | "name": "Haskell (GHC 8.8.1)" 77 | }, 78 | { 79 | "id": 62, 80 | "name": "Java (OpenJDK 13.0.1)" 81 | }, 82 | { 83 | "id": 63, 84 | "name": "JavaScript (Node.js 12.14.0)" 85 | }, 86 | { 87 | "id": 64, 88 | "name": "Lua (5.3.5)" 89 | }, 90 | { 91 | "id": 65, 92 | "name": "OCaml (4.09.0)" 93 | }, 94 | { 95 | "id": 66, 96 | "name": "Octave (5.1.0)" 97 | }, 98 | { 99 | "id": 67, 100 | "name": "Pascal (FPC 3.0.4)" 101 | }, 102 | { 103 | "id": 68, 104 | "name": "PHP (7.4.1)" 105 | }, 106 | { 107 | "id": 43, 108 | "name": "Plain Text" 109 | }, 110 | { 111 | "id": 69, 112 | "name": "Prolog (GNU Prolog 1.4.5)" 113 | }, 114 | { 115 | "id": 70, 116 | "name": "Python (2.7.17)" 117 | }, 118 | { 119 | "id": 71, 120 | "name": "Python (3.8.1)" 121 | }, 122 | { 123 | "id": 72, 124 | "name": "Ruby (2.7.0)" 125 | }, 126 | { 127 | "id": 73, 128 | "name": "Rust (1.40.0)" 129 | }, 130 | { 131 | "id": 74, 132 | "name": "TypeScript (3.7.4)" 133 | } 134 | ] -------------------------------------------------------------------------------- /docs/api/statuses_and_languages/get_statuses.md: -------------------------------------------------------------------------------- 1 | ## Status [/statuses] 2 | ### Get Statuses [GET] 3 | + Response 200 (application/json) 4 | [ 5 | { 6 | "id": 1, 7 | "description": "In Queue" 8 | }, 9 | { 10 | "id": 2, 11 | "description": "Processing" 12 | }, 13 | { 14 | "id": 3, 15 | "description": "Accepted" 16 | }, 17 | { 18 | "id": 4, 19 | "description": "Wrong Answer" 20 | }, 21 | { 22 | "id": 5, 23 | "description": "Time Limit Exceeded" 24 | }, 25 | { 26 | "id": 6, 27 | "description": "Compilation Error" 28 | }, 29 | { 30 | "id": 7, 31 | "description": "Runtime Error (SIGSEGV)" 32 | }, 33 | { 34 | "id": 8, 35 | "description": "Runtime Error (SIGXFSZ)" 36 | }, 37 | { 38 | "id": 9, 39 | "description": "Runtime Error (SIGFPE)" 40 | }, 41 | { 42 | "id": 10, 43 | "description": "Runtime Error (SIGABRT)" 44 | }, 45 | { 46 | "id": 11, 47 | "description": "Runtime Error (NZEC)" 48 | }, 49 | { 50 | "id": 12, 51 | "description": "Runtime Error (Other)" 52 | }, 53 | { 54 | "id": 13, 55 | "description": "Internal Error" 56 | }, 57 | { 58 | "id": 14, 59 | "description": "Exec Format Error" 60 | } 61 | ] 62 | -------------------------------------------------------------------------------- /docs/api/statuses_and_languages/languages.md: -------------------------------------------------------------------------------- 1 | ## Language [/languages/{id}] 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/api/statuses_and_languages/statuses_and_languages.md: -------------------------------------------------------------------------------- 1 | # Group Statuses and Languages 2 | 3 | -------------------------------------------------------------------------------- /docs/api/style.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 25 | -------------------------------------------------------------------------------- /docs/api/submissions/create_a_submission.md: -------------------------------------------------------------------------------- 1 | ### Create a Submission [POST] 2 | Creates new submission. Created submission waits in queue to be processed. On successful 3 | creation, you are returned submission token which can be used to [check submission status](#submissions-submission-get). 4 | 5 | If submission's `source_code`, `stdin` or `expected_output` contains non printable characters, or 6 | characters which cannot be sent with JSON, then set `base64_encoded` parameter to `true` and 7 | send these attributes Base64 encoded. Your responsibility is to encode each of mentioned attributes 8 | (`source_code`, `stdin` and `expected_output`) even if just one of them contains non printable 9 | characters. By default, this parameter is set to `false` and Judge0 assumes you are sending plain text data. 10 | 11 | By default you are returned submission token on successful submission creation. With this token you can [check submission status](#submission-submission-get). 12 | Instead of checking submission status by making another request, you can set the `wait` query parameter to `true` which will enable you to get submission status immediately as part of response to the request you made. 13 | Please note that this feature may or may not be enabled on all Judge0 hosts. So before using this feature please check [configuration](#system-and-configuration-configuration-info-get) of Judge0 you are using. On an [official Judge0](https://api.judge0.com) this feature **is not** enabled. 14 | 15 | ::: note 16 |

Note

17 | * We **do not** recommend the use of `wait=true` feature because it does not scale well. 18 | ::: 19 | 20 | + Parameters 21 | + base64_encoded = `false` (optional, boolean, `false`) ... Set to `true` if you want to send Base64 encoded data to Judge0. 22 | + wait = `false` (optional, boolean, `false`) ... Set to `true` to immediately get submission result. 23 | 24 | + Request (application/json) 25 | { 26 | "source_code": "#include \n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\\n\", name);\n return 0;\n}", 27 | "language_id": 4, 28 | "stdin": "world" 29 | } 30 | 31 | + Response 201 (application/json) 32 | { 33 | "token": "d85cd024-1548-4165-96c7-7bc88673f194" 34 | } 35 | 36 | 37 | + Request (application/json) 38 | { 39 | "source_code": "#include \n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\\n\", name);\n return 0;\n}" 40 | } 41 | 42 | + Response 422 (application/json) 43 | { 44 | "language_id": [ 45 | "can't be blank" 46 | ] 47 | } 48 | 49 | 50 | + Request (application/json) 51 | { 52 | "source_code": "#include \n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\\n\", name);\n return 0;\n}", 53 | "language_id": 150000, 54 | "stdin": "world", 55 | "expected_output": "hello, world" 56 | } 57 | 58 | + Response 422 (application/json) 59 | { 60 | "language_id": [ 61 | "language with id 150000 doesn't exist" 62 | ] 63 | } 64 | 65 | 66 | + Request (application/json) 67 | { 68 | "source_code": "#include \n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\\n\", name);\n return 0;\n}", 69 | "language_id": 4, 70 | "number_of_runs": 1, 71 | "stdin": "Judge0", 72 | "expected_output": "hello, Judge0", 73 | "cpu_time_limit": 1, 74 | "cpu_extra_time": 0.5, 75 | "wall_time_limit": 100000, 76 | "memory_limit": 128000, 77 | "stack_limit": 128000, 78 | "enable_per_process_and_thread_time_limit": false, 79 | "enable_per_process_and_thread_memory_limit": false, 80 | "max_file_size": 1024 81 | } 82 | 83 | + Response 422 (application/json) 84 | { 85 | "wall_time_limit": [ 86 | "must be less than or equal to 150" 87 | ] 88 | } 89 | 90 | 91 | + Request (appliction/json) 92 | Sending Base64 encoded `source_code` and `stdin`. Note that in this request `base64_encoded` query parameter **must** be 93 | set to `true`. 94 | + Body 95 | { 96 | "source_code": "I2luY2x1ZGUgPHN0ZGlvLmg+CgppbnQgbWFpbih2b2lkKSB7CiAgY2hhciBuYW1lWzEwXTsKICBzY2FuZigiJXMiLCBuYW1lKTsKICBwcmludGYoImhlbGxvLCAlc1xuIiwgbmFtZSk7CiAgcmV0dXJuIDA7Cn0=", 97 | "language_id": 4, 98 | "input": "SnVkZ2Uw" 99 | } 100 | 101 | + Response 201 (application/json) 102 | { 103 | "token": "f3fe0215-72f3-4fe6-97f5-353df6682db4" 104 | } 105 | 106 | + Request (application/json) 107 | Creating a submission with `wait=true` that results with one or more attributes that cannot be serialized to JSON without Base64 encoding. 108 | + Body 109 | { 110 | "language_id": 70, 111 | "source_code": "print(\"\\xFE\")" 112 | } 113 | 114 | + Response 201 (application/json) 115 | { 116 | "token": "fcd0de6d-ee52-4a9d-8a00-6e0d98d394cf", 117 | "error": "some attributes for this submission cannot be converted to UTF-8, use base64_encoded=true query parameter" 118 | } 119 | 120 | + Request (application/json) 121 | Waiting for submission to finish. Note that in this request `wait` query parameter **must** be set to `true`. 122 | + Body 123 | { 124 | "source_code": "#include \n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\\n\", name);\n return 0;\n}", 125 | "language_id": "4", 126 | "stdin": "Judge0", 127 | "expected_output": "hello, Judge0" 128 | } 129 | 130 | + Response 201 (application/json) 131 | { 132 | "stdout": "hello, Judge0\n", 133 | "time": "0.001", 134 | "memory": 380, 135 | "stderr": null, 136 | "token": "eb0dd001-66db-47f4-8a69-b736c9bc23f6", 137 | "compile_output": null, 138 | "message": null, 139 | "status": { 140 | "id": 3, 141 | "description": "Accepted" 142 | } 143 | } 144 | 145 | + Response 400 (application/json) 146 | If wait is not allowed. 147 | + Body 148 | { 149 | "error": "wait not allowed" 150 | } 151 | 152 | + Response 503 (application/json) 153 | If submission queue is full. 154 | + Body 155 | { 156 | "error": "queue is full" 157 | } 158 | 159 | 160 | -------------------------------------------------------------------------------- /docs/api/submissions/create_a_submission_batch.md: -------------------------------------------------------------------------------- 1 | ### Create a Submission Batch [POST] 2 | Create multiple submissions at once. 3 | 4 | + Parameters 5 | + base64_encoded = `false` (optional, boolean, `false`) ... Set to `true` if you are sending Base64 encoded data. 6 | 7 | + Request (application/json) 8 | { 9 | "submissions": 10 | [ 11 | { 12 | "language_id": 46, 13 | "source_code": "echo hello from Bash" 14 | }, 15 | { 16 | "language_id": 71, 17 | "source_code": "print(\"hello from Python\")" 18 | }, 19 | { 20 | "language_id": 72, 21 | "source_code": "puts(\"hello from Ruby\")" 22 | } 23 | ] 24 | } 25 | 26 | + Response 201 (application/json) 27 | [ 28 | { 29 | "token": "db54881d-bcf5-4c7b-a2e3-d33fe7e25de7" 30 | }, 31 | { 32 | "token": "ecc52a9b-ea80-4a00-ad50-4ab6cc3bb2a1" 33 | }, 34 | { 35 | "token": "1b35ec3b-5776-48ef-b646-d5522bdeb2cc" 36 | } 37 | ] 38 | 39 | + Request (application/json) 40 | { 41 | "submissions": 42 | [ 43 | { 44 | "language_id": 46, 45 | "source_code": "echo hello from Bash" 46 | }, 47 | { 48 | "language_id": 123456789, 49 | "source_code": "print(\"hello from Python\")" 50 | }, 51 | { 52 | "language_id": 72, 53 | "source_code": "" 54 | } 55 | ] 56 | } 57 | 58 | + Response 201 (application/json) 59 | [ 60 | { 61 | "token": "c2dd8881-644b-462d-b1f9-73dd3bb0118a" 62 | }, 63 | { 64 | "language_id": [ 65 | "language with id 123456789 doesn't exist" 66 | ] 67 | }, 68 | { 69 | "source_code": [ 70 | "can't be blank" 71 | ] 72 | } 73 | ] -------------------------------------------------------------------------------- /docs/api/submissions/delete_a_submission.md: -------------------------------------------------------------------------------- 1 | ### Delete a Submission [DELETE] 2 | Delete specific submission. 3 | 4 | You need to be authorized to issue this request. Although you are 5 | authorized you might not be able to delete submission because administrator of Judge0 instance 6 | you are using disallowed submission deletion. So before using this feature please check [configuration](#system-and-configuration-configuration-info-get) of Judge0 you are using. 7 | 8 | For this request query parameter `base64_encoded` is implicitly set to `true` and cannot be changed. 9 | This guarantees you will successfully get requested submission attributes after deletion. 10 | 11 | + Parameters 12 | + token (required, string, `d85cd024-1548-4165-96c7-7bc88673f194`) ... Token of submission. You got this token when you created submission. 13 | + fields = `stdout,time,memory,stderr,token,compile_output,message,status` (optional, string, `stdout,stderr,status_id,language_id`) ... Return only the desired attributes. 14 | 15 | + Response 200 (applcation/json) 16 | + Body 17 | { 18 | "stdout": "aGVsbG8sIHdvcmxkCg==\n", 19 | "time": "0.045", 20 | "memory": 8556, 21 | "stderr": null, 22 | "token": "e80153f5-e7d8-4cd2-9e10-6c0ddbf9e3bf", 23 | "compile_output": null, 24 | "message": null, 25 | "status": { 26 | "id": 3, 27 | "description": "Accepted" 28 | } 29 | } 30 | 31 | + Response 400 (application/json) 32 | If submission status is `1` or `2`. 33 | + Body 34 | { 35 | "error": "submission cannot be deleted because its status is 1 (In Queue)" 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/api/submissions/get_a_submission.md: -------------------------------------------------------------------------------- 1 | ### Get a Submission [GET] 2 | Returns details about submission. 3 | 4 | Just like in [create submission](/#submission-submission-post) you can receive Base64 encoded data for every text type attribute (check the [table](#submission-submission) to see which attributes are text type). By default, this parameter is set to `false` and Judge0 will send you raw data. 5 | 6 | By default Judge0 is sending 8 attributes for submission. By sending `fields` query parameter you can specify exactly which attributes you want from Judge0. Special value `*` will return all available attributes. 7 | 8 | + Parameters 9 | + token (required, string, `d85cd024-1548-4165-96c7-7bc88673f194`) ... Token of submission. You got this token when you created submission. 10 | + base64_encoded (optional, boolean, `false`) ... Set to `true` if you want to receive Base64 encoded data from Judge0. You should set this to `true` if you expect the program's stdout to contain non-printable characters or if you expect the compiler to output non-printable characters during a compile error (GCC does this, for instance). 11 | + fields = `stdout,time,memory,stderr,token,compile_output,message,status` (optional, string, `stdout,stderr,status_id,language_id`) ... Return only the desired attributes. 12 | 13 | + Response 200 (applicatiion/json) 14 | { 15 | "stdout": "hello, world\n", 16 | "status_id": 5, 17 | "language_id": 4, 18 | "stderr": null 19 | } 20 | 21 | + Response 200 (application/json) 22 | This is the default response. Leave `fields` parameter empty if you want to get default response. 23 | + Body 24 | { 25 | "stdout": "hello, Judge0\n", 26 | "time": "0.001", 27 | "memory": 376, 28 | "stderr": null, 29 | "token": "8531f293-1585-4d36-a34c-73726792e6c9", 30 | "compile_output": null, 31 | "message": null, 32 | "status": { 33 | "id": 3, 34 | "description": "Accepted" 35 | } 36 | } 37 | 38 | + Response 200 (application/json) 39 | Receiving Base64 encoded data for text type attributes. Note that in this request `base64_encoded` query parameter **must** be set to `true`. 40 | + Body 41 | { 42 | "stdout": "aGVsbG8sIEp1ZGdlMAo=\n", 43 | "time": "0.002", 44 | "memory": 376, 45 | "stderr": null, 46 | "token": "4e00f214-b8cb-4fcb-977b-429113c81ece", 47 | "compile_output": null, 48 | "message": null, 49 | "status": { 50 | "id": 3, 51 | "description": "Accepted" 52 | } 53 | } 54 | 55 | + Response 400 (application/json) 56 | + Body 57 | { 58 | "error": "some attributes for this submission cannot be converted to UTF-8, use base64_encoded=true query parameter" 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /docs/api/submissions/get_a_submission_batch.md: -------------------------------------------------------------------------------- 1 | ### Get a Submission Batch [GET] 2 | Get multiple submissions at once. 3 | 4 | + Parameters 5 | + tokens (required, string, `db54881d-bcf5-4c7b-a2e3-d33fe7e25de7,ecc52a9b-ea80-4a00-ad50-4ab6cc3bb2a1,1b35ec3b-5776-48ef-b646-d5522bdeb2cc`) ... Submission tokens separeted with `,`. 6 | + base64_encoded = `false` (optional, boolean, `false`) ... Set to `true` if you want to receive Base64 encoded data. 7 | + fields = `stdout,time,memory,stderr,token,compile_output,message,status` (optional, string, `token,stdout,stderr,status_id,language_id`) ... Return only the desired attributes. 8 | 9 | + Response 200 (application/json) 10 | { 11 | "submissions": [ 12 | { 13 | "language_id": 46, 14 | "stdout": "hello from Bash\n", 15 | "status_id": 3, 16 | "stderr": null, 17 | "token": "db54881d-bcf5-4c7b-a2e3-d33fe7e25de7" 18 | }, 19 | { 20 | "language_id": 71, 21 | "stdout": "hello from Python\n", 22 | "status_id": 3, 23 | "stderr": null, 24 | "token": "ecc52a9b-ea80-4a00-ad50-4ab6cc3bb2a1" 25 | }, 26 | { 27 | "language_id": 72, 28 | "stdout": "hello from Ruby\n", 29 | "status_id": 3, 30 | "stderr": null, 31 | "token": "1b35ec3b-5776-48ef-b646-d5522bdeb2cc" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /docs/api/submissions/get_submissions.md: -------------------------------------------------------------------------------- 1 | ### Get Submissions [GET] 2 | + Parameters 3 | + base64_encoded = `false` (optional, boolean, `false`) ... Set to `true` if you want to receive Base64 encoded data from Judge0. 4 | + page = `1` (optional, integer, `4`) ... Pagination page number. 5 | + per_page = `20` (optional, integer, `2`) ... Number of submissions to return per page. 6 | + fields = `stdout,time,memory,stderr,token,compile_output,message,status` (optional, string, `status,language,time`) ... Return only the desired attributes. 7 | 8 | + Response 200 (application/json) 9 | { 10 | "submissions": [ 11 | { 12 | "time": "0.001", 13 | "status": { 14 | "id": 3, 15 | "description": "Accepted" 16 | }, 17 | "language": { 18 | "id": 4, 19 | "name": "C (gcc 7.2.0)" 20 | } 21 | }, 22 | { 23 | "time": "0.001", 24 | "status": { 25 | "id": 3, 26 | "description": "Accepted" 27 | }, 28 | "language": { 29 | "id": 4, 30 | "name": "C (gcc 7.2.0)" 31 | } 32 | } 33 | ], 34 | "meta": { 35 | "current_page": 4, 36 | "next_page": 5, 37 | "prev_page": 3, 38 | "total_pages": 31, 39 | "total_count": 62 40 | } 41 | } 42 | 43 | + Response 200 (application/json) 44 | When `base64_encoded` is set to `true`. 45 | + Body 46 | { 47 | "submissions": [ 48 | { 49 | "stdout": "aGVsbG8sIEp1ZGdlMAo=\n", 50 | "time": "0.001", 51 | "memory": 376, 52 | "stderr": null, 53 | "token": "a1133bc6-a0f6-46bf-a2d8-6157418c6fe2", 54 | "compile_output": null, 55 | "message": null, 56 | "status": { 57 | "id": 3, 58 | "description": "Accepted" 59 | } 60 | }, 61 | { 62 | "stdout": "aGVsbG8sIEp1ZGdlMAo=\n", 63 | "time": "0.001", 64 | "memory": 380, 65 | "stderr": null, 66 | "token": "eb0dd001-66db-47f4-8a69-b736c9bc23f6", 67 | "compile_output": null, 68 | "message": null, 69 | "status": { 70 | "id": 3, 71 | "description": "Accepted" 72 | } 73 | } 74 | ], 75 | "meta": { 76 | "current_page": 4, 77 | "next_page": 5, 78 | "prev_page": 3, 79 | "total_pages": 31, 80 | "total_count": 62 81 | } 82 | } 83 | 84 | + Response 400 (application/json) 85 | When `page` parameter is invalid. 86 | + Body 87 | { 88 | "error": "invalid page: -4" 89 | } 90 | 91 | + Response 400 (application/json) 92 | When `per_page` parameter is invalid. 93 | + Body 94 | { 95 | "error": "invalid per_page: -2" 96 | } 97 | 98 | + Response 400 (application/json) 99 | + Body 100 | { 101 | "error": "some attributes for one or more submissions cannot be converted to UTF-8, use base64_encoded=true query parameter" 102 | } 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /docs/api/submissions/submissions.md: -------------------------------------------------------------------------------- 1 | ## Group Submissions 2 | ## Submission [/submissions/{token}{?base64_encoded,wait,fields,page,per_page}] 3 | Submission is used for running arbitrary source code in one of 4 | the [available programming languages](#statuses-and-languages-language-get) with specified runtime constraints. 5 | 6 | Submission has 33 attributes. Attributes 1-20 are used for creating a new submissions, whereas 7 | attributes 21-33 give detailed information of submission after it's execution. 8 | 9 | Attributes 7-18 are called [*configuration variables*](#system-and-configuration-configuration-info) 10 | and can be used to configure submission runtime constraints such as time and memory limits. 11 | 12 | |# |Name |Type |Unit |Description |Default Value | 13 | |:---:|:----|:----:|:----:|:-----------|:-------------| 14 | |1|**`source_code`**|text||Program's source code.|No default. This attribute is **required** for [single-file programs](#header-single-file-programs-and-multi-file-programs).| 15 | |2|**`language_id`**|integer||[Language](#statuses-and-languages-language) ID.|No default. This attribute is **required**.| 16 | |3|`compiler_options`|string (max. 512 chars)||Options for the compiler (i.e. compiler flags).|`null`| 17 | |4|`command_line_arguments`|string (max. 512 chars)||Command line arguments for the program.|`null`| 18 | |5|`stdin`|text||Input for program.|`null`. Program won't receive anything to standard input.| 19 | |6|`expected_output`|text||Expected output of program. Used when you want to compare with `stdout`.|`null`. Program's `stdout` won't be compared with `expected_output`.| 20 | |7|`cpu_time_limit`|float|second|Default runtime limit for every program. Time in which the OS assigns the processor to different tasks is not counted.|Depends on [configuration](#system-and-configuration-configuration-info).| 21 | |8|`cpu_extra_time`|float|second|When a time limit is exceeded, wait for extra time, before killing the program. This has the advantage that the real execution time is reported, even though it slightly exceeds the limit.|Depends on [configuration](#system-and-configuration-configuration-info).| 22 | |9|`wall_time_limit`|float|second|Limit wall-clock time in seconds. Decimal numbers are allowed. This clock measures the time from the start of the program to its exit, so it does not stop when the program has lost the CPU or when it is waiting for an external event. We recommend to use `cpu_time_limit` as the main limit, but set `wall_time_limit` to a much higher value as a precaution against sleeping programs.|Depends on [configuration](#system-and-configuration-configuration-info).| 23 | |10|`memory_limit`|float|kilobyte|Limit address space of the program.|Depends on [configuration](#system-and-configuration-configuration-info).| 24 | |11|`stack_limit`|integer|kilobyte|Limit process stack.|Depends on [configuration](#system-and-configuration-configuration-info).| 25 | |12|`max_processes_and_or_threads`|integer||Maximum number of processes and/or threads program can create.|Depends on [configuration](#system-and-configuration-configuration-info).| 26 | |13|`enable_per_process_and_thread_time_limit`|boolean||If `true` then `cpu_time_limit` will be used as per process and thread.|Depends on [configuration](#system-and-configuration-configuration-info).| 27 | |14|`enable_per_process_and_thread_memory_limit`|boolean||If `true` then `memory_limit` will be used as per process and thread.|Depends on [configuration](#system-and-configuration-configuration-info).| 28 | |15|`max_file_size`|integer|kilobyte|Limit file size created or modified by the program.|Depends on [configuration](#system-and-configuration-configuration-info).| 29 | |16|`redirect_stderr_to_stdout`|boolean||If `true` standard error will be redirected to standard output.|Depends on [configuration](#system-and-configuration-configuration-info).| 30 | |17|`enable_network`|boolean||If `true` program will have network access.|Depends on [configuration](#system-and-configuration-configuration-info).| 31 | |18|`number_of_runs`|integer||Run each program `number_of_runs` times and take average of `time` and `memory`.|Depends on [configuration](#system-and-configuration-configuration-info).| 32 | |19|**`additional_files`**|Base64 Encoded String||Additional files that should be available alongside the source code. Value of this string should represent the content of a `.zip` that contains additional files. This attribute is **required** for [multi-file programs](#header-single-file-programs-and-multi-file-programs).|`null`| 33 | |20|`callback_url`|string||URL on which Judge0 will issue `PUT` request with the submission in a request body after submission has been done.|`null`| 34 | |21|`stdout`|text||Standard output of the program after execution.|| 35 | |22|`stderr`|text||Standard error of the program after execution.|| 36 | |23|`compile_output`|text||Compiler output after compilation.|| 37 | |24|`message`|text||If submission status is `Internal Error` then this message comes from Judge0 itself, otherwise this is status message from [isolate](https://github.com/ioi/isolate).|| 38 | |25|`exit_code`|integer||The program's exit code.|| 39 | |26|`exit_signal`|integer||Signal code that the program recieved before exiting.|| 40 | |27|`status`|object||Submission [status](#statuses-and-languages-status).|| 41 | |28|`created_at`|datetime||Date and time when submission was created.|| 42 | |29|`finished_at`|datetime||Date and time when submission was processed.|`null` if submission is still in queue or if submission is processing.| 43 | |30|`token`|string||Unique submission token which can be used to [get a specific submission](#submissions-submission-get).|| 44 | |31|`time`|float|second|Program's run time.|| 45 | |32|`wall_time`|float|second|Program's wall time. Will be greater or equal to `time`.|| 46 | |33|`memory`|float|kilobyte|Memory used by the program after execution.|| 47 | 48 | ### Single-file programs and multi-file programs 49 | Judge0 can run both single-file and multi-file programs in a sandboxed environment with specified resource limitations. 50 | The usage of multi-file programs is slightly different from single-file programs and this section explains their differences and when they should be used. 51 | 52 | #### Single-file programs 53 | This is the simplest way to run a program with Judge0. Pick a [language](#statuses-and-languages-language-get) with `language_id`, provide a `source_code` and Judge0 will use predefined compilation and execution scripts for specified language. Additionally you can set custom compile flags, provide command line arguments and send `additional_files` that will be available in the sandbox alongside your single-file program. 54 | 55 | With `additional_files` you can send, for example, Python modules which are imported by your main program that you provided in `source_code` attribute. For C or C++ programs with `additional_files` you can send header files which are included by your main program that you provided in `source_code` attribute. 56 | 57 | Even though you can send and use multiple Python modules or C and C++ header files, we call this *single-file programs* because for compiled languages only **one** source file is compiled with predefined compilation scripts. 58 | 59 | #### Multi-file programs 60 | Multi-file programs are available since [v1.10.0](https://github.com/judge0/judge0/tree/v1.10.0) and they allow you specify your own compilation and execution scripts that Judge0 will use. 61 | 62 | To use multi-file program feature you need to choose a language called *Multi-file program* whoose ID is **89**. Moreover, you need to send all program files with `additional_files` attribute. With multi-file programs attribute `source_code` cannot be used, i.e. all files should be sent with `additional_files` attribute. 63 | 64 | As mentioned in the table above, `additional_files` attribute should be a content of a Base64 encoded `.zip` archive. This archive will be extracted in the sandbox before compilation and execution. 65 | 66 | For the Judge0 to know how to compile and execute your multi-file program you need to provide two special files that should be available in the root of the `.zip` archive that you are sending with `additional_files` attribute. These files should be named `compile` and `run`, and are expected to be Bash scripts that know how to compile and execute your multi-file program. If your multi-file program does not need compilation step, then you don't need to provide `compile` script. Take a look at [this example](https://github.com/judge0/examples/tree/master/cpp-and-cmake-01) to learn how to use this feature to compile and run multi-file C++ project that uses CMake. 67 | 68 | 69 | 70 | 71 | 72 | 73 | ## Submission Batch [/submissions/batch{?tokens,base64_encoded,fields}] 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/api/system_and_configuration/configuration_info.md: -------------------------------------------------------------------------------- 1 | ## Configuration Info [/config_info] 2 | ## Configuration Info [GET] 3 | Configuration information gives you detailed information about configuration of Judge0. 4 | This configuration can be changed through [judge0.conf](https://github.com/judge0/judge0/blob/master/judge0.conf) 5 | file by admin who hosts Judge0 instance. 6 | 7 | This configuration gives every admin a flexibility to configure Judge0 according to server abilities and needs. It also gives users 8 | insight on some *default configuration values* which are used when their programs are run. 9 | 10 | Each of these *configuration variables* have *default values* which we consider as recommended in case you are not sure should you change them. 11 | 12 | We will refer to *default values* as values which Judge0 automatically assigns to each of these *configuration variables*, 13 | if admin didn't set them. For example, default value of *configuration variable* `cpu_time_limit` is `2`. 14 | 15 | |# |Name|Type |Unit |Description|Default Value| 16 | |:---:|:---|:---:|:---:|:----------|:------------| 17 | |1|`enable_wait_result`|boolean||If enabled user can request to synchronously wait for submission result on submission create.|true| 18 | |2|`enable_compiler_options`|boolean||If enabled user can set `compiler_options`.|true| 19 | |3|`allowed_languages_for_compile_options`|list of strings||Languages for which setting compiler options is allowed.|Empty, i.e. for all languages it is allowed to set compiler options.| 20 | |4|`enable_command_line_arguments`|boolean||If enabled user can set `command_line_arguments`.|true| 21 | |5|`enable_submission_delete`|boolean||If enabled authorized user can [delete a submission](#submissions-submission-delete).|false| 22 | |6|`max_queue_size`|integer||Maximum number of submissions that can wait in queue.|100| 23 | |7|`cpu_time_limit`|float|second|Default runtime limit for every program (in seconds). Decimal numbers are allowed. Time in which the OS assigns the processor to different tasks is not counted.|2| 24 | |8|`cpu_extra_time`|float|second|When a time limit is exceeded, wait for extra time, before killing the program. This has the advantage that the real execution time is reported, even though it slightly exceeds the limit.|0.5| 25 | |9|`wall_time_limit`|float|second|Limit wall-clock time in seconds. Decimal numbers are allowed. This clock measures the time from the start of the program to its exit, for an external event. We recommend to use `cpu_time_limit` as the main limit, but set `wall_time_limit` to a much higher value as a precaution against sleeping programs.|5| 26 | |10|`memory_limit`|integer|kilobyte|Limit address space of the program in kilobytes.|128000| 27 | |11|`stack_limit`|integer|kilobyte|Limit process stack in kilobytes.|64000| 28 | |12|`max_processes_and_or_threads`|integer||Maximum number of processes and/or threads program can create.|60| 29 | |13|`enable_per_process_and_thread_time_limit`|boolean||If `true` then `cpu_time_limit` will be used as per process and thread.|false| 30 | |14|`enable_per_process_and_thread_memory_limit`|boolean||If `true` then `memory_limit` will be used as per process and thread.|true| 31 | |15|`max_file_size`|integer|kilobyte|Limit size of files created (or modified) by the program.|1024| 32 | |16|`allow_enable_network`|boolean||If enabled user can set `enable_network`.|true| 33 | |17|`enable_network`|boolean||If enabled program will have network access.|true| 34 | |18|`number_of_runs`|integer||Run each program this many times and take average of time and memory.|1| 35 | 36 | *Default configuration value* for each variable is given to you as response of this API call. For example, *default configuration value* 37 | for variable `cpu_extra_time` might be `2`, and if admin didn't set this, then it is `0.5` (*default value*). 38 | This means that admin set `cpu_extra_time` *configuration variable* to value `2` and we say it is now *default configuration value* for this 39 | variable `cpu_extra_time`. 40 | 41 | Every [submission](#submissions-submission) can change each of the configuration variables according to its needs. For example, 42 | user might create submission which has `cpu_time_limit` of `5` seconds. For security reasons we need to limit values of each of these 43 | configuration variables. For example, we don't want user to create a submission which has `cpu_time_limit` of `100000` seconds. 44 | 45 | For this security reason we are introducing *limit configuration variables* for each *configuration variable*. 46 | 47 | |# |Name|Type |Unit |Description|Default Value| 48 | |:---:|:---|:---:|:---:|:----------|:------------| 49 | |1|`max_cpu_time_limit`|float|second|Maximum custom `cpu_time_limit`|15| 50 | |2|`max_cpu_extra_time`|float|second|Maximum custom `cpu_extra_time`|2| 51 | |3|`max_wall_time_limit`|float|second|Maximum custom `wall_time_limit`|20| 52 | |4|`max_memory_limit`|integer|kilobyte|Maximum custom `memory_limit`|256000| 53 | |5|`max_stack_limit`|integer|kilobyte|Maximum custom `stack_limit`|128000| 54 | |6|`max_max_processes_and_or_threads`|integer||Maximum custom `max_processes_and_or_threads`|120| 55 | |7|`allow_enable_per_process_and_thread_time_limit`|boolean||If `false` user won't be able to set `enable_per_process_and_thread_time_limit` to `true`|true| 56 | |8|`allow_enable_per_process_and_thread_memory_limit`|boolean||If `false` user won't be able to set `enable_per_process_and_thread_memory_limit` to `true`|true| 57 | |9|`max_max_file_size`|integer|kilobyte|Maximux custom `max_file_size`|4096| 58 | |10|`max_number_of_runs`|integer||Maximum custom `number_of_runs`|20| 59 | 60 | For example, `max_cpu_time_limit` with value `20` means that user cannot create new submission which has `cpu_time_limit` greater than `20`. 61 | 62 | + Response 200 (application/json) 63 | { 64 | "enable_wait_result": true, 65 | "enable_compiler_options": true, 66 | "allowed_languages_for_compile_options": [], 67 | "enable_command_line_arguments": true, 68 | "enable_submission_delete": false, 69 | "max_queue_size": 100, 70 | "cpu_time_limit": 2, 71 | "max_cpu_time_limit": 15, 72 | "cpu_extra_time": 0.5, 73 | "max_cpu_extra_time": 2, 74 | "wall_time_limit": 5, 75 | "max_wall_time_limit": 20, 76 | "memory_limit": 128000, 77 | "max_memory_limit": 256000, 78 | "stack_limit": 64000, 79 | "max_stack_limit": 128000, 80 | "max_processes_and_or_threads": 60, 81 | "max_max_processes_and_or_threads": 120, 82 | "enable_per_process_and_thread_time_limit": false, 83 | "allow_enable_per_process_and_thread_time_limit": true, 84 | "enable_per_process_and_thread_memory_limit": true, 85 | "allow_enable_per_process_and_thread_memory_limit": true, 86 | "max_file_size": 1024, 87 | "max_max_file_size": 4096, 88 | "number_of_runs": 1, 89 | "max_number_of_runs": 20 90 | } -------------------------------------------------------------------------------- /docs/api/system_and_configuration/system_and_configuration.md: -------------------------------------------------------------------------------- 1 | # Group System and Configuration 2 | 3 | -------------------------------------------------------------------------------- /docs/api/system_and_configuration/system_info.md: -------------------------------------------------------------------------------- 1 | ## System Info [/system_info] 2 | ### System Info [GET] 3 | System information gives you detailed information about system on which Judge0 is running. 4 | 5 | This information is result of two commands on a host system: 6 | - `lscpu` 7 | - `free -h` 8 | 9 | Please note that Judge0 consists of two systems: **web** and **worker**. **Web** system is the one who 10 | provides you the web API, and **Worker** is the one who processes your submissions. They can be placed on two or more 11 | different hosts with different system configurations. Result of this API request is always from web system. 12 | This means that this request might be irrelevant to you if you as user don't know if web and worker are 13 | hosted on the same machine. To find that out, please contact admins who host Judge0 you are using. 14 | + Response 200 (application/json) 15 | { 16 | "Architecture": "x86_64", 17 | "CPU op-mode(s)": "32-bit, 64-bit", 18 | "Byte Order": "Little Endian", 19 | "CPU(s)": "4", 20 | "On-line CPU(s) list": "0-3", 21 | "Thread(s) per core": "2", 22 | "Core(s) per socket": "2", 23 | "Socket(s)": "1", 24 | "NUMA node(s)": "1", 25 | "Vendor ID": "GenuineIntel", 26 | "CPU family": "6", 27 | "Model": "61", 28 | "Model name": "Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz", 29 | "Stepping": "4", 30 | "CPU MHz": "2508.703", 31 | "CPU max MHz": "2700.0000", 32 | "CPU min MHz": "500.0000", 33 | "BogoMIPS": "4392.12", 34 | "Virtualization": "VT-x", 35 | "L1d cache": "32K", 36 | "L1i cache": "32K", 37 | "L2 cache": "256K", 38 | "L3 cache": "3072K", 39 | "NUMA node0 CPU(s)": "0-3", 40 | "Mem": "7.7G", 41 | "Swap": "8.0G" 42 | } -------------------------------------------------------------------------------- /docs/maintainers/README.md: -------------------------------------------------------------------------------- 1 | # Documentation for Maintainers 2 | Here you can find documentation for Judge0 maintainers. -------------------------------------------------------------------------------- /docs/maintainers/RELEASE_NOTES_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # vX.Y.Z (YYYY-MM-DD) 2 | ## API Changes 3 | 4 | ## New Features 5 | 6 | ## Improvements 7 | 8 | ## Security Improvements 9 | 10 | ## Bug Fixes 11 | 12 | ## Security Fixes 13 | 14 | ## Other Changes 15 | 16 | ## Deployment Procedure 17 | Judge0 is collecting telemetry data to help understand how to improve the product and to better understand how Judge0 is used in various production environments. Read more about telemetry [here](https://github.com/judge0/judge0/blob/vX.Y.Z/TELEMETRY.md). 18 | 19 | Please note that Judge0 has only been tested on **Linux** and **macOS**, and might not work on Windows, thus we do not provide support for it. 20 | 21 | ### With HTTP 22 | 1. Install [Docker](https://docs.docker.com) and [Docker Compose](https://docs.docker.com/compose). 23 | 2. Download and extract the release archive: 24 | ``` 25 | wget https://github.com/judge0/judge0/releases/download/vX.Y.Z/judge0-vX.Y.Z.zip 26 | unzip judge0-vX.Y.Z.zip 27 | ``` 28 | 29 | 3. Run all services and wait a few seconds until everything is initialized: 30 | ``` 31 | cd judge0-vX.Y.Z 32 | docker-compose up -d db redis 33 | sleep 10s 34 | docker-compose up -d 35 | sleep 5s 36 | ``` 37 | 38 | 4. Your instance of Judge0 vX.Y.Z is now available at `http://:2358`. 39 | 40 | ### With HTTPS (SSL/TLS) 41 | 1. Install [Docker](https://docs.docker.com) and [Docker Compose](https://docs.docker.com/compose). 42 | 2. Download and extract the release archive: 43 | ``` 44 | wget https://github.com/judge0/judge0/releases/download/vX.Y.Z/judge0-vX.Y.Z-https.zip 45 | unzip judge0-vX.Y.Z-https.zip 46 | ``` 47 | 48 | 3. Change directory to `judge0-vX.Y.Z-https`: 49 | ``` 50 | cd judge0-vX.Y.Z-https 51 | ``` 52 | 4. Edit `docker-compose.yml` and change variables `VIRTUAL_HOST`, `LETSENCRYPT_HOST` and `LETSENCRYPT_EMAIL`. 53 | 5. Run all services and wait a few seconds until everything is initialized: 54 | ``` 55 | docker-compose up -d db redis 56 | sleep 10s 57 | docker-compose up -d 58 | sleep 5s 59 | ``` 60 | 61 | 6. Your instance of Judge0 vX.Y.Z is now available at `https://`. 62 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/auto_annotate_models.rake: -------------------------------------------------------------------------------- 1 | if Rails.env.development? 2 | task :set_annotation_options do 3 | # You can override any of these by setting an environment variable of the 4 | # same name. 5 | Annotate.set_defaults( 6 | 'routes' => 'false', 7 | 'position_in_routes' => 'before', 8 | 'position_in_class' => 'before', 9 | 'position_in_test' => 'before', 10 | 'position_in_fixture' => 'before', 11 | 'position_in_factory' => 'before', 12 | 'position_in_serializer' => 'before', 13 | 'show_foreign_keys' => 'true', 14 | 'show_indexes' => 'true', 15 | 'simple_indexes' => 'false', 16 | 'model_dir' => 'app/models', 17 | 'root_dir' => '', 18 | 'include_version' => 'false', 19 | 'require' => '', 20 | 'exclude_tests' => 'true', 21 | 'exclude_fixtures' => 'true', 22 | 'exclude_factories' => 'true', 23 | 'exclude_serializers' => 'true', 24 | 'exclude_scaffolds' => 'true', 25 | 'exclude_controllers' => 'true', 26 | 'exclude_helpers' => 'true', 27 | 'ignore_model_sub_dir' => 'false', 28 | 'ignore_columns' => nil, 29 | 'ignore_routes' => nil, 30 | 'ignore_unknown_models' => 'false', 31 | 'hide_limit_column_types' => 'integer,boolean', 32 | 'skip_on_db_migrate' => 'false', 33 | 'format_bare' => 'true', 34 | 'format_rdoc' => 'false', 35 | 'format_markdown' => 'false', 36 | 'sort' => 'false', 37 | 'force' => 'false', 38 | 'trace' => 'false', 39 | 'wrapper_open' => nil, 40 | 'wrapper_close' => nil 41 | ) 42 | end 43 | 44 | Annotate.load_tasks 45 | end 46 | -------------------------------------------------------------------------------- /lib/tasks/clear_cache.rake: -------------------------------------------------------------------------------- 1 | desc "Clear cache." 2 | 3 | namespace :judge0 do 4 | task :clear_cache => :environment do 5 | Rails.cache.clear 6 | end 7 | end -------------------------------------------------------------------------------- /lib/tasks/run_submissions_in_queue.rake: -------------------------------------------------------------------------------- 1 | desc "Run all submission with status 'In Queue'." 2 | 3 | namespace :judge0 do 4 | task :run_in_queue => :environment do 5 | ARGV.each { |a| task a.to_sym do ; end } 6 | Submission.where(status_id: Status.queue).each do |s| 7 | if ARGV[1].to_s == "now" 8 | IsolateRunner.perform_now(s) 9 | else 10 | IsolateRunner.perform_later(s) 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/log/.keep -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/public/robots.txt -------------------------------------------------------------------------------- /scripts/dev/bundle: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for creating release bundle. 3 | # 4 | # Usage: ./scripts/dev/bundle 5 | # 6 | set -e 7 | 8 | commit_tag="$(git tag --points-at HEAD)" 9 | if [[ $commit_tag == "" ]]; then 10 | echo "No tag for current commit." 11 | exit -1 12 | fi 13 | 14 | docker_tag=${commit_tag:1} # Drop the "v" at the beginning. 15 | 16 | release_dir=release-$commit_tag 17 | mkdir -p $release_dir 18 | 19 | for ext in "" ".https" ".workers" ".server"; do 20 | instance_dir=judge0-$commit_tag 21 | if [[ $ext != "" ]]; then 22 | instance_dir=$instance_dir-${ext:1} 23 | fi 24 | pushd $release_dir 25 | mkdir -p $instance_dir 26 | cp ../docker-compose$ext.yml $instance_dir/docker-compose.yml 27 | cp ../judge0.conf $instance_dir/ 28 | sed -i.bak "s/judge0:latest/judge0:$docker_tag/g" $instance_dir/docker-compose.yml 29 | rm $instance_dir/docker-compose.yml.bak 30 | zip -r $instance_dir.zip $instance_dir 31 | popd 32 | done -------------------------------------------------------------------------------- /scripts/dev/clean: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for removing Judge0 development 3 | # environment (containers and volumes). 4 | # 5 | # Usage: ./scripts/dev/clean 6 | # 7 | docker-compose -f docker-compose.dev.yml down -v 8 | -------------------------------------------------------------------------------- /scripts/dev/generate-docs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for generating Judge0 documentation. 3 | # 4 | # Usage: ./scripts/dev/generate-docs 5 | # 6 | aglio --theme-full-width -i docs/api/docs.md -o public/docs.html 7 | -------------------------------------------------------------------------------- /scripts/dev/serve-docs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for serving Judge0 documentation. 3 | # Used in "development" mode when documentation is written. 4 | # 5 | # Usage: ./scripts/dev/serve-docs 6 | # 7 | aglio --theme-full-width -i docs/api/docs.md -s -h 0.0.0.0 -p 3001 8 | -------------------------------------------------------------------------------- /scripts/dev/shell: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for creating a new or using existing 3 | # Judge0 development environment and 4 | # opening new shell inside Judge0 container. 5 | # 6 | # Usage: ./scripts/dev/shell 7 | # 8 | docker-compose -f docker-compose.dev.yml up -d 9 | docker-compose -f docker-compose.dev.yml exec --privileged judge0 bash 10 | -------------------------------------------------------------------------------- /scripts/load-config: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [[ -f /api/judge0.conf ]]; then 3 | CONFIG_FILE=/api/judge0.conf 4 | elif [[ -f /judge0.conf ]]; then 5 | CONFIG_FILE=/judge0.conf 6 | fi 7 | 8 | if [[ -v CONFIG_FILE ]]; then 9 | set -o allexport 10 | 11 | source $CONFIG_FILE # Source the configuration file. 12 | 13 | set +o allexport 14 | fi 15 | 16 | # Now set defaults if needed... 17 | 18 | # Judge0 19 | export MAINTENANCE_MESSAGE=${MAINTENANCE_MESSAGE:-Judge0 is currently in maintenance.} 20 | export RESTART_MAX_TRIES=${RESTART_MAX_TRIES:-10} 21 | 22 | # Rails 23 | export RAILS_ENV=${RAILS_ENV:-production} 24 | export RAILS_MAX_THREADS=${RAILS_MAX_THREADS:-$(nproc)} 25 | export RAILS_SERVER_PROCESSES=${RAILS_SERVER_PROCESSES:-2} 26 | export SECRET_KEY_BASE=${SECRET_KEY_BASE:-$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 128 | head -n 1)} 27 | export PORT=${PORT:-2358} # This option is not available in judge0.conf 28 | export RAILS_LOG_TO_STDOUT=true # This options is not available in judge0.conf 29 | 30 | # Authentication 31 | export AUTHN_HEADER=${AUTHN_HEADER:-X-Auth-Token} 32 | 33 | # Authorization 34 | export AUTHZ_HEADER=${AUTHZ_HEADER:-X-Auth-User} 35 | 36 | # Workers 37 | export INTERVAL=${INTERVAL:-0.1} 38 | export COUNT=${COUNT:-$(( $(nproc) * 2 ))} 39 | export QUEUE=${JUDGE0_VERSION:-unknown} # This option is not available in judge0.conf 40 | 41 | # Database 42 | export REDIS_HOST=${REDIS_HOST:-localhost} 43 | export REDIS_PORT=${REDIS_PORT:-6379} 44 | export POSTGRES_HOST=${POSTGRES_HOST:-localhost} 45 | export POSTGRES_PORT=${POSTGRES_PORT:-5432} 46 | export POSTGRES_DB=${POSTGRES_DB:-postgres} 47 | export POSTGRES_USER=${POSTGRES_USER:-postgres} 48 | 49 | # Other 50 | export RUBYOPT=-W:no-deprecated 51 | export DISABLE_DATABASE_ENVIRONMENT_CHECK=1 52 | 53 | 54 | export > /api/tmp/environment 55 | -------------------------------------------------------------------------------- /scripts/server: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for running Judge0 server. 3 | # 4 | # Usage: ./scripts/server 5 | # 6 | for i in $(seq 1 $RESTART_MAX_TRIES); do 7 | source ./scripts/load-config 8 | 9 | [[ -f tmp/pids/server.pid ]] && rm -f tmp/pids/server.pid 10 | 11 | rails db:create db:migrate db:seed 12 | rails s -b 0.0.0.0 13 | [[ $? -eq 0 ]] && break 14 | sleep 2s 15 | done 16 | -------------------------------------------------------------------------------- /scripts/workers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script for running Judge0 workers. 3 | # 4 | # Usage: ./scripts/workers 5 | # 6 | source ./scripts/load-config 7 | 8 | run_resque=1 9 | resque_pid=0 10 | scheduler_pid=0 11 | 12 | date_now() { 13 | echo -n $(date +"%Y-%m-%d-%H-%M-%S") 14 | } 15 | 16 | exit_gracefully() { 17 | echo "[$(date_now)] Killing workers." 18 | run_resque=0 19 | kill -SIGQUIT $(pgrep -P $resque_pid) 20 | kill -SIGTERM $resque_pid 21 | } 22 | 23 | trap exit_gracefully SIGTERM SIGINT 24 | 25 | mkdir -p tmp/pids &> /dev/null 26 | while [[ $run_resque -eq 1 ]]; do 27 | echo "[$(date_now)] Starting scheduler." 28 | if ! ps -p $scheduler_pid &> /dev/null; then 29 | rake resque:scheduler & 30 | scheduler_pid=$! 31 | fi 32 | 33 | rm -rf tmp/pids/resque.pid &> /dev/null 34 | echo "[$(date_now)] Starting workers." 35 | rails resque:workers & 36 | resque_pid=$! 37 | while ps -p $resque_pid > /dev/null; do sleep 1s; done 38 | echo "[$(date_now)] Workers are stopped." 39 | done 40 | -------------------------------------------------------------------------------- /spec/controllers/languages_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe LanguagesController, type: :controller do 4 | describe "GET #index" do 5 | it "returns all languages" do 6 | create_list(:language, 10) 7 | get :index 8 | json = JSON.parse(response.body) 9 | expect(response).to be_success 10 | expect(json).to have_serialized(Language.all).with(LanguageSerializer) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/controllers/statuses_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe StatusesController, type: :controller do 4 | describe "GET #index" do 5 | it "returns all statuses" do 6 | get :index 7 | json = JSON.parse(response.body) 8 | expect(response).to be_success 9 | expect(json).to have_serialized(Status.all).with(StatusSerializer) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/controllers/submissions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe SubmissionsController, type: :controller do 4 | 5 | let(:submission) { create(:submission) } 6 | 7 | describe "GET #show" do 8 | it "returns one submission" do 9 | get :show, params: { token: submission.token } 10 | json = JSON.parse(response.body) 11 | expect(response).to be_success 12 | expect(json).to have_serialized(submission).with(SubmissionSerializer) 13 | end 14 | 15 | it "returns 404" do 16 | expect { 17 | get :show, params: { token: submission.token + " give me 404" } 18 | }.to raise_error(ActiveRecord::RecordNotFound) 19 | end 20 | end 21 | 22 | describe "POST #create" do 23 | context "with valid params" do 24 | it "creates a new Submission" do 25 | expect { 26 | post :create, params: attributes_for(:valid_submission) 27 | }.to change(Submission, :count).by(1) 28 | end 29 | 30 | it "returns only id of new Submission" do 31 | post :create, params: attributes_for(:valid_submission) 32 | json = JSON.parse(response.body) 33 | expect(response).to be_success 34 | expect(json).to have_serialized(Submission.first).with(SubmissionSerializer, { fields: [:token] }) 35 | end 36 | 37 | it "doesn't create new Submission because given Language doesn't exist" do 38 | attributes = attributes_for(:valid_submission) 39 | attributes[:language_id] = 142 # Language with id 142 doesn't exist 40 | post :create, params: attributes 41 | expect(response).to have_http_status(422) 42 | end 43 | end 44 | 45 | context "with invalid params" do 46 | it "doesn't create new Submission" do 47 | post :create, params: { submission: attributes_for(:invalid_submission) } 48 | expect(response).to have_http_status(422) 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/factories/languages.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :language do 3 | sequence(:name) { |n| "C (gcc #{n})" } 4 | run_cmd './a.out' 5 | source_file 'main.c' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/submissions.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :valid_submission, class: Submission do 3 | sequence(:token) { |n| SecureRandom.uuid + "-#{n}" } 4 | source_code 'name = gets.strip; puts "hello, " + name' 5 | language_id { create(:language).id } 6 | number_of_runs 1 7 | stdin "world" 8 | expected_output "hello, world" 9 | end 10 | 11 | factory :submission, parent: :valid_submission do 12 | stdout "hello, world" 13 | status_id 1 14 | time 1.0 15 | memory 256 16 | end 17 | 18 | factory :invalid_submission, class: Submission do 19 | source_code 'name = gets.strip; puts "hello, " + name' 20 | # language_id 14 # :language_id should be present 21 | stdin "world" 22 | expected_output "hello, world" 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/jobs/isolate_job_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe IsolateJob, type: :job do 4 | end 5 | -------------------------------------------------------------------------------- /spec/models/language_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Language, type: :model do 4 | it { should validate_presence_of(:name) } 5 | it { should validate_presence_of(:run_cmd) } 6 | it { should validate_presence_of(:source_file) } 7 | end 8 | -------------------------------------------------------------------------------- /spec/models/submission_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Submission, type: :model do 4 | it { should validate_presence_of(:source_code) } 5 | it { should validate_presence_of(:language_id) } 6 | 7 | describe "#language" do 8 | let(:language) { create(:language) } 9 | 10 | it "returns language" do 11 | submission = create(:submission, { language_id: language.id }) 12 | expect(submission.language).to eq(language) 13 | end 14 | end 15 | 16 | it "is invalid because Language with given id doesn't exist" do 17 | submission = build(:submission, { language_id: Language.all.size + 1 }) 18 | expect(submission).not_to be_valid 19 | end 20 | 21 | it "is valid because Language with given id exists" do 22 | language = create(:language) 23 | submission = build(:submission, { language_id: language.id }) 24 | expect(submission).to be_valid 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] = 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | abort("The Rails environment is running in production mode!") if Rails.env.production? 4 | require 'spec_helper' 5 | require 'rspec/rails' 6 | require 'pry-byebug' 7 | 8 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 9 | 10 | ActiveRecord::Migration.maintain_test_schema! 11 | 12 | RSpec.configure do |config| 13 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 14 | config.infer_spec_type_from_file_location! 15 | config.filter_rails_from_backtrace! 16 | end 17 | -------------------------------------------------------------------------------- /spec/requests/languages_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "Languages", type: :request do 4 | describe "GET /languages" do 5 | it "has a 200 status code" do 6 | get languages_path 7 | expect(response).to have_http_status(200) 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/requests/submissions_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "Submissions", type: :request do 4 | end 5 | -------------------------------------------------------------------------------- /spec/routing/languages_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "rails_helper" 2 | 3 | RSpec.describe LanguagesController, type: :routing do 4 | describe "routing" do 5 | it "routes to #index" do 6 | expect(get: "/languages").to route_to("languages#index") 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/routing/submissions_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "rails_helper" 2 | 3 | RSpec.describe SubmissionsController, type: :routing do 4 | describe "routing" do 5 | it "routes to #show" do 6 | token = SecureRandom.uuid 7 | expect(:get => "/submissions/#{token}").to route_to("submissions#show", token: token) 8 | end 9 | 10 | it "routes to #create" do 11 | expect(:post => "/submissions").to route_to("submissions#create") 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'codeclimate-test-reporter' 2 | 3 | CodeClimate::TestReporter.start 4 | CodeClimate::TestReporter.configuration.git_dir = ".." 5 | 6 | RSpec.configure do |config| 7 | config.expect_with :rspec do |expectations| 8 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 9 | end 10 | 11 | config.mock_with :rspec do |mocks| 12 | mocks.verify_partial_doubles = true 13 | end 14 | 15 | config.shared_context_metadata_behavior = :apply_to_host_groups 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/active_model_serializer_matcher.rb: -------------------------------------------------------------------------------- 1 | RSpec::Matchers.define :have_serialized do |unserialized| 2 | chain :with do |serializer, options = {}| 3 | @serializer = serializer 4 | @options = options 5 | end 6 | 7 | chain :wrap do |collection_serializer, options = {}| 8 | @collection_serializer = collection_serializer 9 | end 10 | 11 | def serialize(object) 12 | @collection_serializer ||= ActiveModel::Serializer::CollectionSerializer 13 | 14 | if object.respond_to?(:map) 15 | serializer = @collection_serializer.new(object, serializer: @serializer) 16 | else 17 | serializer = @serializer.new(object) 18 | end 19 | 20 | json = ActiveModelSerializers::Adapter::Attributes.new(serializer, @options).to_json 21 | JSON.parse(json) 22 | end 23 | 24 | match do |serialized| 25 | serialized == serialize(unserialized) 26 | end 27 | 28 | failure_message do |serialized| 29 | <<-FAIL.strip_heredoc 30 | expected: 31 | #{serialized} 32 | to match: 33 | #{serialize(unserialized)} 34 | --- 35 | #{inspect} 36 | FAIL 37 | end 38 | 39 | failure_message_when_negated do |serialized| 40 | <<-FAIL.strip_heredoc 41 | expected 42 | #{serialized} 43 | not to match: 44 | #{serialize(unserialized)} 45 | --- 46 | #{inspect} 47 | FAIL 48 | end 49 | 50 | def inspect 51 | <<-INSPECT.strip_heredoc 52 | Using object serializer: #{@serializer} 53 | Using collection serializer: #{@collection_serializer} 54 | INSPECT 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/support/database_cleaner.rb: -------------------------------------------------------------------------------- 1 | require 'database_cleaner' 2 | 3 | RSpec.configure do |config| 4 | config.use_transactional_fixtures = false 5 | 6 | config.before(:suite) do 7 | DatabaseCleaner.clean_with(:truncation) 8 | end 9 | 10 | config.before(:each) do 11 | DatabaseCleaner.strategy = :transaction 12 | end 13 | 14 | config.before(:each) do 15 | DatabaseCleaner.start 16 | end 17 | 18 | config.after(:each) do 19 | DatabaseCleaner.clean 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/support/factory_girl.rb: -------------------------------------------------------------------------------- 1 | require 'factory_girl_rails' 2 | 3 | RSpec.configure do |config| 4 | config.include FactoryGirl::Syntax::Methods 5 | end 6 | -------------------------------------------------------------------------------- /spec/support/shoulda_matchers.rb: -------------------------------------------------------------------------------- 1 | require 'shoulda-matchers' 2 | 3 | Shoulda::Matchers.configure do |config| 4 | config.integrate do |with| 5 | with.test_framework :rspec 6 | with.library :rails 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/tmp/.keep -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neetcode-gh/judge0/bc910003db3c80a1eae3277bfb8a54b89d5817f9/vendor/.keep --------------------------------------------------------------------------------