Otoh, the closest version with the fix might not be compatible.
I'd vouch for the fix anyways, b/c I'd find it surprising if this tool upgrades to a version that doesn't actually fix the vulnerability. Maybe thow out a warning when semver says it's not compatible, though
...the further one gets away from a version in use the higher the chance of a build fail or other issue...
That does not imply a zero chance of the nearest version that fixes the vulnerability also causing problems. After all, your project that uses the vulnerable crate version may be relying on that vulnerability to work at all!
Personally I don't trust such tools nearly enough to use them for production. There's always some use case where you don't want the exact semantics the tool provides, but some slight variation of it. And invariably, that costs an inordinate amount of time.
Bottom line for me: just do it manually. As convenient as such a tool would be in an idealized state, in practice it often turns out to be less error-prone and more efficient to do it manually.
Hmmm.... occurs to me that "The closest version with the fix" may actually be an earlier version than whatever I might be using. The vulnerability may have been introduced in the version I'm using and not yet fixed. The "fix" being to go backwards.
I guess that possibility is not implied with cargo audit fix.
I almost voted for latest, because I prefer to YOLO all my dependencies, but actually I'd be surprised if a security tool did this instead of making minimal upgrades.
It's very easy to run cargo update, but much harder to upgrade only the known-bad dependencies, only as little as necessary. So a tool that did the trival thing instead of the hard thing would offer little value.
I voted for minimal versions. If I wanted to keep my dependencies at the latest versions, I would use cargo update. It makes sure that all updates are done. In this case, I have no use for cargo audit fix and wouldn't use it.
But if I didn't want to update too frequently out of the fear of accidental breakage, I'd want to update as little as possible (to minimize breakage) while staying clear of vulnerabilities. This cannot be done today with simply cargo update, so cargo audit fix is useful and adds value.
Or put another way: if we view the set of all possible updates in a lockfile, cargo update takes them all (maximal). That's useful. cargo audit fix with the first option takes just the ones that are fixing vulnerabilities (minimal). This is useful too.
But cargo audit fix with the second option takes an arbitrary amount of fixes. It takes the necessary ones but also a few more. I don't know who this would be useful for. It doesn't minimize breakage but still isn't up to date.
I voted for "latest version". Yes, closest version would be the safest choice, but
any update, no matter how small, already carries the risk of breaking changes and new vulnerabilities. It's generally just easier to do one big-step update than multiple small-step ones.
I don't trust a random volunteer-supported tool to have exact information about the versions fixing vulnerabilities, except maybe for most popular crates. Hell, I'd have huge doubts even if this was a commercial tool. Knowing some version with a fix is plausible, but how is one supposed to track every update of every version for every package? And what if some versions do a regression? The latest crate version is thus more likely to be properly supported.
My humble opinion is a combination of both (as always, when two sides have differing views, it's often a combination which works best). To be clear, I voted for the absolute latest version, as I believe that up-to-date software is a bonus one can pull out of here as well. however, I would like to a see a function which updates dependencies to the latest version which compiles. Optionally, you can introduce checks on the test suite provided there is one.
But one should point out that the program compiling is not a 100% safe bet the update is compatible. This is why I believe a mentality shift is required also.
A function whose behaviour changes in the future should not exist. If the developer wishes to have an exposed library function's outwardly-visible behaviour changed, they should write a new function.