Altinn.Dd.Tests.SonarGate
2.1.0
dotnet add package Altinn.Dd.Tests.SonarGate --version 2.1.0
NuGet\Install-Package Altinn.Dd.Tests.SonarGate -Version 2.1.0
<PackageReference Include="Altinn.Dd.Tests.SonarGate" Version="2.1.0" />
<PackageVersion Include="Altinn.Dd.Tests.SonarGate" Version="2.1.0" />
<PackageReference Include="Altinn.Dd.Tests.SonarGate" />
paket add Altinn.Dd.Tests.SonarGate --version 2.1.0
#r "nuget: Altinn.Dd.Tests.SonarGate, 2.1.0"
#:package Altinn.Dd.Tests.SonarGate@2.1.0
#addin nuget:?package=Altinn.Dd.Tests.SonarGate&version=2.1.0
#tool nuget:?package=Altinn.Dd.Tests.SonarGate&version=2.1.0
Altinn.Dd.Tests.SonarGate
Shared SonarQube quality-gate test runner for the Digitalt Dødsbo programme.
This repository publishes two packages.
src/holds them,src/Shared/holds plumbing compiled into both,tests/holds the tests, anddd-qa.slnxat the root ties them together. The shared code is not a package: nothing in it appears in either gate's public API, so publishing it would add a dependency to every consumer and a public contract to maintain, for code no consumer can call. The other gate is Altinn.Dd.Tests.DependencyGate, which audits a repo's NuGet dependencies for known advisories. They are independent: a repo can take either or both, and DependencyGate deliberately carries none of the Testcontainers/Docker tree so it is cheap to add to a repo that has no SonarQube test. Both are released by theRelease Packageworkflow, which takes the package name as a dispatch input.
Spins up SonarQube via Testcontainers, scans a target
.NET project, optionally collects coverage from a test project, asserts the quality gate returns
OK, writes a per-run JSON snapshot to the consumer's QaTests/history/, and archives that
snapshot to a private Azure Blob container. The cross-project dashboard is rendered separately by
the oed-admin app from these snapshots.
Usage
using Altinn.Dd.Tests.SonarGate;
using Xunit;
using Xunit.Abstractions;
public class MyProjectSonarGateTests(ITestOutputHelper output)
{
[SkippableFact, Trait("Category", "qa")]
public Task QualityGate_ReturnsOk() => SonarGate.RunAsync(new()
{
ProjectKey = "my-project",
ScanCsprojRelativePath = "MyProject/MyProject.csproj",
Coverage = new()
{
TestCsprojRelativePath = "MyProject.Tests/MyProject.Tests.csproj",
Excludes = ["[xunit.*]*", "[MyProject.Tests]*"],
},
}, output);
}
Set QATESTS=1 to opt in (a plain dotnet test skips). Docker must be reachable for the
SonarQube TestContainer.
Publish target
Per run, the package archives the snapshot JSON + regenerated summary.md to an Azure Blob
container under {ProjectKey}/history/. Append-only history — every run becomes a new blob, nothing
is overwritten or deleted. The container is private (AAD/SAS-authenticated reads only). The
cross-project dashboard is rendered separately by the oed-admin app, which reads these snapshots.
Defaults:
| Setting | Default value | Override via |
|---|---|---|
BlobStorageAccount |
oedqa |
SonarGateOptions.BlobStorageAccount |
BlobContainer |
reports |
SonarGateOptions.BlobContainer |
The reports container is private. The QA dashboard is rendered from these snapshots inside the
oed-admin app (its backend reads the container via managed identity); there is no public endpoint.
Publish failures are caught and logged but never fail the test. The SonarQube quality gate is the source of truth.
Consumer dependencies
Altinn.Dd.Tests.SonarGate(this package)xunit+xunit.runner.visualstudio— the test frameworkXunit.SkippableFact— pulled in transitively for the[SkippableFact]attribute
Targets net10.0.
SAS token
The Altinn.Dd.Tests.SonarGate package authenticates against the oedqa storage account with a SAS token.
This token must be present in a repository secret named AZURE_STORAGE_SAS_TOKEN for the consuming pipeline.
When the token expires you can regenerate it by performing the following steps:
Step 1 — Get the storage account key
The SAS is signed by the storage account's primary key.
Login in your shell using az login and choose the Altinn-DIGDIR-Test subscription.
Assign the secret to local variable $ACCOUNT_KEY:
$ACCOUNT_KEY = az storage account keys list `
--account-name oedqa `
--query '[0].value' -o tsv
Step 2 — Generate an account-scoped SAS
The token must cover both the private reports container (history) and the $web
static-website container (dashboard), so it's an account SAS rather than a single-container one:
az storage account generate-sas `
--account-name oedqa `
--services b `
--resource-types co `
--permissions rwl `
--expiry 2027-06-02 `
--https-only `
--account-key "$ACCOUNT_KEY" `
-o tsv
--services b/--resource-types co— Blob service, Container + Object level, so the single token reaches every container (reportsand$web).--permissions rwl— read (dashboard regen), write (snapshot +$webuploads), list (find latest snapshot per project). Deliberately nod: a leaked SAS can overwrite, but can't tombstone.--expiry— pick something you can plausibly remember to rotate. 1–2 years balances rotation pain against hygiene.--https-only— refuses plain HTTP. Always on.
Output is a single line starting with sv=…. Treat it as a credential — don't paste it into
chat, tickets, or commits.
Step 3 — Store as a GitHub Actions secret
In each consumer repo:
Settings → Secrets and variables → Actions → Secrets → New repository secret
- Name:
AZURE_STORAGE_SAS_TOKEN - Value: paste the SAS from step 2. Leading
?is optional —BlobAuthtolerates both forms.
Put it under Secrets, not Variables — the SAS is sensitive, and GitHub auto-masks values
pulled from secrets.* in workflow logs.
The workflow's test step picks the SAS up via:
- name: Run QA tests
env:
AZURE_STORAGE_SAS_TOKEN: ${{ secrets.AZURE_STORAGE_SAS_TOKEN }}
run: dotnet test QaTests --no-restore --verbosity normal
The test step is the whole job — the runner archives history to reports and publishes the
dashboard to $web in-process. No separate deploy step or hosting token is needed.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Azure.Identity (>= 1.13.0)
- Azure.Storage.Blobs (>= 12.22.2)
- Testcontainers (>= 4.14.0)
- xunit.abstractions (>= 2.0.3)
- Xunit.SkippableFact (>= 1.4.13)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.1.0 | 745 | 8/31/2026 |
| 2.0.1 | 327 | 8/26/2026 |
| 2.0.0 | 254 | 8/20/2026 |
| 1.0.0 | 268 | 6/23/2026 |
| 0.15.0 | 838 | 6/11/2026 |
| 0.14.0 | 445 | 6/10/2026 |
| 0.13.0 | 218 | 6/5/2026 |
| 0.12.0 | 155 | 6/4/2026 |
| 0.11.0 | 150 | 6/4/2026 |
| 0.10.0 | 143 | 6/4/2026 |
| 0.9.1 | 126 | 6/4/2026 |
| 0.9.0 | 168 | 6/4/2026 |
| 0.8.0 | 129 | 6/3/2026 |
| 0.7.0 | 121 | 6/3/2026 |
| 0.6.0 | 131 | 6/3/2026 |
| 0.5.0 | 138 | 6/2/2026 |
| 0.4.0 | 138 | 6/1/2026 |
| 0.3.1 | 120 | 6/1/2026 |
| 0.3.0 | 169 | 5/29/2026 |
| 0.2.0 | 120 | 5/29/2026 |