This is an automated email from the ASF dual-hosted git repository. tomaswolf pushed a commit to branch rc-3.0.0-M4 in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit 74dc742cfd5bda0f40cd0e2f203540b385955885 Merge: 96846b304 c2d7b7a0b Author: Thomas Wolf <[email protected]> AuthorDate: Mon May 25 18:31:47 2026 +0200 Merge 2.18.0 into dev_3.0.0 Also prepare release documentation. CHANGES.md | 6 + docs/changes/2.18.0.md | 37 ++++ docs/changes/3.0.0-M3.md | 2 +- docs/changes/3.0.0-M4.md | 24 ++ pom.xml | 10 +- .../java/org/apache/sshd/client/kex/DHGClient.java | 25 ++- .../keyverifier/KnownHostsServerKeyVerifier.java | 15 +- .../org/apache/sshd/core/CoreModuleProperties.java | 6 + ...AuthorizedKeyEntriesPublickeyAuthenticator.java | 27 ++- .../signature/KnownHostsCertificateTest.java | 55 +++++ .../server/auth/AuthorizedKeysCertificateTest.java | 35 ++- .../org/apache/sshd/git/AbstractGitCommand.java | 39 ++++ .../org/apache/sshd/git/pack/GitPackCommand.java | 8 +- .../apache/sshd/git/pgm/EmbeddedCommandRunner.java | 3 +- .../apache/sshd/git/pack/GitPackCommandTest.java | 246 +++++++++++++++++++++ .../apache/sshd/putty/AbstractPuttyKeyDecoder.java | 54 ++++- .../sshd/putty/PuttyKeyPairResourceParser.java | 48 +++- .../apache/sshd/putty/PuttySpecialKeysTest.java | 13 +- .../non-ascii-passphrase-encrypted-KeyPair.ppk | 15 ++ .../services/java.nio.file.spi.FileSystemProvider | 2 +- .../client/fs/SftpFileSystemProviderFacade.java | 182 +++++++++++++++ .../sshd/sftp/client/fs/SftpFileSystemTest.java | 2 +- sshd-site/src/site/markdown/index.md | 1 + 23 files changed, 809 insertions(+), 46 deletions(-) diff --cc CHANGES.md index 0d4acb13b,998d8fa08..18f78c336 --- a/CHANGES.md +++ b/CHANGES.md @@@ -1,43 -1,65 +1,49 @@@ -# Apache MINA SSHD 2.18.0 +# Previous Versions -Changes since [version 2.17.1](./docs/changes/2.17.1.md): +* [Change Notes for Version 2](./docs/changes/version2.md) -## Bug Fixes +# Version 3 -* [GH-743](https://github.com/apache/mina-sshd/issues/743) Ensure the Java `ServiceLoader` use a singleton `SftpFileSystemProvider` -* [GH-879](https://github.com/apache/mina-sshd/issues/879) Close SSH channel gracefully on exception in port forwarding -* Improve handling of repository paths in `sshd-git`. +**This is work in progress.** Version 3 contains many API breaks from version 2. API comparison reports +generated by [japicmp](https://siom79.github.io/japicmp) are published at +[https://apache.github.io/mina-sshd](https://apache.github.io/mina-sshd). -## New Features +Version 3 includes all the features and bug fixes of version 2, including the +[latest ones](https://github.com/apache/mina-sshd/blob/master/CHANGES.md#planned-for-next-version). -* [GH-892](https://github.com/apache/mina-sshd/issues/892) Align handling certificates without principals with OpenSSH 10.3 +* For building Apache MINA SSHD 3.0, **Java >= 24** and Apache **Maven >= 3.9.12** are required. Generated artifacts + still use Java 8 as minimum runtime requirement. -Wildcard principals in host certificates are handled now. +## Milestone 1: Pre-Release 3.0.0-M1 -* Putty keys with non-ASCII passphrases +Complete refactoring of the SSH transport protocol. New feature: support for client-side proxies. -The passphrase needs to be converted to a byte sequence to compute a decryption key for an encrypted private key. This -conversion depends on the character encoding. Putty on Windows uses the ANSI codepage set when the key was generated. -Apache MINA SSHD now tries multiple encodings in sequence: UTF-8, then the OS encoding, and finally ISO-8859-1 as a -last-chance fallback. +* [Change notes for 3.0.0-M1](./docs/changes/3.0.0-M1.md) -## Potential Compatibility Issues +## Milestone 2: Pre-Release 3.0.0-M2 -* [GH-892](https://github.com/apache/mina-sshd/issues/892) Align handling certificates without principals with OpenSSH 10.3 +Refactoring of cryptography. New feature: multi-release JARs for `sshd-common` and `sshd-osgi` and using on +newer Java versions the already built-in cryptographic algorithms for ChaCha20, ed25519, and ML-KEM. -OpenSSH 10.3 changed the way such certificates are handled; see the [OpenSSH 10.3 release notes](https://www.openssh.org/txt/release-10.3). -In Apache MINA SSHD, there is a new flag `CoreModuleProperties.ALLOW_EMPTY_CERTIFICATE_PRINCIPALS` (by default `false`) -that can be set on an `SshClient` or `SshServer` or also on a `Session` directly. If the value is `false`, certificates -without principals are rejected as in OpenSSH 10.3; if it is `true`, such certificates are considered to match any -user or host name as in OpenSSH < 10.3. +* [Change notes for 3.0.0-M2](./docs/changes/3.0.0-M2.md) -Set the flag on an `SshClient` or `ClientSession` to determine the handling of host certificates. Set it on an -`SshServer` or `ServerSession` to govern the handling of user certificates. +## Milestone 3: Pre-Release 3.0.0-M3 -## Major Code Re-factoring +This is a minor update to bring the improvements done in 2.17.x into the 3.0.0 stream. Besides that, +there are only two bug fixes from 3.0.0-M2. -None. +* [Change notes for 3.0.0-M3](./docs/changes/3.0.0-M3.md) -# Previous Versions ++## Milestone 3: Pre-Release 3.0.0-M4 ++ ++Merges 2.18.0 into the 3.0.0 stream. ++ ++* [Change notes for 3.0.0-M4](./docs/changes/3.0.0-M4.md) + -* [Version 2.1.0 to 2.2.0](./docs/changes/2.2.0.md) -* [Version 2.2.0 to 2.3.0](./docs/changes/2.3.0.md) -* [Version 2.3.0 to 2.4.0](./docs/changes/2.4.0.md) -* [Version 2.4.0 to 2.5.0](./docs/changes/2.5.0.md) -* [Version 2.5.0 to 2.5.1](./docs/changes/2.5.1.md) -* [Version 2.5.1 to 2.6.0](./docs/changes/2.6.0.md) -* [Version 2.6.0 to 2.7.0](./docs/changes/2.7.0.md) -* [Version 2.7.0 to 2.8.0](./docs/changes/2.8.0.md) -* [Version 2.8.0 to 2.9.0](./docs/changes/2.9.0.md) -* [Version 2.9.0 to 2.9.1](./docs/changes/2.9.1.md) -* [Version 2.9.1 to 2.9.2](./docs/changes/2.9.2.md) -* [Version 2.9.2 to 2.10.0](./docs/changes/2.10.0.md) -* [Version 2.10.0 to 2.11.0](./docs/changes/2.11.0.md) -* [Version 2.11.0 to 2.12.0](./docs/changes/2.12.0.md) -* [Version 2.12.0 to 2.12.1](./docs/changes/2.12.1.md) -* [Version 2.12.1 to 2.13.0](./docs/changes/2.13.0.md) -* [Version 2.13.0 to 2.13.1](./docs/changes/2.13.1.md) -* [Version 2.13.1 to 2.13.2](./docs/changes/2.13.2.md) -* [Version 2.13.2 to 2.14.0](./docs/changes/2.14.0.md) -* [Version 2.14.0 to 2.15.0](./docs/changes/2.15.0.md) -* [Version 2.15.0 to 2.16.0](./docs/changes/2.16.0.md) -* [Version 2.16.0 to 2.17.0](./docs/changes/2.17.0.md) -* [Version 2.17.0 to 2.17.1](./docs/changes/2.17.1.md) +# Planned for the Next Milestone Release + +## Bug Fixes + +## Major Code Re-factoring + +## New Features diff --cc docs/changes/2.18.0.md index 000000000,998d8fa08..7a3aa9592 mode 000000,100644..100644 --- a/docs/changes/2.18.0.md +++ b/docs/changes/2.18.0.md @@@ -1,0 -1,65 +1,37 @@@ -# Apache MINA SSHD 2.18.0 - -Changes since [version 2.17.1](./docs/changes/2.17.1.md): ++# Introduced in 2.18.0 + + ## Bug Fixes + + * [GH-743](https://github.com/apache/mina-sshd/issues/743) Ensure the Java `ServiceLoader` use a singleton `SftpFileSystemProvider` + * [GH-879](https://github.com/apache/mina-sshd/issues/879) Close SSH channel gracefully on exception in port forwarding + * Improve handling of repository paths in `sshd-git`. + + ## New Features + + * [GH-892](https://github.com/apache/mina-sshd/issues/892) Align handling certificates without principals with OpenSSH 10.3 + + Wildcard principals in host certificates are handled now. + + * Putty keys with non-ASCII passphrases + + The passphrase needs to be converted to a byte sequence to compute a decryption key for an encrypted private key. This + conversion depends on the character encoding. Putty on Windows uses the ANSI codepage set when the key was generated. + Apache MINA SSHD now tries multiple encodings in sequence: UTF-8, then the OS encoding, and finally ISO-8859-1 as a + last-chance fallback. + + ## Potential Compatibility Issues + + * [GH-892](https://github.com/apache/mina-sshd/issues/892) Align handling certificates without principals with OpenSSH 10.3 + + OpenSSH 10.3 changed the way such certificates are handled; see the [OpenSSH 10.3 release notes](https://www.openssh.org/txt/release-10.3). + In Apache MINA SSHD, there is a new flag `CoreModuleProperties.ALLOW_EMPTY_CERTIFICATE_PRINCIPALS` (by default `false`) + that can be set on an `SshClient` or `SshServer` or also on a `Session` directly. If the value is `false`, certificates + without principals are rejected as in OpenSSH 10.3; if it is `true`, such certificates are considered to match any + user or host name as in OpenSSH < 10.3. + + Set the flag on an `SshClient` or `ClientSession` to determine the handling of host certificates. Set it on an + `SshServer` or `ServerSession` to govern the handling of user certificates. + + ## Major Code Re-factoring + + None. - -# Previous Versions - -* [Version 2.1.0 to 2.2.0](./docs/changes/2.2.0.md) -* [Version 2.2.0 to 2.3.0](./docs/changes/2.3.0.md) -* [Version 2.3.0 to 2.4.0](./docs/changes/2.4.0.md) -* [Version 2.4.0 to 2.5.0](./docs/changes/2.5.0.md) -* [Version 2.5.0 to 2.5.1](./docs/changes/2.5.1.md) -* [Version 2.5.1 to 2.6.0](./docs/changes/2.6.0.md) -* [Version 2.6.0 to 2.7.0](./docs/changes/2.7.0.md) -* [Version 2.7.0 to 2.8.0](./docs/changes/2.8.0.md) -* [Version 2.8.0 to 2.9.0](./docs/changes/2.9.0.md) -* [Version 2.9.0 to 2.9.1](./docs/changes/2.9.1.md) -* [Version 2.9.1 to 2.9.2](./docs/changes/2.9.2.md) -* [Version 2.9.2 to 2.10.0](./docs/changes/2.10.0.md) -* [Version 2.10.0 to 2.11.0](./docs/changes/2.11.0.md) -* [Version 2.11.0 to 2.12.0](./docs/changes/2.12.0.md) -* [Version 2.12.0 to 2.12.1](./docs/changes/2.12.1.md) -* [Version 2.12.1 to 2.13.0](./docs/changes/2.13.0.md) -* [Version 2.13.0 to 2.13.1](./docs/changes/2.13.1.md) -* [Version 2.13.1 to 2.13.2](./docs/changes/2.13.2.md) -* [Version 2.13.2 to 2.14.0](./docs/changes/2.14.0.md) -* [Version 2.14.0 to 2.15.0](./docs/changes/2.15.0.md) -* [Version 2.15.0 to 2.16.0](./docs/changes/2.16.0.md) -* [Version 2.16.0 to 2.17.0](./docs/changes/2.17.0.md) -* [Version 2.17.0 to 2.17.1](./docs/changes/2.17.1.md) diff --cc docs/changes/3.0.0-M3.md index ea5dd6574,000000000..b932eafee mode 100644,000000..100644 --- a/docs/changes/3.0.0-M3.md +++ b/docs/changes/3.0.0-M3.md @@@ -1,25 -1,0 +1,25 @@@ +# Milestone Pre-Release 3.0.0-M3 + +This milestone release fixes a minor bug in 3.0.0-M3 and brings in all improvements from the 2.X branch. + - It includes all the features and bug fixes of [version 2.17.1](./docs/changes/2.17.1.md) and up to ++It includes all the features and bug fixes of [version 2.17.1](./2.17.1.md) and up to +[commit a3d22510](https://github.com/apache/mina-sshd/blob/a3d22510/CHANGES.md#planned-for-next-version). + +* [Change notes for 3.0.0-M1](./3.0.0-M1.md) +* [Change notes for 3.0.0-M2](./3.0.0-M2.md) + +* For building Apache MINA SSHD 3.0, **Java >= 24** and Apache **Maven >= 3.9.12** are required. Generated artifacts + still use Java 8 as minimum runtime requirement. + +## Bug Fixes + +* [GH-852](https://github.com/apache/mina-sshd/issues/852) (Bug in 3.0.0-M2) Fix wrong import +* [GH-891](https://github.com/apache/mina-sshd/issues/891) (Regression in 3.0.0-M1) Fix format of injected SSH_MSG_IGNORE + +## Major Code Re-factoring + +* None + +## New Features + +* None diff --cc docs/changes/3.0.0-M4.md index 000000000,000000000..e62ed77a9 new file mode 100644 --- /dev/null +++ b/docs/changes/3.0.0-M4.md @@@ -1,0 -1,0 +1,24 @@@ ++# Milestone Pre-Release 3.0.0-M4 ++ ++This milestone release just merges the 2.18.0 branch. ++ ++It includes all the features and bug fixes of [version 2.18.0](./2.18.0.md). ++ ++* [Change notes for 3.0.0-M1](./3.0.0-M1.md) ++* [Change notes for 3.0.0-M2](./3.0.0-M2.md) ++* [Change notes for 3.0.0-M3](./3.0.0-M3.md) ++ ++* For building Apache MINA SSHD 3.0, **Java >= 24** and Apache **Maven >= 3.9.12** are required. Generated artifacts ++ still use Java 8 as minimum runtime requirement. ++ ++## Bug Fixes ++ ++None. ++ ++## Major Code Re-factoring ++ ++None. ++ ++## New Features ++ ++None. diff --cc pom.xml index 1d5f02fd7,08303269b..e1cdafb97 --- a/pom.xml +++ b/pom.xml @@@ -81,20 -80,24 +81,20 @@@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <project.build.outputTimestamp>2026-05-25T15:45:34Z</project.build.outputTimestamp> + <project.build.outputTimestamp>2026-03-26T22:35:23Z</project.build.outputTimestamp> <java.sdk.version>8</java.sdk.version> - <javac.source>${java.sdk.version}</javac.source> - <project.build.java.source>${javac.source}</project.build.java.source> - <maven.compiler.source>${javac.source}</maven.compiler.source> + <javac.release>${java.sdk.version}</javac.release> + <maven.compiler.release>${java.sdk.version}</maven.compiler.release> <ant.version>1.10.15</ant.version> - <ant.build.javac.source>${javac.source}</ant.build.javac.source> <build-helper-maven-plugin.version>3.6.1</build-helper-maven-plugin.version> - <javac.target>${javac.source}</javac.target> - <required.java.version>[${javac.target},)</required.java.version> - <project.build.java.target>${javac.target}</project.build.java.target> - <maven.compiler.target>${javac.target}</maven.compiler.target> - <ant.build.javac.target>${javac.target}</ant.build.javac.target> + <required.java.version>[${java.sdk.version},)</required.java.version> <groovy.version>4.0.17</groovy.version> - <bouncycastle.version>1.83</bouncycastle.version> + <bouncycastle.version>1.84</bouncycastle.version> + <!-- BC FIPS has version numbers 2.x.y. --> + <bouncycastle.upper.bound>3</bouncycastle.upper.bound> <!-- NOTE: upgrading slf4j beyond this version causes Execution verify-style of goal org.apache.maven.plugins:maven-checkstyle-plugin:3.1.2:check failed.: NullPointerException @@@ -108,10 -111,10 +108,10 @@@ <jgit.version>5.13.5.202508271544-r</jgit.version> <!-- mockito 5.0 requires Java 11. --> <mockito.version>4.11.0</mockito.version> - <testcontainers.version>1.21.3</testcontainers.version> + <testcontainers.version>2.0.4</testcontainers.version> - <grpc.version>1.78.0</grpc.version> <!-- Used only in tests --> + <grpc.version>1.79.0</grpc.version> <!-- Used only in tests --> - <maven.archiver.version>3.6.5</maven.archiver.version> + <maven.archiver.version>3.6.6</maven.archiver.version> <plexus.archiver.version>4.11.0</plexus.archiver.version> <!-- See https://pmd.github.io/ for available latest version --> <pmd.version>7.22.0</pmd.version> diff --cc sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java index e0b8b21f3,d8998ddeb..3649d986d --- a/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/kex/DHGClient.java @@@ -284,9 -302,12 +290,12 @@@ public class DHGClient extends Abstract throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, "KeyExchange signature verification failed, could not determine connect host for key ID=" + keyId); } + } else if (!CoreModuleProperties.ALLOW_EMPTY_CERTIFICATE_PRINCIPALS.getRequired(session)) { + throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, + "KeyExchange signature verification failed because the certificate has no principals; key ID=" + keyId); } - if (!GenericUtils.isEmpty(openSshKey.getCriticalOptions())) { + if (!openSshKey.getCriticalOptions().isEmpty()) { // no critical option defined for host keys yet throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED, "KeyExchange signature verification failed, unrecognized critical options " diff --cc sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java index a51c3c740,ec33ae0ba..27c7b3188 --- a/sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java +++ b/sshd-core/src/main/java/org/apache/sshd/core/CoreModuleProperties.java @@@ -780,28 -799,12 +780,34 @@@ public final class CoreModulePropertie } }); + /** + * Whether to allow SSH user or host certificates without principals. OpenSSH < 10.3 considered such certificates to + * be valid for any principal; since OpenSSH 10.3 such certificates are rejected. + */ + public static final Property<Boolean> ALLOW_EMPTY_CERTIFICATE_PRINCIPALS = Property.bool("empty-cert-principals", false); + + public static final int DEFAULT_MAX_MSGS_BEFORE_KEX_INIT = 1_000; + + /** + * After having sent our own SSH_MSG_KEXINIT when starting a new key exchange, we expect the peer's SSH_MSG_KEXINIT. + * But a peer can send any number of other messages first. If those messages require replies, we must buffer these + * replies because once we've sent SSH_MSG_KEXINIT, we may send only key exchange messages until the key exchange is + * over. Buffering replies means a broken peer that just doesn't send its SSH_MSG_KEXINIT could cause unbounded + * memory consumption on our end. This concerns in particular SSH_MSG_GLOBAL_REQUEST with the "want-reply" flag + * {@code true}, SSH_MSG_CHANNEL_REQUEST and SSH_MSG_CHANNEL_OPEN. This property set an upper limit on the number of + * such messages that we'll handle if no SSH_MSG_KEXINIT from the peer is received yet after having sent our own. If + * the limit is exceeded, the session disconnects. + * + * <p> + * The default value is {@link #DEFAULT_MAX_MSGS_BEFORE_KEX_INIT} (1000), which should be very generous. If zero or + * negative, no limit is assumed. + * </p> + * + * @see #DEFAULT_MAX_MSGS_BEFORE_KEX_INIT + */ + public static final Property<Integer> MAX_MSGS_BEFORE_KEX_INIT = Property.integer("kex-max-msgs-before-kex-init", + DEFAULT_MAX_MSGS_BEFORE_KEX_INIT); + private CoreModuleProperties() { throw new UnsupportedOperationException("No instance"); } diff --cc sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java index 521103826,6c5f19de1..2c0f2a82b --- a/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java +++ b/sshd-putty/src/main/java/org/apache/sshd/putty/AbstractPuttyKeyDecoder.java @@@ -23,8 -23,12 +23,10 @@@ import java.io.ByteArrayInputStream import java.io.IOException; import java.io.InputStream; import java.io.StreamCorruptedException; + import java.nio.charset.Charset; + import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.Base64; diff --cc sshd-site/src/site/markdown/index.md index cbed912f7,000000000..ebb3c376c mode 100644,000000..100644 --- a/sshd-site/src/site/markdown/index.md +++ b/sshd-site/src/site/markdown/index.md @@@ -1,58 -1,0 +1,59 @@@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> +# Apache MINA sshd + +Welcome to the _development_ web site of Apache MINA sshd. This web site currently +contains technical information about the development of a new major release **3.0.0**. + +Apache MINA sshd is a pure Java library for client- and server-side SSH. + +* The main web site is at [Apache MINA sshd](https://mina.apache.org/sshd-project). +* For now, [technical documentation](https://github.com/apache/mina-sshd/blob/master/README.md) +still lives directly in the git repository and can be viewed as rendered web pages in GitHub. +* Technical information on the development of release 3.0.0 is available in branch `dev_3.0`: + * [Changes since 2.16.0](https://github.com/apache/mina-sshd/blob/dev_3.0/CHANGES.md) + * [Technical documentation](https://github.com/apache/mina-sshd/tree/dev_3.0/docs/technical) + +Release 3.0.0 will be a new major release and will contain many breaking API changes. +It will not be API-compatible with the 2.X releases. There are +[`japicmp`](https://siom79.github.io/japicmp) reports about the API changes available +here; see the menu on the left. Most of the API changes affect only the `protected` API, +i.e., the API for subclassing. But there are also changes in the `public` API that may +affect user code. + +## Roadmap + +We cannot give a definitive roadmap with milestone dates. All development is done by +volunteers in their free time and resources are limited. + +But we can give you a rough outline of what we want to do: + +* **3.0.0-M1**: Rework of the SSH transport protocol as a filter chain. The main user-visible + new feature is support for client-side proxies. +* **3.0.0-M2**: Refactoring of cryptography. New feature: multi-release JARs for `sshd-common` + and `sshd-osgi` and using on newer Java versions the already built-in cryptographic algorithms + for ChaCha20, ed25519, and ML-KEM. +* **3.0.0-M3**: Bug fix release of 3.0.0-M2, and update base to 2.17.1. ++* **3.0.0-M4**: Update base to 2.18.0. + +Further possible milestones (the order might change, though): + +* Some refactoring of SFTP code; current code has shortcomings regarding SFTP file systems. +* Resolve the split packages between `sshd-common` and `sshd-core`. +* Anything else we stumble upon and that we cannot fix reasonably without breaking API. + +We reserve the right to make arbitrary API changes between M-releases.
