{"record":{"id":"b0b1a69c5766423f","repo":"goharbor/harbor","slug":"cert-file-should-include-san","errorCode":null,"errorMessage":"cert file {} should include SAN","messagePattern":"cert file (.+?) should include SAN","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"make/photon/prepare/models.py","lineNumber":91,"sourceCode":"            raise Exception('File {} not exist'.format(filename))\n\n        if not path.is_file:\n            raise Exception('invalid {}'.format(filename))\n\n        # check key file permission\n        if filename.endswith('.key') and not check_permission(path, mode=0o600):\n            raise Exception('key file {} permission is not 600'.format(filename))\n\n        # check certificate file\n        if filename.endswith('.crt'):\n            if not owner_can_read(path.stat().st_mode):\n                # check owner can read cert file\n                raise Exception('File {} should readable by owner'.format(filename))\n            if not san_existed(path):\n                # check SAN included\n                if filename == 'harbor_internal_ca.crt':\n                    return\n                raise Exception('cert file {} should include SAN'.format(filename))\n\n    def validate(self):\n        if not self.enabled:\n            # pass the validation if not enabled\n            return\n\n        if not internal_tls_dir.exists():\n            raise Exception('Internal dir for tls {} not exist'.format(internal_tls_dir))\n\n        for filename in self.required_filenames:\n            self._check(filename)\n\n    def prepare(self):\n        \"\"\"\n        Prepare moves certs in tls file to data volume with correct permission.\n        \"\"\"\n        if not self.enabled:\n            logging.info('internal tls NOT enabled...')","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/make/photon/prepare/models.py#L73-L109","documentation":"The second assertion in MergeNativeSummary (src/pkg/scan/report/summary.go): s1 passed the *vuln.NativeReportSummary check but the SECOND operand s2 did not. Both operands must be exact *vuln.NativeReportSummary pointers for the native summary merge to proceed.","triggerScenarios":"Merging summaries collected from multiple scan requests where the second one was loaded from storage, a different code path, or never initialised (nil any).","commonSituations":"Incremental summary updates mixing old and new payload shapes; concurrent producers writing summaries with different versions of the model; nil elements in a slice being folded into one summary.","solutions":["Validate every summary in the fold before merging; skip or fail fast on any that is not *vuln.NativeReportSummary","Regenerate stale summaries from their reports instead of merging mixed-version data","Log the dynamic type of the failing operand to locate the producer"],"exampleFix":"// before\nsum, err := report.MergeNativeSummary(ns1, s2) // s2 is `any`\n\n// after\nns2, ok := s2.(*vuln.NativeReportSummary)\nif !ok {\n    return nil, fmt.Errorf(\"second summary is %T, want *vuln.NativeReportSummary\", s2)\n}\nsum, err := report.MergeNativeSummary(ns1, ns2)","handlingStrategy":"type-guard","validationCode":"if !isNativeSummary(s2) {\n    return fmt.Errorf(\"second summary operand is %T, want *vuln.NativeReportSummary\", s2)\n}","typeGuard":"func isNativeSummary(v any) bool {\n    _, ok := v.(*vuln.NativeReportSummary)\n    return ok\n}","tryCatchPattern":"sum, err := report.MergeNativeSummary(ns1, s2)\nif err != nil && strings.Contains(err.Error(), \"native report summary required\") {\n    return fmt.Errorf(\"s2 not a native summary (%T); regenerate it from its report\", s2)\n}","preventionTips":["Validate every element in a summary fold before merging","Regenerate stale summaries from their reports rather than merging mixed versions","Reject nil interfaces early in reduce loops"],"tags":["go","harbor","type-assertion","scan","summary"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}