Skip to content

Commit fcd2639

Browse files
Fix release workflow: correct secret names and workload identity federation (#387)
* Fix release workflow: correct secret names and use workload identity federation The workflow referenced stale secret names (SIGN_KEYVAULT_URL, SIGN_CLIENT_ID, SIGN_CLIENT_SECRET, SIGN_TENANT_ID, SIGN_CERTIFICATE_NAME) that don't exist. Replace with the actual secrets: CODE_SIGN_KEY_VAULT, AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID, CODE_SIGN_CERT_NAME. No SIGN_CLIENT_SECRET exists — authentication uses Azure workload identity federation (OIDC). Add id-token: write permission and azure/login@v2 step so DefaultAzureCredential can acquire a token for Key Vault access. * Fix flaky ShouldAutomaticallyReconnectandSubscribeAfterServerDisconnect test Use a fixed 15s per-lifecycle CancellationTokenSource instead of RemainingOrDefault, which decrements across all three sequential iterations. On loaded CI runners this exhausted the remaining time before the second or third lifecycle could connect, causing a spurious False on connectResult.IsSuccess. Also bound the WhenTerminated await via WaitAsync(cts.Token) to prevent an unbounded hang if cleanup stalls. * Fix flaky protocol actor tests on loaded CI runners Replace CancellationTokenSource(RemainingOrDefault) with a fixed 10-second timeout in BrokerLimitsEnforcementSpecs, AtLeastOncePublishRetryActorSpecs, ExactlyOncePublishRetryActorSpecs, and SharedReceiveMaximumQuotaSpecs. DefaultTimeout (3 s) is exhausted when the Akka TestKit actor system initialization is slow on a heavily loaded CI runner (the TestEventListener can take 5+ seconds to respond), leaving no time budget for the actual test body and causing spurious TaskCanceledException failures.
1 parent bac13a0 commit fcd2639

File tree

6 files changed

+32
-21
lines changed

6 files changed

+32
-21
lines changed

.github/workflows/release.yaml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ on:
77

88
permissions:
99
contents: write
10+
id-token: write # required for workload identity federation (OIDC signing)
1011

1112
jobs:
1213
release:
1314
name: Build, Sign, and Publish
1415
runs-on: ubuntu-latest
1516
env:
16-
SIGN_KEYVAULT_URL: ${{ secrets.SIGN_KEYVAULT_URL }}
17+
CODE_SIGN_KEY_VAULT: ${{ secrets.CODE_SIGN_KEY_VAULT }}
1718

1819
steps:
1920
- name: Checkout
@@ -41,23 +42,30 @@ jobs:
4142
- name: Pack
4243
run: dotnet pack -c Release -o ./bin/nuget
4344

45+
- name: Azure login (workload identity federation)
46+
if: env.CODE_SIGN_KEY_VAULT != ''
47+
uses: azure/login@v2
48+
with:
49+
client-id: ${{ secrets.AZURE_CLIENT_ID }}
50+
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
51+
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
52+
4453
- name: Install dotnet-sign
45-
if: env.SIGN_KEYVAULT_URL != ''
54+
if: env.CODE_SIGN_KEY_VAULT != ''
4655
run: dotnet tool install --global sign --version 0.9.*
4756

4857
- name: Sign NuGet packages
49-
if: env.SIGN_KEYVAULT_URL != ''
58+
if: env.CODE_SIGN_KEY_VAULT != ''
5059
run: >
5160
sign code azure-key-vault
5261
./bin/nuget/*.nupkg
5362
--publisher-name "Petabridge"
5463
--description "TurboMqtt"
5564
--description-url "https://github.com/petabridge/TurboMqtt"
56-
--azure-key-vault-url "${{ secrets.SIGN_KEYVAULT_URL }}"
57-
--azure-key-vault-client-id "${{ secrets.SIGN_CLIENT_ID }}"
58-
--azure-key-vault-client-secret "${{ secrets.SIGN_CLIENT_SECRET }}"
59-
--azure-key-vault-tenant-id "${{ secrets.SIGN_TENANT_ID }}"
60-
--azure-key-vault-certificate "${{ secrets.SIGN_CERTIFICATE_NAME }}"
65+
--azure-key-vault-url "${{ secrets.CODE_SIGN_KEY_VAULT }}"
66+
--azure-key-vault-client-id "${{ secrets.AZURE_CLIENT_ID }}"
67+
--azure-key-vault-tenant-id "${{ secrets.AZURE_TENANT_ID }}"
68+
--azure-key-vault-certificate "${{ secrets.CODE_SIGN_CERT_NAME }}"
6169
6270
- name: Push to NuGet.org
6371
run: >

tests/TurboMqtt.Tests/End2End/InMemoryMqtt311End2EndSpecs.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ async Task RunClientLifeCycle()
4040
{
4141
await using var client = await ClientFactory.CreateInMemoryClient(DefaultConnectOptions);
4242

43-
using var cts = new CancellationTokenSource(RemainingOrDefault);
43+
// Use a fixed per-lifecycle timeout rather than RemainingOrDefault, which decrements
44+
// across all three sequential iterations and causes the later ones to time out on
45+
// loaded CI runners.
46+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
4447
var connectResult = await client.ConnectAsync(cts.Token);
4548
connectResult.IsSuccess.Should().BeTrue();
4649

@@ -50,7 +53,7 @@ async Task RunClientLifeCycle()
5053

5154
// disconnect
5255
await client.DisconnectAsync(cts.Token);
53-
await client.WhenTerminated;
56+
await client.WhenTerminated.WaitAsync(cts.Token);
5457
}
5558
}
5659
}

tests/TurboMqtt.Tests/Protocol/AtLeastOncePublishRetryActorSpecs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ [Fact] public async Task AtLeastOncePublishRetryActor_should_resend_overdue_publ
6868
actor.Tell(PublishProtocolDefaults.CheckTimeout.Instance);
6969

7070
// we should have received the packet back
71-
using var cts = new CancellationTokenSource(RemainingOrDefault);
71+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
7272
var result = await channel.Reader.ReadAsync(cts.Token);
7373
result.Should().Be(packet);
7474
result.Duplicate.Should().BeTrue(); // duplicate flag needs to be set on retries

tests/TurboMqtt.Tests/Protocol/BrokerLimitsEnforcementSpecs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public async Task AtLeastOnceRetryActor_queues_publishes_beyond_receive_maximum_
4040
actor.Tell(packet2, probe);
4141

4242
// packet1 should reach the channel
43-
using var cts = new CancellationTokenSource(RemainingOrDefault);
43+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
4444
var inChannel = await channel.Reader.ReadAsync(cts.Token);
4545
inChannel.Should().Be(packet1);
4646

@@ -77,7 +77,7 @@ public async Task AtLeastOnceRetryActor_sends_five_publishes_two_at_a_time_with_
7777
foreach (var p in packets)
7878
actor.Tell(p, probe);
7979

80-
using var cts = new CancellationTokenSource(RemainingOrDefault);
80+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
8181

8282
// First 2 should go to channel immediately
8383
var r1 = await channel.Reader.ReadAsync(cts.Token);
@@ -158,7 +158,7 @@ public async Task ExactlyOnceRetryActor_queues_publishes_beyond_receive_maximum_
158158
actor.Tell(packet1, probe);
159159
actor.Tell(packet2, probe);
160160

161-
using var cts = new CancellationTokenSource(RemainingOrDefault);
161+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
162162

163163
// packet1 should reach the channel
164164
var inChannel = await channel.Reader.ReadAsync(cts.Token);
@@ -202,7 +202,7 @@ public async Task ExactlyOnceRetryActor_failed_pubrec_frees_slot_and_promotes_bu
202202
actor.Tell(packet1, probe);
203203
actor.Tell(packet2, probe);
204204

205-
using var cts = new CancellationTokenSource(RemainingOrDefault);
205+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
206206

207207
// packet1 goes to channel immediately
208208
var inChannel = await channel.Reader.ReadAsync(cts.Token);

tests/TurboMqtt.Tests/Protocol/ExactlyOncePublishRetryActorSpecs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public async Task ExactlyOncePublishRetryActor_should_publish_packet_completely(
4343
actor.Tell(packet, probe);
4444
actor.Tell(pubRec, probe);
4545

46-
using var cts = new CancellationTokenSource(RemainingOrDefault);
46+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
4747
var msg = await channel.Reader.ReadAsync(cts.Token);
4848
msg.PacketType.Should().Be(MqttPacketType.PubRel);
4949
// check the packet ids - they should all match
@@ -91,7 +91,7 @@ public async Task ExactlyOncePublishRetryActor_should_resend_overdue_publish_pac
9191
actor.Tell(PublishProtocolDefaults.CheckTimeout.Instance);
9292

9393
// we should have received the packet back
94-
using var cts = new CancellationTokenSource(RemainingOrDefault);
94+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
9595
var result = await channel.Reader.ReadAsync(cts.Token);
9696
result.Should().Be(packet);
9797
packet.Duplicate.Should().BeTrue();

tests/TurboMqtt.Tests/Protocol/SharedReceiveMaximumQuotaSpecs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public async Task SharedQuota_limits_combined_Qos1_and_Qos2_to_receive_maximum()
139139
var p2 = MakeQos2(2);
140140
var p3 = MakeQos1(3);
141141

142-
using var cts = new CancellationTokenSource(RemainingOrDefault);
142+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
143143

144144
// Claim slot 1: send p1, wait for it in channel
145145
qos1.Tell(p1, probe);
@@ -192,7 +192,7 @@ public async Task SharedQuota_cross_Qos_drain_when_Qos1_frees_slot_and_Qos2_has_
192192
var p2 = MakeQos2(2);
193193
var p3 = MakeQos2(3);
194194

195-
using var cts = new CancellationTokenSource(RemainingOrDefault);
195+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
196196

197197
qos1.Tell(p1, probe);
198198
var c1 = await channel.Reader.ReadAsync(cts.Token);
@@ -246,7 +246,7 @@ public async Task SharedQuota_cross_Qos_drain_when_Qos2_frees_slot_and_Qos1_has_
246246
var p2 = MakeQos2(2);
247247
var p3 = MakeQos1(3);
248248

249-
using var cts = new CancellationTokenSource(RemainingOrDefault);
249+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
250250

251251
qos1.Tell(p1, probe);
252252
var c1 = await channel.Reader.ReadAsync(cts.Token);
@@ -302,7 +302,7 @@ public async Task SharedQuota_five_interleaved_publishes_respect_receive_maximum
302302
var p4 = MakeQos2(4);
303303
var p5 = MakeQos1(5);
304304

305-
using var cts = new CancellationTokenSource(RemainingOrDefault);
305+
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
306306

307307
// Fill the quota: 3 slots
308308
qos1.Tell(p1, probe);

0 commit comments

Comments
 (0)