Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for rsa-sha2-256 and rsa-sha2-512 #825

Closed
jeson1981 opened this issue May 18, 2021 · 36 comments · Fixed by #1177
Closed

Support for rsa-sha2-256 and rsa-sha2-512 #825

jeson1981 opened this issue May 18, 2021 · 36 comments · Fixed by #1177
Milestone

Comments

@jeson1981
Copy link

Do you have plan to support for rsa-sha2-256 and rsa-sha2-512?

@ml054
Copy link

ml054 commented May 27, 2022

If you are looking for temporary solution it might help:

Note: it doesn't need to touch library code and uses latest version 2020.0.1 - so we need reflection to set props on PrivateKeyFile

 /// <summary>
    /// Based on https://github.com/sshnet/SSH.NET/blob/1d5d58e17c68a2f319c51e7f938ce6e964498bcc/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs#L12
    ///
    /// With following changes:
    ///
    /// - OID changed to sha2-256
    /// - hash changed from sha1 to sha2-256
    /// </summary>
    public class RsaSha256DigitalSignature : CipherDigitalSignature, IDisposable
    {
        private HashAlgorithm _hash;

        public RsaSha256DigitalSignature(RsaWithSha256SignatureKey rsaKey)
            // custom OID
            : base(new ObjectIdentifier(2, 16, 840, 1, 101, 3, 4, 2, 1), new RsaCipher(rsaKey))
        {
            // custom
            _hash = SHA256.Create();
        }

        protected override byte[] Hash(byte[] input)
        {
            return _hash.ComputeHash(input);
        }

        private bool _isDisposed;

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed)
                return;

            if (disposing)
            {
                var hash = _hash;
                if (hash != null)
                {
                    hash.Dispose();
                    _hash = null;
                }

                _isDisposed = true;
            }
        }

        ~RsaSha256DigitalSignature()
        {
            Dispose(false);
        }
    }
 /// <summary>
    /// Utility class which allows ssh.net to connect to servers using ras-sha2-256
    /// </summary>
    public static class RsaSha256Util
    {
        public static void SetupConnection(ConnectionInfo connection)
        {
            connection.HostKeyAlgorithms["rsa-sha2-256"] = data => new KeyHostAlgorithm("rsa-sha2-256", new RsaKey(), data);
        }

        /// <summary>
        /// Converts key file to rsa key with sha2-256 signature
        /// Due to lack of constructor: https://github.com/sshnet/SSH.NET/blob/bc99ada7da3f05f50d9379f2644941d91d5bf05a/src/Renci.SshNet/PrivateKeyFile.cs#L86
        /// We do that in place
        /// </summary>
        /// <param name="keyFile"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void ConvertToKeyWithSha256Signature(PrivateKeyFile keyFile)
        {
            var oldKeyHostAlgorithm = keyFile.HostKey as KeyHostAlgorithm;
            if (oldKeyHostAlgorithm == null)
            {
                throw new ArgumentNullException(nameof(oldKeyHostAlgorithm));
            }
            var oldRsaKey = oldKeyHostAlgorithm.Key as RsaKey;
            if (oldRsaKey == null)
            {
                throw new ArgumentNullException(nameof(oldRsaKey));
            }
            
            var newRsaKey = new RsaWithSha256SignatureKey(oldRsaKey.Modulus, oldRsaKey.Exponent, oldRsaKey.D, oldRsaKey.P, oldRsaKey.Q,
                oldRsaKey.InverseQ);

            UpdatePrivateKeyFile(keyFile, newRsaKey);
        }

        private static void UpdatePrivateKeyFile(PrivateKeyFile keyFile, RsaWithSha256SignatureKey key)
        {
            var keyHostAlgorithm = new KeyHostAlgorithm(key.ToString(), key);
            
            var hostKeyProperty = typeof(PrivateKeyFile).GetProperty(nameof(PrivateKeyFile.HostKey));
            hostKeyProperty.SetValue(keyFile, keyHostAlgorithm);

            var keyField = typeof(PrivateKeyFile).GetField("_key", BindingFlags.NonPublic | BindingFlags.Instance);
            keyField.SetValue(keyFile, key);
        }
    }
public class RsaWithSha256SignatureKey : RsaKey
    {
        public RsaWithSha256SignatureKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q,
            BigInteger inverseQ) : base(modulus, exponent, d, p, q, inverseQ)
        {
        }

        private RsaSha256DigitalSignature _digitalSignature;

        protected override DigitalSignature DigitalSignature
        {
            get
            {
                if (_digitalSignature == null)
                {
                    _digitalSignature = new RsaSha256DigitalSignature(this);
                }

                return _digitalSignature;
            }
        }

        public override string ToString()
        {
            return "rsa-sha2-256";
        }
    }

Usage:

 [Fact]
        public void CanConnectUsingRsaKeyAndSha256Signature()
        {
            var user = "ml054";
            var host = "192.168.2.154";

            var regularKey = File.ReadAllBytes("c:\\temp\\my_rsa_key");
            var pkRsa = new PrivateKeyFile(new MemoryStream(regularKey));

            RsaSha256Util.ConvertToKeyWithSha256Signature(pkRsa);

            using (var authenticationMethodRsa = new PrivateKeyAuthenticationMethod(user, pkRsa))
            {
                var conn = new ConnectionInfo(host, user, authenticationMethodRsa);
                RsaSha256Util.SetupConnection(conn); // adds rsa-sha2-256

                using (var sshClient = new SshClient(conn))
                {
                    sshClient.Connect();
                    using (var command = sshClient.RunCommand("ls"))
                    {
                        Console.WriteLine(command.Result);
                    }
                }
            }
        }

@ml054
Copy link

ml054 commented Jun 1, 2022 via email

@nicholi
Copy link

nicholi commented Jun 22, 2022

Thanks for this workaround, works great.

@superlazycoder
Copy link

Thank you so much for this. I was pulling my hair out.

Score 1 for open source.

dylan-smith added a commit to github/gh-gei that referenced this issue Nov 1, 2022
<!--
For the checkboxes below you must check each one to indicate that you
either did the relevant task, or considered it and decided there was
nothing that needed doing
-->

Stood up a BBS server in our shared Azure Subscription
(e2e-bbs-8-5-0-linux-2204.eastus.cloudapp.azure.com). It's running the
latest version of BBS (8.5.0) and Ubuntu 22.04.

Manually created 2 projects and 2 repos in BBS (in the future we may
automate this like we have for ADO/GH), and added a new integration test
to migrate BBS->GH.

Included asserts to check if the GH repo exists and is initialized.

The default SSH cert that Azure generates didn't seem to work when using
Ubuntu 22.04 (didn't work with our SSH.Net nuget library, but did work
when directly using SSH in a terminal). I found a [workaround in an
issue](sshnet/SSH.NET#825 (comment))
from the SSH.Net repo that I applied in this PR. I don't fully
understand exactly what it's doing, but it looks like it's updating the
signature on the key in-memory before using it. Whatever it's doing, it
makes keys that previously didn't work now work. So it seems like a good
thing to me.

Closes #553 

Future work:
- automate the creation of BBS test data (like we do for ADO/GH)
- Include downloading the migration logs (and asserting that they exist)
- Add BBS windows server (once we support SMB)
- Add AWS
- Add another BBS server with the oldest version we support (5.14 I
think)

Checklist
- [x] Did you write/update appropriate tests
- [x] Release notes updated (if appropriate)
- [x] Appropriate logging output
- [x] Issue linked
- [x] Docs updated (or issue created)

<!--
For docs we should review the docs at:

https://docs.github.com/en/early-access/github/migrating-with-github-enterprise-importer
and the README.md in this repo

If a doc update is required based on the changes in this PR, it is
sufficient to create an issue and link to it here. The doc update can be
made later/separately.

The process to update the docs can be found here:
https://github.com/github/docs-early-access#opening-prs

The markdown files are here: 

https://github.com/github/docs-early-access/tree/main/content/github/migrating-with-github-enterprise-importer
-->
@lcheng526
Copy link

I have implemented the workaround solution which is provided in this

Thanks for this workaround, works great.

The workaround solution does not work for me. I am getting "Key Exchange negotiation failed" exception for rsa-sha2-256.

please help me out?

@lcheng526
Copy link

The workaround solution does not work for me. I am getting "Key Exchange negotiation failed" exception for rsa-sha2-256.

please help me out?

@ml054
Copy link

ml054 commented Jan 30, 2023

@lcheng526 How about this: #971 ? Did you give a try? If it doesn't work. You can always play with debugger and try to fix by yourself. Believe me it is great adventure to play with opensource library and fix such issues. Good luck. :)

@lcheng526
Copy link

@lcheng526 How about this: #971 ? Did you give a try? If it doesn't work. You can always play with debugger and try to fix by yourself. Believe me it is great adventure to play with opensource library and fix such issues. Good luck. :)

I thought the workaround solution which is provided #825 (comment) should just work.

@lcheng526
Copy link

lcheng526 commented Jan 31, 2023

@lcheng526 How about this: #971 ? Did you give a try? If it doesn't work. You can always play with debugger and try to fix by yourself. Believe me it is great adventure to play with opensource library and fix such issues. Good luck. :)

In the workaround solution, it constructs PrivateKeyFile() based on a key file, is this a rsa-sha2-256 openssh private key file or it is a normal rsa key?

var regularKey = File.ReadAllBytes("c:\temp\my_rsa_key");
var pkRsa = new PrivateKeyFile(new MemoryStream(regularKey));

@lcheng526
Copy link

I am getting "Key Exchange negotiation failed" exception

do you need to make any changes to the workaround solution? I am getting "Key Exchange negotiation failed" exception with the workaround exception. any ideas?

@lcheng526
Copy link

Didn't check that - however if you manage to find out - please share with others on github.

On Wed, Jun 1, 2022 at 2:08 PM jhonson27 @.> wrote: If you are looking for temporary solution it might help: Note: it doesn't need to touch library code and uses latest version 2020.0.1 - so we need reflection to set props on PrivateKeyFile ///

/// Based on
public class RsaDigitalSignature : CipherDigitalSignature, IDisposable
/// /// With following changes: /// /// - OID changed to sha2-256 /// - hash changed from sha1 to sha2-256 ///
public class RsaSha256DigitalSignature : CipherDigitalSignature, IDisposable { private HashAlgorithm _hash; public RsaSha256DigitalSignature(RsaWithSha256SignatureKey rsaKey) // custom OID : base(new ObjectIdentifier(2, 16, 840, 1, 101, 3, 4, 2, 1), new RsaCipher(rsaKey)) { // custom _hash = SHA256.Create(); } protected override byte[] Hash(byte[] input) { return _hash.ComputeHash(input); } private bool _isDisposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_isDisposed) return; if (disposing) { var hash = _hash; if (hash != null) { hash.Dispose(); _hash = null; } _isDisposed = true; } } ~RsaSha256DigitalSignature() { Dispose(false); } } /// /// Utility class which allows ssh.net to connect to servers using ras-sha2-256 /// public static class RsaSha256Util { public static void SetupConnection(ConnectionInfo connection) { connection.HostKeyAlgorithms["rsa-sha2-256"] = data => new KeyHostAlgorithm("rsa-sha2-256", new RsaKey(), data); } /// /// Converts key file to rsa key with sha2-256 signature /// Due to lack of constructor:
public PrivateKeyFile(Key key)
/// We do that in place ///
/// /// public static void ConvertToKeyWithSha256Signature(PrivateKeyFile keyFile) { var oldKeyHostAlgorithm = keyFile.HostKey as KeyHostAlgorithm; if (oldKeyHostAlgorithm == null) { throw new ArgumentNullException(nameof(oldKeyHostAlgorithm)); } var oldRsaKey = oldKeyHostAlgorithm.Key as RsaKey; if (oldRsaKey == null) { throw new ArgumentNullException(nameof(oldRsaKey)); } var newRsaKey = new RsaWithSha256SignatureKey(oldRsaKey.Modulus, oldRsaKey.Exponent, oldRsaKey.D, oldRsaKey.P, oldRsaKey.Q, oldRsaKey.InverseQ); UpdatePrivateKeyFile(keyFile, newRsaKey); } private static void UpdatePrivateKeyFile(PrivateKeyFile keyFile, RsaWithSha256SignatureKey key) { var keyHostAlgorithm = new KeyHostAlgorithm(key.ToString(), key); var hostKeyProperty = typeof(PrivateKeyFile).GetProperty(nameof(PrivateKeyFile.HostKey)); hostKeyProperty.SetValue(keyFile, keyHostAlgorithm); var keyField = typeof(PrivateKeyFile).GetField("_key", BindingFlags.NonPublic | BindingFlags.Instance); keyField.SetValue(keyFile, key); } } public class RsaWithSha256SignatureKey : RsaKey { public RsaWithSha256SignatureKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger inverseQ) : base(modulus, exponent, d, p, q, inverseQ) { } private RsaSha256DigitalSignature _digitalSignature; protected override DigitalSignature DigitalSignature { get { if (_digitalSignature == null) { _digitalSignature = new RsaSha256DigitalSignature(this); } return _digitalSignature; } } public override string ToString() { return "rsa-sha2-256"; } } Usage: [Fact] public void CanConnectUsingRsaKeyAndSha256Signature() { var user = "ml054"; var host = "192.168.2.154"; var regularKey = File.ReadAllBytes("c:\temp\my_rsa_key"); var pkRsa = new PrivateKeyFile(new MemoryStream(regularKey)); RsaSha256Util.ConvertToKeyWithSha256Signature(pkRsa); using (var authenticationMethodRsa = new PrivateKeyAuthenticationMethod(user, pkRsa)) { var conn = new ConnectionInfo(host, user, authenticationMethodRsa); RsaSha256Util.SetupConnection(conn); // adds rsa-sha2-256 using (var sshClient = new SshClient(conn)) { sshClient.Connect(); using (var command = sshClient.RunCommand("ls")) { Console.WriteLine(command.Result); } } } } @ml054 https://github.com/ml054 can something similar be used in other authentication methods ? I am having issues with host key algorithm not supported when connecting with user name and password using KeyboardInteractiveAuthenticationMethod host supports rsa-sha2-512,rsa-sha2-256 Thanks — Reply to this email directly, view it on GitHub <#825 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJRI75K7W5P6ASR23LK3ITVM5HE7ANCNFSM45BTP6LA . You are receiving this because you were mentioned.Message ID: <sshnet/SSH. @.
>
-- https://ravendb.net/ Marcin Lewandowski Team Leader / Hibernating Rhinos LTD https://hibernatingrhinos.com/ Sales: @.*** Skype: ml054 Support: @.*** https://www.facebook.com/pages/RavenDB/265907650186374 https://twitter.com/ravendb https://www.linkedin.com/groups/RavenDB-4499263

Thank you so much for this. I was pulling my hair out.

Score 1 for open source.

Should I generate a sha1 key to test out this workaround solution? thanks

@lcheng526
Copy link

Should I generate a sha1 key to test out this workaround solution? thanks

Did you generate a sha1 key to test out the workaround solution? thanks

@vvda1984
Copy link

vvda1984 commented Mar 2, 2023

Following code work

var sshKeyContent = File.ReadAllBytes(sshKeyFile);
var pkRsa = new PrivateKeyFile(new MemoryStream(sshKeyContent), sskKeyPassword);

var authenticationMethodRsa = new PrivateKeyAuthenticationMethod(user, pkRsa);
methods.Add(authenticationMethodRsa);

var conn = new ConnectionInfo(host, port, user, methods.ToArray());
conn.HostKeyAlgorithms.Add("rsa-sha2-256", data =>
{
return new KeyHostAlgorithm("rsa-sha2-256", new RsaWithSha256SignatureKey(), data);
});
conn.HostKeyAlgorithms["ssh-rsa"] = data =>
{
return new KeyHostAlgorithm("ssh-rsa", new RsaWithSha256SignatureKey(), data);
};
var client = new SftpClient(conn);
client.Connect();

@masherak
Copy link

Workaround works, is there plan to update library?

@lcheng526
Copy link

lcheng526 commented Mar 29, 2023 via email

@ml054
Copy link

ml054 commented Mar 29, 2023

@lcheng526

I assume that's what you are looking for: #825 (comment)

@lcheng526
Copy link

lcheng526 commented Mar 29, 2023 via email

@vvda1984
Copy link

Hi, I have tried the solution but the solution doesn’t work . I am getting “Key exchanger negotiation failed” exception. The code is never hitting RsaSah256DigitalSignature class . it always hitting RsaKey class. Thanks Li
On Thu, 30 Mar 2023 at 07:48, Marcin Lewandowski @.> wrote: @lcheng526 https://github.com/lcheng526 I assume that's what you are looking for: #825 (comment) <#825 (comment)> — Reply to this email directly, view it on GitHub <#825 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ASJ6DCX6OA4AZVQ32PUA4CDW6SN3NANCNFSM45BTP6LA . You are receiving this because you were mentioned.Message ID: <sshnet/SSH. @.>
-- Sent from Gmail Mobile

I got same issue because the key is detected as "ssh-rsa", use following code to override the dictionary in connection object.

conn.HostKeyAlgorithms["ssh-rsa"] = data =>
{
return new KeyHostAlgorithm("ssh-rsa", new RsaWithSha256SignatureKey(), data);
};

@avantus-gary-wilkinson
Copy link

avantus-gary-wilkinson commented Mar 30, 2023

Confirm that workaround works although I had to make changes. I changed the SeupConnection method to:

public static void SetupConnection(ConnectionInfo connection)
  connection.HostKeyAlgorithms.Clear();
  connection.HostKeyAlgorithms.Add("rsa-sha2-256", (data) => { return new KeyHostAlgorithm("rsa-sha2-256", new RsaWithSha256SignatureKey(), data); });
  connection.HostKeyAlgorithms.Add("ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaWithSha256SignatureKey(), data);
});

This ensures that if the SSH server permits either the SSH-RSA or RSA-SHA2-256 host keys, you sign the private key with the 256 signature. I clear out the other host keys because you don't need them in this instance.

@masherak
Copy link

can you please share your code?
On Thu, 30 Mar 2023 at 05:36, Jaroslav Klíma @.> wrote: Workaround works, is there plan to update library? — Reply to this email directly, view it on GitHub <#825 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/ASJ6DCSW7SS3GYCJ5F6AZALW6R6L7ANCNFSM45BTP6LA . You are receiving this because you were mentioned.Message ID: <sshnet/SSH. @.>
-- Sent from Gmail Mobile

I just copy-paste snippets from the second comment there. Thanks @ml054

@lcheng526
Copy link

lcheng526 commented Apr 3, 2023 via email

@fabiofeti
Copy link

Confirm that workaround works although I had to make changes. I changed the SeupConnection method to:

public static void SetupConnection(ConnectionInfo connection)
  connection.HostKeyAlgorithms.Clear();
  connection.HostKeyAlgorithms.Add("rsa-sha2-256", (data) => { return new KeyHostAlgorithm("rsa-sha2-256", new RsaWithSha256SignatureKey(), data); });
  connection.HostKeyAlgorithms.Add("ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaWithSha256SignatureKey(), data);
});

This ensures that if the SSH server permits either the SSH-RSA or RSA-SHA2-256 host keys, you sign the private key with the 256 signature. I clear out the other host keys because you don't need them in this instance.

@ml054 @avantus-gary-wilkinson thanks a lot. Marcin's solution along Gary's implementation save my life. I spent a lot of time (a week) searching google, gtp chat and so on. Thank you.

@lcheng526
Copy link

after implemented the workaround solution I am getting "Permission denied (publickey)." exception when using a key file.
any ideas?

@lcheng526
Copy link

Confirm that workaround works although I had to make changes. I changed the SeupConnection method to:

public static void SetupConnection(ConnectionInfo connection)
  connection.HostKeyAlgorithms.Clear();
  connection.HostKeyAlgorithms.Add("rsa-sha2-256", (data) => { return new KeyHostAlgorithm("rsa-sha2-256", new RsaWithSha256SignatureKey(), data); });
  connection.HostKeyAlgorithms.Add("ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaWithSha256SignatureKey(), data);
});

This ensures that if the SSH server permits either the SSH-RSA or RSA-SHA2-256 host keys, you sign the private key with the 256 signature. I clear out the other host keys because you don't need them in this instance.

@ml054 @avantus-gary-wilkinson thanks a lot. Marcin's solution along Gary's implementation save my life. I spent a lot of time (a week) searching google, gtp chat and so on. Thank you.

I am getting "Permission denied (public key)" exception. any ideas?

@lcheng526
Copy link

@lcheng526

I assume that's what you are looking for: #825 (comment)

I am getting "Permission denied (public key)" exception. any ideas?

@tate98
Copy link

tate98 commented Aug 14, 2023

@lcheng526
I assume that's what you are looking for: #825 (comment)

I am getting "Permission denied (public key)" exception. any ideas?

@lcheng526 did you fix this exception? I am getting the same one.

@igavva
Copy link

igavva commented Sep 19, 2023

A simple solution.

Add this line in /etc/ssh/sshd_config.

PubkeyAcceptedAlgorithms +ssh-rsa
Afterwards, restart the sshd service to make the new settings come into effect.

$ sudo systemctl restart sshd

@WojciechNagorski
Copy link
Collaborator

Version 2023.0.0 has been published https://www.nuget.org/packages/SSH.NET/2023.0.0

@timrogers
Copy link

I've tried updating to the new version and removing the workaround code above, and it doesn't seem to work with these keys. Anyone else with the same issue?

@masherak
Copy link

I've tried updating to the new version and removing the workaround code above, and it doesn't seem to work with these keys. Anyone else with the same issue?

I am fine after update and remove workaround above...

@Rob-Hague
Copy link
Collaborator

@timrogers are you saying it worked with the workaround on the old version 2020.0.2, but does not work without the workaround on the new version 2023.0.0? That would be very unexpected. Any more details or code samples you can provide?

@timrogers
Copy link

@timrogers are you saying it worked with the workaround on the old version 2020.0.2, but does not work without the workaround on the new version 2023.0.0? That would be very unexpected. Any more details or code samples you can provide?

That is what I'm saying - but it's definitely possible that I did something wrong, and I don't have a minimal reproduction of the issue. I will look into this in more detail.

@vsvsav
Copy link

vsvsav commented Feb 27, 2024

v2024.0.0 - the issue remains for partnerupload.google.com...

PS
It works! But key must be converted to OpenSSH key, annoying issue

@DamianSuess
Copy link

DamianSuess commented Mar 7, 2024

After upgrading to 2023.0 and 2024.0, the implementation of the workaround has been throwing errors on our Visual Studio extension.

From reading the comments by @timrogers and @masherak, does this mean I should remove this RsaSha256Util.ConvertToKeyWithSha256Signature(keyFile); ... and RsaSha256Util.SetupConnection(conn) altogether? and use the ...

public static void SetupConnection(ConnectionInfo connection)
  connection.HostKeyAlgorithms.Clear();
  connection.HostKeyAlgorithms.Add("rsa-sha2-256", (data) => { return new KeyHostAlgorithm("rsa-sha2-256", new RsaWithSha256SignatureKey(), data); });

The one issue is that the workaround post doesn't have a RsaWithSha256SignatureKey class with an empty constructor. Just want to make sure what I should correctly pass in.

@Rob-Hague
Copy link
Collaborator

Rob-Hague commented Mar 7, 2024

Yes you should delete the workaround completely and use 2023.0.1 or higher

edit: There is no need to modify the HostKeyAlgorithms

@DamianSuess
Copy link

Thank you, @Rob-Hague for the timely response. I'll give it a shot.

Ever since the upgrade to Visual Studio v17.9 our extension has been throwing errors, and didn't see anything reported on "breaking changes". Gotta love it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.