diff --git a/core/aggregate/privilegebudget/budget.go b/core/aggregate/privilegebudget/budget.go index b4199fb..f7b8777 100644 --- a/core/aggregate/privilegebudget/budget.go +++ b/core/aggregate/privilegebudget/budget.go @@ -171,8 +171,8 @@ func mergeAgentContext(current, incoming agginventory.Agent, key string) agginve merged.BindingEvidenceKeys = dedupeSorted(append(append([]string(nil), merged.BindingEvidenceKeys...), incoming.BindingEvidenceKeys...)) merged.MissingBindings = dedupeSorted(append(append([]string(nil), merged.MissingBindings...), incoming.MissingBindings...)) merged.DeploymentStatus = mergeDeploymentStatus(merged.DeploymentStatus, incoming.DeploymentStatus) - merged.DeploymentArtifacts = dedupeSorted(append(append([]string(nil), merged.DeploymentArtifacts...), incoming.DeploymentArtifacts...)) - merged.DeploymentEvidenceKeys = dedupeSorted(append(append([]string(nil), merged.DeploymentEvidenceKeys...), incoming.DeploymentEvidenceKeys...)) + merged.DeploymentArtifacts = dedupeSortedPreserveCase(append(append([]string(nil), merged.DeploymentArtifacts...), incoming.DeploymentArtifacts...)) + merged.DeploymentEvidenceKeys = dedupeSortedPreserveCase(append(append([]string(nil), merged.DeploymentEvidenceKeys...), incoming.DeploymentEvidenceKeys...)) return merged } @@ -368,6 +368,27 @@ func dedupeSorted(in []string) []string { return out } +func dedupeSortedPreserveCase(in []string) []string { + if len(in) == 0 { + return nil + } + seen := map[string]struct{}{} + out := make([]string, 0, len(in)) + for _, item := range in { + trimmed := strings.TrimSpace(item) + if trimmed == "" { + continue + } + if _, exists := seen[trimmed]; exists { + continue + } + seen[trimmed] = struct{}{} + out = append(out, trimmed) + } + sort.Strings(out) + return out +} + func normalizeToken(in string) string { return strings.ToLower(strings.TrimSpace(in)) } diff --git a/core/aggregate/privilegebudget/budget_test.go b/core/aggregate/privilegebudget/budget_test.go index 48c7ef1..935411d 100644 --- a/core/aggregate/privilegebudget/budget_test.go +++ b/core/aggregate/privilegebudget/budget_test.go @@ -226,8 +226,8 @@ func TestBuildIncludesAgentLayerContextDeterministically(t *testing.T) { BindingEvidenceKeys: []string{"tool:deploy.write", "data:warehouse.events", "auth:oauth2"}, MissingBindings: []string{}, DeploymentStatus: "deployed", - DeploymentArtifacts: []string{".github/workflows/release.yml"}, - DeploymentEvidenceKeys: []string{"deployment:.github/workflows/release.yml"}, + DeploymentArtifacts: []string{".github/workflows/Release.yml"}, + DeploymentEvidenceKeys: []string{"deployment:.github/workflows/Release.yml"}, }, } @@ -274,8 +274,8 @@ func TestBuildResolvesInstanceScopedAgentContextForToolEntries(t *testing.T) { BoundDataSources: []string{"warehouse.events"}, BindingEvidenceKeys: []string{"data:warehouse.events"}, DeploymentStatus: "deployed", - DeploymentArtifacts: []string{".github/workflows/release.yml"}, - DeploymentEvidenceKeys: []string{"deployment:.github/workflows/release.yml"}, + DeploymentArtifacts: []string{".github/workflows/Deploy.yml"}, + DeploymentEvidenceKeys: []string{"deployment:.github/workflows/Deploy.yml"}, }} _, entries := Build(tools, agents, nil, nil) @@ -289,7 +289,10 @@ func TestBuildResolvesInstanceScopedAgentContextForToolEntries(t *testing.T) { if !reflect.DeepEqual(entry.BoundDataSources, []string{"warehouse.events"}) { t.Fatalf("unexpected bound_data_sources: %+v", entry.BoundDataSources) } - if !reflect.DeepEqual(entry.DeploymentEvidenceKeys, []string{"deployment:.github/workflows/release.yml"}) { + if !reflect.DeepEqual(entry.DeploymentEvidenceKeys, []string{"deployment:.github/workflows/Deploy.yml"}) { t.Fatalf("unexpected deployment_evidence_keys: %+v", entry.DeploymentEvidenceKeys) } + if !reflect.DeepEqual(entry.DeploymentArtifacts, []string{".github/workflows/Deploy.yml"}) { + t.Fatalf("unexpected deployment_artifacts: %+v", entry.DeploymentArtifacts) + } }