-
Notifications
You must be signed in to change notification settings - Fork 64
fix: add support for sha512-only archives #306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 23 commits
a948b10
e1b7e40
daf5864
46d5658
1511187
bbdf2fe
7501ca0
c973b90
9fa6d53
46fefb3
1e1a0d1
58c0e97
82dd7e7
f8eb118
bc4b7f6
c179489
744fae9
8c5cbc1
7a308a3
2ec8ab9
c5ce9e3
1397709
7cf965b
abfc91f
0ebadf2
606e7a1
86024cd
b70e1b4
311052e
0c9e9e3
b9da3c9
8caa89f
90c46ba
ce36ce4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,10 +129,11 @@ func (s *httpSuite) prepareArchive(suite, version, arch string, components []str | |
|
|
||
| func (s *httpSuite) prepareArchiveAdjustRelease(suite, version, arch string, components []string, adjustRelease func(*testarchive.Release)) *testarchive.Release { | ||
| release := &testarchive.Release{ | ||
| Suite: suite, | ||
| Version: version, | ||
| Label: "Ubuntu", | ||
| PrivKey: s.privKey, | ||
| Suite: suite, | ||
| Version: version, | ||
| Label: "Ubuntu", | ||
| PrivKey: s.privKey, | ||
| DigestKinds: []string{"SHA256"}, | ||
| } | ||
| for i, component := range components { | ||
| index := &testarchive.PackageIndex{ | ||
|
|
@@ -158,7 +159,10 @@ func (s *httpSuite) prepareArchiveAdjustRelease(suite, version, arch string, com | |
| if adjustRelease != nil { | ||
| adjustRelease(release) | ||
| } | ||
| release.Render(base.Path, s.responses) | ||
| err = release.Render(base.Path, s.responses) | ||
| if err != nil { | ||
| panic(err) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This wasn't here before. It's probably a good thing to add it, but please just confirm that this is okay given the context I just mentioned.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the other comment #306 (comment) this should not affect real archive test so this should be okay and should not risk hiding failures. |
||
| } | ||
| return release | ||
| } | ||
|
|
||
|
|
@@ -264,6 +268,70 @@ func (s *httpSuite) TestFetchPackage(c *C) { | |
| c.Assert(read(pkg), Equals, "mypkg4 1.4 data") | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchSHA512Digests(c *C) { | ||
| // Ubuntu 26.10+ publishes SHA512-only indices (no SHA256 section), so both | ||
| // the index digest and the package digest must be read from SHA512. | ||
| s.prepareArchiveAdjustRelease("stonking", "25.10", "amd64", []string{"main", "universe"}, | ||
| func(release *testarchive.Release) { | ||
| release.DigestKinds = []string{"SHA512"} | ||
| }) | ||
|
|
||
| options := archive.Options{ | ||
| Label: "ubuntu", | ||
| Version: "25.10", | ||
| Arch: "amd64", | ||
| Suites: []string{"stonking"}, | ||
| Components: []string{"main", "universe"}, | ||
| CacheDir: c.MkDir(), | ||
| PubKeys: []*packet.PublicKey{s.pubKey}, | ||
| } | ||
|
|
||
| testArchive, err := archive.Open(&options) | ||
| c.Assert(err, IsNil) | ||
|
|
||
| pkg, _, err := testArchive.Fetch("mypkg1") | ||
| c.Assert(err, IsNil) | ||
| c.Assert(read(pkg), Equals, "mypkg1 1.1 data") | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchBothDigests(c *C) { | ||
| // An archive publishing both SHA256 and SHA512 sections (index table and | ||
| // package fields) must be handled, with SHA256 preferred per the cache | ||
| // ordering -- so PackageInfo.SHA256 is the field that surfaces. | ||
| s.prepareArchiveAdjustRelease("stonking", "25.10", "amd64", []string{"main", "universe"}, | ||
| func(release *testarchive.Release) { | ||
| release.DigestKinds = []string{"SHA256", "SHA512"} | ||
| }) | ||
|
|
||
| options := archive.Options{ | ||
| Label: "ubuntu", | ||
| Version: "25.10", | ||
| Arch: "amd64", | ||
| Suites: []string{"stonking"}, | ||
| Components: []string{"main", "universe"}, | ||
| CacheDir: c.MkDir(), | ||
| PubKeys: []*packet.PublicKey{s.pubKey}, | ||
| } | ||
|
|
||
| testArchive, err := archive.Open(&options) | ||
| c.Assert(err, IsNil) | ||
|
|
||
| pkg, info, err := testArchive.Fetch("mypkg1") | ||
| c.Assert(err, IsNil) | ||
| c.Assert(info, DeepEquals, &archive.PackageInfo{ | ||
| Name: "mypkg1", | ||
| Version: "1.1", | ||
| Arch: "amd64", | ||
| SHA256: "1f08ef04cfe7a8087ee38a1ea35fa1810246648136c3c42d5a61ad6503d85e05", | ||
| }) | ||
| c.Assert(read(pkg), Equals, "mypkg1 1.1 data") | ||
|
|
||
| // Pin the cache key: with both digests advertised, packages must stay | ||
| // cached under their SHA256 so existing caches keep their entries. | ||
| _, err = os.Stat(filepath.Join(options.CacheDir, "sha256", info.SHA256)) | ||
| c.Assert(err, IsNil) | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchPortsPackage(c *C) { | ||
|
|
||
| s.base = "http://ports.ubuntu.com/ubuntu-ports/" | ||
|
|
@@ -310,14 +378,16 @@ func (s *httpSuite) TestFetchSecurityPackage(c *C) { | |
|
|
||
| for i, suite := range []string{"jammy", "jammy-updates", "jammy-security"} { | ||
| release := s.prepareArchive(suite, "22.04", "amd64", []string{"main", "universe"}) | ||
| release.Walk(func(item testarchive.Item) error { | ||
| err := release.Walk(func(item testarchive.Item) error { | ||
| if p, ok := item.(*testarchive.Package); ok && p.Name == "mypkg1" { | ||
| p.Version = fmt.Sprintf("%s.%d", p.Version, i) | ||
| p.Data = []byte("package from " + suite) | ||
| } | ||
| return nil | ||
| }) | ||
| release.Render("/ubuntu", s.responses) | ||
| c.Assert(err, IsNil) | ||
| err = release.Render("/ubuntu", s.responses) | ||
| c.Assert(err, IsNil) | ||
| } | ||
|
|
||
| options := archive.Options{ | ||
|
|
@@ -687,6 +757,89 @@ func (s *httpSuite) TestFetchByHashSucceedsWhenNamedPathIsStale(c *C) { | |
| c.Assert(status, Equals, 200) | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchByHashSHA512(c *C) { | ||
| // Ubuntu 26.10+ advertises Acquire-By-Hash with SHA512-only indices, so | ||
| // the by-hash URL must be built under the SHA512 directory. | ||
| s.prepareArchiveAdjustRelease("stonking", "26.10", "amd64", []string{"main"}, func(release *testarchive.Release) { | ||
| release.ByHash = true | ||
| release.DigestKinds = []string{"SHA512"} | ||
| }) | ||
|
|
||
| // Stale content at the named Packages.gz path, so a fallback would fail | ||
| // the digest check -- only the by-hash path serves the correct bytes. | ||
| for p := range s.responses { | ||
| if strings.Contains(p, "Packages.gz") && !strings.Contains(p, "/by-hash/") { | ||
| s.responses[p] = testarchive.MakeGzip([]byte("stale Packages from previous publication")) | ||
| } | ||
| } | ||
|
|
||
| options := archive.Options{ | ||
| Label: "ubuntu", | ||
| Version: "26.10", | ||
| Arch: "amd64", | ||
| Suites: []string{"stonking"}, | ||
| Components: []string{"main"}, | ||
| CacheDir: c.MkDir(), | ||
| PubKeys: []*packet.PublicKey{s.pubKey}, | ||
| } | ||
|
|
||
| testArchive, err := archive.Open(&options) | ||
| c.Assert(err, IsNil) | ||
|
|
||
| pkg, _, err := testArchive.Fetch("mypkg1") | ||
| c.Assert(err, IsNil) | ||
| c.Assert(read(pkg), Equals, "mypkg1 1.1 data") | ||
|
|
||
| // The SHA512 by-hash request must have been attempted and succeeded; | ||
| // the named path only has stale content. | ||
| attempted, status := s.fetchRequestStatus("/by-hash/SHA512/") | ||
| c.Assert(attempted, Equals, true) | ||
| c.Assert(status, Equals, 200) | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchByHashBothDigests(c *C) { | ||
| // When a by-hash archive publishes both digests, the by-hash URL must be | ||
| // built under SHA512: archives only guarantee a by-hash directory for the | ||
| // strongest hash they advertise. SHA256 by-hash must not be requested. | ||
| s.prepareArchiveAdjustRelease("stonking", "26.10", "amd64", []string{"main"}, func(release *testarchive.Release) { | ||
| release.ByHash = true | ||
| release.DigestKinds = []string{"SHA256", "SHA512"} | ||
| }) | ||
|
|
||
| // Stale content at the named Packages.gz path, so a fallback would fail | ||
| // the digest check -- only the by-hash path serves the correct bytes. | ||
| for p := range s.responses { | ||
| if strings.Contains(p, "Packages.gz") && !strings.Contains(p, "/by-hash/") { | ||
| s.responses[p] = testarchive.MakeGzip([]byte("stale Packages from previous publication")) | ||
| } | ||
| } | ||
|
|
||
| options := archive.Options{ | ||
| Label: "ubuntu", | ||
| Version: "26.10", | ||
| Arch: "amd64", | ||
| Suites: []string{"stonking"}, | ||
| Components: []string{"main"}, | ||
| CacheDir: c.MkDir(), | ||
| PubKeys: []*packet.PublicKey{s.pubKey}, | ||
| } | ||
|
|
||
| testArchive, err := archive.Open(&options) | ||
| c.Assert(err, IsNil) | ||
|
|
||
| pkg, _, err := testArchive.Fetch("mypkg1") | ||
| c.Assert(err, IsNil) | ||
| c.Assert(read(pkg), Equals, "mypkg1 1.1 data") | ||
|
|
||
| // The SHA512 by-hash request must have been made and succeeded; the SHA256 | ||
| // by-hash directory must never be touched. | ||
| attempted, status := s.fetchRequestStatus("/by-hash/SHA512/") | ||
| c.Assert(attempted, Equals, true) | ||
| c.Assert(status, Equals, 200) | ||
| attempted, _ = s.fetchRequestStatus("/by-hash/SHA256/") | ||
| c.Assert(attempted, Equals, false) | ||
| } | ||
|
|
||
| func (s *httpSuite) TestFetchByHashFallsBackOnNotFound(c *C) { | ||
| s.prepareArchiveAdjustRelease("jammy", "22.04", "amd64", []string{"main"}, func(r *testarchive.Release) { | ||
| r.ByHash = true | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.