Releases: lsst-sqre/gafaelfawr
Releases · lsst-sqre/gafaelfawr
12.1.0
New features
- Add support for
client_secret_basic
to the token endpoint for the OpenID Connect server. This is the recommended default authentication strategy and some clients don't support negotiatingclient_secret_post
instead. - Add a
config.baseInternalUrl
Helm setting to override Gafaelfawr's understanding of its own internal URL, used when constructingIngress
resources fromGafaelfawrIngress
. - Gafaelfawr now adds the
app.kubernetes.io/managed-by
label with valueGafaelfawr
to allIngress
resources generated fromGafaelfawrIngress
resources. - Separate
auth
metrics intoauth_bot
andauth_user
metrics, where the former are authentications to services from bot users and the latter are authentications from non-bot users. Stop excluding mobu bot users now that they can be included in theauth_bot
metric instead.
What's Changed
- DM-47011: Document config.baseInternalUrl setting by @rra in #1134
- DM-47148: Use
@override
annotations where appropriate by @rra in #1135 - DM-47148: Add label to Gafaelfawr-managed ingresses by @rra in #1136
- DM-47148: Add support for
client_secret_basic
by @rra in #1141 - Bump @babel/eslint-parser from 7.25.8 to 7.25.9 in /ui by @dependabot in #1140
- Bump eslint-config-wesbos from 4.3.1 to 4.3.2 in /ui by @dependabot in #1139
- Bump eslint-plugin-jsx-a11y from 6.10.1 to 6.10.2 in /ui by @dependabot in #1138
- Bump eslint-plugin-react from 7.37.1 to 7.37.2 in /ui by @dependabot in #1137
- DM-47148: Update dependencies by @rra in #1143
- DM-47148: Separate bot users in auth events by @rra in #1142
- DM-47148: Prepare 12.1.0 release by @rra in #1144
Full Changelog: 12.0.1...12.1.0
12.0.1
Bug fixes
- Fix startup error when metrics reporting is disabled.
What's Changed
- Bump eslint-plugin-jsx-a11y from 6.10.0 to 6.10.1 in /ui by @dependabot in #1131
- DM-47011: Fix configuration error by updating Safir by @rra in #1132
- DM-47011: Prepare 12.0.1 release by @rra in #1133
Full Changelog: 12.0.0...12.0.1
12.0.0
Backwards-incompatible changes
- The
/auth
and/auth/anonymous
routes have moved to/ingress/auth
and/ingress/anonymous
and are no longer accessible outside of the cluster. These routes may only be accessed by the ingress controller via cluster-internal URLs. This prevents users from creating arbitrary internal tokens for themselves. - Drop support and remove documentation for configuring an
Ingress
to use Gafaelfawr rather than using theGafaelfawrIngress
custom resource. - The
/ingress/auth
route now requiresX-Original-URL
to be set. - Since the CADC authentication code no longer requires the
sub
claim be a UUID, setsub
to the username in the response from/auth/cadc/userinfo
. This allows the CADC TAP server to store the username in the UWS jobs table.
New features
- Add support for exporting metrics to Kafka using the new event metrics support in Safir. The initial set of events is limited to login metrics, authentications to services, and counts of active sessions and user tokens.
GafaelfawrIngress
now accepts aservice
parameter at the top level of the configuration and uses that to tag authentication metrics by service. This corresponds to theservice
query parameter to the/auth
route. Ifdelegate_to
is also set (config.delegate.internal.service
inGafaelfawrIngress
), it must match the value ofservice
. This parameter is currently optional but will eventually become mandatory.- Add
config.onlyServices
toGafaelfawrIngress
, which restricts the ingress to tokens issued to one of the listed services in addition to the other constraints. - If a request is authenticated with an internal token, include the service associated with that token in an
X-Auth-Request-Service
header passed to the protected service. - Setting
config.baseUrl
in aGafaelfawrIngress
resource is no longer required. That value will be used if present, but only for constructing the login URL, not the/ingress/auth
URL. Instead, a global default is set by the Helm chart. Theconfig.baseUrl
setting will be removed entirely in a future release. - Add new command
gafaelfawr generate-schema
, which generates the SQL required to create the Gafaelfawr database schema.
Bug fixes
- If the user returns from authentication and no longer has login state in their cookie, redirect them to the destination URL without further processing instead of returning an authentication state mismatch error. The most likely cause of this state is that the user authenticated from another browser tab while this authentication is pending, so Gafaelfawr should use their existing token or restart the authentication process.
- Reset login state after an error so that any subsequent authentication attempt will generate a new, random state parameter.
- Stop including the required scopes in 403 errors when the request was rejected by a username restriction rather than a scope restriction, since the client cannot fix this problem by obtaining different scopes.
- Fix an error in configuration validation, introduced in 11.0.0, that caused validation rules to not be applied to any URL or DSN in the Gafaelfawr configuration.
- Cap the Kubernetes operator worker limit at 5 to avoid overwhelming the API server.
- Check that
tokenLifetime
is at least as long as twice the minimum token lifetime.
Other changes
- Honor the
POSTGRES_5432_TCP_PORT
,POSTGRES_HOST
,REDIS_6379_TCP_PORT
, andREDIS_HOST
environment variables if they are set and override the configured database URL and Redis URL with them. This is required to work with the latest version of tox-docker for testing and development. These environment variables are not used inside a Phalanx deployment.
What's Changed
- DM-44567: Update dependencies, adjust for new tox-docker by @rra in #1044
- DM-45518: Update dependencies by @rra in #1060
- Bump react-datepicker from 6.9.0 to 7.3.0 in /ui by @dependabot in #1055
- Bump python from 3.12.3-slim-bookworm to 3.12.4-slim-bookworm by @dependabot in #1047
- Bump medyagh/setup-minikube from 0.0.16 to 0.0.18 by @dependabot in #1053
- DM-45518: Update Node and JavaScript dependencies by @rra in #1061
- Bump python from 3.12.4-slim-bookworm to 3.12.5-slim-bookworm by @dependabot in #1064
- DM-45518: Update dependencies by @rra in #1065
- DM-45518: Add support for OpenTelemetry metrics by @rra in #1062
- DM-45779: Undo the *String variants of Pydantic types by @rra in #1066
- DM-45779: Use new HumanTimedelta from Safir by @rra in #1067
- DM-45779: Switch to shared Ruff configuration by @rra in #1068
- DM-45779: Update GitHub Actions to match current template by @rra in #1069
- DM-45779: Exclude mobu bot users from metrics by @rra in #1070
- DM-45768: Set sub to username for CADC reply by @rra in #1071
- DM-45779: Drop unnecessary get_secret_value() by @rra in #1072
- DM-45779: Update shared Ruff configuration by @rra in #1073
- DM-45779: Improve documentation of headers by @rra in #1074
- DM-44567: Don't upload docs if they haven't changed by @rra in #1075
- DM-45858: Cap Gafaelfawr Kopf workers at five by @rra in #1076
- DM-45858: Add service parameter to the auth endpoint by @rra in #1077
- DM-45858: Update dependencies and fix broken tests by @rra in #1078
- DM-45858: Document future CRD changes by @rra in #1079
- DM-46019: Move dependencies, use universal dependencies by @rra in #1080
- DM-46019: Switch to new documenteer REST API method by @rra in #1081
- DM-46019: Document the new dependency method by @rra in #1082
- Bump eslint-config-wesbos from 3.2.3 to 4.3.1 in /ui by @dependabot in #1084
- Bump eslint-plugin-jsx-a11y from 6.9.0 to 6.10.0 in /ui by @dependabot in #1087
- Bump eslint-plugin-react from 7.35.0 to 7.35.2 in /ui by @dependabot in #1086
- Bump eslint-plugin-import from 2.29.1 to 2.30.0 in /ui by @dependabot in #1085
- Bump styled-components from 6.1.12 to 6.1.13 in /ui by @dependabot in #1083
- Update dependencies, set pytest-asyncio fixture scope by @rra in #1088
- DM-46034: Remove test for top-level gafaelfawr module by @rra in #1089
- DM-46034: Add a test that the database schema hasn't changed by @rra in #1090
- DM-46034: Convert to the new SQLAlchemy ORM syntax by @rra in #1094
- DM-46034: Update dependencies by @rra in #1095
- DM-46034: Update Alembic configuration by @rra in #1096
- DM-46310: Use uv for Docker build, verify hashes by @rra in #1097
- fix: typo in gafaelfawringress.rst by @ac6y in #1102
- DM-46034: Use Alembic support code from Safir by @rra in #1103
- Bump prettier from 2.8.8 to 3.3.3 in /ui by @dependabot in #1098
- Bump date-fns from 3.6.0 to 4.0.0 in /ui by @dependabot in #1099
- Bump eslint from 8.57.0 to 9.10.0 in /ui by @dependabot in #1100
- Bump python from 3.12.5-slim-bookworm to 3.12.6-slim-bookworm by @dependabot in #1101
- Revert eslint update by @rra in #1104
- DM-46399: Check that token lifetime is long enough by @rra in #1105
- DM-46399: Rework handling of missing state during login by @rra in #1106
- DM-46399: Overhaul requests from ingress-nginx by @rra in #1112
- Bump react-datepicker from 7.3.0 to 7.4.0 in /ui by @dependabot in #1111
- Bump date-fns from 4.0.0 to 4.1.0 in /ui by @dependabot in #1110
- Bump eslint-plugin-prettier from 4.2.1 to 5.2.1 in /ui by @dependabot in #1108
- Bump eslint-plugin-html from 8.1.1 to 8.1.2 in /ui by @dependabot in #1107
- DM-46468: Update Python, pre-commit, and JavaScript dependencies by @rra in #1113
- DM-46399: Make baseUrl optional in GafaelfawrIngress CRD by @rra in https://github.com/lsst-sqre/gafaelfaw...
11.1.1
Bug fixes
- Respect the enrollmentUrl configuration setting when CILogon is the authentication provider, fixing a problem introduced in the 11.0.0 release.
- Detect when someone attempts to mark as admin a username that is already an admin and return a 409 error instead of raising an uncaught exception.
- Return a more-correct 409 HTTP error code, instead of 422, when a user attempts to use a duplicate token name.
- When creating a new token, try to remove it from Redis if the SQL write fails. This will hopefully reduce the number of orphaned tokens created during SQL server or proxy restarts.
What's Changed
- DM-44540: Fix handling of duplicate admins by @rra in #1039
- DM-44540: Fix HTTP error code for duplicate token names by @rra in #1040
- DM-44541: Respect enrollmentUrl for CILogon by @rra in #1041
- DM-44541: Remove tokens from Redis if SQL write fails by @rra in #1042
- DM-44541: Prepare 11.1.1 release by @rra in #1043
Full Changelog: 11.1.0...11.1.1
11.1.0
New features
- Add new
authCacheDuration
setting to theGafaelfawrIngress
Kubernetes resource, which tells Gafaelfawr to configure NGINX to cache a Gafaelfawr response for the specified length of time. The cache is invalidated if theCookie
orAuthorization
HTTP headers change.
Bug fixes
- Close database sessions after each execution of a Kopf Kubernetes operator. Previous versions of Gafaelfawr leaked sessions until the Kubernetes operator restarted.
What's Changed
- DM-44468: Add configuration for NGINX caching by @rra in #1035
- DM-44490: Use ParamSpec for Kubernetes exception wrapper by @rra in #1037
- DM-44490: Close async database sessions in the operator by @rra in #1036
- DM-44490: Prepare release 11.1.0 by @rra in #1038
Full Changelog: 11.0.1...11.1.0
11.0.1
Bug fixes
- Correctly parse the configuration if
quota
is set to an empty object. - Reject configuration files that assign scopes in
groupMapping
but do not define those scopes inknownScopes
.
What's Changed
- DM-44269: Fix configuration parsing of empty quota by @rra in #1032
- DM-44269: Cross-check groupMapping and knownScopes by @rra in #1033
- DM-44269: Prepare release 11.0.1 by @rra in #1034
Full Changelog: 11.0.0...11.0.1
11.0.0
Backwards-incompatible changes
- Drop support for getting user metadata from OpenID Connect token claims. LDAP, for both user metadata and group membership, is now required when using an OpenID Connect authentication, including CILogon.
- Remove support for getting group GIDs from a ForgeRock Identity Management server. LDAP support should be used instead.
- Drop support for LDAP groups without GIDs. Either Firestore GID assignment must be enabled or LDAP must contain a GID for each group. Groups without GIDs in LDAP will be ignored if Firestore is not enabled.
- Retrieval of the UID and primary GID from LDAP is now enabled by default unless Firestore is enabled.
- Replace
config.tokenLifetimeMinutes
withconfig.tokenLifetime
, which accepts one or more time intervals with suffixesw
,d
,h
,m
, ands
for weeks, days, hours, minutes, and seconds, respectively. - Change the default of
config.cilogon.usernameClaim
tousername
. This is what we use for all current CILogon integrations. - Change the default of
config.ldap.groupSearchByDn
to true. To preserve the previous behavior of searching by the bare username, this setting must be explicitly set to false. - Support for
config.loglevel
in Helm values has been dropped. Useconfig.logLevel
instead (note the capitalL
). - Remove the
/auth/analyze
route. This was an old way for a user to see information about their token that has been deprecated for many releases. The output used the old JWT token claim format and was missing a great deal of useful information./auth/api/v1/user-info
and/auth/api/v1/token-info
should be used instead.
New features
- Support overriding the HTTP authentication realm for
WWW-Authenticate
challenges by settingconfig.realm
. - Support overriding the OpenID Connect issuer (
iss
claim) and key ID (kid
claim) for the internal OpenID Connect server by settingconfig.oidcServer.issuer
andconfig.oidcServer.kid
, respectively.
Other changes
- Drop support for running a local development instance of Gafaelfawr. This support wasn't used during development and has some maintenance cost. Integration testing of development versions of Gafaelfawr should instead be done in a development Phalanx environment.
- Move the
docker-compose.yaml
file, now used only for creating Alembic migrations, into thealembic
subdirectory and update the documentation for creating new Alembic migraitons accordingly.
What's Changed
- DM-43689: Move more development dependencies to requirements by @rra in #996
- Bump @babel/eslint-parser from 7.23.10 to 7.24.1 in /ui by @dependabot in #994
- Bump react-datepicker from 6.3.0 to 6.6.0 in /ui by @dependabot in #993
- Bump date-fns from 3.5.0 to 3.6.0 in /ui by @dependabot in #991
- DM-43689: Update JavaScript dependencies by @rra in #997
- DM-43714: Switch to tox-uv, fix docs by @rra in #998
- DM-43714: Use frozen dependencies for tox by @rra in #1005
- Bump medyagh/setup-minikube from 0.0.15 to 0.0.16 by @dependabot in #999
- Add explicit mention of Keycloak to docs by @rra in #1006
- DM-44136: Update Docker base image by @rra in #1010
- Bump eslint-plugin-html from 8.0.0 to 8.1.1 in /ui by @dependabot in #1009
- DM-44136: Drop support for ForgeRock by @rra in #1011
- Bump gatsby from 5.13.3 to 5.13.4 in /ui by @dependabot in #1002
- Bump react-datepicker from 6.6.0 to 6.9.0 in /ui by @dependabot in #1007
- Bump react-is from 18.2.0 to 18.3.1 in /ui by @dependabot in #1008
- Bump react-icons from 5.0.1 to 5.1.0 in /ui by @dependabot in #1004
- DM-44136: Update dependencies by @rra in #1012
- DM-44136: Simplify sources of user metadata by @rra in #1013
- DM-44136: Stop importing symbols from _pytest by @rra in #1014
- DM-44136: Switch to native Pydantic camel-case support by @rra in #1015
- DM-44136: Simplify Docker container construction by @rra in #1016
- DM-44136: Use Annotated for dependencies and handlers by @rra in #1017
- Bump react-icons from 5.1.0 to 5.2.0 in /ui by @dependabot in #1018
- DM-44136: Update dependencies by @rra in #1020
- DM-44136: Move database test helper functions to module by @rra in #1021
- DM-44136: Refactor OIDC tests by @rra in #1022
- DM-44136: Add test for disabling LDAP attributes by @rra in #1023
- DM-44289: Remove /auth/analyze routes by @rra in #1024
- DM-44269: Drop support for a local development instance by @rra in #1025
- DM-44269: Remove workaround for FastAPI bug by @rra in #1026
- DM-44269: Rework the Gafaelfawr configuration layer by @rra in #1029
- Bump gatsby from 5.13.4 to 5.13.5 in /ui by @dependabot in #1030
- Bump react-icons from 5.2.0 to 5.2.1 in /ui by @dependabot in #1028
- Bump styled-components from 6.1.9 to 6.1.11 in /ui by @dependabot in #1027
- DM-44269: Prepare Gafaelfawr 11.0.0 release by @rra in #1031
Full Changelog: 10.1.0...11.0.0
10.1.0
New features
- Add a health check internal route,
/health
, which is available only inside the Kubernetes cluster. Check that the database, Redis, and (if configured) LDAP and Firestore connections are all working. Use that as a liveness check so that Kubernetes will restart Gafaelfawr if any of those connection pools are no longer working. - Add a health check for the Kubernetes operator that tests the Kopf infrastructure as well as the database and Redis connections. Use that as a liveness check to restart the operator if the health check starts failing.
Bug fixes
- Ensure that only one Gafaelfawr operator pod is running at a time.
- Add Kubernetes resource requests and limits for the Cloud SQL Auth Proxy sidecar container.
What's Changed
- DM-42627: Add more pointers to the Phalanx documentation by @rra in #977
- Fix construction of the Chronograf OIDC URL by @rra in #978
- Bump date-fns from 3.3.1 to 3.4.0 in /ui by @dependabot in #981
- Bump eslint from 8.56.0 to 8.57.0 in /ui by @dependabot in #975
- Bump react-datepicker from 6.1.0 to 6.3.0 in /ui by @dependabot in #982
- Bump eslint-plugin-react from 7.33.2 to 7.34.0 in /ui by @dependabot in #980
- DM-43288: Add a health check endpoint by @rra in #984
- DM-43288: Add Kopf health check by @rra in #985
- DM-43288: Use user info service for health check by @rra in #986
- DM-43288: Update dependencies by @rra in #987
- DM-43288: Fix Kopf health check by @rra in #988
- DM-43288: Don't check LDAP and Firestore from Kopf by @rra in #989
- DM-43288: Prepare 10.1.0 release by @rra in #990
Full Changelog: 10.0.1...10.1.0
10.0.1
10.0.0
Upgrading to this version requires a database schema migration.
Backwards-incompatible changes
- Clients of the Gafaelfawr OpenID Connect server now must have registered return URIs as well as client IDs and secrets. Each element of the
oidc-server-secrets
secret must, in addition to the previousid
andsecret
keys, contain areturn_uri
key that matches the return URL of authentications from that client. Those return URLs are now allowed to be at any (matching) domain and are not constrained to the same domain as Gafaelfawr. - When acting as an OpenID Connect server, Gafaelfawr no longer exposes all claims by default. Instead, it now honors the
scope
parameter in the request, which must includeopenid
and may includeprofile
andemail
. - In the reply to a successful OpenID Connect authentication, return a Gafaelfawr token of a new
oidc
type as the access token instead of a copy of the ID token. Thisoidc
token will be marked as a child token of the underlying Gafaelfawr token used to authenticate the OpenID Connect login, which means it will automatically be revoked if the user logs out. - Only accept Gafaelfawr tokens of the
oidc
type for the OpenID Connect server userinfo endpoint. - Return only userinfo claims from the OpenID Connect server userinfo endpoint instead of the full set of claims that would go into an ID token. Currently, the userinfo claims are not filtered based on the requested scopes; all available userinfo claims are returned.
- Set the
aud
claim in OpenID Connect ID tokens issued by Gafaelfawr to the client ID of the requesting client instead of a fixed audience used for all tokens. - OpenID Connect ID tokens issued by Gafaelfawr now inherit their expiration time from the underlying Gafaelfawr token used as the authentication basis for the ID token. Previously, OpenID Connect ID tokens would receive the full default lifetime even when issued on the basis of Gafaelfawr tokens that were about to expire.
- Require the
oidcServer.issuer
configuration setting use thehttps
scheme, since this is required by the OpenID Connect 1.0 specification.
New features
- Add a new
rubin
scope for the OpenID Connect server that, if requested, provides adata_rights
claim listing the data releases to which the user has rights. Add a newconfig.oidcServer.dataRightsMapping
configuration option that is used to determine that list of data releases from a user's group memberships. - Add support for a client-supplied nonce in OpenID Connect authentication with Gafaelfawr as a server. The provided nonce is passed through to the ID token following the OpenID Connect specification.
- Check the database schema at startup to ensure that it is current, and refuse to start if the schema is out of date.
- Add new
gafaelfawr update-schema
command that creates the database if necessary and otherwise applies any needed Alembic migrations. - Add new
gafaelfawr validate-schema
command that exits non-zero if the database has not been initialized or if the schema is not up-to-date.
Bug fixes
- Include the scope used to issue the ID token in the reply from the OpenID Connect server token endpoint.
- In the response from
/.well-known/openid-configuration
, declare that the only supported response mode of the OpenID Connect server isquery
.
Other changes
- Gafaelfawr now uses Alembic to perform database migrations as needed.
- Gafaelfawr now uses uv to maintain frozen dependencies and set up a development environment.
What's Changed
- [neophile] Update dependencies by @neophile-square in #916
- [neophile] Update dependencies by @neophile-square in #918
- Bump actions/setup-python from 4 to 5 by @dependabot in #917
- Update artifact actions by @rra in #930
- Bump eslint from 8.55.0 to 8.56.0 in /ui by @dependabot in #921
- Bump gatsby from 5.12.12 to 5.13.1 in /ui by @dependabot in #927
- Bump react-datepicker from 4.24.0 to 4.25.0 in /ui by @dependabot in #925
- Bump eslint-plugin-import from 2.29.0 to 2.29.1 in /ui by @dependabot in #923
- Bump date-fns from 2.30.0 to 3.0.6 in /ui by @dependabot in #928
- [neophile] Update dependencies by @neophile-square in #926
- Bump python from 3.11.5-slim-bullseye to 3.12.1-slim-bullseye by @dependabot in #915
- Switch to Python 3.12 by @rra in #931
- Remove empty setup.cfg by @rra in #932
- [neophile] Update dependencies by @neophile-square in #934
- DM-42384: Fix protocol issues in OpenID Connect server by @rra in #936
- DM-42384: Update Python dependencies by @rra in #937
- Bump date-fns from 3.0.6 to 3.2.0 in /ui by @dependabot in #938
- DM-42384: Add support for OpenID Connect nonces in server by @rra in #940
- [neophile] Update dependencies by @neophile-square in #943
- DM-42384: Add support for data rights information by @rra in #944
- Bump styled-components from 6.1.6 to 6.1.8 in /ui by @dependabot in #942
- Bump react-icons from 4.12.0 to 5.0.1 in /ui by @dependabot in #941
- [neophile] Update dependencies by @neophile-square in #946
- Bump date-fns from 3.2.0 to 3.3.1 in /ui by @dependabot in #947
- Bump actions/cache from 3 to 4 by @dependabot in #945
- DM-42384: Add OpenID Connect return URL registration by @rra in #948
- Update pre-commit with make update-deps by @rra in #949
- Bump @babel/eslint-parser from 7.23.3 to 7.23.9 in /ui by @dependabot in #952
- Bump gatsby from 5.13.2 to 5.13.3 in /ui by @dependabot in #951
- Bump react-datepicker from 4.25.0 to 5.0.0 in /ui by @dependabot in #950
- Update dependencies by @rra in #954
- Bump react-datepicker from 5.0.0 to 6.1.0 in /ui by @dependabot in #955
- Bump @babel/eslint-parser from 7.23.9 to 7.23.10 in /ui by @dependabot in #956
- Update Python and JavaScript dependencies by @rra in #958
- Bump eslint-plugin-html from 7.1.0 to 8.0.0 in /ui by @dependabot in #962
- Bump python from 3.12.1-slim-bullseye to 3.12.2-slim-bullseye by @dependabot in #961
- Bump pre-commit/action from 3.0.0 to 3.0.1 by @dependabot in #960
- DM-42384: Add support for database migrations with Alembic by @rra in #959
- DM-42384: Issue oidc tokens for OIDC access tokens by @rra in #963
- DM-42384: Verify the database schema on startup by @rra in #964
- DM-42384: Improve schema handling and testing by @rra in #965
- DM-42930: Switch to uv for dependency management by @rra in #966
- Bump medyagh/setup-minikube from 0.0.14 to 0.0.15 by @dependabot in #967
- DM-42627: Remove uses of sqlalchemy.future by @rra in #968
- DM-42384: Minor improvements to OpenID Connect documentation by @rra in #969
- DM-42384: Redeem OIDC codes inside a transaction by @rra in #970
- DM-42384: Add OpenID Connect tokens to the UI by @rra in #971
- DM-42384: Prepare 10.0.0 release by @rra in #972
Full Changelog: 9.6.1...10.0.0