Skip to content

Implement AuthenticationMethod support in IInstanceDataAccessor - #1472

Merged
danielskovli merged 15 commits into
mainfrom
fix/signing-sensitive-data
Sep 17, 2025
Merged

danielskovli merged 15 commits into
mainfrom
fix/signing-sensitive-data

Conversation

@danielskovli

@danielskovli danielskovli commented Sep 15, 2025 •

Copy link
Copy Markdown
Contributor

Description

This PR implements AuthenticationMethod support for IInstanceDataAccessor, and uses this ability to automatically support restricted data in the SigningService.

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)
  • All tests run green

Documentation

  • User documentation is updated with a separate linked PR in altinn-studio-docs. (if applicable)

Summary by CodeRabbit

  • Bug Fixes

    • Restricted data types now use service-owner access where needed, preventing authorization failures during signing and when loading signee contexts.
  • Refactor

    • Signing flow and data-access now derive data-type access rules from application metadata, improving reliability with no change to user-facing behavior.
  • Behavior Change

    • Validation now surfaces failures when metadata or signee information cannot be retrieved (exceptions propagate).
  • Tests

    • Tests updated to cover metadata-driven data-type handling and the stricter validation behavior.

@coderabbitai

coderabbitai Bot commented Sep 15, 2025 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds IAppMetadata injections across signing components and the SigningController; introduces per-data-type storage authentication overrides on IInstanceDataAccessor and implements them in the unit-of-work; adds extensions to apply service-owner auth for restricted data types; wires these into signing flows and updates tests and public API snapshots.

Changes

Cohort / File(s) Summary of changes
API Controller DI
src/Altinn.App.Api/Controllers/SigningController.cs, test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
Added IAppMetadata parameter to SigningController constructor (new DI dependency) inserted before the logger; no usage shown in constructor body. Public API snapshot updated.
IInstanceDataAccessor & implementations
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs, src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs, src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs, test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs, test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
Added OverrideAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method) and AuthenticationMethodOverrides { get; } to IInstanceDataAccessor. Implemented override storage and resolution in InstanceDataUnitOfWork (ConcurrentDictionary, default method, GetAuthenticationMethod helpers) and updated storage calls to use resolved authentication method. Added NotImplemented stubs in SingleDataElementAccessor and test fake. Public API snapshot updated.
Signing auth extensions
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
New internal extension OverrideAuthenticationMethodForRestrictedDataTypes(this IInstanceDataAccessor, ApplicationMetadata, string?[] dataTypeIds, StorageAuthenticationMethod) that maps IDs→DataType, detects restricted types, and calls OverrideAuthenticationMethod for each restricted DataType. Includes helper lookups and restriction checks.
Signing services wiring
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs, src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs, src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
Added IAppMetadata dependency to constructors. In signing flows, fetch ApplicationMetadata and call the extension to override auth for relevant data type(s) (signature data type, signee states) before accessing/inserting data. SigneeContextsManager converted to primary-constructor style and uses injected params directly; telemetry/logging adjusted.
Validator changes
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs, test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs
Replaced ServiceResult/CatchError patterns with direct await calls to _appMetadata.GetApplicationMetadata() and _signingService.GetSigneeContexts(...); removed logger usage and error-wrapping. Tests updated to expect exceptions when metadata or signee fetch fails.
Process task helpers
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
Renamed local signatureConfiguration to signingConfiguration. Added private helpers GetDataType, GetDataTypes, and IsRestrictedDataType (with NotNullWhen) to resolve DataType objects and detect restrictions; helpers are private and not otherwise invoked in this diff.
Tests updated for metadata DI
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs, test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs, test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
Tests now mock and inject IAppMetadata, provide ApplicationMetadata with DataTypes (e.g., signature/signeeStates IDs), replace hard-coded data type strings with constants, adapt constructor calls to include the new dependency, verify OverrideAuthenticationMethod is called where expected, and add a DataTypeComparer test for dictionary behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title concisely and accurately captures the primary change: implementing AuthenticationMethod support on IInstanceDataAccessor and related usage in the signing flow, naming the affected interface and intent so reviewers can quickly grasp the main purpose of the PR.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/signing-sensitive-data

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cac029e and aa19abc.

📒 Files selected for processing (2)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (10 hunks)
  • test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Run dotnet build and test (macos-latest)
  • GitHub Check: Run dotnet build and test (windows-latest)
  • GitHub Check: Run dotnet build and test (ubuntu-latest)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Static code analysis

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@danielskovli

Copy link
Copy Markdown
Contributor Author

/publish

@github-actions

github-actions Bot commented Sep 15, 2025 •

Copy link
Copy Markdown

@danielskovli

Copy link
Copy Markdown
Contributor Author

/publish

@github-actions

github-actions Bot commented Sep 15, 2025 •

Copy link
Copy Markdown

@danielskovli danielskovli added bugfix Label Pull requests with bugfix. Used when generation releasenotes backport This PR should be cherry-picked onto older release branches labels Sep 15, 2025
@danielskovli danielskovli added kind/incident-B B incident squad/flyt Issues that belongs to the named squad. labels Sep 15, 2025
@danielskovli danielskovli moved this to 👷 In progress in Team Altinn Studio Sep 15, 2025
@bjorntore

Copy link
Copy Markdown
Contributor

/publish

@github-actions

github-actions Bot commented Sep 15, 2025 •

Copy link
Copy Markdown

PR release:

⚙️ Building...
✅ Done!

… Move shared core for this into IInstanceDataAccessor extension method.
@bjorntore

Copy link
Copy Markdown
Contributor

/publish

@github-actions

github-actions Bot commented Sep 15, 2025 •

Copy link
Copy Markdown

PR release:

⚙️ Building...
✅ Done!

@bjorntore

Copy link
Copy Markdown
Contributor

/publish

@github-actions

github-actions Bot commented Sep 16, 2025 •

Copy link
Copy Markdown

PR release:

⚙️ Building...
✅ Done!

@danielskovli danielskovli changed the title WIP: Implement authentication method concept for IInstanceDataAccessor Implement AuthenticationMethod support in IInstanceDataAccessor Sep 16, 2025
@danielskovli
danielskovli marked this pull request as ready for review September 16, 2025 10:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)

23-29: Filter first, then iterate (tiny readability win).

Inline restriction filtering makes the loop intent explicit.

-foreach (DataType signatureDataType in signatureDataTypes)
-{
-    if (IsRestrictedDataType(signatureDataType))
-    {
-        accessor.SetAuthenticationMethod(signatureDataType, StorageAuthenticationMethod.ServiceOwner());
-    }
-}
+foreach (DataType dt in signatureDataTypes.Where(IsRestrictedDataType))
+{
+    accessor.SetAuthenticationMethod(dt, StorageAuthenticationMethod.ServiceOwner());
+}
🧹 Nitpick comments (11)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (1)

85-98: Remove unused helpers (duplication + dead code)

GetDataType, GetDataTypes, and IsRestrictedDataType are not used here and duplicate logic under SigningInstanceDataAccessorExtensions. Keep single source to avoid drift and drop the unused System.Diagnostics.CodeAnalysis using.

-using System.Diagnostics.CodeAnalysis;
@@
-    private static DataType? GetDataType(ApplicationMetadata appMetadata, string? dataTypeId) =>
-        dataTypeId is null
-            ? null
-            : appMetadata.DataTypes.FirstOrDefault(x => x.Id.Equals(dataTypeId, StringComparison.OrdinalIgnoreCase));
-
-    private static IEnumerable<DataType> GetDataTypes(
-        ApplicationMetadata appMetadata,
-        IEnumerable<string?> dataTypeIds
-    ) => dataTypeIds.Select(dataTypeId => GetDataType(appMetadata, dataTypeId)).OfType<DataType>();
-
-    private static bool IsRestrictedDataType([NotNullWhen(true)] DataType? dataType) =>
-        !string.IsNullOrWhiteSpace(dataType?.ActionRequiredToRead)
-        || !string.IsNullOrWhiteSpace(dataType?.ActionRequiredToWrite);
+    // Removed unused helpers; keep this class focused on task orchestration.
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (1)

98-101: Test double should not throw; implement no-op or store overrides

Throwing in the fake can break tests that invoke the new API indirectly. Make it harmless.

-    public void SetAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method)
-    {
-        throw new NotImplementedException();
-    }
+    public void SetAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method)
+    {
+        // No-op in tests; can be extended to track overrides if needed.
+        _authOverrides[dataType.Id] = method;
+    }

Add a backing field (outside this hunk) to retain calls:

// near other fields
private readonly Dictionary<string, StorageAuthenticationMethod> _authOverrides = new();
src/Altinn.App.Api/Controllers/SigningController.cs (1)

38-45: Constructor injects IAppMetadata but doesn't use it

The new dependency is unused; consider either wiring it for future use or dropping it to avoid API surface churn. If you intend to keep it, assign to a field to document intent and silence analyzers.

@@
 public class SigningController : ControllerBase
 {
     private readonly IInstanceClient _instanceClient;
     private readonly IProcessReader _processReader;
     private readonly IAuthenticationContext _authenticationContext;
+    private readonly IAppMetadata _appMetadata;
     private readonly ILogger<SigningController> _logger;
@@
         IAuthenticationContext authenticationContext,
         IAppMetadata appMetadata,
         ILogger<SigningController> logger
     )
     {
         _instanceClient = instanceClient;
         _processReader = processReader;
         _authenticationContext = authenticationContext;
+        _appMetadata = appMetadata;
         _logger = logger;

Confirm this public API change is intentional for apps consuming Altinn.App.Api; otherwise revert and keep the dependency internal to services.

src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (2)

21-26: Use the correct logger category

Logger is typed as ILogger. Prefer ILogger for accurate logging scopes.

-internal sealed class SignDocumentManager(
+internal sealed class SignDocumentManager(
     IAltinnPartyClient altinnPartyClient,
     IAppMetadata appMetadata,
-    ILogger<SigningService> logger,
+    ILogger<SignDocumentManager> logger,
     Telemetry? telemetry = null
 ) : ISignDocumentManager
 {
-    private readonly ILogger<SigningService> _logger = logger;
+    private readonly ILogger<SignDocumentManager> _logger = logger;

Also applies to: 38-39


148-151: Avoid extra allocation when decoding UTF-8

You can decode from ReadOnlySpan without ToArray().

-            string signDocumentSerialized = Encoding.UTF8.GetString(data.ToArray());
+            string signDocumentSerialized = Encoding.UTF8.GetString(data.Span);
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (1)

113-116: Unreachable null-coalescing after First(...)

First(...) throws if not found; the null-coalescing throw never runs. Use FirstOrDefault and then null-check so the intended ApplicationConfigException is thrown.

-        DataType signatureDateType =
-            appMetadataResult.Ok.DataTypes.First(x => x.Id == signingConfiguration.SignatureDataType)
-            ?? throw new ApplicationConfigException("Didn't find signature data type in app metadata");
+        DataType signatureDateType =
+            appMetadataResult.Ok.DataTypes.FirstOrDefault(x => x.Id == signingConfiguration.SignatureDataType)
+            ?? throw new ApplicationConfigException("Didn't find signature data type in app metadata");
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (1)

119-121: Consistent propagation of authenticationMethod — minor nits.

  • Good: All storage ops now carry the resolved auth method.
  • Nit: Name the boolean argument in DeleteData for clarity.
  • Optional: Consider disposing the temporary stream locally to avoid ownership ambiguity.
- await _dataClient.DeleteData(...,
-     false,
-     authenticationMethod: GetAuthenticationMethod(change.DataElementIdentifier)
- );
+ await _dataClient.DeleteData(...,
+     hard: false,
+     authenticationMethod: GetAuthenticationMethod(change.DataElementIdentifier)
+ );

If DataClient does not take ownership of the stream, prefer:

- new MemoryAsStream(bytes),
+ using var stream = new MemoryAsStream(bytes);
+ // pass 'stream' below

Please confirm DataClient’s ownership contract before changing.

Also applies to: 389-391, 412-414, 451-453

test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (1)

26-45: Good test adaptation; add a case for restricted types.

Nice: injecting IAppMetadata and centralizing SignatureDataTypeId. Add a test where the data type is “restricted” (ActionRequiredToRead/Write set) and assert that SetAuthenticationMethod is invoked with ServiceOwner before downloads.

I can draft a new test that configures ApplicationMetadata with a restricted DataType and verifies a Mock receives SetAuthenticationMethod(ServiceOwner()).

Also applies to: 197-198, 272-273, 306-312

src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)

15-19: Accept IEnumerable for flexibility and add null guards.

Avoids forcing array allocations at call sites and validates inputs.

-public static void SetServiceOwnerAuthForRestrictedDataTypes(
-    this IInstanceDataAccessor accessor,
-    ApplicationMetadata appMetadata,
-    string?[] dataTypeIds
-)
+public static void SetServiceOwnerAuthForRestrictedDataTypes(
+    this IInstanceDataAccessor accessor,
+    ApplicationMetadata appMetadata,
+    IEnumerable<string?> dataTypeIds
+)
 {
-    IEnumerable<DataType> signatureDataTypes = GetDataTypes(appMetadata, dataTypeIds);
+    ArgumentNullException.ThrowIfNull(appMetadata);
+    ArgumentNullException.ThrowIfNull(dataTypeIds);
+    IEnumerable<DataType> signatureDataTypes = GetDataTypes(appMetadata, dataTypeIds);
 }
 
-private static IEnumerable<DataType> GetDataTypes(
+private static IEnumerable<DataType> GetDataTypes(
     ApplicationMetadata appMetadata,
-    IEnumerable<string?> dataTypeIds
+    IEnumerable<string?> dataTypeIds
 ) => dataTypeIds.Select(dataTypeId => GetDataType(appMetadata, dataTypeId)).OfType<DataType>();

Also applies to: 32-35

src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (2)

143-158: Consider person email fallback to mirror SMS fallback.

You already use org or person mobile for SMS. For email, also consider person email if available to improve delivery.

Please confirm whether Person has an email property in Altinn.Platform.Register.Models (naming may be Email or EMailAddress) before adding the fallback.


192-193: Log with context (data type id).

Including the SigneeStatesDataTypeId helps troubleshooting.

-logger.LogInformation("Didn't find any signee states for task.");
+logger.LogInformation("Didn't find any signee states for task. DataTypeId: {DataTypeId}", signeeStatesDataTypeId);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13843c7 and 1c9f42f.

📒 Files selected for processing (15)
  • src/Altinn.App.Api/Controllers/SigningController.cs (1 hunks)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (1 hunks)
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (3 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (8 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (2 hunks)
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (2 hunks)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (7 hunks)
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (1 hunks)
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (2 hunks)
  • test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1 hunks)
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (4 hunks)
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (9 hunks)
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (1 hunks)
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Api/Controllers/SigningController.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Api/Controllers/SigningController.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
test/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.cs: Test projects mirror source structure
Prefer xUnit asserts over FluentAssertions
Mock external dependencies with Moq

Files:

  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs: Types meant to be implemented by apps should be marked with the ImplementableByApps attribute
For HTTP APIs, define DTOs with ...Request and ...Response naming

Files:

  • src/Altinn.App.Api/Controllers/SigningController.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
src/Altinn.App.Core/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
test/Altinn.App.Core.Tests/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Provide corresponding test coverage for each Core feature under /test/Altinn.App.Core.Tests/Features

Files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
🧠 Learnings (7)
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to src/Altinn.App.Core/Features/**/*.cs : New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn app-lib-dotnet projects, ImplicitUsings is enabled in Directory.Build.props, which automatically includes common using statements including Xunit namespace for test projects. This eliminates the need for explicit "using Xunit;" statements in test files.

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn.App.Integration.Tests project, xUnit attributes like [Fact] are available without explicit "using Xunit;" directives, likely through global usings or implicit usings configuration. The code compiles and works as-is.

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs : Types meant to be implemented by apps should be marked with the ImplementableByApps attribute

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to test/Altinn.App.Integration.Tests/**/*.cs : Include integration tests for platform service interactions (using Docker Testcontainers)

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to test/Altinn.App.Core.Tests/Features/**/*.cs : Provide corresponding test coverage for each Core feature under /test/Altinn.App.Core.Tests/Features

Applied to files:

  • src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs
📚 Learning: 2025-08-22T13:46:43.017Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1446
File: test/Altinn.App.Integration.Tests/Basic/_snapshots/BasicAppTests.Full_auth=ServiceOwner_testCase=MultipartXmlPrefill_7_Logs.verified.txt:41-42
Timestamp: 2025-08-22T13:46:43.017Z
Learning: In Altinn App Integration Tests, OldUser and OldServiceOwner test snapshots intentionally preserve the legacy "AuthMethod: localtest" authentication method as part of a migration strategy, while new User and ServiceOwner tests use updated authentication methods like BankID and maskinporten. The "Old*" variants should not be updated to remove localtest references.

Applied to files:

  • test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
🧬 Code graph analysis (12)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (3)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • SetAuthenticationMethod (48-48)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • SetAuthenticationMethod (83-86)
  • DataType (140-140)
  • DataType (547-556)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • SetAuthenticationMethod (94-95)
  • DataType (92-92)
src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (1)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • SetServiceOwnerAuthForRestrictedDataTypes (15-30)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • SetAuthenticationMethod (83-86)
  • DataType (140-140)
  • DataType (547-556)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • SetAuthenticationMethod (94-95)
  • DataType (92-92)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • SetAuthenticationMethod (98-101)
  • DataType (87-96)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • SetAuthenticationMethod (48-48)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • SetAuthenticationMethod (94-95)
  • DataType (92-92)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (3)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • SetAuthenticationMethod (48-48)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • SetAuthenticationMethod (83-86)
  • DataType (140-140)
  • DataType (547-556)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • SetAuthenticationMethod (98-101)
  • DataType (87-96)
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • SetServiceOwnerAuthForRestrictedDataTypes (15-30)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (1)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (1)
  • SigneeContext (182-191)
test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (2)
src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (1)
  • SigneeContextsManager (20-204)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (1)
  • DataType (85-88)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (2)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (4)
  • InstanceDataUnitOfWork (22-639)
  • InstanceDataUnitOfWork (54-78)
  • DataType (140-140)
  • DataType (547-556)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (3)
  • DataType (37-40)
  • IEnumerable (32-35)
  • IsRestrictedDataType (42-44)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (2)
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)
  • SignDocumentManager (21-337)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (2)
  • DataType (85-88)
  • AltinnSignatureConfiguration (155-169)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (3)
  • IEnumerable (90-93)
  • DataType (85-88)
  • IsRestrictedDataType (95-97)
src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (3)
src/Altinn.App.Core/Internal/Sign/SignatureContext.cs (1)
  • Signee (85-109)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • SetServiceOwnerAuthForRestrictedDataTypes (15-30)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (1)
  • IEnumerable (90-93)
🪛 GitHub Check: CodeQL
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs

[notice] 23-29: Missed opportunity to use Where
This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.

🔇 Additional comments (13)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (1)

60-78: Config var rename and guard condition look good

Renaming to signingConfiguration and the null-guard for delegated signing reads clearer and preserves behavior.

src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (1)

42-48: Public interface expansion — confirm compatibility and intent

Adding SetAuthenticationMethod to the public IInstanceDataAccessor is a breaking change for external implementers. In-repo scan reports NO_DIRECT_IMPLEMENTERS (only internal references and tests). Either annotate the interface as ImplementableByApps if apps are expected to implement it, or confirm this change is safe to merge/backport and provide a migration/backport plan.

test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1)

1259-1259: Breaking API: IInstanceDataAccessor now requires SetAuthenticationMethod(DataType, StorageAuthenticationMethod).

Confirmed implementations/tests in this repo: src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (interface), src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs, src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs, test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs.

  • Confirm DI registrations still resolve and that any external consumers/implementers are updated.
  • Add a migration note / CHANGELOG entry and bump the package version.
  • Consider adding a convenience extension overload: SetAuthenticationMethod(this IInstanceDataAccessor, string dataTypeId, StorageAuthenticationMethod) to avoid repeated lookups/null-checks.
src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (1)

7-7: LGTM: extension import

Import is correct and scoped to the call site usage.

src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)

51-53: Good: apply ServiceOwner auth before listing/downloading signature elements

This correctly ensures restricted signature data types are accessed with the right authentication.

Please confirm IAppMetadata.GetApplicationMetadata() is cached internally; this path may be hit on every request.

src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (2)

93-96: Fail-open on app metadata fetch — confirm desired behavior

On metadata read failure you log and return no issues, effectively passing validation. Confirm this is the intended product decision for signing tasks.


103-106: Fail-open on signee contexts read — confirm desired behavior

Similarly, failures in GetSigneeContexts log and pass validation. Ensure this is acceptable; alternatively emit a ValidationIssue to block task completion when signatures cannot be evaluated.

test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (1)

39-45: LGTM: tests updated for app metadata–driven SigneeStates

Solid wiring of IAppMetadata in tests and consistent use of SigneeStatesDataTypeId constant. Mocks and DI setup look correct.

Also applies to: 54-59, 62-67, 118-119, 220-220, 287-287, 317-317, 377-377, 408-414

src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)

50-53: Per‑data‑type auth override looks good.

Thread‑safe dictionary + sensible default are appropriate here.


558-567: Helper resolution reads clean and efficient.

The accessor-based resolution and fallback are straightforward.

src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (2)

20-26: Primary‑ctor refactor LGTM.

Sealed type with DI parameters simplifies state; telemetry usage remains scoped.


180-185: Correct: set service‑owner auth for potentially restricted data.

Fetching metadata and applying overrides before read is appropriate.

test/Altinn.App.Api.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1)

568-568: IAppMetadata is already registered in DI — no action required.

IAppMetadata is registered via services.TryAddSingleton<IAppMetadata, AppMetadata>() in src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs (around line 172).

Comment thread src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
Comment thread src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs Outdated
@bjorntore

Copy link
Copy Markdown
Contributor

/publish

@github-actions

github-actions Bot commented Sep 16, 2025 •

Copy link
Copy Markdown

PR release:

⚙️ Building...
✅ Done!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (2)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (1)

82-86: Add null guards and ensure all implementers override this (no throws).

Defensive checks avoid hidden NREs and make misconfigurations fail fast. Also ensure every IInstanceDataAccessor implementer provides a real implementation (no NotImplementedException).

Apply:

 public void OverrideAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method)
 {
+    ArgumentNullException.ThrowIfNull(dataType);
+    ArgumentNullException.ThrowIfNull(method);
     _authenticationMethodOverrides[dataType.Id] = method;
 }

Run to verify no NotImplementedException remains:

#!/bin/bash
rg -nP --type=cs -C2 '\bclass\s+\w+\s*:\s*[^{]*\bIInstanceDataAccessor\b'
rg -nP --type=cs -C2 'OverrideAuthenticationMethod\s*\(.*\)\s*=>\s*throw\s+new\s+NotImplementedException'
rg -nP --type=cs -C3 'OverrideAuthenticationMethod\s*\(.*\)\s*{\s*throw\s+new\s+NotImplementedException'
src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (1)

74-76: Apply ServiceOwner auth before delete/read to avoid 403 on restricted types.

You still configure auth after calling RemoveSigneeState; move it before any read/write/delete on restricted types.

Apply:

@@
-        //TODO: Can be removed when AddBinaryDataElement supports setting generatedFromTask, because then it will be automatically deleted in ProcessTaskInitializer.
-        RemoveSigneeState(instanceDataMutator, signeeStateDataTypeId);
+        // Ensure ServiceOwner auth is applied for restricted types before any reads/writes/deletes.
+        ApplicationMetadata applicationMetadata = await _appMetadata.GetApplicationMetadata();
+        instanceDataMutator.OverrideAuthenticationMethodForRestrictedDataTypes(
+            applicationMetadata,
+            [signeeStateDataTypeId],
+            StorageAuthenticationMethod.ServiceOwner()
+        );
+
+        // TODO: Can be removed when AddBinaryDataElement supports setting generatedFromTask, because then it will be automatically deleted in ProcessTaskInitializer.
+        RemoveSigneeState(instanceDataMutator, signeeStateDataTypeId);
@@
-        ApplicationMetadata applicationMetadata = await _appMetadata.GetApplicationMetadata();
-        instanceDataMutator.OverrideAuthenticationMethodForRestrictedDataTypes(
-            applicationMetadata,
-            [signeeStateDataTypeId],
-            StorageAuthenticationMethod.ServiceOwner()
-        );
+        // (moved earlier)

Consider doing the same before deletes in AbortRuntimeDelegatedSigning.

Also applies to: 143-149

🧹 Nitpick comments (6)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)

8-9: Prefer internal sealed for test utility class.

Aligns with guidelines: default internal, sealed unless inheritance is intended.

-public class InstanceDataAccessorFake : IInstanceDataAccessor, IEnumerable<KeyValuePair<DataElement?, object>>
+internal sealed class InstanceDataAccessorFake : IInstanceDataAccessor, IEnumerable<KeyValuePair<DataElement?, object>>

If other test projects reflectively instantiate this, keep it public; otherwise switch to internal.


87-96: Remove unreachable null-check on _applicationMetadata.

Field is non-nullable, assigned in ctor (with fallback), so this branch cannot execute.

-    if (_applicationMetadata is null)
-    {
-        throw new InvalidOperationException("Application metadata not set for InstanceDataAccessorFake");
-    }
test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1)

1259-1260: Define scope/thread-safety and lifecycle of auth overrides

Please document whether overrides are per‑accessor instance, per‑request, and thread‑safe. Also clarify reset semantics (e.g., auto‑reset after operation or explicit reset API) to avoid bleed‑through across operations. XML docs on the interface method would suffice.

src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (1)

558-567: Helper methods look good; consider aligning ID comparisons across codebase.

If other lookups are case-sensitive (e.g., GetDataTypeByString), decide on one policy. No change required here.

test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs (1)

151-153: Tests now expect exceptions; rename for clarity and assert message.

Method names still say “LogError/ReturnEmptyList”. Rename to reflect throws and optionally assert the exception message for stronger intent.

Example:

var ex = await Assert.ThrowsAsync<Exception>(() => _validator.Validate(dataAccessorMock.Object, taskId, null!));
Assert.Equal("Error fetching metadata", ex.Message);

Also applies to: 178-180

src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)

15-28: Add null guards and use params for convenience.

Safer API and simpler call sites.

Apply:

-    public static void OverrideAuthenticationMethodForRestrictedDataTypes(
+    public static void OverrideAuthenticationMethodForRestrictedDataTypes(
         this IInstanceDataAccessor accessor,
         ApplicationMetadata appMetadata,
-        string?[] dataTypeIds,
+        params string?[] dataTypeIds,
         StorageAuthenticationMethod authenticationMethod
     )
     {
+        ArgumentNullException.ThrowIfNull(accessor);
+        ArgumentNullException.ThrowIfNull(appMetadata);
+        ArgumentNullException.ThrowIfNull(dataTypeIds);
+        ArgumentNullException.ThrowIfNull(authenticationMethod);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1c9f42f and 756286c.

📒 Files selected for processing (11)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (1 hunks)
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (3 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (8 hunks)
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (2 hunks)
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (2 hunks)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (7 hunks)
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (1 hunks)
  • test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs (2 hunks)
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (1 hunks)
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
  • src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs
🧰 Additional context used
📓 Path-based instructions (6)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
test/Altinn.App.Core.Tests/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Provide corresponding test coverage for each Core feature under /test/Altinn.App.Core.Tests/Features

Files:

  • test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs
test/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.cs: Test projects mirror source structure
Prefer xUnit asserts over FluentAssertions
Mock external dependencies with Moq

Files:

  • test/Altinn.App.Core.Tests/Features/Validators/Default/SigningTaskValidatorTests.cs
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs: Types meant to be implemented by apps should be marked with the ImplementableByApps attribute
For HTTP APIs, define DTOs with ...Request and ...Response naming

Files:

  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
src/Altinn.App.Core/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
🧠 Learnings (4)
📚 Learning: 2025-08-22T13:46:43.017Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1446
File: test/Altinn.App.Integration.Tests/Basic/_snapshots/BasicAppTests.Full_auth=ServiceOwner_testCase=MultipartXmlPrefill_7_Logs.verified.txt:41-42
Timestamp: 2025-08-22T13:46:43.017Z
Learning: In Altinn App Integration Tests, OldUser and OldServiceOwner test snapshots intentionally preserve the legacy "AuthMethod: localtest" authentication method as part of a migration strategy, while new User and ServiceOwner tests use updated authentication methods like BankID and maskinporten. The "Old*" variants should not be updated to remove localtest references.

Applied to files:

  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to src/Altinn.App.Core/Features/**/*.cs : New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn app-lib-dotnet projects, ImplicitUsings is enabled in Directory.Build.props, which automatically includes common using statements including Xunit namespace for test projects. This eliminates the need for explicit "using Xunit;" statements in test files.

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn.App.Integration.Tests project, xUnit attributes like [Fact] are available without explicit "using Xunit;" directives, likely through global usings or implicit usings configuration. The code compiles and works as-is.

Applied to files:

  • src/Altinn.App.Core/Features/Signing/Services/SigningService.cs
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
🧬 Code graph analysis (5)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (3)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • OverrideAuthenticationMethod (48-48)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • OverrideAuthenticationMethod (83-86)
  • DataType (140-140)
  • DataType (547-556)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • OverrideAuthenticationMethod (94-95)
  • DataType (92-92)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • OverrideAuthenticationMethod (48-48)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • OverrideAuthenticationMethod (94-95)
  • DataType (92-92)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • OverrideAuthenticationMethod (98-101)
  • DataType (87-96)
src/Altinn.App.Core/Features/Signing/Services/SigningService.cs (2)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • OverrideAuthenticationMethodForRestrictedDataTypes (15-28)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (3)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • StorageAuthenticationMethod (558-563)
  • StorageAuthenticationMethod (565-566)
  • DataType (140-140)
  • DataType (547-556)
  • OverrideAuthenticationMethod (83-86)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (9)
  • IEnumerable (98-101)
  • IEnumerable (106-109)
  • IEnumerable (117-130)
  • IEnumerable (135-147)
  • IEnumerable (152-165)
  • IEnumerable (170-182)
  • DataType (41-41)
  • DataType (60-75)
  • OverrideAuthenticationMethod (48-48)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • DataType (87-96)
  • OverrideAuthenticationMethod (98-101)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (3)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (2)
  • SigneeContext (182-191)
  • SignDocument (80-91)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • DataType (35-38)
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)
  • SignDocument (180-199)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Static code analysis
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Run dotnet build and test (windows-latest)
  • GitHub Check: Run dotnet build and test (macos-latest)
  • GitHub Check: Run dotnet build and test (ubuntu-latest)
🔇 Additional comments (6)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)

50-53: Good: sensible defaults for auth overrides.

ConcurrentDictionary keyed by dataType.Id with CurrentUser() default keeps behavior stable for non-restricted types.


119-121: Passing auth through read path is correct.

This ensures per-type overrides are honored for GetDataBytes.


451-453: Good: delete path also honors auth override.

src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (1)

90-96: Direct async calls + exception propagation: OK.

Matches the updated tests’ expectations.

src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (2)

30-39: Lookup helpers are fine; consistent case-insensitive matching.

No change required.


40-43: Restriction check reads clearly.

Good use of NotNullWhen for flow analysis.

Comment thread src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs Outdated
Comment thread src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs Outdated
Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (1)

102-104: Fix compile-time issue: MinCount is nullable; treat null as 0 and reuse counts

signatureDataType.MinCount is nullable; signedCount >= signatureDataType.MinCount yields a nullable bool and won’t compile. Also, reuse signedCount to compute “all signed.”

Apply this diff:

-        int signedCount = signeeContextsResult.Count(signeeContext => signeeContext.SignDocument is not null);
-        bool haveMinimumAmountOfSignatures = signedCount >= signatureDataType.MinCount;
-        bool allSigneesHaveSigned = signeeContextsResult.All(signeeContext => signeeContext.SignDocument is not null);
+        int minRequired = signatureDataType.MinCount ?? 0;
+        int signedCount = signeeContextsResult.Count(ctx => ctx.SignDocument is not null);
+        bool haveMinimumAmountOfSignatures = signedCount >= minRequired;
+        bool allSigneesHaveSigned = signedCount == signeeContextsResult.Count;
🧹 Nitpick comments (2)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (2)

90-96: Optional: Avoid CancellationToken.None

If feasible in this code path, prefer threading through a CancellationToken to _appMetadata.GetApplicationMetadata() and _signingService.GetSigneeContexts(...) instead of CancellationToken.None.


106-107: Confirm intended semantics: require all signees or allow min-count?

The current condition requires both minimum count and that every signee has signed. If the intent is “all parties must sign,” allSigneesHaveSigned alone is sufficient; if min-count should allow completion earlier, use ||.

Example (choose per spec):

-        if (haveMinimumAmountOfSignatures && allSigneesHaveSigned)
+        if (allSigneesHaveSigned)

or

-        if (haveMinimumAmountOfSignatures && allSigneesHaveSigned)
+        if (haveMinimumAmountOfSignatures || allSigneesHaveSigned)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 756286c and 633a8d7.

📒 Files selected for processing (1)
  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs: Types meant to be implemented by apps should be marked with the ImplementableByApps attribute
For HTTP APIs, define DTOs with ...Request and ...Response naming

Files:

  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
src/Altinn.App.Core/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Files:

  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
🧠 Learnings (1)
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn.App.Integration.Tests project, xUnit attributes like [Fact] are available without explicit "using Xunit;" directives, likely through global usings or implicit usings configuration. The code compiles and works as-is.

Applied to files:

  • src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs
🧬 Code graph analysis (1)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (4)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (2)
  • SigneeContext (182-191)
  • SignDocument (80-91)
src/Altinn.App.Core/Features/Signing/Extensions/SigningInstanceDataAccessorExtensions.cs (1)
  • DataType (35-38)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (2)
  • DataType (41-41)
  • DataType (60-75)
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)
  • SignDocument (180-199)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Static code analysis
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Run dotnet build and test (macos-latest)
  • GitHub Check: Run dotnet build and test (windows-latest)
  • GitHub Check: Run dotnet build and test (ubuntu-latest)
🔇 Additional comments (1)
src/Altinn.App.Core/Features/Validation/Default/SigningTaskValidator.cs (1)

2-2: LGTM: Needed using

Import is required for SigneeContext and related models.

Comment thread src/Altinn.App.Core/Features/IInstanceDataAccessor.cs Outdated

@ivarne ivarne left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick read through of IInstanceDataAccessor related code found just a few minor nits

Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (1)

231-236: Fix mock setup: wrong GetBinaryData overload

Production calls GetBinaryData(DataElement), but the test sets up the DataElementIdentifier overload. This will return default data and can break the test.

Apply this diff to set up the correct overloads:

-        cachedInstanceMutator
-            .Setup(x => x.GetBinaryData(new DataElementIdentifier(signDocumentDataElement1.Id)))
-            .ReturnsAsync(new ReadOnlyMemory<byte>(ToBytes(signDocument1)));
+        cachedInstanceMutator
+            .Setup(x => x.GetBinaryData(signDocumentDataElement1))
+            .ReturnsAsync(new ReadOnlyMemory<byte>(ToBytes(signDocument1)));

-        cachedInstanceMutator
-            .Setup(x => x.GetBinaryData(new DataElementIdentifier(signDocumentDataElement2.Id)))
-            .ReturnsAsync(new ReadOnlyMemory<byte>(ToBytes(signDocument2)));
+        cachedInstanceMutator
+            .Setup(x => x.GetBinaryData(signDocumentDataElement2))
+            .ReturnsAsync(new ReadOnlyMemory<byte>(ToBytes(signDocument2)));

Alternatively, if you prefer the identifier overload, relax the matcher instead of constructing a new identifier instance:

- .Setup(x => x.GetBinaryData(new DataElementIdentifier(signDocumentDataElement1.Id)))
+ .Setup(x => x.GetBinaryData(It.Is<DataElementIdentifier>(d => d.Id == signDocumentDataElement1.Id)))
🧹 Nitpick comments (5)
test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (3)

1-1: Remove unused using

System.Reflection isn’t used in this file. Drop it to keep test files lean.

-using System.Reflection;

462-467: Verify auth override happens before reading data

You verify that OverrideAuthenticationMethod(...) is called, but not that it occurs before GetBinaryData(...). Enforce call order with MockSequence so we don’t regress and read restricted data without the override.

Apply this diff within the test to replace the existing GetBinaryData setup and add an ordered expectation:

-        cachedInstanceAccessor
-            .Setup(x => x.GetBinaryData(signeeStateDataElement))
-            .ReturnsAsync(new ReadOnlyMemory<byte>(serializedData));
+        var sequence = new MockSequence();
+        cachedInstanceAccessor
+            .InSequence(sequence)
+            .Setup(m =>
+                m.OverrideAuthenticationMethod(
+                    It.Is<DataType>(dt => dt.Id == signatureConfiguration.SigneeStatesDataTypeId),
+                    StorageAuthenticationMethod.ServiceOwner()
+                )
+            );
+        cachedInstanceAccessor
+            .InSequence(sequence)
+            .Setup(x => x.GetBinaryData(signeeStateDataElement))
+            .ReturnsAsync(new ReadOnlyMemory<byte>(serializedData));

Keep the existing Verify(...) to assert it happened exactly once.

Also applies to: 498-505


508-534: Rename test to reflect behavior and avoid duplication with Line 347 test

This test name says “ThrowsApplicationConfigException” but the assertion expects an empty result with no throw; it also duplicates the scenario already covered in GetSigneeContexts_WithNoSigneeStatesDataTypeId_ReturnsEmptyList (Lines 347–375). Rename or remove one to reduce redundancy.

-    public async Task GetSigneeContexts_WithMissingSigneeStatesDataTypeId_ThrowsApplicationConfigException()
+    public async Task GetSigneeContexts_WithMissingSigneeStatesDataTypeId_ReturnsEmptyList()

If you keep both, differentiate them (e.g., one validates log message or verifies no auth override call occurs).

test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (2)

38-46: Minor: align ApplicationMetadata AppId with instance AppId

Not functionally required here, but matching the AppId avoids confusion when debugging.

Apply this diff:

-                new ApplicationMetadata("ttd/app")
+                new ApplicationMetadata("ttd/app1")

251-258: Verification is brittle to future metadata changes

Verifying OverrideAuthenticationMethod once is fine now, but will fail if multiple restricted data types are passed later. Consider tying expected calls to the number of restricted data types.

Example:

-        cachedInstanceMutator.Verify(
+        var expectedCalls = 1; // number of restricted data types under test
+        cachedInstanceMutator.Verify(
             m =>
                 m.OverrideAuthenticationMethod(
                     It.Is<DataType>(dt => dt.Id == signatureConfiguration.SignatureDataType),
                     StorageAuthenticationMethod.ServiceOwner()
                 ),
-            Times.Once
+            Times.Exactly(expectedCalls)
         );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26eee00 and b4f1f15.

📒 Files selected for processing (2)
  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (5 hunks)
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (10 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
test/Altinn.App.Core.Tests/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

Provide corresponding test coverage for each Core feature under /test/Altinn.App.Core.Tests/Features

Files:

  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
test/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.cs: Test projects mirror source structure
Prefer xUnit asserts over FluentAssertions
Mock external dependencies with Moq

Files:

  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
🧠 Learnings (6)
📚 Learning: 2025-08-22T13:46:43.017Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1446
File: test/Altinn.App.Integration.Tests/Basic/_snapshots/BasicAppTests.Full_auth=ServiceOwner_testCase=MultipartXmlPrefill_7_Logs.verified.txt:41-42
Timestamp: 2025-08-22T13:46:43.017Z
Learning: In Altinn App Integration Tests, OldUser and OldServiceOwner test snapshots intentionally preserve the legacy "AuthMethod: localtest" authentication method as part of a migration strategy, while new User and ServiceOwner tests use updated authentication methods like BankID and maskinporten. The "Old*" variants should not be updated to remove localtest references.

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to src/Altinn.App.Core/Features/**/*.cs : New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs : Types meant to be implemented by apps should be marked with the ImplementableByApps attribute

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn app-lib-dotnet projects, ImplicitUsings is enabled in Directory.Build.props, which automatically includes common using statements including Xunit namespace for test projects. This eliminates the need for explicit "using Xunit;" statements in test files.

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn.App.Integration.Tests project, xUnit attributes like [Fact] are available without explicit "using Xunit;" directives, likely through global usings or implicit usings configuration. The code compiles and works as-is.

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
📚 Learning: 2025-08-29T11:06:37.385Z
Learnt from: CR
PR: Altinn/app-lib-dotnet#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-29T11:06:37.385Z
Learning: Applies to test/Altinn.App.Integration.Tests/**/*.cs : Include integration tests for platform service interactions (using Docker Testcontainers)

Applied to files:

  • test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs
🧬 Code graph analysis (2)
test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (1)
src/Altinn.App.Core/Features/Signing/Services/SignDocumentManager.cs (1)
  • SignDocumentManager (21-341)
test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (2)
src/Altinn.App.Core/Features/Signing/Services/SigneeContextsManager.cs (1)
  • SigneeContextsManager (20-205)
src/Altinn.App.Core/Internal/Process/ProcessTasks/SigningProcessTask.cs (1)
  • DataType (85-88)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Run dotnet build and test (windows-latest)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Run dotnet build and test (ubuntu-latest)
  • GitHub Check: Run dotnet build and test (macos-latest)
  • GitHub Check: Static code analysis
🔇 Additional comments (13)
test/Altinn.App.Core.Tests/Features/Signing/SigneeContextsManagerTests.cs (7)

9-10: LGTM: required usings

Adding Internal.App, Internal.Data, and Core.Models usings aligns with the new metadata + accessor extensions.

Also applies to: 13-13


41-41: LGTM: app metadata is now a first‑class dependency

Adding IAppMetadata mock is correct for driving data‑type based behavior.


45-45: LGTM: central constant for data type id

Using a single SigneeStatesDataTypeId constant avoids string drift across tests.


56-66: LGTM: metadata setup covers restricted-read path

Providing ActionRequiredToRead = "restricted-read" ensures the restricted override extension has something to act on.


73-73: LGTM: pass metadata into manager

Constructor wiring matches the production signature.


126-127: LGTM: config now uses the shared data type id

Replacing hardcoded "signeeStates" with SigneeStatesDataTypeId across tests is consistent and future‑proof.

Also applies to: 227-228, 294-295, 325-325, 385-385, 415-416


418-423: LGTM: data element uses the configured data type

Ensures the accessor extension finds the correct element.

test/Altinn.App.Core.Tests/Features/Signing/SignDocumentManagerTests.cs (6)

26-26: Good: app metadata mock added for restricted data handling

This aligns tests with the new IAppMetadata dependency.


30-30: Nice: centralized SignatureDataTypeId constant

Reduces duplication and keeps tests consistent.


47-47: Constructor wiring looks correct

Injecting IAppMetadata into SignDocumentManager in tests matches the production signature.


200-200: Good: uses the shared SignatureDataTypeId

Keeps the setup tight and intention‑revealing.


284-285: Good: consistent use of SignatureDataTypeId

Keeps tests coherent with the new config shape.


318-324: Good: data element uses configured SignatureDataType

Matches production flow that filters by configured type.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)

391-398: Dispose MemoryAsStream to avoid leaks.

Ensure the stream is disposed even if IDataClient does not dispose inputs.

Apply:

-        var dataElement = await _dataClient.InsertBinaryData(
+        using var stream = new MemoryAsStream(bytes);
+        var dataElement = await _dataClient.InsertBinaryData(
             Instance.Id,
             change.DataType.Id,
             change.ContentType,
             (change as BinaryDataChange)?.FileName,
-            new MemoryAsStream(bytes),
+            stream,
             authenticationMethod: GetAuthenticationMethod(change.DataType)
         );

414-421: Dispose MemoryAsStream here as well.

Same leak risk on updates.

Apply:

-        var newDataElement = await _dataClient.UpdateBinaryData(
+        using var stream = new MemoryAsStream(bytes);
+        var newDataElement = await _dataClient.UpdateBinaryData(
             new InstanceIdentifier(Instance),
             contentType,
             filename,
             dataElementIdentifier.Guid,
-            new MemoryAsStream(bytes),
+            stream,
             authenticationMethod: GetAuthenticationMethod(dataElementIdentifier)
         );
🧹 Nitpick comments (5)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (2)

43-51: Clarify null/override semantics in the API contract.

Document null guards and last‑writer‑wins behavior to set expectations for implementers/callers.

Apply:

     /// <summary>
     /// <para>Set the authentication method used when reading and writing data of the given data type.</para>
     /// <para>This method allows multiple calls to the same <see cref="DataType"/> key, but only the last
     /// invocation will be used by the read/write process. If you need to obtain a list of currently registered
     /// overrides, see the <see cref="AuthenticationMethodOverrides"/> property.</para>
     /// </summary>
+    /// <exception cref="ArgumentNullException">
+    /// Thrown if <paramref name="dataType"/> or <paramref name="method"/> is null.
+    /// </exception>
     /// <param name="dataType">The <see cref="DataType"/> this configuration applies to.</param>
     /// <param name="method">The <see cref="StorageAuthenticationMethod"/> to associate with the given data type.</param>
     void OverrideAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method);

53-56: Document snapshot semantics and advise caching for hot paths.

Property returns a fresh immutable snapshot on each access — InstanceDataUnitOfWork's getter calls _authenticationMethodOverrides.ToImmutableDictionary() (src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs). Update the XML docs to state this and advise callers to cache the result when used in tight loops; no call-sites were found in the repo beyond the property declarations.

src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)

458-460: Prefer named boolean argument for clarity.

Passing a bare false is ambiguous; use the parameter name (e.g., hardDelete: false) for readability.


648-671: Seal the comparer and use explicit ordinal hashing.

Minor robustness/readability tweaks.

Apply:

-internal class DataTypeComparer : IEqualityComparer<DataType>
+internal sealed class DataTypeComparer : IEqualityComparer<DataType>
 {
@@
-    public int GetHashCode(DataType obj) => obj.Id != null ? obj.Id.GetHashCode() : 0;
+    public int GetHashCode(DataType obj) =>
+        obj.Id is not null ? StringComparer.Ordinal.GetHashCode(obj.Id) : 0;
 }

25-28: Snapshot allocation on each AuthenticationMethodOverrides access

AuthenticationMethodOverrides returns _authenticationMethodOverrides.ToImmutableDictionary(), which allocates a new snapshot on every get. If this property is read frequently, either cache/memoize the immutable snapshot (invalidate on writes) or add a read API like TryGetAuthenticationMethod(DataType, out StorageAuthenticationMethod) to avoid full copies; if reads are rare, document the allocation cost. Repo scan shows only the interface, LayoutEvaluatorStateInitializer and a test fake references—no obvious hot-path usages.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96eeadb and cd00624.

📒 Files selected for processing (5)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (1 hunks)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (10 hunks)
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (1 hunks)
  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1 hunks)
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
🧰 Additional context used
📓 Path-based instructions (5)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
test/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.cs: Test projects mirror source structure
Prefer xUnit asserts over FluentAssertions
Mock external dependencies with Moq

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs: Types meant to be implemented by apps should be marked with the ImplementableByApps attribute
For HTTP APIs, define DTOs with ...Request and ...Response naming

Files:

  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
src/Altinn.App.Core/Features/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

New features should follow the established feature pattern under /src/Altinn.App.Core/Features (feature folder, DI registration, telemetry, and tests)

Files:

  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
🧬 Code graph analysis (3)
test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)
  • DataType (147-147)
  • DataType (554-563)
  • DataTypeComparer (651-670)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (5)
  • OverrideAuthenticationMethod (90-93)
  • DataType (147-147)
  • DataType (554-563)
  • StorageAuthenticationMethod (565-570)
  • StorageAuthenticationMethod (572-573)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • OverrideAuthenticationMethod (94-95)
  • DataType (92-92)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • OverrideAuthenticationMethod (98-101)
  • DataType (87-96)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • DataType (41-41)
  • DataType (68-83)
  • OverrideAuthenticationMethod (51-51)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • DataType (92-92)
  • OverrideAuthenticationMethod (94-95)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • DataType (87-96)
  • OverrideAuthenticationMethod (98-101)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Static code analysis
🔇 Additional comments (4)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)

55-60: LGTM on defaults.

Using a per‑process default (CurrentUser) and a per‑UoW override map is sensible.


565-574: LGTM on lookup flow.

Overloads keep call sites tidy and hide comparer details.


89-93: Add null guards and short‑circuit equal check in OverrideAuthenticationMethod

Fail fast on misconfigured metadata; keep last‑writer‑wins behavior.

Location: src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs

 public void OverrideAuthenticationMethod(DataType dataType, StorageAuthenticationMethod method)
 {
-    _authenticationMethodOverrides[dataType] = method;
+    ArgumentNullException.ThrowIfNull(dataType);
+    ArgumentNullException.ThrowIfNull(method);
+    if (_authenticationMethodOverrides.TryGetValue(dataType, out var existing) && Equals(existing, method))
+    {
+        return;
+    }
+    _authenticationMethodOverrides[dataType] = method;
 }

Also ensure all IInstanceDataMutator implementers implement this method (no NotImplementedException):

#!/bin/bash
set -euo pipefail
rg -n --hidden -S -g '!**/bin/**' -g '!**/obj/**' '\b:\s*IInstanceDataMutator\b' -C3 || true
rg -n --hidden -S -g '!**/bin/**' -g '!**/obj/**' 'OverrideAuthenticationMethod\s*\(.*\)\s*=>\s*throw\s+new\s+NotImplementedException' -C3 || true
rg -n --hidden -S -g '!**/bin/**' -g '!**/obj/**' 'OverrideAuthenticationMethod\s*\(.*\)\s*\{[^}]*throw\s+new\s+NotImplementedException' -C3 || true
test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1)

8-28: Add a null-Id unit test; internals and xUnit availability verified

  • Add a test asserting DataType.Id == null — expect GetHashCode(obj) == 0 and equality to compare by Id (null == null → equal; null vs non-null → not equal).
  • Internals are already exposed (src/Altinn.App.Core/Altinn.App.Core.csproj contains InternalsVisibleTo) and DataTypeComparer is internal at src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs; test project enables ImplicitUsings and references xUnit so [Fact] is available.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)

391-399: Dispose MemoryAsStream to avoid leaks.

Wrap the stream in a using to ensure disposal after the call completes.

-        var dataElement = await _dataClient.InsertBinaryData(
+        DataElement dataElement;
+        using (var stream = new MemoryAsStream(bytes))
+        {
+            dataElement = await _dataClient.InsertBinaryData(
             Instance.Id,
             change.DataType.Id,
             change.ContentType,
             (change as BinaryDataChange)?.FileName,
-            new MemoryAsStream(bytes),
+            stream,
             authenticationMethod: GetAuthenticationMethod(change.DataType)
-        );
+            );
+        }

414-421: Dispose MemoryAsStream here as well.

Same leak risk on update path.

-        var newDataElement = await _dataClient.UpdateBinaryData(
+        DataElement newDataElement;
+        using (var stream = new MemoryAsStream(bytes))
+        {
+            newDataElement = await _dataClient.UpdateBinaryData(
             new InstanceIdentifier(Instance),
             contentType,
             filename,
             dataElementIdentifier.Guid,
-            new MemoryAsStream(bytes),
+            stream,
             authenticationMethod: GetAuthenticationMethod(dataElementIdentifier)
-        );
+            );
+        }
🧹 Nitpick comments (2)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (2)

572-574: Guard against invalid DataType in resolver (debug-level).

Add an assertion to catch unexpected null Ids early.

-private StorageAuthenticationMethod GetAuthenticationMethod(DataType dataType) =>
-    _authenticationMethodOverrides.GetValueOrDefault(dataType, _defaultAuthenticationMethod);
+private StorageAuthenticationMethod GetAuthenticationMethod(DataType dataType)
+{
+    Debug.Assert(dataType.Id is not null, "DataType.Id must be set");
+    return _authenticationMethodOverrides.GetValueOrDefault(dataType, _defaultAuthenticationMethod);
+}

651-670: Tighten comparer implementation.

Seal the comparer and use StringComparer.Ordinal for stable hashing; assert non-null Ids.

-internal class DataTypeComparer : IEqualityComparer<DataType>
+internal sealed class DataTypeComparer : IEqualityComparer<DataType>
 {
@@
-    public int GetHashCode(DataType obj) => obj.Id != null ? obj.Id.GetHashCode() : 0;
+    public int GetHashCode(DataType obj)
+    {
+        Debug.Assert(obj.Id is not null, "DataType.Id must not be null");
+        return System.StringComparer.Ordinal.GetHashCode(obj.Id ?? string.Empty);
+    }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96eeadb and cac029e.

📒 Files selected for processing (6)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (1 hunks)
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (10 hunks)
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (1 hunks)
  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1 hunks)
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (1 hunks)
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Altinn.App.Core/Features/IInstanceDataAccessor.cs
  • test/Altinn.App.Core.Tests/PublicApiTests.PublicApi_ShouldNotChange_Unintentionally.verified.txt
  • test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs
  • src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs
🧰 Additional context used
📓 Path-based instructions (4)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: Use internal accessibility on types by default
Use sealed for classes unless inheritance is a valid use-case
Dispose IDisposable/IAsyncDisposable instances
Do not use .GetAwaiter().GetResult(), .Result(), .Wait(), or other blocking APIs on Task
Do not use the Async suffix for async methods
Write efficient code; avoid unnecessary allocations (e.g., avoid repeated ToString calls; consider for-loops over LINQ when appropriate)
Do not invoke the same async operation multiple times in the same code path unless necessary
Avoid awaiting async operations inside tight loops; prefer batching with a sensible upper bound on parallelism
Use CSharpier for formatting (required before commits; formatting also runs on build via CSharpier.MSBuild)

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
**/*.{cs,csproj}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Nullable Reference Types

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
test/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.cs: Test projects mirror source structure
Prefer xUnit asserts over FluentAssertions
Mock external dependencies with Moq

Files:

  • test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs
src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

src/{Altinn.App.Api,Altinn.App.Core}/**/*.cs: Types meant to be implemented by apps should be marked with the ImplementableByApps attribute
For HTTP APIs, define DTOs with ...Request and ...Response naming

Files:

  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
🧠 Learnings (1)
📚 Learning: 2025-08-29T10:45:57.158Z
Learnt from: martinothamar
PR: Altinn/app-lib-dotnet#1456
File: test/Altinn.App.Integration.Tests/_fixture/Tests.cs:3-4
Timestamp: 2025-08-29T10:45:57.158Z
Learning: In Altinn app-lib-dotnet projects, ImplicitUsings is enabled in Directory.Build.props, which automatically includes common using statements including Xunit namespace for test projects. This eliminates the need for explicit "using Xunit;" statements in test files.

Applied to files:

  • src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
🧬 Code graph analysis (2)
test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)
  • DataType (147-147)
  • DataType (554-563)
  • DataTypeComparer (651-670)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (4)
src/Altinn.App.Core/Internal/Expressions/LayoutEvaluatorStateInitializer.cs (2)
  • DataType (92-92)
  • OverrideAuthenticationMethod (94-95)
test/Altinn.App.Core.Tests/LayoutExpressions/TestUtilities/InstanceDataAccessorFake.cs (2)
  • DataType (87-96)
  • OverrideAuthenticationMethod (98-99)
src/Altinn.App.Core/Features/IInstanceDataAccessor.cs (3)
  • DataType (41-41)
  • DataType (68-83)
  • OverrideAuthenticationMethod (51-51)
src/Altinn.App.Core/Models/DataElementIdentifier.cs (6)
  • DataElementIdentifier (29-33)
  • DataElementIdentifier (39-43)
  • DataElementIdentifier (48-53)
  • Equals (92-95)
  • Equals (100-103)
  • GetHashCode (108-111)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Run dotnet build and test (ubuntu-latest)
  • GitHub Check: Run dotnet build and test (windows-latest)
  • GitHub Check: Run dotnet build and test (macos-latest)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Static code analysis
🔇 Additional comments (4)
src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs (3)

55-60: Good: concurrent overrides keyed by DataType with custom comparer.

Approach is sound and thread-safe.


126-129: LGTM: auth method plumbed into GetDataBytes.


458-460: LGTM: auth method included in DeleteData.

test/Altinn.App.Core.Tests/Internal/Data/DataTypeComparerTest.cs (1)

6-29: Test covers Id-based key semantics; looks good.

Validates overwrite on same Id and distinct entries on different Ids.

Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
Comment thread src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
44.44% Condition Coverage on New Code (required ≥ 65%)

See analysis details on SonarQube Cloud

@danielskovli
danielskovli merged commit c79351b into main Sep 17, 2025
13 of 14 checks passed
@danielskovli
danielskovli deleted the fix/signing-sensitive-data branch September 17, 2025 11:01
@github-project-automation github-project-automation Bot moved this from 👷 In progress to ✅ Done in Team Altinn Studio Sep 17, 2025
github-actions Bot pushed a commit that referenced this pull request Sep 17, 2025
…1472)

---------
Co-authored-by: Bjørn Tore Gjerde <bjorn.tore.gjerde@vivende.no>
@github-actions

Copy link
Copy Markdown

✅ Automatic backport successful!

A backport PR has been automatically created for the release/v8.7 release branch.

The release branch release/v8.7 already existed and was updated.

The cherry-pick was clean with no conflicts. Please review the backport PR when it appears.

danielskovli added a commit that referenced this pull request Sep 17, 2025
…1472)

---------
Co-authored-by: Bjørn Tore Gjerde <bjorn.tore.gjerde@vivende.no>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport This PR should be cherry-picked onto older release branches bugfix Label Pull requests with bugfix. Used when generation releasenotes kind/incident-B B incident squad/flyt Issues that belongs to the named squad.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants