Release notes — AdvisoryAI envelope-only authentication (sprint SPRINT_20260430_002)
Audit finding closed: docs-archive/qa/audits/microservice-audit-pass2-2026-04-29.md §A2.
What changed
The AdvisoryAI WebService no longer trusts raw identity headers. All identity must arrive via the gateway-signed identity envelope (X-StellaOps-Identity-Envelope + X-StellaOps-Identity-Envelope-Signature, HMAC-SHA256). Specifically:
- Removed. The
AdvisoryAiHeaderAuthenticationHandlerauthentication handler that acceptedX-User-Id,X-Tenant-Id, andX-StellaOps-Scopesas authoritative identity has been deleted outright. There is no configuration toggle to re-enable it. - Added.
UseIdentityEnvelopeAuthentication()fromStellaOps.Router.AspNetis wired into the AdvisoryAI WebService pipeline beforeUseAuthentication(). A new thin scheme,AdvisoryAiEnvelopeAuthenticationHandler, surfaces the envelope-validated principal to ASP.NET authorization. - Added.
InboundIdentityHeaderStripMiddlewareremovesX-User-Id,X-Tenant-Id,X-StellaOps-Actor,X-StellaOps-Scopes,X-StellaOps-TenantId,X-Stella-Scopes, andX-Scopesfrom every inbound request before authentication runs. The strip is unconditional and applies in everyASPNETCORE_ENVIRONMENT. - Updated.
AdvisoryAIPoliciesand the handler-internalEnsureAuthorized/EnsureExplainAuthorized/EnsureRemediationAuthorized/EnsurePolicyAuthorized/EnsureJustifyAuthorized/EnsureChatAuthorizedhelpers, plus theGetTenantId/GetUserIdhelpers inProgram.csandEvidencePackEndpoints.cs, now read scopes / tenant / subject from the envelope-derivedClaimsPrincipal. The legacy “advisory:run” / “advisory:explain” / “advisory:remediate” / “advisory:justify” / etc. scope vocabulary is still honored alongside the canonicaladvisory-ai:view/advisory-ai:operate/advisory-ai:adminscopes.
Behavioral consequences (breaking)
- A request without a valid signed envelope is rejected with HTTP 401 by
RequireAuthorization. Previously, a request with the right legacy headers was authenticated as the requested actor; that path is gone. - A request that includes a valid envelope and also sets
X-User-Id/X-Tenant-Id/X-StellaOps-Scopesis authenticated solely from the envelope; the raw headers are stripped before any handler observes them. - Internal callers (CLI, smoke scripts, ad-hoc curl) that send only raw identity headers must now route through the gateway. Direct-to-pod calls without an envelope are rejected.
Tests
AdvisoryAiAuthIntegrationTests (12 scenarios, all green) covers:
- 401 without envelope (
outputs/{cacheKey},pipeline/{taskType},explain, raw-header-only). - 200/202/… with valid envelope across the same paths.
- Defense-in-depth: forged
X-User-Idalongside a valid envelope authenticates as the envelope subject. - 401 for expired envelope and bad-signature envelope.
- Strip middleware verified in
Development,Testing, andProductionvia a focused test of the middleware itself (no full-app boot needed in Production because AdvisoryAI’s runtime persistence guard is unrelated to the security boundary under test).
Migration guide
If your client previously called AdvisoryAI directly with raw identity headers, update it to either:
- Route the request through the StellaOps gateway, which issues a signed envelope from a verified bearer token, or
- (For internal/test callers) construct and sign a
GatewayIdentityEnvelopeusingStellaOps.Router.Common.Identity.GatewayIdentityEnvelopeCodec.Sign(...)with the configuredRouter:IdentityEnvelopeSigningKey/STELLAOPS_IDENTITY_ENVELOPE_SIGNING_KEYand attach the resultingX-StellaOps-Identity-EnvelopeandX-StellaOps-Identity-Envelope-Signatureheaders.
