{"diffoscope-json-version": 1, "source1": "/srv/reproducible-results/rbuild-debian/r-b-build.Fe8T220W/b1/jupyterhub_5.2.1+ds1-4_amd64.changes", "source2": "/srv/reproducible-results/rbuild-debian/r-b-build.Fe8T220W/b2/jupyterhub_5.2.1+ds1-4_amd64.changes", "unified_diff": null, "details": [{"source1": "Files", "source2": "Files", "unified_diff": "@@ -1,2 +1,2 @@\n \n- ad17678dc07a20c6f72edba3214a67b0 2021932 python optional jupyterhub_5.2.1+ds1-4_all.deb\n+ 2eeaf96bdbe8d65c739320510a5eb956 2022496 python optional jupyterhub_5.2.1+ds1-4_all.deb\n"}, {"source1": "jupyterhub_5.2.1+ds1-4_all.deb", "source2": "jupyterhub_5.2.1+ds1-4_all.deb", "unified_diff": null, "details": [{"source1": "file list", "source2": "file list", "unified_diff": "@@ -1,3 +1,3 @@\n -rw-r--r-- 0 0 0 4 2025-05-28 09:40:25.000000 debian-binary\n--rw-r--r-- 0 0 0 59492 2025-05-28 09:40:25.000000 control.tar.xz\n--rw-r--r-- 0 0 0 1962248 2025-05-28 09:40:25.000000 data.tar.xz\n+-rw-r--r-- 0 0 0 59496 2025-05-28 09:40:25.000000 control.tar.xz\n+-rw-r--r-- 0 0 0 1962808 2025-05-28 09:40:25.000000 data.tar.xz\n"}, {"source1": "control.tar.xz", "source2": "control.tar.xz", "unified_diff": null, "details": [{"source1": "control.tar", "source2": "control.tar", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "unified_diff": null, "details": [{"source1": "./md5sums", "source2": "./md5sums", "comments": ["Files differ"], "unified_diff": null}]}]}]}, {"source1": "data.tar.xz", "source2": "data.tar.xz", "unified_diff": null, "details": [{"source1": "data.tar", "source2": "data.tar", "unified_diff": null, "details": [{"source1": "./usr/share/jupyterhub/jupyterhub_config.py", "source2": "./usr/share/jupyterhub/jupyterhub_config.py", "unified_diff": "@@ -997,14 +997,842 @@\n # \n # It should return the new URL to redirect to, or None to preserve current\n # behavior.\n # Default: None\n # c.JupyterHub.user_redirect_hook = None\n \n #------------------------------------------------------------------------------\n+# Spawner(LoggingConfigurable) configuration\n+#------------------------------------------------------------------------------\n+## Base class for spawning single-user notebook servers.\n+# \n+# Subclass this, and override the following methods:\n+# \n+# - load_state - get_state - start - stop - poll\n+# \n+# As JupyterHub supports multiple users, an instance of the Spawner subclass is\n+# created for each user. If there are 20 JupyterHub users, there will be 20\n+# instances of the subclass.\n+\n+## Extra arguments to be passed to the single-user server.\n+# \n+# Some spawners allow shell-style expansion here, allowing you to use\n+# environment variables here. Most, including the default, do not. Consult the\n+# documentation for your spawner to verify!\n+# Default: []\n+# c.Spawner.args = []\n+\n+## An optional hook function that you can implement to pass `auth_state` to the\n+# spawner after it has been initialized but before it starts. The `auth_state`\n+# dictionary may be set by the `.authenticate()` method of the authenticator.\n+# This hook enables you to pass some or all of that information to your spawner.\n+# \n+# Example::\n+# \n+# def userdata_hook(spawner, auth_state):\n+# spawner.userdata = auth_state[\"userdata\"]\n+# \n+# c.Spawner.auth_state_hook = userdata_hook\n+# Default: None\n+# c.Spawner.auth_state_hook = None\n+\n+## The command used for starting the single-user server.\n+# \n+# Provide either a string or a list containing the path to the startup script\n+# command. Extra arguments, other than this path, should be provided via `args`.\n+# \n+# This is usually set if you want to start the single-user server in a different\n+# python environment (with virtualenv/conda) than JupyterHub itself.\n+# \n+# Some spawners allow shell-style expansion here, allowing you to use\n+# environment variables. Most, including the default, do not. Consult the\n+# documentation for your spawner to verify!\n+# Default: ['jupyterhub-singleuser']\n+# c.Spawner.cmd = ['jupyterhub-singleuser']\n+\n+## Maximum number of consecutive failures to allow before shutting down\n+# JupyterHub.\n+# \n+# This helps JupyterHub recover from a certain class of problem preventing\n+# launch in contexts where the Hub is automatically restarted (e.g. systemd,\n+# docker, kubernetes).\n+# \n+# A limit of 0 means no limit and consecutive failures will not be tracked.\n+# Default: 0\n+# c.Spawner.consecutive_failure_limit = 0\n+\n+## Minimum number of cpu-cores a single-user notebook server is guaranteed to\n+# have available.\n+# \n+# If this value is set to 0.5, allows use of 50% of one CPU. If this value is\n+# set to 2, allows use of up to 2 CPUs.\n+# \n+# **This is a configuration setting. Your spawner must implement support for the\n+# limit to work.** The default spawner, `LocalProcessSpawner`, does **not**\n+# implement this support. A custom spawner **must** add support for this setting\n+# for it to be enforced.\n+# Default: None\n+# c.Spawner.cpu_guarantee = None\n+\n+## Maximum number of cpu-cores a single-user notebook server is allowed to use.\n+# \n+# If this value is set to 0.5, allows use of 50% of one CPU. If this value is\n+# set to 2, allows use of up to 2 CPUs.\n+# \n+# The single-user notebook server will never be scheduled by the kernel to use\n+# more cpu-cores than this. There is no guarantee that it can access this many\n+# cpu-cores.\n+# \n+# **This is a configuration setting. Your spawner must implement support for the\n+# limit to work.** The default spawner, `LocalProcessSpawner`, does **not**\n+# implement this support. A custom spawner **must** add support for this setting\n+# for it to be enforced.\n+# Default: None\n+# c.Spawner.cpu_limit = None\n+\n+## Enable debug-logging of the single-user server\n+# Default: False\n+# c.Spawner.debug = False\n+\n+## The URL the single-user server should start in.\n+# \n+# `{username}` will be expanded to the user's username\n+# \n+# Example uses:\n+# \n+# - You can set `notebook_dir` to `/` and `default_url` to `/tree/home/{username}` to allow people to\n+# navigate the whole filesystem from their notebook server, but still start in their home directory.\n+# - Start with `/notebooks` instead of `/tree` if `default_url` points to a notebook instead of a directory.\n+# - You can set this to `/lab` to have JupyterLab start by default, rather than Jupyter Notebook.\n+# Default: ''\n+# c.Spawner.default_url = ''\n+\n+## Disable per-user configuration of single-user servers.\n+# \n+# When starting the user's single-user server, any config file found in the\n+# user's $HOME directory will be ignored.\n+# \n+# Note: a user could circumvent this if the user modifies their Python\n+# environment, such as when they have their own conda environments / virtualenvs\n+# / containers.\n+# Default: False\n+# c.Spawner.disable_user_config = False\n+\n+## List of environment variables for the single-user server to inherit from the\n+# JupyterHub process.\n+# \n+# This list is used to ensure that sensitive information in the JupyterHub\n+# process's environment (such as `CONFIGPROXY_AUTH_TOKEN`) is not passed to the\n+# single-user server's process.\n+# Default: ['JUPYTERHUB_SINGLEUSER_APP']\n+# c.Spawner.env_keep = ['JUPYTERHUB_SINGLEUSER_APP']\n+\n+## Extra environment variables to set for the single-user server's process.\n+# \n+# Environment variables that end up in the single-user server's process come from 3 sources:\n+# - This `environment` configurable\n+# - The JupyterHub process' environment variables that are listed in `env_keep`\n+# - Variables to establish contact between the single-user notebook and the hub (such as JUPYTERHUB_API_TOKEN)\n+# \n+# The `environment` configurable should be set by JupyterHub administrators to\n+# add installation specific environment variables. It is a dict where the key is\n+# the name of the environment variable, and the value can be a string or a\n+# callable. If it is a callable, it will be called with one parameter (the\n+# spawner instance), and should return a string fairly quickly (no blocking\n+# operations please!).\n+# \n+# Note that the spawner class' interface is not guaranteed to be exactly same\n+# across upgrades, so if you are using the callable take care to verify it\n+# continues to work after upgrades!\n+# \n+# .. versionchanged:: 1.2\n+# environment from this configuration has highest priority,\n+# allowing override of 'default' env variables,\n+# such as JUPYTERHUB_API_URL.\n+# Default: {}\n+# c.Spawner.environment = {}\n+\n+## Override specific traitlets based on group membership of the user.\n+# \n+# This can be a dict, or a callable that returns a dict. The keys of the dict\n+# are *only* used for lexicographical sorting, to guarantee consistent ordering\n+# of the overrides. If it is a callable, it may be async, and will be passed one\n+# parameter - the spawner instance. It should return a dictionary.\n+# \n+# The values of the dict are dicts with the following keys:\n+# \n+# - `\"groups\"` - If the user belongs to *any* of these groups, these overrides are\n+# applied to their server before spawning.\n+# - `\"spawner_override\"` - a dictionary with overrides to apply to the Spawner\n+# settings. Each value can be either the final value to change or a callable that\n+# take the `Spawner` instance as parameter and returns the final value.\n+# If the traitlet being overriden is a *dictionary*, the dictionary\n+# will be *recursively updated*, rather than overriden. If you want to\n+# remove a key, set its value to `None`.\n+# \n+# Example:\n+# \n+# The following example config will:\n+# \n+# 1. Add the environment variable \"AM_I_GROUP_ALPHA\" to everyone in the \"group-alpha\" group\n+# 2. Add the environment variable \"AM_I_GROUP_BETA\" to everyone in the \"group-beta\" group.\n+# If a user is part of both \"group-beta\" and \"group-alpha\", they will get *both* these env\n+# vars, due to the dictionary merging functionality.\n+# 3. Add a higher memory limit for everyone in the \"group-beta\" group.\n+# \n+# ::\n+# \n+# c.Spawner.group_overrides = {\n+# \"01-group-alpha-env-add\": {\n+# \"groups\": [\"group-alpha\"],\n+# \"spawner_override\": {\"environment\": {\"AM_I_GROUP_ALPHA\": \"yes\"}},\n+# },\n+# \"02-group-beta-env-add\": {\n+# \"groups\": [\"group-beta\"],\n+# \"spawner_override\": {\"environment\": {\"AM_I_GROUP_BETA\": \"yes\"}},\n+# },\n+# \"03-group-beta-mem-limit\": {\n+# \"groups\": [\"group-beta\"],\n+# \"spawner_override\": {\"mem_limit\": \"2G\"}\n+# }\n+# }\n+# Default: traitlets.Undefined\n+# c.Spawner.group_overrides = traitlets.Undefined\n+\n+## Timeout (in seconds) before giving up on a spawned HTTP server\n+# \n+# Once a server has successfully been spawned, this is the amount of time we\n+# wait before assuming that the server is unable to accept connections.\n+# Default: 30\n+# c.Spawner.http_timeout = 30\n+\n+## The URL the single-user server should connect to the Hub.\n+# \n+# If the Hub URL set in your JupyterHub config is not reachable from spawned\n+# notebooks, you can set differnt URL by this config.\n+# \n+# Is None if you don't need to change the URL.\n+# Default: None\n+# c.Spawner.hub_connect_url = None\n+\n+## The IP address (or hostname) the single-user server should listen on.\n+# \n+# Usually either '127.0.0.1' (default) or '0.0.0.0'.\n+# \n+# The JupyterHub proxy implementation should be able to send packets to this\n+# interface.\n+# \n+# Subclasses which launch remotely or in containers should override the default\n+# to '0.0.0.0'.\n+# \n+# .. versionchanged:: 2.0\n+# Default changed to '127.0.0.1', from ''.\n+# In most cases, this does not result in a change in behavior,\n+# as '' was interpreted as 'unspecified',\n+# which used the subprocesses' own default, itself usually '127.0.0.1'.\n+# Default: '127.0.0.1'\n+# c.Spawner.ip = '127.0.0.1'\n+\n+## Minimum number of bytes a single-user notebook server is guaranteed to have\n+# available.\n+# \n+# Allows the following suffixes:\n+# - K -> Kilobytes\n+# - M -> Megabytes\n+# - G -> Gigabytes\n+# - T -> Terabytes\n+# \n+# **This is a configuration setting. Your spawner must implement support for the\n+# limit to work.** The default spawner, `LocalProcessSpawner`, does **not**\n+# implement this support. A custom spawner **must** add support for this setting\n+# for it to be enforced.\n+# Default: None\n+# c.Spawner.mem_guarantee = None\n+\n+## Maximum number of bytes a single-user notebook server is allowed to use.\n+# \n+# Allows the following suffixes:\n+# - K -> Kilobytes\n+# - M -> Megabytes\n+# - G -> Gigabytes\n+# - T -> Terabytes\n+# \n+# If the single user server tries to allocate more memory than this, it will\n+# fail. There is no guarantee that the single-user notebook server will be able\n+# to allocate this much memory - only that it can not allocate more than this.\n+# \n+# **This is a configuration setting. Your spawner must implement support for the\n+# limit to work.** The default spawner, `LocalProcessSpawner`, does **not**\n+# implement this support. A custom spawner **must** add support for this setting\n+# for it to be enforced.\n+# Default: None\n+# c.Spawner.mem_limit = None\n+\n+## Path to the notebook directory for the single-user server.\n+# \n+# The user sees a file listing of this directory when the notebook interface is\n+# started. The current interface does not easily allow browsing beyond the\n+# subdirectories in this directory's tree.\n+# \n+# `~` will be expanded to the home directory of the user, and {username} will be\n+# replaced with the name of the user.\n+# \n+# Note that this does *not* prevent users from accessing files outside of this\n+# path! They can do so with many other means.\n+# Default: ''\n+# c.Spawner.notebook_dir = ''\n+\n+## Allowed scopes for oauth tokens issued by this server's oauth client.\n+# \n+# This sets the maximum and default scopes\n+# assigned to oauth tokens issued by a single-user server's\n+# oauth client (i.e. tokens stored in browsers after authenticating with the server),\n+# defining what actions the server can take on behalf of logged-in users.\n+# \n+# Default is an empty list, meaning minimal permissions to identify users,\n+# no actions can be taken on their behalf.\n+# \n+# If callable, will be called with the Spawner as a single argument.\n+# Callables may be async.\n+# Default: traitlets.Undefined\n+# c.Spawner.oauth_client_allowed_scopes = traitlets.Undefined\n+\n+## Allowed roles for oauth tokens.\n+# \n+# Deprecated in 3.0: use oauth_client_allowed_scopes\n+# \n+# This sets the maximum and default roles\n+# assigned to oauth tokens issued by a single-user server's\n+# oauth client (i.e. tokens stored in browsers after authenticating with the server),\n+# defining what actions the server can take on behalf of logged-in users.\n+# \n+# Default is an empty list, meaning minimal permissions to identify users,\n+# no actions can be taken on their behalf.\n+# Default: traitlets.Undefined\n+# c.Spawner.oauth_roles = traitlets.Undefined\n+\n+## An HTML form for options a user can specify on launching their server.\n+# \n+# The surrounding `