Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
services:
web:
build: docker/web
ports:
- "80:80"
volumes:
- ./www:/var/www/html
- ./docker/config/roslogin-connect.php:/var/www/html/www.reactos.org_config/roslogin-connect.php
- ./docker/config/testman-connect.php:/var/www/html/www.reactos.org_config/testman-connect.php
- ./docker/config/gitinfo-connect.php:/var/www/html/www.reactos.org_config/gitinfo-connect.php
- ./docker/parts:/srv/www/www.reactos.org_content/parts:ro
depends_on:
db:
condition: service_healthy
ldap:
condition: service_started

db:
image: mysql:8.0
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
volumes:
- ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10

ldap:
build:
context: .
dockerfile: docker/ldap/Dockerfile
ports:
- "389:389"

volumes:
db_data:
60 changes: 60 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Docker Development Environment

Runs the ReactOS web services locally using three containers:

| Container | Description |
|-----------|-------------|
| `web` | Apache + PHP 8.2 serving all four services |
| `db` | MySQL 8.0 with roslogin, testman, and gitinfo databases |
| `ldap` | In-memory LDAP stub (replaces real LDAP for local testing) |

## Starting

```bash
docker compose up --build
```

The `--build` flag is only needed the first time or after changing files in `docker/web/` or `docker/ldap/`. On subsequent runs, `docker compose up` is sufficient.

## Services

Once running, the following URLs are available:

| URL | Service |
|-----|---------|
| http://localhost/roslogin/ | Authentication / user management |
| http://localhost/testman/ | Build and test results |
| http://localhost/getbuilds/ | Pre-built revision downloads |
| http://localhost/rosweb/ | Shared interface component |

## Test Credentials

The LDAP stub is pre-populated with these test accounts:

| Username | Password | Groups |
|----------|----------|--------|
| test | test12 | — |
| test2 | test12 | — |
| test3 | test12 | — |
| testmod | test12 | Moderators |
| testadmin | test12 | Moderators, Administrators |

## Database Access

Connect directly to the database for debugging:

```bash
docker compose exec db mysql -u roslogin roslogin
docker compose exec db mysql -u testman testman
```

## Configuration

The files in `docker/config/` are Docker-specific overrides for the connection settings in `www/www.reactos.org_config/`. They redirect database connections to the `db` container and LDAP to the `ldap` container. The original config files are not modified.

## Stopping

```bash
docker compose down # stop containers, keep database volume
docker compose down -v # stop containers and delete database volume
```
6 changes: 6 additions & 0 deletions docker/config/gitinfo-connect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
// DB Settings
define("GITINFO_DB_HOST", "db");
define("GITINFO_DB_USER", "gitinfo_reader");
define("GITINFO_DB_PASS", "");
define("GITINFO_DB_NAME", "gitinfo");
35 changes: 35 additions & 0 deletions docker/config/roslogin-connect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
// DB Settings
define("ROSLOGIN_DB_HOST", "db");
define("ROSLOGIN_DB_USER", "roslogin");
define("ROSLOGIN_DB_PASS", "");
define("ROSLOGIN_DB_NAME", "roslogin");

// LDAP Settings
define("ROSLOGIN_LDAP_HOST", "ldap");
define("ROSLOGIN_LDAP_BIND_DN", "uid=roslogin,ou=Service Accounts,o=ReactOS Website");
define("ROSLOGIN_LDAP_BIND_PW", "test");
define("ROSLOGIN_LDAP_BASE_DN", "ou=People,o=ReactOS Website");

// Single Sign-On Settings
define("ROSLOGIN_COOKIE_DOMAIN", "localhost");
define("ROSLOGIN_COOKIE_VALIDITY", 60 * 60 * 24 * 365); // 1 Year
define("ROSLOGIN_SESSION_VALIDITY", "1 YEAR");

// Self-Service Settings
define("ROSLOGIN_MAIL_FROM", "ReactOS Website <noreply@reactos.org>");
define("ROSLOGIN_MAIL_LINK", "http://localhost/roslogin/?p=confirm&");
define("ROSLOGIN_MAIL_VALIDITY", "1 DAY");

// Captcha Settings
define("ROSLOGIN_RECAPTCHA_SITEKEY", "YOUR_GOOGLE_RECAPTCHA_SITEKEY_HERE");
define("ROSLOGIN_RECAPTCHA_SECRET", "YOUR_GOOGLE_RECAPTCHA_SECRET_HERE");

// Miscellaneous Website Settings
define("ROSLOGIN_TITLE_SUFFIX", " | ReactOS Project");

// Admin panel settings
define("ROSLOGIN_ADMIN_GROUP", "LDAP Administrators");
define("ROSLOGIN_MODERATOR_GROUP", "Moderators");
define("ROSLOGIN_MATTERMOST_URL", "https://chat.reactos.org");
define("ROSLOGIN_MATTERMOST_TOKEN", "YOUR_MATTERMOST_TOKEN_HERE");
6 changes: 6 additions & 0 deletions docker/config/testman-connect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
// DB Settings
define("TESTMAN_DB_HOST", "db");
define("TESTMAN_DB_USER", "testman");
define("TESTMAN_DB_PASS", "");
define("TESTMAN_DB_NAME", "testman");
10 changes: 10 additions & 0 deletions docker/ldap/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.11-slim

RUN pip install --no-cache-dir ldaptor twisted

WORKDIR /app
COPY resources/ldaptest/testserver.py .

EXPOSE 389

CMD ["python", "testserver.py", "389"]
136 changes: 136 additions & 0 deletions docker/mysql/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
-- ReactOS Web Services - Docker database initialization

-- -------------------------------------------------------
-- Databases
-- -------------------------------------------------------
CREATE DATABASE IF NOT EXISTS `roslogin` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE IF NOT EXISTS `testman` CHARACTER SET latin1 COLLATE latin1_general_ci;
CREATE DATABASE IF NOT EXISTS `gitinfo` CHARACTER SET utf8 COLLATE utf8_general_ci;

-- -------------------------------------------------------
-- Users
-- -------------------------------------------------------
CREATE USER IF NOT EXISTS 'roslogin'@'%' IDENTIFIED WITH mysql_native_password BY '';
CREATE USER IF NOT EXISTS 'testman'@'%' IDENTIFIED WITH mysql_native_password BY '';
CREATE USER IF NOT EXISTS 'gitinfo_reader'@'%' IDENTIFIED WITH mysql_native_password BY '';

GRANT SELECT, INSERT, UPDATE, DELETE ON `roslogin`.* TO 'roslogin'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON `testman`.* TO 'testman'@'%';
GRANT SELECT ON `gitinfo`.* TO 'gitinfo_reader'@'%';

FLUSH PRIVILEGES;

-- -------------------------------------------------------
-- roslogin schema
-- -------------------------------------------------------
USE `roslogin`;

CREATE TABLE `forbidden_maildomains` (
`domain` varchar(254) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `forbidden_usernames` (
`username` varchar(60) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `pending` (
`username` varchar(60) NOT NULL,
`email` varchar(254) NOT NULL,
`verification_key` char(32) NOT NULL,
`timeout` datetime NOT NULL,
`type` enum('mailchange','registration','resetpassword') NOT NULL,
KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `sessions` (
`id` char(32) CHARACTER SET utf8 NOT NULL,
`username` varchar(60) CHARACTER SET utf8 NOT NULL,
`timeout` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

-- -------------------------------------------------------
-- testman schema
-- -------------------------------------------------------
USE `testman`;

CREATE TABLE `sources` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(100) collate latin1_general_ci NOT NULL,
`password` char(32) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

CREATE TABLE `winetest_logs` (
`id` int(10) unsigned NOT NULL auto_increment,
`log` mediumblob NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

CREATE TABLE `winetest_results` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`test_id` int(10) unsigned NOT NULL,
`suite_id` int(10) unsigned NOT NULL,
`status` enum('ok','crash','canceled') COLLATE latin1_general_ci NOT NULL,
`count` int(10) NOT NULL DEFAULT '0',
`failures` int(10) unsigned NOT NULL DEFAULT '0',
`skipped` int(10) unsigned NOT NULL DEFAULT '0',
`todo` int(10) unsigned NOT NULL DEFAULT '0',
`time` float unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `test_and_suite` (`test_id`,`suite_id`),
KEY `suite_id` (`suite_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

CREATE TABLE `winetest_runs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`finished` tinyint(1) NOT NULL DEFAULT '0',
`source_id` int(10) unsigned NOT NULL,
`revision` varchar(40) NOT NULL,
`platform` varchar(24) COLLATE latin1_general_ci NOT NULL,
`comment` varchar(255) COLLATE latin1_general_ci DEFAULT NULL,
`count` int(10) unsigned NOT NULL DEFAULT '0',
`failures` int(10) unsigned NOT NULL DEFAULT '0',
`boot_cycles` bigint(20) unsigned NOT NULL DEFAULT '0',
`context_switches` int(10) unsigned NOT NULL DEFAULT '0',
`interrupts` int(10) unsigned NOT NULL DEFAULT '0',
`reboots` int(10) unsigned NOT NULL DEFAULT '0',
`system_calls` int(10) unsigned NOT NULL DEFAULT '0',
`time` float unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `revision` (`revision`),
KEY `platform` (`platform`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

CREATE TABLE `winetest_suites` (
`id` int(10) unsigned NOT NULL auto_increment,
`module` varchar(50) collate latin1_general_ci NOT NULL,
`test` varchar(50) collate latin1_general_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

-- -------------------------------------------------------
-- gitinfo schema
-- -------------------------------------------------------
USE `gitinfo`;

CREATE TABLE `master_revisions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`rev_hash` char(40) NOT NULL,
`author_name` varchar(100) NOT NULL,
`author_email` varchar(100) NOT NULL,
`commit_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`message` blob NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `rev_hash` (`rev_hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

CREATE TABLE `master_revisions_todo` (
`oldrev` char(40) NOT NULL,
`newrev` char(40) NOT NULL,
UNIQUE KEY `oldrev` (`oldrev`),
UNIQUE KEY `newrev` (`newrev`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
3 changes: 3 additions & 0 deletions docker/parts/footer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<footer class="container" style="margin-top:2rem;padding-top:1rem;border-top:1px solid #eee;color:#999;">
<p>ReactOS development environment</p>
</footer>
4 changes: 4 additions & 0 deletions docker/parts/head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
12 changes: 12 additions & 0 deletions docker/parts/header.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<span class="navbar-brand">ReactOS [dev]</span>
</div>
<ul class="nav navbar-nav">
<li><a href="/testman/">TestMan</a></li>
<li><a href="/roslogin/">RosLogin</a></li>
<li><a href="/getbuilds/">GetBuilds</a></li>
</ul>
</div>
</nav>
12 changes: 12 additions & 0 deletions docker/web/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM php:8.2-apache

RUN apt-get update && apt-get install -y \
libldap2-dev \
libonig-dev \
&& docker-php-ext-configure ldap \
&& docker-php-ext-install mysqli pdo_mysql ldap mbstring \
&& a2enmod rewrite \
&& rm -rf /var/lib/apt/lists/*

COPY apache.conf /etc/apache2/sites-available/000-default.conf
COPY php.ini /usr/local/etc/php/conf.d/docker-custom.ini
26 changes: 26 additions & 0 deletions docker/web/apache.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<VirtualHost *:80>
DocumentRoot /var/www/html/www.reactos.org
DirectoryIndex index.php

# Tell PHP it's running over HTTPS so roslogin doesn't redirect to https://
SetEnv HTTPS on

<Directory /var/www/html/www.reactos.org>
Options -Indexes
AllowOverride None
Require all granted
</Directory>

# Fallback for non-service paths: serve static content
AliasMatch "^/(?!getbuilds|roslogin|rosweb|testman)(.*)" /var/www/html/www.reactos.org_content/$1

<Directory /var/www/html/www.reactos.org_content>
Options -Indexes
AllowOverride None
Require all granted
php_admin_flag engine off
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
3 changes: 3 additions & 0 deletions docker/web/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
display_errors = Off
log_errors = On
error_reporting = E_ALL