Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ CONNECTIONSTRINGS__HANGFIRE=<set me>
# ============================================
# Storage Configuration
# ============================================
STORAGE__MINIO__ENDPOINT=<set me>
# Compose service origin; host-run apps use http://localhost:${MINIO_PORT}.
STORAGE__MINIO__ENDPOINT=http://minio:9000
STORAGE__MINIO__ACCESSKEY=<set me>
STORAGE__MINIO__SECRETKEY=<set me>
STORAGE__MINIO__BUCKETNAME=<set me>
STORAGE__MINIO__USESSL=<set me>

# ============================================
# Messaging Configuration
Expand Down
3 changes: 1 addition & 2 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ MINIO_ROOT_PASSWORD=minioadmin
CONNECTIONSTRINGS__PAPERLESSDB=Host=localhost;Port=5432;Database=paperless;Username=postgres;Password=postgres
CONNECTIONSTRINGS__HANGFIRE=Host=localhost;Port=5432;Database=paperless;Username=postgres;Password=postgres
RABBITMQ__URI=amqp://guest:guest@localhost:5672/
STORAGE__MINIO__ENDPOINT=localhost:9000
STORAGE__MINIO__ENDPOINT=http://localhost:9000
STORAGE__MINIO__ACCESSKEY=minioadmin
STORAGE__MINIO__SECRETKEY=minioadmin
STORAGE__MINIO__BUCKETNAME=paperless-test
STORAGE__MINIO__USESSL=false
ELASTICSEARCH__URI=http://localhost:9200
ELASTICSEARCH__DEFAULTINDEX=paperless-test

Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Coverage uploads to https://codecov.io/gh/ANcpLua/Paperless via tokenless OIDC.

Coverage uses `DotCov.Nuke` (NuGet, owner `ANcpLua/dotcov`) as a NUKE component package — `Pipeline/Build.csproj:29` references it, `Pipeline/Build.cs:43` mixes the `ICoverageReport` interface into the build class. There is no `dotnet tool` CLI; the gate runs via `./build.sh ReportCoverage`. Two parameters matter on this repo:

- `--coverage-exclude-generated-param true` (the NUKE [Parameter] kebab-cased form of `--exclude-generated`) strips generators, migrations, designer files, async state-machine sequence points, `Program.cs`. With this flag, the gate metric is **99.8% line coverage (928/930)** — see the sequence-point note in Gotchas. Disable by passing `false` to see the raw numbers (currently ~73% with generated code mixed in).
- `--coverage-exclude-generated-param true` (the NUKE [Parameter] kebab-cased form of `--exclude-generated`) strips generators, migrations, designer files, async state-machine sequence points, `Program.cs`. With this flag, the gate metric is **99.9% line coverage (1359/1361)** — see the sequence-point note in Gotchas. Disable by passing `false` to see the raw numbers (currently 66.5% with generated code mixed in).
- `--coverage-min-line` / `--coverage-min-branch` set the gate threshold. CI passes `0 / 0` (report-only mode); per-file numbers and the overall summary still publish to the workflow log as markdown. Codecov-side gating is configured in `codecov.yml` (project: auto, patch: 80%).

## NUKE Cohesion (build code quality bar)
Expand Down Expand Up @@ -100,7 +100,7 @@ Anti-patterns that fail the self-check:
- **BackgroundService race in tests**: `BackgroundService.StartAsync` returns before `ExecuteAsync` runs. Don't wait on a log predicate that's already true for an empty snapshot (`_ => true`). Signal via `TaskCompletionSource` from a mock's `DisposeAsync` or `AckAsync`, then await that.
- **Hangfire NU1107**: Hangfire + Hangfire.AspNetCore must move together. Renovate split them once and broke restore on `main` for days.
- **Gemini placeholder key**: `.env.test` ships `GEMINI__APIKEY=test-gemini-key-placeholder`. The integration test must mock `ITextSummarizer` (`FakeTextSummarizer` in `PaperlessServices.Tests/Integration/`), not hit the real API.
- **The "missing 2 lines" of coverage are sequence-point artifacts, not testable code**. Gate metric is 928/930 = 99.8%. The two unhit lines are the closing braces of try/catch blocks in `GenAiResultListener.cs` and `ReportProcessor.cs:120` — Roslyn emits a sequence point on the fall-through-after-catch path, but every code path inside those try blocks either `return`s early or unwinds via exception. No test can reach those sequence points without breaking the design intent. Leave them; do not chase 100% by restructuring around the coverage tool.
- **The "missing 2 lines" of coverage are sequence-point artifacts, not testable code**. Gate metric is 1359/1361 = 99.9%. The two unhit lines are the closing braces at `GenAiResultListener.cs:34` and `ReportProcessor.cs:114` — Roslyn emits sequence points on fall-through-after-catch paths that the methods cannot take. No test can reach those sequence points without breaking the design intent. Leave them; do not chase 100% by restructuring around the coverage tool.
- **Custom SDK in Dockerfiles**: PaperlessREST.csproj uses `<Project Sdk="ANcpLua.NET.Sdk.Web">` (version pinned in `global.json` msbuild-sdks). For docker builds, `global.json` + `nuget.config` + `Directory.Packages.props` + `Version.props` must be COPYed into the build context BEFORE `dotnet restore`, otherwise the SDK resolver errors with "Could not resolve SDK". Both Dockerfiles do this; if you copy a Dockerfile for a new project, preserve those COPY lines.

## Rating-Matrix mapping (course grading)
Expand Down
10 changes: 3 additions & 7 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,11 @@
<PackageVersion Include="Scalar.AspNetCore" Version="$(ScalarAspNetCoreVersion)" />
<PackageVersion Include="SWEN3.Paperless.RabbitMq" Version="$(SwenPaperlessRabbitMqVersion)" />

<!-- Transitive security overrides: close GHSA-g4vj-cjjj-v7hg (NuGet.Packaging 6.12.1
pulled by Nuke.Common), GHSA-37gx-xxp4-5rgx / GHSA-w3x6-4m5h-cxqf
(System.Security.Cryptography.Xml 9.0.0), and GHSA-v5pm-xwqc-g5wc
(Microsoft.OpenApi 2.0.0 pulled by Microsoft.AspNetCore.OpenApi 10.0.8;
2.7.5 is the first patched 2.x release). Effective because the SDK turns on
CentralPackageTransitivePinningEnabled. -->
<!-- Security pins for vulnerable transitive packages pulled by the framework and build tool.
CentralPackageTransitivePinningEnabled makes these the resolved versions. -->
<PackageVersion Include="Microsoft.OpenApi" Version="2.7.5" />
<PackageVersion Include="NuGet.Packaging" Version="7.6.0" />
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.9" />
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.10" />
</ItemGroup>

</Project>
19 changes: 2 additions & 17 deletions Paperless.TestSupport/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
// Test infrastructure is not product code, so it is not measured.
//
// Coverage answers "did the tests exercise this line". Asking that of the fixtures
// the tests are built from is circular: every helper the suites touch reports as
// covered by construction, and the only thing a number here can reveal is a dead
// helper — which an unused-symbol warning already tells us, more directly.
//
// Left measured it also distorts the gate. These 468 lines sat in the same
// aggregate as PaperlessREST and PaperlessServices, so ContainerFixtureBase
// (77.2%) and FakeLoggerExtensions (83.3%) depressed the number that decides
// whether a push to main passes, while saying nothing about product risk.
//
// This attribute excludes the assembly at collection time, so the raw Cobertura
// never contains it and every downstream consumer — the DotCov gate, Codecov, the
// ReportGenerator HTML — agrees without needing its own rule. The filters in
// Pipeline/Components/ICoverage.cs and codecov.yml still name TestSupport, but as
// a backstop should this attribute ever be dropped, not as the mechanism.
// Shared test infrastructure is not product behavior. Exclude it at collection time so
// local and hosted reports measure PaperlessREST and PaperlessServices consistently.

[assembly: ExcludeFromCodeCoverage]
Loading