Tests fixes, audit progress, UI completions
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
# Auth Abstractions Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: unit coverage for scopes, claims, principal builder, network masks, and problem responses.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs, stable ordering).
|
||||
- Use explicit assertions for scope lists and network mask behavior.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Add edge-case coverage for parsing and canonicalization.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Abstractions Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0079-M | DONE | Maintainability audit for StellaOps.Auth.Abstractions.Tests. |
|
||||
| AUDIT-0079-T | DONE | Test coverage audit for StellaOps.Auth.Abstractions.Tests. |
|
||||
| AUDIT-0079-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Auth Abstractions AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: shared auth scopes, claim types, problem responses, and network mask utilities.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep auth identifiers deterministic and stable (no implicit ordering changes).
|
||||
- Preserve offline posture (no network calls).
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover scope normalization, network masks, principal builder behavior, and problem responses.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Abstractions Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0078-M | DONE | Maintainability audit for StellaOps.Auth.Abstractions. |
|
||||
| AUDIT-0078-T | DONE | Test coverage audit for StellaOps.Auth.Abstractions. |
|
||||
| AUDIT-0078-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Auth Client Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.Client.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: unit coverage for auth client options, caches, and auth handlers.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs, stable ordering).
|
||||
- Avoid live network calls and file system leakage; clean temp artifacts.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover token caches, discovery/JWKS fallback, and bearer handler modes.
|
||||
@@ -77,7 +77,7 @@ public class ServiceCollectionExtensionsTests
|
||||
Assert.Equal(new Uri("https://authority.test/connect/token"), configuration.TokenEndpoint);
|
||||
Assert.Equal(2, attemptCount);
|
||||
Assert.NotEmpty(recordedHandlers);
|
||||
Assert.Contains(recordedHandlers, handler => handler.GetType().Name.Contains("PolicyHttpMessageHandler", StringComparison.Ordinal));
|
||||
Assert.Contains(recordedHandlers, handler => handler.GetType().Name.Contains("ResilienceHandler", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Client Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0081-M | DONE | Maintainability audit for StellaOps.Auth.Client.Tests. |
|
||||
| AUDIT-0081-T | DONE | Test coverage audit for StellaOps.Auth.Client.Tests. |
|
||||
| AUDIT-0081-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,23 @@
|
||||
# Auth Client AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.Client/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: token acquisition, discovery/JWKS caching, and auth handler integration.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep token flows deterministic and time-aware (TimeProvider, skew handling).
|
||||
- Respect offline/air-gap posture and egress policy checks.
|
||||
- Avoid leaking sensitive credentials in logs.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover discovery/JWKS caches, token client error paths, and auth handler behavior.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Client Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0080-M | DONE | Maintainability audit for StellaOps.Auth.Client. |
|
||||
| AUDIT-0080-T | DONE | Test coverage audit for StellaOps.Auth.Client. |
|
||||
| AUDIT-0080-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Auth Server Integration Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: resource server options, policy registration, bypass evaluation, and scope authorization behavior.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs, stable ordering).
|
||||
- Avoid live network calls; use fakes for metadata/JWKS retrieval.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover options validation, bypass deny paths, scope normalization, and audit event emission.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Server Integration Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0084-M | DONE | Maintainability audit for StellaOps.Auth.ServerIntegration.Tests. |
|
||||
| AUDIT-0084-T | DONE | Test coverage audit for StellaOps.Auth.ServerIntegration.Tests. |
|
||||
| AUDIT-0084-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,23 @@
|
||||
# Auth Server Integration AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: ASP.NET Core resource server auth configuration, scope policies, and authorization audit events.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep auth decisions deterministic and time-aware (TimeProvider).
|
||||
- Preserve offline/air-gap posture with resilient metadata/JWKS caching.
|
||||
- Avoid logging sensitive claims; use classified strings.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover options normalization, bypass evaluation, metadata/JWKS caching, scope decisions, and audit event emission.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Auth Server Integration Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0083-M | DONE | Maintainability audit for StellaOps.Auth.ServerIntegration. |
|
||||
| AUDIT-0083-T | DONE | Test coverage audit for StellaOps.Auth.ServerIntegration. |
|
||||
| AUDIT-0083-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority LDAP Plugin Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Ldap.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: LDAP plugin test coverage, fixtures, and determinism.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs); avoid real LDAP network access.
|
||||
- Prefer exercising production code paths over duplicated test-only logic.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit fakes.
|
||||
- Tag integration/snapshot tests appropriately and keep fixtures stable.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority LDAP Plugin Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0091-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Ldap.Tests. |
|
||||
| AUDIT-0091-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Ldap.Tests. |
|
||||
| AUDIT-0091-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority LDAP Plugin AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Ldap/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: LDAP identity provider plugin, connection factory, claims enrichment, and client provisioning.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Preserve TLS and credential handling guarantees; avoid weakening defaults.
|
||||
- Keep timeouts and bind flows configurable; avoid hidden sync-over-async paths.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit fakes; avoid real LDAP network access.
|
||||
- Cover health checks, capability probing, and error/timeout paths deterministically.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority LDAP Plugin Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0090-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Ldap. |
|
||||
| AUDIT-0090-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Ldap. |
|
||||
| AUDIT-0090-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority OIDC Plugin Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Oidc.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: OIDC plugin test coverage, fixtures, and determinism.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs); avoid live OIDC metadata calls.
|
||||
- Prefer exercising production code paths over test-only simulations.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + local fixtures.
|
||||
- Tag snapshot and security tests appropriately and keep fixtures stable.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority OIDC Plugin Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0093-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Oidc.Tests. |
|
||||
| AUDIT-0093-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Oidc.Tests. |
|
||||
| AUDIT-0093-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority OIDC Plugin AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Oidc/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: OIDC identity provider plugin, token validation, metadata retrieval, and claims mapping.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Preserve offline/air-gap posture; avoid implicit external calls without explicit configuration.
|
||||
- Use IHttpClientFactory and configurable timeouts; avoid new HttpClient per call.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + deterministic token fixtures.
|
||||
- Avoid live OIDC network calls; mock metadata retrieval and token validation.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority OIDC Plugin Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0092-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Oidc. |
|
||||
| AUDIT-0092-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Oidc. |
|
||||
| AUDIT-0092-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority SAML Plugin Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Saml.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: SAML plugin test coverage, fixtures, and determinism.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs); avoid live IdP metadata calls.
|
||||
- Prefer exercising production code paths over test-only simulations.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + fixture XML.
|
||||
- Tag snapshot and security tests appropriately and keep fixtures stable.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority SAML Plugin Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0095-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Saml.Tests. |
|
||||
| AUDIT-0095-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Saml.Tests. |
|
||||
| AUDIT-0095-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,23 @@
|
||||
# Authority SAML Plugin AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Saml/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: SAML identity provider plugin, assertion validation, metadata/certificate handling, and claims mapping.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Preserve offline/air-gap posture; avoid implicit external calls without explicit configuration.
|
||||
- Use IHttpClientFactory and configurable timeouts; avoid new HttpClient per call.
|
||||
- Harden XML parsing (no DTD/XXE) and keep assertion validation deterministic.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions with deterministic fixture XML.
|
||||
- Avoid live IdP network calls; mock metadata/cert retrieval.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority SAML Plugin Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0094-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Saml. |
|
||||
| AUDIT-0094-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Saml. |
|
||||
| AUDIT-0094-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,21 @@
|
||||
# Authority Standard Plugin Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugin.Standard.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: Standard plugin test coverage, credential flows, and determinism.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs); avoid external network calls.
|
||||
- Prefer exercising production code paths over test-only simulations.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit helpers.
|
||||
- Cover credential flows, lockouts, bootstrap behavior, and client provisioning.
|
||||
@@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Authority.InMemoryDriver;
|
||||
using StellaOps.Authority.Persistence.Postgres.Repositories;
|
||||
using StellaOps.Authority.Plugins.Abstractions;
|
||||
using StellaOps.Authority.Plugin.Standard;
|
||||
using StellaOps.Authority.Plugin.Standard.Bootstrap;
|
||||
@@ -16,16 +17,16 @@ using StellaOps.Authority.Plugin.Standard.Storage;
|
||||
using StellaOps.Authority.Persistence.Documents;
|
||||
using StellaOps.Authority.Persistence.InMemory.Stores;
|
||||
using StellaOps.Authority.Persistence.Sessions;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography.Audit;
|
||||
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Authority.Plugin.Standard.Tests;
|
||||
|
||||
public class StandardPluginRegistrarTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task Register_ConfiguresIdentityProviderAndSeedsBootstrapUser()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
@@ -58,10 +59,11 @@ public class StandardPluginRegistrarTests
|
||||
"standard.yaml");
|
||||
|
||||
var pluginContext = new AuthorityPluginContext(manifest, configuration);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database, configuration);
|
||||
|
||||
var registrar = new StandardPluginRegistrar();
|
||||
registrar.Register(new AuthorityPluginRegistrationContext(services, pluginContext, configuration));
|
||||
services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider());
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var hostedServices = provider.GetServices<IHostedService>();
|
||||
@@ -88,7 +90,7 @@ public class StandardPluginRegistrarTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Register_LogsWarning_WhenPasswordPolicyWeaker()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
@@ -116,12 +118,13 @@ public class StandardPluginRegistrarTests
|
||||
"standard.yaml");
|
||||
|
||||
var pluginContext = new AuthorityPluginContext(manifest, configuration);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database, configuration);
|
||||
var loggerProvider = new CapturingLoggerProvider();
|
||||
services.AddLogging(builder => builder.AddProvider(loggerProvider));
|
||||
|
||||
var registrar = new StandardPluginRegistrar();
|
||||
registrar.Register(new AuthorityPluginRegistrationContext(services, pluginContext, configuration));
|
||||
services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider());
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
using var scope = provider.CreateScope();
|
||||
@@ -134,7 +137,7 @@ public class StandardPluginRegistrarTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Register_ForcesPasswordCapability_WhenManifestMissing()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
@@ -152,10 +155,11 @@ public class StandardPluginRegistrarTests
|
||||
"standard.yaml");
|
||||
|
||||
var pluginContext = new AuthorityPluginContext(manifest, configuration);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database, configuration);
|
||||
|
||||
var registrar = new StandardPluginRegistrar();
|
||||
registrar.Register(new AuthorityPluginRegistrationContext(services, pluginContext, configuration));
|
||||
services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider());
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
using var scope = provider.CreateScope();
|
||||
@@ -167,7 +171,7 @@ public class StandardPluginRegistrarTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Register_Throws_WhenBootstrapConfigurationIncomplete()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
@@ -191,10 +195,11 @@ public class StandardPluginRegistrarTests
|
||||
"standard.yaml");
|
||||
|
||||
var pluginContext = new AuthorityPluginContext(manifest, configuration);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database, configuration);
|
||||
|
||||
var registrar = new StandardPluginRegistrar();
|
||||
registrar.Register(new AuthorityPluginRegistrationContext(services, pluginContext, configuration));
|
||||
services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider());
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
using var scope = provider.CreateScope();
|
||||
@@ -202,7 +207,7 @@ public class StandardPluginRegistrarTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Register_NormalizesTokenSigningKeyDirectory()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
@@ -232,11 +237,12 @@ public class StandardPluginRegistrarTests
|
||||
configPath);
|
||||
|
||||
var pluginContext = new AuthorityPluginContext(manifest, configuration);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database);
|
||||
var services = StandardPluginRegistrarTestHelpers.CreateServiceCollection(database, configuration);
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
|
||||
var registrar = new StandardPluginRegistrar();
|
||||
registrar.Register(new AuthorityPluginRegistrationContext(services, pluginContext, configuration));
|
||||
services.AddSingleton<ICryptoProvider>(new DefaultCryptoProvider());
|
||||
|
||||
using var provider = services.BuildServiceProvider();
|
||||
var optionsMonitor = provider.GetRequiredService<IOptionsMonitor<StandardPluginOptions>>();
|
||||
@@ -398,6 +404,7 @@ internal static class StandardPluginRegistrarTestHelpers
|
||||
{
|
||||
public static ServiceCollection CreateServiceCollection(
|
||||
IDatabase database,
|
||||
IConfiguration? configuration = null,
|
||||
IAuthEventSink? authEventSink = null,
|
||||
IAuthorityCredentialAuditContextAccessor? auditContextAccessor = null)
|
||||
{
|
||||
@@ -405,10 +412,12 @@ internal static class StandardPluginRegistrarTestHelpers
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddSingleton(configuration ?? new ConfigurationBuilder().Build());
|
||||
services.AddSingleton(database);
|
||||
services.AddSingleton<IAuthorityClientStore>(new InMemoryClientStore());
|
||||
services.AddSingleton<IAuthorityRevocationStore>(new StubRevocationStore());
|
||||
services.AddSingleton<IAuthorityLoginAttemptStore>(new InMemoryLoginAttemptStore());
|
||||
services.AddSingleton<IUserRepository>(new InMemoryUserRepository());
|
||||
services.AddSingleton(TimeProvider.System);
|
||||
services.AddSingleton<IAuthorityCredentialAuditContextAccessor>(
|
||||
auditContextAccessor ?? new TestAuthorityCredentialAuditContextAccessor());
|
||||
|
||||
@@ -2,12 +2,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using StellaOps.Authority.InMemoryDriver;
|
||||
using StellaOps.Authority.Persistence.Postgres.Repositories;
|
||||
using StellaOps.Authority.Persistence.Postgres.Models;
|
||||
using StellaOps.Authority.Plugins.Abstractions;
|
||||
using StellaOps.Authority.Plugin.Standard.Security;
|
||||
using StellaOps.Authority.Plugin.Standard.Storage;
|
||||
@@ -15,20 +14,18 @@ using StellaOps.Cryptography;
|
||||
using StellaOps.Cryptography.Audit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
|
||||
namespace StellaOps.Authority.Plugin.Standard.Tests;
|
||||
|
||||
public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
{
|
||||
private readonly IDatabase database;
|
||||
private readonly InMemoryUserRepository userRepository;
|
||||
private readonly StandardPluginOptions options;
|
||||
private readonly StandardUserCredentialStore store;
|
||||
private readonly TestAuditLogger auditLogger;
|
||||
private readonly Mock<IUserRepository> userRepositoryMock;
|
||||
|
||||
public StandardUserCredentialStoreTests()
|
||||
{
|
||||
var client = new InMemoryClient();
|
||||
database = client.GetDatabase("authority-tests");
|
||||
options = new StandardPluginOptions
|
||||
{
|
||||
PasswordPolicy = new PasswordPolicyOptions
|
||||
@@ -55,11 +52,11 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
};
|
||||
var cryptoProvider = new DefaultCryptoProvider();
|
||||
auditLogger = new TestAuditLogger();
|
||||
userRepositoryMock = new Mock<IUserRepository>();
|
||||
userRepository = new InMemoryUserRepository();
|
||||
store = new StandardUserCredentialStore(
|
||||
"standard",
|
||||
"test-tenant",
|
||||
userRepositoryMock.Object,
|
||||
userRepository,
|
||||
options,
|
||||
new CryptoPasswordHasher(options, cryptoProvider),
|
||||
auditLogger,
|
||||
@@ -67,7 +64,7 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task VerifyPasswordAsync_ReturnsSuccess_ForValidCredentials()
|
||||
{
|
||||
auditLogger.Reset();
|
||||
@@ -95,7 +92,7 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task VerifyPasswordAsync_EnforcesLockout_AfterRepeatedFailures()
|
||||
{
|
||||
auditLogger.Reset();
|
||||
@@ -144,7 +141,7 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task VerifyPasswordAsync_RehashesLegacyHashesToArgon2()
|
||||
{
|
||||
auditLogger.Reset();
|
||||
@@ -156,19 +153,24 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
Iterations = 160_000
|
||||
});
|
||||
|
||||
var document = new StandardUserDocument
|
||||
await userRepository.CreateAsync(new UserEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = "test-tenant",
|
||||
Username = "legacy",
|
||||
NormalizedUsername = "legacy",
|
||||
Email = "legacy@local",
|
||||
DisplayName = "Legacy",
|
||||
PasswordHash = legacyHash,
|
||||
Roles = new List<string>(),
|
||||
Attributes = new Dictionary<string, string?>(),
|
||||
CreatedAt = DateTimeOffset.UtcNow.AddDays(-1),
|
||||
UpdatedAt = DateTimeOffset.UtcNow.AddDays(-1)
|
||||
};
|
||||
|
||||
await database.GetCollection<StandardUserDocument>("authority_users_standard")
|
||||
.InsertOneAsync(document);
|
||||
PasswordSalt = "",
|
||||
Enabled = true,
|
||||
Metadata = JsonSerializer.Serialize(new Dictionary<string, object?>
|
||||
{
|
||||
["subjectId"] = "legacy",
|
||||
["roles"] = new List<string>(),
|
||||
["attributes"] = new Dictionary<string, string?>(),
|
||||
["requirePasswordReset"] = false
|
||||
})
|
||||
});
|
||||
|
||||
var result = await store.VerifyPasswordAsync("legacy", "Legacy1!", CancellationToken.None);
|
||||
|
||||
@@ -180,16 +182,14 @@ public class StandardUserCredentialStoreTests : IAsyncLifetime
|
||||
Assert.True(auditEntry.Success);
|
||||
Assert.Equal("legacy", auditEntry.Username);
|
||||
|
||||
var results = await database.GetCollection<StandardUserDocument>("authority_users_standard")
|
||||
.FindAsync(u => u.NormalizedUsername == "legacy");
|
||||
var updated = results.FirstOrDefault();
|
||||
var updated = await userRepository.GetByUsernameAsync("test-tenant", "legacy", CancellationToken.None);
|
||||
|
||||
Assert.NotNull(updated);
|
||||
Assert.StartsWith("$argon2id$", updated!.PasswordHash, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task VerifyPasswordAsync_RecordsAudit_ForUnknownUser()
|
||||
{
|
||||
auditLogger.Reset();
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Standard Plugin Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0097-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Standard.Tests. |
|
||||
| AUDIT-0097-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Standard.Tests. |
|
||||
| AUDIT-0097-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,281 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Authority.Persistence.Postgres.Models;
|
||||
using StellaOps.Authority.Persistence.Postgres.Repositories;
|
||||
|
||||
namespace StellaOps.Authority.Plugin.Standard.Tests;
|
||||
|
||||
internal sealed class InMemoryUserRepository : IUserRepository
|
||||
{
|
||||
private readonly Dictionary<Guid, UserEntity> users = new();
|
||||
private readonly Dictionary<string, Guid> byUsername = new(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, Guid> byEmail = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public Task<UserEntity> CreateAsync(UserEntity user, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var created = new UserEntity
|
||||
{
|
||||
Id = user.Id,
|
||||
TenantId = user.TenantId,
|
||||
Username = user.Username,
|
||||
Email = user.Email,
|
||||
DisplayName = user.DisplayName,
|
||||
PasswordHash = user.PasswordHash,
|
||||
PasswordSalt = user.PasswordSalt,
|
||||
Enabled = user.Enabled,
|
||||
EmailVerified = user.EmailVerified,
|
||||
MfaEnabled = user.MfaEnabled,
|
||||
MfaSecret = user.MfaSecret,
|
||||
MfaBackupCodes = user.MfaBackupCodes,
|
||||
FailedLoginAttempts = user.FailedLoginAttempts,
|
||||
LockedUntil = user.LockedUntil,
|
||||
LastLoginAt = user.LastLoginAt,
|
||||
PasswordChangedAt = user.PasswordChangedAt,
|
||||
Settings = string.IsNullOrWhiteSpace(user.Settings) ? "{}" : user.Settings,
|
||||
Metadata = string.IsNullOrWhiteSpace(user.Metadata) ? "{}" : user.Metadata,
|
||||
CreatedAt = user.CreatedAt == default ? now : user.CreatedAt,
|
||||
UpdatedAt = user.UpdatedAt == default ? now : user.UpdatedAt,
|
||||
CreatedBy = user.CreatedBy
|
||||
};
|
||||
|
||||
users[created.Id] = created;
|
||||
byUsername[GetUsernameKey(created.TenantId, created.Username)] = created.Id;
|
||||
byEmail[GetEmailKey(created.TenantId, created.Email)] = created.Id;
|
||||
|
||||
return Task.FromResult(created);
|
||||
}
|
||||
|
||||
public Task<UserEntity?> GetByIdAsync(string tenantId, Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (users.TryGetValue(id, out var user) && string.Equals(user.TenantId, tenantId, StringComparison.Ordinal))
|
||||
{
|
||||
return Task.FromResult<UserEntity?>(user);
|
||||
}
|
||||
|
||||
return Task.FromResult<UserEntity?>(null);
|
||||
}
|
||||
|
||||
public Task<UserEntity?> GetByUsernameAsync(string tenantId, string username, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var key = GetUsernameKey(tenantId, username);
|
||||
if (byUsername.TryGetValue(key, out var id) && users.TryGetValue(id, out var user))
|
||||
{
|
||||
return Task.FromResult<UserEntity?>(user);
|
||||
}
|
||||
|
||||
return Task.FromResult<UserEntity?>(null);
|
||||
}
|
||||
|
||||
public Task<UserEntity?> GetByEmailAsync(string tenantId, string email, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var key = GetEmailKey(tenantId, email);
|
||||
if (byEmail.TryGetValue(key, out var id) && users.TryGetValue(id, out var user))
|
||||
{
|
||||
return Task.FromResult<UserEntity?>(user);
|
||||
}
|
||||
|
||||
return Task.FromResult<UserEntity?>(null);
|
||||
}
|
||||
|
||||
public Task<IReadOnlyList<UserEntity>> GetAllAsync(
|
||||
string tenantId,
|
||||
bool? enabled = null,
|
||||
int limit = 100,
|
||||
int offset = 0,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var results = users.Values
|
||||
.Where(u => string.Equals(u.TenantId, tenantId, StringComparison.Ordinal))
|
||||
.Where(u => enabled is null || u.Enabled == enabled.Value)
|
||||
.OrderBy(u => u.Username, StringComparer.OrdinalIgnoreCase)
|
||||
.Skip(offset)
|
||||
.Take(limit)
|
||||
.ToList();
|
||||
|
||||
return Task.FromResult<IReadOnlyList<UserEntity>>(results);
|
||||
}
|
||||
|
||||
public Task<bool> UpdateAsync(UserEntity user, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!users.TryGetValue(user.Id, out var existing))
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var updated = new UserEntity
|
||||
{
|
||||
Id = user.Id,
|
||||
TenantId = user.TenantId,
|
||||
Username = user.Username,
|
||||
Email = user.Email,
|
||||
DisplayName = user.DisplayName,
|
||||
PasswordHash = user.PasswordHash,
|
||||
PasswordSalt = user.PasswordSalt,
|
||||
Enabled = user.Enabled,
|
||||
EmailVerified = user.EmailVerified,
|
||||
MfaEnabled = user.MfaEnabled,
|
||||
MfaSecret = user.MfaSecret,
|
||||
MfaBackupCodes = user.MfaBackupCodes,
|
||||
FailedLoginAttempts = user.FailedLoginAttempts,
|
||||
LockedUntil = user.LockedUntil,
|
||||
LastLoginAt = user.LastLoginAt,
|
||||
PasswordChangedAt = user.PasswordChangedAt,
|
||||
Settings = string.IsNullOrWhiteSpace(user.Settings) ? existing.Settings : user.Settings,
|
||||
Metadata = string.IsNullOrWhiteSpace(user.Metadata) ? existing.Metadata : user.Metadata,
|
||||
CreatedAt = existing.CreatedAt,
|
||||
UpdatedAt = now,
|
||||
CreatedBy = user.CreatedBy ?? existing.CreatedBy
|
||||
};
|
||||
|
||||
users[updated.Id] = updated;
|
||||
byUsername[GetUsernameKey(updated.TenantId, updated.Username)] = updated.Id;
|
||||
byEmail[GetEmailKey(updated.TenantId, updated.Email)] = updated.Id;
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public Task<bool> DeleteAsync(string tenantId, Guid id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (users.TryGetValue(id, out var user) && string.Equals(user.TenantId, tenantId, StringComparison.Ordinal))
|
||||
{
|
||||
users.Remove(id);
|
||||
byUsername.Remove(GetUsernameKey(user.TenantId, user.Username));
|
||||
byEmail.Remove(GetEmailKey(user.TenantId, user.Email));
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public Task<bool> UpdatePasswordAsync(
|
||||
string tenantId,
|
||||
Guid userId,
|
||||
string passwordHash,
|
||||
string passwordSalt,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!users.TryGetValue(userId, out var existing) || !string.Equals(existing.TenantId, tenantId, StringComparison.Ordinal))
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var updated = new UserEntity
|
||||
{
|
||||
Id = existing.Id,
|
||||
TenantId = existing.TenantId,
|
||||
Username = existing.Username,
|
||||
Email = existing.Email,
|
||||
DisplayName = existing.DisplayName,
|
||||
PasswordHash = passwordHash,
|
||||
PasswordSalt = passwordSalt,
|
||||
Enabled = existing.Enabled,
|
||||
EmailVerified = existing.EmailVerified,
|
||||
MfaEnabled = existing.MfaEnabled,
|
||||
MfaSecret = existing.MfaSecret,
|
||||
MfaBackupCodes = existing.MfaBackupCodes,
|
||||
FailedLoginAttempts = existing.FailedLoginAttempts,
|
||||
LockedUntil = existing.LockedUntil,
|
||||
LastLoginAt = existing.LastLoginAt,
|
||||
PasswordChangedAt = now,
|
||||
Settings = existing.Settings,
|
||||
Metadata = existing.Metadata,
|
||||
CreatedAt = existing.CreatedAt,
|
||||
UpdatedAt = now,
|
||||
CreatedBy = existing.CreatedBy
|
||||
};
|
||||
|
||||
users[updated.Id] = updated;
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public Task<int> RecordFailedLoginAsync(
|
||||
string tenantId,
|
||||
Guid userId,
|
||||
DateTimeOffset? lockUntil = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!users.TryGetValue(userId, out var existing) || !string.Equals(existing.TenantId, tenantId, StringComparison.Ordinal))
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var attempts = existing.FailedLoginAttempts + 1;
|
||||
var updated = new UserEntity
|
||||
{
|
||||
Id = existing.Id,
|
||||
TenantId = existing.TenantId,
|
||||
Username = existing.Username,
|
||||
Email = existing.Email,
|
||||
DisplayName = existing.DisplayName,
|
||||
PasswordHash = existing.PasswordHash,
|
||||
PasswordSalt = existing.PasswordSalt,
|
||||
Enabled = existing.Enabled,
|
||||
EmailVerified = existing.EmailVerified,
|
||||
MfaEnabled = existing.MfaEnabled,
|
||||
MfaSecret = existing.MfaSecret,
|
||||
MfaBackupCodes = existing.MfaBackupCodes,
|
||||
FailedLoginAttempts = attempts,
|
||||
LockedUntil = lockUntil,
|
||||
LastLoginAt = existing.LastLoginAt,
|
||||
PasswordChangedAt = existing.PasswordChangedAt,
|
||||
Settings = existing.Settings,
|
||||
Metadata = existing.Metadata,
|
||||
CreatedAt = existing.CreatedAt,
|
||||
UpdatedAt = now,
|
||||
CreatedBy = existing.CreatedBy
|
||||
};
|
||||
|
||||
users[updated.Id] = updated;
|
||||
return Task.FromResult(attempts);
|
||||
}
|
||||
|
||||
public Task RecordSuccessfulLoginAsync(string tenantId, Guid userId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!users.TryGetValue(userId, out var existing) || !string.Equals(existing.TenantId, tenantId, StringComparison.Ordinal))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var updated = new UserEntity
|
||||
{
|
||||
Id = existing.Id,
|
||||
TenantId = existing.TenantId,
|
||||
Username = existing.Username,
|
||||
Email = existing.Email,
|
||||
DisplayName = existing.DisplayName,
|
||||
PasswordHash = existing.PasswordHash,
|
||||
PasswordSalt = existing.PasswordSalt,
|
||||
Enabled = existing.Enabled,
|
||||
EmailVerified = existing.EmailVerified,
|
||||
MfaEnabled = existing.MfaEnabled,
|
||||
MfaSecret = existing.MfaSecret,
|
||||
MfaBackupCodes = existing.MfaBackupCodes,
|
||||
FailedLoginAttempts = 0,
|
||||
LockedUntil = null,
|
||||
LastLoginAt = now,
|
||||
PasswordChangedAt = existing.PasswordChangedAt,
|
||||
Settings = existing.Settings,
|
||||
Metadata = existing.Metadata,
|
||||
CreatedAt = existing.CreatedAt,
|
||||
UpdatedAt = now,
|
||||
CreatedBy = existing.CreatedBy
|
||||
};
|
||||
|
||||
users[updated.Id] = updated;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private static string GetUsernameKey(string tenantId, string username)
|
||||
=> $"{tenantId}::{username}".ToLowerInvariant();
|
||||
|
||||
private static string GetEmailKey(string tenantId, string email)
|
||||
=> $"{tenantId}::{email}".ToLowerInvariant();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Standard Plugin Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0096-M | DONE | Maintainability audit for StellaOps.Authority.Plugin.Standard. |
|
||||
| AUDIT-0096-T | DONE | Test coverage audit for StellaOps.Authority.Plugin.Standard. |
|
||||
| AUDIT-0096-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,22 @@
|
||||
# Authority Plugin Abstractions Tests AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugins.Abstractions.Tests/`.
|
||||
- Roles: QA automation, backend engineer.
|
||||
- Focus: contract type validation, normalization, and edge-case behavior.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep tests deterministic (fixed time/IDs); avoid external network calls.
|
||||
- Prefer explicit assertions over documentation-only tests.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + TestKit.
|
||||
- Cover capability parsing, normalization logic, and validation failures.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Plugin Abstractions Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0099-M | DONE | Maintainability audit for StellaOps.Authority.Plugins.Abstractions.Tests. |
|
||||
| AUDIT-0099-T | DONE | Test coverage audit for StellaOps.Authority.Plugins.Abstractions.Tests. |
|
||||
| AUDIT-0099-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,21 @@
|
||||
# Authority Plugin Abstractions AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority.Plugins.Abstractions/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: Authority plugin contracts, identity provider abstractions, and shared metadata types.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep contracts deterministic (stable ordering, normalized data).
|
||||
- Avoid breaking changes without coordinating downstream plugin implementations.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + TestKit; cover normalization, validation, and edge cases for contract types.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Plugin Abstractions Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0098-M | DONE | Maintainability audit for StellaOps.Authority.Plugins.Abstractions. |
|
||||
| AUDIT-0098-T | DONE | Test coverage audit for StellaOps.Authority.Plugins.Abstractions. |
|
||||
| AUDIT-0098-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,29 @@
|
||||
# Authority Tests Charter
|
||||
|
||||
## Mission
|
||||
Own the Authority test suite for the Authority web service and shared components. Ensure coverage for auth flows, policy enforcement, and deterministic behavior.
|
||||
|
||||
## Responsibilities
|
||||
- Maintain `StellaOps.Authority.Tests` and supporting test utilities.
|
||||
- Keep tests deterministic and offline-friendly; avoid external dependencies unless explicitly approved.
|
||||
- Surface open work on `TASKS.md`; update statuses (TODO/DOING/DONE/BLOCKED/REVIEW).
|
||||
|
||||
## Key Paths
|
||||
- `Infrastructure/AuthorityWebApplicationFactory.cs`
|
||||
- `OpenIddict/*`, `Auth/*`, `Bootstrap/*`, `Notifications/*`, `Observability/*`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
|
||||
## Coordination
|
||||
- Authority Core and Security guilds for auth flows and crypto.
|
||||
- Observability guild for trace/metrics assertions.
|
||||
|
||||
## Required Reading
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
|
||||
## Working Agreement
|
||||
- 1. Update task status to `DOING`/`DONE` in both corresponding sprint file `/docs/implplan/SPRINT_*.md` and the local `TASKS.md` when you start or finish work.
|
||||
- 2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met.
|
||||
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
|
||||
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
|
||||
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0100-M | DONE | Maintainability audit for StellaOps.Authority.Tests. |
|
||||
| AUDIT-0100-T | DONE | Test coverage audit for StellaOps.Authority.Tests. |
|
||||
| AUDIT-0100-A | TODO | Pending approval for changes. |
|
||||
@@ -0,0 +1,25 @@
|
||||
# Authority Service AGENTS
|
||||
|
||||
## Purpose & Scope
|
||||
- Working directory: `src/Authority/StellaOps.Authority/StellaOps.Authority/`.
|
||||
- Roles: backend engineer, QA automation.
|
||||
- Focus: Authority web service composition, OpenIddict flows, plugins, storage adapters, and security controls.
|
||||
|
||||
## Required Reading (treat as read before DOING)
|
||||
- `docs/README.md`
|
||||
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
- `docs/modules/authority/architecture.md`
|
||||
- `docs/architecture/console-admin-rbac.md`
|
||||
- `docs/architecture/console-branding.md`
|
||||
- Relevant sprint files.
|
||||
|
||||
## Working Agreements
|
||||
- Keep auth flows deterministic (TimeProvider/ID generators where feasible).
|
||||
- Preserve offline/air-gap posture and avoid new hard network dependencies.
|
||||
- Audit events must stay structured and avoid leaking secrets.
|
||||
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
|
||||
|
||||
## Testing
|
||||
- Use xUnit + FluentAssertions + TestKit.
|
||||
- Cover OpenIddict handlers, auth audit sinks, storage adapters, and policy enforcement.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Authority Service Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0085-M | DONE | Maintainability audit for StellaOps.Authority. |
|
||||
| AUDIT-0085-T | DONE | Test coverage audit for StellaOps.Authority. |
|
||||
| AUDIT-0085-A | TODO | Pending approval for changes. |
|
||||
Reference in New Issue
Block a user