@@ -193,20 +193,23 @@
_model.KeepOldCidPinned = InitialKeepOldCidPinned;
}
- private IEnumerable
Validate()
+ private string? ValidateName(string? value)
{
- _error = null;
+ if (string.IsNullOrWhiteSpace(value))
+ return "Name is required.";
- if (string.IsNullOrWhiteSpace(_model.Name))
- yield return "Name is required.";
- if (string.IsNullOrWhiteSpace(_model.Key))
- yield return "IPNS key is required.";
+ return IpfsGateway.ToSafeLeaf(value) is null ? "Invalid name." : null;
+ }
- var leaf = IpfsGateway.ToSafeLeaf(_model.Name);
- if (leaf is null)
- yield return "Invalid name.";
- if (!_model.Key.StartsWith("k51") && !_model.Key.StartsWith("/ipns/"))
- yield return "IPNS Key should look like k51… or /ipns/k51…";
+ private static string? ValidateKey(string? value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ return "IPNS key is required.";
+
+ return value.StartsWith("k51", StringComparison.OrdinalIgnoreCase) ||
+ value.StartsWith("/ipns/k51", StringComparison.OrdinalIgnoreCase)
+ ? null
+ : "IPNS Key should look like k51… or /ipns/k51…";
}
private void Cancel() => MudDialog.Cancel();
@@ -293,9 +296,9 @@
return null;
}
- private async void Submit()
+ private async Task Submit()
{
- await _form.Validate();
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
// Name leaf (immutable on edit)
diff --git a/TruthGate-Web/TruthGate-Web/Components/Shared/AddPinnedItemDialog.razor b/TruthGate-Web/TruthGate-Web/Components/Shared/AddPinnedItemDialog.razor
index b473c89..76207eb 100644
--- a/TruthGate-Web/TruthGate-Web/Components/Shared/AddPinnedItemDialog.razor
+++ b/TruthGate-Web/TruthGate-Web/Components/Shared/AddPinnedItemDialog.razor
@@ -1,9 +1,9 @@
-@using MudBlazor
+@using MudBlazor
@using TruthGate_Web.Utils
-
+
Add Pinned Item
@@ -7,7 +7,7 @@
@Message
}
-
+
Validate()
+ private string? ValidateValue(string? value)
{
_error = null;
- if (Required && string.IsNullOrWhiteSpace(_value))
- {
- _error = "Please enter a value.";
- yield return _error;
- }
+ if (Required && string.IsNullOrWhiteSpace(value))
+ return _error = "Please enter a value.";
+
+ return null;
}
private async Task Submit()
{
- await _form.Validate();
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
MudDialog.Close(DialogResult.Ok(_value));
}
From 190af2f24a6460d4674020d54ea8f1510aa1f25c Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:01:14 -0400
Subject: [PATCH 16/27] Update .NET 10 test host packages
---
.../TruthGate-Web.Tests/TruthGate-Web.Tests.csproj | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj b/TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj
index 825fa90..4b520df 100644
--- a/TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj
+++ b/TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj
@@ -9,9 +9,9 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
From 19b9840f76824ed343b0ec3be57a2701590e1c52 Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:03:25 -0400
Subject: [PATCH 17/27] Add .NET 10 test-host diagnostics
---
.github/workflows/tls-lifecycle.yml | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tls-lifecycle.yml b/.github/workflows/tls-lifecycle.yml
index e458f25..3f26f46 100644
--- a/.github/workflows/tls-lifecycle.yml
+++ b/.github/workflows/tls-lifecycle.yml
@@ -37,12 +37,14 @@ jobs:
dotnet test \
TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj \
--no-restore \
- --no-build \
--configuration Release \
--logger "console;verbosity=normal" \
+ --diag tls-vstest-diag.log \
> tls-test-output.log 2>&1
status=$?
echo "status=$status" >> "$GITHUB_OUTPUT"
+ echo "Test output directory:"
+ find TruthGate-Web/TruthGate-Web.Tests/bin/Release/net10.0 -maxdepth 1 -type f -printf '%f\n' | sort
tail -n 200 tls-test-output.log
exit 0
@@ -51,7 +53,9 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: tls-test-output
- path: tls-test-output.log
+ path: |
+ tls-test-output.log
+ tls-vstest-diag.log
if-no-files-found: error
- name: Report test failure
From cbc586d7037b3c33577caec9034f8d3fa1678e1e Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:05:31 -0400
Subject: [PATCH 18/27] Restore TLS test project explicitly
---
.github/workflows/tls-lifecycle.yml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tls-lifecycle.yml b/.github/workflows/tls-lifecycle.yml
index 3f26f46..9b1e657 100644
--- a/.github/workflows/tls-lifecycle.yml
+++ b/.github/workflows/tls-lifecycle.yml
@@ -26,6 +26,9 @@ jobs:
- name: Restore solution
run: dotnet restore TruthGate-IPFS.sln
+ - name: Restore TLS tests
+ run: dotnet restore TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj
+
- name: Build solution
run: dotnet build TruthGate-IPFS.sln --no-restore --configuration Release
@@ -43,8 +46,6 @@ jobs:
> tls-test-output.log 2>&1
status=$?
echo "status=$status" >> "$GITHUB_OUTPUT"
- echo "Test output directory:"
- find TruthGate-Web/TruthGate-Web.Tests/bin/Release/net10.0 -maxdepth 1 -type f -printf '%f\n' | sort
tail -n 200 tls-test-output.log
exit 0
From cf0090430ec72bfc3063e7cfa3c7073d0194bcb5 Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:08:59 -0400
Subject: [PATCH 19/27] Migrate add-ban validation to async MudForm APIs
---
.../Pages/Settings/Shared/AddBanDialog.razor | 77 ++++++++++---------
1 file changed, 41 insertions(+), 36 deletions(-)
diff --git a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddBanDialog.razor b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddBanDialog.razor
index 45e4ca4..55d30b2 100644
--- a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddBanDialog.razor
+++ b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddBanDialog.razor
@@ -10,7 +10,7 @@
@Message
}
-
+
@@ -19,6 +19,7 @@
Placeholder="@(_usePrefix ? "2001:db8::/64" : "203.0.113.42 or ::ffff:203.0.113.42")"
Immediate="true"
Required="true"
+ Validation="@(new Func(ValidateTarget))"
@onkeydown="OnKeyDown" />
@@ -30,7 +31,13 @@
-
+
Validate()
+ private string? ValidateTarget(string? value)
{
_error = null;
- if (string.IsNullOrWhiteSpace(_target))
- {
- _error = "Please provide a target.";
- yield return _error!;
- yield break;
- }
-
- var t = _target.Trim();
+ if (string.IsNullOrWhiteSpace(value))
+ return _error = "Please provide a target.";
+ var target = value.Trim();
if (_usePrefix)
{
- // Accept "2001:db8::" or "2001:db8::/64" — the service canonicalizes either
- var bare = t.Contains('/') ? t[..t.IndexOf('/')] : t;
- if (!IPAddress.TryParse(bare, out var parsed) || parsed.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
+ // Accept "2001:db8::" or "2001:db8::/64" — the service canonicalizes either.
+ var slash = target.IndexOf('/');
+ var bare = slash >= 0 ? target[..slash] : target;
+ if (!IPAddress.TryParse(bare, out var parsed) ||
+ parsed.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
{
- _error = "Invalid IPv6 prefix format.";
- yield return _error!;
+ return _error = "Invalid IPv6 prefix format.";
}
}
- else
+ else if (!IPAddress.TryParse(target, out _))
{
- if (!IPAddress.TryParse(t, out _))
- {
- _error = "Invalid IP address.";
- yield return _error!;
- }
+ return _error = "Invalid IP address.";
}
- if (_durationMinutes <= 0)
- {
- _error = "Duration must be at least 1 minute.";
- yield return _error!;
- }
+ return null;
+ }
+
+ private string? ValidateDuration(int value)
+ {
+ if (value <= 0)
+ return _error = "Duration must be at least 1 minute.";
+
+ return null;
}
private async Task Submit()
{
- await _form.Validate();
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
try
{
- var t = _target!.Trim();
- var dur = TimeSpan.FromMinutes(_durationMinutes);
- var reason = string.IsNullOrWhiteSpace(_reason) ? (_usePrefix ? "MANUAL_PREFIX_BAN" : "MANUAL_BAN") : _reason;
-
- bool ok = _usePrefix
- ? await RateSvc.BanIpv6PrefixAsync(t, dur, _scope, _trueBan, reason)
- : await RateSvc.BanIpAsync(t, dur, _scope, _trueBan, reason);
+ var target = _target!.Trim();
+ var duration = TimeSpan.FromMinutes(_durationMinutes);
+ var reason = string.IsNullOrWhiteSpace(_reason)
+ ? (_usePrefix ? "MANUAL_PREFIX_BAN" : "MANUAL_BAN")
+ : _reason;
+
+ var ok = _usePrefix
+ ? await RateSvc.BanIpv6PrefixAsync(target, duration, _scope, _trueBan, reason)
+ : await RateSvc.BanIpAsync(target, duration, _scope, _trueBan, reason);
if (ok)
{
From 362294cce97647de0a1088ce376ce259a5aa61cb Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:09:11 -0400
Subject: [PATCH 20/27] Migrate add-user validation to async MudForm APIs
---
.../Pages/Settings/Shared/AddUserDialog.razor | 51 ++++++++++++-------
1 file changed, 32 insertions(+), 19 deletions(-)
diff --git a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddUserDialog.razor b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddUserDialog.razor
index 53e1c30..8e2691c 100644
--- a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddUserDialog.razor
+++ b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddUserDialog.razor
@@ -2,10 +2,24 @@
-
-
-
-
+
+
+
+
@if (!string.IsNullOrEmpty(_error))
{
@_error
@@ -29,7 +43,7 @@
}
private MudForm _form = default!;
- private Model _model = new();
+ private readonly Model _model = new();
private string? _error;
private class Model
@@ -39,34 +53,33 @@
public string Confirm { get; set; } = "";
}
- private IEnumerable Validate()
+ private string? ValidateConfirmation(string? value)
{
_error = null;
- if (string.IsNullOrWhiteSpace(_model.UserName))
- yield return "Username is required.";
+ if (string.IsNullOrEmpty(value))
+ return _error = "Please confirm the password.";
- if (string.IsNullOrEmpty(_model.Password))
- yield return "Password is required.";
+ if (_model.Password != value)
+ return _error = "Passwords must match.";
- if (_model.Password != _model.Confirm)
- yield return "Passwords must match.";
+ return null;
}
private void Cancel() => MudDialog.Cancel();
private async Task Submit()
{
- await _form.Validate();
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
- // normalize username to lowercase (your Config also normalizes)
+ // Normalize username to lowercase (Config also normalizes it).
var result = new AddUserResult
- {
- UserName = _model.UserName.Trim().ToLowerInvariant(),
- Password = _model.Password
- };
+ {
+ UserName = _model.UserName.Trim().ToLowerInvariant(),
+ Password = _model.Password
+ };
MudDialog.Close(DialogResult.Ok(result));
}
-}
\ No newline at end of file
+}
From baec649ae732facc4453bcc4a4ae596b546329e4 Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:09:24 -0400
Subject: [PATCH 21/27] Migrate password validation to async MudForm APIs
---
.../Shared/ChangePasswordDialog.razor | 34 +++++++++++++------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/ChangePasswordDialog.razor b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/ChangePasswordDialog.razor
index 07ba96d..06383f3 100644
--- a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/ChangePasswordDialog.razor
+++ b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/ChangePasswordDialog.razor
@@ -2,10 +2,20 @@
-
+
User: @TargetUserName
-
-
+
+
@if (!string.IsNullOrEmpty(_error))
{
@_error
@@ -29,7 +39,7 @@
}
private MudForm _form = default!;
- private Model _model = new();
+ private readonly Model _model = new();
private string? _error;
private class Model
@@ -38,25 +48,27 @@
public string Confirm { get; set; } = "";
}
- private IEnumerable Validate()
+ private string? ValidateConfirmation(string? value)
{
_error = null;
- if (string.IsNullOrEmpty(_model.Password))
- yield return "Password is required.";
+ if (string.IsNullOrEmpty(value))
+ return _error = "Please confirm the password.";
- if (_model.Password != _model.Confirm)
- yield return "Passwords must match.";
+ if (_model.Password != value)
+ return _error = "Passwords must match.";
+
+ return null;
}
private void Cancel() => MudDialog.Cancel();
private async Task Submit()
{
- await _form.Validate();
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
var result = new ChangePasswordResult { NewPassword = _model.Password };
MudDialog.Close(DialogResult.Ok(result));
}
-}
\ No newline at end of file
+}
From 9018affba1f98230f0f635efd267b91b82174ac3 Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:09:38 -0400
Subject: [PATCH 22/27] Migrate domain validation to async MudForm APIs
---
.../Shared/AddOrEditDomainDialog.razor | 87 +++++++++----------
1 file changed, 43 insertions(+), 44 deletions(-)
diff --git a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddOrEditDomainDialog.razor b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddOrEditDomainDialog.razor
index ceeb101..d57b477 100644
--- a/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddOrEditDomainDialog.razor
+++ b/TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/AddOrEditDomainDialog.razor
@@ -3,20 +3,20 @@
-
+
+ @bind-Value="_model.Domain"
+ Immediate="true"
+ Required="true"
+ RequiredError="Domain is required."
+ For="@(() => _model.Domain)" />
+ @bind-Value="_model.UseSSL"
+ Color="Color.Primary"
+ Label="@(_model.UseSSL ? "Enabled" : "Disabled")" />
When enabled, TruthGate provisions a valid Let’s Encrypt certificate for this domain.
@@ -25,16 +25,15 @@
+ @bind-Value="_model.RedirectUrl"
+ Immediate="true"
+ Required="false"
+ For="@(() => _model.RedirectUrl)" />
Leave empty to serve this domain normally.
If a Redirect URL is set, all visitors will be instantly redirected there instead.
-
@if (!string.IsNullOrEmpty(_error))
{
@_error
@@ -85,14 +84,6 @@
public string? RedirectUrl { get; set; }
}
- private IEnumerable Validate()
- {
- _error = null;
-
- if (string.IsNullOrWhiteSpace(_model.Domain))
- yield return "Domain is required.";
- }
-
private void Cancel() => MudDialog.Cancel();
[Inject] IHttpClientFactory HttpFactory { get; set; } = default!;
@@ -100,38 +91,46 @@
private static string ToSafeFolderLeaf(string input)
{
- var s = (input ?? "").Trim().ToLowerInvariant();
- // kill pathy stuff — you only want a single folder leaf here
- s = s.Replace('\\', '/').Trim('/');
- if (s.Contains("..")) throw new InvalidOperationException("Invalid domain.");
- if (string.IsNullOrWhiteSpace(s)) throw new InvalidOperationException("Empty domain.");
- return s;
+ var value = (input ?? "").Trim().ToLowerInvariant();
+ // Kill path-like input — this must remain a single folder leaf.
+ value = value.Replace('\\', '/').Trim('/');
+ if (value.Contains("..")) throw new InvalidOperationException("Invalid domain.");
+ if (string.IsNullOrWhiteSpace(value)) throw new InvalidOperationException("Empty domain.");
+ return value;
}
private async Task Submit()
{
- await _form.Validate();
+ _error = null;
+ await _form.ValidateAsync();
if (!_form.IsValid) return;
- var domainLeaf = ToSafeFolderLeaf(_model.Domain);
- var basePath = "/production/sites";
- var fullPath = $"{basePath}/{domainLeaf}";
+ try
+ {
+ var domainLeaf = ToSafeFolderLeaf(_model.Domain);
+ const string basePath = "/production/sites";
+ var fullPath = $"{basePath}/{domainLeaf}";
- // Ensure the folder path exists (creates parents as needed), returns final CID
- var cid = await IpfsGateway.EnsureMfsFolderExistsAsync(fullPath, HttpFactory);
+ // Ensure the folder path exists (creates parents as needed), returning the final CID.
+ _ = await IpfsGateway.EnsureMfsFolderExistsAsync(fullPath, HttpFactory);
- // (Optional) warm/refresh your cached CID for this MFS path, so the rest of your app sees it:
- var ttl = TimeSpan.FromHours(2);
- _ = await IpfsGateway.GetCidForMfsPathAsync(
+ // Warm/refresh the cached CID so the rest of the app sees the newly created path.
+ var ttl = TimeSpan.FromHours(2);
+ _ = await IpfsGateway.GetCidForMfsPathAsync(
fullPath, HttpFactory, Cache, ttl, IpfsGateway.CacheMode.Refresh);
- var result = new DomainResult
+ var result = new DomainResult
+ {
+ Domain = _model.Domain, // Normalization happens on the page.
+ UseSSL = _model.UseSSL,
+ RedirectUrl = _model.RedirectUrl
+ };
+
+ MudDialog.Close(DialogResult.Ok(result));
+ }
+ catch (Exception ex)
{
- Domain = _model.Domain, // normalization happens on the page
- UseSSL = _model.UseSSL,
- RedirectUrl = _model.RedirectUrl
- };
-
- MudDialog.Close(DialogResult.Ok(result));
+ _error = ex.Message;
+ }
}
}
From 10596be23e120b7ac7354088e9ffa1a300d24a7e Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:10:27 -0400
Subject: [PATCH 23/27] Pin patched SQLite native bundle
---
TruthGate-Web/TruthGate-Web/TruthGate-Web.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/TruthGate-Web/TruthGate-Web/TruthGate-Web.csproj b/TruthGate-Web/TruthGate-Web/TruthGate-Web.csproj
index e416567..d18a0fb 100644
--- a/TruthGate-Web/TruthGate-Web/TruthGate-Web.csproj
+++ b/TruthGate-Web/TruthGate-Web/TruthGate-Web.csproj
@@ -22,6 +22,7 @@
+
From 0b3fb9a01abf5d72d3d4f63e6d1f0e7d949b4171 Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:12:08 -0400
Subject: [PATCH 24/27] Finalize .NET 10 TLS validation workflow
---
.github/workflows/tls-lifecycle.yml | 35 +++++------------------------
1 file changed, 6 insertions(+), 29 deletions(-)
diff --git a/.github/workflows/tls-lifecycle.yml b/.github/workflows/tls-lifecycle.yml
index 9b1e657..386d0bf 100644
--- a/.github/workflows/tls-lifecycle.yml
+++ b/.github/workflows/tls-lifecycle.yml
@@ -33,32 +33,9 @@ jobs:
run: dotnet build TruthGate-IPFS.sln --no-restore --configuration Release
- name: Test TLS lifecycle
- id: test
- shell: bash
- run: |
- set +e
- dotnet test \
- TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj \
- --no-restore \
- --configuration Release \
- --logger "console;verbosity=normal" \
- --diag tls-vstest-diag.log \
- > tls-test-output.log 2>&1
- status=$?
- echo "status=$status" >> "$GITHUB_OUTPUT"
- tail -n 200 tls-test-output.log
- exit 0
-
- - name: Upload test diagnostics
- if: always()
- uses: actions/upload-artifact@v4
- with:
- name: tls-test-output
- path: |
- tls-test-output.log
- tls-vstest-diag.log
- if-no-files-found: error
-
- - name: Report test failure
- if: steps.test.outputs.status != '0'
- run: exit 1
+ run: >-
+ dotnet test
+ TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj
+ --no-restore
+ --configuration Release
+ --logger "console;verbosity=normal"
From 2b4b2e050dba4b86abb15be4df5a22d37283a93e Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:13:14 -0400
Subject: [PATCH 25/27] Remove temporary migration build workflow
---
.github/workflows/net10-migration-build.yml | 65 ---------------------
1 file changed, 65 deletions(-)
delete mode 100644 .github/workflows/net10-migration-build.yml
diff --git a/.github/workflows/net10-migration-build.yml b/.github/workflows/net10-migration-build.yml
deleted file mode 100644
index fcdf3f0..0000000
--- a/.github/workflows/net10-migration-build.yml
+++ /dev/null
@@ -1,65 +0,0 @@
-name: .NET 10 migration build
-
-on:
- push:
- branches:
- - agent/net10-mudblazor-migration
- pull_request:
- branches:
- - magiccodingman/net10
- workflow_dispatch:
-
-permissions:
- contents: write
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout repair branch
- uses: actions/checkout@v4
- with:
- ref: agent/net10-mudblazor-migration
-
- - name: Apply compiler-driven migration fixes
- shell: bash
- run: |
- python3 .github/scripts/apply-net10-migrations.py
- if ! git diff --quiet; then
- git config user.name "github-actions[bot]"
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git add TruthGate-Web
- git commit -m "Finish MudBlazor 9 form and component migrations"
- git push origin HEAD:agent/net10-mudblazor-migration
- fi
-
- - name: Setup .NET 10
- uses: actions/setup-dotnet@v4
- with:
- dotnet-version: 10.0.x
-
- - name: Restore
- run: dotnet restore TruthGate-IPFS.sln
-
- - name: Build
- id: build
- shell: bash
- run: |
- set +e
- dotnet build TruthGate-IPFS.sln --configuration Release --no-restore > net10-build.log 2>&1
- status=$?
- echo "status=$status" >> "$GITHUB_OUTPUT"
- tail -n 200 net10-build.log
- exit 0
-
- - name: Upload build diagnostics
- if: always()
- uses: actions/upload-artifact@v4
- with:
- name: net10-build-log
- path: net10-build.log
- if-no-files-found: error
-
- - name: Report build failure
- if: steps.build.outputs.status != '0'
- run: exit 1
From c36e6a575e34253f905d1c6e4a66aff087cb036b Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:13:20 -0400
Subject: [PATCH 26/27] Remove temporary migration helper script
---
.github/scripts/apply-net10-migrations.py | 170 ----------------------
1 file changed, 170 deletions(-)
delete mode 100644 .github/scripts/apply-net10-migrations.py
diff --git a/.github/scripts/apply-net10-migrations.py b/.github/scripts/apply-net10-migrations.py
deleted file mode 100644
index 957ec3d..0000000
--- a/.github/scripts/apply-net10-migrations.py
+++ /dev/null
@@ -1,170 +0,0 @@
-from pathlib import Path
-
-
-def replace(path: str, old: str, new: str) -> None:
- file = Path(path)
- text = file.read_text(encoding="utf-8-sig")
- if old in text:
- file.write_text(text.replace(old, new), encoding="utf-8")
-
-
-simple_prompt = "TruthGate-Web/TruthGate-Web/Components/Shared/SimplePromptDialog.razor"
-replace(simple_prompt, '', '')
-replace(
- simple_prompt,
- 'Required="@Required"\n Lines=',
- 'Required="@Required"\n Validation="@(new Func(ValidateValue))"\n Lines=',
-)
-replace(
- simple_prompt,
- ''' private IEnumerable Validate()
- {
- _error = null;
- if (Required && string.IsNullOrWhiteSpace(_value))
- {
- _error = "Please enter a value.";
- yield return _error;
- }
- }
-''',
- ''' private string? ValidateValue(string? value)
- {
- _error = null;
- if (Required && string.IsNullOrWhiteSpace(value))
- return _error = "Please enter a value.";
-
- return null;
- }
-''',
-)
-replace(simple_prompt, "await _form.Validate();", "await _form.ValidateAsync();")
-
-add_pinned = "TruthGate-Web/TruthGate-Web/Components/Shared/AddPinnedItemDialog.razor"
-replace(
- add_pinned,
- '',
- '',
-)
-
-add_ipns = "TruthGate-Web/TruthGate-Web/Components/Shared/AddOrEditIpnsDialog.razor"
-replace(
- add_ipns,
- '',
- '',
-)
-replace(
- add_ipns,
- 'Required="true"\n Disabled="_isEdit" />',
- 'Required="true"\n Validation="@(new Func(ValidateName))"\n Disabled="_isEdit" />',
-)
-replace(
- add_ipns,
- 'Label="IPNS Key (k51… or /ipns/k51…)"\n @bind-Value="_model.Key"\n Immediate="true"\n Required="true"\n Validation="@(new Func(ValidateName))"',
- 'Label="IPNS Key (k51… or /ipns/k51…)"\n @bind-Value="_model.Key"\n Immediate="true"\n Required="true"\n Validation="@(new Func(ValidateKey))"',
-)
-replace(
- add_ipns,
- ''' private IEnumerable Validate()
- {
- _error = null;
-
- if (string.IsNullOrWhiteSpace(_model.Name))
- yield return "Name is required.";
- if (string.IsNullOrWhiteSpace(_model.Key))
- yield return "IPNS key is required.";
-
- var leaf = IpfsGateway.ToSafeLeaf(_model.Name);
- if (leaf is null)
- yield return "Invalid name.";
- if (!_model.Key.StartsWith("k51") && !_model.Key.StartsWith("/ipns/"))
- yield return "IPNS Key should look like k51… or /ipns/k51…";
- }
-''',
- ''' private string? ValidateName(string? value)
- {
- if (string.IsNullOrWhiteSpace(value))
- return "Name is required.";
-
- return IpfsGateway.ToSafeLeaf(value) is null ? "Invalid name." : null;
- }
-
- private static string? ValidateKey(string? value)
- {
- if (string.IsNullOrWhiteSpace(value))
- return "IPNS key is required.";
-
- return value.StartsWith("k51", StringComparison.OrdinalIgnoreCase) ||
- value.StartsWith("/ipns/k51", StringComparison.OrdinalIgnoreCase)
- ? null
- : "IPNS Key should look like k51… or /ipns/k51…";
- }
-''',
-)
-replace(add_ipns, "private async void Submit()", "private async Task Submit()")
-replace(add_ipns, "await _form.Validate();", "await _form.ValidateAsync();")
-replace(
- add_ipns,
- '',
- '',
-)
-
-search_ip = "TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Shared/SearchIpDialog.razor"
-replace(search_ip, '', '')
-replace(
- search_ip,
- 'Required="true"\n @onkeydown=',
- 'Required="true"\n Validation="@(new Func(ValidateIp))"\n @onkeydown=',
-)
-replace(
- search_ip,
- ''' private IEnumerable Validate()
- {
- _error = null;
- if (string.IsNullOrWhiteSpace(_ip))
- {
- _error = "Please enter an IP address.";
- yield return _error;
- yield break;
- }
- if (!IPAddress.TryParse(_ip, out _))
- {
- _error = "Invalid IP format (v4 or v6 required).";
- yield return _error;
- }
- }
-''',
- ''' private string? ValidateIp(string? value)
- {
- _error = null;
- if (string.IsNullOrWhiteSpace(value))
- return _error = "Please enter an IP address.";
-
- if (!IPAddress.TryParse(value, out _))
- return _error = "Invalid IP format (v4 or v6 required).";
-
- return null;
- }
-''',
-)
-replace(search_ip, "await _form.Validate();", "await _form.ValidateAsync();")
-replace(search_ip, 'Sortable="false"', 'SortMode="SortMode.None"')
-
-ip_bans = "TruthGate-Web/TruthGate-Web/Components/Pages/Settings/IpBansPage.razor"
-replace(ip_bans, 'Sortable="false"', 'SortMode="SortMode.None"')
-
-domains = "TruthGate-Web/TruthGate-Web/Components/Pages/Settings/Domains.razor"
-replace(
- domains,
- 'Class="truncate-text" Title="@context.RedirectUrl"',
- 'Class="truncate-text" title="@context.RedirectUrl"',
-)
-replace(
- domains,
- 'Color="Color.Primary" Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.Link"',
- 'Color="Color.Primary" Variant="Variant.Outlined" Icon="@Icons.Material.Filled.Link"',
-)
-replace(
- domains,
- 'Color="Color.Primary" Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.Fingerprint"',
- 'Color="Color.Primary" Variant="Variant.Outlined" Icon="@Icons.Material.Filled.Fingerprint"',
-)
From 39adf11c5f9ac24782dd90e57c6cc4b74105631b Mon Sep 17 00:00:00 2001
From: Magic <131926685+magiccodingman@users.noreply.github.com>
Date: Fri, 24 Jul 2026 13:14:09 -0400
Subject: [PATCH 27/27] Document explicit TLS test restore
---
.github/workflows/tls-lifecycle.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/workflows/tls-lifecycle.yml b/.github/workflows/tls-lifecycle.yml
index 386d0bf..3f1191b 100644
--- a/.github/workflows/tls-lifecycle.yml
+++ b/.github/workflows/tls-lifecycle.yml
@@ -26,6 +26,7 @@ jobs:
- name: Restore solution
run: dotnet restore TruthGate-IPFS.sln
+ # This test project is intentionally outside TruthGate-IPFS.sln, so restore it explicitly.
- name: Restore TLS tests
run: dotnet restore TruthGate-Web/TruthGate-Web.Tests/TruthGate-Web.Tests.csproj