about summary refs log tree commit diff
path: root/nixpkgs/pkgs/applications/networking/browsers/chromium
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/applications/networking/browsers/chromium')
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/README.md99
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix98
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix357
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix234
-rwxr-xr-xnixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py53
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch17
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch13
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix43
-rwxr-xr-xnixpkgs/pkgs/applications/networking/browsers/chromium/update.py233
-rw-r--r--nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json63
10 files changed, 1210 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md b/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md
new file mode 100644
index 000000000000..9576cb486288
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/README.md
@@ -0,0 +1,99 @@
+# Maintainers
+
+- Note: We could always use more contributors, testers, etc. E.g.:
+  - A dedicated maintainer for the NixOS stable channel
+  - PRs with cleanups, improvements, fixes, etc. (but please try to make reviews
+    as easy as possible)
+  - People who handle stale issues/PRs
+- Primary maintainer (responsible for all updates): @primeos
+- Testers (test all stable channel updates)
+  - `nixos-unstable`:
+    - `x86_64`: @danielfullmer
+    - `aarch64`: @thefloweringash
+  - Stable channel:
+    - `x86_64`: @Frostman
+- Other relevant packages:
+  - `chromiumBeta` and `chromiumDev`: For testing purposes only (not build on
+    Hydra). We use these channels for testing and to fix build errors in advance
+    so that `chromium` updates are trivial and can be merged fast.
+  - `google-chrome`, `google-chrome-beta`, `google-chrome-dev`: Updated via
+    Chromium's `upstream-info.json`
+  - `ungoogled-chromium`: @squalus
+  - `chromedriver`: Updated via Chromium's `upstream-info.json` and not built
+    from source.
+
+# Upstream links
+
+- Source code: https://source.chromium.org/chromium/chromium/src
+- Bugs: https://bugs.chromium.org/p/chromium/issues/list
+- Release updates: https://chromereleases.googleblog.com/
+  - Available as Atom or RSS feed (filter for
+    "Stable Channel Update for Desktop")
+  - Channel overview: https://omahaproxy.appspot.com/
+  - Release schedule: https://chromiumdash.appspot.com/schedule
+
+# Updating Chromium
+
+Simply run `./pkgs/applications/networking/browsers/chromium/update.py` to
+update `upstream-info.json`. After updates it is important to test at least
+`nixosTests.chromium` (or basic manual testing) and `google-chrome` (which
+reuses `upstream-info.json`).
+
+Note: The source tarball is often only available a few hours after the release
+was announced. The CI/CD status can be tracked here:
+- https://ci.chromium.org/p/infra/builders/cron/publish_tarball
+- https://ci.chromium.org/p/infra/builders/cron/publish_tarball_dispatcher
+
+To run all automated NixOS VM tests for Chromium, ungoogled-chromium,
+and Google Chrome (not recommended, currently 6x tests!):
+```
+nix-build nixos/tests/chromium.nix
+```
+
+A single test can be selected, e.g. to test `ungoogled-chromium` (see
+`channelMap` in `nixos/tests/chromium.nix` for all available options):
+```
+nix-build nixos/tests/chromium.nix -A ungoogled
+```
+(Note: Testing Google Chrome requires `export NIXPKGS_ALLOW_UNFREE=1`.)
+
+For custom builds it's possible to "override" `channelMap`.
+
+## Backports
+
+All updates are considered security critical and should be ported to the stable
+channel ASAP. When there is a new stable release the old one should receive
+security updates for roughly one month. After that it is important to mark
+Chromium as insecure (see 69e4ae56c4b for an example; it is important that the
+tested job still succeeds and that all browsers that use `upstream-info.json`
+are marked as insecure).
+
+## Major version updates
+
+Unfortunately, Chromium regularly breaks on major updates and might need
+various patches. Either due to issues with the Nix build sandbox (e.g. we cannot
+fetch dependencies via the network and do not use standard FHS paths) or due to
+missing upstream fixes that need to be backported.
+
+Good sources for such patches and other hints:
+- https://github.com/archlinux/svntogit-packages/tree/packages/chromium/trunk
+- https://gitweb.gentoo.org/repo/gentoo.git/tree/www-client/chromium
+- https://src.fedoraproject.org/rpms/chromium/tree/master
+
+If the build fails immediately due to unknown compiler flags this usually means
+that a new major release of LLVM is required.
+
+## Beta and Dev channels
+
+Those channels are only used to test and fix builds in advance. They may be
+broken at times and must not delay stable channel updates.
+
+# Testing
+
+Useful tests:
+- Version: chrome://version/
+- GPU acceleration: chrome://gpu/
+- Essential functionality: Browsing, extensions, video+audio, JS, ...
+- WebGL: https://get.webgl.org/
+- VA-API: https://wiki.archlinux.org/index.php/chromium#Hardware_video_acceleration
+- Optional: Widevine CDM (proprietary), Benchmarks, Ozone, etc.
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix
new file mode 100644
index 000000000000..96729f1dcda6
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/browser.nix
@@ -0,0 +1,98 @@
+{ lib, mkChromiumDerivation
+, channel, chromiumVersionAtLeast
+, enableWideVine, ungoogled
+}:
+
+with lib;
+
+mkChromiumDerivation (base: rec {
+  name = "chromium-browser";
+  packageName = "chromium";
+  buildTargets = [ "mksnapshot" "chrome_sandbox" "chrome" ];
+
+  outputs = ["out" "sandbox"];
+
+  sandboxExecutableName = "__chromium-suid-sandbox";
+
+  installPhase = ''
+    mkdir -p "$libExecPath"
+    cp -v "$buildPath/"*.so "$buildPath/"*.pak "$buildPath/"*.bin "$libExecPath/"
+    cp -v "$buildPath/icudtl.dat" "$libExecPath/"
+    cp -vLR "$buildPath/locales" "$buildPath/resources" "$libExecPath/"
+    cp -v "$buildPath/chrome_crashpad_handler" "$libExecPath/"
+    cp -v "$buildPath/chrome" "$libExecPath/$packageName"
+
+    # Swiftshader
+    # See https://stackoverflow.com/a/4264351/263061 for the find invocation.
+    if [ -n "$(find "$buildPath/swiftshader/" -maxdepth 1 -name '*.so' -print -quit)" ]; then
+      echo "Swiftshader files found; installing"
+      mkdir -p "$libExecPath/swiftshader"
+      cp -v "$buildPath/swiftshader/"*.so "$libExecPath/swiftshader/"
+    else
+      echo "Swiftshader files not found"
+    fi
+
+    mkdir -p "$sandbox/bin"
+    cp -v "$buildPath/chrome_sandbox" "$sandbox/bin/${sandboxExecutableName}"
+
+    mkdir -vp "$out/share/man/man1"
+    cp -v "$buildPath/chrome.1" "$out/share/man/man1/$packageName.1"
+
+    for icon_file in chrome/app/theme/chromium/product_logo_*[0-9].png; do
+      num_and_suffix="''${icon_file##*logo_}"
+      icon_size="''${num_and_suffix%.*}"
+      expr "$icon_size" : "^[0-9][0-9]*$" || continue
+      logo_output_prefix="$out/share/icons/hicolor"
+      logo_output_path="$logo_output_prefix/''${icon_size}x''${icon_size}/apps"
+      mkdir -vp "$logo_output_path"
+      cp -v "$icon_file" "$logo_output_path/$packageName.png"
+    done
+
+    # Install Desktop Entry
+    install -D chrome/installer/linux/common/desktop.template \
+      $out/share/applications/chromium-browser.desktop
+
+    substituteInPlace $out/share/applications/chromium-browser.desktop \
+      --replace "@@MENUNAME@@" "Chromium" \
+      --replace "@@PACKAGE@@" "chromium" \
+      --replace "Exec=/usr/bin/@@USR_BIN_SYMLINK_NAME@@" "Exec=chromium"
+
+    # Append more mime types to the end
+    sed -i '/^MimeType=/ s,$,x-scheme-handler/webcal;x-scheme-handler/mailto;x-scheme-handler/about;x-scheme-handler/unknown,' \
+      $out/share/applications/chromium-browser.desktop
+
+    # See https://github.com/NixOS/nixpkgs/issues/12433
+    sed -i \
+      -e '/\[Desktop Entry\]/a\' \
+      -e 'StartupWMClass=chromium-browser' \
+      $out/share/applications/chromium-browser.desktop
+  '';
+
+  passthru = { inherit sandboxExecutableName; };
+
+  requiredSystemFeatures = [ "big-parallel" ];
+
+  meta = {
+    description = "An open source web browser from Google"
+      + optionalString ungoogled ", with dependencies on Google web services removed";
+    longDescription = ''
+      Chromium is an open source web browser from Google that aims to build a
+      safer, faster, and more stable way for all Internet users to experience
+      the web. It has a minimalist user interface and provides the vast majority
+      of source code for Google Chrome (which has some additional features).
+    '';
+    homepage = if ungoogled
+      then "https://github.com/Eloston/ungoogled-chromium"
+      else "https://www.chromium.org/";
+    maintainers = with maintainers; if ungoogled
+      then [ squalus primeos ]
+      else [ primeos thefloweringash ];
+    license = if enableWideVine then licenses.unfree else licenses.bsd3;
+    platforms = platforms.linux;
+    mainProgram = "chromium";
+    hydraPlatforms = if (channel == "stable" || channel == "ungoogled-chromium")
+      then ["aarch64-linux" "x86_64-linux"]
+      else [];
+    timeout = 172800; # 48 hours (increased from the Hydra default of 10h)
+  };
+})
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix
new file mode 100644
index 000000000000..4b7fbc38bbcc
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/common.nix
@@ -0,0 +1,357 @@
+{ stdenv, lib, fetchurl, fetchpatch
+# Channel data:
+, channel, upstream-info
+# Helper functions:
+, chromiumVersionAtLeast, versionRange
+
+# Native build inputs:
+, ninja, pkg-config
+, python2, python3, perl
+, gnutar, which
+, llvmPackages
+# postPatch:
+, pkgsBuildHost
+# configurePhase:
+, gnChromium
+
+# Build inputs:
+, libpng
+, bzip2, flac, speex, libopus
+, libevent, expat, libjpeg, snappy
+, libcap
+, xdg-utils, minizip, libwebp
+, libusb1, re2
+, ffmpeg, libxslt, libxml2
+, nasm
+, nspr, nss, systemd
+, util-linux, alsa-lib
+, bison, gperf, libkrb5
+, glib, gtk3, dbus-glib
+, libXScrnSaver, libXcursor, libXtst, libxshmfence, libGLU, libGL
+, mesa
+, pciutils, protobuf, speechd, libXdamage, at-spi2-core
+, pipewire
+, libva
+, libdrm, wayland, libxkbcommon # Ozone
+, curl
+# postPatch:
+, glibc # gconv + locale
+
+# Package customization:
+, gnomeSupport ? false, gnome2 ? null
+, gnomeKeyringSupport ? false, libgnome-keyring3 ? null
+, cupsSupport ? true, cups ? null
+, proprietaryCodecs ? true
+, pulseSupport ? false, libpulseaudio ? null
+, ungoogled ? false, ungoogled-chromium
+# Optional dependencies:
+, libgcrypt ? null # gnomeSupport || cupsSupport
+}:
+
+buildFun:
+
+with lib;
+
+let
+  python2WithPackages = python2.withPackages(ps: with ps; [
+    ply jinja2 setuptools
+  ]);
+  python3WithPackages = python3.withPackages(ps: with ps; [
+    ply jinja2 setuptools
+  ]);
+
+  # The additional attributes for creating derivations based on the chromium
+  # source tree.
+  extraAttrs = buildFun base;
+
+  githubPatch = { commit, sha256, revert ? false }: fetchpatch {
+    url = "https://github.com/chromium/chromium/commit/${commit}.patch";
+    inherit sha256 revert;
+  };
+
+  mkGnFlags =
+    let
+      # Serialize Nix types into GN types according to this document:
+      # https://source.chromium.org/gn/gn/+/master:docs/language.md
+      mkGnString = value: "\"${escape ["\"" "$" "\\"] value}\"";
+      sanitize = value:
+        if value == true then "true"
+        else if value == false then "false"
+        else if isList value then "[${concatMapStringsSep ", " sanitize value}]"
+        else if isInt value then toString value
+        else if isString value then mkGnString value
+        else throw "Unsupported type for GN value `${value}'.";
+      toFlag = key: value: "${key}=${sanitize value}";
+    in attrs: concatStringsSep " " (attrValues (mapAttrs toFlag attrs));
+
+  # https://source.chromium.org/chromium/chromium/src/+/master:build/linux/unbundle/replace_gn_files.py
+  gnSystemLibraries = lib.optionals (!chromiumVersionAtLeast "95") [
+    "zlib"
+  ] ++ [
+    # TODO:
+    # "ffmpeg"
+    # "snappy"
+    "flac"
+    "libjpeg"
+    "libpng"
+    "libwebp"
+    "libxslt"
+    "opus"
+  ];
+
+  opusWithCustomModes = libopus.override {
+    withCustomModes = true;
+  };
+
+  # build paths and release info
+  packageName = extraAttrs.packageName or extraAttrs.name;
+  buildType = "Release";
+  buildPath = "out/${buildType}";
+  libExecPath = "$out/libexec/${packageName}";
+
+  ungoogler = ungoogled-chromium {
+    inherit (upstream-info.deps.ungoogled-patches) rev sha256;
+  };
+
+  base = rec {
+    name = "${packageName}-unwrapped-${version}";
+    inherit (upstream-info) version;
+    inherit packageName buildType buildPath;
+
+    src = fetchurl {
+      url = "https://commondatastorage.googleapis.com/chromium-browser-official/chromium-${version}.tar.xz";
+      inherit (upstream-info) sha256;
+    };
+
+    nativeBuildInputs = [
+      ninja pkg-config
+      python2WithPackages python3WithPackages perl
+      gnutar which
+      llvmPackages.bintools
+    ];
+
+    buildInputs = [
+      (libpng.override { apngSupport = false; }) # https://bugs.chromium.org/p/chromium/issues/detail?id=752403
+      bzip2 flac speex opusWithCustomModes
+      libevent expat libjpeg snappy
+      libcap
+      xdg-utils minizip libwebp
+      libusb1 re2
+      ffmpeg libxslt libxml2
+      nasm
+      nspr nss systemd
+      util-linux alsa-lib
+      bison gperf libkrb5
+      glib gtk3 dbus-glib
+      libXScrnSaver libXcursor libXtst libxshmfence libGLU libGL
+      mesa # required for libgbm
+      pciutils protobuf speechd libXdamage at-spi2-core
+      pipewire
+      libva
+      libdrm wayland mesa.drivers libxkbcommon
+      curl
+    ] ++ optionals gnomeSupport [ gnome2.GConf libgcrypt ]
+      ++ optional gnomeKeyringSupport libgnome-keyring3
+      ++ optionals cupsSupport [ libgcrypt cups ]
+      ++ optional pulseSupport libpulseaudio;
+
+    patches = [
+      # Optional patch to use SOURCE_DATE_EPOCH in compute_build_timestamp.py (should be upstreamed):
+      ./patches/no-build-timestamps.patch
+      # For bundling Widevine (DRM), might be replaceable via bundle_widevine_cdm=true in gnFlags:
+      ./patches/widevine-79.patch
+    ];
+
+    postPatch = ''
+      # remove unused third-party
+      for lib in ${toString gnSystemLibraries}; do
+        if [ -d "third_party/$lib" ]; then
+          find "third_party/$lib" -type f \
+            \! -path "third_party/$lib/chromium/*" \
+            \! -path "third_party/$lib/google/*" \
+            \! -path "third_party/harfbuzz-ng/utils/hb_scoped.h" \
+            \! -regex '.*\.\(gn\|gni\|isolate\)' \
+            -delete
+        fi
+      done
+
+      # Required for patchShebangs (unsupported interpreter directive, basename: invalid option -- '*', etc.):
+      substituteInPlace native_client/SConstruct --replace "#! -*- python -*-" ""
+      if [ -e third_party/harfbuzz-ng/src/src/update-unicode-tables.make ]; then
+        substituteInPlace third_party/harfbuzz-ng/src/src/update-unicode-tables.make \
+          --replace "/usr/bin/env -S make -f" "/usr/bin/make -f"
+      fi
+      chmod -x third_party/webgpu-cts/src/tools/${lib.optionalString (chromiumVersionAtLeast "96") "run_"}deno
+
+      # We want to be able to specify where the sandbox is via CHROME_DEVEL_SANDBOX
+      substituteInPlace sandbox/linux/suid/client/setuid_sandbox_host.cc \
+        --replace \
+          'return sandbox_binary;' \
+          'return base::FilePath(GetDevelSandboxPath());'
+
+      substituteInPlace services/audio/audio_sandbox_hook_linux.cc \
+        --replace \
+          '/usr/share/alsa/' \
+          '${alsa-lib}/share/alsa/' \
+        --replace \
+          '/usr/lib/x86_64-linux-gnu/gconv/' \
+          '${glibc}/lib/gconv/' \
+        --replace \
+          '/usr/share/locale/' \
+          '${glibc}/share/locale/'
+
+      sed -i -e 's@"\(#!\)\?.*xdg-@"\1${xdg-utils}/bin/xdg-@' \
+        chrome/browser/shell_integration_linux.cc
+
+      sed -i -e '/lib_loader.*Load/s!"\(libudev\.so\)!"${lib.getLib systemd}/lib/\1!' \
+        device/udev_linux/udev?_loader.cc
+
+      sed -i -e '/libpci_loader.*Load/s!"\(libpci\.so\)!"${pciutils}/lib/\1!' \
+        gpu/config/gpu_info_collector_linux.cc
+
+      # Allow to put extensions into the system-path.
+      sed -i -e 's,/usr,/run/current-system/sw,' chrome/common/chrome_paths.cc
+
+      patchShebangs .
+      # Link to our own Node.js and Java (required during the build):
+      mkdir -p third_party/node/linux/node-linux-x64/bin
+      ln -s "${pkgsBuildHost.nodejs}/bin/node" third_party/node/linux/node-linux-x64/bin/node
+      ln -s "${pkgsBuildHost.jre8}/bin/java" third_party/jdk/current/bin/
+
+      # Allow building against system libraries in official builds
+      sed -i 's/OFFICIAL_BUILD/GOOGLE_CHROME_BUILD/' tools/generate_shim_headers/generate_shim_headers.py
+
+    '' + optionalString stdenv.isAarch64 ''
+      substituteInPlace build/toolchain/linux/BUILD.gn \
+        --replace 'toolprefix = "aarch64-linux-gnu-"' 'toolprefix = ""'
+    '' + optionalString ungoogled ''
+      ${ungoogler}/utils/prune_binaries.py . ${ungoogler}/pruning.list || echo "some errors"
+      ${ungoogler}/utils/patches.py . ${ungoogler}/patches
+      ${ungoogler}/utils/domain_substitution.py apply -r ${ungoogler}/domain_regex.list -f ${ungoogler}/domain_substitution.list -c ./ungoogled-domsubcache.tar.gz .
+    '';
+
+    gnFlags = mkGnFlags ({
+      # Main build and toolchain settings:
+      # Create an official and optimized release build (only official builds
+      # should be distributed to users, as non-official builds are intended for
+      # development and may not be configured appropriately for production,
+      # e.g. unsafe developer builds have developer-friendly features that may
+      # weaken or disable security measures like sandboxing or ASLR):
+      is_official_build = true;
+      disable_fieldtrial_testing_config = true;
+      # Build Chromium using the system toolchain (for Linux distributions):
+      custom_toolchain = "//build/toolchain/linux/unbundle:default";
+      host_toolchain = "//build/toolchain/linux/unbundle:default";
+      # Don't build against a sysroot image downloaded from Cloud Storage:
+      use_sysroot = false;
+      # The default value is hardcoded instead of using pkg-config:
+      system_wayland_scanner_path = "${wayland}/bin/wayland-scanner";
+      # Because we use a different toolchain / compiler version:
+      treat_warnings_as_errors = false;
+      # We aren't compiling with Chrome's Clang (would enable Chrome-specific
+      # plugins for enforcing coding guidelines, etc.):
+      clang_use_chrome_plugins = false;
+      # Disable symbols (they would negatively affect the performance of the
+      # build since the symbols are large and dealing with them is slow):
+      symbol_level = 0;
+      blink_symbol_level = 0;
+
+      # Google API key, see: https://www.chromium.org/developers/how-tos/api-keys
+      # Note: The API key is for NixOS/nixpkgs use ONLY.
+      # For your own distribution, please get your own set of keys.
+      google_api_key = "AIzaSyDGi15Zwl11UNe6Y-5XW_upsfyw31qwZPI";
+
+      # Optional features:
+      use_gio = gnomeSupport;
+      use_gnome_keyring = gnomeKeyringSupport;
+      use_cups = cupsSupport;
+
+      # Feature overrides:
+      # Native Client support was deprecated in 2020 and support will end in June 2021:
+      enable_nacl = false;
+      # Enabling the Widevine component here doesn't affect whether we can
+      # redistribute the chromium package; the Widevine component is either
+      # added later in the wrapped -wv build or downloaded from Google:
+      enable_widevine = true;
+      # Provides the enable-webrtc-pipewire-capturer flag to support Wayland screen capture:
+      rtc_use_pipewire = true;
+    } // optionalAttrs proprietaryCodecs {
+      # enable support for the H.264 codec
+      proprietary_codecs = true;
+      enable_hangout_services_extension = true;
+      ffmpeg_branding = "Chrome";
+    } // optionalAttrs pulseSupport {
+      use_pulseaudio = true;
+      link_pulseaudio = true;
+    } // optionalAttrs ungoogled {
+      chrome_pgo_phase = 0;
+      enable_hangout_services_extension = false;
+      enable_js_type_check = false;
+      enable_mdns = false;
+      enable_nacl_nonsfi = false;
+      enable_one_click_signin = false;
+      enable_reading_list = false;
+      enable_remoting = false;
+      enable_reporting = false;
+      enable_service_discovery = false;
+      exclude_unwind_tables = true;
+      google_api_key = "";
+      google_default_client_id = "";
+      google_default_client_secret = "";
+      safe_browsing_mode = 0;
+      use_official_google_api_keys = false;
+      use_unofficial_version_number = false;
+    } // (extraAttrs.gnFlags or {}));
+
+    configurePhase = ''
+      runHook preConfigure
+
+      # This is to ensure expansion of $out.
+      libExecPath="${libExecPath}"
+      ${python2}/bin/python2 build/linux/unbundle/replace_gn_files.py --system-libraries ${toString gnSystemLibraries}
+      ${gnChromium}/bin/gn gen --args=${escapeShellArg gnFlags} out/Release | tee gn-gen-outputs.txt
+
+      # Fail if `gn gen` contains a WARNING.
+      grep -o WARNING gn-gen-outputs.txt && echo "Found gn WARNING, exiting nix build" && exit 1
+
+      runHook postConfigure
+    '';
+
+    # Don't spam warnings about unknown warning options. This is useful because
+    # our Clang is always older than Chromium's and the build logs have a size
+    # of approx. 25 MB without this option (and this saves e.g. 66 %).
+    NIX_CFLAGS_COMPILE = "-Wno-unknown-warning-option";
+
+    buildPhase = let
+      buildCommand = target: ''
+        ninja -C "${buildPath}" -j$NIX_BUILD_CORES -l$NIX_BUILD_CORES "${target}"
+        (
+          source chrome/installer/linux/common/installer.include
+          PACKAGE=$packageName
+          MENUNAME="Chromium"
+          process_template chrome/app/resources/manpage.1.in "${buildPath}/chrome.1"
+        )
+      '';
+      targets = extraAttrs.buildTargets or [];
+      commands = map buildCommand targets;
+    in concatStringsSep "\n" commands;
+
+    postFixup = ''
+      # Make sure that libGLESv2 is found by dlopen (if using EGL).
+      chromiumBinary="$libExecPath/$packageName"
+      origRpath="$(patchelf --print-rpath "$chromiumBinary")"
+      patchelf --set-rpath "${libGL}/lib:$origRpath" "$chromiumBinary"
+    '';
+
+    passthru = {
+      updateScript = ./update.py;
+      chromiumDeps = {
+        gn = gnChromium;
+      };
+    };
+  };
+
+# Remove some extraAttrs we supplied to the base attributes already.
+in stdenv.mkDerivation (base // removeAttrs extraAttrs [
+  "name" "gnFlags" "buildTargets"
+] // { passthru = base.passthru // (extraAttrs.passthru or {}); })
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix
new file mode 100644
index 000000000000..c4521c89caa6
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/default.nix
@@ -0,0 +1,234 @@
+{ newScope, config, stdenv, fetchurl, makeWrapper
+, llvmPackages_13, ed, gnugrep, coreutils, xdg-utils
+, glib, gtk3, gnome, gsettings-desktop-schemas, gn, fetchgit
+, libva, pipewire, wayland
+, gcc, nspr, nss, runCommand
+, lib
+
+# package customization
+# Note: enable* flags should not require full rebuilds (i.e. only affect the wrapper)
+, channel ? "stable"
+, gnomeSupport ? false, gnome2 ? null
+, gnomeKeyringSupport ? false
+, proprietaryCodecs ? true
+, enableWideVine ? false
+, ungoogled ? false # Whether to build chromium or ungoogled-chromium
+, cupsSupport ? true
+, pulseSupport ? config.pulseaudio or stdenv.isLinux
+, commandLineArgs ? ""
+}:
+
+let
+  llvmPackages = llvmPackages_13;
+  stdenv = llvmPackages.stdenv;
+
+  upstream-info = (lib.importJSON ./upstream-info.json).${channel};
+
+  # Helper functions for changes that depend on specific versions:
+  warnObsoleteVersionConditional = min-version: result:
+    let ungoogled-version = (lib.importJSON ./upstream-info.json).ungoogled-chromium.version;
+    in lib.warnIf
+         (lib.versionAtLeast ungoogled-version min-version)
+         "chromium: ungoogled version ${ungoogled-version} is newer than a conditional bounded at ${min-version}. You can safely delete it."
+         result;
+  chromiumVersionAtLeast = min-version:
+    let result = lib.versionAtLeast upstream-info.version min-version;
+    in  warnObsoleteVersionConditional min-version result;
+  versionRange = min-version: upto-version:
+    let inherit (upstream-info) version;
+        result = lib.versionAtLeast version min-version && lib.versionOlder version upto-version;
+    in warnObsoleteVersionConditional upto-version result;
+
+  callPackage = newScope chromium;
+
+  chromium = rec {
+    inherit stdenv llvmPackages upstream-info;
+
+    mkChromiumDerivation = callPackage ./common.nix ({
+      inherit channel chromiumVersionAtLeast versionRange;
+      inherit gnome2 gnomeSupport gnomeKeyringSupport proprietaryCodecs
+              cupsSupport pulseSupport ungoogled;
+      gnChromium = gn.overrideAttrs (oldAttrs: {
+        inherit (upstream-info.deps.gn) version;
+        src = fetchgit {
+          inherit (upstream-info.deps.gn) url rev sha256;
+        };
+      });
+    });
+
+    browser = callPackage ./browser.nix {
+      inherit channel chromiumVersionAtLeast enableWideVine ungoogled;
+    };
+
+    ungoogled-chromium = callPackage ./ungoogled.nix {};
+  };
+
+  pkgSuffix = if channel == "dev" then "unstable" else
+    (if channel == "ungoogled-chromium" then "stable" else channel);
+  pkgName = "google-chrome-${pkgSuffix}";
+  chromeSrc =
+    let
+      # Use the latest stable Chrome version if necessary:
+      version = if chromium.upstream-info.sha256bin64 != null
+        then chromium.upstream-info.version
+        else (lib.importJSON ./upstream-info.json).stable.version;
+      sha256 = if chromium.upstream-info.sha256bin64 != null
+        then chromium.upstream-info.sha256bin64
+        else (lib.importJSON ./upstream-info.json).stable.sha256bin64;
+    in fetchurl {
+      urls = map (repo: "${repo}/${pkgName}/${pkgName}_${version}-1_amd64.deb") [
+        "https://dl.google.com/linux/chrome/deb/pool/main/g"
+        "http://95.31.35.30/chrome/pool/main/g"
+        "http://mirror.pcbeta.com/google/chrome/deb/pool/main/g"
+        "http://repo.fdzh.org/chrome/deb/pool/main/g"
+      ];
+      inherit sha256;
+  };
+
+  mkrpath = p: "${lib.makeSearchPathOutput "lib" "lib64" p}:${lib.makeLibraryPath p}";
+  widevineCdm = stdenv.mkDerivation {
+    name = "chrome-widevine-cdm";
+
+    src = chromeSrc;
+
+    unpackCmd = let
+      widevineCdmPath =
+        if (channel == "stable" || channel == "ungoogled-chromium") then
+          "./opt/google/chrome/WidevineCdm"
+        else if channel == "beta" then
+          "./opt/google/chrome-beta/WidevineCdm"
+        else if channel == "dev" then
+          "./opt/google/chrome-unstable/WidevineCdm"
+        else
+          throw "Unknown chromium channel.";
+    in ''
+      # Extract just WidevineCdm from upstream's .deb file
+      ar p "$src" data.tar.xz | tar xJ "${widevineCdmPath}"
+
+      # Move things around so that we don't have to reference a particular
+      # chrome-* directory later.
+      mv "${widevineCdmPath}" ./
+
+      # unpackCmd wants a single output directory; let it take WidevineCdm/
+      rm -rf opt
+    '';
+
+    doCheck = true;
+    checkPhase = ''
+      ! find -iname '*.so' -exec ldd {} + | grep 'not found'
+    '';
+
+    PATCH_RPATH = mkrpath [ gcc.cc glib nspr nss ];
+
+    patchPhase = ''
+      patchelf --set-rpath "$PATCH_RPATH" _platform_specific/linux_x64/libwidevinecdm.so
+    '';
+
+    installPhase = ''
+      mkdir -p $out/WidevineCdm
+      cp -a * $out/WidevineCdm/
+    '';
+
+    meta = {
+      platforms = [ "x86_64-linux" ];
+      license = lib.licenses.unfree;
+    };
+  };
+
+  suffix = if (channel == "stable" || channel == "ungoogled-chromium")
+    then ""
+    else "-" + channel;
+
+  sandboxExecutableName = chromium.browser.passthru.sandboxExecutableName;
+
+  version = chromium.browser.version;
+
+  # We want users to be able to enableWideVine without rebuilding all of
+  # chromium, so we have a separate derivation here that copies chromium
+  # and adds the unfree WidevineCdm.
+  chromiumWV = let browser = chromium.browser; in if enableWideVine then
+    runCommand (browser.name + "-wv") { version = browser.version; }
+      ''
+        mkdir -p $out
+        cp -a ${browser}/* $out/
+        chmod u+w $out/libexec/chromium
+        cp -a ${widevineCdm}/WidevineCdm $out/libexec/chromium/
+      ''
+    else browser;
+
+in stdenv.mkDerivation {
+  name = lib.optionalString ungoogled "ungoogled-"
+    + "chromium${suffix}-${version}";
+  inherit version;
+
+  nativeBuildInputs = [
+    makeWrapper ed
+  ];
+
+  buildInputs = [
+    # needed for GSETTINGS_SCHEMAS_PATH
+    gsettings-desktop-schemas glib gtk3
+
+    # needed for XDG_ICON_DIRS
+    gnome.adwaita-icon-theme
+  ];
+
+  outputs = ["out" "sandbox"];
+
+  buildCommand = let
+    browserBinary = "${chromiumWV}/libexec/chromium/chromium";
+    libPath = lib.makeLibraryPath [ libva pipewire wayland gtk3 ];
+
+  in with lib; ''
+    mkdir -p "$out/bin"
+
+    eval makeWrapper "${browserBinary}" "$out/bin/chromium" \
+      --add-flags ${escapeShellArg (escapeShellArg commandLineArgs)}
+
+    ed -v -s "$out/bin/chromium" << EOF
+    2i
+
+    if [ -x "/run/wrappers/bin/${sandboxExecutableName}" ]
+    then
+      export CHROME_DEVEL_SANDBOX="/run/wrappers/bin/${sandboxExecutableName}"
+    else
+      export CHROME_DEVEL_SANDBOX="$sandbox/bin/${sandboxExecutableName}"
+    fi
+
+  '' + lib.optionalString (libPath != "") ''
+    # To avoid loading .so files from cwd, LD_LIBRARY_PATH here must not
+    # contain an empty section before or after a colon.
+    export LD_LIBRARY_PATH="\$LD_LIBRARY_PATH\''${LD_LIBRARY_PATH:+:}${libPath}"
+  '' + ''
+
+    # libredirect causes chromium to deadlock on startup
+    export LD_PRELOAD="\$(echo -n "\$LD_PRELOAD" | ${coreutils}/bin/tr ':' '\n' | ${gnugrep}/bin/grep -v /lib/libredirect\\\\.so$ | ${coreutils}/bin/tr '\n' ':')"
+
+    export XDG_DATA_DIRS=$XDG_ICON_DIRS:$GSETTINGS_SCHEMAS_PATH\''${XDG_DATA_DIRS:+:}\$XDG_DATA_DIRS
+
+    # Mainly for xdg-open but also other xdg-* tools:
+    export PATH="${xdg-utils}/bin\''${PATH:+:}\$PATH"
+
+    .
+    w
+    EOF
+
+    ln -sv "${chromium.browser.sandbox}" "$sandbox"
+
+    ln -s "$out/bin/chromium" "$out/bin/chromium-browser"
+
+    mkdir -p "$out/share"
+    for f in '${chromium.browser}'/share/*; do # hello emacs */
+      ln -s -t "$out/share/" "$f"
+    done
+  '';
+
+  inherit (chromium.browser) packageName;
+  meta = chromium.browser.meta;
+  passthru = {
+    inherit (chromium) upstream-info browser;
+    mkDerivation = chromium.mkChromiumDerivation;
+    inherit chromeSrc sandboxExecutableName;
+    updateScript = ./update.py;
+  };
+}
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py b/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py
new file mode 100755
index 000000000000..b0fbe20db8ef
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/get-commit-message.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i python3 -p python3Packages.feedparser python3Packages.requests
+
+# This script prints the Git commit message for stable channel updates.
+# Usage: ./get-commit-message.py [version]
+
+import re
+import sys
+import textwrap
+
+from collections import OrderedDict
+
+import feedparser
+import requests
+
+feed = feedparser.parse('https://chromereleases.googleblog.com/feeds/posts/default')
+html_tags = re.compile(r'<[^>]+>')
+target_version = sys.argv[1] if len(sys.argv) == 2 else None
+
+for entry in feed.entries:
+    url = requests.get(entry.link).url.split('?')[0]
+    if entry.title != 'Stable Channel Update for Desktop':
+        if target_version and entry.title == '':
+            # Workaround for a special case (Chrome Releases bug?):
+            if not 'the-stable-channel-has-been-updated-to' in url:
+                continue
+        else:
+            continue
+    content = entry.content[0].value
+    content = html_tags.sub('', content)  # Remove any HTML tags
+    if re.search(r'Linux', content) is None:
+        continue
+    #print(url)  # For debugging purposes
+    version = re.search(r'\d+(\.\d+){3}', content).group(0)
+    if target_version:
+        if version != target_version:
+            continue
+    else:
+        print('chromium: TODO -> ' + version + '\n')
+    print(url)
+    if fixes := re.search(r'This update includes .+ security fixes\.', content).group(0):
+        zero_days = re.search(r'Google is aware( of reports)? that .+ in the wild\.', content)
+        if zero_days:
+            fixes += " " + zero_days.group(0)
+        print('\n' + '\n'.join(textwrap.wrap(fixes, width=72)))
+    if cve_list := re.findall(r'CVE-[^: ]+', content):
+        cve_list = list(OrderedDict.fromkeys(cve_list))  # Remove duplicates but preserve the order
+        cve_string = ' '.join(cve_list)
+        print("\nCVEs:\n" + '\n'.join(textwrap.wrap(cve_string, width=72)))
+    sys.exit(0)  # We only care about the most recent stable channel update
+
+print("Error: No match.")
+sys.exit(1)
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch
new file mode 100644
index 000000000000..6b788f43d29c
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/no-build-timestamps.patch
@@ -0,0 +1,17 @@
+--- chromium-70.0.3538.67/build/compute_build_timestamp.py.orig	2018-11-02 16:00:34.368933077 +0200
++++ chromium-70.0.3538.67/build/compute_build_timestamp.py	2018-11-08 04:06:21.658105129 +0200
+@@ -94,6 +94,14 @@
+       'build_type', help='The type of build', choices=('official', 'default'))
+   args = argument_parser.parse_args()
+ 
++  # I don't trust LASTCHANGE magic, and I definelly want something deterministic here
++  SOURCE_DATE_EPOCH = os.getenv("SOURCE_DATE_EPOCH", None)
++  if SOURCE_DATE_EPOCH is not None:
++    print(SOURCE_DATE_EPOCH)
++    return 0
++  else:
++    raise RuntimeError("SOURCE_DATE_EPOCH not set")
++
+   # The mtime of the revision in build/util/LASTCHANGE is stored in a file
+   # next to it. Read it, to get a deterministic time close to "now".
+   # That date is then modified as described at the top of the file so that
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch
new file mode 100644
index 000000000000..32f0ae2fb5e6
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/patches/widevine-79.patch
@@ -0,0 +1,13 @@
+diff --git a/third_party/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn
+index ed0e2f5208b..5b431a030d5 100644
+--- a/third_party/widevine/cdm/BUILD.gn
++++ b/third_party/widevine/cdm/BUILD.gn
+@@ -14,7 +14,7 @@ buildflag_header("buildflags") {
+ 
+   flags = [
+     "ENABLE_WIDEVINE=$enable_widevine",
+-    "BUNDLE_WIDEVINE_CDM=$bundle_widevine_cdm",
++    "BUNDLE_WIDEVINE_CDM=true",
+     "ENABLE_WIDEVINE_CDM_COMPONENT=$enable_widevine_cdm_component",
+   ]
+ }
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix b/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix
new file mode 100644
index 000000000000..a8e84dae196d
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/ungoogled.nix
@@ -0,0 +1,43 @@
+{ stdenv
+, fetchFromGitHub
+, python3Packages
+, makeWrapper
+, patch
+}:
+
+{ rev
+, sha256
+}:
+
+stdenv.mkDerivation rec {
+  pname = "ungoogled-chromium";
+
+  version = rev;
+
+  src = fetchFromGitHub {
+    owner = "Eloston";
+    repo = "ungoogled-chromium";
+    inherit rev sha256;
+  };
+
+  dontBuild = true;
+
+  buildInputs = [
+    python3Packages.python
+    patch
+  ];
+
+  nativeBuildInputs = [
+    makeWrapper
+  ];
+
+  patchPhase = ''
+    sed -i '/chromium-widevine/d' patches/series
+  '';
+
+  installPhase = ''
+    mkdir $out
+    cp -R * $out/
+    wrapProgram $out/utils/patches.py --add-flags "apply" --prefix PATH : "${patch}/bin"
+  '';
+}
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py b/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py
new file mode 100755
index 000000000000..72d6df055b38
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/update.py
@@ -0,0 +1,233 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i python -p python3 nix nix-prefetch-git
+
+"""This script automatically updates chromium, google-chrome, chromedriver, and ungoogled-chromium
+via upstream-info.json."""
+# Usage: ./update.py [--commit]
+
+import csv
+import json
+import re
+import subprocess
+import sys
+
+from codecs import iterdecode
+from collections import OrderedDict
+from datetime import datetime
+from distutils.version import LooseVersion
+from os.path import abspath, dirname
+from urllib.request import urlopen
+
+HISTORY_URL = 'https://omahaproxy.appspot.com/history?os=linux'
+DEB_URL = 'https://dl.google.com/linux/chrome/deb/pool/main/g'
+BUCKET_URL = 'https://commondatastorage.googleapis.com/chromium-browser-official'
+
+JSON_PATH = dirname(abspath(__file__)) + '/upstream-info.json'
+COMMIT_MESSAGE_SCRIPT = dirname(abspath(__file__)) + '/get-commit-message.py'
+
+
+def load_json(path):
+    """Loads the given JSON file."""
+    with open(path, 'r') as f:
+        return json.load(f)
+
+
+def nix_prefetch_url(url, algo='sha256'):
+    """Prefetches the content of the given URL."""
+    print(f'nix-prefetch-url {url}')
+    out = subprocess.check_output(['nix-prefetch-url', '--type', algo, url])
+    return out.decode('utf-8').rstrip()
+
+
+def nix_prefetch_git(url, rev):
+    """Prefetches the requested Git revision of the given repository URL."""
+    print(f'nix-prefetch-git {url} {rev}')
+    out = subprocess.check_output(['nix-prefetch-git', '--quiet', '--url', url, '--rev', rev])
+    return json.loads(out)
+
+
+def get_file_revision(revision, file_path):
+    """Fetches the requested Git revision of the given Chromium file."""
+    url = f'https://raw.githubusercontent.com/chromium/chromium/{revision}/{file_path}'
+    with urlopen(url) as http_response:
+        return http_response.read()
+
+
+def get_matching_chromedriver(version):
+    """Gets the matching chromedriver version for the given Chromium version."""
+    # See https://chromedriver.chromium.org/downloads/version-selection
+    build = re.sub('.[0-9]+$', '', version)
+    chromedriver_version_url = f'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_{build}'
+    with urlopen(chromedriver_version_url) as http_response:
+        chromedriver_version = http_response.read().decode()
+        def get_chromedriver_url(system):
+            return ('https://chromedriver.storage.googleapis.com/' +
+                    f'{chromedriver_version}/chromedriver_{system}.zip')
+        return {
+            'version': chromedriver_version,
+            'sha256_linux': nix_prefetch_url(get_chromedriver_url('linux64')),
+            'sha256_darwin': nix_prefetch_url(get_chromedriver_url('mac64'))
+        }
+
+
+def get_channel_dependencies(version):
+    """Gets all dependencies for the given Chromium version."""
+    deps = get_file_revision(version, 'DEPS')
+    gn_pattern = b"'gn_version': 'git_revision:([0-9a-f]{40})'"
+    gn_commit = re.search(gn_pattern, deps).group(1).decode()
+    gn = nix_prefetch_git('https://gn.googlesource.com/gn', gn_commit)
+    return {
+        'gn': {
+            'version': datetime.fromisoformat(gn['date']).date().isoformat(),
+            'url': gn['url'],
+            'rev': gn['rev'],
+            'sha256': gn['sha256']
+        }
+    }
+
+
+def get_latest_ungoogled_chromium_tag():
+    """Returns the latest ungoogled-chromium tag using the GitHub API."""
+    api_tag_url = 'https://api.github.com/repos/Eloston/ungoogled-chromium/tags?per_page=1'
+    with urlopen(api_tag_url) as http_response:
+        tag_data = json.load(http_response)
+        return tag_data[0]['name']
+
+
+def get_latest_ungoogled_chromium_build():
+    """Returns a dictionary for the latest ungoogled-chromium build."""
+    tag = get_latest_ungoogled_chromium_tag()
+    version = tag.split('-')[0]
+    return {
+        'channel': 'ungoogled-chromium',
+        'version': version,
+        'ungoogled_tag': tag
+    }
+
+
+def channel_name_to_attr_name(channel_name):
+    """Maps a channel name to the corresponding main Nixpkgs attribute name."""
+    if channel_name == 'stable':
+        return 'chromium'
+    if channel_name == 'beta':
+        return 'chromiumBeta'
+    if channel_name == 'dev':
+        return 'chromiumDev'
+    if channel_name == 'ungoogled-chromium':
+        return 'ungoogled-chromium'
+    print(f'Error: Unexpected channel: {channel_name}', file=sys.stderr)
+    sys.exit(1)
+
+
+def get_channel_key(item):
+    """Orders Chromium channels by their name."""
+    channel_name = item[0]
+    if channel_name == 'stable':
+        return 0
+    if channel_name == 'beta':
+        return 1
+    if channel_name == 'dev':
+        return 2
+    if channel_name == 'ungoogled-chromium':
+        return 3
+    print(f'Error: Unexpected channel: {channel_name}', file=sys.stderr)
+    sys.exit(1)
+
+
+def print_updates(channels_old, channels_new):
+    """Print a summary of the updates."""
+    print('Updates:')
+    for channel_name in channels_old:
+        version_old = channels_old[channel_name]["version"]
+        version_new = channels_new[channel_name]["version"]
+        if LooseVersion(version_old) < LooseVersion(version_new):
+            attr_name = channel_name_to_attr_name(channel_name)
+            print(f'- {attr_name}: {version_old} -> {version_new}')
+
+
+channels = {}
+last_channels = load_json(JSON_PATH)
+
+
+print(f'GET {HISTORY_URL}', file=sys.stderr)
+with urlopen(HISTORY_URL) as resp:
+    builds = csv.DictReader(iterdecode(resp, 'utf-8'))
+    builds = list(builds)
+    builds.append(get_latest_ungoogled_chromium_build())
+    for build in builds:
+        channel_name = build['channel']
+
+        # If we've already found a newer build for this channel, we're
+        # no longer interested in it.
+        if channel_name in channels:
+            continue
+
+        # If we're back at the last build we used, we don't need to
+        # keep going -- there's no new version available, and we can
+        # just reuse the info from last time.
+        if build['version'] == last_channels[channel_name]['version']:
+            channels[channel_name] = last_channels[channel_name]
+            continue
+
+        channel = {'version': build['version']}
+        if channel_name == 'dev':
+            google_chrome_suffix = 'unstable'
+        elif channel_name == 'ungoogled-chromium':
+            google_chrome_suffix = 'stable'
+        else:
+            google_chrome_suffix = channel_name
+
+        try:
+            channel['sha256'] = nix_prefetch_url(f'{BUCKET_URL}/chromium-{build["version"]}.tar.xz')
+            channel['sha256bin64'] = nix_prefetch_url(
+                f'{DEB_URL}/google-chrome-{google_chrome_suffix}/' +
+                f'google-chrome-{google_chrome_suffix}_{build["version"]}-1_amd64.deb')
+        except subprocess.CalledProcessError:
+            if (channel_name == 'ungoogled-chromium' and 'sha256' in channel and
+                    build['version'].split('.')[0] == last_channels['stable']['version'].split('.')[0]):
+                # Sometimes ungoogled-chromium is updated to a newer tag than
+                # the latest stable Chromium version. In this case we'll set
+                # sha256bin64 to null and the Nixpkgs code will fall back to
+                # the latest stable Google Chrome (only required for
+                # Widevine/DRM which is disabled by default):
+                channel['sha256bin64'] = None
+            else:
+                # This build isn't actually available yet.  Continue to
+                # the next one.
+                continue
+
+        channel['deps'] = get_channel_dependencies(channel['version'])
+        if channel_name == 'stable':
+            channel['chromedriver'] = get_matching_chromedriver(channel['version'])
+        elif channel_name == 'ungoogled-chromium':
+            ungoogled_repo_url = 'https://github.com/Eloston/ungoogled-chromium.git'
+            channel['deps']['ungoogled-patches'] = {
+                'rev': build['ungoogled_tag'],
+                'sha256': nix_prefetch_git(ungoogled_repo_url, build['ungoogled_tag'])['sha256']
+            }
+
+        channels[channel_name] = channel
+
+
+sorted_channels = OrderedDict(sorted(channels.items(), key=get_channel_key))
+if len(sys.argv) == 2 and sys.argv[1] == '--commit':
+    for channel_name in sorted_channels.keys():
+        version_old = last_channels[channel_name]['version']
+        version_new = sorted_channels[channel_name]['version']
+        if LooseVersion(version_old) < LooseVersion(version_new):
+            last_channels[channel_name] = sorted_channels[channel_name]
+            with open(JSON_PATH, 'w') as out:
+                json.dump(last_channels, out, indent=2)
+                out.write('\n')
+            attr_name = channel_name_to_attr_name(channel_name)
+            commit_message = f'{attr_name}: {version_old} -> {version_new}'
+            if channel_name == 'stable':
+                body = subprocess.check_output([COMMIT_MESSAGE_SCRIPT, version_new]).decode('utf-8')
+                commit_message += '\n\n' + body
+            subprocess.run(['git', 'add', JSON_PATH], check=True)
+            subprocess.run(['git', 'commit', '--file=-'], input=commit_message.encode(), check=True)
+else:
+    with open(JSON_PATH, 'w') as out:
+        json.dump(sorted_channels, out, indent=2)
+        out.write('\n')
+    print_updates(last_channels, sorted_channels)
diff --git a/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json b/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json
new file mode 100644
index 000000000000..d7f29c4fefa2
--- /dev/null
+++ b/nixpkgs/pkgs/applications/networking/browsers/chromium/upstream-info.json
@@ -0,0 +1,63 @@
+{
+  "stable": {
+    "version": "94.0.4606.61",
+    "sha256": "1gxrxmd2almwf067zycilyxkmc0d62h99ln8wp3n3i02bi9xnik4",
+    "sha256bin64": "116xrf8hcprbdpdx6a4xysac2phyvw88vs3n1bs24ly6pxydsasz",
+    "deps": {
+      "gn": {
+        "version": "2021-08-11",
+        "url": "https://gn.googlesource.com/gn",
+        "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263",
+        "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0"
+      }
+    },
+    "chromedriver": {
+      "version": "94.0.4606.41",
+      "sha256_linux": "06flgis4am4jmd9qz6yn1jfdr07w2n3mfrlicw6a9icg5ir64fdq",
+      "sha256_darwin": "1mc0hhksqm5ms4k4aji043xzxncbifjwz5fqzywy4ji64w5kqrca"
+    }
+  },
+  "beta": {
+    "version": "95.0.4638.17",
+    "sha256": "1v5r8m3wlwh6prcj7bd4zprsr4g43869lhxv43m207c5nlnqiriz",
+    "sha256bin64": "0h88gd8y4i2jmvhiwadbq6hzqygddym8jy1fhzp8qnwfhc30qm4m",
+    "deps": {
+      "gn": {
+        "version": "2021-08-11",
+        "url": "https://gn.googlesource.com/gn",
+        "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263",
+        "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0"
+      }
+    }
+  },
+  "dev": {
+    "version": "96.0.4651.0",
+    "sha256": "0da1mhz3cy0k2igdh208i28k8fxca0yjfypvmj7624p7igrp4an6",
+    "sha256bin64": "1gslpdnpjp7w40lsl748rmbkbs31v22f2x45gahrijkvfrkgdqp9",
+    "deps": {
+      "gn": {
+        "version": "2021-08-11",
+        "url": "https://gn.googlesource.com/gn",
+        "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263",
+        "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0"
+      }
+    }
+  },
+  "ungoogled-chromium": {
+    "version": "94.0.4606.54",
+    "sha256": "0p8kfnyhykbv1cylsx4hj2qdzqr2xdql9rhpva8bfla2w9hr8g83",
+    "sha256bin64": "0lq34l00zrr92g882xzqwq1lf2vf12x1mwidrr2qh6fz7v5418d3",
+    "deps": {
+      "gn": {
+        "version": "2021-08-11",
+        "url": "https://gn.googlesource.com/gn",
+        "rev": "69ec4fca1fa69ddadae13f9e6b7507efa0675263",
+        "sha256": "031znmkbm504iim5jvg3gmazj4qnkfc7zg8aymjsij18fhf7piz0"
+      },
+      "ungoogled-patches": {
+        "rev": "94.0.4606.54-1",
+        "sha256": "0phy87fiqdgikgl60yap7n1mvyvsidgznqp06j86287iihml3z2m"
+      }
+    }
+  }
+}