Commit graph

3 commits

Author SHA1 Message Date
c3f2408c4a test(blogs): real JwtBearer in fixture, drop X-Test-Role bypass
Wire the Blogs integration test host with a real AddJwtBearer
(HS256, IssuerSigningKey shared with the new TestTokenIssuer) and
the production BlogScope policy verbatim, instead of the
TestAuthPolicyProvider / AllowAllAuthorizationService /
NoopAuthHandler stack that short-circuited every authorization
check.

Why: BlogSpotService.Modify calls
IAuthorizationService.AuthorizeAsync(user, blog, EditPermission);
the previous AllowAllAuthorizationService stub made that a
no-op, so the tests could not exercise the real ownership chain
and any change in PermissionHandler would silently slip through.
The new test host registers the real PermissionHandler, so a PUT
that succeeds (204) is now proof that PermissionHandler.IsOwner
accepted the request — i.e. the JWT's sub matched the post's
AuthorId, end-to-end.

Notes for future-me:
  - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear() is
    called once on the first Issue() to keep the 'sub' claim
    literal; without it UserHelpers.GetUserId (which reads 'sub')
    gets ClaimTypes.NameIdentifier instead, returns null, and the
    owner check fails for every PUT. The companion
    options.MapInboundClaims = false on the validation pipeline
    keeps both sides in sync.
  - Production still uses AddYavscJwtBearer against the OIDC
    authority; the test-only HS256 path is local to the test
    process and never crosses a network boundary.

Coverage:
  - GetBlog_returns_401_when_no_token_is_provided — anonymous
    request, real policy fails closed.
  - PutBlog_with_valid_token_and_owner_returns_204_and_Get_
    reflects_update — POST then PUT then GET, all behind a real
    JWT, asserting 204 + list contains the updated title.

Packages added to Directory.Packages.props at 8.2.1 to match
what Microsoft.AspNetCore.Authentication.JwtBearer 10.0.9 already
transitively pulls in (no version drift).
2026-07-06 23:29:51 +01:00
6d222cf819 fix(blogs): accept JSON on POST /api/v1/blog (no file)
BlogApiController.PostBlog called Request.Form.Files
unconditionally, which throws on a plain JSON body — the
exception is "This request does not have a Content-Type header.
Forms are available from requests with bodies like POSTs and a
form Content-Type of either application/x-www-form-urlencoded or
multipart/form-data."

That broke PostIt's first-bill-of-blog flow: the client posts a
BlogPost as JSON and has no files to attach. The endpoint
contract is [FromBody] BlogPost, so the JSON body is deserialised
into 'blog' as expected — only the IFormFileCollection argument
to BlogSpotService.Create needs a real-or-empty value.

Branch on Request.HasFormContentType: pass the form files when
present, pass an empty FormFileCollection otherwise. BlogSpotService
already short-circuits on a null/empty file collection, so the
JSON-only path is now a clean code path.

Tests: add PostBlog_creates_a_post_and_Get_returns_it_in_the_list
(POST a draft, assert 201 + server-assigned Id, GET the index,
assert exactly one entry with that Id). Add a per-test
ResetDatabase helper because the in-memory store is shared across
the lifetime of the BlogsWebServerFixture instance.
2026-07-06 22:03:41 +01:00
9f5a1505e3 test(blogs): GET /api/v1/blog returns 200 with empty list
First behavioural test for the Yavsc.Blogs API surface. Sends a
GET on the blog index with the X-Test-Role auth bypass and asserts
the response is 200 with an empty JSON array — the in-memory
ApplicationDbContext has no rows, and BlogSpotService.Index returns
an empty enumeration.

While here, fix a routing miss: AddControllers() in the test
fixture was only scanning the test assembly, so BlogApiController
was never registered. Add the Yavsc.Blogs application part
explicitly. Without this, every request to /api/v1/blog came back
as 404 — the same symptom PostIt was seeing in production.

The POST flow lands in the next commit, once BlogApiController is
made to accept JSON (it currently requires multipart/form-data
because of Request.Form.Files).
2026-07-06 21:58:14 +01:00