{"record":{"id":"642eb3889c6a36a7","repo":"JuliusBrussee/caveman","slug":"invalid-agent-evidence-identity","errorCode":null,"errorMessage":"invalid agent evidence identity","messagePattern":"invalid agent evidence identity","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/store.go","lineNumber":567,"sourceCode":"\tContextBill                  string `json:\"context_bill\"`\n\tTransformTrace               string `json:\"transform_trace\"`\n\tTransformLocation            string `json:\"transform_location\"`\n\tCacheEpoch                   string `json:\"cache_epoch\"`\n\tCachePrefixSHA256            string `json:\"declared_cache_prefix_sha256\"`\n\tProviderCachePrefixSHA256    string `json:\"provider_cache_prefix_sha256\"`\n\tProviderCacheComponentSHA256 string `json:\"provider_cache_component_sha256\"`\n\tCacheBoundaryKnown           bool   `json:\"cache_boundary_known\"`\n\tRecoveryHandle               string `json:\"recovery_handle\"`\n\tCompressionTokensBefore      int64  `json:\"compression_tokens_before\"`\n\tCompressionTokensAfter       int64  `json:\"compression_tokens_after\"`\n\tBasis                        string `json:\"basis\"`\n}\n\n// AgentEvidenceForBuild returns all requests for one exact session/build/plan\n// tuple in provider-call order. Partial or malformed identity fails closed.\nfunc (s *Store) AgentEvidenceForBuild(sessionID, buildSHA256, planSHA256 string) ([]AgentEvidence, error) {\n\tif !validEvidenceToken(sessionID, 256) || !validDigest(buildSHA256) || !validDigest(planSHA256) {\n\t\treturn nil, fmt.Errorf(\"invalid agent evidence identity\")\n\t}\n\trows, err := s.db.Query(\n\t\t`SELECT ts, request_id, session_id, agent_build_sha256, efficiency_plan_sha256,\n\t\t        COALESCE(provider,''), COALESCE(model,''), COALESCE(status_code,0),\n\t\t        COALESCE(input_tokens,0), COALESCE(output_tokens,0), COALESCE(cached_input_tokens,0),\n\t\t        COALESCE(cache_creation_input_tokens,0), COALESCE(reasoning_tokens,0),\n\t\t        COALESCE(token_usage_basis,'unavailable'), COALESCE(raw_request_sha256,''),\n\t\t        COALESCE(transformed_request_sha256,''), COALESCE(request_hash_complete,0), COALESCE(optimization_ids,''),\n\t\t        COALESCE(context_bill,''), COALESCE(transform_trace,''), COALESCE(transform_location,''),\n\t\t        COALESCE(cache_epoch,''), COALESCE(cache_prefix_sha256,''),\n\t\t        COALESCE(provider_cache_prefix_sha256,''), COALESCE(provider_cache_component_sha256,''),\n\t\t        COALESCE(cache_boundary_known,0), COALESCE(recovery_handle,''),\n\t\t        COALESCE(compression_tokens_before,0), COALESCE(compression_tokens_after,0), basis\n\t\t   FROM requests\n\t\t  WHERE session_id = ? AND agent_build_sha256 = ? AND efficiency_plan_sha256 = ?\n\t\t  ORDER BY id ASC\n\t\t  LIMIT 500`,\n\t\tsessionID, buildSHA256, planSHA256,","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/proxy/internal/store/store.go#L549-L585","documentation":"Returned by Store.AgentEvidenceForBuild when the session/build/plan identity fails validation before any query: sessionID must pass validEvidenceToken (1-256 chars, only [A-Za-z0-9._:-]) and buildSHA256/planSHA256 must each be exactly 64 lowercase hex chars. The method fails closed — partial or malformed identity yields no evidence rather than a fuzzy match.","triggerScenarios":"Calling AgentEvidenceForBuild with a SHA that is uppercase, shorter/longer than 64, or has a 'sha256:' prefix left on; a session id containing spaces, slashes, or other characters outside [A-Za-z0-9._:-]; an empty string argument.","commonSituations":"Passing a digest computed with hex.EncodeToString but then prefixed for display ('sha256:ab...') and not stripped; copying session ids with surrounding quotes/whitespace from logs; passing a git commit SHA (40 hex chars) where a 64-char content digest is expected; shell argument truncation mangling the value.","solutions":["Pass raw 64-char lowercase hex digests: hex.EncodeToString(sum[:]) with no prefix, no trimming needed","Keep session ids alphanumeric plus . _ : - only, and trim whitespace/quotes before calling","Validate identity with the same rules client-side before invoking the CLI (see typeGuard)","If the digest genuinely is uppercase, normalize with strings.ToLower before the call"],"exampleFix":"# before\ncaveman-proxy agent-evidence --session \"'sess-1'\" --build sha256:9f2a... --plan 3c1f\n# invalid agent evidence identity\n\n# after\ncaveman-proxy agent-evidence --session sess-1 --build 9f2a...64hex --plan 3c1f...64hex","handlingStrategy":"validation","validationCode":"func validEvidenceArgs(session, build, plan string) bool {\n    return validToken(session, 256) && isDigest(build) && isDigest(plan)\n}\nfunc isDigest(s string) bool {\n    if len(s) != 64 { return false }\n    for _, c := range s {\n        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) { return false }\n    }\n    return true\n}\nfunc validToken(s string, max int) bool {\n    if s == \"\" || len(s) > max { return false }\n    for _, c := range s {\n        if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strings.ContainsRune(\"._:-\", c)) { return false }\n    }\n    return true\n}","typeGuard":"func isValidEvidenceCall(sessionID, buildSHA256, planSHA256 string) error {\n    if !validToken(sessionID, 256) { return fmt.Errorf(\"session id malformed\") }\n    if !isDigest(buildSHA256) || !isDigest(planSHA256) { return fmt.Errorf(\"digests must be 64-char lowercase hex\") }\n    return nil\n}","tryCatchPattern":"ev, err := st.AgentEvidenceForBuild(session, build, plan)\nif err != nil && strings.Contains(err.Error(), \"invalid agent evidence identity\") {\n    return fmt.Errorf(\"usage: agent-evidence --session <id> --build <64-hex> --plan <64-hex> (no sha256: prefix)\")\n}","preventionTips":["Emit digests via hex.EncodeToString and never decorate them with prefixes","Strip quotes/whitespace from ids copied out of logs","Add the same validation to CLI arg parsing so users get a usage error, not a store error"],"tags":["validation","cli","security","go"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}