Commit e95a255
Cherry pick of #9144
In `RegistryClient.swift` there is an in-memory package metadata cache
expiration check
```swift
let cacheKey = MetadataCacheKey(registry: registry, package: package)
if let cached = self.metadataCache[cacheKey], cached.expires < .now() {
return cached.metadata
}
```
The logic for `cached.expires < .now()` appears to be inverted, e.g. if
a cache is found for the cacheKey, the initial values look like this
`2389992062152` < `2303592072235` which equates to false, because
[`cached.expires`](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/RegistryClient.swift#L443)
is set with a TTL of [60*60
seconds](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/RegistryClient.swift#L38)
in the future. This leads to the cache only being used _after_ it has
expired and may be causing downstream fingerprint TOFU issues when new
package releases are published and the metadata cache is in-memory.
### Motivation:
This issue was identified via the use of a private SPM registry
conforming to the [registry server
specification](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/registryserverspecification/).
Disclaimer: This issue was also occurring in previous versions of Xcode
but now that they are [sharing code with
SPM](https://developer.apple.com/documentation/xcode-release-notes/xcode-26-release-notes#Swift-Package-Manager),
I hope this example is still relevant. The scenario it is occurring in
is as follows:
1. Have Xcode open for 1 hour or more after resolving dependencies at
least once to populate the cache.
2. Release a new package version to the registry
3. Attempt to resolve the new version in Xcode
4. At this stage, my belief is that the previous release's metadata
(including the checksum) from the "expired" cache is stored to disk as
the fingerprint associated with the new release for TOFU purposes.
- Code path:
- -> [Get expected checksum for new
version](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/ChecksumTOFU.swift#L49)
- -> [Get metadata for
version](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/ChecksumTOFU.swift#L111-L122)
- -> [Check if we should hit the server or use
cache](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/RegistryClient.swift#L290-L310)
- -> [Use cached metadata if it's been in memory for 1
hour](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/RegistryClient.swift#L400-L403)
- -> [Write cached (old) checksum to fingerprint storage for new
version](https://github.com/swiftlang/swift-package-manager/blob/18bc4801d1e0aa02ca69633c3c12d5d1135b65bc/Sources/PackageRegistry/ChecksumTOFU.swift#L131-L138)
6. Attempting even `swift package resolve` via CLI at this point results
the following error:
- `invalid registry source archive checksum 'newchecksum', expected
'previouschecksum'`
Because the checksum fingerprint is stored on disk in
`~/Library/org.swift.swiftpm/security/fingerprints/`, it takes manual
intervention to recover from this by purging various caches.
Example of a common workaround:
https://stackoverflow.com/questions/79417322/invalid-registry-source-archive-checksum-a-expected-b
Related github issue:
#8981
In addition to that, there are probably excessive requests being sent to
various registries due to the cache not being used during the initial
TTL.
### Modifications:
Two main changes in this PR that should help with this:
1. Adding `version` property to the `MetadataCacheKey`, so that even if
the previous metadata is in cache and hasn't expired, it won't be
applied to the new version.
2. Reversing the logic for checking expiration, so that it will
appropriately fetch new data upon expiration, rather than only fetching
new data until expiration.
In addition to that, this PR also:
- Fixes a similar cache expiration issue for the `availabilityCache`
- Adds tests for both caches
- Updates `withAvailabilityCheck` to internal (from private) for
testability.
### Result:
The hopeful result of this is that package registry consumers will no
longer require manual workarounds to fix their local state when they hit
this edge case, as well as avoid hitting github and other package
registries [too
often](https://x.com/krzyzanowskim/status/1967333807318777900) (my guess
for the original intent of the cache).
That said, it will be a bit tricky to validate in its entirety because
this cache is only relevant for long-running tasks via libSwiftPM I
presume.
One big thing to note is that this may be a noticeable change to
existing behavior since the cache is not currently being used as far as
I can tell, and once fixed, it will significantly reduce the freshness
of the metadata compared to before.
Co-authored-by: Zach Nagengast <[email protected]>
1 parent 0da281d commit e95a255
File tree
2 files changed
+219
-17
lines changed- Sources/PackageRegistry
- Tests/PackageRegistryTests
2 files changed
+219
-17
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
397 | 397 | | |
398 | 398 | | |
399 | 399 | | |
400 | | - | |
401 | | - | |
| 400 | + | |
| 401 | + | |
402 | 402 | | |
403 | 403 | | |
404 | 404 | | |
| |||
1403 | 1403 | | |
1404 | 1404 | | |
1405 | 1405 | | |
1406 | | - | |
1407 | | - | |
1408 | | - | |
1409 | | - | |
1410 | | - | |
1411 | | - | |
1412 | | - | |
1413 | | - | |
1414 | | - | |
1415 | | - | |
1416 | | - | |
1417 | | - | |
1418 | 1406 | | |
1419 | 1407 | | |
1420 | | - | |
| 1408 | + | |
1421 | 1409 | | |
1422 | 1410 | | |
1423 | 1411 | | |
| |||
1438 | 1426 | | |
1439 | 1427 | | |
1440 | 1428 | | |
1441 | | - | |
| 1429 | + | |
1442 | 1430 | | |
1443 | 1431 | | |
1444 | 1432 | | |
| |||
1453 | 1441 | | |
1454 | 1442 | | |
1455 | 1443 | | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
| 1454 | + | |
| 1455 | + | |
1456 | 1456 | | |
1457 | 1457 | | |
1458 | 1458 | | |
| |||
1495 | 1495 | | |
1496 | 1496 | | |
1497 | 1497 | | |
| 1498 | + | |
1498 | 1499 | | |
1499 | 1500 | | |
1500 | 1501 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| |||
440 | 440 | | |
441 | 441 | | |
442 | 442 | | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
443 | 563 | | |
444 | 564 | | |
445 | 565 | | |
| |||
3701 | 3821 | | |
3702 | 3822 | | |
3703 | 3823 | | |
| 3824 | + | |
| 3825 | + | |
| 3826 | + | |
| 3827 | + | |
| 3828 | + | |
| 3829 | + | |
| 3830 | + | |
| 3831 | + | |
| 3832 | + | |
| 3833 | + | |
| 3834 | + | |
| 3835 | + | |
| 3836 | + | |
| 3837 | + | |
| 3838 | + | |
| 3839 | + | |
| 3840 | + | |
| 3841 | + | |
| 3842 | + | |
| 3843 | + | |
| 3844 | + | |
| 3845 | + | |
| 3846 | + | |
| 3847 | + | |
| 3848 | + | |
| 3849 | + | |
| 3850 | + | |
| 3851 | + | |
| 3852 | + | |
| 3853 | + | |
| 3854 | + | |
| 3855 | + | |
| 3856 | + | |
| 3857 | + | |
| 3858 | + | |
| 3859 | + | |
| 3860 | + | |
| 3861 | + | |
| 3862 | + | |
| 3863 | + | |
| 3864 | + | |
| 3865 | + | |
| 3866 | + | |
| 3867 | + | |
| 3868 | + | |
| 3869 | + | |
| 3870 | + | |
| 3871 | + | |
| 3872 | + | |
| 3873 | + | |
| 3874 | + | |
| 3875 | + | |
| 3876 | + | |
| 3877 | + | |
| 3878 | + | |
| 3879 | + | |
| 3880 | + | |
| 3881 | + | |
| 3882 | + | |
| 3883 | + | |
| 3884 | + | |
| 3885 | + | |
| 3886 | + | |
| 3887 | + | |
| 3888 | + | |
| 3889 | + | |
| 3890 | + | |
| 3891 | + | |
| 3892 | + | |
| 3893 | + | |
| 3894 | + | |
| 3895 | + | |
| 3896 | + | |
| 3897 | + | |
| 3898 | + | |
| 3899 | + | |
| 3900 | + | |
| 3901 | + | |
| 3902 | + | |
| 3903 | + | |
| 3904 | + | |
3704 | 3905 | | |
3705 | 3906 | | |
3706 | 3907 | | |
| |||
0 commit comments