)]}'
{"cyborg/accelerator/drivers/mdev/devspec.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":false,"context_lines":[{"line_number":47,"context_line":""},{"line_number":48,"context_line":"    def __init__(self, spec_dict):"},{"line_number":49,"context_line":"        if not isinstance(spec_dict, dict):"},{"line_number":50,"context_line":"            raise exception.PciConfigInvalidWhitelist("},{"line_number":51,"context_line":"                reason\u003df\u0027mdev device_spec entry is not a dict: {spec_dict}\u0027"},{"line_number":52,"context_line":"            )"},{"line_number":53,"context_line":"        self._validate_required_fields(spec_dict)"}],"source_content_type":"text/x-python","patch_set":13,"id":"c63d0213_4bbaa9b4","line":50,"range":{"start_line":50,"start_character":28,"end_line":50,"end_character":53},"updated":"2026-08-04 19:14:14.000000000","message":"hum ok, you have updated the reason so that ok but we may want to factor out a seperte shared invalidDevSpecConfig excption and have per driver version fo that at some point.\n\nthat also remins me we need to do the config option change next cycle to replace whitelist with devspec","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":57,"context_line":"            spec_dict.get(\u0027max_instances\u0027),"},{"line_number":58,"context_line":"        )"},{"line_number":59,"context_line":"        resource_class \u003d spec_dict.get(\u0027resource_class\u0027)"},{"line_number":60,"context_line":"        if resource_class and not isinstance(resource_class, str):"},{"line_number":61,"context_line":"            LOG.warning("},{"line_number":62,"context_line":"                \u0027resource class is not string, ignoring %s\u0027, resource_class"},{"line_number":63,"context_line":"            )"},{"line_number":64,"context_line":"            resource_class \u003d None"},{"line_number":65,"context_line":"        self.resource_class \u003d resource_class"},{"line_number":66,"context_line":"        self.traits \u003d self._parse_traits("},{"line_number":67,"context_line":"            spec_dict.get(\u0027traits\u0027, []),"}],"source_content_type":"text/x-python","patch_set":13,"id":"85a7ff6c_eb981c61","line":64,"range":{"start_line":60,"start_character":7,"end_line":64,"end_character":33},"updated":"2026-08-04 19:14:14.000000000","message":"if its defiend and its not valid im inclided to raise exception.PciConfigInvalidWhitelist here as well and treat it as a fatal start up error.\n\n\nits hard to make that change later but we can do that now in this new driver.\n\nif it unset we shoudl auto generate it later form the mdev_type but if its set to anythign that is not a valid resouce class when normalsied we shoudl error","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":83,"context_line":"                f\u0027or mdev_type: {spec_dict}\u0027"},{"line_number":84,"context_line":"            )"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"    @staticmethod"},{"line_number":87,"context_line":"    def _parse_max_instances(value):"},{"line_number":88,"context_line":"        \"\"\"Parse and validate max_instances."},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"        :param value: Raw value from the spec dict, or None."},{"line_number":91,"context_line":"        :returns: A positive int, or None if absent or"},{"line_number":92,"context_line":"            invalid."},{"line_number":93,"context_line":"        \"\"\""},{"line_number":94,"context_line":"        if value is None:"},{"line_number":95,"context_line":"            return None"},{"line_number":96,"context_line":"        try:"},{"line_number":97,"context_line":"            max_inst \u003d int(value)"},{"line_number":98,"context_line":"        except (ValueError, TypeError):"},{"line_number":99,"context_line":"            LOG.warning("},{"line_number":100,"context_line":"                \u0027Invalid max_instances value %r in mdev \u0027"},{"line_number":101,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":102,"context_line":"                value,"},{"line_number":103,"context_line":"            )"},{"line_number":104,"context_line":"            return None"},{"line_number":105,"context_line":"        if max_inst \u003c 0:"},{"line_number":106,"context_line":"            LOG.warning("},{"line_number":107,"context_line":"                \u0027Negative max_instances value %d in mdev \u0027"},{"line_number":108,"context_line":"                \u0027device_spec, ignoring cap\u0027,"},{"line_number":109,"context_line":"                max_inst,"},{"line_number":110,"context_line":"            )"},{"line_number":111,"context_line":"            return None"},{"line_number":112,"context_line":"        return max_inst"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    @staticmethod"},{"line_number":115,"context_line":"    def _parse_traits(raw_traits):"},{"line_number":116,"context_line":"        \"\"\"Parse and validate traits list."}],"source_content_type":"text/x-python","patch_set":13,"id":"3e11d36e_a2221f3a","line":113,"range":{"start_line":86,"start_character":0,"end_line":113,"end_character":1},"updated":"2026-08-04 19:14:14.000000000","message":"same here if you spcify an invlaid max_instnaces it shoudl prevent the agent form starting","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"55a786a72551fb6e35ebbc5de5fc5b81b055290c","unresolved":false,"context_lines":[{"line_number":126,"context_line":"            )"},{"line_number":127,"context_line":"            return []"},{"line_number":128,"context_line":"        traits \u003d []"},{"line_number":129,"context_line":"        for trait in raw_traits:"},{"line_number":130,"context_line":"            if not isinstance(trait, str):"},{"line_number":131,"context_line":"                LOG.warning(\u0027trait is not a string, ignoring: %s \u0027, trait)"},{"line_number":132,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":13,"id":"58af3fd6_6dd14a9a","line":129,"updated":"2026-08-04 17:07:14.000000000","message":"The _parse_traits method validates that each trait is a string via isinstance(trait, str) but does not check for empty strings. An empty string passes validation and is stored. Later, _get_traits calls os_traits.normalize_name on it, which produces \u0027CUSTOM_\u0027 — an invalid Placement trait name that...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An operator who accidentally includes an empty string in the traits list (e.g., {\"traits\": [\"CUSTOM_FAST\", \"\"]}) would get an invalid CUSTOM_ trait sent to Placement during resource reporting, causing a Placement API error. The error would surface during agent discovery/reporting, potentially blo...\n\n**Recommendation**:\nAdd an emptiness check alongside the isinstance check in _parse_traits. For example: \u0027if not isinstance(trait, str) or not trait: LOG.warning(...); continue\u0027. This is consistent with the validation already applied to address/mdev_type (checked for falsiness in _validate_required_fields) and max_instances (checked for negativity).","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":130,"context_line":"            if not isinstance(trait, str):"},{"line_number":131,"context_line":"                LOG.warning(\u0027trait is not a string, ignoring: %s \u0027, trait)"},{"line_number":132,"context_line":"                continue"},{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"}],"source_content_type":"text/x-python","patch_set":13,"id":"ed4c5799_c7bc539b","line":133,"range":{"start_line":133,"start_character":10,"end_line":133,"end_character":32},"updated":"2026-08-04 19:14:14.000000000","message":"so we proably shoudl to the os traits normalsistion here.","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":133,"context_line":"            traits.append(trait)"},{"line_number":134,"context_line":"        return traits"},{"line_number":135,"context_line":""},{"line_number":136,"context_line":"    @property"},{"line_number":137,"context_line":"    def specificity(self):"},{"line_number":138,"context_line":"        \"\"\"Return specificity score (lower is more specific)."},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        Used for ordering specs so that more specific matches"},{"line_number":141,"context_line":"        take priority."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        :returns: Integer specificity score."},{"line_number":144,"context_line":"        \"\"\""},{"line_number":145,"context_line":"        score \u003d 0"},{"line_number":146,"context_line":"        if self.address \u003d\u003d WILDCARD:"},{"line_number":147,"context_line":"            score +\u003d 2"},{"line_number":148,"context_line":"        if self.mdev_type \u003d\u003d WILDCARD:"},{"line_number":149,"context_line":"            score +\u003d 1"},{"line_number":150,"context_line":"        return score"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"    def match(self, pci_address, type_name):"},{"line_number":153,"context_line":"        \"\"\"Check if this spec matches a device/type pair."}],"source_content_type":"text/x-python","patch_set":13,"id":"f560ef4f_77befeea","line":150,"range":{"start_line":136,"start_character":1,"end_line":150,"end_character":20},"updated":"2026-08-04 19:14:14.000000000","message":"intersting choice\n\nin nova we consider it operaotr error to have overlaping device specs\n\ni belive we take the first of you do it but it not something we really wanted to supprot\n\nhaving precendce based on teh number of wild card can work wiht a bias but its alos complex to reason about.\n\nwhy not just use the order in the config and have first match win.\n\n\nnote that wildcarding the mdev_type is not part of the appoved spec\n\nhttps://specs.openstack.org/openstack/cyborg-specs/specs/2026.2/approved/generic-mdev-driver.html#mdevbusmanager-class-design\nit was intened to be a fixed value.\n\n\nwe didnt dicuss overlaping mapping and precedence either so im inclidne to say this is overly complx and we shoudl either error if a device matches mutlipel or keep it simple for now and take the first match in config order","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":166,"context_line":"            f\u0027mdev_type\u003d{self.mdev_type})\u0027"},{"line_number":167,"context_line":"        )"},{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    @staticmethod"},{"line_number":170,"context_line":"    def from_config(spec_str):"},{"line_number":171,"context_line":"        \"\"\"Parse a single JSON config string into a spec."},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"5c5ade30_ac5cd4b6","line":169,"range":{"start_line":169,"start_character":5,"end_line":169,"end_character":17},"updated":"2026-08-04 19:14:14.000000000","message":"this shoudl be a class method\n\nits a constructor function","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":182,"context_line":"                reason\u003d\u0027Invalid mdev device_spec entry: %s\u0027 % spec_str"},{"line_number":183,"context_line":"            )"},{"line_number":184,"context_line":"        return MdevDeviceSpec(spec_dict)"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"    @staticmethod"},{"line_number":187,"context_line":"    def from_config_list(spec_strings):"},{"line_number":188,"context_line":"        \"\"\"Parse a list of JSON config strings into specs."},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"        Parses all ``[mdev] device_spec`` entries, deduplicates"},{"line_number":191,"context_line":"        by ``(address, mdev_type)`` (last entry wins), and"},{"line_number":192,"context_line":"        returns specs sorted by specificity (most specific"},{"line_number":193,"context_line":"        first)."},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        :param spec_strings: List of JSON-encoded strings."},{"line_number":196,"context_line":"        :returns: A list of :class:`MdevDeviceSpec` objects"},{"line_number":197,"context_line":"            sorted by specificity."},{"line_number":198,"context_line":"        \"\"\""},{"line_number":199,"context_line":"        seen \u003d {}"},{"line_number":200,"context_line":"        for spec_str in spec_strings:"},{"line_number":201,"context_line":"            spec \u003d MdevDeviceSpec.from_config(spec_str)"},{"line_number":202,"context_line":"            key \u003d (spec.address, spec.mdev_type)"},{"line_number":203,"context_line":"            if key in seen:"},{"line_number":204,"context_line":"                LOG.warning("},{"line_number":205,"context_line":"                    \u0027Duplicate mdev device_spec for \u0027"},{"line_number":206,"context_line":"                    \u0027(address\u003d%s, mdev_type\u003d%s), \u0027"},{"line_number":207,"context_line":"                    \u0027overwriting previous entry\u0027,"},{"line_number":208,"context_line":"                    spec.address,"},{"line_number":209,"context_line":"                    spec.mdev_type,"},{"line_number":210,"context_line":"                )"},{"line_number":211,"context_line":"            seen[key] \u003d spec"},{"line_number":212,"context_line":"        specs \u003d list(seen.values())"},{"line_number":213,"context_line":"        specs.sort(key\u003dlambda s: s.specificity)"},{"line_number":214,"context_line":"        return specs"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"    @staticmethod"},{"line_number":217,"context_line":"    def build_filters(specs):"},{"line_number":218,"context_line":"        \"\"\"Build PCI address and mdev type filters from specs."}],"source_content_type":"text/x-python","patch_set":13,"id":"4bed6d58_72b84f32","line":215,"range":{"start_line":185,"start_character":1,"end_line":215,"end_character":1},"updated":"2026-08-04 19:14:14.000000000","message":"i dont think this is correct\n\nosloconfg will returhn the list of string and we can just parse that into a list of objects","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"cyborg/accelerator/drivers/mdev/driver.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"cf81eef0398f3df841744549e79f74b33c9f26af","unresolved":false,"context_lines":[{"line_number":232,"context_line":"        :returns: A list of trait strings."},{"line_number":233,"context_line":"        \"\"\""},{"line_number":234,"context_line":"        traits \u003d [constants.OWNER_CYBORG]"},{"line_number":235,"context_line":"        extra \u003d spec.get(\u0027traits\u0027, [])"},{"line_number":236,"context_line":"        extra_traits \u003d ["},{"line_number":237,"context_line":"            os_traits.normalize_name(trait.replace(\u0027CUSTOM_\u0027, \u0027\u0027))"},{"line_number":238,"context_line":"            for trait in extra"}],"source_content_type":"text/x-python","patch_set":1,"id":"9e526c96_c17fb15f","line":235,"updated":"2026-07-13 14:12:32.000000000","message":"The _get_traits method retrieves the \u0027traits\u0027 key from the config spec via spec.get(\u0027traits\u0027, []) and immediately iterates over it in a list comprehension. If an operator provides traits as a string (e.g. \"traits\": \"CUSTOM_FAST\" instead of [\"CUSTOM_FAST\"]), the comprehension iterates over individ...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Operator misconfiguration of traits as a string silently produces wrong Placement traits, affecting scheduling. If traits is null or non-iterable, the entire mdev discovery crashes with an unhandled TypeError, preventing all mdev devices from being reported.\n\n**Suggestion**:\nAdd a type check before the list comprehension, e.g.: extra \u003d spec.get(\u0027traits\u0027, []) if not isinstance(extra, list): LOG.warning(\u0027traits in mdev device_spec is not a list, ignoring: %r\u0027, extra) extra \u003d [] Then proceed with the comprehension. This prevents both the silent wrong-results case and the crash.","commit_id":"5795bcd108c61d36a8b8dcf3983dec96194d26d4"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"cf81eef0398f3df841744549e79f74b33c9f26af","unresolved":false,"context_lines":[{"line_number":316,"context_line":"        created \u003d mdev_type_info[\u0027created_instances\u0027]"},{"line_number":317,"context_line":"        num_accelerators \u003d available + created"},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"        max_inst \u003d spec.get(\u0027max_instances\u0027)"},{"line_number":320,"context_line":"        if max_inst is not None:"},{"line_number":321,"context_line":"            try:"},{"line_number":322,"context_line":"                max_inst \u003d int(max_inst)"}],"source_content_type":"text/x-python","patch_set":1,"id":"bd264fa1_5b90a65d","line":319,"updated":"2026-07-13 14:12:32.000000000","message":"In _generate_deployable, max_instances from the config spec is cast to int but not validated as non-negative. A negative value (e.g. -1) causes num_accelerators \u003d min(num_accelerators, -1) to become negative. This results in a DriverDeployable with a negative num_accelerators value and zero attac...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: A negative max_instances config value would cause the driver to report a deployable with a negative num_accelerators to Placement, which is semantically invalid and could cause downstream issues in resource tracking and scheduling.\n\n**Suggestion**:\nAfter the int conversion, validate that max_inst is non-negative: max_inst \u003d int(max_inst) if max_inst \u003c 0: LOG.warning(\u0027Invalid negative max_instances value %d for mdev type %s, ignoring cap\u0027, max_inst, type_name) else: num_accelerators \u003d min(num_accelerators, max_inst)","commit_id":"5795bcd108c61d36a8b8dcf3983dec96194d26d4"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"efd54905d1cfa4156d191edf3697c53c0e51d12c","unresolved":false,"context_lines":[{"line_number":487,"context_line":"                    ),"},{"line_number":488,"context_line":"                )"},{"line_number":489,"context_line":""},{"line_number":490,"context_line":"        LOG.info(\u0027mdev device_list: %s\u0027, device_list)"},{"line_number":491,"context_line":"        return device_list"}],"source_content_type":"text/x-python","patch_set":4,"id":"84066b4f_0a008e3c","line":490,"updated":"2026-07-20 11:04:08.000000000","message":"The discover() method logs the entire device_list (a list of DriverDevice objects, each containing nested deployables with multiple attach handles) at INFO level. On a host with several GPU cards and multiple mdev types, this produces very large log output on every cyborg-agent sync cycle.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Excessive log volume on every agent sync cycle in production. Makes logs harder to search, wastes disk, and potentially impacts performance when formatting large object graphs.\n\n**Suggestion**:\nChange LOG.info to LOG.debug for the full device list, or replace with a count-based summary like LOG.info(\u0027Discovered %d mdev device(s)\u0027, len(device_list)).","commit_id":"0a011c7c28536b3b02f7dc8b954a20c475bc92df"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"43fedf8085419e273823f8a64b64355d0ccef6ad","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                raise exception.PciConfigInvalidWhitelist("},{"line_number":118,"context_line":"                    reason\u003df\u0027Invalid mdev device_spec entry: {spec_str}\u0027"},{"line_number":119,"context_line":"                )"},{"line_number":120,"context_line":"            if not isinstance(spec, dict):"},{"line_number":121,"context_line":"                raise exception.PciConfigInvalidWhitelist("},{"line_number":122,"context_line":"                    reason\u003df\u0027mdev device_spec entry is not a dict: {spec_str}\u0027"},{"line_number":123,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":7,"id":"a4fbe380_88a0b6f2","line":120,"updated":"2026-07-22 15:48:13.000000000","message":"The _parse_device_specs method includes a guard that raises PciConfigInvalidWhitelist when a JSON entry parses to a non-dict type (e.g., a list or number), but no unit test exercises this code path. Tests exist for invalid JSON strings and for dicts missing required keys, but not for valid JSON t...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An untested code path could harbor regressions if the guard logic changes. Currently the guard is simple and likely correct, but a test would provide confidence and documentation of the expected behavior.\n\n**Recommendation**:\nAdd a test in test_driver.py that sets device_spec to a JSON array or number string (e.g., \u0027[1, 2, 3]\u0027) and asserts that PciConfigInvalidWhitelist is raised, mirroring the existing test_invalid_json_device_spec_raises pattern.","commit_id":"58abc9a63cde28c004b4211adab98065b8b19e3f"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"e88566f0224e32839a81fa43ad79cdae95e3f047","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        :returns: Resource class string."},{"line_number":217,"context_line":"        \"\"\""},{"line_number":218,"context_line":"        rc \u003d spec.get(\u0027resource_class\u0027)"},{"line_number":219,"context_line":"        rc_name \u003d rc.replace(\u0027CUSTOM_\u0027, \u0027\u0027) if rc else \u0027MDEV_\u0027 + type_name"},{"line_number":220,"context_line":"        return orc.normalize_name(rc_name)"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"    def _get_traits("}],"source_content_type":"text/x-python","patch_set":8,"id":"c0263235_6e31a029","line":219,"updated":"2026-07-29 11:31:37.000000000","message":"Both _get_resource_class and _get_traits use str.replace(\u0027CUSTOM_\u0027, \u0027\u0027) to strip the CUSTOM_ namespace prefix before passing the result to normalize_name. str.replace removes every occurrence of the substring, not just a leading prefix. If an operator specifies a resource_class or trait name cont...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: An operator who specifies a resource_class or trait containing an embedded \u0027CUSTOM_\u0027 substring will get a different Placement resource class or trait than intended, leading to incorrect resource reporting. The issue is silent (no error or warning) so it would be hard to diagnose.\n\n**Recommendation**:\nUse str.removeprefix(\u0027CUSTOM_\u0027) (available since Python 3.9, project minimum is 3.10) instead of str.replace(\u0027CUSTOM_\u0027, \u0027\u0027) in both _get_resource_class and _get_traits to strip only the leading prefix. For example: rc.removeprefix(\u0027CUSTOM_\u0027) and trait.removeprefix(\u0027CUSTOM_\u0027).","commit_id":"542bea5c51135fe14517e052054cb8a40adc7bb3"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"659919f2c4f8663f78f0841599928a82e1d491db","unresolved":false,"context_lines":[{"line_number":234,"context_line":"                extra,"},{"line_number":235,"context_line":"            )"},{"line_number":236,"context_line":"            extra \u003d []"},{"line_number":237,"context_line":"        extra_traits \u003d ["},{"line_number":238,"context_line":"            os_traits.normalize_name(trait.removeprefix(\u0027CUSTOM_\u0027))"},{"line_number":239,"context_line":"            for trait in extra"},{"line_number":240,"context_line":"        ]"}],"source_content_type":"text/x-python","patch_set":10,"id":"bea6827e_f73a0746","line":237,"updated":"2026-07-30 11:55:22.000000000","message":"The _get_traits method validates that the \u0027traits\u0027 config value is a list, but individual list entries are not type-checked before calling str.removeprefix in the list comprehension. If an operator configures a traits list containing non-string values (e.g., a number or JSON null), the code will...\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: If an operator mistakenly includes a non-string trait value in the device_spec JSON (e.g., {\"traits\": [\"CUSTOM_FAST\", 123]}), discovery will crash with AttributeError instead of gracefully skipping the invalid entry. This makes the driver fragile against minor configuration errors.\n\n**Recommendation**:\nAdd a type check or try/except for individual trait entries before calling removeprefix. For example: filter out non-string entries with a warning log, or wrap each normalize_name call in a try/except.","commit_id":"8f372aaf8c2d6bbeeffc338aeb24f71102e5d8b2"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"a6baa37ca5d20fdff5f1ebca2a1e4dbda7d4b323","unresolved":false,"context_lines":[{"line_number":350,"context_line":"                    ),"},{"line_number":351,"context_line":"                )"},{"line_number":352,"context_line":""},{"line_number":353,"context_line":"        LOG.info(\u0027mdev device_list: %s\u0027, device_list)"},{"line_number":354,"context_line":"        return device_list"}],"source_content_type":"text/x-python","patch_set":12,"id":"840dff99_5385cb03","line":353,"updated":"2026-08-03 08:55:42.000000000","message":"The discover() method calls LOG.info with the entire device_list, which contains DriverDevice VersionedObjects with deeply nested deployables and attach handles. Since discover() is called periodically by the cyborg-agent, this can produce significant log volume in production environments with ma...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Excessive INFO-level logging of serialized VersionedObject lists on every periodic discovery cycle. In production with many devices, this floods logs with multi-line object dumps that are difficult to filter and consume disk space.\n\n**Suggestion**:\nChange LOG.info to LOG.debug, or log only a summary (e.g., device count and PCI addresses) at INFO while reserving the full object dump for DEBUG level.","commit_id":"a2df176291092377ef4823301c21d1160b92a518"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":140,"context_line":"        driver_ah \u003d driver_attach_handle.DriverAttachHandle()"},{"line_number":141,"context_line":"        driver_ah.in_use \u003d False"},{"line_number":142,"context_line":"        driver_ah.attach_type \u003d constants.AH_TYPE_MDEV"},{"line_number":143,"context_line":"        vgpu_mark \u003d type_name + \u0027_\u0027 + str(num)"},{"line_number":144,"context_line":"        driver_ah.attach_info \u003d utils.mdev_str_to_json("},{"line_number":145,"context_line":"            pci_address,"},{"line_number":146,"context_line":"            type_name,"}],"source_content_type":"text/x-python","patch_set":13,"id":"b8c79cbf_f069a93c","line":143,"range":{"start_line":143,"start_character":7,"end_line":143,"end_character":12},"updated":"2026-08-04 19:14:14.000000000","message":"this is a generic mdev driver\nwe shoudl not use the term gpu anywher in it\n\nwe do not wnat to assuem these device are gpus","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":161,"context_line":"        :returns: Resource class string."},{"line_number":162,"context_line":"        \"\"\""},{"line_number":163,"context_line":"        rc \u003d spec.resource_class"},{"line_number":164,"context_line":"        rc_name \u003d rc.removeprefix(\u0027CUSTOM_\u0027) if rc else \u0027MDEV_\u0027 + type_name"},{"line_number":165,"context_line":"        return orc.normalize_name(rc_name)"},{"line_number":166,"context_line":""},{"line_number":167,"context_line":"    def _get_traits(self, spec):"}],"source_content_type":"text/x-python","patch_set":13,"id":"31d41198_9b7fe1da","line":164,"range":{"start_line":164,"start_character":34,"end_line":164,"end_character":43},"updated":"2026-08-04 19:14:14.000000000","message":"nit: we should factor this out into a shared constant","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":318,"context_line":"        LOG.info(\u0027Discovered %d mdev parent device(s)\u0027, len(parents))"},{"line_number":319,"context_line":""},{"line_number":320,"context_line":"        device_list \u003d []"},{"line_number":321,"context_line":"        hostname \u003d CONF.host"},{"line_number":322,"context_line":"        for parent in parents:"},{"line_number":323,"context_line":"            pci_address \u003d parent.address"},{"line_number":324,"context_line":"            mdev_types \u003d self._bus_manager.get_mdev_types("}],"source_content_type":"text/x-python","patch_set":13,"id":"7845406d_0904a0a8","line":321,"range":{"start_line":321,"start_character":8,"end_line":321,"end_character":28},"updated":"2026-08-04 19:14:14.000000000","message":"this kind of problematic.\n\nthe name of the resouce provider  should be  prefixed with the hypervior_hostnaem which cannot be assumed to be  CONF.host\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/conf/default.py#L40-L50\n\nwe shoudl use\n\n`CONF.agent.resource_provider_name` \n\nwhich default to socket.getfqdn() instead of socket.gethostname()\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/conf/agent.py#L45-L57\n\nsocket.getfqdn() more closely matches libvirts hostname behvior then socket.gethostname()\n\nlibvirt really tries to prefer the fqdn if it can find it and has a 3 level fallback to find it and socket.gethostname() is effectivly the first stagey that it tires but its not the same\n\nanyway we should be using CONF.agent.resource_provider_name for the root resouce provider name\n\ni guess i didnt fix that in the nested provider names when i fixed the agent startup bug last cycle.\n\nfor now we can continue to use this but we may want to fix this in the future as a follow up to \n\nhttps://github.com/openstack/cyborg/commit/0e9a632f3165af8d108301d7838ba2792de64222\n\nthe compute manager shoudl really passin the rp name to the drivers when its creatin the driver.\n\n\ntechnially the root provider name and nested prodivcer dont need to be related in any way we just need to ensure we dont have name collisions.\n\nhaving them be related is just for humans to grok","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"cyborg/tests/unit/accelerator/drivers/mdev/test_devspec.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":17,"context_line":"from cyborg.tests import base"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"class TestMdevDeviceSpec(base.TestCase):"},{"line_number":21,"context_line":"    \"\"\"Tests for MdevDeviceSpec construction and validation.\"\"\""},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"    def test_basic_construction(self):"}],"source_content_type":"text/x-python","patch_set":13,"id":"a59555d1_b8674841","line":20,"updated":"2026-08-04 19:14:14.000000000","message":"these will have to be updated as we are far to leanent with invalid config","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}],"cyborg/tests/unit/accelerator/drivers/mdev/test_driver.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"8e0c49e1f5993a563404d09a8a82e1f2b9176b7e","unresolved":true,"context_lines":[{"line_number":93,"context_line":""},{"line_number":94,"context_line":"        :param specs: List of JSON-encoded device_spec entries."},{"line_number":95,"context_line":"        \"\"\""},{"line_number":96,"context_line":"        self.config(device_spec\u003dspecs, group\u003d\u0027mdev\u0027)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    def _make_driver(self):"},{"line_number":99,"context_line":"        \"\"\"Create a GenericMdevDriver with test paths."}],"source_content_type":"text/x-python","patch_set":13,"id":"566af22f_a7bdd0eb","line":96,"range":{"start_line":96,"start_character":0,"end_line":96,"end_character":52},"updated":"2026-08-04 19:14:14.000000000","message":"you should be using self.flags here\n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/tests/base.py#L65-L69\n\nthe both do mostly the same thing bug mucell memory makes me want to use flags instead\n\nhttps://github.com/openstack/cyborg/blob/65c76dc8188a2c0d6c838751c92395b0e660c8b2/cyborg/tests/unit/accelerator/drivers/pci/pci/test_sysinfo.py#L152\n\nand \nhttps://github.com/openstack/cyborg/blob/65c76dc8188a2c0d6c838751c92395b0e660c8b2/cyborg/tests/base.py#L54\nare the only curren usage of self.config and i would prefer to remove it in the future and only keep self.flags\n\n\nset_defaults alslo shoudl be replaced with self.flags\n\nwe shoudl be using set_override rather then change the default or direcly overriding the config option","commit_id":"1f7a750474ba150cf2c325b3623b89d53853fbdb"}]}
