greenlight: init at 3.8.2.4; nixos/greenlight: init (#550046)

This commit is contained in:
Jonas Heinrich
2026-09-22 09:13:37 +00:00
committed by GitHub
10 changed files with 4204 additions and 0 deletions

View File

@@ -98,6 +98,8 @@
- [ioquake3](https://ioquake3.org), a open-source port of the 3D action shooter Quake 3 Arena. Available as [programs.ioquake3](#opt-programs.ioquake3.enable).
- [Greenlight](https://github.com/bigbluebutton/greenlight), an end-user web interface for the virtual classroom software BigBlueButton. Available as [services.greenlight](#opt-services.greenlight.enable).
- [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service) is an OAuth2.0 and OpenID Connect provider for Matrix homeservers (such as Synapse). It replaces standard password authentication with modern OpenID Connect flows, and can delegate authentication to upstream OIDC providers. Available as [services.matrix-authentication-service](#opt-services.matrix-authentication-service.enable).
- [Krill](https://nlnetlabs.nl/projects/krill/about), RPKI CA and Publication Server written in Rust. Available as [services.krill](#opt-services.krill.enable).

View File

@@ -1730,6 +1730,7 @@
./services/web-apps/gotosocial.nix
./services/web-apps/goupile.nix
./services/web-apps/grav.nix
./services/web-apps/greenlight.nix
./services/web-apps/grocy.nix
./services/web-apps/guacamole-client.nix
./services/web-apps/guacamole-server.nix

View File

@@ -0,0 +1,567 @@
{
lib,
config,
pkgs,
options,
...
}:
let
cfg = config.services.greenlight;
opt = options.services.greenlight;
dataDir = "/var/lib/greenlight";
listeningAddress = "${cfg.settings.BINDING}:${lib.toString cfg.settings.PORT}";
configEnv = lib.concatMapAttrs (
name: value:
lib.optionalAttrs (value != null) {
${name} = if lib.isBool value then lib.boolToString value else toString value;
}
) cfg.settings;
defaultSecretKeyBaseFile = "${dataDir}/secrets/secret-key-base";
needsGenCredentialsUnit = cfg.secretKeyBaseFile == null;
credentials = {
SECRET_KEY_BASE = lib.defaultTo defaultSecretKeyBaseFile cfg.secretKeyBaseFile;
}
// lib.optionalAttrs (cfg.database.passwordFile != null) {
DATABASE_PASSWORD = cfg.database.passwordFile;
};
loadCredentialsIntoEnv = lib.concatMapAttrsStringSep "\n" (
name: _: ''export ${name}="$(systemd-creds cat ${name})"''
) credentials;
loadCredentials = lib.mapAttrsToList (name: path: "${name}:${path}") credentials;
isRedisUnixSocket = lib.hasPrefix "/" cfg.redis.host;
isDatabaseUnixSocket = lib.hasPrefix "/" cfg.database.host;
databaseUrl = "postgresql://${lib.strings.escapeURL cfg.database.user}:$DATABASE_PASSWORD@${lib.strings.escapeURL cfg.database.host}${
lib.optionalString (
!isDatabaseUnixSocket && cfg.database.port != null
) ":${toString cfg.database.port}"
}/${lib.strings.escapeURL cfg.database.name}";
redisEnv =
if isRedisUnixSocket then
{
REDIS_URL = "unix://${cfg.redis.host}";
}
else
{
# Does not support passwords, but upstream does not provide an adequate env variable
# Perhaps patch or make a PR upstream in the future
REDIS_URL = "redis://${cfg.redis.host}:${toString cfg.redis.port}";
};
greenlight-rake = pkgs.writeShellApplication {
name = "greenlight-rake";
text =
let
command = pkgs.writeShellScript "greenlight-rake-unwrapped" ''
${loadCredentialsIntoEnv}
export DATABASE_PASSWORD="''${DATABASE_PASSWORD:-}"
export DATABASE_URL="${databaseUrl}"
exec ${lib.getExe' cfg.package.rubyEnv "rake"} "$@"
'';
env' = lib.filterAttrs (_: value: value != null) configEnv;
supplementaryGroups = lib.optionalString (cfg.redis.createLocally && isRedisUnixSocket) (
lib.escapeShellArg "--property=SupplementaryGroups=${config.services.redis.servers.greenlight.group}"
);
in
''
exec ${lib.getExe' config.systemd.package "systemd-run"} \
${
lib.escapeShellArgs (map (credential: "--property=LoadCredential=${credential}") loadCredentials)
} \
${
lib.escapeShellArgs (lib.mapAttrsToList (name: value: "--setenv=${name}=${toString value}") env')
} \
--uid=${lib.escapeShellArg cfg.user} \
--gid=${lib.escapeShellArg cfg.group} \
${supplementaryGroups} \
--working-directory=${lib.escapeShellArg cfg.package}/share/greenlight \
--property=PrivateTmp=yes \
--pty \
--wait \
--collect \
--service-type=exec \
--quiet \
-- \
${command} "$@"
'';
};
defaultServiceConfig = {
User = cfg.user;
Group = cfg.group;
WorkingDirectory = "${cfg.package}/share/greenlight";
StateDirectory = [
"greenlight"
"greenlight/secrets"
"greenlight/storage"
];
StateDirectoryMode = "0700";
LogsDirectory = "greenlight";
# Service hardening
ReadWritePaths = [
dataDir
"/var/log/greenlight"
];
CacheDirectory = "greenlight";
AmbientCapabilities = "";
CapabilityBoundingSet = "";
# ProtectClock adds DeviceAllow=char-rtc r
DeviceAllow = "";
DevicePolicy = "closed";
LockPersonality = true;
# Loosening setting, required by Ruby daemon
MemoryDenyWriteExecute = false;
NoNewPrivileges = true;
RemoveIPC = true;
PrivateDevices = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectClock = true;
ProtectHome = true;
ProtectHostname = true;
ProtectSystem = "strict";
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
# Loosening setting, required by Ruby daemon
#"~@privileged @setuid @keyring"
];
UMask = "0077";
# ensure permissions to connect to the redis socket
SupplementaryGroups = lib.mkIf (cfg.redis.createLocally && isRedisUnixSocket) [
config.services.redis.servers.greenlight.group
];
};
in
{
meta = {
buildDocsInSandbox = false;
maintainers = [ lib.maintainers.onny ];
teams = [ lib.teams.ngi ];
};
options.services.greenlight = {
enable = lib.mkEnableOption "Greenlight web interface for BigBlueButton";
package = lib.mkPackageOption pkgs "greenlight" { };
database = {
createLocally = lib.mkOption {
description = ''
Whether to configure a local PostgreSQL server and database for Greenlight.
The connection is performed via Unix sockets.
'';
type = lib.types.bool;
default = true;
};
host = lib.mkOption {
type = lib.types.str;
default = "/run/postgresql";
example = "127.0.0.1";
description = "Hostname or address of the postgresql server. If an absolute path is given here, it will be interpreted as a unix socket path.";
};
port = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = 5432;
description = "Port of the postgresql server.";
};
name = lib.mkOption {
type = lib.types.str;
default = "greenlight";
description = "The name of the Greenlight database.";
};
user = lib.mkOption {
type = lib.types.str;
default = "greenlight";
description = "The database user for Greenlight.";
};
passwordFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
example = "/run/keys/greenlight-db-password";
description = ''
A file containing the password corresponding to {option}`${opt.database.user}`.
'';
};
};
redis = {
createLocally = lib.mkOption {
description = ''
Whether to configure a local Redis server for Greenlight.
The connection is performed via Unix sockets by default,
but that can be changed by configuring {option}`${opt.redis.host}` and {option}`${opt.redis.port}`.
'';
type = lib.types.bool;
default = true;
};
host = lib.mkOption {
description = "The redis host Greenlight will connect to.";
type = lib.types.str;
default =
if cfg.redis.createLocally then config.services.redis.servers.greenlight.unixSocket else null;
defaultText = lib.literalExpression "config.services.redis.servers.greenlight.unixSocket";
};
port = lib.mkOption {
description = "The port of the redis server Greenlight will connect to. Set to zero to disable TCP and use Unix sockets instead.";
type = lib.types.port;
default = 0;
};
};
configureNginx = lib.mkOption {
description = ''
Configure nginx as a reverse proxy for Greenlight.
Alternatively you can configure a reverse-proxy of your choice to serve specific
paths. Take a look at Greenlight's provided reverse proxy configurations at
`https://github.com/bigbluebutton/greenlight/blob/master/greenlight-v3.nginx`.
'';
type = lib.types.bool;
default = true;
};
user = lib.mkOption {
description = ''
User under which Greenlight runs. If it is set to "greenlight",
that user will be created, otherwise it should be set to the
name of a user created elsewhere.
'';
type = lib.types.str;
default = "greenlight";
};
group = lib.mkOption {
description = ''
Group under which Greenlight runs.
'';
type = lib.types.str;
default = "greenlight";
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = lib.types.attrsOf (
lib.types.nullOr (
lib.types.oneOf [
lib.types.str
lib.types.bool
lib.types.int
lib.types.port
lib.types.path
]
)
);
options = {
URL_HOST = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = "Hostname to use";
};
PORT = lib.mkOption {
type = lib.types.port;
default = 6346;
description = "Port for the puma daemon to bind to.";
};
BINDING = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Address for the puma daemon to bind to.";
};
};
};
default = { };
description = ''
Extra configuration options to append or override.
For available and default option values see
[upstream configuration file](https://github.com/bigbluebutton/greenlight/blob/master/sample.env).
'';
};
secretKeyBaseFile = lib.mkOption {
description = ''
Path to file containing the secret key base.
The content of the file will be sourced into {env}`SECRET_KEY_BASE` environment
variable. The secret has a minimum length requirement of 64 bytes.
One way to generate such a secret is to use `openssl rand -hex 64`.
This file is loaded using systemd credentials, and therefore does not need to be
owned by the greenlight user.
If this option is null, it will be created at ${defaultSecretKeyBaseFile}
with a new secret key base.
'';
default = null;
type = lib.types.nullOr lib.types.str;
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !isRedisUnixSocket -> cfg.redis.port != 0;
message = ''
`services.greenlight.redis.port` needs to be configured if `services.greenlight.redis.host` is not a unix socket.
'';
}
{
assertion = !isDatabaseUnixSocket -> cfg.database.port != null;
message = ''
`services.greenlight.database.port` needs to be configured if `services.greenlight.database.host` is not a unix socket.
'';
}
{
assertion = cfg.database.passwordFile == null || !isDatabaseUnixSocket;
message = ''
`services.greenlight.database.passwordFile` has no effect when `services.greenlight.database.host`
is a unix socket, since local socket connections normally authenticate via peer/ident, not a password.
Either point `database.host` at a TCP address, or drop `passwordFile`.
'';
}
{
assertion = !(cfg.database.createLocally && cfg.database.passwordFile != null);
message = ''
`services.greenlight.database.passwordFile` is set, but `database.createLocally` is also enabled.
The PostgreSQL role created via `ensureUsers` has no password configured, so authentication would
fail. Either disable `database.createLocally` and use an external database, or configure the local
role's password yourself (e.g. via `services.postgresql.initialScript`) and keep it in sync with
`passwordFile`.
'';
}
{
assertion = cfg.database.createLocally && isDatabaseUnixSocket -> cfg.database.user == cfg.user;
message = ''
services.greenlight.database.user must equal services.greenlight.user when
services.greenlight.database.createLocally is true and services.greenlight.database.host
is a unix socket, since the local PostgreSQL connection authenticates via peer auth
(OS user must match the Postgres role name).
'';
}
];
services.greenlight.settings = lib.mkMerge [
{
RAILS_ENV = lib.mkDefault "production";
RAILS_ROOT = "${cfg.package}/share/greenlight";
BUNDLE_WITHOUT = "development:test";
BUNDLE_USER_HOME = "/tmp/bundle"; # will use private tmp inside systemd unit
}
redisEnv
];
systemd.services.greenlight-init-credentials = lib.mkIf needsGenCredentialsUnit {
script = ''
if ! test -f ${defaultSecretKeyBaseFile}; then
${lib.getExe' cfg.package.rubyEnv "bundle"} exec rails secret > ${defaultSecretKeyBaseFile}
fi
'';
serviceConfig = {
Type = "oneshot";
SyslogIdentifier = "greenlight-init-dirs";
}
// defaultServiceConfig;
environment = configEnv;
after = [ "network.target" ];
};
systemd.services."greenlight-seeder" = {
script = ''
set -o pipefail -o nounset
shopt -s inherit_errexit
${loadCredentialsIntoEnv}
export DATABASE_PASSWORD="''${DATABASE_PASSWORD:-}"
export DATABASE_URL="${databaseUrl}"
# Auto-migrate on first run or if the package has changed
versionFile="${dataDir}/src-version"
version=$(cat "$versionFile" 2>/dev/null || echo 0)
if [[ $version == 0 ]]; then
echo "Initialising database and running seed..."
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:migrate db:migrate:with_data
echo ${cfg.package.version} > "$versionFile"
elif [[ $version != ${cfg.package.version} ]]; then
echo "Executing database migration and database seed..."
rails db:migrate db:migrate:with_data
echo ${cfg.package.version} > "$versionFile"
fi
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
LoadCredential = loadCredentials;
}
// defaultServiceConfig;
path = [ cfg.package.rubyEnv ];
environment = configEnv;
wants = lib.optional cfg.database.createLocally "postgresql.target";
after = [
"network.target"
]
++ lib.optional cfg.database.createLocally "postgresql.target"
++ lib.optional needsGenCredentialsUnit "greenlight-init-credentials.service"
++ lib.optional cfg.redis.createLocally "redis-greenlight.service";
requires =
lib.optional needsGenCredentialsUnit "greenlight-init-credentials.service"
++ lib.optional cfg.database.createLocally "postgresql.target"
++ lib.optional cfg.redis.createLocally "redis-greenlight.service";
};
systemd.services."greenlight-web" = {
script = ''
${loadCredentialsIntoEnv}
export DATABASE_PASSWORD="''${DATABASE_PASSWORD:-}"
export DATABASE_URL="${databaseUrl}"
${lib.getExe' cfg.package.rubyEnv "bundle"} exec rails server -u puma
'';
serviceConfig = {
LoadCredential = loadCredentials;
}
// defaultServiceConfig;
environment = configEnv;
bindsTo = [ "greenlight-seeder.service" ];
after = [
"greenlight-seeder.service"
]
++ lib.optional needsGenCredentialsUnit "greenlight-init-credentials.service"
++ lib.optional cfg.database.createLocally "postgresql.target"
++ lib.optional cfg.redis.createLocally "redis-greenlight.service";
requires =
lib.optional needsGenCredentialsUnit "greenlight-init-credentials.service"
++ lib.optional cfg.database.createLocally "postgresql.target"
++ lib.optional cfg.redis.createLocally "redis-greenlight.service";
wantedBy = [ "multi-user.target" ];
};
services.redis.servers = lib.mkIf cfg.redis.createLocally {
greenlight = {
enable = true;
port = cfg.redis.port;
bind = lib.mkIf (!isRedisUnixSocket) cfg.redis.host;
};
};
services.postgresql = lib.mkIf cfg.database.createLocally {
enable = true;
ensureUsers = [
{
name = cfg.database.user;
ensureDBOwnership = true;
}
];
ensureDatabases = [ cfg.database.name ];
};
services.nginx = lib.mkIf cfg.configureNginx {
enable = true;
# See https://github.com/bigbluebutton/greenlight/blob/master/greenlight-v3.nginx
virtualHosts."${cfg.settings.URL_HOST}" =
let
bbbProxyHeaders = ''
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host "${cfg.settings.URL_HOST}";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
in
{
root = "${cfg.package}/share/greenlight/public";
locations."/" = {
tryFiles = "$uri @greenlight";
};
locations."@greenlight" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders;
};
locations."/cable" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders + ''
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
'';
};
locations."@bbb-fe" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders + ''
proxy_set_header Connection "";
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
'';
};
locations."~ '/api/v1/rooms/\\w{3}-\\w{3}-\\w{3}-\\w{3}\\.json$'" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders + ''
proxy_set_header Connection "";
client_max_body_size 31m;
'';
};
locations."~ '/api/v1/users/\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}\\.json$'" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders + ''
proxy_set_header Connection "";
client_max_body_size 4m;
'';
};
locations."~ /api/v1/admin/site_settings/BrandingImage\\.json$" = {
proxyPass = "http://${listeningAddress}";
extraConfig = bbbProxyHeaders + ''
proxy_set_header Connection "";
client_max_body_size 4m;
'';
};
};
};
users.users = lib.mkIf (cfg.user == "greenlight") {
greenlight = {
isSystemUser = true;
home = cfg.package;
inherit (cfg) group;
};
};
users.groups = lib.mkIf (cfg.group == "greenlight") { ${cfg.group} = { }; };
environment.systemPackages = [ greenlight-rake ];
};
}

View File

@@ -804,6 +804,7 @@ in
graphite = runTest ./graphite.nix;
grav = runTest ./web-apps/grav.nix;
graylog = runTest ./graylog.nix;
greenlight = runTest ./greenlight.nix;
greetd-no-shadow = runTest ./greetd-no-shadow.nix;
grocy = runTest ./grocy.nix;
grow-partition = runTest ./grow-partition.nix;

View File

@@ -0,0 +1,56 @@
{
lib,
pkgs,
...
}:
{
name = "greenlight";
meta = {
maintainers = [ lib.maintainers.onny ];
teams = [ lib.teams.ngi ];
};
nodes = {
greenlight = {
services.greenlight = {
enable = true;
# For local testing without SSL
settings = {
RAILS_ENV = "development";
RAILS_DUMP_SCHEMA = false;
};
};
};
};
testScript = ''
greenlight.start
greenlight.wait_for_unit("greenlight-web.service")
greenlight.wait_for_open_port(80)
greenlight.wait_for_open_port(6346)
greenlight.succeed("curl -sSfL http://greenlight:80 | grep 'BigBlueButton open source conferencing system'")
greenlight.succeed(
"greenlight-rake admin:create",
)
# grab session cookie + CSRF token
greenlight.succeed("curl -sS -c /tmp/cookies.txt http://localhost/ -o /tmp/page.html")
csrf_token = greenlight.succeed(
"grep -o 'name=\"csrf-token\" content=\"[^\"]*\"' /tmp/page.html "
"| sed 's/.*content=\"//;s/\"$//'"
).strip()
# log in with default credentials
login_result = greenlight.succeed(
f"curl -sSf -c /tmp/cookies.txt -b /tmp/cookies.txt "
f"-X POST http://localhost/api/v1/sessions.json "
f"-H 'Content-Type: application/json' -H 'Accept: application/json' "
f"-H 'X-CSRF-Token: {csrf_token}' "
f"-d '{{\"session\":{{\"email\":\"admin@example.com\",\"password\":\"Administrator1!\"}}}}'"
)
assert '"signed_in":true' in login_result, f"login failed: {login_result}"
'';
}

583
pkgs/by-name/gr/greenlight/Gemfile.lock generated Normal file
View File

@@ -0,0 +1,583 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (7.2.3.1)
actionpack (= 7.2.3.1)
activesupport (= 7.2.3.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (7.2.3.1)
actionpack (= 7.2.3.1)
activejob (= 7.2.3.1)
activerecord (= 7.2.3.1)
activestorage (= 7.2.3.1)
activesupport (= 7.2.3.1)
mail (>= 2.8.0)
actionmailer (7.2.3.1)
actionpack (= 7.2.3.1)
actionview (= 7.2.3.1)
activejob (= 7.2.3.1)
activesupport (= 7.2.3.1)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (7.2.3.1)
actionview (= 7.2.3.1)
activesupport (= 7.2.3.1)
cgi
nokogiri (>= 1.8.5)
racc
rack (>= 2.2.4, < 3.3)
rack-session (>= 1.0.1)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (7.2.3.1)
actionpack (= 7.2.3.1)
activerecord (= 7.2.3.1)
activestorage (= 7.2.3.1)
activesupport (= 7.2.3.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (7.2.3.1)
activesupport (= 7.2.3.1)
builder (~> 3.1)
cgi
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
active_model_serializers (0.10.15)
actionpack (>= 4.1)
activemodel (>= 4.1)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
active_storage_validations (3.0.2)
activejob (>= 6.1.4)
activemodel (>= 6.1.4)
activestorage (>= 6.1.4)
activesupport (>= 6.1.4)
marcel (>= 1.0.3)
activejob (7.2.3.1)
activesupport (= 7.2.3.1)
globalid (>= 0.3.6)
activemodel (7.2.3.1)
activesupport (= 7.2.3.1)
activerecord (7.2.3.1)
activemodel (= 7.2.3.1)
activesupport (= 7.2.3.1)
timeout (>= 0.4.0)
activestorage (7.2.3.1)
actionpack (= 7.2.3.1)
activejob (= 7.2.3.1)
activerecord (= 7.2.3.1)
activesupport (= 7.2.3.1)
marcel (~> 1.0)
activesupport (7.2.3.1)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1, < 6)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
aes_key_wrap (1.1.0)
ast (2.4.3)
attr_required (1.0.2)
aws-eventstream (1.4.0)
aws-partitions (1.1196.0)
aws-sdk-core (3.240.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.118.0)
aws-sdk-core (~> 3, >= 3.239.1)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.208.0)
aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.3.0)
bcrypt (3.1.22)
benchmark (0.5.0)
bigbluebutton-api-ruby (2.0.0)
base64 (>= 0.1.0)
xml-simple (~> 1.1)
bigdecimal (4.1.1)
bindata (2.5.1)
bindex (0.8.1)
bootsnap (1.16.0)
msgpack (~> 1.2)
builder (3.3.0)
capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
case_transform (0.2)
activesupport
cgi (0.5.1)
clamby (1.6.10)
concurrent-ruby (1.3.7)
connection_pool (2.5.5)
crack (1.0.0)
bigdecimal
rexml
crass (1.0.6)
cssbundling-rails (1.4.3)
railties (>= 6.0.0)
data_migrate (11.3.1)
activerecord (>= 6.1)
railties (>= 6.1)
date (3.5.1)
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
declarative (0.0.20)
diff-lcs (1.6.2)
digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0)
dotenv (3.2.0)
dotenv-rails (3.2.0)
dotenv (= 3.2.0)
railties (>= 6.1)
drb (2.2.3)
email_validator (2.2.4)
activemodel
erb (6.0.1.1)
erubi (1.13.1)
factory_bot (6.5.6)
activesupport (>= 6.1.0)
factory_bot_rails (6.5.1)
factory_bot (~> 6.5)
railties (>= 6.1.0)
faker (3.1.1)
i18n (>= 1.8.11, < 2)
faraday (2.14.3)
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-follow_redirects (0.4.0)
faraday (>= 1, < 3)
faraday-net_http (3.4.4)
net-http (~> 0.5)
ffi (1.17.2)
globalid (1.3.0)
activesupport (>= 6.1)
google-apis-core (1.0.2)
addressable (~> 2.8, >= 2.8.7)
faraday (~> 2.13)
faraday-follow_redirects (~> 0.3)
googleauth (~> 1.14)
mini_mime (~> 1.1)
representable (~> 3.0)
retriable (~> 3.1)
google-apis-iamcredentials_v1 (0.26.0)
google-apis-core (>= 0.15.0, < 2.a)
google-apis-storage_v1 (0.60.0)
google-apis-core (>= 0.15.0, < 2.a)
google-cloud-core (1.8.0)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (2.3.1)
base64 (~> 0.2)
faraday (>= 1.0, < 3.a)
google-cloud-errors (1.5.0)
google-cloud-storage (1.58.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-core (>= 0.18, < 2)
google-apis-iamcredentials_v1 (~> 0.18)
google-apis-storage_v1 (>= 0.42)
google-cloud-core (~> 1.6)
googleauth (~> 1.9)
mini_mime (~> 1.0)
google-logging-utils (0.2.0)
googleauth (1.16.1)
faraday (>= 1.0, < 3.a)
google-cloud-env (~> 2.2)
google-logging-utils (~> 0.1)
jwt (>= 1.4, < 4.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
hashdiff (1.1.2)
hashie (5.0.0)
hcaptcha (7.1.0)
json
i18n (1.14.8)
concurrent-ruby (~> 1.0)
i18n-language-mapping (0.1.3.1)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
io-console (0.8.1)
irb (1.15.3)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
jbuilder (2.13.0)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
jmespath (1.6.2)
jsbundling-rails (1.3.1)
railties (>= 6.0.0)
json (2.19.9)
json-jwt (1.17.0)
activesupport (>= 4.2)
aes_key_wrap
base64
bindata
faraday (~> 2.0)
faraday-follow_redirects
jsonapi-renderer (0.2.2)
jwt (3.2.0)
base64
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
logger (1.7.0)
lograge (0.14.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
loofah (2.25.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.9.0)
logger
mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
marcel (1.1.0)
matrix (0.4.3)
mini_magick (4.12.0)
mini_mime (1.1.5)
mini_portile2 (2.8.9)
minitest (5.27.0)
msgpack (1.6.0)
multi_json (1.19.1)
net-http (0.9.1)
uri (>= 0.11.1)
net-imap (0.5.15)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
timeout
net-smtp (0.5.1)
net-protocol
nio4r (2.7.5)
nkf (0.2.0)
nokogiri (1.19.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
omniauth (2.1.4)
hashie (>= 3.4.6)
logger
rack (>= 2.2.3)
rack-protection
omniauth-rails_csrf_protection (2.0.0)
actionpack (>= 4.2)
omniauth (~> 2.0)
omniauth_openid_connect (0.8.0)
omniauth (>= 1.9, < 3)
openid_connect (~> 2.2)
openid_connect (2.3.1)
activemodel
attr_required (>= 1.0.0)
email_validator
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.16)
mail
rack-oauth2 (~> 2.2)
swd (~> 2.0)
tzinfo
validate_url
webfinger (~> 2.0)
os (1.1.4)
pagy (6.0.4)
parallel (1.27.0)
parser (3.3.10.0)
ast (~> 2.4.1)
racc
pg (1.4.5)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.6.0)
psych (5.2.6)
date
stringio
public_suffix (7.0.5)
puma (7.2.1)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.2.6)
rack-oauth2 (2.3.0)
activesupport
attr_required
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (4.2.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
rack-session (2.1.2)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
rackup (2.2.1)
rack (>= 3)
rails (7.2.3.1)
actioncable (= 7.2.3.1)
actionmailbox (= 7.2.3.1)
actionmailer (= 7.2.3.1)
actionpack (= 7.2.3.1)
actiontext (= 7.2.3.1)
actionview (= 7.2.3.1)
activejob (= 7.2.3.1)
activemodel (= 7.2.3.1)
activerecord (= 7.2.3.1)
activestorage (= 7.2.3.1)
activesupport (= 7.2.3.1)
bundler (>= 1.15.0)
railties (= 7.2.3.1)
rails-dom-testing (2.3.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.7.0)
loofah (~> 2.25)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (7.2.3.1)
actionpack (= 7.2.3.1)
activesupport (= 7.2.3.1)
cgi
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
tsort (>= 0.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.3.1)
rdoc (6.16.1)
erb
psych (>= 4.0.0)
tsort
redis (4.8.0)
regexp_parser (2.11.3)
reline (0.6.3)
io-console (~> 0.5)
remote_syslog_logger (1.0.4)
syslog_protocol
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
request_store (1.5.1)
rack (>= 1.4)
retriable (3.1.2)
rexml (3.4.4)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-rails (7.1.1)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
rspec-core (~> 3.13)
rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13)
rspec-support (~> 3.13)
rspec-support (3.13.6)
rubocop (1.81.7)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.48.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-capybara (2.19.0)
rubocop (~> 1.41)
rubocop-factory_bot (2.24.0)
rubocop (~> 1.33)
rubocop-performance (1.16.0)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.34.2)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rspec (2.9.0)
rubocop (~> 1.19)
ruby-progressbar (1.13.0)
ruby-vips (2.1.4)
ffi (~> 1.12)
rubyzip (2.4.1)
securerandom (0.4.1)
selenium-webdriver (4.8.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
shoulda-matchers (5.3.0)
activesupport (>= 5.2.0)
signet (0.21.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 4.0)
multi_json (~> 1.10)
sprockets (4.2.2)
concurrent-ruby (~> 1.0)
logger
rack (>= 2.2.4, < 4)
sprockets-rails (3.5.2)
actionpack (>= 6.1)
activesupport (>= 6.1)
sprockets (>= 3.0.0)
stringio (3.1.9)
swd (2.0.3)
activesupport (>= 3)
attr_required (>= 0.0.5)
faraday (~> 2.0)
faraday-follow_redirects
syslog_protocol (0.9.2)
thor (1.4.0)
timeout (0.6.1)
trailblazer-option (0.1.2)
tsort (0.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.1.0)
uri (1.1.1)
useragent (0.16.11)
validate_url (1.0.15)
activemodel (>= 3.0.0)
public_suffix
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webdrivers (5.2.0)
nokogiri (~> 1.6)
rubyzip (>= 1.3.0)
selenium-webdriver (~> 4.0)
webfinger (2.1.3)
activesupport
faraday (~> 2.0)
faraday-follow_redirects
webmock (3.24.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
websocket (1.2.9)
websocket-driver (0.8.1)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xml-simple (1.1.9)
rexml
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.7.3)
PLATFORMS
ruby
DEPENDENCIES
active_model_serializers (>= 0.10.15)
active_storage_validations (>= 1.4.0)
aws-sdk-s3
bcrypt (~> 3.1.22)
bigbluebutton-api-ruby (= 2.0.0)
bootsnap
capybara (>= 3.39.0)
clamby (~> 1.6.10)
connection_pool (~> 2.4)
cssbundling-rails (>= 1.4.0)
data_migrate (>= 11.3.0)
debug
dotenv-rails (>= 3.0.0)
factory_bot (>= 6.4.1)
factory_bot_rails (>= 6.4.4)
faker
google-cloud-storage (~> 1.45, >= 1.45.0)
hcaptcha
i18n-language-mapping
image_processing (~> 1.2)
jbuilder (>= 2.12)
jsbundling-rails (>= 1.3.0)
jwt
lograge (~> 0.14.0)
mini_magick (>= 4.9.5)
nkf (~> 0.2.0)
omniauth (~> 2.1.3)
omniauth-rails_csrf_protection (~> 2.0.0)
omniauth_openid_connect (>= 0.8.0)
pagy (~> 6.0, >= 6.0.0)
pg
puma (~> 7.2)
rails (~> 7.2.3)
redis (~> 4.8.0)
remote_syslog_logger
rspec-rails (~> 7.1, >= 7.1.1)
rubocop (~> 1.26)
rubocop-capybara (~> 2.19.0)
rubocop-factory_bot (~> 2.24.0)
rubocop-performance (~> 1.13)
rubocop-rails (~> 2.21, >= 2.21.0)
rubocop-rspec (~> 2.9.0)
selenium-webdriver
shoulda-matchers (~> 5.0)
sprockets-rails (>= 3.5.1)
tzinfo-data
web-console (>= 4.2.1)
webdrivers
webmock (>= 3.23.1)
RUBY VERSION
ruby 3.3.10p183
BUNDLED WITH
2.5.22

View File

@@ -0,0 +1,17 @@
diff --git a/config/environments/development.rb b/config/environments/development.rb
index c0cba740..a4a3f4d1 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -117,6 +117,12 @@ Rails.application.configure do
# Suppress logger output for asset requests.
config.assets.quiet = true
+ # Do not dump schema after migrations.
+ config.active_record.dump_schema_after_migration = Rails.env.development? && ENV["RAILS_DUMP_SCHEMA"] != "false"
+
+ # Ensure requests are considered secure if they come through a reverse proxy with the correct headers
+ config.action_controller.forgery_protection_origin_check = ENV['FORGERY_ORIGIN_CHECK'] != 'false'
+
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true

2838
pkgs/by-name/gr/greenlight/gemset.nix generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,119 @@
{
lib,
stdenv,
fetchFromGitHub,
bundlerEnv,
fetchNpmDeps,
nodejs_26,
npmHooks,
ruby_3_3,
makeWrapper,
which,
nixosTests,
nix-update-script,
_experimental-update-script-combinators,
}:
let
ruby = ruby_3_3;
nodejs = nodejs_26;
in
stdenv.mkDerivation (finalAttrs: {
pname = "greenlight";
version = "3.8.2.4";
__structuredAttrs = true;
strictDeps = true;
src = fetchFromGitHub {
owner = "bigbluebutton";
repo = "greenlight";
tag = "release-${finalAttrs.version}";
hash = "sha256-GOgOEP6dx1E/rIe4HBR35TM294ad8ywcBXVea1xFOag=";
};
patches = [
# Expose further Rails development configurations as env vars
./expose_rails_dev_configs.patch
];
postPatch = ''
# jsbundling-rails dependency would executes yarn install but
# we'll stick with npm
rm -f yarn.lock
substituteInPlace "config/storage.yml" --replace-fail \
'root: <%= Rails.root.join("storage") %>' \
'root: "/var/lib/greenlight/storage"'
substituteInPlace "config/environments/development.rb" --replace-fail \
' config.hosts = nil' \
' config.hosts = nil; config.paths["log"] = ["/var/log/greenlight/development.log"]'
'';
nativeBuildInputs = [
makeWrapper
which
nodejs
npmHooks.npmConfigHook
finalAttrs.rubyEnv.wrappedRuby
];
npmDeps = fetchNpmDeps {
inherit (finalAttrs) src;
hash = "sha256-aTDd6+mc3DIE5FiaPVjjorJ0r8RfodhEVCs3o2zHbZk=";
};
rubyEnv = bundlerEnv {
name = "greenlight-env-${finalAttrs.version}";
inherit ruby;
gemfile = "${finalAttrs.src}/Gemfile";
# Manually need to remove platform not supported by bundix
# See https://github.com/bigbluebutton/greenlight/pull/6317
lockfile = ./Gemfile.lock;
gemset = ./gemset.nix;
groups = [ "production" ];
};
makeCacheWritable = true;
buildPhase = ''
runHook preBuild
export BUNDLE_WITHOUT=development:test
export SECRET_KEY_BASE=1
bundle exec rails assets:precompile
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/share/greenlight $out/bin
cp -r app bin config config.ru db lib public vendor Gemfile Gemfile.lock Rakefile $out/share/greenlight/
ln -s $out/share/greenlight/lib $out/lib
ln -s $out/share/greenlight/bin $out/bin
ln -sf /tmp $out/share/greenlight/tmp
runHook postInstall
'';
passthru = {
inherit (finalAttrs) rubyEnv;
tests = { inherit (nixosTests) greenlight; };
# run with: nix-shell ./maintainers/scripts/update.nix --argstr package greenlight
updateScript = _experimental-update-script-combinators.sequence [
(nix-update-script { })
./update.sh
];
};
meta = {
description = "End-user web interface for BigBlueButton server";
homepage = "https://github.com/bigbluebutton/greenlight";
platforms = lib.platforms.linux;
license = lib.licenses.lgpl3Only;
maintainers = [ lib.maintainers.onny ];
teams = [ lib.teams.ngi ];
};
})

View File

@@ -0,0 +1,20 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bundix ruby_3_3 nixfmt
set -eu -o pipefail
set -x
dir="$(dirname "$(readlink -f "$0")")"
# nix-update-script already bumped src.tag/hash before this runs.
# Just regenerate the gem lockfiles for the current (already-updated) source.
repo=$(mktemp -d /tmp/greenlight-update.XXX)
rm -f "$dir/gemset.nix" "$dir/Gemfile.lock"
greenlight_storepath=$(nix build --no-link --print-out-paths -f . greenlight.src)
cp -r --no-preserve=mode,ownership "$greenlight_storepath/." "$repo/"
# remove binary platform otherwise building will fail
# see https://github.com/bigbluebutton/greenlight/pull/6317
BUNDLE_GEMFILE="$repo/Gemfile" bundler lock --remove-platform x86_64-linux --lockfile="$repo/Gemfile.lock"
bundix --lock --lockfile="$repo/Gemfile.lock" --gemfile="$repo/Gemfile" --gemset="$dir/gemset.nix"
cp "$repo/Gemfile.lock" "$dir/"
nixfmt "$dir/gemset.nix"