2022-01-05 04:27:54 +01:00
package task
import (
"context"
"errors"
2022-01-06 21:13:51 +01:00
"strings"
2022-01-05 04:27:54 +01:00
"cuelang.org/go/cue"
"github.com/rs/zerolog/log"
2022-01-06 21:13:51 +01:00
"github.com/sergi/go-diff/diffmatchpatch"
2022-01-05 04:27:54 +01:00
"go.dagger.io/dagger/compiler"
"go.dagger.io/dagger/plancontext"
"go.dagger.io/dagger/solver"
)
func init ( ) {
Register ( "TransformSecret" , func ( ) Task { return & transformSecretTask { } } )
}
type transformSecretTask struct {
}
func ( c * transformSecretTask ) Run ( ctx context . Context , pctx * plancontext . Context , _ solver . Solver , v * compiler . Value ) ( * compiler . Value , error ) {
lg := log . Ctx ( ctx )
lg . Debug ( ) . Msg ( "transforming secret" )
input := v . Lookup ( "input" )
inputSecret , err := pctx . Secrets . FromValue ( input )
if err != nil {
return nil , err
}
function := v . Lookup ( "#function" )
2022-01-06 21:13:51 +01:00
inputSecretPlaintext := inputSecret . PlainText ( )
err = function . FillPath ( cue . ParsePath ( "input" ) , inputSecretPlaintext )
2022-01-05 04:27:54 +01:00
if err != nil {
2022-01-06 21:13:51 +01:00
dmp := diffmatchpatch . New ( )
errStr := err . Error ( )
diffs := dmp . DiffMain ( inputSecretPlaintext , err . Error ( ) , false )
for _ , diff := range diffs {
if diff . Type == diffmatchpatch . DiffEqual {
2022-01-11 21:37:03 +01:00
// diffText := strings.ReplaceAll(diff.Text, ":", "") // colons are tricky. Yaml keys end with them but if a secret contained one that got replaced, the secret wouldn't get redacted
2022-01-13 23:21:30 +01:00
errStr = strings . ReplaceAll ( errStr , diff . Text , "***" )
2022-01-06 21:13:51 +01:00
}
}
return nil , errors . New ( errStr )
2022-01-05 04:27:54 +01:00
}
2022-01-26 00:10:39 +01:00
type pathSecret struct {
2022-01-26 00:49:27 +01:00
path cue . Path
secret * plancontext . Secret
2022-01-26 00:10:39 +01:00
}
var pathsSecrets [ ] pathSecret
2022-01-06 21:13:51 +01:00
// users could yaml.Unmarshal(input) and return a map
// or yaml.Unmarshal(input).someKey and return a string
// walk will ensure we convert every leaf
functionPathSelectors := function . Path ( ) . Selectors ( )
function . Lookup ( "output" ) . Walk ( nil , func ( v * compiler . Value ) {
if v . Kind ( ) == cue . StringKind {
plaintext , _ := v . String ( )
secret := pctx . Secrets . New ( plaintext )
newLeafSelectors := v . Path ( ) . Selectors ( ) [ len ( functionPathSelectors ) : ]
newLeafSelectors = append ( newLeafSelectors , cue . Str ( "contents" ) )
newLeafPath := cue . MakePath ( newLeafSelectors ... )
2022-01-26 00:49:27 +01:00
pathsSecrets = append ( pathsSecrets , pathSecret { newLeafPath , secret } )
2022-01-06 21:13:51 +01:00
}
2022-01-05 04:27:54 +01:00
} )
2022-01-06 21:13:51 +01:00
2022-01-26 00:10:39 +01:00
output := compiler . NewValue ( )
for _ , ps := range pathsSecrets {
2022-01-26 00:49:27 +01:00
output . FillPath ( ps . path , ps . secret . MarshalCUE ( ) )
2022-01-26 00:10:39 +01:00
}
2022-01-06 21:13:51 +01:00
return output , nil
2022-01-05 04:27:54 +01:00
}