create driver package for runtime

pull/1/head
Brad Rydzewski 5 years ago
parent 1b06beb63c
commit edde4db0f3

@ -1,60 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
import (
"context"
"github.com/drone/drone-go/drone"
"github.com/drone/runner-go/manifest"
"github.com/drone/runner-go/secret"
)
// CompilerArgs provides compiler arguments.
type CompilerArgs struct {
// Manifest provides the parsed manifest.
Manifest *manifest.Manifest
// Pipeline provides the parsed pipeline. This pipeline is
// the compiler source and is converted to the intermediate
// representation by the Compile method.
Pipeline manifest.Resource
// Build provides the compiler with stage information that
// is converted to environment variable format and passed to
// each pipeline step. It is also used to clone the commit.
Build *drone.Build
// Stage provides the compiler with stage information that
// is converted to environment variable format and passed to
// each pipeline step.
Stage *drone.Stage
// Repo provides the compiler with repo information. This
// repo information is converted to environment variable
// format and passed to each pipeline step. It is also used
// to clone the repository.
Repo *drone.Repo
// System provides the compiler with system information that
// is converted to environment variable format and passed to
// each pipeline step.
System *drone.System
// Netrc provides netrc parameters that can be used by the
// default clone step to authenticate to the remote
// repository.
Netrc *drone.Netrc
// Secret returns a named secret value that can be injected
// into the pipeline step.
Secret secret.Provider
}
// Compiler compiles the Yaml configuration file to an
// intermediate representation optimized for simple execution.
type Compiler interface {
Compile(context.Context, CompilerArgs) Spec
}

@ -2,7 +2,7 @@
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
package driver
import (
"bytes"

@ -2,7 +2,7 @@
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
package driver
import (
"bytes"

@ -2,14 +2,79 @@
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
// Package driver defines interfaces to be implemented by
// pipeline drivers as used by package runtime.
package driver
import (
"context"
"io"
"github.com/drone/drone-go/drone"
"github.com/drone/runner-go/manifest"
"github.com/drone/runner-go/secret"
)
type (
// CompilerArgs provides compiler arguments.
CompilerArgs struct {
// Manifest provides the parsed manifest.
Manifest *manifest.Manifest
// Pipeline provides the parsed pipeline. This pipeline is
// the compiler source and is converted to the intermediate
// representation by the Compile method.
Pipeline manifest.Resource
// Build provides the compiler with stage information that
// is converted to environment variable format and passed to
// each pipeline step. It is also used to clone the commit.
Build *drone.Build
// Stage provides the compiler with stage information that
// is converted to environment variable format and passed to
// each pipeline step.
Stage *drone.Stage
// Repo provides the compiler with repo information. This
// repo information is converted to environment variable
// format and passed to each pipeline step. It is also used
// to clone the repository.
Repo *drone.Repo
// System provides the compiler with system information that
// is converted to environment variable format and passed to
// each pipeline step.
System *drone.System
// Netrc provides netrc parameters that can be used by the
// default clone step to authenticate to the remote
// repository.
Netrc *drone.Netrc
// Secret returns a named secret value that can be injected
// into the pipeline step.
Secret secret.Provider
}
// Compiler compiles the Yaml configuration file to an
// intermediate representation optimized for simple execution.
Compiler interface {
Compile(context.Context, CompilerArgs) Spec
}
// LinterArgs provides linting arguments.
LinterArgs struct {
Build *drone.Build
Repo *drone.Repo
}
// Linter lints the Yaml configuration file and returns an
// error if one or more linting rules fails.
Linter interface {
Lint(context.Context, LinterArgs) error
}
// Engine is the interface that must be implemented by a
// pipeline execution engine.
Engine interface {

@ -12,6 +12,8 @@ import (
"github.com/drone/runner-go/environ"
"github.com/drone/runner-go/logger"
"github.com/drone/runner-go/pipeline"
"github.com/drone/runner-go/pipeline/runtime/driver"
"github.com/drone/runner-go/pipeline/runtime/internal/replacer"
"github.com/hashicorp/go-multierror"
"github.com/natessilva/dag"
@ -21,7 +23,7 @@ import (
// Execer executes the pipeline.
type Execer struct {
mu sync.Mutex
engine Engine
engine driver.Engine
reporter pipeline.Reporter
streamer pipeline.Streamer
sem *semaphore.Weighted
@ -31,7 +33,7 @@ type Execer struct {
func NewExecer(
reporter pipeline.Reporter,
streamer pipeline.Streamer,
engine Engine,
engine driver.Engine,
threads int64,
) *Execer {
exec := &Execer{
@ -49,7 +51,7 @@ func NewExecer(
// Exec executes the intermediate representation of the pipeline
// and returns an error if execution fails.
func (e *Execer) Exec(ctx context.Context, spec Spec, state *pipeline.State) error {
func (e *Execer) Exec(ctx context.Context, spec driver.Spec, state *pipeline.State) error {
defer e.engine.Destroy(noContext, spec)
if err := e.engine.Setup(noContext, spec); err != nil {
@ -90,7 +92,7 @@ func (e *Execer) Exec(ctx context.Context, spec Spec, state *pipeline.State) err
return result
}
func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec Spec, step Step) error {
func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec driver.Spec, step driver.Step) error {
var result error
select {
@ -129,14 +131,14 @@ func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec Spec, ste
return nil
case state.Cancelled():
return nil
case step.GetRunPolicy() == RunNever:
case step.GetRunPolicy() == driver.RunNever:
return nil
case step.GetRunPolicy() == RunAlways:
case step.GetRunPolicy() == driver.RunAlways:
break
case step.GetRunPolicy() == RunOnFailure && state.Failed() == false:
case step.GetRunPolicy() == driver.RunOnFailure && state.Failed() == false:
state.Skip(step.GetName())
return e.reporter.ReportStep(noContext, state, step.GetName())
case step.GetRunPolicy() == RunOnSuccess && state.Failed():
case step.GetRunPolicy() == driver.RunOnSuccess && state.Failed():
state.Skip(step.GetName())
return e.reporter.ReportStep(noContext, state, step.GetName())
}
@ -164,7 +166,7 @@ func (e *Execer) exec(ctx context.Context, state *pipeline.State, spec Spec, ste
// writer used to stream build logs.
wc := e.streamer.Stream(noContext, state, step.GetName())
wc = newReplacer(wc, secretSlice(step))
wc = replacer.New(wc, secretSlice(step))
// if the step is configured as a daemon, it is detached
// from the main process and executed separately.
@ -226,8 +228,8 @@ func findStep(state *pipeline.State, name string) *drone.Step {
// helper function returns an array of secrets from the
// pipeline step.
func secretSlice(step Step) []Secret {
var secrets []Secret
func secretSlice(step driver.Step) []driver.Secret {
var secrets []driver.Secret
for i := 0; i < step.GetSecretLen(); i++ {
secrets = append(secrets, step.GetSecretAt(i))
}

@ -2,4 +2,4 @@
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
package internal

@ -2,38 +2,46 @@
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime
// Package replacer provides helper functions to mask
// secrets in data streams.
package replacer
import (
"fmt"
"io"
"strings"
"github.com/drone/runner-go/pipeline/runtime/driver"
)
const maskedF = "[secret:%s]"
// replacer is an io.Writer that finds and masks sensitive data.
type replacer struct {
// Replacer is an io.Writer that finds and masks sensitive data.
type Replacer struct {
w io.WriteCloser
r *strings.Replacer
}
// newReplacer returns a replacer that wraps writer w.
func newReplacer(w io.WriteCloser, secrets []Secret) io.WriteCloser {
// New returns a replacer that wraps io.Writer w.
func New(w io.WriteCloser, secrets []driver.Secret) io.WriteCloser {
var oldnew []string
for _, secret := range secrets {
if len(secret.GetValue()) == 0 || secret.IsMasked() == false {
continue
}
name := strings.ToLower(secret.GetName())
masked := fmt.Sprintf(maskedF, name)
// name := strings.ToLower(secret.GetName())
// masked := fmt.Sprintf(maskedF, name)
// TODO temporarily revert back to masking secrets
// using the asterisk symbol due to confusion when
// masking with [secret:name]
masked := "******"
oldnew = append(oldnew, string(secret.GetValue()))
oldnew = append(oldnew, masked)
}
if len(oldnew) == 0 {
return w
}
return &replacer{
return &Replacer{
w: w,
r: strings.NewReplacer(oldnew...),
}
@ -41,12 +49,12 @@ func newReplacer(w io.WriteCloser, secrets []Secret) io.WriteCloser {
// Write writes p to the base writer. The method scans for any
// sensitive data in p and masks before writing.
func (r *replacer) Write(p []byte) (n int, err error) {
func (r *Replacer) Write(p []byte) (n int, err error) {
_, err = r.w.Write([]byte(r.r.Replace(string(p))))
return len(p), err
}
// Close closes the base writer.
func (r *replacer) Close() error {
func (r *Replacer) Close() error {
return r.w.Close()
}

@ -0,0 +1,64 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package replacer
import (
"bytes"
"io"
"testing"
"github.com/drone/runner-go/pipeline/runtime/driver"
)
func TestReplace(t *testing.T) {
secrets := []driver.Secret{
&secret{Name: "DOCKER_USERNAME", Data: "octocat", Mask: false},
&secret{Name: "DOCKER_PASSWORD", Data: "correct-horse-batter-staple", Mask: true},
&secret{Name: "DOCKER_EMAIL", Data: "", Mask: true},
}
buf := new(bytes.Buffer)
w := New(&nopCloser{buf}, secrets)
w.Write([]byte("username octocat password correct-horse-batter-staple"))
w.Close()
if got, want := buf.String(), "username octocat password ******"; got != want {
t.Errorf("Want masked string %s, got %s", want, got)
}
}
// this test verifies that if there are no secrets to scan and
// mask, the io.WriteCloser is returned as-is.
func TestReplaceNone(t *testing.T) {
secrets := []driver.Secret{
&secret{Name: "DOCKER_USERNAME", Data: "octocat", Mask: false},
&secret{Name: "DOCKER_PASSWORD", Data: "correct-horse-batter-staple", Mask: false},
}
buf := new(bytes.Buffer)
w := &nopCloser{buf}
r := New(w, secrets)
if w != r {
t.Errorf("Expect buffer returned with no replacer")
}
}
type nopCloser struct {
io.Writer
}
func (*nopCloser) Close() error {
return nil
}
type secret struct {
Name string
Data string
Mask bool
}
func (s *secret) GetName() string { return s.Name }
func (s *secret) GetValue() string { return s.Data }
func (s *secret) IsMasked() bool { return s.Mask }

@ -1,5 +0,0 @@
// Copyright 2019 Drone.IO Inc. All rights reserved.
// Use of this source code is governed by the Polyform License
// that can be found in the LICENSE file.
package runtime

@ -16,6 +16,7 @@ import (
"github.com/drone/runner-go/logger"
"github.com/drone/runner-go/manifest"
"github.com/drone/runner-go/pipeline"
"github.com/drone/runner-go/pipeline/runtime/driver"
"github.com/drone/runner-go/secret"
"github.com/drone/drone-go/drone"
@ -36,7 +37,7 @@ type Runner struct {
// Compiler is responsible for compiling the pipeline
// configuration to the intermediate representation.
Compiler Compiler
Compiler driver.Compiler
// Reporter reports pipeline status and logs back to the
// remote server.
@ -44,7 +45,7 @@ type Runner struct {
// Execer is responsible for executing intermediate
// representation of the pipeline and returns its results.
Exec func(context.Context, Spec, *pipeline.State) error
Exec func(context.Context, driver.Spec, *pipeline.State) error
// Lint is responsible for linting the pipeline
// and failing if any rules are broken.
@ -201,7 +202,7 @@ func (s *Runner) Run(ctx context.Context, stage *drone.Stage) error {
// compile the yaml configuration file to an intermediate
// representation, and then
args := CompilerArgs{
args := driver.CompilerArgs{
Pipeline: resource,
Manifest: manifest,
Build: data.Build,
@ -218,7 +219,7 @@ func (s *Runner) Run(ctx context.Context, stage *drone.Stage) error {
// steps that are skipped are ignored and are not stored
// in the drone database, nor displayed in the UI.
if src.GetRunPolicy() == RunNever {
if src.GetRunPolicy() == driver.RunNever {
continue
}
stage.Steps = append(stage.Steps, &drone.Step{
@ -226,7 +227,7 @@ func (s *Runner) Run(ctx context.Context, stage *drone.Stage) error {
Number: len(stage.Steps) + 1,
StageID: stage.ID,
Status: drone.StatusPending,
ErrIgnore: src.GetErrPolicy() == ErrIgnore,
ErrIgnore: src.GetErrPolicy() == driver.ErrIgnore,
})
}

Loading…
Cancel
Save