From 2e3752b4304ecb626ed1b789bacd03983937dbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ren=C3=A9=20White=20Enciso?= Date: Sun, 22 Feb 2026 04:31:43 -0600 Subject: [PATCH] feat(thalos-dal): define identity dal contracts and read ports --- docs/architecture/thalos-dal-map.puml | 15 +++++++ docs/dal/identity-persistence-strategy.md | 2 + docs/dal/identity-provider-boundaries.md | 3 ++ .../IIdentityDalGrpcContractAdapter.cs | 38 ++++++++++++++++ .../Contracts/DalDependencyHealthStatus.cs | 12 +++++ .../Contracts/IdentityContractEnvelope.cs | 8 ++++ .../Contracts/IdentityModuleLookupRequest.cs | 8 ++++ .../Contracts/IdentityModuleRecord.cs | 9 ++++ .../Contracts/IdentityPermissionRecord.cs | 12 +++++ .../IdentityPermissionSetLookupRequest.cs | 12 +++++ .../Contracts/IdentityPolicyLookupRequest.cs | 14 ++++++ .../Contracts/IdentityPolicyRecord.cs | 14 ++++++ .../Contracts/IdentityRoleLookupRequest.cs | 9 ++++ .../Contracts/IdentityRoleRecord.cs | 9 ++++ .../Contracts/IdentityTenantLookupRequest.cs | 8 ++++ .../Contracts/IdentityTenantRecord.cs | 14 ++++++ .../Contracts/IdentityTokenLookupRequest.cs | 9 ++++ .../Contracts/IdentityTokenRecord.cs | 16 +++++++ .../Contracts/IdentityUserLookupRequest.cs | 8 ++++ .../Contracts/IdentityUserRecord.cs | 14 ++++++ .../Contracts/ThalosDalPackageContract.cs | 15 +++++++ .../Grpc/IdentityPolicyDalGrpcContract.cs | 9 ++++ .../Grpc/IdentityTokenDalGrpcContract.cs | 8 ++++ .../Health/IDalDependencyHealthCheck.cs | 8 ++++ .../Providers/IModuleDataProvider.cs | 11 +++++ .../Providers/IPermissionDataProvider.cs | 11 +++++ src/Thalos.DAL/Providers/IRoleDataProvider.cs | 11 +++++ .../Providers/ITenantDataProvider.cs | 11 +++++ src/Thalos.DAL/Providers/IUserDataProvider.cs | 11 +++++ .../Repositories/IIdentityRepository.cs | 31 +++++++++++++ src/Thalos.DAL/Thalos.DAL.csproj | 3 ++ .../BoundaryShapeTests.cs | 23 ++++++++++ .../ContractShapeTests.cs | 44 +++++++++++++++++++ 33 files changed, 430 insertions(+) create mode 100644 src/Thalos.DAL/Adapters/IIdentityDalGrpcContractAdapter.cs create mode 100644 src/Thalos.DAL/Contracts/DalDependencyHealthStatus.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityContractEnvelope.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityModuleLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityModuleRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityPermissionRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityPermissionSetLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityPolicyLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityPolicyRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityRoleLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityRoleRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityTenantLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityTenantRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityTokenLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityTokenRecord.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs create mode 100644 src/Thalos.DAL/Contracts/IdentityUserRecord.cs create mode 100644 src/Thalos.DAL/Contracts/ThalosDalPackageContract.cs create mode 100644 src/Thalos.DAL/Grpc/IdentityPolicyDalGrpcContract.cs create mode 100644 src/Thalos.DAL/Grpc/IdentityTokenDalGrpcContract.cs create mode 100644 tests/Thalos.DAL.UnitTests/ContractShapeTests.cs diff --git a/docs/architecture/thalos-dal-map.puml b/docs/architecture/thalos-dal-map.puml index e7060de..89bb78d 100644 --- a/docs/architecture/thalos-dal-map.puml +++ b/docs/architecture/thalos-dal-map.puml @@ -2,6 +2,13 @@ skinparam packageStyle rectangle package "thalos-dal" { + class IdentityPolicyLookupRequest + class IdentityPolicyRecord + class IdentityTokenLookupRequest + class IdentityTokenRecord + class IdentityPermissionSetLookupRequest + class IdentityPermissionRecord + interface IIdentityDalGrpcContractAdapter interface IUserDataProvider interface IRoleDataProvider interface IPermissionDataProvider @@ -10,12 +17,20 @@ package "thalos-dal" { interface IIdentityRepository interface IDalDependencyHealthCheck + IIdentityDalGrpcContractAdapter --> IdentityPolicyLookupRequest + IIdentityDalGrpcContractAdapter --> IdentityTokenLookupRequest IIdentityRepository --> IUserDataProvider IIdentityRepository --> IRoleDataProvider IIdentityRepository --> IPermissionDataProvider IIdentityRepository --> IModuleDataProvider IIdentityRepository --> ITenantDataProvider IIdentityRepository --> IDalDependencyHealthCheck + IIdentityRepository --> IdentityPolicyLookupRequest + IIdentityRepository --> IdentityPolicyRecord + IIdentityRepository --> IdentityTokenLookupRequest + IIdentityRepository --> IdentityTokenRecord + IIdentityRepository --> IdentityPermissionSetLookupRequest + IIdentityRepository --> IdentityPermissionRecord } package "thalos-service" as ThalosService diff --git a/docs/dal/identity-persistence-strategy.md b/docs/dal/identity-persistence-strategy.md index 38f96d5..5186cdb 100644 --- a/docs/dal/identity-persistence-strategy.md +++ b/docs/dal/identity-persistence-strategy.md @@ -5,8 +5,10 @@ - DAL repository boundaries coordinate identity aggregate persistence operations. - Dependency health checks are defined inside DAL boundaries. - Storage and cache dependencies are modeled in DAL-owned contracts. +- gRPC translation stays at adapter interfaces and does not include persistence implementation. ## Constraints - Identity persistence concerns do not leak to non-Thalos repositories. - Service layer consumes DAL boundaries without owning persistence details. +- This stage defines contracts and ports only; no datastore implementation is introduced. diff --git a/docs/dal/identity-provider-boundaries.md b/docs/dal/identity-provider-boundaries.md index 717246f..f57bc23 100644 --- a/docs/dal/identity-provider-boundaries.md +++ b/docs/dal/identity-provider-boundaries.md @@ -7,9 +7,12 @@ - `IPermissionDataProvider`: permission aggregate provider boundary. - `IModuleDataProvider`: module aggregate provider boundary. - `ITenantDataProvider`: tenant aggregate provider boundary. +- `IIdentityRepository`: DAL composition boundary for policy, token, and permission-set reads. +- `IIdentityDalGrpcContractAdapter`: gRPC translation boundary for DAL contracts. ## Rules - Providers isolate datastore-specific behavior. - Provider boundaries remain internal to Thalos DAL. +- DAL interfaces expose only transport-neutral contracts and read ports. - Identity abstractions remain Thalos-owned. diff --git a/src/Thalos.DAL/Adapters/IIdentityDalGrpcContractAdapter.cs b/src/Thalos.DAL/Adapters/IIdentityDalGrpcContractAdapter.cs new file mode 100644 index 0000000..e2609cf --- /dev/null +++ b/src/Thalos.DAL/Adapters/IIdentityDalGrpcContractAdapter.cs @@ -0,0 +1,38 @@ +using Thalos.DAL.Contracts; +using Thalos.DAL.Grpc; + +namespace Thalos.DAL.Adapters; + +/// +/// Defines adapter boundary for dal gRPC contract translation. +/// +public interface IIdentityDalGrpcContractAdapter +{ + /// + /// Maps transport-neutral policy lookup request into gRPC contract shape. + /// + /// Policy lookup request contract. + /// gRPC policy contract shape. + IdentityPolicyDalGrpcContract ToGrpcPolicyRequest(IdentityPolicyLookupRequest request); + + /// + /// Maps gRPC policy contract into transport-neutral policy lookup request. + /// + /// gRPC policy contract shape. + /// Policy lookup request contract. + IdentityPolicyLookupRequest FromGrpcPolicyRequest(IdentityPolicyDalGrpcContract contract); + + /// + /// Maps transport-neutral token lookup request into gRPC contract shape. + /// + /// Token lookup request contract. + /// gRPC token contract shape. + IdentityTokenDalGrpcContract ToGrpcTokenRequest(IdentityTokenLookupRequest request); + + /// + /// Maps gRPC token contract into transport-neutral token lookup request. + /// + /// gRPC token contract shape. + /// Token lookup request contract. + IdentityTokenLookupRequest FromGrpcTokenRequest(IdentityTokenDalGrpcContract contract); +} diff --git a/src/Thalos.DAL/Contracts/DalDependencyHealthStatus.cs b/src/Thalos.DAL/Contracts/DalDependencyHealthStatus.cs new file mode 100644 index 0000000..fc098a0 --- /dev/null +++ b/src/Thalos.DAL/Contracts/DalDependencyHealthStatus.cs @@ -0,0 +1,12 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing dal dependency health status. +/// +/// Contract envelope metadata. +/// Indicates whether dependencies are healthy. +/// Dependency boundaries included in health probe. +public sealed record DalDependencyHealthStatus( + IdentityContractEnvelope Envelope, + bool IsHealthy, + IReadOnlyList DependencyNames); diff --git a/src/Thalos.DAL/Contracts/IdentityContractEnvelope.cs b/src/Thalos.DAL/Contracts/IdentityContractEnvelope.cs new file mode 100644 index 0000000..7a03817 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityContractEnvelope.cs @@ -0,0 +1,8 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Defines transport-neutral envelope metadata for thalos dal contract messages. +/// +/// Contract schema version. +/// Correlation identifier for cross-layer tracing. +public sealed record IdentityContractEnvelope(string ContractVersion, string CorrelationId); diff --git a/src/Thalos.DAL/Contracts/IdentityModuleLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityModuleLookupRequest.cs new file mode 100644 index 0000000..b9808af --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityModuleLookupRequest.cs @@ -0,0 +1,8 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for module aggregate lookup. +/// +/// Contract envelope metadata. +/// Tenant scope identifier. +public sealed record IdentityModuleLookupRequest(IdentityContractEnvelope Envelope, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityModuleRecord.cs b/src/Thalos.DAL/Contracts/IdentityModuleRecord.cs new file mode 100644 index 0000000..5938def --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityModuleRecord.cs @@ -0,0 +1,9 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing persisted module metadata for tenant scope. +/// +/// Contract envelope metadata. +/// Module code identifier. +/// Indicates whether module is enabled. +public sealed record IdentityModuleRecord(IdentityContractEnvelope Envelope, string ModuleCode, bool IsEnabled); diff --git a/src/Thalos.DAL/Contracts/IdentityPermissionRecord.cs b/src/Thalos.DAL/Contracts/IdentityPermissionRecord.cs new file mode 100644 index 0000000..8ee10f2 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityPermissionRecord.cs @@ -0,0 +1,12 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing a persisted permission grant for identity scope. +/// +/// Contract envelope metadata. +/// Permission code identifier. +/// Role code that grants the permission. +public sealed record IdentityPermissionRecord( + IdentityContractEnvelope Envelope, + string PermissionCode, + string SourceRoleCode); diff --git a/src/Thalos.DAL/Contracts/IdentityPermissionSetLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityPermissionSetLookupRequest.cs new file mode 100644 index 0000000..d41d316 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityPermissionSetLookupRequest.cs @@ -0,0 +1,12 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for identity permission set lookup. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +public sealed record IdentityPermissionSetLookupRequest( + IdentityContractEnvelope Envelope, + string SubjectId, + string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityPolicyLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityPolicyLookupRequest.cs new file mode 100644 index 0000000..c6a338c --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityPolicyLookupRequest.cs @@ -0,0 +1,14 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for identity policy context lookup. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +/// Permission code to evaluate. +public sealed record IdentityPolicyLookupRequest( + IdentityContractEnvelope Envelope, + string SubjectId, + string TenantId, + string PermissionCode); diff --git a/src/Thalos.DAL/Contracts/IdentityPolicyRecord.cs b/src/Thalos.DAL/Contracts/IdentityPolicyRecord.cs new file mode 100644 index 0000000..4a47f3e --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityPolicyRecord.cs @@ -0,0 +1,14 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Response contract representing persisted identity policy context. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Permission code evaluated. +/// Indicates whether policy context is satisfied. +public sealed record IdentityPolicyRecord( + IdentityContractEnvelope Envelope, + string SubjectId, + string PermissionCode, + bool ContextSatisfied); diff --git a/src/Thalos.DAL/Contracts/IdentityRoleLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityRoleLookupRequest.cs new file mode 100644 index 0000000..277c4de --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityRoleLookupRequest.cs @@ -0,0 +1,9 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for role aggregate lookup. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +public sealed record IdentityRoleLookupRequest(IdentityContractEnvelope Envelope, string SubjectId, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityRoleRecord.cs b/src/Thalos.DAL/Contracts/IdentityRoleRecord.cs new file mode 100644 index 0000000..023ab8c --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityRoleRecord.cs @@ -0,0 +1,9 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing a persisted identity role assignment. +/// +/// Contract envelope metadata. +/// Role code identifier. +/// Tenant scope identifier. +public sealed record IdentityRoleRecord(IdentityContractEnvelope Envelope, string RoleCode, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityTenantLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityTenantLookupRequest.cs new file mode 100644 index 0000000..531e2b4 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityTenantLookupRequest.cs @@ -0,0 +1,8 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for tenant aggregate lookup. +/// +/// Contract envelope metadata. +/// Tenant scope identifier. +public sealed record IdentityTenantLookupRequest(IdentityContractEnvelope Envelope, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityTenantRecord.cs b/src/Thalos.DAL/Contracts/IdentityTenantRecord.cs new file mode 100644 index 0000000..2009b25 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityTenantRecord.cs @@ -0,0 +1,14 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing persisted tenant metadata. +/// +/// Contract envelope metadata. +/// Tenant scope identifier. +/// Tenant code identifier. +/// Indicates whether tenant is active. +public sealed record IdentityTenantRecord( + IdentityContractEnvelope Envelope, + string TenantId, + string TenantCode, + bool IsActive); diff --git a/src/Thalos.DAL/Contracts/IdentityTokenLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityTokenLookupRequest.cs new file mode 100644 index 0000000..034118d --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityTokenLookupRequest.cs @@ -0,0 +1,9 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for identity token record lookup. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +public sealed record IdentityTokenLookupRequest(IdentityContractEnvelope Envelope, string SubjectId, string TenantId); diff --git a/src/Thalos.DAL/Contracts/IdentityTokenRecord.cs b/src/Thalos.DAL/Contracts/IdentityTokenRecord.cs new file mode 100644 index 0000000..e932ff4 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityTokenRecord.cs @@ -0,0 +1,16 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Response contract representing token issuance persistence data. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +/// Issued access token value. +/// Token expiration in seconds. +public sealed record IdentityTokenRecord( + IdentityContractEnvelope Envelope, + string SubjectId, + string TenantId, + string Token, + int ExpiresInSeconds); diff --git a/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs b/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs new file mode 100644 index 0000000..8e6d4e4 --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityUserLookupRequest.cs @@ -0,0 +1,8 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Request contract for user aggregate lookup. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +public sealed record IdentityUserLookupRequest(IdentityContractEnvelope Envelope, string SubjectId); diff --git a/src/Thalos.DAL/Contracts/IdentityUserRecord.cs b/src/Thalos.DAL/Contracts/IdentityUserRecord.cs new file mode 100644 index 0000000..aa364ac --- /dev/null +++ b/src/Thalos.DAL/Contracts/IdentityUserRecord.cs @@ -0,0 +1,14 @@ +namespace Thalos.DAL.Contracts; + +/// +/// Contract representing a persisted identity user aggregate. +/// +/// Contract envelope metadata. +/// Identity subject identifier. +/// Tenant scope identifier. +/// Current user status. +public sealed record IdentityUserRecord( + IdentityContractEnvelope Envelope, + string SubjectId, + string TenantId, + string Status); diff --git a/src/Thalos.DAL/Contracts/ThalosDalPackageContract.cs b/src/Thalos.DAL/Contracts/ThalosDalPackageContract.cs new file mode 100644 index 0000000..6857a0b --- /dev/null +++ b/src/Thalos.DAL/Contracts/ThalosDalPackageContract.cs @@ -0,0 +1,15 @@ +using Core.Blueprint.Common.Contracts; + +namespace Thalos.DAL.Contracts; + +/// +/// Defines package descriptor metadata for thalos dal contracts. +/// +public sealed class ThalosDalPackageContract : IBlueprintPackageContract +{ + /// + public BlueprintPackageDescriptor Descriptor { get; } = new( + "Thalos.DAL.Contracts", + PackageVersionPolicy.Minor, + ["Core.Blueprint.Common"]); +} diff --git a/src/Thalos.DAL/Grpc/IdentityPolicyDalGrpcContract.cs b/src/Thalos.DAL/Grpc/IdentityPolicyDalGrpcContract.cs new file mode 100644 index 0000000..2a705e7 --- /dev/null +++ b/src/Thalos.DAL/Grpc/IdentityPolicyDalGrpcContract.cs @@ -0,0 +1,9 @@ +namespace Thalos.DAL.Grpc; + +/// +/// Defines minimal gRPC contract shape for identity policy dal adapter translation. +/// +/// Identity subject identifier. +/// Tenant scope identifier. +/// Permission code to evaluate. +public sealed record IdentityPolicyDalGrpcContract(string SubjectId, string TenantId, string PermissionCode); diff --git a/src/Thalos.DAL/Grpc/IdentityTokenDalGrpcContract.cs b/src/Thalos.DAL/Grpc/IdentityTokenDalGrpcContract.cs new file mode 100644 index 0000000..40e8c6f --- /dev/null +++ b/src/Thalos.DAL/Grpc/IdentityTokenDalGrpcContract.cs @@ -0,0 +1,8 @@ +namespace Thalos.DAL.Grpc; + +/// +/// Defines minimal gRPC contract shape for identity token dal adapter translation. +/// +/// Identity subject identifier. +/// Tenant scope identifier. +public sealed record IdentityTokenDalGrpcContract(string SubjectId, string TenantId); diff --git a/src/Thalos.DAL/Health/IDalDependencyHealthCheck.cs b/src/Thalos.DAL/Health/IDalDependencyHealthCheck.cs index f2f3606..387d57e 100644 --- a/src/Thalos.DAL/Health/IDalDependencyHealthCheck.cs +++ b/src/Thalos.DAL/Health/IDalDependencyHealthCheck.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Health; /// @@ -5,4 +7,10 @@ namespace Thalos.DAL.Health; /// public interface IDalDependencyHealthCheck { + /// + /// Probes dependency health for DAL-owned providers. + /// + /// Cancellation token. + /// Health status contract for DAL dependency boundaries. + Task CheckAsync(CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Providers/IModuleDataProvider.cs b/src/Thalos.DAL/Providers/IModuleDataProvider.cs index 60014eb..74c8a1e 100644 --- a/src/Thalos.DAL/Providers/IModuleDataProvider.cs +++ b/src/Thalos.DAL/Providers/IModuleDataProvider.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Providers; /// @@ -5,4 +7,13 @@ namespace Thalos.DAL.Providers; /// public interface IModuleDataProvider { + /// + /// Reads module capability metadata for tenant scope. + /// + /// Module lookup request contract. + /// Cancellation token. + /// Module records matching lookup scope. + Task> ReadModulesAsync( + IdentityModuleLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Providers/IPermissionDataProvider.cs b/src/Thalos.DAL/Providers/IPermissionDataProvider.cs index 61c9c0b..ac95fe6 100644 --- a/src/Thalos.DAL/Providers/IPermissionDataProvider.cs +++ b/src/Thalos.DAL/Providers/IPermissionDataProvider.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Providers; /// @@ -5,4 +7,13 @@ namespace Thalos.DAL.Providers; /// public interface IPermissionDataProvider { + /// + /// Reads permission grants for subject and tenant scope. + /// + /// Permission lookup request contract. + /// Cancellation token. + /// Permission grant records matching lookup scope. + Task> ReadPermissionsAsync( + IdentityPermissionSetLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Providers/IRoleDataProvider.cs b/src/Thalos.DAL/Providers/IRoleDataProvider.cs index 4910e3e..739afa4 100644 --- a/src/Thalos.DAL/Providers/IRoleDataProvider.cs +++ b/src/Thalos.DAL/Providers/IRoleDataProvider.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Providers; /// @@ -5,4 +7,13 @@ namespace Thalos.DAL.Providers; /// public interface IRoleDataProvider { + /// + /// Reads identity role records for subject and tenant scope. + /// + /// Role lookup request contract. + /// Cancellation token. + /// Role records matching the lookup scope. + Task> ReadRolesAsync( + IdentityRoleLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Providers/ITenantDataProvider.cs b/src/Thalos.DAL/Providers/ITenantDataProvider.cs index 976f57c..50d0b46 100644 --- a/src/Thalos.DAL/Providers/ITenantDataProvider.cs +++ b/src/Thalos.DAL/Providers/ITenantDataProvider.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Providers; /// @@ -5,4 +7,13 @@ namespace Thalos.DAL.Providers; /// public interface ITenantDataProvider { + /// + /// Reads tenant scope metadata for identity policy and token decisions. + /// + /// Tenant lookup request contract. + /// Cancellation token. + /// Tenant record when found; otherwise null. + Task ReadTenantAsync( + IdentityTenantLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Providers/IUserDataProvider.cs b/src/Thalos.DAL/Providers/IUserDataProvider.cs index 5afd2d8..2a1eff6 100644 --- a/src/Thalos.DAL/Providers/IUserDataProvider.cs +++ b/src/Thalos.DAL/Providers/IUserDataProvider.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Providers; /// @@ -5,4 +7,13 @@ namespace Thalos.DAL.Providers; /// public interface IUserDataProvider { + /// + /// Reads an identity user record by subject identifier. + /// + /// User lookup request contract. + /// Cancellation token. + /// User record when found; otherwise null. + Task ReadUserAsync( + IdentityUserLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Repositories/IIdentityRepository.cs b/src/Thalos.DAL/Repositories/IIdentityRepository.cs index 2b1c317..228b436 100644 --- a/src/Thalos.DAL/Repositories/IIdentityRepository.cs +++ b/src/Thalos.DAL/Repositories/IIdentityRepository.cs @@ -1,3 +1,5 @@ +using Thalos.DAL.Contracts; + namespace Thalos.DAL.Repositories; /// @@ -5,4 +7,33 @@ namespace Thalos.DAL.Repositories; /// public interface IIdentityRepository { + /// + /// Reads token issuance record data for a subject and tenant scope. + /// + /// Token lookup request contract. + /// Cancellation token. + /// Token record when found; otherwise null. + Task ReadIdentityTokenAsync( + IdentityTokenLookupRequest request, + CancellationToken cancellationToken = default); + + /// + /// Reads policy context data required for authorization checks. + /// + /// Policy lookup request contract. + /// Cancellation token. + /// Policy record when found; otherwise null. + Task ReadIdentityPolicyAsync( + IdentityPolicyLookupRequest request, + CancellationToken cancellationToken = default); + + /// + /// Reads permission set data for subject and tenant scope. + /// + /// Permission set lookup request contract. + /// Cancellation token. + /// Permission records for the requested scope. + Task> ReadPermissionSetAsync( + IdentityPermissionSetLookupRequest request, + CancellationToken cancellationToken = default); } diff --git a/src/Thalos.DAL/Thalos.DAL.csproj b/src/Thalos.DAL/Thalos.DAL.csproj index 6c3a887..04a4bbc 100644 --- a/src/Thalos.DAL/Thalos.DAL.csproj +++ b/src/Thalos.DAL/Thalos.DAL.csproj @@ -4,4 +4,7 @@ enable enable + + + diff --git a/tests/Thalos.DAL.UnitTests/BoundaryShapeTests.cs b/tests/Thalos.DAL.UnitTests/BoundaryShapeTests.cs index 21c50dd..7e36d03 100644 --- a/tests/Thalos.DAL.UnitTests/BoundaryShapeTests.cs +++ b/tests/Thalos.DAL.UnitTests/BoundaryShapeTests.cs @@ -1,6 +1,7 @@ using Thalos.DAL.Health; using Thalos.DAL.Providers; using Thalos.DAL.Repositories; +using System.Reflection; namespace Thalos.DAL.UnitTests; @@ -22,4 +23,26 @@ public class BoundaryShapeTests Assert.True(typeof(IIdentityRepository).IsInterface); Assert.True(typeof(IDalDependencyHealthCheck).IsInterface); } + + [Fact] + public void IdentityRepository_WhenReflected_ExposesContractMethodsOnly() + { + var methods = typeof(IIdentityRepository).GetMethods(BindingFlags.Public | BindingFlags.Instance); + var methodNames = methods.Select(method => method.Name).OrderBy(name => name).ToArray(); + + Assert.Equal( + ["ReadIdentityPolicyAsync", "ReadIdentityTokenAsync", "ReadPermissionSetAsync"], + methodNames); + } + + [Fact] + public void ProviderBoundaries_WhenReflected_ExposeReadOnlyMethods() + { + Assert.Equal("ReadUserAsync", typeof(IUserDataProvider).GetMethods().Single().Name); + Assert.Equal("ReadRolesAsync", typeof(IRoleDataProvider).GetMethods().Single().Name); + Assert.Equal("ReadPermissionsAsync", typeof(IPermissionDataProvider).GetMethods().Single().Name); + Assert.Equal("ReadModulesAsync", typeof(IModuleDataProvider).GetMethods().Single().Name); + Assert.Equal("ReadTenantAsync", typeof(ITenantDataProvider).GetMethods().Single().Name); + Assert.Equal("CheckAsync", typeof(IDalDependencyHealthCheck).GetMethods().Single().Name); + } } diff --git a/tests/Thalos.DAL.UnitTests/ContractShapeTests.cs b/tests/Thalos.DAL.UnitTests/ContractShapeTests.cs new file mode 100644 index 0000000..58949ba --- /dev/null +++ b/tests/Thalos.DAL.UnitTests/ContractShapeTests.cs @@ -0,0 +1,44 @@ +using Core.Blueprint.Common.Contracts; +using Thalos.DAL.Contracts; + +namespace Thalos.DAL.UnitTests; + +public class ContractShapeTests +{ + [Fact] + public void IdentityPolicyLookupRequest_WhenCreated_StoresTransportNeutralData() + { + var envelope = new IdentityContractEnvelope("1.0.0", "corr-123"); + var request = new IdentityPolicyLookupRequest(envelope, "user-1", "tenant-1", "identity.token.issue"); + + Assert.Equal("1.0.0", request.Envelope.ContractVersion); + Assert.Equal("corr-123", request.Envelope.CorrelationId); + Assert.Equal("user-1", request.SubjectId); + Assert.Equal("tenant-1", request.TenantId); + Assert.Equal("identity.token.issue", request.PermissionCode); + } + + [Fact] + public void IdentityTokenRecord_WhenCreated_StoresTransportNeutralData() + { + var envelope = new IdentityContractEnvelope("1.0.0", "corr-123"); + var record = new IdentityTokenRecord(envelope, "user-1", "tenant-1", "token-xyz", 1800); + + Assert.Equal("1.0.0", record.Envelope.ContractVersion); + Assert.Equal("corr-123", record.Envelope.CorrelationId); + Assert.Equal("user-1", record.SubjectId); + Assert.Equal("tenant-1", record.TenantId); + Assert.Equal("token-xyz", record.Token); + Assert.Equal(1800, record.ExpiresInSeconds); + } + + [Fact] + public void ThalosDalPackageContract_WhenCreated_UsesBlueprintDescriptorContract() + { + IBlueprintPackageContract contract = new ThalosDalPackageContract(); + + Assert.Equal("Thalos.DAL.Contracts", contract.Descriptor.PackageId); + Assert.Equal(PackageVersionPolicy.Minor, contract.Descriptor.VersionPolicy); + Assert.Contains("Core.Blueprint.Common", contract.Descriptor.DependencyPackageIds); + } +}