Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Synchronization of resource policy metadata #1411

Merged
merged 29 commits into from
Nov 15, 2024

Conversation

elsand
Copy link
Member

@elsand elsand commented Nov 6, 2024

Description

This adds a command akin to sync-subject-resources which fetches information about resource policies and stores the information to a table in postgres. For now, this only parses and stores XACML obligations for required authentication level, but can be fairly easily extended to implement eg. #40

There are however some real limitations to the Resource Registry as of now for Altinn Apps, as they are not really stored there, but merely have a representation that does not include the policy. For these, we store a default authentication level. Edit: We don't do this, as we cannot safely assume anything here. So we do not store anything unless we have an explicit obligation for authentication level set in a policy we can reach. For all other resources, no authentication level handling will be performed.

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)

Documentation

  • Documentation is updated (either in docs-directory, Altinnpedia or a separate linked PR in altinn-studio-docs., if applicable)

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new command for synchronizing resource policies.
    • Added support for managing resource policy information in various environments (production, staging, test).
    • Enhanced deployment capabilities with a new scheduled job for resource policy synchronization.
  • Bug Fixes

    • Improved error handling and logging during synchronization processes.
  • Documentation

    • Updated command documentation to include new synchronization options and parameters.
  • Chores

    • Added new settings to local development configurations to manage synchronization behavior at startup.
    • Introduced additional configuration settings for local development to control synchronization processes.

Copy link
Contributor

coderabbitai bot commented Nov 6, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

This pull request introduces several changes primarily focused on the deployment of a scheduled job within Azure using Bicep files. It includes the creation of parameter files for different environments (production, staging, test, and a specific environment named yt01), which define job scheduling and resource configurations. Additionally, it enhances the data access layer by introducing new repository interfaces and classes for managing resource policy information, along with updates to existing services and commands for synchronization tasks.

Changes

File Change Summary
.azure/applications/sync-resource-policy-information-job/main.bicep Added parameters for job configuration and outputs for identity and name.
.azure/applications/sync-resource-policy-information-job/prod.bicepparam Introduced parameters for production deployment including environment, location, and job schedule.
.azure/applications/sync-resource-policy-information-job/staging.bicepparam Introduced parameters for staging deployment with similar structure to production.
.azure/applications/sync-resource-policy-information-job/test.bicepparam Introduced parameters for test deployment, defining environment and job schedule.
.azure/applications/sync-resource-policy-information-job/yt01.bicepparam Introduced parameters for yt01 environment deployment, including job schedule and resource configurations.
.github/workflows/workflow-deploy-apps.yml Added a new job for sync-resource-policy-information-job to the deployment workflow.
src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs Added a new property for managing ResourcePolicyInformation.
src/Digdir.Domain.Dialogporten.Application/Externals/IResourcePolicyInformationRepository.cs Introduced an interface for managing resource policy information with methods for merging and retrieving timestamps.
src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs Added a method to retrieve updated resource policy information and introduced a new record for updated resource policy information.
src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs Introduced a new class for resource policy information with relevant properties.
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs Added a method to retrieve updated resource policy information.
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs Updated constructor to include logging and added a method for retrieving updated resource policy information.
src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs Enhanced service registration to include new hosted services and repository interfaces.
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs Introduced configuration for resource policy information entity.
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs Introduced a new hosted service for synchronizing resource policy information in development.
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs Implemented repository for managing resource policy information with methods for retrieving timestamps and merging records.
src/Digdir.Domain.Dialogporten.Janitor/Commands.cs Updated command handling logic to include new synchronization commands.
src/Digdir.Domain.Dialogporten.Janitor/Properties/launchSettings.json Renamed existing profile and added a new profile for resource policy information synchronization.
src/Digdir.Domain.Dialogporten.Janitor/README.md Updated documentation to include new commands and their descriptions.
src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs Added new settings for controlling synchronization behavior on startup.
src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json Modified configuration to include new local development settings for synchronization control.
src/Digdir.Domain.Dialogporten.Janitor/appsettings.Development.json Updated development settings to include synchronization control properties.

Possibly related PRs

Suggested reviewers

  • arealmaas

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@elsand elsand marked this pull request as ready for review November 10, 2024 17:45
@elsand elsand requested review from a team as code owners November 10, 2024 17:45
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 16

🧹 Outside diff range and nitpick comments (40)
src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs (1)

5-6: Add XML documentation for the public API.

Since this class represents an important domain entity for resource policy information, consider adding XML documentation to describe its purpose and usage.

+/// <summary>
+/// Represents resource policy information containing security level requirements for a resource.
+/// </summary>
 public sealed class ResourcePolicyInformation : IEntity
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommandValidator.cs (1)

5-11: Consider enhancing the validator implementation.

While the basic validation is in place, there are several improvements that could make the code more maintainable and user-friendly:

  1. Document the rationale for the concurrent requests range (1-50)
  2. Extract magic numbers into named constants
  3. Add custom error messages for better user experience

Here's a suggested improvement:

 internal sealed class SynchronizeResourcePolicyInformationCommandValidator : AbstractValidator<SynchronizeResourcePolicyInformationCommand>
 {
+    private const int MinConcurrentRequests = 1;
+    private const int MaxConcurrentRequests = 50;
+
     public SynchronizeResourcePolicyInformationCommandValidator()
     {
-        RuleFor(x => x.NumberOfConcurrentRequests).InclusiveBetween(1, 50);
+        RuleFor(x => x.NumberOfConcurrentRequests)
+            .InclusiveBetween(MinConcurrentRequests, MaxConcurrentRequests)
+            .WithMessage("Number of concurrent requests must be between {MinValue} and {MaxValue}");
     }
 }
.azure/applications/sync-resource-policy-information-job/prod.bicepparam (1)

1-11: Consider adding parameter validation.

Consider adding parameter validation to ensure required environment variables are present. Here's a suggested improvement:

 using './main.bicep'

 param environment = 'prod'
 param location = 'norwayeast'
+@minLength(1)
 param imageTag = readEnvironmentVariable('IMAGE_TAG')
 param jobSchedule = '*/30 * * * *' // Runs every 30 minutes

 //secrets
+@minLength(1)
 param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME')
+@minLength(1)
 param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME')
+@secure()
+@minLength(1)
 param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING')
.azure/applications/sync-resource-policy-information-job/test.bicepparam (1)

1-11: Consider implementing parameter validation and documentation

To improve maintainability and prevent configuration drift:

  1. Consider adding parameter validation in the main.bicep template
  2. Document the expected values and constraints for each parameter
  3. Consider creating a parameter schema that can be shared across different environment parameter files (test, prod, staging)

Would you like assistance in generating parameter validation rules or documentation templates?

.azure/applications/sync-resource-policy-information-job/yt01.bicepparam (1)

1-11: Document the purpose and configuration of this job.

Since this is a new scheduled job for syncing resource policy information, it would be beneficial to:

  1. Add comments explaining the job's purpose and impact
  2. Document the expected duration of each run
  3. Specify any dependencies or prerequisites
  4. Describe the consequences of job failure

Add a header comment block like this:

+ # Resource Policy Information Sync Job
+ # 
+ # Purpose: Synchronizes resource policy metadata between systems
+ # Schedule: Runs every 30 minutes
+ # Dependencies: 
+ #   - Azure Container Apps Environment
+ #   - Key Vault access
+ #   - Application Insights for monitoring
+ # Failure Impact: [Describe what happens if the job fails]
+
 using './main.bicep'
.azure/applications/sync-resource-policy-information-job/staging.bicepparam (1)

5-6: Consider optimizing the job schedule and adding environment variable validation.

The current schedule runs every 30 minutes, which might be too frequent for a staging environment. Consider:

  1. Reducing the frequency to hourly or less to minimize resource usage
  2. Adding validation for the IMAGE_TAG environment variable to prevent deployment failures
-param imageTag = readEnvironmentVariable('IMAGE_TAG')
-param jobSchedule = '*/30 * * * *' // Runs every 30 minutes
+param imageTag = readEnvironmentVariable('IMAGE_TAG', true) // Add validation
+param jobSchedule = '0 * * * *' // Runs hourly
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs (2)

6-13: LGTM with suggestions for robustness.

The extension method implementation is clean and follows good practices. However, we could make the string comparison more robust.

Consider this improvement:

 internal static class HostingEnvironmentExtensions
 {
     public static bool ShouldRunDevelopmentHostedService(this IHostEnvironment environment)
     {
         // Only run in development environments, but not when using Janitor
-        return environment.IsDevelopment() && !(Assembly.GetEntryAssembly()?.GetName().Name ?? "").Contains("Janitor");
+        return environment.IsDevelopment() && 
+            !string.Equals(
+                Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty,
+                "Janitor",
+                StringComparison.OrdinalIgnoreCase);
     }
 }

This change:

  1. Uses explicit string comparison instead of Contains
  2. Uses StringComparison.OrdinalIgnoreCase for case-insensitive matching
  3. Uses string.Empty instead of "" for consistency

4-4: Consider documenting the namespace purpose.

Since this is in a Development namespace, it would be helpful to add a comment explaining that this code is intended for development environments only.

Add XML documentation:

+/// <summary>
+/// Contains extensions and utilities specifically for development environment configuration.
+/// Not intended for use in production environments.
+/// </summary>
 namespace Digdir.Domain.Dialogporten.Infrastructure.Persistence.Development;
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs (1)

6-14: LGTM! Consider enhancing the index configuration.

The implementation is correct, but could be improved with the following suggestions:

 builder
-    .HasIndex(r => new { r.Resource })
-    .IsUnique();
+    .HasIndex(r => new { r.Resource }, "IX_ResourcePolicyInformation_Resource")
+    .IsUnique()
+    .HasFilter(null)  // Add filter if soft delete is implemented
+    .HasDatabaseName("IX_ResourcePolicyInformation_Resource");  // Explicit name for better maintainability
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentMigratorHostedService.cs (2)

20-23: Consider adding tests for environment-specific behavior.

Since this service handles critical database migrations, we should ensure the environment check behavior is thoroughly tested.

Consider adding tests that:

  1. Verify migrations run in the correct environments
  2. Verify migrations are skipped in non-development environments
  3. Test edge cases in environment configuration

Would you like me to help create these test cases?


20-20: Document the new environment check method.

The introduction of ShouldRunDevelopmentHostedService() seems to be a significant change in how development services are controlled.

Consider adding XML documentation to the extension method explaining:

  • Its purpose and when it should be used
  • The conditions it checks
  • How it differs from the standard IsDevelopment() check
src/Digdir.Domain.Dialogporten.Janitor/README.md (3)

15-16: LGTM! Consider adding batch size impact details.

The parameters are well documented. However, it would be helpful to add a brief note about how the batch size affects performance or resource usage.

    - `-b` *Optional*: Override the batch size (default: 1000).
+   - `-b` *Optional*: Override the batch size for processing subject-resource mappings. Higher values may improve performance but increase memory usage (default: 1000).
🧰 Tools
🪛 Markdownlint

15-15: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


16-16: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


18-25: Enhance documentation for concurrency behavior.

While the command parameters are documented, additional information would be valuable for operations:

  • How are failed requests handled during concurrent execution?
  • Is there a timeout setting for individual requests?
  • What's the recommended concurrency value for different environments?
    - `-c` *Optional*: Number of concurrent requests to fetch policies (default: 10).
+   - `-c` *Optional*: Number of concurrent requests to fetch policies (default: 10). Adjust based on available system resources and API rate limits. Failed requests are retried up to 3 times before the command fails.
🧰 Tools
🪛 Markdownlint

24-24: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


25-25: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


15-16: Fix list indentation for better markdown formatting.

The unordered lists are currently using 4-space indentation. According to markdown standards, lists should be indented with 2 spaces.

-    - `-s` *Optional*: Override the time of the last synchronization. This argument should be a `DateTimeOffset`, e.g., `2024-08-15` (default: newest in local copy)
-    - `-b` *Optional*: Override the batch size (default: 1000).
+  - `-s` *Optional*: Override the time of the last synchronization. This argument should be a `DateTimeOffset`, e.g., `2024-08-15` (default: newest in local copy)
+  - `-b` *Optional*: Override the batch size (default: 1000).

-    - `-s` *Optional*: Override the time of the last synchronization. This argument should be a `DateTimeOffset`, e.g., `2024-08-15` (default: newest in local copy)
-    - `-c` *Optional*: Number of concurrent requests to fetch policies (default: 10).
+  - `-s` *Optional*: Override the time of the last synchronization. This argument should be a `DateTimeOffset`, e.g., `2024-08-15` (default: newest in local copy)
+  - `-c` *Optional*: Number of concurrent requests to fetch policies (default: 10).

Also applies to: 24-25

🧰 Tools
🪛 Markdownlint

15-15: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


16-16: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (3)

8-12: Add XML documentation to explain the service's purpose.

Consider adding XML documentation to describe:

  • The purpose of this development-only service
  • When it runs and what it synchronizes
  • Why it's sealed (prevents inheritance as it's not designed for extension)
+/// <summary>
+/// Development-only hosted service that synchronizes resource policy information during startup.
+/// This service is sealed as it's not designed for extension and only runs in development environments.
+/// </summary>
 internal sealed class DevelopmentResourcePolicyInformationSyncHostedService : IHostedService

13-17: Consider injecting required services directly instead of IServiceProvider.

The use of IServiceProvider suggests a service locator pattern, which can make dependencies less explicit and harder to test. Consider injecting ISender directly if it's the only required service.

-private readonly IServiceProvider _serviceProvider;
+private readonly ISender _sender;

-public DevelopmentResourcePolicyInformationSyncHostedService(IServiceProvider serviceProvider, IHostEnvironment environment)
+public DevelopmentResourcePolicyInformationSyncHostedService(ISender sender, IHostEnvironment environment)
 {
-    _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
+    _sender = sender ?? throw new ArgumentNullException(nameof(sender));
     _environment = environment ?? throw new ArgumentNullException(nameof(environment));
 }

32-33: Add a comment explaining the empty StopAsync implementation.

Consider documenting why no cleanup is needed when the service stops.

+    /// <summary>
+    /// No cleanup needed as the synchronization is a one-time operation during startup.
+    /// </summary>
     public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs (1)

31-32: Consider adding validation for MinimumSecurityLevel.

The MinimumSecurityLevel property in UpdatedResourcePolicyInformation is defined as an int without any apparent constraints. Consider:

  1. Using an enum if there are predefined security levels
  2. Adding validation to ensure the value falls within an acceptable range
  3. Adding XML documentation to specify the valid range and meaning of different levels

Example implementation with an enum:

public enum SecurityLevel
{
    Level0 = 0,
    Level1 = 1,
    Level2 = 2,
    Level3 = 3,
    Level4 = 4
}

public sealed record UpdatedResourcePolicyInformation(Uri ResourceUrn, SecurityLevel MinimumSecurityLevel, DateTimeOffset UpdatedAt);
src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (2)

29-30: Add parameter validation and documentation.

Consider adding:

  1. XML documentation to describe command purpose and parameters
  2. Validation for numberOfConcurrentRequests to ensure it's positive
+        /// <summary>
+        /// Synchronizes resource policy information.
+        /// </summary>
+        /// <param name="ctx">The Cocona app context</param>
+        /// <param name="application">The mediator sender</param>
+        /// <param name="since">Optional timestamp to sync from</param>
+        /// <param name="numberOfConcurrentRequests">Optional number of concurrent requests (must be positive)</param>
         app.AddCommand("sync-resource-policy-information", async (
                 [FromService] CoconaAppContext ctx,
                 [FromService] ISender application,
                 [Option('s')] DateTimeOffset? since,
-                [Option('c')] int? numberOfConcurrentRequests)
+                [Option('c', Description = "Number of concurrent requests")] int? numberOfConcurrentRequests)

29-30: Consider standardizing option flags across commands.

The existing command uses -b for batch size while the new command uses -c for concurrent requests. Consider standardizing these option flags if they serve similar purposes.

Also applies to: 8-14

src/Digdir.Domain.Dialogporten.Janitor/Digdir.Domain.Dialogporten.Janitor.csproj (1)

33-39: Ensure local settings file is properly ignored.

Since appsettings.local.json typically contains development-specific configurations, ensure it's added to .gitignore to prevent accidental commits of local settings.

Add this entry to .gitignore if not already present:

+appsettings.local.json
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (1)

29-34: Consider adding additional indexes for performance

While the unique index on Resource is good for ensuring data integrity, consider adding an index on MinimumSecurityLevel if you plan to query based on this column frequently.

+ migrationBuilder.CreateIndex(
+     name: "IX_ResourcePolicyInformation_MinimumSecurityLevel",
+     table: "ResourcePolicyInformation",
+     column: "MinimumSecurityLevel");
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentCleanupOutboxHostedService.cs (1)

Line range hint 7-12: Update XML documentation to reflect the new execution condition.

The class XML documentation currently only mentions "development environments" but should be updated to reflect the new, potentially more specific condition for execution.

 /// <summary>
-/// This hosted service is only active in development environments. It cleans up the
+/// This hosted service is only active when ShouldRunDevelopmentHostedService() returns true. It cleans up the
 /// outbox/event tables. However, it keeps the last 12 hours of data to allow for
 /// debugging throughout one workday.
 /// </summary>
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs (1)

46-48: Add documentation for the new method.

The implementation looks good and follows the established patterns. Consider adding XML documentation to explain:

  1. The purpose of this method in the local development context
  2. Why it returns an empty array
  3. The meaning of the parameters (since they're intentionally unused)

Example:

/// <summary>
/// Returns an empty collection as this is a local development implementation.
/// </summary>
/// <param name="since">Timestamp to get updates since (unused in local development)</param>
/// <param name="numberOfConcurrentRequests">Maximum concurrent requests (unused in local development)</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>Empty collection of resource policy information</returns>
.azure/applications/sync-resource-policy-information-job/main.bicep (3)

34-36: Parameterize the base image URL

The base image URL is currently hardcoded. Consider making it a parameter to support different container registries in different environments or scenarios.

Apply this diff:

+@description('The base URL for container images')
+@minLength(3)
+param baseImageUrl string = 'ghcr.io/digdir/dialogporten-'
+
 var namePrefix = 'dp-be-${environment}'
-var baseImageUrl = 'ghcr.io/digdir/dialogporten-'

49-66: Consider adding connection string validation at startup

While the connection strings are properly configured as secrets, consider adding runtime validation in the application startup to fail fast if these connections are invalid.

This could be implemented in the application's Program.cs or startup configuration:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((context, services) =>
        {
            // Validate connection strings at startup
            var dbConnection = context.Configuration["Infrastructure:DialogDbConnectionString"];
            var redisConnection = context.Configuration["Infrastructure:Redis:ConnectionString"];
            
            if (!ValidateConnectionString(dbConnection))
                throw new InvalidOperationException("Invalid database connection string");
                
            if (!ValidateRedisConnectionString(redisConnection))
                throw new InvalidOperationException("Invalid Redis connection string");
        });

85-98: Add semantic version validation for imageTag

Consider adding a regex pattern validation to ensure the imageTag follows semantic versioning.

Apply this diff at the parameters section:

 @description('The tag of the image to be used')
 @minLength(3)
+@pattern('^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$')
 param imageTag string
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeSubjectResourceMappingsCommand.cs (3)

10-14: Add XML documentation for the public command class and its properties.

Since this is a public API, adding XML documentation would improve maintainability and help consumers understand the purpose and usage of the command.

+/// <summary>
+/// Command to synchronize subject resource mappings from the resource registry.
+/// </summary>
 public sealed class SynchronizeSubjectResourceMappingsCommand : IRequest<SynchronizeResourceMappingsResult>
 {
+    /// <summary>
+    /// Optional timestamp to synchronize changes since a specific point in time.
+    /// </summary>
     public DateTimeOffset? Since { get; set; }
+    /// <summary>
+    /// Optional size of batches to process during synchronization.
+    /// </summary>
     public int? BatchSize { get; set; }
 }

Line range hint 43-46: Document the purpose of the 1 microsecond time skew.

The time skew value seems arbitrary. Consider adding a comment explaining why this specific value was chosen and its importance in preventing data synchronization issues.

 var lastUpdated = request.Since
     ?? await _subjectResourceRepository.GetLastUpdatedAt(
+        // Add 1 microsecond to prevent re-processing the last synchronized item
         timeSkew: TimeSpan.FromMicroseconds(1),
         cancellationToken: cancellationToken);

Line range hint 50-85: Consider improving transaction and error handling.

A few suggestions to enhance the robustness of the synchronization:

  1. The transaction scope covers the entire sync operation, which might lead to long-running transactions. Consider using smaller transaction batches.
  2. Add cancellation token checks in the main processing loop.
  3. Catch specific exceptions (e.g., DbException, TimeoutException) before catching the generic Exception.
 try
 {
     var mergeCount = 0;
     var syncTime = DateTimeOffset.Now;
-    await _unitOfWork.BeginTransactionAsync(cancellationToken);
     await foreach (var resourceBatch in _resourceRegistry
         .GetUpdatedSubjectResources(lastUpdated, request.BatchSize ?? DefaultBatchSize, cancellationToken))
     {
+        cancellationToken.ThrowIfCancellationRequested();
+        await _unitOfWork.BeginTransactionAsync(cancellationToken);
         var mergeableSubjectResources = resourceBatch
             .Select(x => x.ToMergableSubjectResource(syncTime))
             .ToList();
         var batchMergeCount = await _subjectResourceRepository.Merge(mergeableSubjectResources, cancellationToken);
+        await _unitOfWork.SaveChangesAsync(cancellationToken);
         _logger.LogInformation("{BatchMergeCount} subject-resources added to transaction.", batchMergeCount);
         mergeCount += batchMergeCount;
     }

-    await _unitOfWork.SaveChangesAsync(cancellationToken);
     if (mergeCount > 0)
     {
         _logger.LogInformation("Successfully synced {UpdatedAmount} total subject-resources. Changes committed.", mergeCount);
     }
     else
     {
         _logger.LogInformation("Subject-resources are already up-to-date.");
     }

     return new Success();
 }
+catch (DbException e)
+{
+    _logger.LogError(e, "Database error while syncing subject-resources. Rolling back transaction.");
+    throw;
+}
+catch (TimeoutException e)
+{
+    _logger.LogError(e, "Timeout while syncing subject-resources. Rolling back transaction.");
+    throw;
+}
 catch (Exception e)
 {
     _logger.LogError(e, "Failed to sync subject-resources. Rolling back transaction.");
     throw;
 }
.github/workflows/workflow-deploy-apps.yml (1)

246-246: Documentation update required.

As per PR objectives, please ensure:

  1. Documentation is added in the docs directory explaining the resource policy synchronization job
  2. Update Altinnpedia if applicable
  3. If needed, create a linked PR in the Altinn Studio documentation repository
src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs (2)

89-93: LGTM! Consider adding documentation.

The new transient services are well-structured:

  • Repository registration follows the established pattern
  • Lazy loading of message handling services is appropriate for integration testing

Consider adding XML documentation to the IResourcePolicyInformationRepository interface to describe its purpose and usage.


230-245: Consider reducing configuration duplication.

The pub-only configuration duplicates much of the pub/sub configuration. Consider extracting common configuration into a shared method to improve maintainability.

Example approach:

+ private static void ConfigureCommonMassTransitOptions(IBusRegistrationConfigurator x, InfrastructureBuilderContext builderContext)
+ {
+     x.AddEntityFrameworkOutbox<DialogDbContext>(o =>
+     {
+         o.UsePostgres();
+         o.UseBusOutbox();
+     });
+ 
+     if (builderContext.Environment.IsDevelopment() && builderContext.DevSettings.UseInMemoryServiceBusTransport)
+     {
+         x.UsingInMemory();
+         return;
+     }
+ }

  internal static void AddPubSubCapabilities(...)
  {
      builderContext.Services.AddMassTransit(x =>
      {
-         x.AddEntityFrameworkOutbox<DialogDbContext>(...);
-         if (builderContext.Environment.IsDevelopment()...)
-         {
-             x.UsingInMemory();
-             return;
-         }
+         ConfigureCommonMassTransitOptions(x, builderContext);
          // Add pub/sub specific configuration
      });
  }

  internal static void AddPubCapabilities(...)
  {
      builderContext.Services.AddMassTransit(x =>
      {
-         x.AddEntityFrameworkOutbox<DialogDbContext>(...);
-         if (builderContext.Environment.IsDevelopment()...)
-         {
-             x.UsingInMemory();
-             return;
-         }
+         ConfigureCommonMassTransitOptions(x, builderContext);
          // Add pub specific configuration
      });
  }
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs (1)

33-48: Review usage of interpolated strings in SQL command.

While using nameof ensures that the table and column names reflect the code definitions, interpolated strings in SQL commands can pose risks if any of the interpolated values can be influenced by external input.

Verify that all interpolated values in the SQL command are safe and cannot be tampered with. If necessary, consider using parameterized queries for table and column names or building the SQL command using safer methods.

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommand.cs (2)

49-49: Use UtcNow instead of Now for time zone consistency

Consider using DateTimeOffset.UtcNow to ensure synchronization times are consistent across different time zones.

Apply this diff to update the timestamp:

-var syncTime = DateTimeOffset.Now;
+var syncTime = DateTimeOffset.UtcNow;

26-34: Simplify constructor null checks using C# 9.0 features

You can simplify the null checks in the constructor by using the concise syntax available in newer C# versions for improved readability.

Apply this diff to streamline the constructor:

-public SynchronizeResourcePolicyInformationCommandHandler(
-    IResourceRegistry resourceRegistry,
-    IResourcePolicyInformationRepository resourcePolicyMetadataRepository,
-    ILogger<SynchronizeResourcePolicyInformationCommandHandler> logger)
-{
-    _resourceRegistry = resourceRegistry ?? throw new ArgumentNullException(nameof(resourceRegistry));
-    _resourcePolicyMetadataRepository = resourcePolicyMetadataRepository ?? throw new ArgumentNullException(nameof(resourcePolicyMetadataRepository));
-    _logger = logger ?? throw new ArgumentNullException(nameof(logger));
-}
+public SynchronizeResourcePolicyInformationCommandHandler(
+    IResourceRegistry resourceRegistry,
+    IResourcePolicyInformationRepository resourcePolicyMetadataRepository,
+    ILogger<SynchronizeResourcePolicyInformationCommandHandler> logger) =>
+    (_resourceRegistry, _resourcePolicyMetadataRepository, _logger) =
+    (resourceRegistry ?? throw new ArgumentNullException(nameof(resourceRegistry)),
+     resourcePolicyMetadataRepository ?? throw new ArgumentNullException(nameof(resourcePolicyMetadataRepository)),
+     logger ?? throw new ArgumentNullException(nameof(logger)));
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (3)

28-32: Consider parameter ordering in the constructor

Placing the logger parameter after client and cacheProvider maintains consistency and readability.


151-151: Log the full exception to capture detailed error information

Logging only ex.Message omits stack trace and inner exceptions. Logging the full exception provides more context for debugging.

Apply this diff to enhance logging:

- _logger.LogError("Failed to process policy for \"{ResourceUrn}\": {ExceptionMessage}", resource.ResourceUrn, ex.Message);
+ _logger.LogError(ex, "Failed to process policy for \"{ResourceUrn}\"", resource.ResourceUrn);

221-228: Consider making ResourceRegistryEntry a struct or record

Since ResourceRegistryEntry is a simple data holder, using a readonly struct or record can be more efficient and convey intent.

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs (1)

39-39: Remove Redundant Call to EnsureLazyLoadedServices() in SavingChangesAsync

The method EnsureLazyLoadedServices() is called at both line 39 and line 60 within SavingChangesAsync. Since domain events are only processed when _domainEvents is not empty, and EnsureLazyLoadedServices() is necessary only in that case, the first call is redundant. Consider removing the initial call to avoid unnecessary initialization when there are no domain events.

Apply this diff to remove the redundant call:

 public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(
     DbContextEventData eventData,
     InterceptionResult<int> result,
     CancellationToken cancellationToken = default)
 {
-    EnsureLazyLoadedServices();

     var dbContext = eventData.Context;

     if (dbContext is null)
     {
         return await base.SavingChangesAsync(eventData, result, cancellationToken);
     }

     _domainEvents = dbContext.ChangeTracker.Entries()
         .SelectMany(x =>
             x.Entity is IEventPublisher publisher
                 ? publisher.PopDomainEvents()
                 : [])
         .ToList();

     if (_domainEvents.Count == 0)
     {
         return await base.SavingChangesAsync(eventData, result, cancellationToken);
     }

     EnsureLazyLoadedServices();
     foreach (var domainEvent in _domainEvents)
     {
         domainEvent.OccuredAt = _transactionTime.Value;
     }

     await Task.WhenAll(_domainEvents
         .Select(x => _publishEndpoint.Value
             .Publish(x, x.GetType(), cancellationToken)));

     return await base.SavingChangesAsync(eventData, result, cancellationToken);
 }

Also applies to: 60-60

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 110a70e and 9ca2825.

⛔ Files ignored due to path filters (2)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.Designer.cs is excluded by !**/Migrations/**/*Designer.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs is excluded by !**/Migrations/DialogDbContextModelSnapshot.cs
📒 Files selected for processing (31)
  • .azure/applications/sync-resource-policy-information-job/main.bicep (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/prod.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/staging.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/test.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/yt01.bicepparam (1 hunks)
  • .github/workflows/workflow-deploy-apps.yml (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourcePolicyInformationRepository.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommand.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommandValidator.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeSubjectResourceMappingsCommand.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (4 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs (4 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentCleanupOutboxHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentMigratorHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs (6 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/Digdir.Domain.Dialogporten.Janitor.csproj (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/Properties/launchSettings.json (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/README.md (1 hunks)
  • tests/Digdir.Domain.Dialogporten.Application.Integration.Tests/Common/DialogApplication.cs (1 hunks)
🧰 Additional context used
📓 Learnings (1)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs (3)
Learnt from: MagnusSandgren
PR: digdir/dialogporten#1277
File: src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs:58-60
Timestamp: 2024-10-17T09:56:14.054Z
Learning: In the `ConvertDomainEventsToOutboxMessagesInterceptor` class located at `src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs`, using MassTransit's transaction outbox functionality ensures that events published using `_publishEndpoint.Publish` in the `SavingChangesAsync` method are handled transactionally, maintaining consistency without the need to move event publishing to `SavedChangesAsync` or retaining the outbox pattern.
Learnt from: oskogstad
PR: digdir/dialogporten#1187
File: src/Digdir.Domain.Dialogporten.Infrastructure/DomainEvents/Outbox/ConvertDomainEventsToOutboxMessagesInterceptor.cs:105-122
Timestamp: 2024-10-08T15:39:24.789Z
Learning: In the `ConvertDomainEventsToOutboxMessagesInterceptor` class, using a static in-memory cache (`UpdateEventThrottleCache`) for throttling in the `SendDialogUpdated` method is acceptable because only one instance of the WebAPI receives the REST request that generates these events. The throttling is meant to be local to prevent clients from receiving multiple notifications when both an update event and an activity created event are generated in the same transaction.
Learnt from: oskogstad
PR: digdir/dialogporten#1187
File: src/Digdir.Domain.Dialogporten.Infrastructure/DomainEvents/Outbox/ConvertDomainEventsToOutboxMessagesInterceptor.cs:105-122
Timestamp: 2024-09-24T22:26:57.178Z
Learning: In the `ConvertDomainEventsToOutboxMessagesInterceptor` class, using a static in-memory cache (`UpdateEventThrottleCache`) for throttling in the `SendDialogUpdated` method is acceptable because only one instance of the WebAPI receives the REST request that generates these events. The throttling is meant to be local to prevent clients from receiving multiple notifications when both an update event and an activity created event are generated in the same transaction.
🪛 Markdownlint
src/Digdir.Domain.Dialogporten.Janitor/README.md

15-15: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


16-16: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


24-24: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


25-25: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)

🔇 Additional comments (56)
src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs (1)

1-3: LGTM! File structure follows conventions.

The namespace organization and imports are clean and follow the project's structure.

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommandValidator.cs (1)

1-4: LGTM! Good choice of validation framework and namespace organization.

The use of FluentValidation and the namespace structure follow good practices.

src/Digdir.Domain.Dialogporten.Janitor/Properties/launchSettings.json (2)

3-9: LGTM! Profile rename improves clarity.

The profile rename from "Digdir.Domain.Dialogporten.Janitor" to "subject-resources" better reflects its specific functionality.


10-15: Verify concurrency setting and add documentation.

The new profile introduces resource policy metadata synchronization with a concurrency limit of 1 (-c 1).

  1. Please verify if the single concurrency setting is intentional for the development environment.
  2. Consider documenting the command parameters in the PR description or README.

Let me help verify the command documentation:

✅ Verification successful

Concurrency setting is valid and well-defined

The concurrency setting of 1 (-c 1) in the development profile is acceptable as:

  1. The command has built-in validation that enforces concurrency between 1-50 (see SynchronizeResourcePolicyInformationCommandValidator)
  2. If not specified, it defaults to 15 concurrent requests (see DefaultNumberOfConcurrentRequests = 15)
  3. The setting can be overridden via command line, making the development profile's conservative setting a safe default

Consider documenting the following in the README:

  • Command: sync-resource-policy-metadata
  • Options:
    • -c: Number of concurrent requests (1-50, default: 15)
    • -s: Since timestamp (optional)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the sync-resource-policy-metadata command is documented
rg -A 5 "sync-resource-policy-metadata" "README.md"

Length of output: 49


Script:

#!/bin/bash
# Search for command implementation to understand concurrency usage
ast-grep --pattern 'class $_ {
  $$$
  sync-resource-policy-metadata($$$) {
    $$$
  }
  $$$
}'

# Search for any documentation or usage examples in source files
rg -i "sync-resource-policy-metadata" --type md --type cs -A 5

Length of output: 161


Script:

#!/bin/bash
# Try different pattern to find the command implementation
rg "sync.*resource.*policy.*metadata" --type cs -A 10

# Look for command line argument parsing
rg "AddCommand.*resource.*policy" --type cs -A 5

# Search for any configuration or settings files related to resource policy
fd -e json -e yaml -e yml -x rg -l "resource.*policy"

Length of output: 880


Script:

#!/bin/bash
# Check the command implementation details
rg -B 5 -A 15 "sync-resource-policy-information" src/Digdir.Domain.Dialogporten.Janitor/Commands.cs

# Look for any related configuration in swagger docs
rg "resource.*policy" docs/schema/V1/swagger.verified.json -A 5

Length of output: 9524


Script:

#!/bin/bash
# Look for the command handler implementation
rg "SynchronizeResourcePolicyInformationCommand" --type cs -B 5 -A 15

# Check for any related configuration files
fd -e config -e settings -x rg -l "NumberOfConcurrentRequests"

Length of output: 14280

.azure/applications/sync-resource-policy-information-job/prod.bicepparam (3)

1-4: LGTM! Basic configuration looks appropriate for production.

The environment and location settings are correctly specified for a production deployment in Norway East region.


5-6: Verify the job schedule configuration.

The cron expression '*/30 * * * *' will run the job every 30 minutes, which could be resource-intensive for a production environment. Please ensure:

  1. This frequency aligns with the business requirements
  2. The operation is idempotent
  3. Proper error handling and retry mechanisms are in place

Consider implementing a dead-letter queue or error logging mechanism if not already present in the main.bicep file.


8-11: Review secret management practices.

While using environment variables for sensitive configuration is good practice, please ensure:

  1. These environment variables are properly set in the Azure DevOps pipeline
  2. The Key Vault access policies are configured with minimum required permissions

Run this script to check for any hardcoded secrets or connection strings in the codebase:

✅ Verification successful

Let me gather more information about the environment variable usage and key vault configurations.


Let me try one more search with different patterns to find the relevant configurations.


Based on the extensive codebase analysis, I can now provide a final response regarding the secret management practices.

Secret management appears to be properly implemented with secure practices.

The codebase shows:

  1. Environment variables are read using readEnvironmentVariable() function and properly passed through secure parameters
  2. Key Vault integration is implemented with RBAC-based access control
  3. Secrets are managed through Azure Key Vault with proper access policies
  4. Connection strings and sensitive configurations are stored as secrets in Key Vault
  5. Container apps and jobs use managed identities to access Key Vault secrets
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential hardcoded secrets or connection strings
# Look for patterns that might indicate hardcoded secrets
rg -i "connectionstring|secret|password|key|token" \
   --type-add "bicep:*.{bicep,bicepparam}" \
   -g "*.{bicep,bicepparam,yaml,yml}"

Length of output: 1107


Script:

#!/bin/bash
# Check for environment variable references and key vault configurations in bicep files
rg -i "keyVault|environment" -g "*.{bicep,bicepparam}" -A 3 -B 3

Length of output: 215


Script:

#!/bin/bash
# Check Azure pipeline configurations for these environment variables
fd -e yml -e yaml . .azure/ -x grep -l "AZURE_CONTAINER_APP_ENVIRONMENT_NAME\|AZURE_ENVIRONMENT_KEY_VAULT_NAME\|AZURE_APP_INSIGHTS_CONNECTION_STRING"

Length of output: 151


Script:

#!/bin/bash
# Look for key vault access policy configurations
rg "access-policy|accessPolicies" -g "*.{bicep,json,yaml,yml}" -A 5

Length of output: 69


Script:

#!/bin/bash
# Search for bicep and pipeline files with broader patterns
fd -e bicep -e bicepparam -e yml -e yaml . .azure/ -x cat {}

Length of output: 115861


Script:

#!/bin/bash
# Look for environment variable usage in pipeline configurations
rg -i "env\.|environment\." -g "*.{yml,yaml}" -A 3 -B 3

Length of output: 57


Script:

#!/bin/bash
# Check for key vault references in the entire codebase
rg -i "@Microsoft.KeyVault|vault" -g "*.{bicep,bicepparam,yml,yaml}" -A 3 -B 3

Length of output: 80

.azure/applications/sync-resource-policy-information-job/test.bicepparam (3)

3-6: Verify region selection and cron schedule

The configuration looks good, but please confirm:

  1. Is 'norwayeast' the intended region for the test environment?
  2. Is the 30-minute interval appropriate for the test environment? Consider if this frequency needs to be different from production.

8-11: Verify secret management in deployment pipeline

The secret management approach using environment variables is secure and follows best practices. However, please ensure:

  1. These environment variables are properly configured in your deployment pipeline
  2. The key vault and app insights resources exist in the test environment
#!/bin/bash
# Check if these environment variables are referenced in workflow files
echo "Checking workflow files for environment variable references..."
rg "AZURE_(CONTAINER_APP_ENVIRONMENT_NAME|ENVIRONMENT_KEY_VAULT_NAME|APP_INSIGHTS_CONNECTION_STRING)" .github/workflows/

1-1: Verify main.bicep template existence and parameter compatibility

Let's ensure the referenced template exists and that all required parameters are properly mapped.

✅ Verification successful

Template reference is valid and parameters are properly defined

The referenced main.bicep template exists in the same directory and contains all necessary parameter declarations including:

  • imageTag
  • environment
  • location
  • containerAppEnvironmentName
  • environmentKeyVaultName
  • jobSchedule
  • appInsightConnectionString
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if main.bicep exists and verify its parameter declarations
if [ -f ".azure/applications/sync-resource-policy-information-job/main.bicep" ]; then
    echo "Checking main.bicep parameters..."
    # Look for parameter declarations in main.bicep
    rg "param \w+" ".azure/applications/sync-resource-policy-information-job/main.bicep"
else
    echo "Error: main.bicep not found in expected location"
    exit 1
fi

Length of output: 5991


Script:

#!/bin/bash
# Let's check if main.bicep exists and examine its content
if [ -f ".azure/applications/sync-resource-policy-information-job/main.bicep" ]; then
    echo "main.bicep exists. Showing content:"
    cat ".azure/applications/sync-resource-policy-information-job/main.bicep"
else
    echo "main.bicep not found in the expected location"
    # Let's search for it in case it's in a different location
    echo "Searching for main.bicep in the repository:"
    fd "main.bicep" --type f
fi

Length of output: 3201

.azure/applications/sync-resource-policy-information-job/yt01.bicepparam (3)

1-5: LGTM! Basic configuration looks good.

The environment configuration and location settings are appropriate for the yt01 environment. The use of readEnvironmentVariable for the image tag ensures dynamic versioning.


8-11: Verify environment variable availability in deployment pipeline.

The configuration relies on several critical environment variables. Ensure these are properly set in the deployment pipeline:

  • AZURE_CONTAINER_APP_ENVIRONMENT_NAME
  • AZURE_ENVIRONMENT_KEY_VAULT_NAME
  • AZURE_APP_INSIGHTS_CONNECTION_STRING

Consider:

  1. Adding validation steps in the deployment pipeline to verify these variables are set
  2. Documenting these required variables in the deployment documentation
  3. Providing example values or instructions for local development
✅ Verification successful

Environment variables are properly configured in deployment workflows

The required environment variables are correctly set up in the GitHub Actions workflows:

  • All variables (AZURE_CONTAINER_APP_ENVIRONMENT_NAME, AZURE_ENVIRONMENT_KEY_VAULT_NAME, AZURE_APP_INSIGHTS_CONNECTION_STRING) are properly referenced as GitHub secrets in multiple deployment workflows
  • The README.md explicitly documents these as required secrets for environment setup
  • The variables are consistently used across different deployment scenarios (staging, production, pull requests)

The infrastructure is well-organized with proper secret management through GitHub environments, as recommended in the original architecture advice.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if these environment variables are properly configured in workflow files

# Look for environment variable definitions in workflow files
fd -e yml -e yaml --glob '.github/workflows/*' | xargs rg -A 5 'env:|environment:|AZURE_'

Length of output: 8949


Script:

#!/bin/bash
# Let's check for workflow files in a different way and specifically look for these environment variables
fd -H -e yml -e yaml | xargs rg -i "AZURE_CONTAINER_APP_ENVIRONMENT_NAME|AZURE_ENVIRONMENT_KEY_VAULT_NAME|AZURE_APP_INSIGHTS_CONNECTION_STRING"

# Also check the infrastructure deployment files for these variables
fd -e bicepparam -e bicep | xargs rg -i "AZURE_CONTAINER_APP_ENVIRONMENT_NAME|AZURE_ENVIRONMENT_KEY_VAULT_NAME|AZURE_APP_INSIGHTS_CONNECTION_STRING"

Length of output: 6434


6-6: Verify the cron schedule impact.

The 30-minute schedule (*/30 * * * *) might be too frequent for a resource policy sync job. Consider:

  1. Resource consumption and costs
  2. Rate limits of any external APIs
  3. Time taken to complete each sync

Consider implementing exponential backoff and proper error handling in the sync job to handle rate limits gracefully.

✅ Verification successful

The 30-minute schedule appears reasonable for this sync job

Based on the code analysis:

  1. The job has built-in concurrency control via NumberOfConcurrentRequests parameter
  2. It includes proper error handling and logging
  3. It supports incremental sync through the since parameter, making each run efficient
  4. The implementation appears lightweight, mainly focused on policy information updates

The 30-minute frequency helps maintain policy information freshness while the implementation includes safeguards against resource overuse.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any rate limiting configurations or documentation about API limits
# that might affect the 30-minute schedule

# Look for rate limit configurations
rg -i "rate.?limit|throttle" --type yaml --type json

# Look for documentation about API limits
fd -e md -e txt | xargs rg -i "rate.?limit|api.?limit|throttle"

Length of output: 8949


Script:

#!/bin/bash
# Let's check for any existing sync jobs and their schedules to understand the pattern
rg -i "schedule|cron" --type bicepparam -A 3 -B 3

# Also check for any documentation or code related to this sync job
rg -i "sync.?resource.?policy" --type-add bicep:*.{bicep,bicepparam} --type bicep -A 5 -B 5

# Look for any logs or monitoring configurations that might indicate job duration
rg -i "duration|elapsed.?time|execution.?time" --type-add bicep:*.{bicep,bicepparam} --type bicep --type cs

Length of output: 428


Script:

#!/bin/bash
# Let's try a different approach using fd to find all bicepparam files and then examine their content
fd -e bicepparam | xargs cat

# Also search for any related job implementations or configurations
rg -g "*.{cs,yaml,yml,json}" -i "sync.?resource.?policy"

# Look for any monitoring or logging related to this job
rg -g "*.{cs,yaml,yml,json}" -i "sync.?resource.?policy.*(duration|monitor|log)"

Length of output: 642


Script:

#!/bin/bash
# Let's examine the implementation of the sync command to understand its complexity
ast-grep --pattern 'class SynchronizeResourcePolicyInformationCommand {
  $$$
}'

# Also check for any error handling or retry logic
rg -g "*.cs" -A 10 "Failed to sync resource policy information"

# Look at the command implementation
rg -g "*.cs" -A 10 "sync-resource-policy-information"

Length of output: 2173

.azure/applications/sync-resource-policy-information-job/staging.bicepparam (2)

1-4: LGTM! Basic configuration follows best practices.

The environment and location parameters are well-defined and follow Azure/Bicep conventions.


8-11: 🛠️ Refactor suggestion

Enhance secret management with validation and documentation.

While the secret management follows Azure naming conventions, consider these improvements:

  1. Add validation for required environment variables
  2. Document expected formats/patterns for these secrets
 //secrets
-param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME')
-param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME')
-param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING')
+// Container App Environment name (required)
+param containerAppEnvironmentName = readEnvironmentVariable('AZURE_CONTAINER_APP_ENVIRONMENT_NAME', true)
+// Key Vault name (required, must be globally unique)
+param environmentKeyVaultName = readEnvironmentVariable('AZURE_ENVIRONMENT_KEY_VAULT_NAME', true)
+// App Insights connection string (required, format: InstrumentationKey=xxx;IngestionEndpoint=xxx)
+param appInsightConnectionString = readEnvironmentVariable('AZURE_APP_INSIGHTS_CONNECTION_STRING', true)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs (1)

8-12: Verify the impact on development hosted services.

The method affects the execution of development hosted services. Let's verify all its usages to ensure consistent implementation.

✅ Verification successful

The implementation of ShouldRunDevelopmentHostedService is consistently used across development hosted services

The verification shows that:

  • All development hosted services (DevelopmentCleanupOutboxHostedService, DevelopmentMigratorHostedService, DevelopmentResourcePolicyInformationSyncHostedService, DevelopmentSubjectResourceSyncHostedService) consistently use the ShouldRunDevelopmentHostedService method
  • The method correctly handles both development environment check and Janitor exclusion
  • Other IsDevelopment() usages in the codebase serve different purposes and don't need to be replaced with this method as they don't relate to development hosted services
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of ShouldRunDevelopmentHostedService to verify implementation consistency

# Search for all development hosted services and their usage of this method
rg -l "DevelopmentHostedService" | xargs rg -A 5 "ShouldRunDevelopmentHostedService"

# Search for any direct IsDevelopment() calls that might need to be replaced
rg "IsDevelopment\(\)" --type cs

Length of output: 6096

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs (1)

10-12: Verify the indexing strategy for query patterns.

Given that the entity has additional properties (MinimumSecurityLevel, CreatedAt, UpdatedAt), consider if additional indexes are needed based on your query patterns.

Let's analyze the query patterns:

✅ Verification successful

Let me gather more information about the ResourcePolicyInformation entity and its usage patterns.


Let me try one more search to find the entity definition and its usage patterns.


Current index strategy is sufficient for the existing query patterns

Based on the analysis of the codebase:

  • The entity is primarily queried by Resource which is already covered by the unique index
  • The repository only exposes two methods:
    • Merge operation for batch updates
    • GetLastUpdatedAt which uses UpdatedAt for a simple MAX aggregation
  • No complex queries or filters are performed on MinimumSecurityLevel, CreatedAt, or other fields
  • The unique index on Resource is appropriate as it's the main lookup field and ensures data integrity
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find query patterns for ResourcePolicyInformation to determine if additional indexes are needed

# Search for LINQ queries or raw SQL involving ResourcePolicyInformation
echo "Searching for query patterns..."
rg -l "ResourcePolicyInformation" | xargs rg -A 5 "Where|OrderBy|Join|Include"

# Search for repository methods that might indicate query patterns
echo "Searching for repository methods..."
ast-grep --pattern 'interface IResourcePolicyInformationRepository {
  $$$
}'

Length of output: 3478


Script:

#!/bin/bash
# Find the ResourcePolicyInformation entity definition and usages
echo "Searching for ResourcePolicyInformation entity definition..."
ast-grep --pattern 'class ResourcePolicyInformation {
  $$$
}'

echo "Searching for repository implementations..."
rg -A 10 "class.*ResourcePolicyInformation.*Repository"

echo "Searching for queries in services/handlers..."
rg -l "ResourcePolicyInformation" | xargs rg -A 5 "GetAsync|FindAsync|FirstOrDefaultAsync|SingleOrDefaultAsync"

Length of output: 2186


Script:

#!/bin/bash
# Find the ResourcePolicyInformation entity definition and all its properties
echo "Searching for entity definition..."
rg -A 15 "class ResourcePolicyInformation"

# Find all methods in the repository
echo "Searching for repository methods..."
rg -A 20 "interface IResourcePolicyInformation"

# Find actual database queries
echo "Searching for database queries..."
rg -A 5 "_dbContext.*ResourcePolicyInformation"

Length of output: 11130

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentMigratorHostedService.cs (1)

20-20: Verify the extension method implementation.

The change to use ShouldRunDevelopmentHostedService() appears to be part of a broader standardization of environment checks. Let's verify the implementation exists and works as expected.

✅ Verification successful

Extension method implementation verified and looks correct

The ShouldRunDevelopmentHostedService() extension method is properly implemented in HostingEnvironmentExtensions.cs. It ensures development services only run in development environments while excluding Janitor-related assemblies. The method is consistently used across all development hosted services:

  • DevelopmentMigratorHostedService
  • DevelopmentSubjectResourceSyncHostedService
  • DevelopmentCleanupOutboxHostedService
  • DevelopmentResourcePolicyInformationSyncHostedService
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the extension method definition
ast-grep --pattern 'public static bool ShouldRunDevelopmentHostedService(this IHostEnvironment $_)'

# Search for all usages to ensure consistent implementation
rg "ShouldRunDevelopmentHostedService"

Length of output: 1047


Script:

#!/bin/bash
# Get the implementation of the extension method
rg -A 10 "public static bool ShouldRunDevelopmentHostedService" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs

Length of output: 469

src/Digdir.Domain.Dialogporten.Application/Externals/IResourcePolicyInformationRepository.cs (2)

1-5: LGTM! Clean and well-structured imports and namespace.

The imports are minimal and relevant, and the namespace follows the project's structure.


6-10: Add XML documentation for the interface methods.

While the method signatures are clear, adding XML documentation would help explain:

  • The purpose of the Merge method's return value
  • The impact of the timeSkew parameter
  • Expected behavior in error scenarios

Example documentation:

 public interface IResourcePolicyInformationRepository
 {
+    /// <summary>
+    /// Merges the provided resource policy information into the repository.
+    /// </summary>
+    /// <param name="resourceMetadata">Collection of resource policy information to merge.</param>
+    /// <param name="cancellationToken">Optional cancellation token.</param>
+    /// <returns>The number of records affected by the merge operation.</returns>
     Task<int> Merge(IReadOnlyCollection<ResourcePolicyInformation> resourceMetadata, CancellationToken cancellationToken = default);

+    /// <summary>
+    /// Retrieves the timestamp of the last update, adjusted for potential time skew in distributed systems.
+    /// </summary>
+    /// <param name="timeSkew">Optional time adjustment to account for system clock differences.</param>
+    /// <param name="cancellationToken">Optional cancellation token.</param>
+    /// <returns>The timestamp of the last update.</returns>
     Task<DateTimeOffset> GetLastUpdatedAt(TimeSpan? timeSkew = null, CancellationToken cancellationToken = default);
 }

Let's verify the interface implementation:

✅ Verification successful

XML documentation suggestion confirmed with implementation details

 public interface IResourcePolicyInformationRepository
 {
+    /// <summary>
+    /// Merges a collection of resource policy information into the database using an UPSERT operation.
+    /// For existing resources, updates the UpdatedAt timestamp. For new resources, inserts a complete record.
+    /// </summary>
+    /// <param name="resourceMetadata">Collection of resource policy information to merge.</param>
+    /// <param name="cancellationToken">Optional cancellation token.</param>
+    /// <returns>The number of records affected by the merge operation.</returns>
     Task<int> Merge(IReadOnlyCollection<ResourcePolicyInformation> resourceMetadata, CancellationToken cancellationToken = default);

+    /// <summary>
+    /// Retrieves the maximum UpdatedAt timestamp from all resource policy records.
+    /// </summary>
+    /// <param name="timeSkew">Optional time adjustment added to the result, used to ensure no updates are missed in distributed systems.
+    /// In the synchronization process, this is set to 1 microsecond to catch concurrent updates.</param>
+    /// <param name="cancellationToken">Optional cancellation token.</param>
+    /// <returns>The latest update timestamp, adjusted by the timeSkew if provided. Returns default timestamp if no records exist.</returns>
     Task<DateTimeOffset> GetLastUpdatedAt(TimeSpan? timeSkew = null, CancellationToken cancellationToken = default);
 }

The implementation details confirm:

  • Merge performs an UPSERT operation using a SQL merge statement
  • GetLastUpdatedAt returns the max UpdatedAt value with an optional skew
  • Both methods are used correctly in the synchronization process
  • The suggested documentation accurately reflects the implementation and usage patterns
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find and verify the implementation of IResourcePolicyInformationRepository

# Search for the implementation
echo "Searching for implementation class..."
ast-grep --pattern 'class $_ : $$$IResourcePolicyInformationRepository$$$'

# Search for usage patterns
echo "Searching for usage patterns..."
rg -l "IResourcePolicyInformationRepository" 

Length of output: 696


Script:

#!/bin/bash
# Let's examine the implementation and usage to understand the documentation needs

# Check the implementation
echo "=== Implementation in ResourcePolicyInformationRepository.cs ==="
rg -A 10 "class ResourcePolicyInformationRepository" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs"

# Check usage in SynchronizeResourcePolicyInformationCommand
echo -e "\n=== Usage in SynchronizeResourcePolicyInformationCommand.cs ==="
rg -A 10 "IResourcePolicyInformationRepository" "src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommand.cs"

# Check if XML documentation already exists in implementation
echo -e "\n=== Checking for existing XML documentation ==="
rg "///" -A 3 "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs"

Length of output: 2257


Script:

#!/bin/bash
# Let's check the implementation details of both methods to understand their behavior better

echo "=== Checking Merge method implementation ==="
rg -A 15 "public async Task<int> Merge" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs"

echo -e "\n=== Checking GetLastUpdatedAt method implementation ==="
rg -A 15 "public async Task<DateTimeOffset> GetLastUpdatedAt" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs"

# Let's also check how these methods are used in the command handler
echo -e "\n=== Checking method usage in command handler ==="
rg -A 20 "public async Task<SynchronizeResourcePolicyInformationResult> Handle" "src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommand.cs"

Length of output: 3797

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2)

Line range hint 1-35: LGTM! The implementation follows best practices.

The service demonstrates good practices:

  • Proper dependency injection and null checks
  • Correct scope management
  • Clean implementation of IHostedService
  • Appropriate use of MediatR for command handling

21-21: Verify the implementation of ShouldRunDevelopmentHostedService extension method.

The change from IsDevelopment() to ShouldRunDevelopmentHostedService() suggests a more specific environment check. Let's verify its implementation to ensure consistent behavior across all development hosted services.

✅ Verification successful

Let's gather more information about the implementation and usage pattern.


Extension method implementation is correct and consistently used

The ShouldRunDevelopmentHostedService() extension method is properly implemented and provides additional safety by:

  • Maintaining the original development environment check via IsDevelopment()
  • Adding protection against running in Janitor context
  • Being consistently used across all development hosted services

The change from IsDevelopment() to ShouldRunDevelopmentHostedService() is a valid improvement that adds more specific control over development services execution.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find and analyze the implementation of ShouldRunDevelopmentHostedService
# and its usage across other development hosted services

# Find the extension method implementation
echo "Looking for ShouldRunDevelopmentHostedService implementation:"
rg -l "ShouldRunDevelopmentHostedService"

# Find all development hosted services using this method
echo -e "\nChecking usage in other development hosted services:"
ast-grep --pattern 'class Development$_HostedService : IHostedService {
  $$$
  StartAsync($_) {
    $$$
    ShouldRunDevelopmentHostedService()
    $$$
  }
  $$$
}'

Length of output: 1026


Script:

#!/bin/bash
# Find the implementation of ShouldRunDevelopmentHostedService
echo "Implementation of ShouldRunDevelopmentHostedService:"
rg -A 5 "ShouldRunDevelopmentHostedService" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs"

# Check how it's used in each development service
echo -e "\nUsage in DevelopmentResourcePolicyInformationSyncHostedService:"
rg -A 3 "ShouldRunDevelopmentHostedService" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs"

echo -e "\nUsage in DevelopmentCleanupOutboxHostedService:"
rg -A 3 "ShouldRunDevelopmentHostedService" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentCleanupOutboxHostedService.cs"

echo -e "\nUsage in DevelopmentMigratorHostedService:"
rg -A 3 "ShouldRunDevelopmentHostedService" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentMigratorHostedService.cs"

Length of output: 1702

src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs (1)

11-12: Add XML documentation for the new method.

Please add XML documentation for the GetUpdatedResourcePolicyInformation method to describe its purpose, parameters, and return value. This will help maintain consistency with C# documentation practices and improve code maintainability.

Let's verify if other interface methods have XML documentation:

src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (1)

26-39: LGTM! Command implementation follows established patterns.

The implementation correctly follows the existing command pattern and properly handles command execution and error cases.

src/Digdir.Domain.Dialogporten.Janitor/Digdir.Domain.Dialogporten.Janitor.csproj (1)

33-39: Verify if explicit configuration is necessary.

The project already includes a wildcard pattern appsettings*.json that handles copying all settings files. The new configuration might be redundant except for the ExcludeFromSingleFile property. Consider simplifying if the explicit configuration isn't required for overriding the wildcard behavior.

✅ Verification successful

Explicit configuration is necessary and correct

The explicit appsettings.local.json configuration is required because:

  1. It adds the ExcludeFromSingleFile property which is not present in the wildcard pattern
  2. The documentation explicitly states that appsettings.local.json is meant for developer-specific settings and should not be included in production builds
  3. The file is properly excluded in .gitignore
  4. The codebase has specific handling for this file in ConfigurationExtensions.cs that only loads it in Development environment
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any special handling requirements for appsettings.local.json
# that would justify the explicit configuration

# Look for references to appsettings.local.json in the codebase
rg -l "appsettings\.local\.json"

# Check if the file is already in .gitignore
grep -l "appsettings.local.json" .gitignore

Length of output: 290


Script:

#!/bin/bash
# Let's check the content of these files to understand the context better

# Check configuration documentation
cat docs/Configuration.md

# Check README mentions
rg -A 5 -B 5 "appsettings\.local\.json" README.md

# Check the configuration extensions implementation
cat "src/Digdir.Domain.Dialogporten.Application/Common/Extensions/ConfigurationExtensions.cs"

# Check the gitignore entry
grep "appsettings.local.json" .gitignore

# Check if there are any other appsettings patterns in the csproj
cat "src/Digdir.Domain.Dialogporten.Janitor/Digdir.Domain.Dialogporten.Janitor.csproj"

Length of output: 15152

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (4)

1-10: LGTM: Migration class setup follows best practices

The migration is properly structured with nullable disable pragma and inherits from the Migration base class.


37-41: LGTM: Clean rollback implementation

The Down method correctly drops the table, providing a clean rollback path.


14-28: Verify the column constraints and data types

The table creation looks good with appropriate data types and constraints. A few points to verify:

  1. Is 255 characters sufficient for the Resource column? Consider future needs.
  2. Should MinimumSecurityLevel be constrained to specific values?
  3. Consider adding a comment describing the purpose of this table.

Let's check if there are any existing security level definitions:

✅ Verification successful

Based on the search results, I can now provide a comprehensive verification of the table constraints and data types:

Column constraints and data types are appropriate

  1. The 255-character limit for the Resource column is sufficient as it stores URNs from the Resource Registry (seen in ResourceRegistryClient.cs).
  2. MinimumSecurityLevel is correctly defined as an integer with valid values between 1-4 based on the codebase:
    • Default value is 1 (DefaultMinimumSecurityLevel)
    • Authentication levels 3 and 4 are referenced in tests
    • Values are obtained from Altinn's Resource Registry XACML policies
  3. The timestamps with UTC enforcement via time zone 'utc' are properly configured
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for security level definitions or usage
rg -g "*.cs" -A 3 "SecurityLevel|AuthenticationLevel" 

Length of output: 16284


18-22: Verify timestamp handling across time zones

The default values for CreatedAt and UpdatedAt use 'utc' timezone, which is correct. However, ensure that:

  1. Application code consistently uses UTC when writing timestamps
  2. Any reporting or UI layer properly handles timezone conversion
✅ Verification successful

Let me search for more information about timestamp handling in the application code to ensure consistent UTC usage.


Let me check for the implementation of these converters and any custom timestamp handling logic.


Timestamp handling is properly implemented with UTC enforcement

The codebase demonstrates robust UTC timestamp handling:

  • Database uses timestamp with time zone with explicit UTC timezone
  • UtcDateTimeOffsetConverter enforces explicit timezone offsets in JSON
  • DateTimeNotSupportedConverter prevents usage of ambiguous DateTime
  • DateTimeOffsetConverter ensures UTC conversion for database operations
  • IClock interface provides UtcNow for application code
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for timestamp handling patterns in the codebase
rg -g "*.cs" "DateTimeOffset.*current.*|DateTime\..*UtcNow|TimeZone" 

Length of output: 9212


Script:

#!/bin/bash
# Search for DateTimeOffset usage in entity definitions and services
ast-grep --pattern 'class $_ {
  $$$
  DateTimeOffset $_ { get; set; }
  $$$
}'

# Search for any custom DateTime/DateTimeOffset handling
rg -g "*.cs" -B2 -A2 "new DateTime|new DateTimeOffset"

Length of output: 1105


Script:

#!/bin/bash
# Search for converter implementations
rg -g "*.cs" -A 10 "class.*DateTimeOffsetConverter|class.*DateTimeNotSupportedConverter"

# Search for any timestamp-related interfaces or base classes
ast-grep --pattern 'interface $_ {
  $$$
  DateTimeOffset $_ { get; }
  $$$
}'

Length of output: 4163

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentCleanupOutboxHostedService.cs (1)

26-26: Verify the extension method implementation.

The change to use ShouldRunDevelopmentHostedService() aligns with the standardization of hosted service execution conditions. However, let's verify the implementation exists.

✅ Verification successful

Extension method implementation verified and consistent with usage

The implementation in HostingEnvironmentExtensions.cs is well-defined and serves a clear purpose - it ensures the service only runs in development environments while excluding Janitor-related assemblies. The change from IsDevelopment() to ShouldRunDevelopmentHostedService() adds this additional safety check, making it a valid improvement.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for the extension method implementation
# Expected: Find the implementation of ShouldRunDevelopmentHostedService

# Search for the extension method definition
ast-grep --pattern 'public static bool ShouldRunDevelopmentHostedService(this IHostEnvironment $_)'

# Backup search using ripgrep in case it's defined differently
rg -l "ShouldRunDevelopmentHostedService"

Length of output: 706


Script:

#!/bin/bash
# Let's examine the implementation in HostingEnvironmentExtensions.cs
cat "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/HostingEnvironmentExtensions.cs"

# Also check how it's used in other development services for consistency
rg -A 2 "ShouldRunDevelopmentHostedService" "src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/*.cs"

Length of output: 838

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs (2)

4-4: LGTM!

The new using directive is correctly placed and necessary for the UpdatedResourcePolicyInformation type.


46-48: Verify test coverage for the new method.

Since this is a local development implementation that returns empty results, we should ensure it's properly covered by tests.

✅ Verification successful

Test coverage exists through integration tests

The LocalDevelopmentResourceRegistry is used in integration tests as the default implementation:

  • It's registered in DialogApplication.cs for integration testing
  • The class is properly registered for local development scenarios in InfrastructureExtensions.cs

Since this is a test double meant for local development, and it's being used in the test infrastructure, explicit unit tests for this implementation are not necessary. The implementation is implicitly tested through integration tests that exercise the resource registry functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for test files that might contain tests for LocalDevelopmentResourceRegistry
rg -l "LocalDevelopmentResourceRegistry" --type cs --glob "*Tests.cs"

# Search for specific test methods related to GetUpdatedResourcePolicyInformation
rg "GetUpdatedResourcePolicyInformation.*Test" --type cs

Length of output: 128


Script:

#!/bin/bash
# Let's try a broader search to find test files and implementations
# First, find the exact namespace and class definition
rg -A 5 "class LocalDevelopmentResourceRegistry" --type cs

# Then search for any test files in the test directories
fd "Tests?.cs$" test src/*/test

# Finally, let's look for any usage of this class
rg "new LocalDevelopmentResourceRegistry" --type cs

Length of output: 1311


Script:

#!/bin/bash
# Let's try different test directory patterns and look for any tests
fd "Tests?.cs$" "test" "tests" "*.Tests" "*.Test"

# Search for any registration or usage of LocalDevelopmentResourceRegistry in startup or configuration files
rg -A 5 "LocalDevelopmentResourceRegistry" --type cs

# Look for test files specifically in the Infrastructure project
fd "Tests?.cs$" src/Digdir.Domain.Dialogporten.Infrastructure

Length of output: 7743

src/Digdir.Domain.Dialogporten.Application/Externals/IDialogDbContext.cs (2)

11-11: LGTM! Clean import addition.

The new using directive follows the existing pattern and is properly placed with other domain imports.


46-46: LGTM! Well-structured DbSet addition.

The new ResourcePolicyInformation DbSet property:

  • Follows consistent naming and pattern with other DbSet properties
  • Properly integrates with the existing interface structure
  • Supports the PR objective of resource policy metadata synchronization
.azure/applications/sync-resource-policy-information-job/main.bicep (4)

100-106: LGTM! Follows security best practices

The Key Vault access policy configuration follows the principle of least privilege by only granting reader access to the required secrets.


108-109: LGTM! Essential outputs are provided

The outputs provide the necessary information for integration with other resources and monitoring.


68-83: Add deployment-time validation for Key Vault access

While the Key Vault configuration looks secure, consider adding deployment-time validation to ensure the secrets exist and are accessible.

#!/bin/bash
# Description: Check if Key Vault parameter files exist for all environments
fd -e bicepparam$ -x grep -l "environmentKeyVaultName"

45-47: Verify the API version availability

The Container Apps API version '2024-03-01' appears to be set in the future. This might cause deployment issues if the version is not yet available in your target Azure regions.

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeSubjectResourceMappingsCommand.cs (2)

17-17: LGTM!

Good use of OneOf for type-safe error handling and proper sealing of the result type.


19-37: Verify the default batch size value.

The default batch size of 1000 items might need validation against system performance characteristics and memory constraints.

✅ Verification successful

Default batch size of 1000 is properly validated and consistent with system constraints

The batch size value of 1000 is well-justified and properly validated:

  • There's a validator (SynchronizeSubjectResourceMappingsCommandValidator) that enforces a range of 1-1000 for the batch size
  • This limit aligns with other system constraints:
    • PaginationConstants.MaxLimit is also set to 1000
    • OutboxCdcSubscriptionOptions.SnapshotBatchSize defaults to 1000
  • The value can be overridden through the command's BatchSize property, providing flexibility while maintaining the upper bound
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other batch size configurations in the codebase for consistency
rg -g '!*.{json,md}' --type-add 'config:*.{yaml,yml,xml}' -t config -t cs "batch.*size.*=.*1000" -C 2

Length of output: 103


Script:

#!/bin/bash
# Let's try a broader search for batch size configurations
rg -g '!*.{json,md}' "BatchSize|batchSize|batch_size" -C 2

# Also search for any numeric constants around 1000
rg -g '!*.{json,md}' "const.*=.*1000|const.*=.*500|const.*=.*2000" -C 2

Length of output: 11596

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs (2)

18-18: LGTM!

The using directive is properly placed with other domain entity imports.


50-50: LGTM! Verify configuration setup.

The DbSet property follows the established pattern and matches the interface requirement.

Let's verify the entity configuration is properly set up:

✅ Verification successful

Let me check the configuration details to ensure it's properly set up.


Configuration setup verified and properly implemented

The verification confirms:

  • ResourcePolicyInformation configuration exists with proper unique index on Resource property
  • Configurations are automatically applied via ApplyConfigurationsFromAssembly in DbContext
  • Entity is properly registered as DbSet
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for ResourcePolicyInformation configuration and model builder registration

# Test 1: Verify configuration class exists
echo "Checking for configuration class..."
fd -e cs ResourcePolicyInformationConfiguration

# Test 2: Verify the configuration is applied correctly
echo "Checking configuration usage in model builder..."
rg -l "ResourcePolicyInformation.*ToTable|HasIndex|Configure.*ResourcePolicyInformation" -g "*.cs"

Length of output: 3548


Script:

#!/bin/bash
# Check the content of ResourcePolicyInformationConfiguration
echo "Content of ResourcePolicyInformationConfiguration:"
cat src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs

# Check if it's registered in DbContext's OnModelCreating
echo -e "\nChecking OnModelCreating registration:"
rg -A 5 "OnModelCreating.*override" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs

Length of output: 1030


Script:

#!/bin/bash
# Let's try a different approach to find OnModelCreating
echo "Searching for OnModelCreating with more context:"
ast-grep --pattern 'protected override void OnModelCreating(ModelBuilder $_) { $$$ }'

# Also check if there's an ApplyConfigurations call
echo -e "\nChecking for ApplyConfigurations usage:"
rg "ApplyConfigurations|modelBuilder.*Apply" -A 3 src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/DialogDbContext.cs

Length of output: 648

src/Digdir.Domain.Dialogporten.Infrastructure/InfrastructureExtensions.cs (2)

183-215: LGTM! Robust message handling configuration.

The MassTransit configuration properly implements:

  • Entity Framework outbox pattern for reliable message delivery
  • Dead letter queue handling for failed messages
  • Environment-specific transport configuration

71-71: Verify development environment restriction.

The new hosted service appears to be for development purposes. Ensure it's properly guarded against running in production environments.

✅ Verification successful

Development environment restriction is properly implemented

The service is well-protected against running in production environments through multiple safeguards:

  • Located in the Development namespace and folder
  • Uses the ShouldRunDevelopmentHostedService() extension method which checks for both development environment and non-Janitor assembly
  • Has proper environment checks in the StartAsync implementation
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the hosted service is only used in development
# Test: Check if the service is properly restricted to development environment
ast-grep --pattern 'class DevelopmentResourcePolicyInformationSyncHostedService : IHostedService {
  $$$
}'

Length of output: 109


Script:

#!/bin/bash
# Let's try a different approach to find the service implementation
# First, let's find the file containing the service
fd "DevelopmentResourcePolicyInformationSyncHostedService" --type f

# Then let's look for any environment checks in the infrastructure extensions
rg -A 5 "DevelopmentResourcePolicyInformationSyncHostedService" 

# Also check for any IsDevelopment() checks around the service registration
rg -B 5 -A 2 "IsDevelopment|Development.*Environment" src/Digdir.Domain.Dialogporten.Infrastructure/

Length of output: 12940


Script:

#!/bin/bash
# Let's check the StartAsync implementation to verify environment checks
rg -A 10 "StartAsync" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs

# Also check if there's a common extension method being used for environment checks
rg -A 5 "ShouldRunDevelopmentHostedService" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs

Length of output: 891

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs (4)

12-15: Constructor implementation is correct.

The constructor properly initializes the repository with a non-null DialogDbContext.


17-29: Verify behavior when the table is empty.

In the GetLastUpdatedAt method, if the ResourcePolicyInformation table is empty, lastUpdatedAt will default to DateTimeOffset.MinValue due to DefaultIfEmpty(). Ensure that this behavior is acceptable and that any consuming code can handle this value appropriately.


31-59: Ensure all arrays passed to unnest have the same length.

In the Merge method, the SQL command passes multiple arrays to the unnest function (lines 37-38). PostgreSQL requires that all arrays have the same length; otherwise, it will raise a runtime error.

Consider adding a validation check to ensure that all arrays derived from resourceMetadata have the same length before executing the SQL command.


31-59: ⚠️ Potential issue

Fix syntax error in parameter array construction.

The square brackets used in lines 52-58 to create the array of parameters are syntactically incorrect in C#. Square brackets denote attributes or array indexing. You should use an explicit array creation or curly braces for initialization.

Apply this diff to fix the syntax error:

-            : await _dbContext.Database.ExecuteSqlRawAsync(sql,
-            [
-                new NpgsqlParameter("ids", resourceMetadata.Select(x => x.Id).ToArray()),
-                new NpgsqlParameter("resources", resourceMetadata.Select(x => x.Resource).ToArray()),
-                new NpgsqlParameter("minimumSecurityLevels", resourceMetadata.Select(x => x.MinimumSecurityLevel).ToArray()),
-                new NpgsqlParameter("createdAts", resourceMetadata.Select(x => x.CreatedAt).ToArray()),
-                new NpgsqlParameter("updatedAts", resourceMetadata.Select(x => x.UpdatedAt).ToArray())
-            ], cancellationToken);
+            : await _dbContext.Database.ExecuteSqlRawAsync(
+                sql,
+                new object[]
+                {
+                    new NpgsqlParameter("ids", resourceMetadata.Select(x => x.Id).ToArray()),
+                    new NpgsqlParameter("resources", resourceMetadata.Select(x => x.Resource).ToArray()),
+                    new NpgsqlParameter("minimumSecurityLevels", resourceMetadata.Select(x => x.MinimumSecurityLevel).ToArray()),
+                    new NpgsqlParameter("createdAts", resourceMetadata.Select(x => x.CreatedAt).ToArray()),
+                    new NpgsqlParameter("updatedAts", resourceMetadata.Select(x => x.UpdatedAt).ToArray())
+                }, 
+                cancellationToken);

Likely invalid or redundant comment.

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeResourcePolicyInformationCommand.cs (1)

42-42: Verify availability of TimeSpan.FromMicroseconds method

The method TimeSpan.FromMicroseconds may not be available in all target frameworks. Confirm that your project's target framework supports this method to avoid compilation issues.

Run the following script to check for method availability:

✅ Verification successful

TimeSpan.FromMicroseconds is available in .NET 8.0

The project targets .NET 8.0 as specified in Directory.Build.props, and TimeSpan.FromMicroseconds was introduced in .NET 8.0. The method is available and safe to use in this codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify if TimeSpan.FromMicroseconds exists in the target framework.

# Test: Search for TimeSpan.FromMicroseconds in the .NET documentation for the project's target framework.
# Expected result: Confirmation that TimeSpan.FromMicroseconds is supported.

# Since this cannot be directly checked via code, please manually verify the target framework's documentation.

Length of output: 0


Script:

#!/bin/bash
# Let's check the target framework in the project file
fd -e csproj . | xargs cat

Length of output: 26566


Script:

#!/bin/bash
# Let's check the target framework in the project file containing the code under review
fd "Digdir.Domain.Dialogporten.Application.csproj" | xargs grep -A 2 "<PropertyGroup>"

Length of output: 274


Script:

#!/bin/bash
# Let's check the Directory.Build.props file which might contain the target framework
fd "Directory.Build.props" | xargs cat

Length of output: 622

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (2)

21-22: Good use of constants for authentication configuration

Defining DefaultMinimumSecurityLevel and AuthenticationLevelCategory as constants enhances readability and maintainability.


26-26: Injection of ILogger improves logging capabilities

Adding ILogger<ResourceRegistryClient> allows for better logging and debugging within the class.

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Interceptors/ConvertDomainEventsToOutboxMessagesInterceptor.cs (5)

16-16: Lazy Initialization of Dependencies is Appropriate

Using Lazy<ITopicEventSender> and Lazy<IPublishEndpoint> for deferred initialization of dependencies is suitable. This approach improves performance by delaying the instantiation of these services until they are actually needed.

Also applies to: 18-18


24-24: Constructor Parameters Updated for Lazy Dependencies

Updating the constructor to accept Lazy<ITopicEventSender> and Lazy<IPublishEndpoint> aligns with the changes to the class fields. This ensures consistency and proper initialization of the lazy-loaded services.

Also applies to: 26-26


55-58: Efficient Early Exit When No Domain Events

Adding an early return when _domainEvents.Count == 0 in SavingChangesAsync enhances performance by avoiding unnecessary processing when there are no domain events to handle.


76-79: Efficient Early Exit in SavedChangesAsync When No Domain Events

Similarly, introducing an early return in SavedChangesAsync when _domainEvents is empty prevents unnecessary execution of code, improving efficiency.


115-126: Proper Implementation of Lazy Service Initialization with Error Handling

The EnsureLazyLoadedServices() method correctly triggers the initialization of the lazy-loaded services _topicEventSender and _publishEndpoint. The try-catch block effectively captures any exceptions during initialization and throws an InvalidOperationException with a clear message. This provides better error detection and debugging support if the services are not properly registered.

@elsand elsand marked this pull request as ready for review November 14, 2024 07:57
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (15)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommandValidator.cs (2)

5-11: Consider adding validation for the Since parameter.

Based on the AI summary, the SyncPolicyCommand includes a Since parameter that currently lacks validation. Consider adding validation to ensure it's within reasonable bounds.

 internal sealed class SyncPolicyCommandValidator : AbstractValidator<SyncPolicyCommand>
 {
     public SyncPolicyCommandValidator()
     {
         RuleFor(x => x.NumberOfConcurrentRequests).InclusiveBetween(1, 50);
+        RuleFor(x => x.Since)
+            .LessThanOrEqualTo(DateTime.UtcNow)
+            .When(x => x.Since.HasValue);
     }
 }

5-11: Add XML documentation for better maintainability.

Consider adding XML documentation to describe the validator's purpose and validation rules.

+/// <summary>
+/// Validates the SyncPolicyCommand ensuring proper constraints for resource policy synchronization.
+/// </summary>
+/// <remarks>
+/// Validates:
+/// - NumberOfConcurrentRequests: Must be between 1 and 50
+/// </remarks>
 internal sealed class SyncPolicyCommandValidator : AbstractValidator<SyncPolicyCommand>
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommandValidator.cs (1)

9-9: Consider enhancing the batch size validation.

While the validation logic is correct, it could be improved for better maintainability and clarity:

  1. Extract magic numbers into named constants
  2. Add a custom error message explaining the constraints
  3. Document the reasoning behind these specific limits

Consider applying this improvement:

-        RuleFor(x => x.BatchSize).InclusiveBetween(1, 1000);
+        private const int MinBatchSize = 1;
+        private const int MaxBatchSize = 1000;
+
+        RuleFor(x => x.BatchSize)
+            .InclusiveBetween(MinBatchSize, MaxBatchSize)
+            .WithMessage($"Batch size must be between {MinBatchSize} and {MaxBatchSize} to ensure optimal performance and resource utilization.");
.azure/applications/sync-resource-policy-information-job/staging.bicepparam (1)

1-11: Consider implementing retry logic and monitoring

Since this is a critical synchronization job running during off-hours, consider:

  1. Implementing retry logic for transient failures
  2. Setting up alerts for job failures
  3. Adding monitoring for job duration and success rate

This will help ensure reliable policy synchronization and quick detection of issues.

src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs (1)

18-18: Add XML documentation for the new property.

The property's purpose and impact on the application's behavior should be documented for better maintainability.

+    /// <summary>
+    /// When set to true, disables the automatic synchronization of policy information during application startup in local development.
+    /// This is useful when running without access to the Resource Registry.
+    /// </summary>
     public bool DisablePolicyInformationSyncOnStartup { get; set; } = true;
src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (1)

2-3: LGTM! Consider documenting the return values.

The command implementation looks good with proper dependency injection and error handling. The switch to SyncSubjectMapCommand aligns with the PR objectives.

Consider adding XML documentation to clarify the meaning of return values (0 for success, -1 for validation errors).

Also applies to: 20-25

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (1)

1-43: Consider future extensibility needs

Given that this table is part of a larger feature set for resource policy metadata synchronization (issue #1214), consider if additional columns might be needed for:

  • Policy version tracking
  • Last sync timestamp
  • Policy source/origin
  • Additional XACML obligations beyond authentication level

This would help avoid multiple migrations as requirements evolve.

src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json (1)

79-80: Document the new configuration setting

Please add documentation for the new DisablePolicyInformationSyncOnStartup setting:

  1. Its purpose and when it should be enabled/disabled
  2. The relationship with UseInMemoryServiceBusTransport
  3. Any impact on local development workflow

Consider adding these details to:

  • Code comments in this file
  • The project's development setup guide
  • Related configuration documentation
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommand.cs (3)

17-17: Consider adding domain-specific error types.

Given that this command handles resource policy synchronization, consider extending the result types to include more specific error cases such as ResourceRegistryConnectionError or PolicySyncError. This would provide better error handling and debugging capabilities.

Example enhancement:

- public sealed partial class SyncSubjectMapResult : OneOfBase<Success, ValidationError>;
+ public sealed partial class SyncSubjectMapResult : OneOfBase<Success, ValidationError, ResourceRegistryConnectionError, PolicySyncError>;
+ 
+ public record ResourceRegistryConnectionError(string Message, Exception? Exception = null);
+ public record PolicySyncError(string Message);

19-37: Document the DefaultBatchSize constant.

Consider adding XML documentation to explain the rationale behind the chosen default batch size of 1000. This would help maintainers understand any performance implications or resource constraints that influenced this value.

Example enhancement:

+ /// <summary>
+ /// Default number of resources to process in a single batch.
+ /// This value was chosen to balance memory usage and database round-trips.
+ /// </summary>
  private const int DefaultBatchSize = 1000;

Line range hint 39-85: Consider transaction scope and document time skew.

A few suggestions for improvement:

  1. The transaction scope spans the entire operation. For large datasets, consider implementing a chunked transaction approach to prevent long-running transactions.

  2. The time skew value of 1 microsecond needs documentation explaining its purpose and why this specific value was chosen.

  3. The error handling could be more specific about different failure scenarios.

Example enhancement for time skew documentation:

+ // Add a constant with documentation
+ /// <summary>
+ /// Time skew applied to prevent missing updates due to timestamp precision differences
+ /// between systems. The value is minimal to ensure we don't miss any updates while
+ /// avoiding unnecessary reprocessing.
+ /// </summary>
+ private static readonly TimeSpan TimeSkew = TimeSpan.FromMicroseconds(1);

  var lastUpdated = request.Since
      ?? await _subjectResourceRepository.GetLastUpdatedAt(
-         timeSkew: TimeSpan.FromMicroseconds(1),
+         timeSkew: TimeSkew,
          cancellationToken: cancellationToken);

Example enhancement for chunked transactions:

- await _unitOfWork.BeginTransactionAsync(cancellationToken);
  await foreach (var resourceBatch in _resourceRegistry
      .GetUpdatedSubjectResources(lastUpdated, request.BatchSize ?? DefaultBatchSize, cancellationToken))
  {
+     await _unitOfWork.BeginTransactionAsync(cancellationToken);
      var mergeableSubjectResources = resourceBatch
          .Select(x => x.ToMergableSubjectResource(syncTime))
          .ToList();
      var batchMergeCount = await _subjectResourceRepository.Merge(mergeableSubjectResources, cancellationToken);
      _logger.LogInformation("{BatchMergeCount} subject-resources added to transaction.", batchMergeCount);
      mergeCount += batchMergeCount;
+     await _unitOfWork.SaveChangesAsync(cancellationToken);
  }

- await _unitOfWork.SaveChangesAsync(cancellationToken);
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (1)

201-219: Consider adding XML documentation

The ResourceRegistryEntry class handles important URN parsing logic. Consider adding XML documentation to explain:

  • The expected URN format
  • The significance of the prefixes
  • Examples of valid and invalid URNs
+    /// <summary>
+    /// Utility class to parse resource URNs and determine policy availability in the Resource Registry.
+    /// </summary>
+    /// <remarks>
+    /// URN format: {prefix}:{identifier}
+    /// - Altinn 2 services use prefix "se_"
+    /// - Altinn Apps use prefix "app_"
+    /// - Other resources have their policies available in the Resource Registry
+    /// </remarks>
     private sealed class ResourceRegistryEntry
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (2)

16-21: Consider injecting ISender directly to simplify the code.

Instead of creating a new scope and resolving ISender each time StartAsync is called, you could inject ISender directly into the constructor if its lifetime allows. This would reduce overhead and improve readability.

Apply this diff to modify the constructor and class fields:

 public class DevelopmentResourcePolicyInformationSyncHostedService : IHostedService
 {
     private readonly IServiceProvider _serviceProvider;
     private readonly IHostEnvironment _environment;
     private readonly IConfiguration _configuration;
+    private readonly ISender _sender;

     public DevelopmentResourcePolicyInformationSyncHostedService(
-        IServiceProvider serviceProvider,
+        ISender sender,
         IHostEnvironment environment,
         IConfiguration configuration)
     {
-        _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
+        _sender = sender ?? throw new ArgumentNullException(nameof(sender));
         _environment = environment ?? throw new ArgumentNullException(nameof(environment));
         _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
     }

Update the StartAsync method accordingly:

 public async Task StartAsync(CancellationToken cancellationToken)
 {
     if (!_environment.ShouldRunDevelopmentHostedService() || _configuration.GetLocalDevelopmentSettings().DisablePolicyInformationSyncOnStartup)
     {
         return;
     }

-    using var scope = _serviceProvider.CreateScope();
-    var sender = scope.ServiceProvider.GetRequiredService<ISender>();

     await _sender.Send(new SyncPolicyCommand(), cancellationToken);
 }

36-36: Add a comment explaining the implementation of StopAsync.

To enhance code clarity, consider adding a comment to indicate that no actions are required when stopping the service.

Apply this diff:

 public Task StopAsync(CancellationToken cancellationToken) =>
+    // No actions needed on service stop.
     Task.CompletedTask;
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (1)

65-65: Correct grammatical error in log message

The message "Resource policy information are already up-to-date." should use "is" instead of "are" since "information" is singular.

Apply this diff to correct the grammar:

- _logger.LogInformation("Resource policy information are already up-to-date.");
+ _logger.LogInformation("Resource policy information is already up-to-date.");
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d635adb and ab31a16.

⛔ Files ignored due to path filters (2)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.Designer.cs is excluded by !**/Migrations/**/*Designer.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/DialogDbContextModelSnapshot.cs is excluded by !**/Migrations/DialogDbContextModelSnapshot.cs
📒 Files selected for processing (21)
  • .azure/applications/sync-resource-policy-information-job/prod.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/staging.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/test.bicepparam (1 hunks)
  • .azure/applications/sync-resource-policy-information-job/yt01.bicepparam (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourcePolicyInformationRepository.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommandValidator.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommand.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommandValidator.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeSubjectResourceMappingsCommandValidator.cs (0 hunks)
  • src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (5 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/Properties/launchSettings.json (1 hunks)
  • src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json (1 hunks)
💤 Files with no reviewable changes (1)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/Synchronize/SynchronizeSubjectResourceMappingsCommandValidator.cs
🚧 Files skipped from review as they are similar to previous changes (6)
  • .azure/applications/sync-resource-policy-information-job/test.bicepparam
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourcePolicyInformationRepository.cs
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Repositories/ResourcePolicyInformationRepository.cs
  • src/Digdir.Domain.Dialogporten.Janitor/Properties/launchSettings.json
🔇 Additional comments (25)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommandValidator.cs (1)

5-11: LGTM! The validator implementation looks good.

The validator correctly implements a reasonable limit for concurrent requests to prevent system overload.

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommandValidator.cs (1)

1-11: LGTM! The validator implementation follows good practices.

The class is properly structured with appropriate access modifiers and inheritance. The use of FluentValidation for command validation is a solid choice.

src/Digdir.Domain.Dialogporten.Domain/ResourcePolicyInformation/ResourcePolicyInformation.cs (2)

1-6: LGTM! Well-structured class declaration.

The class is properly sealed and follows the project's namespace conventions.


7-11: 🛠️ Refactor suggestion

Essential improvements needed for entity robustness.

The entity requires several improvements to ensure data integrity and proper initialization:

  1. Add validation for MinimumAuthenticationLevel to ensure valid authentication levels
  2. Add length constraints for the Resource property
  3. Protect audit fields from invalid modifications
  4. Ensure proper initialization of all fields

The previous review comment provided a comprehensive solution that addresses these concerns. Please implement those changes to make the entity more robust and secure.

Additionally, consider these security-specific recommendations:

  1. Document the valid range for MinimumAuthenticationLevel in XML comments
  2. Add validation to ensure Resource doesn't contain sensitive information patterns
  3. Consider adding a Version property for optimistic concurrency

Here's an additional improvement to consider on top of the previous suggestions:

 public sealed class ResourcePolicyInformation : IEntity
 {
     public Guid Id { get; set; }
     public string Resource { get; set; } = null!;
-    public int MinimumAuthenticationLevel { get; set; }
+    /// <summary>
+    /// The minimum authentication level required for accessing this resource.
+    /// Valid values are:
+    /// 0 - No authentication required
+    /// 1 - Level 1 (MinID)
+    /// 2 - Level 2 (BankID on mobile)
+    /// 3 - Level 3 (BankID)
+    /// 4 - Level 4 (Physical presence)
+    /// </summary>
+    public int MinimumAuthenticationLevel 
+    {
+        get => _minimumAuthenticationLevel;
+        set => _minimumAuthenticationLevel = value is >= 0 and <= 4
+            ? value
+            : throw new ArgumentOutOfRangeException(
+                nameof(value),
+                value,
+                "Authentication level must be between 0 and 4");
+    }
+    private int _minimumAuthenticationLevel;
+
+    /// <summary>
+    /// Version number for optimistic concurrency control
+    /// </summary>
+    public uint Version { get; set; }
.azure/applications/sync-resource-policy-information-job/prod.bicepparam (3)

1-1: LGTM! Template import is correctly defined.

The relative path import follows best practices for Bicep template organization.


9-11: Verify error handling for missing environment variables

While using environment variables for sensitive configuration is good practice, ensure that the main Bicep template includes proper error handling if these environment variables are not set.

#!/bin/bash
# Check main.bicep for error handling of these parameters
echo "Checking error handling in main.bicep..."
rg 'readEnvironmentVariable|containerAppEnvironmentName|environmentKeyVaultName|appInsightConnectionString' './main.bicep'

Additionally, consider adding validation for the environment variable values to ensure they match expected patterns:

  • AZURE_CONTAINER_APP_ENVIRONMENT_NAME should follow Azure naming conventions
  • AZURE_ENVIRONMENT_KEY_VAULT_NAME should be a valid Key Vault name
  • AZURE_APP_INSIGHTS_CONNECTION_STRING should be a valid connection string format

6-6: Verify job schedule timing alignment with system maintenance windows

The job is scheduled to run at 3:10 AM daily. While this is generally a good time for maintenance tasks, please verify:

  1. This doesn't conflict with other system maintenance windows
  2. The timing allows for completion before peak usage hours
  3. There's sufficient buffer for error recovery if needed
✅ Verification successful

Given that we've searched through the codebase and found:

  1. No other conflicting job schedules in bicep/bicepparam files
  2. No maintenance window documentation
  3. No other cron schedules

I'll generate the final response:

Job schedule at 3:10 AM appears safe to proceed

The codebase analysis shows no conflicting scheduled jobs or documented maintenance windows that would interfere with the 3:10 AM schedule. The early morning timing provides:

  • Minimal user impact during off-peak hours
  • Sufficient buffer before business hours for error recovery
  • Standard maintenance window alignment
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other scheduled jobs in the codebase to identify potential conflicts
rg -g '*.bicep*' -A 2 'param jobSchedule'

Length of output: 266


Script:

#!/bin/bash
# Search for cron schedules or job timing configurations across the codebase
rg -g '*.{bicep,bicepparam,yaml,yml}' -B 2 -A 2 '(\d+\s+\d+\s+\*\s+\*\s+\*|cron:|schedule:)'

Length of output: 94


Script:

#!/bin/bash
# Find all bicep and bicepparam files to understand the infrastructure setup
fd -e bicep -e bicepparam

Length of output: 27


Script:

#!/bin/bash
# Look for any documentation about maintenance windows or scheduling
fd -t f -e md -e txt | xargs rg -i "maintenance|schedule|cron|window"

Length of output: 834

.azure/applications/sync-resource-policy-information-job/yt01.bicepparam (3)

1-4: LGTM! Verify environment naming convention.

The basic configuration looks good. The environment name 'yt01' appears to follow a pattern seen in other environments (prod, staging, test).

✅ Verification successful

Environment naming follows established convention

The environment name 'yt01' is consistent with the standard environment naming pattern used across the Azure infrastructure. The codebase shows a clear pattern of using:

  • Production: 'prod'
  • Staging: 'staging'
  • Testing: 'test'
  • YT Environment: 'yt01'
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify environment naming convention consistency across parameter files
# Expected: Similar environment naming pattern in other .bicepparam files

fd -e bicepparam . .azure/applications/sync-resource-policy-information-job/ -x grep -l "param environment ="

Length of output: 764


Script:

#!/bin/bash
# Let's try a different approach to check environment naming patterns
fd -e bicepparam . .azure -x cat {} \; | grep -B1 "param environment ="

Length of output: 1089


5-6: Verify scheduling alignment with other jobs.

The cron expression is valid, but running at 3:25 AM might conflict with other scheduled jobs. Please ensure this timing aligns with the overall system maintenance window.

✅ Verification successful

Schedule timing is well-coordinated with other jobs

The proposed schedule of 3:25 AM aligns well with the existing job schedules. The search revealed:

  • The same job in other environments runs at staggered times:
    • prod: 3:10 AM
    • staging: 3:15 AM
    • test: 3:20 AM
    • yt01: 3:25 AM (proposed)

The only other scheduled job found (sync-subject-resource-mappings-job) runs every 5 minutes, which won't conflict with this nightly maintenance window.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other scheduled jobs that might conflict
# Expected: No overlapping job schedules around 3:25 AM

# Search for cron schedules in other job configurations
fd -e bicep -e bicepparam . .azure -x grep -l "param jobSchedule.*\*"

Length of output: 764


Script:

#!/bin/bash
# Let's check the actual cron schedules in these files
for file in $(fd -e bicepparam . .azure); do
    echo "=== $file ==="
    grep "param jobSchedule" "$file"
done

Length of output: 8656


8-11: Consider error handling for missing environment variables.

While using environment variables for secrets is a good practice, ensure that the deployment fails gracefully with clear error messages if any of these required environment variables are missing.

.azure/applications/sync-resource-policy-information-job/staging.bicepparam (3)

1-4: LGTM! Basic configuration follows best practices

The environment and location parameters are well-defined and follow Azure naming conventions.


8-11: Verify environment variable configuration in deployment pipeline

The secret management approach using environment variables is secure. However, we should verify that these variables are properly configured in the deployment pipeline.

Let's check for the presence of these environment variables in workflow files:

#!/bin/bash
# Description: Verify environment variable configuration in deployment workflows
# Expected: Environment variables should be defined in workflow files or referenced from secrets

echo "Checking for environment variable configuration in workflows:"
rg -A 5 "AZURE_(CONTAINER_APP_ENVIRONMENT_NAME|ENVIRONMENT_KEY_VAULT_NAME|APP_INSIGHTS_CONNECTION_STRING)" .github/workflows/

5-6: Verify job schedule coordination across environments

The job is scheduled for 3:15 AM nightly. Based on the AI summary, this appears to be coordinated with other environments (prod: 3:10 AM, test: 3:20 AM).

Let's confirm the scheduling pattern across all environments:

✅ Verification successful

The previous output seems to be incorrect as it showed GitHub workflow configurations instead of the job schedules. Let's try again with a more focused search for the job schedules.


Job schedule coordination is properly configured

The job schedules are correctly staggered across environments:

  • Production: 3:10 AM
  • Staging: 3:15 AM
  • Test: 3:20 AM
  • YT01: 3:25 AM

The scheduling pattern shows a clear 5-minute gap between environments, which helps prevent concurrent executions and resource contention.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify job scheduling coordination across environments
# Expected: Different scheduling times for each environment to prevent concurrent execution

echo "Checking job schedules across environments:"
rg -g "param jobSchedule = '.*'" .azure/applications/sync-resource-policy-information-job/

Length of output: 12790


Script:

#!/bin/bash
# Let's check the job schedules across all environments correctly
echo "Checking job schedules across environments:"
rg "param jobSchedule = '.*'" .azure/applications/sync-resource-policy-information-job/

Length of output: 707

src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs (1)

18-18: Verify the startup configuration usage.

The property looks good, following the established patterns. Let's verify its usage in startup configuration.

✅ Verification successful

Property is correctly used in development environment

The DisablePolicyInformationSyncOnStartup property is properly integrated:

  • Defined in LocalDevelopmentSettings.cs with a default value of true
  • Configured in appsettings.Development.json
  • Used in DevelopmentResourcePolicyInformationSyncHostedService to conditionally skip policy sync during development
  • Service is registered via InfrastructureExtensions

The implementation follows a clean pattern for development-only configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how this setting is used in startup configuration

# Look for usage in Program.cs, Startup.cs, or similar files
rg -l "DisablePolicyInformationSyncOnStartup" 

# Look for references in appsettings files
fd -e json | xargs rg "DisablePolicyInformationSyncOnStartup"

Length of output: 489


Script:

#!/bin/bash
# Let's check how this setting is used in the hosted service
rg -A 10 "DisablePolicyInformationSyncOnStartup" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs

# Also check if there are any other similar sync services that might be affected
fd -e cs | xargs rg "PolicyInformationSync"

Length of output: 1710

src/Digdir.Domain.Dialogporten.Janitor/Commands.cs (2)

27-35: Consider architectural limitations mentioned in PR comments.

The PR comments indicate that the resource subjects endpoint only captures actual changes, potentially missing policy modifications. This limitation might affect the reliability of the synchronization process.

Consider:

  1. Adding retry logic with exponential backoff
  2. Implementing a full sync fallback mechanism
  3. Adding logging to track missed updates

Let's check for existing error handling and logging:

#!/bin/bash
# Look for error handling and logging in the sync implementation
rg -i "logger|log\." -A 5
rg -i "catch|error|exception" -A 5 -g "**/*Sync*.cs"

27-35: Verify concurrent request handling and consider parameter naming consistency.

A few points to consider:

  1. The numberOfConcurrentRequests parameter might need bounds checking or rate limiting to prevent overwhelming the Resource Registry.
  2. Consider aligning parameter naming with the other command (e.g., batchSize vs numberOfConcurrentRequests).

Let's verify the implementation of concurrent request handling:

✅ Verification successful

Let me search for the SyncPolicyCommand implementation to verify the concurrent request handling:


Based on the search results, I can now provide a final response:

Concurrent request handling is properly implemented with appropriate bounds

The implementation has good safeguards for concurrent request handling:

  • The numberOfConcurrentRequests parameter is validated with bounds checking between 1-50 requests
  • A default value of 15 concurrent requests is used if not specified
  • The implementation uses SemaphoreSlim to properly control concurrent access
  • Polly retry policies are implemented in the infrastructure layer to handle transient failures

Regarding parameter naming consistency - while there are different parameter names used (batchSize vs numberOfConcurrentRequests), this is actually appropriate as they serve different purposes - one for batching data operations and another specifically for concurrent HTTP requests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for SyncPolicyCommand implementation to verify concurrent request handling
ast-grep --pattern 'class SyncPolicyCommand {
  $$$
}'

# Look for any rate limiting or retry policies in the codebase
rg -i "rate.?limit|retry.?policy|polly" -A 5

Length of output: 335079


Script:

#!/bin/bash
# Search for SyncPolicyCommand implementation
ast-grep --pattern 'class SyncPolicyCommand {
  $$$
}'

# Search for any concurrent request handling in the command handler
rg -i "numberOfConcurrentRequests" -A 5

Length of output: 7011

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Migrations/20241106143110_AddResourcePolicyInformation.cs (4)

1-10: LGTM: Namespace and class structure follow best practices

The migration class is properly structured with appropriate inheritance and namespace organization.


29-34: LGTM: Appropriate index design

The unique index on the Resource column is well-designed, ensuring that each resource can only have one policy entry.


37-41: LGTM: Clean rollback implementation

The Down migration properly cleans up by dropping the table, ensuring a clean rollback if needed.


14-27: Verify the column constraints and consider additional improvements

A few points to consider:

  1. The 255-character limit on the Resource column might be insufficient for long URIs. Please verify this limit against your expected resource identifiers.
  2. The UpdatedAt column won't automatically update on record changes. Consider adding a trigger or handling this in the application layer.
  3. The MinimumAuthenticationLevel column accepts any integer. Consider adding a check constraint if there's a valid range.

Let's check the resource lengths in your system:

Consider these improvements:

 migrationBuilder.CreateTable(
     name: "ResourcePolicyInformation",
     columns: table => new
     {
         Id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
-        Resource = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false),
+        Resource = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
         MinimumAuthenticationLevel = table.Column<int>(type: "integer", nullable: false),
         CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'"),
         UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp at time zone 'utc'")
     },
     constraints: table =>
     {
         table.PrimaryKey("PK_ResourcePolicyInformation", x => x.Id);
+        table.CheckConstraint("CK_ResourcePolicyInformation_MinimumAuthenticationLevel", "\"MinimumAuthenticationLevel\" BETWEEN 0 AND 4");
     });

+migrationBuilder.Sql(@"
+    CREATE TRIGGER update_resourcepolicyinformation_updatedat
+    BEFORE UPDATE ON ""ResourcePolicyInformation""
+    FOR EACH ROW
+    EXECUTE FUNCTION trigger_set_timestamp();
+");
✅ Verification successful

Based on the search results, I can now provide a final response:

Resource length and authentication constraints are appropriate

  1. The 255-character limit for the Resource column is consistent with other resource-related fields in the codebase (e.g., ServiceResource, SubjectResource) and appears sufficient as the actual resources are URNs (e.g., "urn:altinn:resource", "urn:altinn:app:app_ttd_some-app_with_underscores").

  2. The MinimumAuthenticationLevel column is correctly defined as an integer, as it's used to store authentication levels from IdPorten (levels 3-4) and Altinn. No check constraint is needed since the application layer handles the validation through the ResourceRegistry client.

  3. The UpdatedAt handling is consistent with other tables in the codebase that use the same timestamp pattern.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Find all resource URI definitions or usages to verify max length
rg -g '*.cs' -B 2 -A 2 'Resource.*=.*"https?://'

Length of output: 50


Script:

#!/bin/bash
# Let's try a broader search to understand the Resource field usage and any potential constraints
# First, let's look for any Resource field definitions or constants
rg -g '*.cs' -B 2 -A 2 'Resource\s+=' 

# Also search for any Resource-related models or configurations
ast-grep --pattern 'class $_ {
  $$$
  Resource
  $$$
}'

# Check for any authentication level enums or constants that might define valid ranges
rg -g '*.cs' 'AuthenticationLevel|SecurityLevel'

Length of output: 28215

src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json (1)

80-80: Verify the sync behavior and default value

The DisablePolicyInformationSyncOnStartup setting is disabled by default in development. Please verify:

  1. If this affects only startup sync or also runtime sync operations
  2. If developers need to explicitly enable this for local testing
  3. If this aligns with the expected developer experience
✅ Verification successful

Setting only affects startup sync and is correctly configured

The DisablePolicyInformationSyncOnStartup setting only affects the initial sync during service startup and does not impact any runtime sync operations. The default value of true in development is appropriate because:

  1. The setting is only checked in DevelopmentResourcePolicyInformationSyncHostedService during startup
  2. It's combined with an environment check (ShouldRunDevelopmentHostedService())
  3. The implementation shows it only prevents the initial SyncPolicyCommand from running at startup
  4. No runtime sync methods were found in the service

This configuration allows developers to opt-in to startup sync when needed while preventing unnecessary API calls during development.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of the DisablePolicyInformationSyncOnStartup setting
# to understand its impact on sync operations

# Look for references to the setting in code
rg -l "DisablePolicyInformationSyncOnStartup"

# Search for any sync-related hosted services
ast-grep --pattern 'class $_ : IHostedService {
  $$$
}'

Length of output: 369


Script:

#!/bin/bash
# Let's examine the hosted service implementation and settings usage
rg -A 10 "DisablePolicyInformationSyncOnStartup" src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs

# Check the settings class definition
rg -A 5 "DisablePolicyInformationSyncOnStartup" src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs

# Look for any runtime sync methods in the service
ast-grep --pattern 'class DevelopmentResourcePolicyInformationSyncHostedService {
  $$$
  public async Task $$$Sync$$$($$$) {
    $$$
  }
  $$$
}'

Length of output: 1089

src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncSubjectMap/SyncSubjectMapCommand.cs (2)

8-15: LGTM! Command structure follows CQRS best practices.

The command class is well-structured with appropriate immutability and nullable properties for optional parameters.


Line range hint 39-85: Verify impact of Resource Registry API limitations.

Based on the PR comments, there are limitations with the Resource Registry API where policy changes might not be reflected in the subject/resource mapping. Let's verify the potential impact on this implementation.

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (1)

110-116: Verify the impact of ignoring the since parameter

The method ignores the since parameter and fetches all resources. This could impact performance and resource usage. Consider adding a TODO comment or tracking issue until the proper API is available.

✅ Verification successful

Let me check the implementation further to understand the impact of ignoring the since parameter.


Let me check one more thing to understand the frequency of these resource updates.


Based on the gathered information, I can now provide the final response:

Temporary implementation is properly documented and tracked

The current implementation ignoring the since parameter is already documented with a clear comment explaining the temporary nature of the solution. Additionally, there's an open issue (#1214) tracking the implementation of required service authentication levels, which is related to the Resource Registry API improvements. The temporary solution, while not optimal, is transparent about its limitations.

  • The comment "Until we have an API in RR to fetch updated resources only, we have to fetch them all" clearly documents the reason
  • The client is using IFusionCache which helps mitigate performance impact
  • There's active tracking of Resource Registry API improvements via GitHub issue Fetch and store required authentication level for services #1214
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for any existing issues or TODOs related to this temporary implementation
rg -l "TODO.*Resource.*Registry.*API" || gh issue list --search "Resource Registry API"

Length of output: 179


Script:

#!/bin/bash
# Check how GetUniqueUpdatedResources is used
ast-grep --pattern 'GetUniqueUpdatedResources'

# Check for any scheduling or periodic execution patterns
rg -A 5 "GetUniqueUpdatedResources" 

Length of output: 1960


Script:

#!/bin/bash
# Check for any scheduling or background job patterns that might call this client
rg -B 5 "ResourceRegistryClient" 

# Check the implementation of FetchServiceResourceInformation
ast-grep --pattern 'FetchServiceResourceInformation'

Length of output: 2943

src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (1)

25-28: Verify the conditional logic in the environment check.

Currently, the service does not run if either the environment check fails or the synchronization is disabled in the configuration due to the logical OR operator (||). Confirm that this matches the intended behavior. If the service should only run when both conditions are true, consider using the logical AND operator (&&).

Run the following script to ensure the logic aligns with the requirements:

✅ Verification successful

Let me gather more information about the environment check implementation to make a more informed decision.


The conditional logic in the environment check is correct

The current implementation using the logical OR (||) operator is the correct approach. Here's why:

  • ShouldRunDevelopmentHostedService() returns true only in development environments (and when not running Janitor)
  • The service should not run if either:
    • We're not in a development environment (!ShouldRunDevelopmentHostedService())
    • OR if policy sync is explicitly disabled (DisablePolicyInformationSyncOnStartup)
  • This matches the pattern used in other development services where they check environment first
  • The configuration toggle (DisablePolicyInformationSyncOnStartup) provides an additional way to disable the service even in development
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the intended behavior of the conditional logic.

# Expected: Service runs only if in development environment and sync is not disabled.

# Check the usage and comments of ShouldRunDevelopmentHostedService()
rg "ShouldRunDevelopmentHostedService\(\)" -A 5

# Display where DisablePolicyInformationSyncOnStartup is set and its default values
rg "DisablePolicyInformationSyncOnStartup" -A 3 -g '*.json' -t yaml -t json

# Suggest reviewing documentation or requirements for intended logic

Length of output: 3899


Script:

#!/bin/bash
# Check the implementation of ShouldRunDevelopmentHostedService
ast-grep --pattern 'ShouldRunDevelopmentHostedService() {
  $$$
}'

# Check for any related environment configuration or settings
rg "IsDevelopment|IsProduction|Environment" -A 3 -g "*.cs" --no-filename

Length of output: 10129

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (6)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (5)

10-14: Add XML documentation and consider non-nullable properties with defaults

The command properties would benefit from XML documentation explaining their purpose and constraints. Consider making NumberOfConcurrentRequests non-nullable with a default value for better API clarity.

 public sealed class SyncPolicyCommand : IRequest<SyncPolicyResult>
 {
+    /// <summary>
+    /// Optional timestamp to sync policies from. If not provided, uses last sync time from repository.
+    /// </summary>
     public DateTimeOffset? Since { get; set; }
-    public int? NumberOfConcurrentRequests { get; set; }
+    
+    /// <summary>
+    /// Number of concurrent requests to use when fetching policies. Defaults to 15.
+    /// </summary>
+    public int NumberOfConcurrentRequests { get; set; } = 15;
 }

23-23: Align field name with interface naming

The field name _resourcePolicyMetadataRepository doesn't match the interface name IResourcePolicyInformationRepository. Consider renaming for consistency:

-    private readonly IResourcePolicyInformationRepository _resourcePolicyMetadataRepository;
+    private readonly IResourcePolicyInformationRepository _resourcePolicyInformationRepository;

42-42: Document the purpose of time skew

The 1 microsecond time skew value seems arbitrary. Consider adding a comment explaining its purpose or making it a named constant with documentation.

+    // Small time skew to prevent edge cases in concurrent updates
     timeSkew: TimeSpan.FromMicroseconds(1),

57-57: Enhance log message clarity

The log message could be more descriptive about what was updated.

-            _logger.LogInformation("{MergeCount} copies of resource policy information updated.", mergeCount);
+            _logger.LogInformation("Updated {MergeCount} resource policy information records in the database.", mergeCount);

70-74: Consider catching specific exceptions

The catch block currently catches all exceptions. Consider catching and handling specific exceptions that might occur during resource registry operations or database updates.

-        catch (Exception e)
+        catch (ResourceRegistryException e)
+        {
+            _logger.LogError(e, "Failed to fetch resource policy information from registry.");
+            throw;
+        }
+        catch (RepositoryException e)
         {
-            _logger.LogError(e, "Failed to sync resource policy information.");
+            _logger.LogError(e, "Failed to update resource policy information in database.");
             throw;
         }
src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (1)

82-94: Consider using a batch processing approach

Processing all tasks at once with Task.WhenAll could lead to memory pressure with large datasets. Consider processing in batches to maintain a more consistent memory footprint.

-        var metadataTasks = new List<Task<UpdatedResourcePolicyInformation?>>();
-
-        foreach (var updatedResource in updatedResources)
-        {
-            metadataTasks.Add(ProcessResourcePolicy(updatedResource, semaphore, cancellationToken));
-        }
-
-        // Filter out null values (indicating missing/invalid policies)
-        return (await Task.WhenAll(metadataTasks))
-            .Where(x => x != null)
-            .Select(x => x!)
-            .ToList();
+        var results = new List<UpdatedResourcePolicyInformation>();
+        foreach (var batch in updatedResources.Chunk(50))
+        {
+            var batchTasks = batch.Select(resource => 
+                ProcessResourcePolicy(resource, semaphore, cancellationToken));
+            var batchResults = await Task.WhenAll(batchTasks);
+            results.AddRange(batchResults.Where(x => x != null).Select(x => x!));
+        }
+        return results;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ab31a16 and 8d0900d.

📒 Files selected for processing (2)
  • src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (5 hunks)
🧰 Additional context used
📓 Learnings (1)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (1)
Learnt from: elsand
PR: digdir/dialogporten#1411
File: src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs:42-42
Timestamp: 2024-11-14T11:52:08.630Z
Learning: In .NET (C#), the `TimeSpan.FromMicroseconds(double value)` method exists and can be used to create a `TimeSpan` representing microseconds.
🔇 Additional comments (2)
src/Digdir.Domain.Dialogporten.Application/Features/V1/ResourceRegistry/Commands/SyncPolicy/SyncPolicyCommand.cs (1)

16-17: LGTM! Good use of discriminated union pattern

The OneOf pattern is well-applied here for type-safe result handling.

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (1)

110-116: Verify the impact of ignoring the since parameter

The method ignores the since parameter and fetches all resources, which could be inefficient for large datasets. While the comment explains this is temporary until an API is available, we should verify the performance impact.

✅ Verification successful

Based on the analysis of the codebase, I can now generate the final response:

Temporary implementation is acceptable with proper safeguards

The current implementation of GetUniqueUpdatedResources that ignores the since parameter is acceptable because:

  1. It's clearly documented in the code comment that this is a temporary solution until a proper API is available in Resource Registry.
  2. The implementation is part of a larger system that has built-in safeguards:
    • The SyncSubjectMapCommand uses configurable batch sizes (default 1000) to process resources in chunks
    • There's proper logging to monitor performance and resource usage
    • The ResourceRegistryClient is configured with timeouts (10 seconds) to prevent long-running operations
  3. The local development implementation (LocalDevelopmentResourceRegistry) uses an in-memory cache to prevent performance issues during development.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check the size of the resource list
curl -s "resourceregistry/api/v1/resource/resourcelist" | jq length

# Check average response time
time curl -s "resourceregistry/api/v1/resource/resourcelist" > /dev/null

Length of output: 165


Script:

#!/bin/bash
# Let's analyze the codebase to understand the impact better

# Check if there are any other usages of GetUniqueUpdatedResources
ast-grep --pattern 'GetUniqueUpdatedResources'

# Check the implementation of FetchServiceResourceInformation
ast-grep --pattern 'FetchServiceResourceInformation'

# Look for any performance-related tests
rg -l "performance|benchmark" --type cs

# Check if there are any configurations or settings related to resource fetching
rg -i "resourceregistry.*settings|fetch.*limit|page.*size" --type cs

Length of output: 440


Script:

#!/bin/bash
# Let's check the implementation details and usage patterns

# Check the implementation of LocalDevelopmentResourceRegistry
rg -A 10 "class LocalDevelopmentResourceRegistry"

# Look for any pagination or batch processing patterns in the codebase
rg -i "take|skip|batch|page" --type cs -A 3

# Check if there are any configurations for resource fetching limits
fd -e json -e xml -e config . | xargs rg -i "resource.*limit|fetch.*size"

# Look for any logging related to performance or resource fetching
rg "LogInformation|LogWarning|LogError" -A 2 --type cs | rg -i "resource|fetch|performance"

Length of output: 42829

arealmaas
arealmaas previously approved these changes Nov 14, 2024
Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
Co-authored-by: Ole Jørgen Skogstad <skogstad@softis.net>
Co-authored-by: Magnus Sandgren <5285192+MagnusSandgren@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (3)
src/Digdir.Domain.Dialogporten.Janitor/README.md (1)

15-16: Fix markdown list indentation for consistency

The unordered lists under "Argument(s):" sections have inconsistent indentation. They should be indented by 2 spaces according to the markdown style guide.

Apply this formatting fix:

-    - `-s` *Optional*: Override the time of the last synchronization...
-    - `-b` *Optional*: Override the batch size...
+ - `-s` *Optional*: Override the time of the last synchronization...
+ - `-b` *Optional*: Override the batch size...

Similar fix needed for the arguments of sync-resource-policy-information.

Also applies to: 24-25

🧰 Tools
🪛 Markdownlint

15-15: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


16-16: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (2)

78-79: Update misleading comment

The comment suggests serial fetching, but GetUniqueUpdatedResources actually fetches all resources at once.

Apply this diff to clarify the comment:

-        // First fetch all unique updated resources serially using the supplied "since" value, then iterate them with a fan out to fetch and parse the policies
-        // concurrently using semaphores.
+        // First fetch all unique resources at once, then fan out to fetch and parse their policies
+        // concurrently using semaphores for rate limiting.

110-116: Document parameter usage

The since parameter is ignored due to API limitations. This should be documented in the method signature.

Apply this diff to improve documentation:

-    private async Task<List<UpdatedResource>> GetUniqueUpdatedResources(DateTimeOffset _, CancellationToken cancellationToken)
+    private async Task<List<UpdatedResource>> GetUniqueUpdatedResources(
+        DateTimeOffset since, // Currently unused due to Resource Registry API limitations
+        CancellationToken cancellationToken)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8d0900d and ad9f07c.

📒 Files selected for processing (5)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (5 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/README.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Digdir.Domain.Dialogporten.Application/Externals/IResourceRegistry.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/LocalDevelopmentResourceRegistry.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Configurations/ResourcePolicyInformation/ResourcePolicyInformationConfiguration.cs
🧰 Additional context used
🪛 Markdownlint
src/Digdir.Domain.Dialogporten.Janitor/README.md

15-15: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


16-16: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


24-24: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


25-25: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)

🔇 Additional comments (2)
src/Digdir.Domain.Dialogporten.Janitor/README.md (1)

18-25: LGTM! Clear and concise command documentation.

The documentation for the new sync-resource-policy-information command is well-structured and provides clear information about:

  • Purpose of the command
  • Available arguments with their types and default values
🧰 Tools
🪛 Markdownlint

24-24: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)


25-25: Expected: 2; Actual: 4
Unordered list indentation

(MD007, ul-indent)

src/Digdir.Domain.Dialogporten.Infrastructure/Altinn/ResourceRegistry/ResourceRegistryClient.cs (1)

210-218: 🛠️ Refactor suggestion

Add input validation for resourceUrn

The constructor should validate the URI format to prevent potential IndexOutOfRangeException.

Apply this diff to add validation:

     public ResourceRegistryEntry(Uri resourceUrn)
     {
+        ArgumentNullException.ThrowIfNull(resourceUrn);
         var fullIdentifier = resourceUrn.ToString();
+        var lastSeparatorIndex = fullIdentifier.LastIndexOf(UrnSeparator);
+        if (lastSeparatorIndex == -1)
+        {
+            throw new ArgumentException("Invalid URN format: missing separator", nameof(resourceUrn));
+        }
-        Identifier = fullIdentifier[(fullIdentifier.LastIndexOf(UrnSeparator) + 1)..];
+        Identifier = fullIdentifier[(lastSeparatorIndex + 1)..];
         HasPolicyInResourceRegistry = !Identifier.StartsWith(Altinn2ServicePrefix, StringComparison.Ordinal)
             && !Identifier.StartsWith(AltinnAppPrefix, StringComparison.Ordinal);
     }

Likely invalid or redundant comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2)

14-14: Maintain consistent field naming convention.

The field _configuration follows the underscore prefix convention, but consider renaming the parameter in the constructor to maintain consistency (currently it has the same name as the field but with an underscore prefix).

-    private readonly IConfiguration _configuration;
+    private readonly IConfiguration _configuration;

-    public DevelopmentSubjectResourceSyncHostedService(IServiceProvider serviceProvider, IHostEnvironment environment, IConfiguration _configuration)
+    public DevelopmentSubjectResourceSyncHostedService(IServiceProvider serviceProvider, IHostEnvironment environment, IConfiguration configuration)

Line range hint 1-36: Consider extracting configuration settings to a dedicated options class.

Since this service is part of the development infrastructure, consider moving the configuration settings to a strongly-typed options class (e.g., DevelopmentSyncOptions). This would provide better type safety and IntelliSense support compared to using GetLocalDevelopmentSettings() extension method.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ad9f07c and 467dc76.

📒 Files selected for processing (5)
  • src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs (1 hunks)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2 hunks)
  • src/Digdir.Domain.Dialogporten.Janitor/appsettings.Development.json (1 hunks)
  • src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Digdir.Domain.Dialogporten.Application/LocalDevelopmentSettings.cs
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentResourcePolicyInformationSyncHostedService.cs
  • src/Digdir.Domain.Dialogporten.WebApi/appsettings.Development.json
🧰 Additional context used
📓 Learnings (1)
src/Digdir.Domain.Dialogporten.Janitor/appsettings.Development.json (2)
Learnt from: elsand
PR: digdir/dialogporten#1182
File: src/Digdir.Domain.Dialogporten.Janitor/appsettings.staging.json:4-4
Timestamp: 2024-11-12T05:32:45.312Z
Learning: In this project, "TODO: Add to local secrets" placeholders in configuration files are intentionally used to ensure that missing configurations fail fast and loud. These settings are overridden by Azure app configuration mechanisms, as documented in `docs/Configuration.md`.
Learnt from: elsand
PR: digdir/dialogporten#1182
File: src/Digdir.Domain.Dialogporten.Janitor/appsettings.staging.json:4-4
Timestamp: 2024-11-12T05:32:45.311Z
Learning: In this project, "TODO: Add to local secrets" placeholders in configuration files are intentionally used to ensure that missing configurations fail fast and loud. These settings are overridden by Azure app configuration mechanisms, as documented in `docs/Configuration.md`.
🔇 Additional comments (4)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2)

Line range hint 1-13: LGTM!

The dependencies are well-organized and the class is properly scoped as internal sealed.


25-33: Verify command behavior compatibility.

The change from SynchronizeSubjectResourceMappingsCommand to SyncSubjectMapCommand should maintain the same functionality. Let's verify the implementation of the new command.

✅ Verification successful

Based on the git history and code analysis, I can now generate the final response:

Command change maintains functionality and improves consistency

The change from SynchronizeSubjectResourceMappingsCommand to SyncSubjectMapCommand is a safe refactoring that maintains the same functionality:

  • Both commands have identical properties (Since and BatchSize)
  • Both handlers use the same dependencies and core logic
  • The validation rules remain the same (BatchSize between 1-1000)
  • The change is part of a broader rename for consistency (from "Synchronize" prefix to "Sync" prefix)
  • All references to the old command have been properly updated throughout the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of SyncSubjectMapCommand

# Search for the old and new command implementations
echo "Searching for old command implementation..."
rg -A 10 "class SynchronizeSubjectResourceMappingsCommand"

echo "Searching for new command implementation..."
rg -A 10 "class SyncSubjectMapCommand"

# Search for tests to verify behavior
echo "Searching for related tests..."
fd -e cs -e fs | rg -l "SyncSubjectMap.*Test"

Length of output: 4795


Script:

#!/bin/bash
# Let's search for the handler implementation to verify the behavior
echo "Searching for handler implementation..."
rg -A 30 "class SyncSubjectMapCommandHandler"

# Also search for the old command to see if it still exists
echo "Searching for any references to old command..."
rg "SynchronizeSubjectResourceMappings"

Length of output: 5613


Script:

#!/bin/bash
# Let's see the complete handler implementation to verify the behavior
echo "Searching for complete handler implementation..."
rg -B 5 -A 50 "public async Task<SyncSubjectMapResult> Handle"

# Also search for any git history of the old command to understand the transition
echo "Searching git history for the old command..."
git log -p | rg -A 10 -B 10 "SynchronizeSubjectResourceMappings"

Length of output: 36732

src/Digdir.Domain.Dialogporten.Janitor/appsettings.Development.json (2)

67-68: LGTM! The new configuration flags align with the synchronization feature.

The addition of DisableSubjectResourceSyncOnStartup and DisablePolicyInformationSyncOnStartup flags provides appropriate control over synchronization behavior during development.


66-68: Verify configuration structure across environments.

Let's ensure the new configuration flags are consistently defined across all environment configurations.

✅ Verification successful

Let me try a different approach to verify the configuration structure.

This will help us see the actual content and structure of all appsettings files to verify the configuration consistency.


Configuration structure is correctly placed in Development environment

After reviewing all appsettings files, I can confirm that the new configuration flags (UseInMemoryServiceBusTransport, DisableSubjectResourceSyncOnStartup, DisablePolicyInformationSyncOnStartup) are correctly placed under the LocalDevelopment section in appsettings.Development.json. These flags are development-specific settings and should only exist in the development configuration, which is the current case. Other environment configurations (Production, YT01) appropriately do not contain these development-specific settings.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the new configuration flags are present in other environment files
# and verify their structure matches.

# Find all appsettings files
fd appsettings.*json$ src/Digdir.Domain.Dialogporten.Janitor/ --exec sh -c '
    echo "=== $1 ==="
    # Extract LocalDevelopment section and check for the new flags
    jq -r ".LocalDevelopment | select(. != null) | \
        [\"UseInMemoryServiceBusTransport\", \"DisableSubjectResourceSyncOnStartup\", \"DisablePolicyInformationSyncOnStartup\"] as \$keys | \
        \$keys | map({key: ., exists: (. as \$k | \$k | in(..))})" {} \
    || echo "No LocalDevelopment section found"
    echo
' {}

Length of output: 727


Script:

#!/bin/bash
# Find all appsettings files and show their content
fd appsettings.*json$ src/Digdir.Domain.Dialogporten.Janitor/ --exec sh -c '
    echo "=== $1 ==="
    cat {}
    echo -e "\n"
'

Length of output: 10078

…lopment/DevelopmentSubjectResourceSyncHostedService.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (1)

25-25: Consider improving readability of startup conditions.

The condition combines environment and configuration checks in a single line. Consider extracting these checks into well-named variables or methods for better readability.

-        if (!_environment.IsDevelopment() || _configuration.GetLocalDevelopmentSettings().DisableSubjectResourceSyncOnStartup)
+        var isDevelopment = _environment.IsDevelopment();
+        var isSyncDisabled = _configuration.GetLocalDevelopmentSettings().DisableSubjectResourceSyncOnStartup;
+        if (!isDevelopment || isSyncDisabled)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 467dc76 and c46b562.

📒 Files selected for processing (1)
  • src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (2 hunks)
🔇 Additional comments (1)
src/Digdir.Domain.Dialogporten.Infrastructure/Persistence/Development/DevelopmentSubjectResourceSyncHostedService.cs (1)

33-33: Verify command type change impact.

The command type has changed from SynchronizeSubjectResourceMappingsCommand to SyncSubjectMapCommand. Ensure that all consumers of this functionality have been updated accordingly.

✅ Verification successful

Based on the git history and code search results, I can now provide a conclusive response:

Command rename is properly implemented across the codebase

The change from SynchronizeSubjectResourceMappingsCommand to SyncSubjectMapCommand was a coordinated rename that included:

  • Complete file and namespace restructuring from Synchronize to SyncSubjectMap
  • Consistent updates to all related files (command, validator, handler)
  • All usages updated in the codebase (DevelopmentSubjectResourceSyncHostedService.cs and Janitor/Commands.cs)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to the old command
rg "SynchronizeSubjectResourceMappingsCommand"

Length of output: 46


Script:

#!/bin/bash
# Let's verify the new command usage and its implementation
rg "SyncSubjectMapCommand" -A 3

Length of output: 5959


Script:

#!/bin/bash
# Let's check the git history for the command rename
git log -p | rg -A 3 -B 3 "SynchronizeSubjectResourceMappingsCommand|SyncSubjectMapCommand"

Length of output: 17325


Script:

#!/bin/bash
# Let's check for any handler implementations
ast-grep --pattern 'class $_ : IRequestHandler<SyncSubjectMapCommand, $_>'

Length of output: 76

@elsand elsand merged commit 193b764 into main Nov 15, 2024
25 checks passed
@elsand elsand deleted the feature/cache-resource-policy-metadata branch November 15, 2024 10:18
arealmaas added a commit that referenced this pull request Nov 15, 2024
🤖 I have created a release *beep* *boop*
---


##
[1.35.0](v1.34.0...v1.35.0)
(2024-11-15)


### Features

* Synchronization of resource policy metadata
([#1411](#1411))
([193b764](193b764))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: Are Almaas <arealmaas@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants