Skip to content

[PM-41259] Scaffold PAM cipher-lease endpoints - #8105

Open
Hinton wants to merge 2 commits into
mainfrom
pam/scaffold-cipher-lease
Open

[PM-41259] Scaffold PAM cipher-lease endpoints#8105
Hinton wants to merge 2 commits into
mainfrom
pam/scaffold-cipher-lease

Conversation

@Hinton

@Hinton Hinton commented Jul 31, 2026

Copy link
Copy Markdown
Member

🎟️ Tracking

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

📔 Objective

Adds the /leases/ciphers/{id} Minimal API group (pre-check, state, submit) with an intentionally unimplemented handler, following the access-rule, access-request, and lease scaffolds.

The four new response/request DTOs (AccessPreCheckResponseModel, CipherAccessStateResponseModel, AccessRequestResponseModel, AccessRequestResultResponseModel, AccessRequestCreateRequestModel) and the wire-only AccessApprovalMode enum carry the wire contract without coupling to the (not-yet-landed) PAM domain. Contract tests lock the routes, names, methods, and return types the generated spec is built from.

Adds the /leases/ciphers/{id} Minimal API group (pre-check, state, submit)
with an intentionally unimplemented handler, following the access-rule,
access-request, and lease scaffolds. Contract tests lock the routes, names,
methods, and return types the generated spec is built from.
Comment thread bitwarden_license/src/Services/Pam/Api/Models/AccessApprovalMode.cs Outdated
No coupling to unlanded PAM domain code to avoid: it's a standalone byte
enum. Land it directly instead of duplicating a wire-only copy under
Api/Models like the other scaffold enums.
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 24.52830% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.81%. Comparing base (8589031) to head (a283ddb).

Files with missing lines Patch % Lines
.../Api/Models/Response/AccessRequestResponseModel.cs 0.00% 12 Missing ⚠️
.../Models/Response/CipherAccessStateResponseModel.cs 0.00% 9 Missing ⚠️
...Api/Models/Response/AccessPreCheckResponseModel.cs 0.00% 6 Missing ⚠️
...odels/Response/AccessRequestResultResponseModel.cs 0.00% 5 Missing ⚠️
.../Models/Request/AccessRequestCreateRequestModel.cs 0.00% 4 Missing ⚠️
.../Endpoints/Handlers/CipherLeaseEndpointsHandler.cs 0.00% 3 Missing ⚠️
...Services/Pam/Api/Endpoints/CipherLeaseEndpoints.cs 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8105      +/-   ##
==========================================
- Coverage   62.83%   62.81%   -0.03%     
==========================================
  Files        2299     2306       +7     
  Lines      100138   100191      +53     
  Branches     9012     9012              
==========================================
+ Hits        62923    62935      +12     
- Misses      35030    35071      +41     
  Partials     2185     2185              

☔ View full report in Codecov by Harness.
📢 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.

@Hinton Hinton added the t:feature Change Type - Feature Development label Jul 31, 2026
@Hinton
Hinton marked this pull request as ready for review July 31, 2026 11:07
@Hinton
Hinton requested a review from a team as a code owner July 31, 2026 11:07
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the new /leases/ciphers/{id} Minimal API group (pre-check, state, submit), its unimplemented handler, the five new request/response DTOs, the AccessApprovalMode enum, DI registration, and the contract tests. The group picks up the shared PAM chain (Policies.Application authorization, exception → ErrorResponseModel translation, the Pam feature gate, and model validation) via WithPamDefaults, and the new routes do not collide with the existing /leases/{id:guid}/… patterns. Handler stubs throwing NotImplementedException surface as a generic 500 through PamExceptionHandlerEndpointFilter, with details only in Development, so no sensitive data is exposed. The contract tests mirror the existing lease/access-request/access-rule test shape and lock routes, names, methods, and return types.

Code Review Details
  • ❓ : Second access-request wire shape duplicates AccessRequestDetailsResponseModel field-for-field, giving clients two generated types for the same entity
    • bitwarden_license/src/Services/Pam/Api/Models/Response/AccessRequestResponseModel.cs:9

/// An access request as its requester sees it right after submit — the shape <see cref="AccessRequestResultResponseModel"/>
/// wraps for the cipher-lease submit response.
/// </summary>
public class AccessRequestResponseModel : ResponseModel

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

QUESTION: Is the second access-request wire shape intentional, rather than reusing AccessRequestDetailsResponseModel?

Details

All nine members here (Id, CipherId, CollectionId, OrganizationId, Status, LeaseNotBefore, LeaseNotAfter, Reason, SubmittedAt) are name-, type-, and doc-identical to AccessRequestDetailsResponseModel, so this is a strict subset with a different object discriminator (accessRequest vs accessRequestDetails).

The practical effect on the generated spec: within this same group, GET leases/ciphers/{id}/state hands back AccessRequestDetailsResponseModel (via PendingRequest/ApprovedRequest) while POST leases/ciphers/{id} hands back this one, so clients get two generated types for the same entity and can't pass one where the other is expected. Since these DTOs are what client bindings are generated from, collapsing them later is a breaking change.

If the narrower shape is deliberate (e.g. deliberately withholding decision history at submit), a one-line note in the class doc would keep the next person from "fixing" it. Otherwise AccessRequestResultResponseModel.Request could point at AccessRequestDetailsResponseModel and this type would go away.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:feature Change Type - Feature Development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant