Skip to content
Open
Show file tree
Hide file tree
Changes from all 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, i.RemoteTargetValidator)
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