mirror of
https://github.com/go-task/task.git
synced 2025-11-23 22:24:45 +02:00
feat: checksum pinning (#2223)
This commit is contained in:
@@ -24,6 +24,7 @@ type (
|
||||
AdvancedImport bool
|
||||
Vars *Vars
|
||||
Flatten bool
|
||||
Checksum string
|
||||
}
|
||||
// Includes is an ordered map of namespaces to includes.
|
||||
Includes struct {
|
||||
@@ -165,6 +166,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
||||
Aliases []string
|
||||
Excludes []string
|
||||
Vars *Vars
|
||||
Checksum string
|
||||
}
|
||||
if err := node.Decode(&includedTaskfile); err != nil {
|
||||
return errors.NewTaskfileDecodeError(err, node)
|
||||
@@ -178,6 +180,7 @@ func (include *Include) UnmarshalYAML(node *yaml.Node) error {
|
||||
include.AdvancedImport = true
|
||||
include.Vars = includedTaskfile.Vars
|
||||
include.Flatten = includedTaskfile.Flatten
|
||||
include.Checksum = includedTaskfile.Checksum
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -200,5 +203,7 @@ func (include *Include) DeepCopy() *Include {
|
||||
AdvancedImport: include.AdvancedImport,
|
||||
Vars: include.Vars.DeepCopy(),
|
||||
Flatten: include.Flatten,
|
||||
Aliases: deepcopy.Slice(include.Aliases),
|
||||
Checksum: include.Checksum,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ type Node interface {
|
||||
Parent() Node
|
||||
Location() string
|
||||
Dir() string
|
||||
Checksum() string
|
||||
Verify(checksum string) bool
|
||||
ResolveEntrypoint(entrypoint string) (string, error)
|
||||
ResolveDir(dir string) (string, error)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,9 @@ type (
|
||||
// designed to be embedded in other node types so that this boilerplate code
|
||||
// does not need to be repeated.
|
||||
baseNode struct {
|
||||
parent Node
|
||||
dir string
|
||||
parent Node
|
||||
dir string
|
||||
checksum string
|
||||
}
|
||||
)
|
||||
|
||||
@@ -32,6 +33,12 @@ func WithParent(parent Node) NodeOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithChecksum(checksum string) NodeOption {
|
||||
return func(node *baseNode) {
|
||||
node.checksum = checksum
|
||||
}
|
||||
}
|
||||
|
||||
func (node *baseNode) Parent() Node {
|
||||
return node.parent
|
||||
}
|
||||
@@ -39,3 +46,11 @@ func (node *baseNode) Parent() Node {
|
||||
func (node *baseNode) Dir() string {
|
||||
return node.dir
|
||||
}
|
||||
|
||||
func (node *baseNode) Checksum() string {
|
||||
return node.checksum
|
||||
}
|
||||
|
||||
func (node *baseNode) Verify(checksum string) bool {
|
||||
return node.checksum == "" || node.checksum == checksum
|
||||
}
|
||||
|
||||
@@ -250,6 +250,7 @@ func (r *Reader) include(ctx context.Context, node Node) error {
|
||||
AdvancedImport: include.AdvancedImport,
|
||||
Excludes: include.Excludes,
|
||||
Vars: include.Vars,
|
||||
Checksum: include.Checksum,
|
||||
}
|
||||
if err := cache.Err(); err != nil {
|
||||
return err
|
||||
@@ -267,6 +268,7 @@ func (r *Reader) include(ctx context.Context, node Node) error {
|
||||
|
||||
includeNode, err := NewNode(entrypoint, include.Dir, r.insecure,
|
||||
WithParent(node),
|
||||
WithChecksum(include.Checksum),
|
||||
)
|
||||
if err != nil {
|
||||
if include.Optional {
|
||||
@@ -362,7 +364,24 @@ func (r *Reader) readNodeContent(ctx context.Context, node Node) ([]byte, error)
|
||||
if node, isRemote := node.(RemoteNode); isRemote {
|
||||
return r.readRemoteNodeContent(ctx, node)
|
||||
}
|
||||
return node.Read()
|
||||
|
||||
// Read the Taskfile
|
||||
b, err := node.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the given checksum doesn't match the sum pinned in the Taskfile
|
||||
checksum := checksum(b)
|
||||
if !node.Verify(checksum) {
|
||||
return nil, &errors.TaskfileDoesNotMatchChecksum{
|
||||
URI: node.Location(),
|
||||
ExpectedChecksum: node.Checksum(),
|
||||
ActualChecksum: checksum,
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (r *Reader) readRemoteNodeContent(ctx context.Context, node RemoteNode) ([]byte, error) {
|
||||
@@ -427,17 +446,29 @@ func (r *Reader) readRemoteNodeContent(ctx context.Context, node RemoteNode) ([]
|
||||
}
|
||||
|
||||
r.debugf("found remote file at %q\n", node.Location())
|
||||
checksum := checksum(downloadedBytes)
|
||||
prompt := cache.ChecksumPrompt(checksum)
|
||||
|
||||
// Prompt the user if required
|
||||
if prompt != "" {
|
||||
if err := func() error {
|
||||
r.promptMutex.Lock()
|
||||
defer r.promptMutex.Unlock()
|
||||
return r.promptf(prompt, node.Location())
|
||||
}(); err != nil {
|
||||
return nil, &errors.TaskfileNotTrustedError{URI: node.Location()}
|
||||
// If the given checksum doesn't match the sum pinned in the Taskfile
|
||||
checksum := checksum(downloadedBytes)
|
||||
if !node.Verify(checksum) {
|
||||
return nil, &errors.TaskfileDoesNotMatchChecksum{
|
||||
URI: node.Location(),
|
||||
ExpectedChecksum: node.Checksum(),
|
||||
ActualChecksum: checksum,
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no manual checksum pin, run the automatic checks
|
||||
if node.Checksum() == "" {
|
||||
// Prompt the user if required
|
||||
prompt := cache.ChecksumPrompt(checksum)
|
||||
if prompt != "" {
|
||||
if err := func() error {
|
||||
r.promptMutex.Lock()
|
||||
defer r.promptMutex.Unlock()
|
||||
return r.promptf(prompt, node.Location())
|
||||
}(); err != nil {
|
||||
return nil, &errors.TaskfileNotTrustedError{URI: node.Location()}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user