Publish detached sanitized source evidence
This commit is contained in:
@@ -63,8 +63,9 @@ func WriteDiagnostics(output io.Writer, diagnostics []Diagnostic) error {
|
||||
}
|
||||
|
||||
type diagnosticAccumulator struct {
|
||||
diagnostics []Diagnostic
|
||||
sources []SourceInfo
|
||||
diagnostics []Diagnostic
|
||||
sources []SourceInfo
|
||||
versionState *sourceVersionState
|
||||
}
|
||||
|
||||
func (a *diagnosticAccumulator) add(diagnostics ...Diagnostic) {
|
||||
@@ -74,9 +75,13 @@ func (a *diagnosticAccumulator) add(diagnostics ...Diagnostic) {
|
||||
}
|
||||
|
||||
func (a *diagnosticAccumulator) loadError() *LoadError {
|
||||
sources := a.sources
|
||||
if a.versionState != nil {
|
||||
sources = sourceInfosWithVersionEvidence(sources, a.versionState.evidence, nil, true)
|
||||
}
|
||||
return &LoadError{
|
||||
diagnostics: canonicalDiagnostics(a.diagnostics),
|
||||
sources: cloneSourceInfos(a.sources),
|
||||
sources: cloneSourceInfos(sources),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -173,6 +173,7 @@ func executeLoadRequest[T any](request loadRequest[T], secrets SecretBinding, lo
|
||||
versionState := &sourceVersionState{
|
||||
localRule: request.definition.Version, effectiveRule: request.protectionVersion(), mode: request.sourceVersionMode,
|
||||
}
|
||||
accumulator.versionState = versionState
|
||||
input, diagnostics := assembleBaseInputTrackedWithVersion(request.main.source, mainOptions, request.main.destination, accounting, nil, nil, versionState)
|
||||
accumulator.sources = input.sources
|
||||
accumulator.add(versionState.diagnostics...)
|
||||
|
||||
@@ -37,7 +37,7 @@ func assembleBaseInputTrackedForRole[T any](source Source, options Options[T], d
|
||||
if parsed.source != nil {
|
||||
parsed.source.Destination = destination.clone()
|
||||
}
|
||||
input := assembledInput{parsed: parsed, document: parsed.document, versionState: versionState}
|
||||
input := assembledInput{parsed: parsed, document: parsed.document, sources: sourceInfos(parsed.source), versionState: versionState}
|
||||
if len(diagnostics) != 0 {
|
||||
input.sources = sourceInfos(parsed.source)
|
||||
// Mapping value issues already identify application content. Other early
|
||||
|
||||
@@ -58,7 +58,11 @@ func resolveLoadInput[T any](schema *schemaDescriptor, definition Definition[T],
|
||||
final := decoded.final
|
||||
var resolutionSnapshots []resolutionSnapshot
|
||||
if definition.Resolve != nil {
|
||||
entry := newResolutionInput(metadata, decoded.final, input.sources, input.contexts)
|
||||
sources := input.sources
|
||||
if input.versionState != nil {
|
||||
sources = sourceInfosWithVersionEvidence(sources, input.versionState.evidence, nil, true)
|
||||
}
|
||||
entry := newResolutionInput(metadata, decoded.final, sources, input.contexts)
|
||||
resolved := runResolution(&configuration, definition.Resolve, schema, decoded, input.document, entry)
|
||||
diagnostics = append(diagnostics, resolved.diagnostics...)
|
||||
if hasErrors(resolved.diagnostics) {
|
||||
@@ -103,6 +107,7 @@ func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T]
|
||||
final, applications, resolutionSnapshots := resolved.final, resolved.applications, resolved.snapshots
|
||||
finalizeMetadataPaths(&metadata, final, applications, decoded.baseline, decoded.final)
|
||||
secrets := classifySecretPathsWithEvidence(schema, definition.Secret, metadata, final, applications, resolved.versionEvidence, decoded.baseline, decoded.final)
|
||||
sources := sourceInfosWithVersionEvidence(accumulator.sources, resolved.versionEvidence, secrets, false)
|
||||
retainedTrees := make([]*document.Node, 0, len(applications)+2)
|
||||
retainedTrees = append(retainedTrees, decoded.final, final)
|
||||
for _, application := range applications {
|
||||
@@ -110,7 +115,7 @@ func publishLoadResult[T any](schema *schemaDescriptor, definition Definition[T]
|
||||
}
|
||||
inspection := &Inspection{
|
||||
metadata: metadata,
|
||||
sources: cloneSourceInfos(accumulator.sources),
|
||||
sources: sources,
|
||||
contexts: cloneResourceContexts(resolved.contexts),
|
||||
diagnostics: canonicalDiagnostics(accumulator.diagnostics),
|
||||
baseline: decoded.baseline,
|
||||
|
||||
@@ -191,9 +191,19 @@ type SourceInfo struct {
|
||||
Kind SourceKind
|
||||
UnderlayIndex int
|
||||
ImportedFrom *Location
|
||||
VersionCheck *SourceVersionCheck
|
||||
namespace *namespaceToken
|
||||
}
|
||||
|
||||
// SourceVersionCheck is a detached, public-safe record of a source-local
|
||||
// version declaration observed during an enabled load.
|
||||
type SourceVersionCheck struct {
|
||||
Path Path
|
||||
Version Version
|
||||
Location *Location
|
||||
Redacted bool
|
||||
}
|
||||
|
||||
// Diagnostic is a safe structured problem report. Message and source labels must
|
||||
// never contain configuration values or other secrets.
|
||||
type Diagnostic struct {
|
||||
@@ -262,9 +272,20 @@ func cloneLocations(locations []Location) []Location {
|
||||
func cloneSourceInfo(source SourceInfo) SourceInfo {
|
||||
source.ImportedFrom = cloneLocation(source.ImportedFrom)
|
||||
source.Destination = source.Destination.clone()
|
||||
source.VersionCheck = cloneSourceVersionCheck(source.VersionCheck)
|
||||
return source
|
||||
}
|
||||
|
||||
func cloneSourceVersionCheck(value *SourceVersionCheck) *SourceVersionCheck {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
cloned := *value
|
||||
cloned.Path = value.Path.clone()
|
||||
cloned.Location = cloneLocation(value.Location)
|
||||
return &cloned
|
||||
}
|
||||
|
||||
func cloneSourceInfos(sources []SourceInfo) []SourceInfo {
|
||||
if sources == nil {
|
||||
return nil
|
||||
|
||||
@@ -51,6 +51,46 @@ type sourceVersionState struct {
|
||||
diagnostics []Diagnostic
|
||||
}
|
||||
|
||||
func sourceInfosWithVersionEvidence(sources []SourceInfo, evidence []*sourceVersionEvidence, secrets map[string]bool, conservative bool) []SourceInfo {
|
||||
result := cloneSourceInfos(sources)
|
||||
if len(evidence) == 0 {
|
||||
return result
|
||||
}
|
||||
sensitivity := newDiffSensitivity(secrets, nil)
|
||||
for _, item := range evidence {
|
||||
if item == nil || item.sourceID == "" {
|
||||
continue
|
||||
}
|
||||
for index := range result {
|
||||
if result[index].ID == item.sourceID {
|
||||
result[index].VersionCheck = sourceVersionCheckForEvidence(item, sensitivity, conservative)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func sourceVersionCheckForEvidence(evidence *sourceVersionEvidence, sensitivity *diffSensitivity, conservative bool) *SourceVersionCheck {
|
||||
path := evidence.resolvedPath
|
||||
if !path.valid() {
|
||||
path = evidence.path
|
||||
}
|
||||
version := evidence.version
|
||||
redacted := evidence.redacted
|
||||
if conservative {
|
||||
redacted = redacted || version.Text != ""
|
||||
} else if sensitivity.isSensitiveAtOrAbove(appendDestination(evidence.destination, path).String()) {
|
||||
redacted = true
|
||||
}
|
||||
if redacted {
|
||||
version.Text = ""
|
||||
}
|
||||
return &SourceVersionCheck{
|
||||
Path: path.clone(), Version: version, Location: cloneLocation(evidence.location), Redacted: redacted,
|
||||
}
|
||||
}
|
||||
|
||||
func (state *sourceVersionState) process(root *document.Node, role sourceVersionRole, destination Path, sourceID string) (sourceVersionProcessingResult, []Diagnostic) {
|
||||
if state == nil || state.mode == sourceVersionModeDefault {
|
||||
return sourceVersionProcessingResult{}, nil
|
||||
|
||||
Reference in New Issue
Block a user