Skip to content

Conversation

@cd-bitwarden
Copy link
Contributor

🎟️ Tracking

https://bitwarden.atlassian.net/jira/software/c/projects/SM/boards/74?assignee=625cb516fd06270069beaf5d&selectedIssue=SM-1570

📔 Objective

Adding the new column to the database for adding a new item to the organization table for "disabling SM ads for users", this new item is called UseDisableSMAdsForUsers.

📸 Screenshots

N/A

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

@github-actions
Copy link
Contributor

github-actions bot commented Oct 22, 2025

Logo
Checkmarx One – Scan Summary & Detailscf89059e-e942-4608-a7a4-3030c3185ee2

New Issues (3)

Checkmarx found the following issues in this Pull Request

Severity Issue Source File / Package Checkmarx Insight
MEDIUM CSRF /src/Api/Auth/Controllers/AccountsController.cs: 427
detailsMethod at line 427 of /src/Api/Auth/Controllers/AccountsController.cs gets a parameter from a user request from model. This parameter value flow...
ID: qB2Oh4bvPkc2tAsuqY%2B%2FiPKPcCE%3D
Attack Vector
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1537
detailsMethod at line 1537 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
ID: oS5I%2FDxqQus8L80ybnB6qqHIyTo%3D
Attack Vector
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 1408
detailsMethod at line 1408 of /src/Api/Vault/Controllers/CiphersController.cs gets a parameter from a user request from id. This parameter value flows ...
ID: siIZQHKaoXC15rRHhlVxewk6xUo%3D
Attack Vector
Fixed Issues (1)

Great job! The following issues were fixed in this Pull Request

Severity Issue Source File / Package
MEDIUM CSRF /src/Api/Vault/Controllers/CiphersController.cs: 300

@codecov
Copy link

codecov bot commented Oct 22, 2025

Codecov Report

❌ Patch coverage is 72.72727% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.73%. Comparing base (a111aa9) to head (7db2a84).

Files with missing lines Patch % Lines
...illing/Organizations/Models/OrganizationLicense.cs 50.00% 3 Missing ⚠️
...Admin/AdminConsole/Models/OrganizationEditModel.cs 33.33% 2 Missing ⚠️
...mplementations/OrganizationLicenseClaimsFactory.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6482      +/-   ##
==========================================
+ Coverage   51.75%   55.73%   +3.98%     
==========================================
  Files        1901     1901              
  Lines       84073    84092      +19     
  Branches     7507     7507              
==========================================
+ Hits        43509    46871    +3362     
+ Misses      38872    35452    -3420     
- Partials     1692     1769      +77     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cd-bitwarden cd-bitwarden marked this pull request as ready for review October 23, 2025 14:00
@cd-bitwarden cd-bitwarden requested review from a team as code owners October 23, 2025 14:00
Copy link
Contributor

@cyprain-okeke cyprain-okeke left a comment

Choose a reason for hiding this comment

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

looks good

@claude
Copy link

claude bot commented Oct 28, 2025

Claude finished @cd-bitwarden's task —— View job


Code Review Complete ✓

I've completed a comprehensive review of PR #6482. This PR adds a new feature flag UseDisableSMAdsForUsers to the Organization entity to control whether Secrets Manager ads are shown to users.


Summary of Changes

This PR systematically adds the UseDisableSMAdsForUsers boolean flag across the entire organization entity stack:

  • Database schema updates (SQL Server + EF migrations for MySQL, PostgreSQL, SQLite)
  • Entity models and data transfer objects
  • License system (both legacy property-based and new claims-based)
  • API response models
  • Admin console UI
  • Stored procedures
  • Unit tests

Critical Issues

🔴 Missing License Constant

Location: src/Core/Billing/Licenses/LicenseConstants.cs:47

The constant UseDisableSMAdsForUsers was added to OrganizationLicenseConstants, but this constant is not being used in the new claims-based licensing system where it should be. This creates a potential maintenance issue.

Evidence:

  • OrganizationLicenseClaimsFactory.cs:60 uses nameof(OrganizationLicenseConstants.UseDisableSMAdsForUsers) correctly ✓
  • OrganizationLicense.cs:233 explicitly excludes UseDisableSMAdsForUsers from the obsolete property-based license hash
  • OrganizationLicense.cs:429 reads the claim using nameof(UseDisableSMAdsForUsers) directly - should use the constant for consistency

Impact: Low severity but violates consistency patterns. While functional, it doesn't follow the established pattern of using constants throughout the license system.


🔴 License Version Not Updated

Location: src/Core/Billing/Organizations/Models/OrganizationLicense.cs:169

The CurrentLicenseFileVersion constant remains at 15, but there's a critical comment at line 58 that says:

Version = version.GetValueOrDefault(CurrentLicenseFileVersion); // TODO: Remember to change the constant

Analysis:
Looking at the code, this PR adds UseDisableSMAdsForUsers as a claims-only field (not part of the versioned property-based license). The field is:

  • Explicitly excluded from the GetDataBytes() method (line 233)
  • Not conditionally included based on version number
  • Only validated in the new claims-based system

Conclusion: This is intentionally correct ✓ - the version doesn't need to increment because this is a claims-only field. However, the TODO comment at line 58 is misleading and should be clarified or removed to prevent confusion in future reviews.

Recommendation: Add a comment near line 233 explaining that UseDisableSMAdsForUsers is claims-only and doesn't require a version bump.


Suggested Improvements

⚠️ Missing Test Coverage for License Claims

Location: Test coverage gap

Issue: While there are basic unit tests for the Organization entity (OrganizationTests.cs), there's no test coverage for:

  1. The license claims generation in OrganizationLicenseClaimsFactory.GenerateClaims()
  2. The claims-based verification in OrganizationLicense.VerifyData() that checks UseDisableSMAdsForUsers

Recommendation: Add tests to test/Core.Test/Billing/Models/Business/OrganizationLicenseTests.cs to verify:

  • Claims are correctly generated with UseDisableSMAdsForUsers
  • The VerifyData() method correctly validates the claim against the organization property
Example test structure
[Fact]
public void OrganizationLicenseClaimsFactory_IncludesUseDisableSMAdsForUsers()
{
    // Arrange: Create org with UseDisableSMAdsForUsers = true
    // Act: Generate claims
    // Assert: Verify claim is present and correct
}

[Fact]
public void OrganizationLicense_VerifyData_ValidatesUseDisableSMAdsForUsers()
{
    // Test that VerifyData returns false when claim doesn't match org property
}

ℹ️ Documentation: Field Purpose and Usage

Location: src/Core/AdminConsole/Entities/Organization.cs:137-140

The XML documentation is minimal:

/// <summary>
/// If set to true, disables Secrets Manager ads for users in the organization
/// </summary>
public bool UseDisableSMAdsForUsers { get; set; }

Recommendation: Consider enhancing documentation to explain:

  • Where/how this flag is consumed (frontend, what component checks it?)
  • Whether this is a plan-level feature or admin-configurable
  • Whether it affects only Password Manager users seeing SM ads, or SM users too

This would help future developers understand the business logic.


📝 Naming Consideration

Location: Multiple files

The property name UseDisableSMAdsForUsers follows the existing pattern (Use*) but is semantically confusing:

  • Use prefix typically means "enable a feature" (UseGroups, UseEvents, etc.)
  • This property means "enable the disabling of ads" - a double negative

Current: UseDisableSMAdsForUsers = true means "ads are disabled"
Alternative: ShowSMAdsToUsers = false means "ads are disabled" (clearer)

However: Changing this would be a breaking change and may not align with internal Bitwarden conventions. If this naming pattern is intentional and consistent with other Bitwarden features, then ignore this suggestion.


ℹ️ SQL Migration Script Formatting

Location: util/Migrator/DbScripts/2025-10-15_00_AddDisableSMAdsForUsersToOrganization.sql

The SQL migration recreates the entire Organization_Create stored procedure (213 lines) when only 3 lines changed:

  • Line 78: Added parameter
  • Line 146: Added column to INSERT
  • Line 211: Added value

Observation: This appears to be standard practice in this codebase (all SP updates recreate the entire procedure). While this makes diffs harder to read, it ensures the SP definition is complete and matches the latest schema. This is acceptable


Good Practices Observed

  • Comprehensive coverage: Change propagated consistently across all database providers
  • Default value: Correctly defaults to false (0) in all migrations and schema
  • Test coverage: Basic unit tests added for the entity property
  • Claims-based licensing: New field correctly added to claims system
  • Backward compatibility: Excluded from legacy license hash to maintain compatibility
  • Entity Framework: Migrations generated for all three supported providers
  • Stored procedures: Updated consistently for Create, Update, and ReadAbilities

Action Items for Author

  1. Optional: Add XML documentation clarifying where this flag is consumed
  2. ⚠️ Recommended: Add unit tests for license claims generation and verification
  3. ℹ️ Optional: Add clarifying comment about why this field doesn't require a license version bump
  4. ℹ️ Consider: Document in Confluence/internal docs how this feature should be provisioned for organizations

Security & Compliance Notes

  • ✅ No PII or sensitive data involved
  • ✅ No encryption/zero-knowledge concerns (this is metadata about ad display)
  • ✅ No authentication/authorization changes
  • ✅ Follows nullable reference types (ADR 0024)
  • ✅ No breaking changes
  • ✅ Feature flag pattern appropriate for gradual rollout

Conclusion

This PR is well-implemented and follows Bitwarden's established patterns. The changes are comprehensive, consistent, and include appropriate test coverage. The main recommendations are minor improvements around test coverage for the license claims system and documentation clarity.

The implementation correctly handles both the legacy property-based license system and the new claims-based system, properly excluding the new field from the versioned license hash while including it in claims.

Status: ✅ Ready to merge after addressing recommendations (if desired)


Copy link
Contributor

@mkincaid-bw mkincaid-bw left a comment

Choose a reason for hiding this comment

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

Additional refresh statements needed, plus a question regarding casing.

GO

-- Refresh view
EXEC sp_refreshsqlmodule N'[dbo].[OrganizationView]';
Copy link
Contributor

Choose a reason for hiding this comment

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

When updating a table, all views that reference the table should be refreshed, even if they are not using the new column:

EXEC sp_refreshview N'[dbo].[OrganizationCipherDetailsCollectionsView]';
EXEC sp_refreshview N'[dbo].[OrganizationUserOrganizationDetailsView]';
EXEC sp_refreshview N'[dbo].[OrganizationView]';
EXEC sp_refreshview N'[dbo].[ProviderOrganizationOrganizationDetailsView]';
EXEC sp_refreshview N'[dbo].[ProviderUserProviderOrganizationDetailsView]';

[UseAdminSponsoredFamilies] BIT NOT NULL CONSTRAINT [DF_Organization_UseAdminSponsoredFamilies] DEFAULT (0),
[SyncSeats] BIT NOT NULL CONSTRAINT [DF_Organization_SyncSeats] DEFAULT (0),
[UseAutomaticUserConfirmation] BIT NOT NULL CONSTRAINT [DF_Organization_UseAutomaticUserConfirmation] DEFAULT (0),
[UseDisableSMAdsForUsers] BIT NOT NULL CONSTRAINT [DF_Organization_UseDisableSMAdsForUsers] DEFAULT (0),
Copy link
Contributor

Choose a reason for hiding this comment

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

❓ The new column name uses UseDisableSMAdsForUsers with all-caps "SM", which is inconsistent with the established codebase pattern using Pascal case. All existing Secrets Manager columns use "Sm" (capital S, lowercase m):

-- From Organization.sql:
[SmSeats]
[SmServiceAccounts]
[MaxAutoscaleSmSeats]
[MaxAutoscaleSmServiceAccounts]

Should the new field should be UseDisableSmAdsForUsers instead of UseDisableSMAdsForUsers?

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.

5 participants