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

[PM-18235] Add PersonalOwnershipPolicyRequirement #5439

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

r-tome
Copy link
Contributor

@r-tome r-tome commented Feb 24, 2025

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-18235

📔 Objective

Implement PersonalOwnershipPolicyRequirement and use it on code checking if the "Remove individual vault" applies to the user.

This standardizes policy enforcement by following our established PolicyRequirement pattern, ensuring consistent handling of role/status exemptions.

⏰ 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

…nt if the PolicyRequirements flag is enabled

Update unit tests
…th feature flag

- Add support for checking personal ownership policy using PolicyRequirementQuery when feature flag is enabled
- Update CipherService constructor to inject new dependencies
- Add tests for personal vault restrictions with and without feature flag
Copy link
Contributor

github-actions bot commented Feb 24, 2025

Logo
Checkmarx One – Scan Summary & Detailsb2b82dcb-9d30-4fcc-8591-0e884c9c697f

New Issues (3)

Checkmarx found the following issues in this Pull Request

Severity Issue Source File / Package Checkmarx Insight
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 143
detailsMethod Post at line 143 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flow...
Attack Vector
MEDIUM CSRF /src/Api/Controllers/CollectionsController.cs: 171
detailsMethod Put at line 171 of /src/Api/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value flows...
Attack Vector
MEDIUM CSRF /src/Api/Public/Controllers/CollectionsController.cs: 87
detailsMethod Put at line 87 of /src/Api/Public/Controllers/CollectionsController.cs gets a parameter from a user request from model. This parameter value...
Attack Vector
Fixed Issues (16)

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

Severity Issue Source File / Package
MEDIUM CSRF /src/Billing/Controllers/PayPalController.cs: 70
MEDIUM CSRF /src/Api/AdminConsole/Controllers/GroupsController.cs: 164
MEDIUM CSRF /src/Api/AdminConsole/Public/Controllers/GroupsController.cs: 133
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 94
MEDIUM CSRF /bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs: 104
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70
LOW Log_Forging /src/Billing/Controllers/PayPalController.cs: 70

@r-tome r-tome marked this pull request as ready for review February 24, 2025 16:17
@r-tome r-tome requested review from a team as code owners February 24, 2025 16:17
Copy link

codecov bot commented Feb 24, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 44.56%. Comparing base (492a3d6) to head (99e4e06).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5439      +/-   ##
==========================================
+ Coverage   44.52%   44.56%   +0.03%     
==========================================
  Files        1514     1515       +1     
  Lines       70403    70429      +26     
  Branches     6352     6355       +3     
==========================================
+ Hits        31347    31385      +38     
+ Misses      37708    37695      -13     
- Partials     1348     1349       +1     

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

@@ -26,7 +29,8 @@ public class ImportCiphersCommand : IImportCiphersCommand
private readonly ICollectionRepository _collectionRepository;
private readonly IReferenceEventService _referenceEventService;
private readonly ICurrentContext _currentContext;

private readonly IPolicyRequirementQuery _policyRequirementQuery;
private readonly IFeatureService _featureService;

public ImportCiphersCommand(
Copy link
Member

Choose a reason for hiding this comment

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

🌱 This constructor now has 10 dependencies. That's a good indication that this code is doing too much and a refactoring is in order.

❓ What would you recommend changing if you could? Dream big!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Excellent observation! I think an easy thing to do would be to separate the individual vault import and the org vault import each into its own command. From there we could extract the validation logic into a validation class.

Copy link
Member

Choose a reason for hiding this comment

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

@djsmith85 ☝🏻

@r-tome r-tome requested a review from audreyality February 25, 2025 15:29
audreyality
audreyality previously approved these changes Feb 25, 2025
@@ -139,8 +147,11 @@ public async Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId, Date
else
{
// Make sure the user can save new ciphers to their personal vault
var anyPersonalOwnershipPolicies = await _policyService.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership);
if (anyPersonalOwnershipPolicies)
var isPersonalVaultRestricted = _featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not a blocker since it can be considered a personal preference, but I think ternary statements are difficult to read when they are used for more than assigning simple values; when multiple steps are involved, they become hard to follow.

I would suggest abstracting this out into a function and using the early return pattern with if statements. Maybe something like this.

Calling area

 if (await IsPersonalVaultRestricted(savingUserId))
  {
      throw new BadRequestException("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.");
  }

Function

    public async Task<bool> IsPersonalVaultRestricted(Guid savingUserId)
    {
        if (_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements))
        {
            var policy = await _policyRequirementQuery.GetAsync<PersonalOwnershipPolicyRequirement>(savingUserId);
            return policy.DisablePersonalOwnership;
        }

        return await _policyService.AnyPoliciesApplicableToUserAsync(savingUserId, PolicyType.PersonalOwnership);
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Normally I would agree but this ternary is temporary - it will only exist while the PolicyRequirements feature flag exists. When we eventually remove that feature flag and only use PersonalOwnershipPolicyRequirement to check this then the private method doesn't make sense anymore because it will be a one liner. Having this a ternary makes it simpler to replace in the future.

@@ -139,8 +147,11 @@ public async Task SaveDetailsAsync(CipherDetails cipher, Guid savingUserId, Date
else
{
// Make sure the user can save new ciphers to their personal vault
Copy link
Contributor

Choose a reason for hiding this comment

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

Non-blocker: I know it's not part of your scope, but can we replace this comment with a meaningful variable name? I think your variable IsPersonalVaultRestricted is a good option.

{
[Theory, AutoData]
public void DisablePersonalOwnership_IsFalse_IfNoPersonalOwnershipPolicies(
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we should follow the should-when naming pattern for consistency?

Consider: DisablePersonalOwnership_ShouldNotBeEnforced_WhenNoPersonalOwnershipPoliciesExist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have renamed them to follow my usual pattern of <MethodName>_<WithSomething>_<ExpectedResult>

}

[Theory, AutoData]
public void DisablePersonalOwnership_Not_EnforcedAgainstProviders(
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using this name or something similar: DisablePersonalOwnership_ShouldNotBeEnforced_WhenUserIsAProvider.

Copy link
Contributor

@JimmyVo16 JimmyVo16 left a comment

Choose a reason for hiding this comment

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

I have some minor feedback and questions, but it's pretty much approved

…rity

- Improve test method names to better describe their purpose and behavior
- Rename methods to follow a more descriptive naming convention
- No functional changes to the test logic
@r-tome r-tome requested a review from JimmyVo16 February 26, 2025 11:17
@r-tome
Copy link
Contributor Author

r-tome commented Feb 26, 2025

@JimmyVo16 thanks for the review! I've addressed your comments, let me know if you want to discuss anything further

@r-tome r-tome marked this pull request as draft February 26, 2025 11:42
@r-tome
Copy link
Contributor Author

r-tome commented Feb 26, 2025

Putting this back in draft as it'll require a refactor with the eventual changes from #5445

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.

3 participants