feat(release): prepare 1.1.0 candidate
This commit is contained in:
parent
5a34f66981
commit
5205dcdfa9
736 changed files with 115667 additions and 12203 deletions
100
apps/api-server.Tests/SttGatewayAuthorizationE2ETests.cs
Normal file
100
apps/api-server.Tests/SttGatewayAuthorizationE2ETests.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Xunit;
|
||||
|
||||
namespace D3ROVoice.Api.Tests;
|
||||
|
||||
[Collection("Api server integration")]
|
||||
public sealed class SttGatewayAuthorizationE2ETests : IClassFixture<AdminAuthorizationE2ETests.ApiFactory>
|
||||
{
|
||||
private const string Secret = "admin-e2e-jwt-secret-0123456789-abcdef";
|
||||
private const string Issuer = "https://admin-e2e.test";
|
||||
private const string Audience = "d3ro-admin-e2e";
|
||||
private const string GatewayToken = "fixture-internal-gateway-token-32-bytes-minimum";
|
||||
private readonly AdminAuthorizationE2ETests.ApiFactory _factory;
|
||||
|
||||
public SttGatewayAuthorizationE2ETests(AdminAuthorizationE2ETests.ApiFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserEndpointRequiresJwtThenStillRefusesQuotaBypass()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
using var anonymousBody = JsonBody();
|
||||
Assert.Equal(HttpStatusCode.Unauthorized,
|
||||
(await client.PostAsync("/api/stt/transcribe", anonymousBody)).StatusCode);
|
||||
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", UserToken());
|
||||
using var authenticatedBody = JsonBody();
|
||||
var response = await client.PostAsync("/api/stt/transcribe", authenticatedBody);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Gone, response.StatusCode);
|
||||
Assert.Contains("stt_edge_gateway_required", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("one-character-off")]
|
||||
public async Task InternalEndpointRejectsMissingOrWrongGatewaySecret(string? suppliedToken)
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
if (suppliedToken != null)
|
||||
client.DefaultRequestHeaders.Add("X-D3RO-STT-Gateway-Token", suppliedToken);
|
||||
using var body = AudioBody();
|
||||
|
||||
var response = await client.PostAsync("/api/stt/internal/transcribe", body);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Contains("stt_gateway_unauthorized", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InternalEndpointAcceptsExactSecretButFailsClosedWithoutProvider()
|
||||
{
|
||||
using var client = _factory.CreateClient();
|
||||
client.DefaultRequestHeaders.Add("X-D3RO-STT-Gateway-Token", GatewayToken);
|
||||
using var body = AudioBody();
|
||||
|
||||
var response = await client.PostAsync("/api/stt/internal/transcribe", body);
|
||||
|
||||
Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
|
||||
Assert.Contains("stt_provider_unavailable", await response.Content.ReadAsStringAsync(), StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static StringContent JsonBody() =>
|
||||
new("{\"audioBase64\":\"AQID\"}", Encoding.UTF8, "application/json");
|
||||
|
||||
private static MultipartFormDataContent AudioBody()
|
||||
{
|
||||
var body = new MultipartFormDataContent();
|
||||
var audio = new ByteArrayContent([1, 2, 3, 4]);
|
||||
audio.Headers.ContentType = new MediaTypeHeaderValue("audio/wav");
|
||||
body.Add(audio, "file", "fixture.wav");
|
||||
return body;
|
||||
}
|
||||
|
||||
private static string UserToken()
|
||||
{
|
||||
var credentials = new SigningCredentials(
|
||||
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Secret)),
|
||||
SecurityAlgorithms.HmacSha256);
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: Issuer,
|
||||
audience: Audience,
|
||||
claims:
|
||||
[
|
||||
new Claim(ClaimTypes.NameIdentifier, "1"),
|
||||
new Claim(ClaimTypes.Email, "user@example.com"),
|
||||
new Claim(ClaimTypes.Role, "user")
|
||||
],
|
||||
expires: DateTime.UtcNow.AddMinutes(5),
|
||||
signingCredentials: credentials);
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue