Skip to content

fix(extractor): flatten multi-match limitations and make pattern matching deterministic (#125) - #127

Open
drk-ram wants to merge 1 commit into
GenAI-Security-Project:mainfrom
drk-ram:fix/125-limitations-flatten
Open

drk-ram wants to merge 1 commit into
GenAI-Security-Project:mainfrom
drk-ram:fix/125-limitations-flatten

Conversation

@drk-ram

@drk-ram drk-ram commented Nov 3, 2026

Copy link
Copy Markdown

Summary

Fixes #125.

A README with more than one limitations-style statement made EnhancedExtractor return a list, which _create_model_card_section() wrapped in another list (technicalLimitations: [[...]]). That is invalid against the CycloneDX 1.6 schema. Separately, _find_pattern_matches() used list(set(...)), so match order, and the first match used for model_type, varied with PYTHONHASHSEED.

Changes

  • extractor.py: _find_pattern_matches() de-duplicates with dict.fromkeys(), keeping pattern order.
  • service.py: new _as_string_list() flattens a scalar or list into non-empty strings. useCases, technicalLimitations and ethicalConsiderations (one {"name": ...} per item) use it, so lists are never nested and empty values are not emitted.

Tests (tests/test_limitations_extraction.py)

  • two limitation statements give a flat technicalLimitations list and validate_aibom() passes
  • a single string is still wrapped once
  • list values for intendedUse / ethicalConsiderations are flattened and schema-valid
  • empty values are not emitted
  • matches follow pattern order and are de-duplicated
  • model_type and technicalLimitations output is identical across PYTHONHASHSEED 0 to 5 (subprocess per seed)

Five of the seven tests fail on origin/main.

Validation

  • pytest -q --no-cov: all passed
  • pytest tests/test_limitations_extraction.py --no-cov on origin/main sources: 5 failed, 2 passed; with this change: 7 passed

…hing deterministic (GenAI-Security-Project#125)

When a README matched more than one limitations pattern, the extractor
returned a list and _create_model_card_section() wrapped it in another
list, producing technicalLimitations: [[...]], which fails CycloneDX 1.6
validation (items must be strings). useCases and ethicalConsiderations
used the same wrapping.

_find_pattern_matches() also returned list(set(matches)), so the order of
the matches, and the "first match" used for model_type, changed with
PYTHONHASHSEED.

- extractor.py: de-duplicate with dict.fromkeys() so matches keep the
  order of the patterns.
- service.py: add _as_string_list() and use it for useCases,
  technicalLimitations and ethicalConsiderations so lists are flattened
  to non-empty strings and scalars are wrapped once.
- tests: schema-valid flat output for multiple matches, scalar wrapping,
  empty values skipped, pattern order, de-duplication, and identical
  output across six PYTHONHASHSEED values.

Fixes GenAI-Security-Project#125

Signed-off-by: Raghuvar Karthik Durga <177662415+drk-ram@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple README limitation matches produce nested technicalLimitations array (schema-invalid BOM) with non-deterministic ordering

1 participant