Skip to content

Commit 397278d

Browse files
committed
Merge branch 'main' into ios/PM-23500/sourcery-usage
2 parents 43eb39e + 4232839 commit 397278d

File tree

17 files changed

+346
-177
lines changed

17 files changed

+346
-177
lines changed

.github/workflows/scan.yml

Lines changed: 15 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
pull_request:
99
types: [opened, synchronize, reopened]
1010
branches-ignore:
11-
- main
11+
- "main"
1212
pull_request_target:
1313
types: [opened, synchronize, reopened]
1414
branches:
@@ -24,68 +24,28 @@ jobs:
2424
contents: read
2525

2626
sast:
27-
name: SAST scan
28-
runs-on: ubuntu-22.04
27+
name: Checkmarx
28+
uses: bitwarden/gh-actions/.github/workflows/_checkmarx.yml@main
2929
needs: check-run
30+
secrets:
31+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
32+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
33+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
3034
permissions:
3135
contents: read
3236
pull-requests: write
3337
security-events: write
34-
35-
steps:
36-
- name: Check out repo
37-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
38-
with:
39-
ref: ${{ github.event.pull_request.head.sha }}
40-
41-
- name: Scan with Checkmarx
42-
uses: checkmarx/ast-github-action@ef93013c95adc60160bc22060875e90800d3ecfc # 2.3.19
43-
env:
44-
INCREMENTAL:
45-
"${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
46-
with:
47-
project_name: ${{ github.repository }}
48-
cx_tenant: ${{ secrets.CHECKMARX_TENANT }}
49-
base_uri: https://ast.checkmarx.net/
50-
cx_client_id: ${{ secrets.CHECKMARX_CLIENT_ID }}
51-
cx_client_secret: ${{ secrets.CHECKMARX_SECRET }}
52-
additional_params: |
53-
--report-format sarif \
54-
--filter "state=TO_VERIFY;PROPOSED_NOT_EXPLOITABLE;CONFIRMED;URGENT" \
55-
--output-path . ${{ env.INCREMENTAL }}
56-
57-
- name: Upload Checkmarx results to GitHub
58-
uses: github/codeql-action/upload-sarif@ce28f5bb42b7a9f2c824e633a3f6ee835bab6858 # v3.29.0
59-
with:
60-
sarif_file: cx_result.sarif
61-
sha:
62-
${{ contains(github.event_name, 'pull_request') && github.event.pull_request.head.sha ||
63-
github.sha }}
64-
ref:
65-
${{ contains(github.event_name, 'pull_request') && format('refs/pull/{0}/head',
66-
github.event.pull_request.number) || github.ref }}
38+
id-token: write
6739

6840
quality:
69-
name: Quality scan
70-
runs-on: ubuntu-22.04
41+
name: Sonar
42+
uses: bitwarden/gh-actions/.github/workflows/_sonar.yml@main
7143
needs: check-run
44+
secrets:
45+
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
46+
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
47+
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
7248
permissions:
7349
contents: read
7450
pull-requests: write
75-
76-
steps:
77-
- name: Check out repo
78-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
79-
with:
80-
fetch-depth: 0
81-
ref: ${{ github.event.pull_request.head.sha }}
82-
83-
- name: Scan with SonarCloud
84-
uses: sonarsource/sonarqube-scan-action@2500896589ef8f7247069a56136f8dc177c27ccf # v5.2.0
85-
env:
86-
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
87-
with:
88-
args: >
89-
-Dsonar.organization=${{ github.repository_owner }} -Dsonar.projectKey=${{
90-
github.repository_owner }}_${{ github.event.repository.name }}
91-
-Dsonar.pullrequest.key=${{ github.event.pull_request.number }}
51+
id-token: write

custom-words.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ recompositions
6161
refactorings
6262
roadmap
6363
roadmaps
64+
rollout
65+
rollouts
6466
rustup
6567
sandboxed
6668
SARIF
@@ -85,6 +87,7 @@ typechecks
8587
typesafe
8688
WCAG
8789
Xcodes.app
90+
xcworkspace
8891
xmldoc
8992
Yellowpages
9093
Yubico

docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
adr: "0026"
3-
status: "Proposed"
3+
status: "Accepted"
44
date: 2025-05-30
55
tags: [server]
66
---
@@ -120,7 +120,7 @@ as they are expected to always be included in the host -- those services are `IL
120120

121121
## Decision Outcome
122122

123-
Chosen option: **Encourage usage**.
123+
Chosen option: **Enforce usage**.
124124

125125
### Positive Consequences
126126

@@ -136,10 +136,10 @@ Chosen option: **Encourage usage**.
136136

137137
### Plan
138138

139-
The plan to encourage the usage will be to update our C# style guide with the recommendation to
140-
begin using the `TryAdd` overloads (the document should explain when you want to use each one). The
141-
coding guidelines can be part of a newly-added document about general dependency injection
142-
guidelines for .NET here at Bitwarden.
139+
Enforcing usage through the `Microsoft.CodeAnalysis.BannedApiAnalyzers` NuGet package, we will tone
140+
down the diagnostic from the banned APIs to be warnings instead of errors. We will have the warning
141+
include custom diagnostic text to point to a new section in the C# style guide with the instructions
142+
on how to migrate.
143143

144144
A one-time recorded learning session will also be hosted; the session will go over the new docs,
145145
show off migrating existing service registrations to using the `TryAdd` overloads, and host a QnA.

docs/contributing/code-style/csharp.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,46 @@ For example you might have an assertion like `Debug.Assert(user.IsVerified)` in
130130
that only expects verified users. `Debug.Assert` works by using one of the aforementioned attributes
131131
`[DoesNotReturnIf(false)]` to make it work in case you want to implement your own assertion.
132132

133+
## Dependency Injection
134+
135+
### Use `TryAdd*` overloads on `IServiceCollection`
136+
137+
Use [`TryAdd*` overloads][tryadd-overloads] as opposed to the less clear versions like
138+
`AddSingleton` and `AddKeyedTransient`. If you want to use your service using multi-inject then you
139+
should use the `TryAddEnumerable` method along with the static factory methods on
140+
`ServiceDescriptor` to register your service. This has the benefit of allowing your services to be
141+
registered many times during startup and not polluting the collection with duplicates that either
142+
won't ever be used or might accidentally be used if someone wants to inject multiple of that service
143+
type.
144+
145+
Single inject scenario:
146+
147+
```csharp
148+
// ❌ Don't do this
149+
services.AddSingleton<IMyService, DefaultMyService>();
150+
// ✅ Do this instead
151+
services.TryAddSingleton<IMyService, DefaultMyService>();
152+
```
153+
154+
Multi-inject scenario:
155+
156+
```csharp
157+
// ❌ Don't do this
158+
services.AddKeyedTransient<IMyService, FirstMyService>("first");
159+
// ✅ Do this instead
160+
services.TryAddEnumerable(ServiceDescriptor.KeyedTransient<IMyService, FirstMyService>("first"));
161+
```
162+
163+
In multi-inject scenarios you are especially in danger of adding the same implementation multiple
164+
times and having them all be used.
165+
166+
### Dependency Groups
167+
168+
Consider creating [dependency groups][dependency-groups]. This gives other teams a nice interface to
169+
register your group when they depend on it. If you've used
170+
[`TryAdd`](#use-tryadd-overloads-on-iservicecollection) overloads it won't matter how many times
171+
your group of services is added to the collection.
172+
133173
[null-forgiving]:
134174
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving
135175
[null-state-attributes]:
@@ -138,3 +178,7 @@ that only expects verified users. `Debug.Assert` works by using one of the afore
138178
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-9.0#non-nullable-reference-types-and-required-attribute
139179
[debug-assert]:
140180
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.debug.assert?view=net-9.0
181+
[tryadd-overloads]:
182+
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.extensions.servicecollectiondescriptorextensions?view=net-9.0-pp
183+
[dependency-groups]:
184+
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-9.0#register-groups-of-services-with-extension-methods
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
label: "Database Migrations"
2+
position: 2

docs/contributing/database-migrations/edd.mdx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
15
import Tabs from "@theme/Tabs";
26
import TabItem from "@theme/TabItem";
37

@@ -130,6 +134,8 @@ actions.
130134
<Tabs>
131135
<TabItem value="first" label="Initial Migration" default>
132136

137+
Located in `util/Migrator/DbScripts`.
138+
133139
```sql
134140
-- Add Column
135141
IF COL_LENGTH('[dbo].[Customer]', 'FirstName') IS NULL
@@ -177,6 +183,8 @@ END
177183
</TabItem>
178184
<TabItem value="data" label="Transition Migration">
179185

186+
Located in `util/Migrator/DbScripts_transition`.
187+
180188
```sql
181189
UPDATE [dbo].Customer SET
182190
FirstName=FName
@@ -186,6 +194,8 @@ WHERE FirstName IS NULL
186194
</TabItem>
187195
<TabItem value="second" label="Finalization Migration">
188196

197+
Located in `util/Migrator/DbScripts_finalization`.
198+
189199
```sql
190200
-- Remove Column
191201
IF COL_LENGTH('[dbo].[Customer]', 'FName') IS NOT NULL
@@ -239,7 +249,7 @@ There are some important constraints to the implementation of the process:
239249

240250
The process to support all of these constraints is a complex one. Below is an image of a state
241251
machine that will hopefully help visualize the process and what it supports. It assumes that all
242-
database changes follow the standards that are laid out in [Migrations](./).
252+
database changes follow the standards that are laid out in [Migrations](./mssql.md).
243253

244254
---
245255

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
sidebar_position: 2
3+
---
4+
5+
# Entity Framework
6+
7+
:::info
8+
9+
For instructions on how to apply database migrations, please refer to the
10+
[Getting Started](../../getting-started/server/database/ef/index.mdx#updating-the-database)
11+
documentation.
12+
13+
:::
14+
15+
If you alter the database schema, you must create an EF migration script to ensure that EF databases
16+
keep pace with these changes. Developers must do this and include the migrations with their PR.
17+
18+
To create these scripts, you must first update your data model in `Core/Entities` as desired. This
19+
will be used to generate the migrations for each of our EF targets. Additionally, for table changes
20+
it is strongly recommended to define or update an `IEntityTypeConfiguration<T>` to accurately
21+
represent any constraints needed on the data model.
22+
23+
Once the model is updated, navigate to the `dev` directory in the `server` repo and execute the
24+
`ef_migrate.ps1` PowerShell command. You should provide a name for the migration as the only
25+
parameter:
26+
27+
```bash
28+
pwsh ef_migrate.ps1 [NAME_OF_MIGRATION]
29+
```
30+
31+
This will generate the migrations, which should then be included in your PR.

docs/contributing/database-migrations/index.md

Lines changed: 0 additions & 104 deletions
This file was deleted.

0 commit comments

Comments
 (0)