Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to match something that is missing in a file? #668

Open
JaneX8 opened this issue Dec 6, 2024 · 5 comments
Open

Is it possible to match something that is missing in a file? #668

JaneX8 opened this issue Dec 6, 2024 · 5 comments
Labels

Comments

@JaneX8
Copy link

JaneX8 commented Dec 6, 2024

Is it possible to match something that is missing in a file? For example if I apply a DevSkim rule on all yaml files or better if possible on all files ending with .sometool.yaml, can I then specifically trigger a warning on something that does not exist? For example the file is expected to have a certain option but it doesn't contain it.

I tried to achieve it with regex negative lookaheads but it doesn't seem possible, I get the self-tests (must-match / must-not-match) to work but not triggering on the actual content.

@gfs
Copy link
Contributor

gfs commented Dec 6, 2024

I don't think this is something I've tried before, but can you share the sample that worked with match/must-not match? If it passes those tests I think it should be possible to make it work, but it may be that there's a check somewhere in the conversion from match to issue object creation/output creation that is swallowing it. If you share the sample rule I could debug in and see where it might be getting stuck.

@JaneX8
Copy link
Author

JaneX8 commented Dec 6, 2024

A very minimal test for negative lookaheads:

xyz.devskim.json:

[{
    "name": "Ensure 'xyz' is used",
    "id": "ensure_xyz_is_used",
    "description": "The string 'xyz' must be present.",
    "recommendation": "Ensure that the string 'xyz' is included anywhere.",
    "tags": [
        "test"
    ],
    "confidence": "high",
    "severity": "important",
    "patterns": [{
        "pattern": "^(?!.*xyz).*$",
        "type": "regex",
        "scopes": [
            "code"
        ]
    }],
    "must-match": [
        "abc",
        "dee ghi"
    ],
    "must-not-match": [
        "abc xyz",
        "xyz abc"
    ]
}]
devskim verify -r ".\xyz.devskim.json"                                                                         
[21:10:40 INF] 1 of 1 rules have must-match self-tests.
[21:10:40 INF] 1 of 1 rules have must-not-match self-tests.

If I use this rule one a simple text file with one line that does not contain or does contain, it works as expected as well.

The negative lookahead seems to work in self-test and on one-line files, although I'm having trouble getting it to work when I include newlines and tabs in the must-match and must-not-match tests (such as with yaml). Even with modifier m, which I guess is multiline? I'm trying to use this on a yaml file. I want to detect is a certain key say xyz: is used. Preferably only with, or in combination with ymlpath and regex, so that I can also check the specific location in the yaml structure. But I have no idea how to pull that of yet.

@gfs
Copy link
Contributor

gfs commented Dec 6, 2024

I just remembered this is possible using conditions. Here I just set the initial pattern to something that matches everything, and then leverage the negate_finding feature of the condition mechanism.

[{
    "name": "Ensure 'xyz' is used",
    "id": "ensure_xyz_is_used",
    "description": "The string 'xyz' must be present.",
    "recommendation": "Ensure that the string 'xyz' is included anywhere.",
    "tags": [
        "test"
    ],
    "confidence": "high",
    "severity": "important",
    "patterns": [{
        "pattern": ".*",
        "type": "regex",
        "scopes": [
            "code"
        ]
    }],
   "conditions": [
      {
        "pattern": {
          "pattern": "xyz",
          "type": "string",
          "scopes": [
            "code"
          ],
          "modifiers": [
            "i"
          ]
        },
        "search_in": "same-file",
        "negate_finding": true
      }
    ],
    "must-match": [
        "abc",
        "dee ghi"
    ],
    "must-not-match": [
        "abc xyz",
        "xyz abc"
    ]
}]

I believe you can add newlines to the must-match and must-not-match samples using \\n.

@JaneX8
Copy link
Author

JaneX8 commented Dec 6, 2024

Thank you. That's great and it works with \n\t in the the self-tests. But the outcome of .* is that every char and line is red underlined now.
Logically so, there is nothing to match (or negative everything to match). I'm not sure how to practically and properly implement this behavior with non-matchers in a usable way.

Yes I can use ^(.) and just match everything on the first char on the first line, but this doesn't structurally solve it. Also it makes fixits unusable. If I could somehow combine this with ymlpath (same for xpath/jsonpath) matchers, we could even construct a fixit that suggests where to insert the missing line or word approximately, I think.

@gfs
Copy link
Contributor

gfs commented Dec 6, 2024

You should be able to substitute any pattern you want (including ymlpath etc) in the initial pattern for what you would want highlighted - I just left it very broad for the example. That should then only be identified as an issue in the absence of the condition negating the finding (which could additionally be a different ymlpath query if desired), but functionally you'd need something to hook onto for the original match before being potentially negated.

@gfs gfs added question and removed enhancement labels Dec 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants