190 lines
5.8 KiB
Go
190 lines
5.8 KiB
Go
package config
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
|
|
)
|
|
|
|
func (c Config) Redacted() Config {
|
|
return redactConfig(cloneConfig(c))
|
|
}
|
|
|
|
func (c Config) RedactedSummaryPayload() any {
|
|
return c.Redacted()
|
|
}
|
|
|
|
func (e EffectiveConfig) RedactedSummaryPayload() any {
|
|
return EffectiveConfig{
|
|
Config: e.Config.Redacted(),
|
|
PipelineID: e.PipelineID,
|
|
Only: append([]string(nil), e.Only...),
|
|
ReferenceOverrides: append([]pipeline.ReferenceBinding(nil), e.ReferenceOverrides...),
|
|
ReferenceUnbinds: append([]pipeline.ReferenceUnbind(nil), e.ReferenceUnbinds...),
|
|
ResolvedPipeline: cloneResolvedPipeline(e.ResolvedPipeline),
|
|
}
|
|
}
|
|
|
|
func (e EffectiveConfig) RedactedResolvedPipelinePayload() pipeline.ResolvedPipeline {
|
|
return cloneResolvedPipeline(e.ResolvedPipeline)
|
|
}
|
|
|
|
func cloneResolvedPipeline(in pipeline.ResolvedPipeline) pipeline.ResolvedPipeline {
|
|
out := in
|
|
out.Input = redactBinding(cloneModuleBinding(in.Input))
|
|
out.Chunk = redactBinding(cloneModuleBinding(in.Chunk))
|
|
out.ChunkReferences = pipeline.CloneReferenceTarget(in.ChunkReferences)
|
|
out.Output = redactBinding(cloneModuleBinding(in.Output))
|
|
if len(in.ValidatorChains) > 0 {
|
|
out.ValidatorChains = make([]pipeline.ResolvedValidatorChain, len(in.ValidatorChains))
|
|
for i, chain := range in.ValidatorChains {
|
|
out.ValidatorChains[i] = cloneResolvedValidatorChain(chain)
|
|
}
|
|
}
|
|
if len(in.Steps) > 0 {
|
|
out.Steps = make([]pipeline.ResolvedPipelineStep, len(in.Steps))
|
|
for i, step := range in.Steps {
|
|
out.Steps[i] = pipeline.ResolvedPipelineStep{ID: step.ID}
|
|
if len(step.ArtifactLanes) > 0 {
|
|
out.Steps[i].ArtifactLanes = make([]pipeline.ResolvedArtifactLane, len(step.ArtifactLanes))
|
|
for j, lane := range step.ArtifactLanes {
|
|
out.Steps[i].ArtifactLanes[j] = cloneResolvedArtifactLane(lane)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func cloneResolvedValidatorChain(in pipeline.ResolvedValidatorChain) pipeline.ResolvedValidatorChain {
|
|
out := in
|
|
if len(in.Validators) > 0 {
|
|
out.Validators = make([]pipeline.ResolvedValidator, len(in.Validators))
|
|
for i, validator := range in.Validators {
|
|
out.Validators[i] = pipeline.ResolvedValidator{
|
|
Binding: redactBinding(cloneModuleBinding(validator.Binding)),
|
|
ExecutionClass: validator.ExecutionClass,
|
|
Target: validator.Target,
|
|
ArtifactKind: validator.ArtifactKind,
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func cloneResolvedArtifactLane(in pipeline.ResolvedArtifactLane) pipeline.ResolvedArtifactLane {
|
|
out := in
|
|
out.Extract = redactBinding(cloneModuleBinding(in.Extract))
|
|
out.Merge = redactBinding(cloneModuleBinding(in.Merge))
|
|
out.Normalize = redactBinding(cloneModuleBinding(in.Normalize))
|
|
out.ExtractReferences = pipeline.CloneReferenceTarget(in.ExtractReferences)
|
|
out.MergeReferences = pipeline.CloneReferenceTarget(in.MergeReferences)
|
|
out.NormalizeReferences = pipeline.CloneReferenceTarget(in.NormalizeReferences)
|
|
if len(in.Validators) > 0 {
|
|
out.Validators = make([]pipeline.ModuleBinding, len(in.Validators))
|
|
for i, binding := range in.Validators {
|
|
out.Validators[i] = redactBinding(cloneModuleBinding(binding))
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func redactConfig(cfg Config) Config {
|
|
for id, profile := range cfg.Pipelines {
|
|
profile.Input = redactBinding(profile.Input)
|
|
profile.Chunk = redactBinding(profile.Chunk)
|
|
profile.Output = redactBinding(profile.Output)
|
|
redactLanes := func(lanes map[string]pipeline.ArtifactLaneProfile) {
|
|
for laneID, lane := range lanes {
|
|
lane.Extract = redactBinding(lane.Extract)
|
|
lane.Merge = redactBinding(lane.Merge)
|
|
lane.Normalize = redactBinding(lane.Normalize)
|
|
for i := range lane.Validators {
|
|
lane.Validators[i] = redactBinding(lane.Validators[i])
|
|
}
|
|
lanes[laneID] = lane
|
|
}
|
|
}
|
|
redactLanes(profile.Artifacts)
|
|
for i := range profile.Steps {
|
|
redactLanes(profile.Steps[i].Artifacts)
|
|
}
|
|
cfg.Pipelines[id] = profile
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
func redactBinding(binding pipeline.ModuleBinding) pipeline.ModuleBinding {
|
|
binding.Options = redactOptions(binding.Options)
|
|
for i := range binding.Validators.Validators {
|
|
binding.Validators.Validators[i] = redactBinding(binding.Validators.Validators[i])
|
|
}
|
|
return binding
|
|
}
|
|
|
|
func redactOptions(values map[string]any) map[string]any {
|
|
if len(values) == 0 {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, len(values))
|
|
for key, value := range values {
|
|
if sensitiveConfigKey(key) {
|
|
out[key] = "[REDACTED]"
|
|
continue
|
|
}
|
|
out[key] = redactOptionValue(value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func redactOptionValue(value any) any {
|
|
if value == nil {
|
|
return nil
|
|
}
|
|
reflected := reflect.ValueOf(value)
|
|
switch reflected.Kind() {
|
|
case reflect.Map:
|
|
if reflected.Type().Key().Kind() != reflect.String {
|
|
return value
|
|
}
|
|
if reflected.IsNil() {
|
|
return nil
|
|
}
|
|
out := make(map[string]any, reflected.Len())
|
|
iterator := reflected.MapRange()
|
|
for iterator.Next() {
|
|
key := iterator.Key().String()
|
|
if sensitiveConfigKey(key) {
|
|
out[key] = "[REDACTED]"
|
|
continue
|
|
}
|
|
out[key] = redactOptionValue(iterator.Value().Interface())
|
|
}
|
|
return out
|
|
case reflect.Slice:
|
|
if reflected.IsNil() {
|
|
return nil
|
|
}
|
|
if reflected.Type().Elem().Kind() == reflect.Uint8 {
|
|
out := reflect.MakeSlice(reflected.Type(), reflected.Len(), reflected.Len())
|
|
reflect.Copy(out, reflected)
|
|
return out.Interface()
|
|
}
|
|
fallthrough
|
|
case reflect.Array:
|
|
items := make([]any, reflected.Len())
|
|
for i := 0; i < reflected.Len(); i++ {
|
|
items[i] = redactOptionValue(reflected.Index(i).Interface())
|
|
}
|
|
return items
|
|
default:
|
|
return value
|
|
}
|
|
}
|
|
|
|
func sensitiveConfigKey(key string) bool {
|
|
key = strings.ToLower(key)
|
|
return strings.Contains(key, "api_key") || strings.Contains(key, "apikey") || strings.Contains(key, "authorization") || strings.Contains(key, "bearer") || strings.Contains(key, "password") || strings.Contains(key, "secret") || strings.Contains(key, "token")
|
|
}
|