From 505e3110e8c311a1828ff59a2d04ce4f7c8244f4 Mon Sep 17 00:00:00 2001 From: Talgat Ryshmanov Date: Mon, 16 Mar 2026 17:43:03 -0400 Subject: [PATCH 1/2] perf: reduce gate and guard benchmark overhead --- core/gate/context_evidence.go | 2 +- core/gate/policy.go | 43 +++++++++++++++++++++++++++++++---- core/guard/pack.go | 39 +++++++++++++++++++++++-------- 3 files changed, 68 insertions(+), 16 deletions(-) diff --git a/core/gate/context_evidence.go b/core/gate/context_evidence.go index e00bc8f4..bf465242 100644 --- a/core/gate/context_evidence.go +++ b/core/gate/context_evidence.go @@ -149,7 +149,7 @@ func mergeContextSource(current string, extra string) string { } func PolicyRequiresContextEvidence(policy Policy) bool { - normalizedPolicy, err := normalizePolicy(policy) + normalizedPolicy, err := normalizedPolicy(policy) if err != nil { return false } diff --git a/core/gate/policy.go b/core/gate/policy.go index bfac359d..de568e53 100644 --- a/core/gate/policy.go +++ b/core/gate/policy.go @@ -69,6 +69,7 @@ type Policy struct { FailClosed FailClosedPolicy `yaml:"fail_closed"` MCPTrust MCPTrustPolicy `yaml:"mcp_trust"` Rules []PolicyRule `yaml:"rules"` + normalized bool `yaml:"-" json:"-"` } type ScriptPolicy struct { @@ -263,6 +264,13 @@ func ParsePolicyYAML(data []byte) (Policy, error) { return normalizePolicy(policy) } +func normalizedPolicy(input Policy) (Policy, error) { + if input.normalized { + return input, nil + } + return normalizePolicy(input) +} + func EvaluatePolicy(policy Policy, intent schemagate.IntentRequest, opts EvalOptions) (schemagate.GateResult, error) { outcome, err := EvaluatePolicyDetailed(policy, intent, opts) if err != nil { @@ -272,7 +280,7 @@ func EvaluatePolicy(policy Policy, intent schemagate.IntentRequest, opts EvalOpt } func PolicyHasHighRiskUnbrokeredActions(policy Policy) bool { - normalizedPolicy, err := normalizePolicy(policy) + normalizedPolicy, err := normalizedPolicy(policy) if err != nil { return false } @@ -288,7 +296,7 @@ func PolicyHasHighRiskUnbrokeredActions(policy Policy) bool { } func PolicyRequiresBrokerForHighRisk(policy Policy) bool { - normalizedPolicy, err := normalizePolicy(policy) + normalizedPolicy, err := normalizedPolicy(policy) if err != nil { return false } @@ -304,7 +312,7 @@ func PolicyRequiresBrokerForHighRisk(policy Policy) bool { } func EvaluatePolicyDetailed(policy Policy, intent schemagate.IntentRequest, opts EvalOptions) (EvalOutcome, error) { - normalizedPolicy, err := normalizePolicy(policy) + normalizedPolicy, err := normalizedPolicy(policy) if err != nil { return EvalOutcome{}, err } @@ -721,7 +729,7 @@ func compositeRiskClass(riskClasses []string) string { } func PolicyDigest(policy Policy) (string, error) { - normalized, err := normalizePolicy(policy) + normalized, err := normalizedPolicy(policy) if err != nil { return "", err } @@ -1246,6 +1254,7 @@ func normalizePolicy(input Policy) (Policy, error) { } return output.Rules[i].Name < output.Rules[j].Name }) + output.normalized = true return output, nil } @@ -1990,8 +1999,32 @@ func normalizeStringListLower(values []string) []string { } func uniqueSorted(values []string) []string { - if len(values) == 0 { + switch len(values) { + case 0: return []string{} + case 1: + trimmed := strings.TrimSpace(values[0]) + if trimmed == "" { + return []string{} + } + return []string{trimmed} + case 2: + first := strings.TrimSpace(values[0]) + second := strings.TrimSpace(values[1]) + switch { + case first == "" && second == "": + return []string{} + case first == "": + return []string{second} + case second == "": + return []string{first} + case first == second: + return []string{first} + case first < second: + return []string{first, second} + default: + return []string{second, first} + } } seen := make(map[string]struct{}, len(values)) out := make([]string, 0, len(values)) diff --git a/core/guard/pack.go b/core/guard/pack.go index 72dbd799..af7f835e 100644 --- a/core/guard/pack.go +++ b/core/guard/pack.go @@ -328,12 +328,15 @@ func VerifyPackWithOptions(path string, opts VerifyOptions) (VerifyResult, error _ = zipReader.Close() }() - files := make(map[string]*zip.File, len(zipReader.File)) - for _, zipFile := range zipReader.File { - files[zipFile.Name] = zipFile + var files map[string]*zip.File + if len(zipReader.File) > 16 { + files = make(map[string]*zip.File, len(zipReader.File)) + for _, zipFile := range zipReader.File { + files[zipFile.Name] = zipFile + } } - manifestFile := files["pack_manifest.json"] + manifestFile := findZipFile(zipReader.File, files, "pack_manifest.json") if manifestFile == nil { return VerifyResult{}, fmt.Errorf("missing pack_manifest.json") } @@ -354,7 +357,7 @@ func VerifyPackWithOptions(path string, opts VerifyOptions) (VerifyResult, error SignaturesTotal: len(manifest.Signatures), } for _, entry := range manifest.Contents { - zipFile := files[entry.Path] + zipFile := findZipFile(zipReader.File, files, entry.Path) if zipFile == nil { result.MissingFiles = append(result.MissingFiles, entry.Path) continue @@ -363,7 +366,7 @@ func VerifyPackWithOptions(path string, opts VerifyOptions) (VerifyResult, error if err != nil { return VerifyResult{}, fmt.Errorf("hash %s: %w", entry.Path, err) } - if !strings.EqualFold(actualHash, entry.SHA256) { + if actualHash != entry.SHA256 && !strings.EqualFold(actualHash, entry.SHA256) { result.HashMismatches = append(result.HashMismatches, HashMismatch{ Path: entry.Path, Expected: entry.SHA256, @@ -371,10 +374,14 @@ func VerifyPackWithOptions(path string, opts VerifyOptions) (VerifyResult, error }) } } - sort.Strings(result.MissingFiles) - sort.Slice(result.HashMismatches, func(i, j int) bool { - return result.HashMismatches[i].Path < result.HashMismatches[j].Path - }) + if len(result.MissingFiles) > 1 { + sort.Strings(result.MissingFiles) + } + if len(result.HashMismatches) > 1 { + sort.Slice(result.HashMismatches, func(i, j int) bool { + return result.HashMismatches[i].Path < result.HashMismatches[j].Path + }) + } if len(manifest.Signatures) == 0 { if opts.RequireSignature { result.SignatureErrors = append(result.SignatureErrors, "pack manifest has no signatures") @@ -418,6 +425,18 @@ func VerifyPackWithOptions(path string, opts VerifyOptions) (VerifyResult, error return result, nil } +func findZipFile(all []*zip.File, indexed map[string]*zip.File, name string) *zip.File { + if indexed != nil { + return indexed[name] + } + for _, zipFile := range all { + if zipFile.Name == name { + return zipFile + } + } + return nil +} + func buildRunpackSummary(data runpack.Runpack) ([]byte, error) { summary := struct { RunID string `json:"run_id"` From 6c4567d1c3d0c08d5c972c2dcd02f8cf33e12d2a Mon Sep 17 00:00:00 2001 From: Talgat Ryshmanov Date: Mon, 16 Mar 2026 18:09:37 -0400 Subject: [PATCH 2/2] fix: address actionable PR comments (loop 1) --- core/guard/pack.go | 7 +++--- core/guard/pack_test.go | 55 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/core/guard/pack.go b/core/guard/pack.go index af7f835e..90d5274f 100644 --- a/core/guard/pack.go +++ b/core/guard/pack.go @@ -429,9 +429,10 @@ func findZipFile(all []*zip.File, indexed map[string]*zip.File, name string) *zi if indexed != nil { return indexed[name] } - for _, zipFile := range all { - if zipFile.Name == name { - return zipFile + // Preserve the existing map-based last-entry-wins semantics for duplicate names. + for index := len(all) - 1; index >= 0; index-- { + if all[index].Name == name { + return all[index] } } return nil diff --git a/core/guard/pack_test.go b/core/guard/pack_test.go index 9a1b1bb9..aa0f79c1 100644 --- a/core/guard/pack_test.go +++ b/core/guard/pack_test.go @@ -284,6 +284,61 @@ func TestVerifyPackWithSignatures(t *testing.T) { } } +func TestVerifyPackDetectsTamperedLastDuplicateEntry(t *testing.T) { + workDir := t.TempDir() + now := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC) + matchingContent := []byte(`{"status":"ok"}`) + tamperedContent := []byte(`{"status":"tampered"}`) + expectedHash := sha256Hex(matchingContent) + tamperedHash := sha256Hex(tamperedContent) + + manifestBytes, err := marshalCanonicalJSON(schemaguard.PackManifest{ + SchemaID: "gait.guard.pack_manifest", + SchemaVersion: "1.0.0", + CreatedAt: now, + ProducerVersion: "0.0.0-test", + PackID: "pack_duplicate_entry", + RunID: "run_duplicate_entry", + GeneratedAt: now, + Contents: []schemaguard.PackEntry{{ + Path: "evidence.json", + SHA256: expectedHash, + Type: "evidence", + }}, + }) + if err != nil { + t.Fatalf("marshal manifest: %v", err) + } + + var archive bytes.Buffer + if err := zipx.WriteDeterministicZip(&archive, []zipx.File{ + {Path: "pack_manifest.json", Data: manifestBytes, Mode: 0o644}, + {Path: "evidence.json", Data: matchingContent, Mode: 0o644}, + {Path: "evidence.json", Data: tamperedContent, Mode: 0o644}, + }); err != nil { + t.Fatalf("write duplicate-entry zip: %v", err) + } + + packPath := filepath.Join(workDir, "duplicate_entries.zip") + if err := os.WriteFile(packPath, archive.Bytes(), 0o600); err != nil { + t.Fatalf("write duplicate-entry zip: %v", err) + } + + verifyResult, err := VerifyPack(packPath) + if err != nil { + t.Fatalf("verify duplicate-entry zip: %v", err) + } + if len(verifyResult.HashMismatches) != 1 { + t.Fatalf("expected one hash mismatch, got %#v", verifyResult.HashMismatches) + } + if verifyResult.HashMismatches[0].Path != "evidence.json" { + t.Fatalf("expected mismatch for evidence.json, got %#v", verifyResult.HashMismatches) + } + if verifyResult.HashMismatches[0].Expected != expectedHash || verifyResult.HashMismatches[0].Actual != tamperedHash { + t.Fatalf("unexpected mismatch payload: %#v", verifyResult.HashMismatches[0]) + } +} + func tamperPackMissingFile(t *testing.T, source string, destination string, remove string) { t.Helper() reader, err := zip.OpenReader(source)