Skip to content

Commit 127599b

Browse files
committed
Add support for Pro FIPS archives
Support Pro archives by a pro property in chisel.yaml. When the pro property is specified, it has to be either "fips" or "fips-updates". The repository URL is inferred from the value. Also, credentials for these URLs are searched. If credentials are not found, the corresponding pro archive is silently disabled. Otherwise, all requests to the archive are sent with the credentials found.
1 parent 762040c commit 127599b

File tree

6 files changed

+184
-15
lines changed

6 files changed

+184
-15
lines changed

cmd/chisel/cmd_cut.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,19 @@ func (cmd *cmdCut) Execute(args []string) error {
9292
Components: archiveInfo.Components,
9393
CacheDir: cache.DefaultDir("chisel"),
9494
Priority: archiveInfo.Priority,
95+
Pro: archiveInfo.Pro,
9596
})
9697
if err != nil {
97-
return err
98+
if err != archive.ErrCredentialsNotFound {
99+
return err
100+
}
101+
} else {
102+
archives[archiveName] = openArchive
98103
}
99-
archives[archiveName] = openArchive
104+
}
105+
106+
if len(archives) == 0 {
107+
return fmt.Errorf("no valid archives (%d skipped)", len(release.Archives))
100108
}
101109

102110
return slicer.Run(&slicer.RunOptions{

internal/archive/archive.go

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
"net/http"
8+
"sort"
89
"strings"
910
"time"
1011

@@ -35,6 +36,7 @@ type Options struct {
3536
Components []string
3637
CacheDir string
3738
Priority int32
39+
Pro string
3840
}
3941

4042
func Open(options *Options) (Archive, error) {
@@ -66,6 +68,8 @@ type ubuntuArchive struct {
6668
options Options
6769
indexes []*ubuntuIndex
6870
cache *cache.Cache
71+
baseURL string
72+
auth string
6973
}
7074

7175
type ubuntuIndex struct {
@@ -76,7 +80,7 @@ type ubuntuIndex struct {
7680
component string
7781
release control.Section
7882
packages control.File
79-
cache *cache.Cache
83+
archive *ubuntuArchive
8084
}
8185

8286
func (a *ubuntuArchive) Options() *Options {
@@ -141,6 +145,52 @@ func (a *ubuntuArchive) Fetch(pkg string) (io.ReadCloser, error) {
141145

142146
const ubuntuURL = "http://archive.ubuntu.com/ubuntu/"
143147
const ubuntuPortsURL = "http://ports.ubuntu.com/ubuntu-ports/"
148+
const ubuntuProURL = "https://esm.ubuntu.com/"
149+
150+
// keep it sorted
151+
var validPro = []string{
152+
"fips",
153+
"fips-updates",
154+
}
155+
156+
func initProArchive(pro string, archive *ubuntuArchive) error {
157+
if i := sort.SearchStrings(validPro, pro); !(i < len(validPro) && validPro[i] == pro) {
158+
strvals := strings.Join(validPro, ", ")
159+
return fmt.Errorf("invalid pro type, supported types: %s", strvals)
160+
}
161+
162+
baseURL := ubuntuProURL + pro + "/ubuntu/"
163+
creds, err := findCredentials(baseURL)
164+
if err != nil {
165+
return err
166+
}
167+
168+
// Check that credentials are valid.
169+
// It appears that only pool/ URLs are protected.
170+
req, err := http.NewRequest("HEAD", baseURL+"pool/", nil)
171+
if err != nil {
172+
return fmt.Errorf("cannot create HTTP request: %w", err)
173+
}
174+
req.SetBasicAuth(creds.Username, creds.Password)
175+
176+
resp, err := httpDo(req)
177+
if err != nil {
178+
return fmt.Errorf("cannot talk to the archive: %w", err)
179+
}
180+
resp.Body.Close()
181+
switch resp.StatusCode {
182+
case 200: // ok
183+
case 401:
184+
return fmt.Errorf("cannot authenticate to the archive")
185+
default:
186+
return fmt.Errorf("error from the archive: %v", resp.Status)
187+
}
188+
189+
archive.baseURL = baseURL
190+
archive.auth = req.Header.Get("Authorization")
191+
192+
return nil
193+
}
144194

145195
func openUbuntu(options *Options) (Archive, error) {
146196
if len(options.Components) == 0 {
@@ -160,6 +210,18 @@ func openUbuntu(options *Options) (Archive, error) {
160210
},
161211
}
162212

213+
if options.Pro != "" {
214+
if err := initProArchive(options.Pro, archive); err != nil {
215+
return nil, err
216+
}
217+
} else {
218+
if options.Arch == "amd64" || options.Arch == "i386" {
219+
archive.baseURL = ubuntuURL
220+
} else {
221+
archive.baseURL = ubuntuPortsURL
222+
}
223+
}
224+
163225
for _, suite := range options.Suites {
164226
var release control.Section
165227
for _, component := range options.Components {
@@ -170,7 +232,7 @@ func openUbuntu(options *Options) (Archive, error) {
170232
suite: suite,
171233
component: component,
172234
release: release,
173-
cache: archive.cache,
235+
archive: archive,
174236
}
175237
if release == nil {
176238
err := index.fetchRelease()
@@ -258,29 +320,27 @@ func (index *ubuntuIndex) checkComponents(components []string) error {
258320
}
259321

260322
func (index *ubuntuIndex) fetch(suffix, digest string) (io.ReadCloser, error) {
261-
reader, err := index.cache.Open(digest)
323+
reader, err := index.archive.cache.Open(digest)
262324
if err == nil {
263325
return reader, nil
264326
} else if err != cache.MissErr {
265327
return nil, err
266328
}
267329

268-
baseURL := ubuntuURL
269-
if index.arch != "amd64" && index.arch != "i386" {
270-
baseURL = ubuntuPortsURL
271-
}
272-
273330
var url string
274331
if strings.HasPrefix(suffix, "pool/") {
275-
url = baseURL + suffix
332+
url = index.archive.baseURL + suffix
276333
} else {
277-
url = baseURL + "dists/" + index.suite + "/" + suffix
334+
url = index.archive.baseURL + "dists/" + index.suite + "/" + suffix
278335
}
279336

280337
req, err := http.NewRequest("GET", url, nil)
281338
if err != nil {
282339
return nil, fmt.Errorf("cannot create HTTP request: %v", err)
283340
}
341+
if index.archive.auth != "" {
342+
req.Header.Set("Authorization", index.archive.auth)
343+
}
284344
resp, err := httpDo(req)
285345
if err != nil {
286346
return nil, fmt.Errorf("cannot talk to archive: %v", err)
@@ -290,7 +350,7 @@ func (index *ubuntuIndex) fetch(suffix, digest string) (io.ReadCloser, error) {
290350
switch resp.StatusCode {
291351
case 200:
292352
// ok
293-
case 401, 404:
353+
case 404:
294354
return nil, fmt.Errorf("cannot find archive data")
295355
default:
296356
return nil, fmt.Errorf("error from archive: %v", resp.Status)
@@ -306,7 +366,7 @@ func (index *ubuntuIndex) fetch(suffix, digest string) (io.ReadCloser, error) {
306366
body = reader
307367
}
308368

309-
writer := index.cache.Create(digest)
369+
writer := index.archive.cache.Create(digest)
310370
defer writer.Close()
311371

312372
_, err = io.Copy(writer, body)
@@ -317,5 +377,5 @@ func (index *ubuntuIndex) fetch(suffix, digest string) (io.ReadCloser, error) {
317377
return nil, fmt.Errorf("cannot fetch from archive: %v", err)
318378
}
319379

320-
return index.cache.Open(writer.Digest())
380+
return index.archive.cache.Open(writer.Digest())
321381
}

internal/archive/archive_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,59 @@ func (s *httpSuite) TestPackageInfo(c *C) {
365365
c.Assert(info99, IsNil)
366366
}
367367

368+
func (s *httpSuite) TestFetchProPackage(c *C) {
369+
var err error
370+
371+
credsDir := c.MkDir()
372+
restore := fakeEnv("CHISEL_AUTH_DIR", credsDir)
373+
defer restore()
374+
375+
s.base = "https://esm.ubuntu.com/fips/ubuntu/"
376+
s.prepareArchive("jammy", "22.04", "amd64", []string{"main", "universe"})
377+
378+
invalidOptions := archive.Options{
379+
Label: "ubuntu",
380+
Version: "22.04",
381+
Arch: "amd64",
382+
Suites: []string{"jammy"},
383+
Components: []string{"main", "universe"},
384+
CacheDir: c.MkDir(),
385+
Pro: "invalid",
386+
}
387+
388+
_, err = archive.Open(&invalidOptions)
389+
c.Assert(err, ErrorMatches, "invalid pro type, supported types: fips, fips-updates")
390+
391+
fipsOptions := archive.Options{
392+
Label: "ubuntu",
393+
Version: "22.04",
394+
Arch: "amd64",
395+
Suites: []string{"jammy"},
396+
Components: []string{"main", "universe"},
397+
CacheDir: c.MkDir(),
398+
Pro: "fips",
399+
}
400+
401+
_, err = archive.Open(&fipsOptions)
402+
c.Assert(err, Equals, archive.ErrCredentialsNotFound)
403+
404+
credsFile := filepath.Join(credsDir, "90ubuntu-advantage")
405+
credsData := "machine https://esm.ubuntu.com/fips/ubuntu/ login user password pw\n"
406+
err = ioutil.WriteFile(credsFile, []byte(credsData), 0600)
407+
c.Assert(err, IsNil)
408+
409+
archive, err := archive.Open(&fipsOptions)
410+
c.Assert(err, IsNil)
411+
412+
pkg, err := archive.Fetch("mypkg1")
413+
c.Assert(err, IsNil)
414+
c.Assert(read(pkg), Equals, "mypkg1 1.1 data")
415+
416+
pkg, err = archive.Fetch("mypkg4")
417+
c.Assert(err, IsNil)
418+
c.Assert(read(pkg), Equals, "mypkg4 1.4 data")
419+
}
420+
368421
func read(r io.Reader) string {
369422
data, err := ioutil.ReadAll(r)
370423
if err != nil {

internal/setup/setup.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type Archive struct {
3030
Suites []string
3131
Components []string
3232
Priority int32
33+
Pro string
3334
}
3435

3536
// Package holds a collection of slices that represent parts of themselves.
@@ -323,6 +324,7 @@ type yamlArchive struct {
323324
Suites []string `yaml:"suites"`
324325
Components []string `yaml:"components"`
325326
Priority int32 `yaml:"priority"`
327+
Pro string `yaml:"pro"`
326328
}
327329

328330
type yamlPackage struct {
@@ -430,6 +432,7 @@ func parseRelease(baseDir, filePath string, data []byte) (*Release, error) {
430432
Suites: details.Suites,
431433
Components: details.Components,
432434
Priority: details.Priority,
435+
Pro: details.Pro,
433436
}
434437
}
435438

internal/setup/setup_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,50 @@ var setupTests = []setupTest{{
792792
`,
793793
},
794794
relerror: "(?s).*\\bcannot unmarshal !!int `2147483648` into int32\\b.*",
795+
}, {
796+
summary: "Pro property",
797+
input: map[string]string{
798+
"chisel.yaml": `
799+
format: chisel-v1
800+
archives:
801+
ubuntu:
802+
version: 22.04
803+
components: [main, universe]
804+
suites: [jammy, jammy-updates, jammy-security]
805+
ubuntu-fips:
806+
pro: fips
807+
version: 22.04
808+
components: [main]
809+
suites: [jammy]
810+
`,
811+
"slices/mydir/mypkg.yaml": `
812+
package: mypkg
813+
`,
814+
},
815+
release: &setup.Release{
816+
Archives: map[string]*setup.Archive{
817+
"ubuntu": {
818+
Name: "ubuntu",
819+
Version: "22.04",
820+
Suites: []string{"jammy", "jammy-updates", "jammy-security"},
821+
Components: []string{"main", "universe"},
822+
},
823+
"ubuntu-fips": {
824+
Name: "ubuntu-fips",
825+
Version: "22.04",
826+
Suites: []string{"jammy"},
827+
Components: []string{"main"},
828+
Pro: "fips",
829+
},
830+
},
831+
Packages: map[string]*setup.Package{
832+
"mypkg": {
833+
Name: "mypkg",
834+
Path: "slices/mydir/mypkg.yaml",
835+
Slices: map[string]*setup.Slice{},
836+
},
837+
},
838+
},
795839
}}
796840

797841
const defaultChiselYaml = `

internal/slicer/slicer_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,7 @@ func (s *S) TestRun(c *C) {
949949
Suites: setupArchive.Suites,
950950
Components: setupArchive.Components,
951951
Priority: setupArchive.Priority,
952+
Pro: setupArchive.Pro,
952953
Arch: test.arch,
953954
},
954955
pkgs: archivePkgs,

0 commit comments

Comments
 (0)