Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/octobus/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func serve(opts serveOptions) error {
if err := startupInventory(ctx, logger, st); err != nil {
return err
}
adminServer := &admin.Server{Store: st, Importer: &packageimport.Importer{DataDir: dataDir, Store: st}, Supervisor: sup, Gateway: gateway, AccessLogPath: filepath.Join(dataDir, accesslog.FileName), Logger: logger}
adminServer := &admin.Server{Store: st, Importer: &packageimport.Importer{DataDir: dataDir, Store: st, RemoteTargetValidator: packageimport.DefaultRemoteTargetValidator}, Supervisor: sup, Gateway: gateway, AccessLogPath: filepath.Join(dataDir, accesslog.FileName), Logger: logger}
grpcServer := protocol.GRPCServer(gateway)
publicServer := admin.NewHTTPServer(opts.addr, h2c.NewHandler(server.CombinedHandler(adminServer.Handler(), grpcServer, gateway), &http2.Server{}))
publicListener, err := net.Listen("tcp", opts.addr)
Expand Down
37 changes: 31 additions & 6 deletions internal/packageimport/git_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,14 +219,29 @@ func (i *Importer) prepareGitSource(ctx context.Context, rawSource, staging stri
if err != nil {
return preparedSource{}, err
}
runner, err := newGitRunner(src, staging)
var gitProxy *validatedGitProxy
var proxyURL string
if i.RemoteTargetValidator != nil {
gitProxy, err = startValidatedGitProxy(ctx)
if err != nil {
return preparedSource{}, fmt.Errorf("start Git validation proxy: %w", err)
}
defer gitProxy.Close()
proxyURL = gitProxy.URL()
}
runner, err := newGitRunner(src, staging, proxyURL)
if err != nil {
return preparedSource{}, err
}
repoDir := filepath.Join(staging, "git")
if err := os.MkdirAll(repoDir, 0o755); err != nil {
return preparedSource{}, err
}
if i.RemoteTargetValidator != nil {
Comment thread
monkeyscan[bot] marked this conversation as resolved.
if err := i.RemoteTargetValidator(ctx, src.CredentialURL); err != nil {
return preparedSource{}, fmt.Errorf("validate Git remote: %w", err)
}
}
if err := runner.run(ctx, repoDir, "init", "--bare", "."); err != nil {
return preparedSource{}, err
}
Expand Down Expand Up @@ -271,11 +286,12 @@ func serviceRootOrDefault(serviceRoot string) string {
}

type gitRunner struct {
source gitSource
env []string
source gitSource
env []string
proxyURL string
}

func newGitRunner(src gitSource, staging string) (*gitRunner, error) {
func newGitRunner(src gitSource, staging string, proxyURL ...string) (*gitRunner, error) {
if _, err := exec.LookPath("git"); err != nil {
return nil, errors.New("git is required to import HTTPS Git sources; install git and ensure it is on PATH")
}
Expand All @@ -294,7 +310,11 @@ func newGitRunner(src gitSource, staging string) (*gitRunner, error) {
} else {
env = append(env, "GIT_TERMINAL_PROMPT=0")
}
return &gitRunner{source: src, env: env}, nil
runner := &gitRunner{source: src, env: env}
if len(proxyURL) > 0 {
runner.proxyURL = proxyURL[0]
}
return runner, nil
}

func writeGitAskpass(staging string, src gitSource) (string, error) {
Expand All @@ -318,7 +338,12 @@ func (r *gitRunner) run(ctx context.Context, dir string, args ...string) error {
}

func (r *gitRunner) output(ctx context.Context, dir string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, "git", args...)
gitArgs := []string{"-c", "http.followRedirects=false"}
if r.proxyURL != "" {
gitArgs = append(gitArgs, "-c", "http.proxy="+r.proxyURL)
}
gitArgs = append(gitArgs, args...)
cmd := exec.CommandContext(ctx, "git", gitArgs...)
cmd.Dir = dir
cmd.Env = r.env
var out strings.Builder
Expand Down
40 changes: 8 additions & 32 deletions internal/packageimport/importer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"fmt"
"io"
"io/fs"
"net/http"
"net/url"
"os"
"os/exec"
Expand All @@ -27,6 +26,11 @@ import (
type Importer struct {
DataDir string
Store *store.Store

// RemoteTargetValidator is configured by the daemon to enforce the
// network policy for server-side remote imports. Tests and local-only
// importers may leave it unset.
RemoteTargetValidator func(context.Context, string) error
}

type Options struct {
Expand Down Expand Up @@ -608,7 +612,7 @@ func (i *Importer) prepareSource(ctx context.Context, opts Options, staging stri
prepared.ServiceRoot = serviceRoot
return prepared, nil
case sourceRemoteArchive:
return prepareRemoteArchiveSource(ctx, source, serviceRoot, staging)
return i.prepareRemoteArchiveSource(ctx, source, serviceRoot, staging)
case sourceHTTPSGit:
return i.prepareGitSource(ctx, opts.Source, staging)
case sourceUnsupportedGit:
Expand Down Expand Up @@ -771,13 +775,13 @@ func hashFile(path string) (string, error) {
return domain.HashBytes(b), nil
}

func prepareRemoteArchiveSource(ctx context.Context, source, serviceRoot, staging string) (preparedSource, error) {
func (i *Importer) prepareRemoteArchiveSource(ctx context.Context, source, serviceRoot, staging string) (preparedSource, error) {
artifactName, err := remoteArchiveArtifactName(source)
if err != nil {
return preparedSource{}, err
}
artifactPath := filepath.Join(staging, artifactName)
if err := downloadRemoteArchive(ctx, source, artifactPath); err != nil {
if err := downloadRemoteArchive(ctx, source, artifactPath, i.RemoteTargetValidator); err != nil {
return preparedSource{}, err
}
packageDir := filepath.Join(staging, "package")
Expand Down Expand Up @@ -819,34 +823,6 @@ func remoteArchiveArtifactName(source string) (string, error) {
return "", fmt.Errorf("unsupported remote package source %q: must end with .tgz, .tar.gz, or .zip", redactedRemoteArchiveSource(source))
}

func downloadRemoteArchive(ctx context.Context, source, artifactPath string) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, source, nil)
if err != nil {
return fmt.Errorf("download remote package %q: %w", redactedRemoteArchiveSource(source), err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("download remote package %q: %w", redactedRemoteArchiveSource(source), err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("download remote package %q: HTTP %d", redactedRemoteArchiveSource(source), resp.StatusCode)
}
if err := os.MkdirAll(filepath.Dir(artifactPath), 0o755); err != nil {
return err
}
out, err := os.OpenFile(artifactPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
if err != nil {
return err
}
_, copyErr := io.Copy(out, resp.Body)
closeErr := out.Close()
if copyErr != nil {
return copyErr
}
return closeErr
}

func redactedRemoteArchiveSource(source string) string {
u, err := url.Parse(source)
if err != nil {
Expand Down
Loading
Loading