mirror of
https://github.com/CHN-beta/nixpkgs.git
synced 2026-01-12 02:40:31 +08:00
https://meta.discourse.org/t/release-v3-5-3-security-and-maintenance-release/392357 Fixes: CVE-2025-64528
546 lines
14 KiB
Nix
546 lines
14 KiB
Nix
{
|
|
stdenv,
|
|
pkgs,
|
|
makeWrapper,
|
|
runCommand,
|
|
lib,
|
|
writeShellScript,
|
|
fetchFromGitHub,
|
|
bundlerEnv,
|
|
callPackage,
|
|
nixosTests,
|
|
|
|
defaultGemConfig,
|
|
ruby_3_3,
|
|
gzip,
|
|
gnutar,
|
|
git,
|
|
cacert,
|
|
util-linux,
|
|
gawk,
|
|
net-tools,
|
|
imagemagick,
|
|
optipng,
|
|
pngquant,
|
|
libjpeg,
|
|
jpegoptim,
|
|
gifsicle,
|
|
jhead,
|
|
oxipng,
|
|
libpsl,
|
|
redis,
|
|
postgresql,
|
|
which,
|
|
brotli,
|
|
procps,
|
|
rsync,
|
|
icu,
|
|
rustPlatform,
|
|
buildRubyGem,
|
|
rustc,
|
|
cargo,
|
|
pnpm_9,
|
|
fetchPnpmDeps,
|
|
pnpmConfigHook,
|
|
svgo,
|
|
nodejs,
|
|
jq,
|
|
moreutils,
|
|
terser,
|
|
uglify-js,
|
|
|
|
plugins ? [ ],
|
|
}:
|
|
|
|
let
|
|
version = "3.5.3";
|
|
|
|
src = fetchFromGitHub {
|
|
owner = "discourse";
|
|
repo = "discourse";
|
|
rev = "v${version}";
|
|
sha256 = "sha256-2lx6vFxio2CkMWa0vmzUGTljz1WC9OzpNgSxKjYPn8g=";
|
|
};
|
|
|
|
ruby = ruby_3_3;
|
|
|
|
runtimeDeps = [
|
|
# For backups, themes and assets
|
|
rubyEnv.wrappedRuby
|
|
rsync
|
|
gzip
|
|
gnutar
|
|
git
|
|
brotli
|
|
nodejs
|
|
|
|
# Misc required system utils
|
|
which
|
|
procps # For ps and kill
|
|
util-linux # For renice
|
|
gawk
|
|
net-tools # For hostname
|
|
|
|
# Image optimization
|
|
imagemagick
|
|
optipng
|
|
oxipng
|
|
pngquant
|
|
libjpeg
|
|
jpegoptim
|
|
gifsicle
|
|
svgo
|
|
jhead
|
|
];
|
|
|
|
runtimeEnv = {
|
|
HOME = "/run/discourse/home";
|
|
RAILS_ENV = "production";
|
|
UNICORN_LISTENER = "/run/discourse/sockets/unicorn.sock";
|
|
};
|
|
|
|
mkDiscoursePlugin =
|
|
{
|
|
name ? null,
|
|
pname ? null,
|
|
version ? null,
|
|
meta ? null,
|
|
bundlerEnvArgs ? { },
|
|
preserveGemsDir ? false,
|
|
src,
|
|
...
|
|
}@args:
|
|
let
|
|
rubyEnv = bundlerEnv (
|
|
bundlerEnvArgs
|
|
// {
|
|
inherit
|
|
name
|
|
pname
|
|
version
|
|
ruby
|
|
;
|
|
}
|
|
);
|
|
in
|
|
stdenv.mkDerivation (
|
|
# Allow overriding the plugin name
|
|
{
|
|
pluginName = if name != null then name else "${pname}-${version}";
|
|
}
|
|
// removeAttrs args [ "bundlerEnvArgs" ]
|
|
// {
|
|
dontConfigure = true;
|
|
dontBuild = true;
|
|
installPhase = ''
|
|
runHook preInstall
|
|
mkdir -p $out
|
|
cp -r * $out/
|
|
''
|
|
+ lib.optionalString (bundlerEnvArgs != { }) (
|
|
if preserveGemsDir then
|
|
''
|
|
cp -r ${rubyEnv}/lib/ruby/gems/* $out/gems/
|
|
''
|
|
else
|
|
''
|
|
if [[ -e $out/gems ]]; then
|
|
echo "Warning: The repo contains a 'gems' directory which will be removed!"
|
|
echo " If you need to preserve it, set 'preserveGemsDir = true'."
|
|
rm -r $out/gems
|
|
fi
|
|
ln -sf ${rubyEnv}/lib/ruby/gems $out/gems
|
|
''
|
|
+ ''
|
|
runHook postInstall
|
|
''
|
|
);
|
|
}
|
|
);
|
|
|
|
rake =
|
|
runCommand "discourse-rake"
|
|
{
|
|
nativeBuildInputs = [ makeWrapper ];
|
|
}
|
|
''
|
|
mkdir -p $out/bin
|
|
makeWrapper ${rubyEnv}/bin/rake $out/bin/discourse-rake \
|
|
${
|
|
lib.concatStrings (lib.mapAttrsToList (name: value: "--set ${name} '${value}' ") runtimeEnv)
|
|
} \
|
|
--prefix PATH : ${lib.makeBinPath runtimeDeps} \
|
|
--set RAKEOPT '-f ${discourse}/share/discourse/Rakefile' \
|
|
--chdir '${discourse}/share/discourse'
|
|
'';
|
|
|
|
rubyEnv = bundlerEnv {
|
|
name = "discourse-ruby-env-${version}";
|
|
inherit version ruby;
|
|
gemdir = ./rubyEnv;
|
|
gemset = import ./rubyEnv/gemset.nix;
|
|
gemConfig = defaultGemConfig // {
|
|
mini_racer = attrs: {
|
|
buildInputs = [ icu ];
|
|
dontBuild = false;
|
|
NIX_LDFLAGS = "-licui18n";
|
|
};
|
|
libv8-node =
|
|
attrs:
|
|
let
|
|
noopScript = writeShellScript "noop" "exit 0";
|
|
linkFiles = writeShellScript "link-files" ''
|
|
cd ../..
|
|
|
|
mkdir -p vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/
|
|
ln -s "${nodejs.libv8}/lib/libv8.a" vendor/v8/${stdenv.hostPlatform.system}/libv8/obj/libv8_monolith.a
|
|
|
|
ln -s ${nodejs.libv8}/include vendor/v8/include
|
|
|
|
mkdir -p ext/libv8-node
|
|
echo '--- !ruby/object:Libv8::Node::Location::Vendor {}' >ext/libv8-node/.location.yml
|
|
'';
|
|
in
|
|
{
|
|
dontBuild = false;
|
|
postPatch = ''
|
|
cp ${noopScript} libexec/build-libv8
|
|
cp ${noopScript} libexec/build-monolith
|
|
cp ${noopScript} libexec/download-node
|
|
cp ${noopScript} libexec/extract-node
|
|
cp ${linkFiles} libexec/inject-libv8
|
|
'';
|
|
};
|
|
mini_suffix = attrs: {
|
|
propagatedBuildInputs = [ libpsl ];
|
|
dontBuild = false;
|
|
# Use our libpsl instead of the vendored one, which isn't
|
|
# available for aarch64. It has to be called
|
|
# libpsl.x86_64.so or it isn't found.
|
|
postPatch = ''
|
|
cp $(readlink -f ${lib.getLib libpsl}/lib/libpsl.so) vendor/libpsl.x86_64.so
|
|
'';
|
|
};
|
|
tokenizers = attrs: {
|
|
cargoDeps = rustPlatform.fetchCargoVendor {
|
|
inherit (buildRubyGem { inherit (attrs) gemName version source; })
|
|
name
|
|
src
|
|
unpackPhase
|
|
nativeBuildInputs
|
|
;
|
|
hash = "sha256-ydSXo3wp13/mPgJv1HbavNurkd2KxuKzuJNHliPpn2I=";
|
|
};
|
|
|
|
dontBuild = false;
|
|
|
|
nativeBuildInputs = [
|
|
cargo
|
|
rustc
|
|
rustPlatform.cargoSetupHook
|
|
rustPlatform.bindgenHook
|
|
];
|
|
|
|
disallowedReferences = [
|
|
rustc.unwrapped
|
|
];
|
|
|
|
preInstall = ''
|
|
export CARGO_HOME="$PWD/../.cargo/"
|
|
'';
|
|
|
|
postInstall = ''
|
|
find $out -type f -name .rustc_info.json -delete
|
|
'';
|
|
};
|
|
tiktoken_ruby = attrs: {
|
|
cargoDeps = rustPlatform.fetchCargoVendor {
|
|
inherit (buildRubyGem { inherit (attrs) gemName version source; })
|
|
name
|
|
src
|
|
unpackPhase
|
|
nativeBuildInputs
|
|
;
|
|
hash = "sha256-IABOxUymtFkF9sl1kRWAS5hM6GNJI6Y4VFICXdX7zF0=";
|
|
};
|
|
|
|
dontBuild = false;
|
|
|
|
nativeBuildInputs = [
|
|
cargo
|
|
rustc
|
|
rustPlatform.cargoSetupHook
|
|
rustPlatform.bindgenHook
|
|
];
|
|
|
|
disallowedReferences = [
|
|
rustc.unwrapped
|
|
];
|
|
|
|
preInstall = ''
|
|
export CARGO_HOME="$PWD/../.cargo/"
|
|
'';
|
|
|
|
postInstall = ''
|
|
#ls $GEM_HOME/gems/${attrs.gemName}-${attrs.version}/lib
|
|
#mv -v $GEM_HOME/gems/${attrs.gemName}-${attrs.version}/lib/{glfm_markdown/glfm_markdown.so,}
|
|
find $out -type f -name .rustc_info.json -delete
|
|
'';
|
|
};
|
|
};
|
|
|
|
groups = [
|
|
"default"
|
|
"assets"
|
|
"development"
|
|
"test"
|
|
];
|
|
};
|
|
|
|
assets = stdenv.mkDerivation {
|
|
pname = "discourse-assets";
|
|
inherit version src;
|
|
|
|
pnpmDeps = fetchPnpmDeps {
|
|
pname = "discourse-assets";
|
|
inherit version src;
|
|
pnpm = pnpm_9;
|
|
fetcherVersion = 1;
|
|
hash = "sha256-npRKX5Lr2QrPD8OFBysDl30exP+FTnjMxFeR/Gv0Z0I=";
|
|
};
|
|
|
|
nativeBuildInputs = runtimeDeps ++ [
|
|
(postgresql.withPackages (ps: [
|
|
ps.pgvector
|
|
]))
|
|
redis
|
|
uglify-js
|
|
terser
|
|
jq
|
|
moreutils
|
|
nodejs
|
|
pnpmConfigHook
|
|
pnpm_9
|
|
];
|
|
|
|
outputs = [
|
|
"out"
|
|
"javascripts"
|
|
"node_modules"
|
|
"generated"
|
|
];
|
|
|
|
patches = [
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
# one constructed by bundlerEnv
|
|
./plugin_gem_api_version.patch
|
|
|
|
# Change the path to the auto generated plugin assets, which
|
|
# defaults to the plugin's directory and isn't writable at the
|
|
# time of asset generation
|
|
./auto_generated_path.patch
|
|
|
|
# Fix the rake command used to recursively execute itself in the
|
|
# assets precompilation task.
|
|
./assets_rake_command.patch
|
|
|
|
# Little does he know, so he decided there is no need to generate the
|
|
# theme-transpiler over and over again. Which at the same time allows the removal
|
|
# of javascript devDependencies from the runtime environment.
|
|
./prebuild-theme-transpiler.patch
|
|
];
|
|
|
|
env.RAILS_ENV = "production";
|
|
env.DISCOURSE_DOWNLOAD_PRE_BUILT_ASSETS = "0";
|
|
# Allow to use different bundler version than the lockfile has
|
|
env.BUNDLER_VERSION = pkgs.bundler.version;
|
|
|
|
# requires full git and repository, even a src `leaveDotGit` is not enough. So patch this function to return the version
|
|
postPatch = ''
|
|
substituteInPlace script/assemble_ember_build.rb --replace-fail "def core_tree_hash" "def core_tree_hash; return \"v${version}\""
|
|
'';
|
|
|
|
# We have to set up an environment that is close enough to
|
|
# production ready or the assets:precompile task refuses to
|
|
# run. This means that Redis and PostgreSQL has to be running and
|
|
# database migrations performed.
|
|
preBuild = ''
|
|
# Patch before running postinstall hook script
|
|
patchShebangs node_modules/
|
|
patchShebangs --build app/assets/javascripts
|
|
export SSL_CERT_FILE=${cacert}/etc/ssl/certs/ca-bundle.crt
|
|
|
|
redis-server >/dev/null &
|
|
|
|
initdb -A trust $NIX_BUILD_TOP/postgres >/dev/null
|
|
postgres -D $NIX_BUILD_TOP/postgres -k $NIX_BUILD_TOP >/dev/null &
|
|
export PGHOST=$NIX_BUILD_TOP
|
|
|
|
echo "Waiting for Redis and PostgreSQL to be ready.."
|
|
while ! redis-cli --scan >/dev/null || ! psql -l >/dev/null; do
|
|
sleep 0.1
|
|
done
|
|
|
|
psql -d postgres -tAc 'CREATE USER "discourse"'
|
|
psql -d postgres -tAc 'CREATE DATABASE "discourse" OWNER "discourse"'
|
|
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
|
|
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS hstore"
|
|
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS vector"
|
|
|
|
${lib.concatMapStringsSep "\n" (p: "ln -sf ${p} plugins/${p.pluginName or ""}") plugins}
|
|
|
|
bundle exec rake db:migrate >/dev/null
|
|
chmod -R +w tmp
|
|
'';
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
patchShebangs script/
|
|
bundle exec rake assets:precompile
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mv public/assets $out
|
|
|
|
mv node_modules $node_modules
|
|
|
|
rm -rf app/assets/javascripts/plugins
|
|
mv app/assets/javascripts $javascripts
|
|
ln -sf /run/discourse/assets/javascripts/plugins $javascripts/plugins
|
|
mv app/assets/generated $generated
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
# The node_modules output by design has broken symlinks, as it refers to the source code.
|
|
# They are resolved in the primary discourse derivation.
|
|
dontCheckForBrokenSymlinks = true;
|
|
};
|
|
|
|
discourse = stdenv.mkDerivation {
|
|
pname = "discourse";
|
|
inherit version src;
|
|
|
|
buildInputs = [
|
|
rubyEnv
|
|
rubyEnv.wrappedRuby
|
|
rubyEnv.bundler
|
|
];
|
|
|
|
patches = [
|
|
# Load a separate NixOS site settings file
|
|
./nixos_defaults.patch
|
|
|
|
# Add a noninteractive admin creation task
|
|
./admin_create.patch
|
|
|
|
# Add the path to the CA cert bundle to make TLS work
|
|
./action_mailer_ca_cert.patch
|
|
|
|
# Log Unicorn messages to the journal and make request timeout
|
|
# configurable
|
|
./unicorn_logging_and_timeout.patch
|
|
|
|
# Use the Ruby API version in the plugin gem path, to match the
|
|
# one constructed by bundlerEnv
|
|
./plugin_gem_api_version.patch
|
|
|
|
# Change the path to the auto generated plugin assets, which
|
|
# defaults to the plugin's directory and isn't writable at the
|
|
# time of asset generation
|
|
./auto_generated_path.patch
|
|
|
|
# Make sure the notification email setting applies
|
|
./notification_email.patch
|
|
|
|
# Little does he know, so he decided there is no need to generate the
|
|
# theme-transpiler over and over again. Which at the same time allows the removal
|
|
# of javascript devDependencies from the runtime environment.
|
|
./prebuild-theme-transpiler.patch
|
|
|
|
# Our app/assets/generated folder is a symlink, but the ruby File.mkdir_p doesn't allow
|
|
# a symlink in the way to the last directory. This patch explicitly resolves the symlink.
|
|
./resolve_generated_assets_symlink.patch
|
|
];
|
|
|
|
postPatch = ''
|
|
# Always require lib-files and application.rb through their store
|
|
# path, not their relative state directory path. This gets rid of
|
|
# warnings and means we don't have to link back to lib from the
|
|
# state directory.
|
|
find config -type f -name "*.rb" -execdir \
|
|
sed -Ei "s,(\.\./)+(lib|app)/,$out/share/discourse/\2/," {} \;
|
|
find config -maxdepth 1 -type f -name "*.rb" -execdir \
|
|
sed -Ei "s,require_relative (\"|')([[:alnum:]].*)(\"|'),require_relative '$out/share/discourse/config/\2'," {} \;
|
|
'';
|
|
|
|
buildPhase = ''
|
|
runHook preBuild
|
|
|
|
mv config config.dist
|
|
mv public public.dist
|
|
|
|
runHook postBuild
|
|
'';
|
|
|
|
installPhase = ''
|
|
runHook preInstall
|
|
|
|
mkdir -p $out/share
|
|
cp -r . $out/share/discourse
|
|
rm -r $out/share/discourse/log
|
|
ln -sf /var/log/discourse $out/share/discourse/log
|
|
ln -sf /var/lib/discourse/tmp $out/share/discourse/tmp
|
|
ln -sf /run/discourse/config $out/share/discourse/config
|
|
ln -sf /run/discourse/public $out/share/discourse/public
|
|
ln -sf /run/discourse/assets-generated $out/share/discourse/app/assets/generated
|
|
ln -sf ${assets.node_modules} $out/share/discourse/node_modules
|
|
ln -sf ${assets} $out/share/discourse/public.dist/assets
|
|
rm -r $out/share/discourse/app/assets/javascripts
|
|
# This needs to be copied because it contains symlinks to node_modules
|
|
cp -r ${assets.javascripts} $out/share/discourse/app/assets/javascripts
|
|
${lib.concatMapStringsSep "\n" (
|
|
p: "ln -sf ${p} $out/share/discourse/plugins/${p.pluginName or ""}"
|
|
) plugins}
|
|
|
|
runHook postInstall
|
|
'';
|
|
|
|
passthru = {
|
|
inherit
|
|
rubyEnv
|
|
runtimeEnv
|
|
runtimeDeps
|
|
rake
|
|
mkDiscoursePlugin
|
|
assets
|
|
;
|
|
inherit (pkgs)
|
|
discourseAllPlugins
|
|
;
|
|
enabledPlugins = plugins;
|
|
plugins = callPackage ./plugins/all-plugins.nix { inherit mkDiscoursePlugin; };
|
|
ruby = rubyEnv.wrappedRuby;
|
|
tests = {
|
|
inherit (nixosTests)
|
|
discourse
|
|
discourseAllPlugins
|
|
;
|
|
};
|
|
};
|
|
meta = {
|
|
homepage = "https://www.discourse.org/";
|
|
platforms = lib.platforms.linux;
|
|
maintainers = with lib.maintainers; [ talyz ];
|
|
license = lib.licenses.gpl2Plus;
|
|
description = "Open source discussion platform";
|
|
};
|
|
};
|
|
in
|
|
discourse
|