Skip to content

Every Dependabot NuGet PR reds on restore: NU1004, because it updates Directory.Packages.props and cannot regenerate the nine packages.lock.json files #3143

Description

@erikdarlingdata

Every Dependabot NuGet PR fails Darling whole-tree guards on restore, before a single test runs, because Dependabot updates Directory.Packages.props and cannot regenerate the packages.lock.json files that go with it.

NU1004: Mismatch between the requestedVersion of a lock file dependency marked as
CentralTransitive and the version specified in the central package management file.
Lock file version [4.0.100.11, ), central package management version [4.0.100.12, ).

NU1004: The packages lock file is inconsistent with the project dependencies so restore
can't be run in locked mode.

Currently red on #3130 and #3131.

dev is consistent — this is created by the change, not present in the tree

Directory.Packages.props Darling.Tests/packages.lock.json
dev AWSSDK.PI 4.0.100.11 [4.0.100.11, ), resolved 4.0.100.11

So the nightly and the release path are unaffected — a nightly built from dev succeeds, and every merge today went 8/8 including that guard. Both Dependabot PRs change exactly one file, Directory.Packages.props, leaving nine lock files pinned to the old version.

Scope, measured

Nine packages.lock.json files, four live and five under deprecated/:

Darling/Darling.Tests            Lite                      deprecated/Dashboard
Darling/PerformanceMonitor.Darling.Viewer   Lite.Tests     deprecated/Dashboard.Tests
                                                           deprecated/Installer
                                                           deprecated/Installer.Core
                                                           deprecated/Installer.Tests

--locked-mode is passed explicitly on eight restore invocations across three jobs (build.yml lines 296–301, 761, 1109). This is not implicit CI behaviour — it is a deliberate choice, made eight times.

Volume is ~1–2 PRs per week, not a flood: Dependabot runs weekly on Mondays with minor and patch grouped into one PR, majors deliberately separate, limit 10. With CPM each bump is one line.

Recommended direction: automate the regeneration. Do NOT relax locked mode.

Relaxing RestoreLockedMode is the tempting option and should be refused. CPM already pins direct versions; the lock files pin the transitive closure, which is the part nobody reviews and the part that can drift into a build shipping to production boxes. Eight explicit flags is a decision. Making Dependabot green by deleting the guarantee inverts it for convenience.

Instead: a workflow on Dependabot PRs that runs dotnet restore --force-evaluate across the nine projects and commits the updated lock files back to the branch. Preserves the guarantee, removes the recurring human step, and is the standard pattern for CPM + lock files + Dependabot in .NET.

One hazard to design around rather than discover: pushing to a PR branch needs write permission, and Dependabot PRs run with a restricted token — so this wants workflow_run or pull_request_target. The latter runs with repo write against PR code, which is a real footgun for fork PRs and bounded here because Dependabot branches are repo-internal. build.yml already documents its own workflow_dispatch recursion guard, so the mechanics are familiar in this repo; follow that precedent for the loop guard.

Rejected alternatives, with reasons:

  • Regenerate manually per PR. Works, mechanical, ~weekly. Rejected as the primary answer because the failure mode is a red PR sitting unnoticed — which is the current state.
  • Relax RestoreLockedMode. Trades a real reproducibility guarantee for convenience.
  • Delete the lock files. Same trade, larger.

Immediate, independent of the long-term fix

Both open PRs need one dotnet restore --force-evaluate and a commit. That unblocks them today whichever direction is chosen.

Acceptance criteria

  • a Dependabot NuGet PR reaches Darling whole-tree guards with restore succeeding, without any --locked-mode flag being removed;
  • the nine lock files stay consistent with Directory.Packages.props on dev;
  • a PR that changes Directory.Packages.props by hand and forgets the lock files still fails — the guarantee must survive the automation, or it has been traded rather than kept.

The third arm is the one that matters: an automation that regenerates unconditionally would make the guard unable to catch a genuine mismatch.

Two observations, not part of this fix

Five of the nine lock files are under deprecated/, and two of them — Installer.Tests, Dashboard.Tests — are restored in locked mode by CI at lines 298–299. Deprecated projects are still gating builds. Possibly worth pruning; a separate decision.

#3131 is a major bump (BlackwellSystems.Gcf 0.2.1 → 1.0.0). The Dependabot config deliberately keeps majors out of the group so a breaking change arrives on its own PR rather than buried in a batch — so that one wants reading on its merits, separately from the lockfile mechanics.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions