@@ -14,6 +14,7 @@ import (
1414 "strings"
1515
1616 "chainguard.dev/apko/pkg/apk/apk"
17+ "chainguard.dev/apko/pkg/apk/auth"
1718 sbomSyft "github.com/anchore/syft/syft/sbom"
1819 "github.com/chainguard-dev/clog"
1920 "github.com/charmbracelet/lipgloss"
@@ -25,7 +26,6 @@ import (
2526 "github.com/wolfi-dev/wolfictl/pkg/configs"
2627 v2 "github.com/wolfi-dev/wolfictl/pkg/configs/advisory/v2"
2728 rwos "github.com/wolfi-dev/wolfictl/pkg/configs/rwfs/os"
28- "github.com/wolfi-dev/wolfictl/pkg/index"
2929 "github.com/wolfi-dev/wolfictl/pkg/sbom"
3030 "github.com/wolfi-dev/wolfictl/pkg/scan"
3131 "github.com/wolfi-dev/wolfictl/pkg/versions"
@@ -357,6 +357,7 @@ type scanParams struct {
357357 disableSBOMCache bool
358358 triageWithGoVulnCheck bool
359359 remoteScanning bool
360+ remoteRepository string
360361 useCPEMatching bool
361362 verbosity int
362363}
@@ -374,6 +375,7 @@ func (p *scanParams) addFlagsTo(cmd *cobra.Command) {
374375 cmd .Flags ().BoolVar (& p .triageWithGoVulnCheck , "govulncheck" , false , "EXPERIMENTAL: triage vulnerabilities in Go binaries using govulncheck" )
375376 _ = cmd .Flags ().MarkHidden ("govulncheck" ) //nolint:errcheck
376377 cmd .Flags ().BoolVarP (& p .remoteScanning , "remote" , "r" , false , "treat input(s) as the name(s) of package(s) in the Wolfi package repository to download and scan the latest versions of" )
378+ cmd .Flags ().StringVar (& p .remoteRepository , "repository" , "https://packages.wolfi.dev/os" , "URL of the APK package repository" )
377379 cmd .Flags ().BoolVar (& p .useCPEMatching , "use-cpes" , false , "turn on all CPE matching in Grype" )
378380 addVerboseFlag (& p .verbosity , cmd )
379381}
@@ -403,7 +405,7 @@ func (p *scanParams) resolveInputsToScan(ctx context.Context, args []string) (in
403405 }
404406
405407 for _ , arg := range args {
406- targetPaths , cleanup , err := resolveInputForRemoteTarget (ctx , arg )
408+ targetPaths , cleanup , err := resolveInputForRemoteTarget (ctx , arg , p . remoteRepository )
407409 if err != nil {
408410 return nil , nil , fmt .Errorf ("failed to resolve input %q for remote scanning: %w" , arg , err )
409411 }
@@ -606,6 +608,18 @@ func resolveInputFileFromArg(inputFilePath string) (*os.File, error) {
606608 }
607609}
608610
611+ // getAPKIndexURL returns the URL of the APKINDEX.tar.gz file for the given
612+ // repository and architecture. If the repository URL already points to an
613+ // APKINDEX.tar.gz file, it will be returned as-is. User input may or may not
614+ // have included the architecture or the APKINDEX.tar.gz suffix, so construct
615+ // the full URL to provide better UX.
616+ func getAPKIndexURL (repositoryURL , arch string ) string {
617+ if strings .HasSuffix (repositoryURL , "/x86_64/APKINDEX.tar.gz" ) || strings .HasSuffix (repositoryURL , "/aarch64/APKINDEX.tar.gz" ) {
618+ return repositoryURL
619+ }
620+ return fmt .Sprintf ("%s/%s/APKINDEX.tar.gz" , repositoryURL , arch )
621+ }
622+
609623// resolveInputForRemoteTarget takes the given input string, which is expected
610624// to be the name of a Wolfi package (or subpackage), and it queries the Wolfi
611625// APK repository to find the latest version of the package for each
@@ -615,13 +629,14 @@ func resolveInputFileFromArg(inputFilePath string) (*os.File, error) {
615629// For example, given the input value "calico", this function will find the
616630// latest version of the package (e.g. "calico-3.26.3-r3.apk") and download it
617631// for each architecture.
618- func resolveInputForRemoteTarget (ctx context.Context , input string ) (downloadedAPKFilePaths []string , cleanup func () error , err error ) {
632+ func resolveInputForRemoteTarget (ctx context.Context , input , repository string ) (downloadedAPKFilePaths []string , cleanup func () error , err error ) {
619633 logger := clog .FromContext (ctx )
620634
621635 archesFound := 0
622636 for _ , arch := range []string {"x86_64" , "aarch64" } {
623- const apkRepositoryURL = "https://packages.wolfi.dev/os"
624- apkindex , err := index .Index (arch , apkRepositoryURL )
637+ // Since index.Index function doesn't respect the `$HTTP_AUTH`, use
638+ // fetchAPKIndex function instead.
639+ apkindex , _ , err := fetchAPKIndex (ctx , getAPKIndexURL (repository , arch ))
625640 if err != nil {
626641 return nil , nil , fmt .Errorf ("getting APKINDEX: %w" , err )
627642 }
@@ -651,7 +666,7 @@ func resolveInputForRemoteTarget(ctx context.Context, input string) (downloadedA
651666 break
652667 }
653668 }
654- downloadURL := fmt .Sprintf ("%s/%s/%s" , apkRepositoryURL , arch , latestPkg .Filename ())
669+ downloadURL := fmt .Sprintf ("%s/%s/%s" , repository , arch , latestPkg .Filename ())
655670
656671 apkTempFileName := fmt .Sprintf ("%s-%s-%s-*.apk" , arch , input , latestVersion )
657672 tmpFile , err := os .CreateTemp ("" , apkTempFileName )
@@ -665,6 +680,7 @@ func resolveInputForRemoteTarget(ctx context.Context, input string) (downloadedA
665680 return nil , nil , fmt .Errorf ("creating request for %q: %w" , downloadURL , err )
666681 }
667682
683+ auth .DefaultAuthenticators .AddAuth (ctx , req )
668684 logger .Debug ("downloading APK" , "url" , downloadURL )
669685 resp , err := http .DefaultClient .Do (req )
670686 if err != nil {
0 commit comments