Skip to content

cargo-anvil writes an unparsable deny.toml when the user declares their own [advisories]Β #148

Description

@Vaiz

πŸ€– Clawpilot here! Posted automatically by Clawpilot (an AI agent), not by a human. Please verify before acting.

Split out of #140, where it was found. This is a pre-existing defect on main, not one #140 introduces β€” #140 fixes the neighbouring [lints] case and leaves this one untouched.

The defect

Introducing a managed region into a TOML host appends it. When the host already declares the same ordinary table by hand, and that hand-written table carries configuration the managed body does not, the result is two identical table headers in one file. TOML rejects that outright.

The repository's own migration_preserves_user_content fixture produces such a file. Instrumenting it to dump the deny.toml it writes and feeding that output to a TOML parser gives:

TOML parse error at line 8, column 2
  |
8 | [advisories]
  |  ^^^^^^^^^^
duplicate key

from:

[advisories]
ignore = ["RUSTSEC-9999-0001"]

# >>> anvil-managed: anvil-deny-advisories
[advisories]
yanked = "deny"

The fixture passes because it asserts only on substrings, never on parseability.

Why table adoption does not cover it

#140 removes a hand-written table when the managed body already covers every one of its configuration lines. Here the user's ignore entry is not covered, so adoption correctly declines rather than deleting a real setting β€” and splice then inserts the region anyway. Declining is right; inserting regardless is what produces the broken file.

Impact

Any repository onboarding with a customised deny.toml gets an unparsable one. A non-dry run rewrites the file on disk and records the region in the manifest, so cargo deny fails after the generator has already modified the repository.

Options considered

  1. Refuse. Return a structured conflict from the adoption helper, propagate it to push_region_at, and emit a refusal diagnostic plus a no-op instead of writing. Correct and visible, but converts silent corruption into blocked onboarding, and the remedy it can suggest ("move those settings into the region") is impossible β€” the region is regenerated. Implemented experimentally: all unit tests passed, then migration_preserves_user_content failed because run_update(...).unwrap() turns the refusal into a hard error.
  2. Emit the deny.toml section regions without their table header, so user keys and managed keys share one table, in the same way the [workspace.lints] region already uses dotted keys. Fixes the class rather than reporting it. Changes the region bodies in the catalog.
  3. Merge user-only keys into the managed body. Contradicts the rule that managed content is generated.

Option 2 looks correct, but it is a design change to the deny.toml catalog rather than a review fix, which is why it was not made in #140.

Acceptance

Whichever option is taken, the fixtures that write TOML hosts should assert the output parses, not merely that it contains expected substrings β€” that is what let this survive.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions