chore: use Docker Desktop proxy if available

used with ATOMIST_OFFLINE flag it allows to have all requests going
through the configured proxy if any

Signed-off-by: Yves Brissaud <yves.brissaud@docker.com>
This commit is contained in:
Yves Brissaud 2023-02-08 11:30:46 +01:00
Родитель 00c5852290
Коммит 25765fd3ce
Не найден ключ, соответствующий данной подписи
8 изменённых файлов: 115 добавлений и 17 удалений

2
go.mod
Просмотреть файл

@ -3,6 +3,7 @@ module github.com/docker/index-cli-plugin
go 1.19
require (
github.com/Microsoft/go-winio v0.5.2
github.com/anchore/packageurl-go v0.1.1-0.20220428202044-a072fa3cb6d7
github.com/anchore/stereoscope v0.0.0-20221006201143-d24c9d626b33
github.com/anchore/syft v0.62.1
@ -46,7 +47,6 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.5 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895 // indirect
github.com/acobaugh/osrelease v0.1.0 // indirect

53
internal/ddhttp/ddhttp.go Normal file
Просмотреть файл

@ -0,0 +1,53 @@
package ddhttp
import (
"context"
"net"
"net/http"
"net/url"
)
var transport http.RoundTripper
func init() {
// Check if we can discuss with the proxy socket from Docker Desktop.
// If we can, it doesn't necessarily mean there a configured proxy.
// But we delegate that management to Docker Desktop: if the socket is open, we connect to it. Docker Desktop can
// then send the requests to a proxy or not, but that's Docker Desktop scope.
// If we can't connect to the socket, then just use plain default transport.
if !isDesktopHTTPProxyAvailable() {
transport = http.DefaultTransport
return
}
transport = &http.Transport{
Proxy: http.ProxyURL(&url.URL{
Scheme: "http",
}),
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return dialDesktopHTTPProxy()
},
}
}
func isDesktopHTTPProxyAvailable() bool {
c, err := dialDesktopHTTPProxy()
if err != nil {
return false
}
_ = c.Close()
return true
}
func DefaultClient() *http.Client {
return &http.Client{
Transport: transport,
}
}
func DefaultTransport() *http.Transport {
if t, ok := transport.(*http.Transport); ok {
return t
}
panic("could not get transport")
}

Просмотреть файл

@ -0,0 +1,16 @@
package ddhttp
import (
"net"
"os/user"
"path"
)
func dialDesktopHTTPProxy() (net.Conn, error) {
current, err := user.Current()
if err != nil {
return nil, err
}
socket := path.Join(current.HomeDir, "Library/Containers/com.docker.docker/Data/httpproxy.sock")
return net.Dial("unix", socket)
}

Просмотреть файл

@ -0,0 +1,16 @@
package ddhttp
import (
"net"
"os/user"
"path"
)
func dialDesktopHTTPProxy() (net.Conn, error) {
current, err := user.Current()
if err != nil {
return nil, err
}
socket := path.Join(current.HomeDir, ".docker/desktop/httpproxy.sock")
return net.Dial("unix", socket)
}

Просмотреть файл

@ -0,0 +1,13 @@
package ddhttp
import (
"net"
"time"
"github.com/Microsoft/go-winio"
)
func dialDesktopHTTPProxy() (net.Conn, error) {
timeout := time.Second
return winio.DialPipe(`\\.\pipe\dockerHTTPProxy`, &timeout)
}

Просмотреть файл

@ -22,7 +22,6 @@ import (
"encoding/json"
"fmt"
"io"
"net/http"
"sort"
"strings"
@ -34,7 +33,7 @@ import (
"olympos.io/encoding/edn"
"github.com/atomist-skills/go-skill"
"github.com/docker/index-cli-plugin/internal/ddhttp"
"github.com/docker/index-cli-plugin/types"
)
@ -94,7 +93,7 @@ func Detect(sb *types.Sbom, excludeSelf bool, workspace string, apiKey string) (
func ForBaseImageInIndex(digest digest.Digest, workspace string, apiKey string) (*[]types.Image, error) {
url := fmt.Sprintf("https://api.dso.docker.com/docker-images/chain-ids/%s.json", digest.String())
resp, err := http.Get(url)
resp, err := ddhttp.DefaultClient().Get(url)
if err != nil {
return nil, errors.Wrapf(err, "failed to query index")
}
@ -243,7 +242,7 @@ func ForBaseImageInGraphQL(cfg *v1.ConfigFile) (*types.BaseImagesByDiffIdsQuery,
}
url := "https://api.dso.docker.com/v1/graphql"
client := graphql.NewClient(url, nil)
client := graphql.NewClient(url, ddhttp.DefaultClient())
variables := map[string]interface{}{
"diffIds": diffIds,
}
@ -270,7 +269,7 @@ func ForBaseImageInGraphQL(cfg *v1.ConfigFile) (*types.BaseImagesByDiffIdsQuery,
func ForImageInGraphQL(sb *types.Sbom) (*types.ImageByDigestQuery, error) {
url := "https://api.dso.docker.com/v1/graphql"
client := graphql.NewClient(url, nil)
client := graphql.NewClient(url, ddhttp.DefaultClient())
variables := map[string]interface{}{
"digest": sb.Source.Image.Digest,
"os": sb.Source.Image.Platform.Os,

Просмотреть файл

@ -24,14 +24,13 @@ import (
"strings"
"github.com/hasura/go-graphql-client"
"github.com/docker/index-cli-plugin/internal"
"github.com/docker/index-cli-plugin/types"
"github.com/pkg/errors"
"olympos.io/encoding/edn"
"github.com/atomist-skills/go-skill"
"github.com/docker/index-cli-plugin/internal"
"github.com/docker/index-cli-plugin/internal/ddhttp"
"github.com/docker/index-cli-plugin/types"
)
type CveResult struct {
@ -115,7 +114,7 @@ func query(query string, name string, workspace string, apiKey string) (*http.Re
}
query = fmt.Sprintf(`{:queries [{:name "query" :query %s}]}`, query)
skill.Log.Debugf("Query %s", query)
client := &http.Client{}
client := ddhttp.DefaultClient()
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(query))
if err != nil {
return nil, errors.Wrapf(err, "failed to create http request")
@ -139,7 +138,7 @@ func query(query string, name string, workspace string, apiKey string) (*http.Re
func ForVulnerabilitiesInGraphQL(sb *types.Sbom) (*types.VulnerabilitiesByPurls, error) {
url := "https://api.dso.docker.com/v1/graphql"
client := graphql.NewClient(url, nil)
client := graphql.NewClient(url, ddhttp.DefaultClient())
purls := make([]string, 0)
for _, p := range sb.Artifacts {

Просмотреть файл

@ -26,10 +26,6 @@ import (
stereoscopeimage "github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/syft/source"
"github.com/atomist-skills/go-skill"
"github.com/docker/cli/cli/command"
"github.com/docker/distribution/reference"
"github.com/docker/index-cli-plugin/internal"
"github.com/dustin/go-humanize"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
@ -41,6 +37,12 @@ import (
"github.com/google/go-containerregistry/pkg/v1/tarball"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/atomist-skills/go-skill"
"github.com/docker/cli/cli/command"
"github.com/docker/distribution/reference"
"github.com/docker/index-cli-plugin/internal"
"github.com/docker/index-cli-plugin/internal/ddhttp"
)
type ImageId struct {
@ -287,7 +289,7 @@ func SaveImage(image string, username string, password string, cli command.Cli)
}, nil
}
// try remote image next
desc, err := remote.Get(ref, WithAuth(username, password))
desc, err := remote.Get(ref, WithAuth(username, password), remote.WithTransport(ddhttp.DefaultTransport()))
if err != nil {
return nil, errors.Wrapf(err, "failed to pull image: %s", image)
}