def parse_config_string(config_id: str, contents: str, filename: Optional[str]) -> Dict[str, YamlTree]: try: data = parse_yaml_preserve_spans(contents, filename) return {config_id: data} except YAMLError as se: raise SemgrepError( f"Invalid YAML file {config_id}:\n{indent(str(se))}", code=UNPARSEABLE_YAML_EXIT_CODE, )
def manual_config(pattern: str, lang: str) -> Dict[str, YamlTree]: # TODO remove when using sgrep -e ... -l ... instead of this hacked config pattern_span = Span.from_string(pattern, filename="CLI Input") pattern_tree = YamlTree[str](value=pattern, span=pattern_span) error_span = parse_yaml_preserve_spans( f"Semgrep bug generating manual config {PLEASE_FILE_ISSUE_TEXT}", filename=None).span return { "manual": YamlTree.wrap( { RULES_KEY: [{ ID_KEY: "-", "pattern": pattern_tree, "message": pattern, "languages": [lang], "severity": "ERROR", }] }, span=error_span, ) }
def test_span_tracking(): data = parse_yaml_preserve_spans(test_yaml, Path("filename")) def test_span(start: Position, end: Position) -> Span: return attr.evolve(data.span, start=start, end=end) # basic spans assert data.span == test_span( start=Position(line=2, col=1), end=Position(line=10, col=1), ) # values act like dictionaries assert data.value["a"].span == test_span( start=Position(line=3, col=3), end=Position(line=10, col=1), ) # values act like lists assert data.value["a"].value[1].span == test_span( start=Position(line=4, col=5), end=Position(line=4, col=6), ) assert data.value["a"].value[1].value == 2 # spans are also attached to keys kvs = list(data.value.items()) key, value = kvs[0] assert key.span == test_span( start=Position(line=2, col=1), end=Position(line=2, col=2), ) # unrolling is equivalent assert data.unroll() == parse_yaml(test_yaml)