Skip to content

Commit 14ff87a

Browse files
authored
Implement IgnoreServerCertificateErrors feature in Cake.Http (#96)
* Implement IgnoreServerCertificateErrors feature in Cake.Http - ✨ Add IgnoreServerCertificateErrors property to HttpSettings - 🔒 Update CakeHttpClientHandler to respect IgnoreServerCertificateErrors setting - 🧪 Add unit tests for server certificate validation behavior - 📜 Enhance HttpSettingsExtensions with method to configure IgnoreServerCertificateErrors - 📄 Create copilot instructions for better developer onboarding Signed-off-by: Louis Fischer <louisfischer@gmail.com> * Refactor timeout exception handling in HttpGet tests - 🛠️ Simplified exception assertion for timeout cases - 🔄 Removed conditional compilation for .NET versions Signed-off-by: Louis Fischer <louisfischer@gmail.com> * Update timeout exception message in HttpGet test - 🔄 Change exception message from "The operation was canceled." to "A task was canceled." Signed-off-by: Louis Fischer <louisfischer@gmail.com> --------- Signed-off-by: Louis Fischer <louisfischer@gmail.com>
1 parent 2f4bb75 commit 14ff87a

File tree

7 files changed

+112
-14
lines changed

7 files changed

+112
-14
lines changed

.github/copilot-instructions.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copilot instructions for Cake.Http
2+
3+
Purpose: help AI coding agents get productive quickly in this repo — build, test, common patterns, and important gotchas.
4+
5+
Quick commands
6+
- `dotnet build` : build the solution (`Cake.Http.slnx`).
7+
- `dotnet test src/Cake.Http.Tests` : run tests; tests target `net8.0;net9.0`.
8+
- Use the Cake script for full CI flow: install Cake.Tool and run `dotnet cake build.cake --target=Tests --configuration=Release`.
9+
- Pack/publish via Cake: `dotnet cake build.cake --target=Push --NUGET_PUSH=true --NUGET_URL=<url> --NUGET_API_KEY=<key>`.
10+
11+
Big picture
12+
- This project implements Cake build aliases that wrap HTTP calls. The runtime surface is a set of static Cake alias methods in `src/Cake.Http/HttpClientAliases.cs` (GET/POST/PUT/PATCH/etc.).
13+
- `HttpSettings` (`src/Cake.Http/HttpSettings.cs`) is the central configuration object used by the aliases and the custom handler.
14+
- `CakeHttpClientHandler` (`src/Cake.Http/CakeHttpClientHandler.cs`) composes `HttpSettings` into an `HttpClientHandler` and performs request/response logging via the `ICakeContext` logger.
15+
16+
Key files to inspect for behavior
17+
- `src/Cake.Http/HttpClientAliases.cs` : public Cake aliases. Keep the `[CakeMethodAlias]` attributes and method signatures stable.
18+
- `src/Cake.Http/HttpSettingsExtensions.cs` : fluent helpers used by consumers: `UseBearerAuthorization`, `SetJsonRequestBody`, `SetMultipartFormDataRequestBody`, `SetFormUrlEncodedRequestBody`, `AppendHeader`, `UseClientCertificates`, `IgnoreServerCertificateErrors`, `EnsureSuccessStatusCode`.
19+
- `src/Cake.Http/CakeHttpClientHandler.cs` : header composition, cookie handling, client cert application, request/response logging, and EnsureSuccessStatusCode handling.
20+
- `src/Cake.Http/JsonEncoder.cs` : serialization helper used by `SetJsonRequestBody`.
21+
22+
Project-specific conventions & important patterns
23+
- Aliases are implemented as synchronous wrappers over async `HttpClient` calls (e.g. using `.GetAwaiter().GetResult()` / `Task.Run(...).ConfigureAwait(false).GetAwaiter().GetResult()`). When modifying code, preserve these synchronous entry points because Cake alias consumers expect sync methods.
24+
- `HttpSettings.RequestBody` is a `byte[]`. Most helpers set it (JSON, form-url-encoded, multipart). Respect that binary contract.
25+
- Logging: `CakeHttpClientHandler` logs request/response at Diagnostic/Verbose via `ICakeContext.Log`. Logging of bodies can be disabled per-request with `SuppressLogResponseRequestBodyOutput()` or the `LogRequestResponseOutput` flag on `HttpSettings`.
26+
- Certificates: add client certs with `UseClientCertificates(...)` and optionally set `IgnoreServerCertificateErrors(true)`. The handler uses `DangerousAcceptAnyServerCertificateValidator` when server-untrusted behavior is requested — document and be careful.
27+
- EnsureSuccessStatusCode behavior: `EnsureSuccessStatusCode()` sets two flags — `EnsureSuccessStatusCode` and `ThrowExceptionOnNonSuccessStatusCode`. The handler will call `response.EnsureSuccessStatusCode()` and will only rethrow when `ThrowExceptionOnNonSuccessStatusCode` is true.
28+
29+
Testing notes
30+
- Tests use xUnit and NSubstitute. Data fixtures are in `src/Cake.Http.Tests/Data` and copied to output (see the test csproj).
31+
- Run `dotnet test src/Cake.Http.Tests --configuration Debug` locally. To exercise a single TF, pass `-f net9.0` etc.
32+
- Integration-like tests use fixtures under `src/Cake.Http.Tests/Fixtures` (e.g. `WebServerFixture`) — inspect these before changing networking/logging behavior.
33+
34+
Common maintenance tasks
35+
- Bumping versions and packaging is handled by `build.cake` using `Cake.MinVer`. When changing public API (aliases, settings), update tests and ensure packaging metadata remains stable.
36+
- Keep `Cake.Core` package version in tests consistent with the project; tests reference `Cake.Core` in the test csproj.
37+
38+
Gotchas and things an agent should not change
39+
- Do not remove or rename `[CakeMethodAlias]` and `[CakeAliasCategory]` attributes — they are the public contract for Cake integration.
40+
- Avoid changing the sync-over-async patterns unless you also update all alias entry points and tests — Cake aliases are expected to be synchronous.
41+
- Be conservative when changing default values (e.g., `LogRequestResponseOutput` defaults to `true`) because tests and consumers rely on them.
42+
43+
Where to look for context
44+
- Start at `src/Cake.Http/HttpClientAliases.cs`, then `HttpSettings`, `HttpSettingsExtensions`, and `CakeHttpClientHandler`.
45+
- Tests: `src/Cake.Http.Tests/Unit` and `src/Cake.Http.Tests/Fixtures` for examples of using `HttpSettings` and how the handler is exercised.
46+
47+
If anything is unclear
48+
- Ask for the intended target (change API, tests, or CI) and whether you should preserve backward compatibility for Cake aliases.

src/Cake.Http.Tests/Unit/CakeHttpClientHandlerTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,42 @@ public void Http_Client_Handler_Should_Add_Client_Certificates_From_Settings_To_
2929
Assert.Equal(settings.ClientCertificates[0], handler.ClientCertificates[0]);
3030
Assert.Equal(settings.ClientCertificates[1], handler.ClientCertificates[1]);
3131
}
32+
33+
[Fact]
34+
[Trait(Traits.TestCategory, TestCategories.Unit)]
35+
public void Http_Client_Handler_Should_Respect_IgnoreServerCertificateErrors_Setting_When_True()
36+
{
37+
// Given
38+
var cakeContext = Substitute.For<ICakeContext>();
39+
var settings = new HttpSettings
40+
{
41+
IgnoreServerCertificateErrors = true
42+
};
43+
44+
// When
45+
var handler = new CakeHttpClientHandler(cakeContext, settings);
46+
47+
// Then
48+
Assert.NotNull(handler.ServerCertificateCustomValidationCallback);
49+
Assert.Equal(System.Net.Http.HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, handler.ServerCertificateCustomValidationCallback);
50+
}
51+
52+
[Fact]
53+
[Trait(Traits.TestCategory, TestCategories.Unit)]
54+
public void Http_Client_Handler_Should_Not_Set_ServerCertificateCallback_When_Setting_Is_False()
55+
{
56+
// Given
57+
var cakeContext = Substitute.For<ICakeContext>();
58+
var settings = new HttpSettings
59+
{
60+
IgnoreServerCertificateErrors = false
61+
};
62+
63+
// When
64+
var handler = new CakeHttpClientHandler(cakeContext, settings);
65+
66+
// Then
67+
Assert.Null(handler.ServerCertificateCustomValidationCallback);
68+
}
3269
}
3370
}

src/Cake.Http.Tests/Unit/HttpClientAliasesTests.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -561,14 +561,8 @@ public void HttpSend_Should_Throw_Exception_If_Request_Times_Out()
561561
.SetTimeout(TimeSpan.FromMilliseconds(1));
562562

563563
var record = Record.Exception(() => _Context.HttpGet(address, settings));
564-
#if NET5_0
565-
CakeAssert.IsExceptionWithMessage<TimeoutException>(record.InnerException, "The operation was canceled.");
566564

567-
#elif NETCOREAPP3_1
568-
Assert.Null(record.InnerException);
569-
#else
570565
CakeAssert.IsExceptionWithMessage<TimeoutException>(record.InnerException, "A task was canceled.");
571-
#endif
572566
}
573567

574568
[Fact]

src/Cake.Http/CakeHttpClientHandler.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
using Cake.Core;
2-
using System;
3-
using System.Linq;
4-
using System.Net.Http;
52
using System.Net.Http.Headers;
63
using System.Text;
7-
using System.Threading;
8-
using System.Threading.Tasks;
94

105
namespace Cake.Http;
116

@@ -30,6 +25,11 @@ public CakeHttpClientHandler(ICakeContext context, HttpSettings settings)
3025
UseDefaultCredentials = settings.UseDefaultCredentials;
3126
UseCookies = false;
3227

28+
if (settings.IgnoreServerCertificateErrors)
29+
{
30+
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
31+
}
32+
3333
foreach (var clientCertificate in settings.ClientCertificates)
3434
{
3535
ClientCertificates.Add(clientCertificate);

src/Cake.Http/HttpClientAliases.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
using Cake.Core;
22
using Cake.Core.Annotations;
3-
using System;
4-
using System.Net.Http;
53
using System.Text;
6-
using System.Threading.Tasks;
74

85
namespace Cake.Http;
96

src/Cake.Http/HttpSettings.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,10 @@ public HttpSettings()
6868
/// Determines whether to log the response/request body to the console.
6969
/// </summary>
7070
public bool LogRequestResponseOutput { get; set; } = true;
71+
72+
/// <summary>
73+
/// Determines whether SSL server certificate validation errors should be ignored.
74+
/// Use with caution - disabling validation exposes you to man-in-the-middle attacks.
75+
/// </summary>
76+
public bool IgnoreServerCertificateErrors { get; set; }
7177
}

src/Cake.Http/HttpSettingsExtensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,22 @@ public static HttpSettings UseClientCertificates(this HttpSettings settings, IEn
361361
return settings;
362362
}
363363

364+
/// <summary>
365+
/// Configure the settings to ignore SSL server certificate validation errors.
366+
/// Use with caution - disabling validation exposes you to man-in-the-middle attacks.
367+
/// </summary>
368+
/// <param name="settings">The settings.</param>
369+
/// <param name="ignore">Whether to ignore server certificate validation errors.</param>
370+
/// <returns>The same <see cref="HttpSettings"/> instance so that multiple calls can be chained.</returns>
371+
public static HttpSettings IgnoreServerCertificateErrors(this HttpSettings settings, bool ignore = true)
372+
{
373+
if (settings == null)
374+
throw new ArgumentNullException(nameof(settings));
375+
376+
settings.IgnoreServerCertificateErrors = ignore;
377+
return settings;
378+
}
379+
364380
/// <summary>
365381
/// Sets the timeout for the http request
366382
/// </summary>

0 commit comments

Comments
 (0)