Skip to content

fix: prevent intermittent digest-mismatch errors during archive updates#296

Open
gruyaume wants to merge 4 commits into
canonical:mainfrom
gruyaume:dev-fixhash
Open

fix: prevent intermittent digest-mismatch errors during archive updates#296
gruyaume wants to merge 4 commits into
canonical:mainfrom
gruyaume:dev-fixhash

Conversation

@gruyaume

@gruyaume gruyaume commented May 15, 2026

Copy link
Copy Markdown

Chisel intermittently fails with expected digest X, got Y when Ubuntu's archive is mid-publication and InRelease is temporarily inconsistent with Packages.gz at the named path (a window we observed lasting at least 39 minutes against the same publication in real CI runs for Ella Core). Fetch the package index by content hash using apt's Acquire-By-Hash , which Ubuntu archives have advertised since 16.04 (2016), so the URL itself encodes the expected bytes; falls back to the named path when an archive doesn't advertise the feature or a specific hash has been garbage-collected.

Fixes #295

Reference


  • Have you signed the CLA?

@lczyk lczyk added the Bug An undesired feature ;-) label May 29, 2026
@upils

upils commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Hey @gruyaume, thanks for your PR! Is this ready for review?

@gruyaume

gruyaume commented Jun 1, 2026

Copy link
Copy Markdown
Author

Hey @gruyaume, thanks for your PR! Is this ready for review?

Yes.

If you find the code changes mostly up to you standards, I am happy to address minor issues. However if there are major issues and you have a completely different idea of the solution, please go ahead and implement it your way. I only want the issue fixed as soon as possible, I don't care about getting the attribution.

@gruyaume gruyaume marked this pull request as ready for review June 1, 2026 13:10
@upils

upils commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Yes.

If you find the code changes mostly up to you standards, I am happy to address minor issues. However if there are major issues and you have a completely different idea of the solution, please go ahead and implement it your way. I only want the issue fixed as soon as possible, I don't care about getting the attribution.

Thanks! I explored another approach in parallel but I ended up circling back to yours so there is no point just having another PR for the sake of it. I will review yours then, because I expect only minor changes will be requested.

@gruyaume

gruyaume commented Jun 9, 2026

Copy link
Copy Markdown
Author

@upils , @lczyk can you or another admin please review this PR?

@upils upils left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gruyaume for the PR. Overall I think it looks great and the approach seems right to me. I have a few suggestions that should be very quick to fix.

Comment thread internal/archive/testarchive/testarchive.go Outdated
Comment thread internal/archive/testarchive/testarchive.go Outdated
Comment thread internal/archive/archive_test.go Outdated
Signed-off-by: Guillaume Belanger <[email protected]>
@gruyaume gruyaume requested a review from upils June 15, 2026 11:47

@upils upils left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gruyaume! Once the CI is done I will move it to the next review stage.

@upils upils added the Priority Look at me first label Jun 15, 2026

@niemeyer niemeyer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feature @gruyaume. There are a couple of minor details about the organization only. Let us know how you'd prefer to evolve this... might take it over from here as well if you want. /cc @upils


body := resp.Body
if strings.HasSuffix(path, ".gz") {
if flags&fetchGzip != 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a behavioral change. Has anyone double checked that we don't have any other cases that were handled before and are not handled now?

// are content-addressed and so are immune to the inconsistent view of
// InRelease vs Packages.gz that mirrors and CDNs can serve while a
// publication is propagating. See https://wiki.ubuntu.com/AptByHash.
gzPath := packagesPath + ".gz"

@niemeyer niemeyer Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole function needs to have its variable names reviewed and polished, as it's becoming unreadable. We have digests, digest, gzPath, gzDigest, byHashPath, etc. These things all talk about their types and suffixes, and not about what they are. And they are not the same thing.

/cc @upils

func (s *httpSuite) sawByHashRequest() bool {
for _, req := range s.requests {
if strings.Contains(req.URL.Path, "/by-hash/SHA256/") {
return true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the archive only has the right file in the right place, the only way for us to get the right content is to use that file. I might be missing something, but it looks like at the moment all we are looking at is a request being made inside a directory, possibly in the wrong place considering we fallback.

}
if r.AcquireByHash && itemPath != r.Path() && !skipByHash[itemPath] {
byHashPath := path.Join(prefix, "dists", r.Suite, path.Dir(itemPath), "by-hash", "SHA256", makeSha256(itemContent))
content[byHashPath] = itemContent

@niemeyer niemeyer Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used to be a very clean and simple function, and it'd be nice to keep it that way. From these options, having a ByHash bool (not "Acquire", that's on the fetch side) seems in line with the type semantics. The other options look like custom hacks that require reading both the test and the implementation to be made sense of, so we need to think a bit about how to represent these while keeping that clean and simple aspect.

/cc @upils

@niemeyer niemeyer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👆

@gruyaume

Copy link
Copy Markdown
Author

Thanks for the feature @gruyaume. There are a couple of minor details about the organization only. Let us know how you'd prefer to evolve this... might take it over from here as well if you want. /cc @upils

Yes feel free to take it over from here.

Thank you.

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

Labels

Bug An undesired feature ;-) Priority Look at me first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chisel is flaky when the archive is updating

4 participants