Skip to content

Commit 2e98d07

Browse files
authored
Merge branch 'develop' into bcl-ciphermode
2 parents 6997251 + 17afcdb commit 2e98d07

29 files changed

+1648
-620
lines changed

.editorconfig

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,22 +456,22 @@ dotnet_diagnostic.SA1601.severity = none
456456
# SA1648: <inheritdoc> must be used with inheriting class
457457
#
458458
# This rule is disabled by default, hence we need to explicitly enable it.
459-
dotnet_diagnostic.SA1648.severity = error
459+
dotnet_diagnostic.SA1648.severity = warning
460460

461461
# SX1101: Do not prefix local members with 'this.'
462462
#
463463
# This rule is disabled by default, hence we need to explicitly enable it.
464-
dotnet_diagnostic.SX1101.severity = error
464+
dotnet_diagnostic.SX1101.severity = warning
465465

466466
# SX1309: Field names must begin with underscore
467467
#
468468
# This rule is disabled by default, hence we need to explicitly enable it.
469-
dotnet_diagnostic.SX1309.severity = error
469+
dotnet_diagnostic.SX1309.severity = warning
470470

471471
# SX1309S: Static field names must begin with underscore
472472
#
473473
# This rule is disabled by default, hence we need to explicitly enable it.
474-
dotnet_diagnostic.SX1309S.severity = error
474+
dotnet_diagnostic.SX1309S.severity = warning
475475

476476
#### Meziantou.Analyzer rules ####
477477

@@ -608,7 +608,7 @@ MA0053.class_with_virtual_member_shoud_be_sealed = true
608608
# MA0112: Use 'Count > 0' instead of 'Any()'
609609
#
610610
# This rule is disabled by default, hence we need to explicitly enable it.
611-
dotnet_diagnostic.MA0112.severity = error
611+
dotnet_diagnostic.MA0112.severity = warning
612612

613613
# MA0165: Make interpolated string
614614
dotnet_diagnostic.MA0165.severity = none
@@ -646,7 +646,7 @@ dotnet_diagnostic.CA1008.severity = none
646646
#
647647
# Even when enabled, this diagnostic does not appear to be reported for assemblies without CLSCompliantAttribute.
648648
# We reported this issue as https://github.com/dotnet/roslyn-analyzers/issues/6563.
649-
dotnet_diagnostic.CA1014.severity = error
649+
dotnet_diagnostic.CA1014.severity = warning
650650

651651
# CA1051: Do not declare visible instance fields
652652
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1051
@@ -1003,19 +1003,19 @@ dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
10031003

10041004
dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.symbols = private_fields
10051005
dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.style = camel_case_begins_with_underscore
1006-
dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.severity = error
1006+
dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.severity = warning
10071007

10081008
dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.symbols = private_static_fields
10091009
dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.style = camel_case_begins_with_underscore
1010-
dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.severity = error
1010+
dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.severity = warning
10111011

10121012
dotnet_naming_rule.private_static_readonly_fields_pascal_case.symbols = private_static_readonly_fields
10131013
dotnet_naming_rule.private_static_readonly_fields_pascal_case.style = pascal_case
1014-
dotnet_naming_rule.private_static_readonly_fields_pascal_case.severity = error
1014+
dotnet_naming_rule.private_static_readonly_fields_pascal_case.severity = warning
10151015

10161016
dotnet_naming_rule.private_const_fields_pascal_case.symbols = private_const_fields
10171017
dotnet_naming_rule.private_const_fields_pascal_case.style = pascal_case
1018-
dotnet_naming_rule.private_const_fields_pascal_case.severity = error
1018+
dotnet_naming_rule.private_const_fields_pascal_case.severity = warning
10191019

10201020
# Symbol specifications
10211021

@@ -1067,7 +1067,7 @@ dotnet_naming_style.camel_case_begins_with_underscore.capitalization = camel_cas
10671067
#### .NET Compiler Platform general options ####
10681068

10691069
# Change the default rule severity for all analyzer rules that are enabled by default
1070-
dotnet_analyzer_diagnostic.severity = error
1070+
dotnet_analyzer_diagnostic.severity = warning
10711071

10721072
#### .NET Compiler Platform code refactoring rules ####
10731073

.github/workflows/build.yml

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,13 @@ jobs:
1616

1717
- name: Setup .NET
1818
uses: actions/setup-dotnet@v4
19-
with:
20-
dotnet-version: 9.0.x
2119

2220
- name: Build Unit Tests .NET
2321
run: dotnet build -f net9.0 test/Renci.SshNet.Tests/
2422

2523
- name: Build IntegrationTests .NET
2624
run: dotnet build -f net9.0 test/Renci.SshNet.IntegrationTests/
2725

28-
- name: Build IntegrationTests .NET Framework
29-
run: dotnet build -f net48 test/Renci.SshNet.IntegrationTests/
30-
3126
- name: Run Unit Tests .NET
3227
run: |
3328
dotnet test \
@@ -52,36 +47,14 @@ jobs:
5247
-p:CoverletOutput=../../coverlet/linux_integration_test_net_9_coverage.xml \
5348
test/Renci.SshNet.IntegrationTests/
5449
55-
# Also run a subset of the integration tests targeting netfx using mono. This is a temporary measure to get
56-
# some coverage until a proper solution for running the .NET Framework integration tests in CI is found.
57-
# Running all the tests causes problems which are not worth solving in this rare configuration.
58-
# See https://github.com/sshnet/SSH.NET/pull/1462 and related links
59-
- name: Run Integration Tests Mono
60-
run: |
61-
sudo apt-get install ca-certificates gnupg
62-
sudo gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/mono-official-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
63-
echo "deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/ubuntu stable-focal main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list
64-
sudo apt-get update
65-
sudo apt-get install mono-devel
66-
dotnet test \
67-
-f net48 \
68-
--no-build \
69-
--logger "console;verbosity=normal" \
70-
--logger GitHubActions \
71-
-p:CollectCoverage=true \
72-
-p:CoverletOutputFormat=cobertura \
73-
-p:CoverletOutput=../../coverlet/linux_integration_test_net_48_coverage.xml \
74-
--filter "Name~Ecdh|Name~ECDsa|Name~Zlib|Name~Gcm" \
75-
test/Renci.SshNet.IntegrationTests/
76-
7750
- name: Archive Coverlet Results
7851
uses: actions/upload-artifact@v4
7952
with:
8053
name: Coverlet Results Linux
8154
path: coverlet
8255

8356
Windows:
84-
runs-on: windows-2022
57+
runs-on: windows-2025
8558
steps:
8659
- name: Checkout
8760
uses: actions/checkout@v4
@@ -90,8 +63,6 @@ jobs:
9063

9164
- name: Setup .NET
9265
uses: actions/setup-dotnet@v4
93-
with:
94-
dotnet-version: 9.0.x
9566

9667
- name: Build Solution
9768
run: dotnet build Renci.SshNet.sln
@@ -132,6 +103,42 @@ jobs:
132103
-p:CoverletOutput=../../coverlet/windows_unit_test_net_4_6_2_coverage.xml `
133104
test/Renci.SshNet.Tests/
134105
106+
Windows-Integration-Tests:
107+
name: Windows Integration Tests
108+
runs-on: windows-2025
109+
steps:
110+
- name: Checkout
111+
uses: actions/checkout@v4
112+
with:
113+
fetch-depth: 0 # needed for Nerdbank.GitVersioning
114+
115+
- name: Setup .NET
116+
uses: actions/setup-dotnet@v4
117+
118+
- name: Setup WSL2
119+
uses: Vampire/setup-wsl@f40fb59d850112c9a292b0218bca8271305b9127 # v5.0.0
120+
with:
121+
distribution: Ubuntu-24.04
122+
123+
- name: Setup SSH Server
124+
shell: wsl-bash {0}
125+
run: |
126+
apt-get update && apt-get upgrade -y
127+
apt-get install -y podman
128+
podman build -t renci-ssh-tests-server-image -f test/Renci.SshNet.IntegrationTests/Dockerfile test/Renci.SshNet.IntegrationTests/
129+
podman run --rm -h renci-ssh-tests-server -d -p 2222:22 renci-ssh-tests-server-image
130+
131+
- name: Run Integration Tests .NET Framework
132+
run:
133+
dotnet test `
134+
-f net48 `
135+
--logger "console;verbosity=normal" `
136+
--logger GitHubActions `
137+
-p:CollectCoverage=true `
138+
-p:CoverletOutputFormat=cobertura `
139+
-p:CoverletOutput=..\..\coverlet\windows_integration_test_net_4_8_coverage.xml `
140+
test\Renci.SshNet.IntegrationTests\
141+
135142
- name: Archive Coverlet Results
136143
uses: actions/upload-artifact@v4
137144
with:

.github/workflows/docs.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@ jobs:
2727
- name: Setup Pages
2828
uses: actions/configure-pages@v5
2929

30-
- name: Setup .NET 8.0
30+
- name: Setup .NET
3131
uses: actions/setup-dotnet@v4
32-
with:
33-
dotnet-version: 8.x
3432

3533
- name: Setup docfx
3634
run: dotnet tool update -g docfx

Directory.Build.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1212
<LangVersion>latest</LangVersion>
1313
<WarningLevel>9999</WarningLevel>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition="'$(Configuration)' == 'Release' Or '$(CI)' != ''">
1417
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1518
</PropertyGroup>
1619

Directory.Packages.props

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,13 @@
88
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.5.1" />
99
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
1010
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
11-
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1">
12-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13-
<PrivateAssets>all</PrivateAssets>
14-
</PackageVersion>
11+
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
1512
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.188" />
1613

17-
<!-- Must be kept at version 1.0.0, see https://github.com/sshnet/SSH.NET/pull/1288 for details. -->
18-
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="1.0.0" />
19-
20-
<!-- No reason to require later than 6.0.0 at this time. -->
21-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
22-
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.2" />
23-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
24-
<PackageVersion Include="MSTest.TestAdapter" Version="3.8.2" />
25-
<PackageVersion Include="MSTest.TestFramework" Version="3.8.2" />
14+
<!-- Should stay on LTS .NET releases. -->
15+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
16+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.3" />
17+
<PackageVersion Include="MSTest" Version="3.8.3" />
2618
<PackageVersion Include="Moq" Version="4.20.72" />
2719
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.7.115" />
2820
<PackageVersion Include="PolySharp" Version="1.15.0" />

global.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"sdk": {
3-
"version": "9.0.100",
4-
"rollForward": "latestMajor"
3+
"version": "9.0.200",
4+
"rollForward": "latestFeature"
55
}
66
}

src/Renci.SshNet/Channels/Channel.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ internal abstract class Channel : IChannel
1717
{
1818
private readonly Lock _serverWindowSizeLock = new Lock();
1919
private readonly Lock _messagingLock = new Lock();
20+
private readonly Lock _sendDataLock = new Lock();
2021
private readonly uint _initialWindowSize;
2122
private readonly ISession _session;
2223
private readonly ILogger _logger;
@@ -340,19 +341,22 @@ public void SendData(byte[] data, int offset, int size)
340341
return;
341342
}
342343

343-
var totalBytesToSend = size;
344-
while (totalBytesToSend > 0)
344+
lock (_sendDataLock)
345345
{
346-
var sizeOfCurrentMessage = GetDataLengthThatCanBeSentInMessage(totalBytesToSend);
346+
var totalBytesToSend = size;
347+
while (totalBytesToSend > 0)
348+
{
349+
var sizeOfCurrentMessage = GetDataLengthThatCanBeSentInMessage(totalBytesToSend);
347350

348-
var channelDataMessage = new ChannelDataMessage(RemoteChannelNumber,
349-
data,
350-
offset,
351-
sizeOfCurrentMessage);
352-
_session.SendMessage(channelDataMessage);
351+
var channelDataMessage = new ChannelDataMessage(RemoteChannelNumber,
352+
data,
353+
offset,
354+
sizeOfCurrentMessage);
355+
_session.SendMessage(channelDataMessage);
353356

354-
totalBytesToSend -= sizeOfCurrentMessage;
355-
offset += sizeOfCurrentMessage;
357+
totalBytesToSend -= sizeOfCurrentMessage;
358+
offset += sizeOfCurrentMessage;
359+
}
356360
}
357361
}
358362

src/Renci.SshNet/Common/ChannelInputStream.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,10 @@ public override int Read(byte[] buffer, int offset, int count)
101101
/// <exception cref="ArgumentOutOfRangeException">offset or count is negative.</exception>
102102
public override void Write(byte[] buffer, int offset, int count)
103103
{
104-
ThrowHelper.ThrowIfNull(buffer);
105-
106-
if (offset + count > buffer.Length)
107-
{
108-
throw new ArgumentException("The sum of offset and count is greater than the buffer length.");
109-
}
110-
111-
if (offset < 0 || count < 0)
112-
{
113-
throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative.");
114-
}
104+
#if !NET
105+
ThrowHelper.
106+
#endif
107+
ValidateBufferArguments(buffer, offset, count);
115108

116109
ThrowHelper.ThrowObjectDisposedIf(_isDisposed, this);
117110

src/Renci.SshNet/Common/Extensions.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,5 +358,30 @@ internal static string Join(this IEnumerable<string> values, string separator)
358358
// which is not available on all targets.
359359
return string.Join(separator, values);
360360
}
361+
362+
#if NETFRAMEWORK || NETSTANDARD2_0
363+
internal static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
364+
{
365+
if (!dictionary.ContainsKey(key))
366+
{
367+
dictionary.Add(key, value);
368+
return true;
369+
}
370+
371+
return false;
372+
}
373+
374+
internal static bool Remove<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, out TValue value)
375+
{
376+
if (dictionary.TryGetValue(key, out value))
377+
{
378+
_ = dictionary.Remove(key);
379+
return true;
380+
}
381+
382+
value = default;
383+
return false;
384+
}
385+
#endif
361386
}
362387
}

src/Renci.SshNet/Common/PacketDump.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ public static string Create(List<byte> data, int indentLevel)
1515
public static string Create(byte[] data, int indentLevel)
1616
{
1717
ThrowHelper.ThrowIfNull(data);
18-
19-
if (indentLevel < 0)
20-
{
21-
throw new ArgumentOutOfRangeException(nameof(indentLevel), "Cannot be less than zero.");
22-
}
18+
ThrowHelper.ThrowIfNegative(indentLevel);
2319

2420
const int lineWidth = 16;
2521

0 commit comments

Comments
 (0)