Apologies—"gaslighting" was not directed at you personally. It's directed at the collective group 'gaslighting' (perhaps 'delusion' or 'self-delusion' is more accurate) that we can all easily experience when considering these kinds of questions, perhaps because of the kind of "toxic positivity" work culture that pervades this industry. Nobody can call it out when something is obviously illogical and wrong, anymore. To use an analogy from the story, "The Emperor's New Clothes"—there is a collective effect whereby nobody can call the Emperor "naked" when in fact he is obviously exactly naked.
Your intentions aren't at issue. And yes of course this distinction exists—I'm the one who pointed it out to begin with.
However I disagree that it's a technical distinction. It's actually a semantic distinction—it's about what words mean. The words of the Semantic Versioning standard don't say anything that should compel anyone to change the meaning of "exact version". In fact the authors were very careful to explicitly state:
Build metadata MUST be ignored when determining version precedence
The only time we are not determining version precedence is when we are matching an identity relation like "exact version".
It's obvious that it should function identically to pinning a version specified in a .resolved or lockfile. We'd consider it an obvious security flaw if .resolved or lockfile pulled down a different version—by your own arguments. So why is it not a security flaw if this relation is broken in Package.swift where the author expresses their actual intent?
Again that's not a technical issue, it's about respecting the plain meaning of words.
Your argument was that this SwiftPM behavior is based on a legitimate "interpretation" of something the SemVer standard leaves unstated, but in reality it is simply a misreading and misapplication of that standard to an aspect that falls outside its scope, and a breaking of the solemn contract that the SPM API has with its users to accurately portray intent.
On compatibility, this is not simply a matter of independently bumping SwiftPM to 7.0. SwiftPM is distributed as part of Swift toolchain releases, and preserving the old behavior for existing manifests would require an explicit compatibility mechanism, potentially based on
swift-tools-version. That design and implementation would itself need to be considered.
I'm generally not in favor of preserving security bugs in production for backwards compatibility, as that exposes a larger attack surface unnecessarily. However if it must be done then at least the availability of advanced coding tools now makes the amount of work involved not a blocker.
But if SwiftPM needs the current precedence-based behavior for compatibility, give that behavior a name that describes it, such as .samePrecedence(as:) or .semverEquivalent(to:). Do not require users to discover that .exact is not exact.
The cited security examples do not establish that publishing a new metadata variant can replace a dependency already pinned in
Package.resolved.
That is not the criteria for determining it's a security issue.
I specifically said that it exposes people when "updating" their dependencies.
Because someone might easily update them on the false assumption that pinning a version with Version.exact(...) means that they don't have to worry about the version changing. That is what exact is supposed to mean and the fact that it doesn't is a grave risk.
Build metadata does not create a higher-precedence version under SemVer, so the scenario described is selection among precedence-equivalent identifiers, not injection of a higher-precedence version.
Whether the attack or accident owes to a higher-precedence relation is irrelevant to the question of the security risk. The security risk is that a different version than the one someone intended to pin in their Package.swift by using Version.exact(..) could wind up in a distributed build completely by accident and possibly without them even knowing.
That could be from a third-party dependency or their own repo. That's an attack surface and an obvious risk factor for accidental leaks of debug code, etc.
SwiftPM also records the resolved source-control revision in the lockfile.
You don't always have a lockfile. Also, why would someone think they need to rely on the lockfile if they've pinned all their versions with Version.exact?
Demonstrating that an existing pin can be silently replaced during ordinary resolution would therefore require a concrete SwiftPM reproduction that distinguishes ordinary resolution from an explicit dependency update, removal of the lockfile, or mutation of an existing tag
Here is such a demonstration. Do the following:
swift package init
swift package add-target Target
swift package add-dependency "https://github.com/gistya/spm-test" --exact 0.5.1+debug
swift build
This outputs:
Fetching https://github.com/gistya/spm-test from cache
Fetched https://github.com/gistya/spm-test from cache (0.45s)
Computing version for https://github.com/gistya/spm-test
Computed https://github.com/gistya/spm-test at 0.5.1 (0.69s)
Creating working copy for https://github.com/gistya/spm-test
Working copy of https://github.com/gistya/spm-test resolved at 0.5.1
That's ordinary resolution pulling down THE WRONG VERSION. If that can happen, there's a security risk. Because then anyone adding a compromised package to their app would get the malware payload.
Further, suppose that the pin was to 0.5.1+release AND it turns out that plain 0.5.1 is a debug build. Now we've released debug code to millions of users.
Without one, I do not think the broader security analogy resolves the compatibility question before this proposal: whether to change the established behavior of
exact:or add an opt-in API for literal identifier matching.
You're arguing heavily from compatibility, but who out there is actually using exact: but who did not intend to exactly pin versions? If they did not intend to pin versions, wouldn't they already be using Version(from: )? And why would the proposal under discussion exist?
Can you articulate a genuine real example of a use-case that makes it worth preserving a security risk in production?