{"record":{"id":"fa68ca785001fef9","repo":"can1357/oh-my-pi","slug":"security-scan-manifest-contains-duplicate-finding","errorCode":null,"errorMessage":"Security scan manifest contains duplicate finding references","messagePattern":"Security scan manifest contains duplicate finding references","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/contracts/validation.ts","lineNumber":39,"sourceCode":"}\n\nexport function parseSecurityScanPlan(value: unknown): SecurityScanPlan {\n\tconst { securityScanPlanSchema } = getSecurityContractSchemas();\n\tconst result = securityScanPlanSchema(value);\n\tif (result instanceof type.errors) throw schemaError(\"Security scan plan\", result);\n\treturn result as SecurityScanPlan;\n}\n\nexport function parseSecurityScanBundle(value: unknown): SecurityScanBundle {\n\tconst { securityScanBundleSchema } = getSecurityContractSchemas();\n\tconst result = securityScanBundleSchema(value);\n\tif (result instanceof type.errors) throw schemaError(\"Security scan bundle\", result);\n\tconst bundle = result as SecurityScanBundle;\n\tconst findingIds = new Set(bundle.findings.map(finding => finding.id));\n\tif (findingIds.size !== bundle.findings.length) throw new Error(\"Security scan contains duplicate finding ids\");\n\tconst referencedFindingIds = new Set(bundle.scan.findingIds);\n\tif (referencedFindingIds.size !== bundle.scan.findingIds.length) {\n\t\tthrow new Error(\"Security scan manifest contains duplicate finding references\");\n\t}\n\tfor (const findingId of referencedFindingIds) {\n\t\tif (!findingIds.has(findingId)) throw new Error(`Security scan references missing finding: ${findingId}`);\n\t}\n\tfor (const findingId of findingIds) {\n\t\tif (!referencedFindingIds.has(findingId))\n\t\t\tthrow new Error(`Security scan omits finding from manifest: ${findingId}`);\n\t}\n\tfor (const finding of bundle.findings) {\n\t\tif (finding.scanId !== bundle.scan.id) {\n\t\t\tthrow new Error(`Finding ${finding.id} belongs to ${finding.scanId}, expected ${bundle.scan.id}`);\n\t\t}\n\t\tconst evidenceIds = new Set(finding.evidence.map(evidence => evidence.id));\n\t\tif (evidenceIds.size !== finding.evidence.length) {\n\t\t\tthrow new Error(`Finding ${finding.id} contains duplicate evidence ids`);\n\t\t}\n\t\tconst occurrenceIds = new Set(finding.occurrences.map(occurrence => occurrence.id));\n\t\tif (occurrenceIds.size !== finding.occurrences.length) {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/contracts/validation.ts#L21-L57","documentation":"The bundle's scan manifest (scan.findingIds) must list each finding at most once. Duplicated manifest references indicate a corrupt or hand-edited manifest and would double-count findings in consumers, so parseSecurityScanBundle rejects the bundle.","triggerScenarios":"Parsing a bundle JSON where bundle.scan.findingIds contains the same id twice (findings array itself may be fine).","commonSituations":"Scripted bundle generation appending to findingIds instead of replacing it; manual edits to exported JSON; a merge tool that deduplicated findings but not the manifest.","solutions":["Regenerate the bundle so scan.findingIds is derived as the unique set of finding ids","Deduplicate the manifest before parse: findingIds: [...new Set(raw.scan.findingIds)]","Validate pre-parse: compare new Set(manifest).size against manifest.length","Fix the exporting tool to build the manifest from the findings array"],"exampleFix":"// before\nparseSecurityScanBundle(raw); // raw.scan.findingIds has a duplicate\n// after\nraw.scan.findingIds = [...new Set(raw.scan.findingIds)];\nparseSecurityScanBundle(raw);","handlingStrategy":"validation","validationCode":"const m = raw.scan.findingIds;\nif (new Set(m).size !== m.length) throw new Error(\"Manifest has duplicate finding references\");","typeGuard":null,"tryCatchPattern":"try {\n\tbundle = parseSecurityScanBundle(value);\n} catch (err) {\n\tif (err instanceof Error && err.message === \"Security scan manifest contains duplicate finding references\") {\n\t\traw.scan.findingIds = [...new Set(raw.scan.findingIds)];\n\t\tbundle = parseSecurityScanBundle(raw);\n\t} else throw err;\n}","preventionTips":["Build scan.findingIds as a set-derived unique list at generation time","Never append to an existing manifest when merging bundles","Round-trip bundles through parseSecurityScanBundle in CI to catch corrupt manifests early"],"tags":["validation","manifest","security-scan"],"backgroundTag":"duplicate-finding-ids","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}