Skip to content

Commit

Permalink
Provide read-only modes of using git
Browse files Browse the repository at this point in the history
For the helm operator (and in some places in fluxd) we need only
read-only access to the git repo. Indeed in some deployments, the helm
operator will be given a read-only SSH key.

So: give the git mirroring (git.Repo) a read-only option, which means
it will

 - consider itself ready when it's been cloned, without checking
   whether it can write to the upstream repo;
 - not let you make a working clone (because it's assumed you won't be
   able to push commits from it)

We still need a way to get a copy of the repo, so the helm operator
can look at the files. For that purpose, add a bare-bones type
`git.Export`, with which all you can do is get the directory it's been
cloned to.
  • Loading branch information
squaremo committed Jul 19, 2018
1 parent 40f537c commit 44a3a27
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 10 deletions.
29 changes: 29 additions & 0 deletions git/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package git

import (
"context"
"os"
)

type Export struct {
dir string
}

func (e *Export) Dir() string {
return e.dir
}

func (e *Export) Clean() {
if e.dir != "" {
os.RemoveAll(e.dir)
}
}

// Export creates a minimal clone of the repo, at the ref given.
func (r *Repo) Export(ctx context.Context, ref string) (*Export, error) {
dir, err := r.workingClone(ctx, ref)
if err != nil {
return nil, err
}
return &Export{dir}, nil
}
35 changes: 25 additions & 10 deletions git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Repo struct {
// As supplied to constructor
origin Remote
interval time.Duration
readonly bool

// State
mu sync.RWMutex
Expand All @@ -69,12 +70,22 @@ type Option interface {
apply(*Repo)
}

type optionFunc func(*Repo)

func (f optionFunc) apply(r *Repo) {
f(r)
}

type PollInterval time.Duration

func (p PollInterval) apply(r *Repo) {
r.interval = time.Duration(p)
}

var ReadOnly optionFunc = func(r *Repo) {
r.readonly = true
}

// NewRepo constructs a repo mirror which will sync itself.
func NewRepo(origin Remote, opts ...Option) *Repo {
status := RepoNew
Expand Down Expand Up @@ -253,17 +264,21 @@ func (r *Repo) Start(shutdown <-chan struct{}, done *sync.WaitGroup) error {
r.setUnready(RepoNew, err)

case RepoCloned:
ctx, cancel := context.WithTimeout(bg, opTimeout)
err := checkPush(ctx, dir, url)
cancel()
if err == nil {
r.setReady()
// Treat every transition to ready as a refresh, so
// that any listeners can respond in the same way.
r.refreshed()
continue // with new status, skipping timer
if !r.readonly {
ctx, cancel := context.WithTimeout(bg, opTimeout)
err := checkPush(ctx, dir, url)
cancel()
if err != nil {
r.setUnready(RepoCloned, err)
break
}
}
r.setUnready(RepoCloned, err)

r.setReady()
// Treat every transition to ready as a refresh, so
// that any listeners can respond in the same way.
r.refreshed()
continue // with new status, skipping timer

case RepoReady:
if err := r.refreshLoop(shutdown); err != nil {
Expand Down
9 changes: 9 additions & 0 deletions git/working.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ package git

import (
"context"
"errors"
"os"
"path/filepath"
)

var (
ErrReadOnly = errors.New("cannot make a working clone of a read-only git repo")
)

// Config holds some values we use when working in the working clone of
// a repo.
type Config struct {
Expand Down Expand Up @@ -43,6 +48,10 @@ type CommitAction struct {
// Clone returns a local working clone of the sync'ed `*Repo`, using
// the config given.
func (r *Repo) Clone(ctx context.Context, conf Config) (*Checkout, error) {
if r.readonly {
return nil, ErrReadOnly
}

upstream := r.Origin()
repoDir, err := r.workingClone(ctx, conf.Branch)
if err != nil {
Expand Down

0 comments on commit 44a3a27

Please sign in to comment.