Repository: bridgecrewio/checkov

Issue:
Checkov failure on F driver windows
**Describe the bug**
When running checkov from the jetbrains plugin using this command:
```checkov -s --bc-api-key **-**-**-** --repo-id jetbrains/extension -f F:\Code\modules\test2\s3.tf -o json ```
We are getting this error:
 File "c:\Python39\Scripts\checkov.cmd", line 53, in <module>
    run()
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\main.py", line 232, in run
    repo_root_for_plan_enrichment=config.repo_root_for_plan_enrichment)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\common\runners\runner_registry.py", line 66, in run
    for scan_report in reports:
  File "C:\Python37\lib\concurrent\futures\_base.py", line 598, in result_iterator
    yield fs.pop().result()
  File "C:\Python37\lib\concurrent\futures\_base.py", line 428, in result
    return self.__get_result()
  File "C:\Python37\lib\concurrent\futures\_base.py", line 384, in __get_result
    raise self._exception
  File "C:\Python37\lib\concurrent\futures\thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\common\runners\runner_registry.py", line 63, in <lambda>
    runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments),
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\terraform\runner.py", line 102, in run
    self.check_tf_definition(report, root_folder, runner_filter, collect_skip_comments)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\terraform\runner.py", line 195, in check_tf_definition
    scanned_file, runner_filter, abs_referrer)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\terraform\runner.py", line 206, in run_all_blocks
    scanned_file, block_type, runner_filter, None, module_referrer)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\terraform\runner.py", line 289, in run_block
    caller_file_line_range=caller_file_line_range)
  File "C:\Users\MESH User\AppData\Roaming\Python\Python37\site-packages\checkov\common\output\record.py", line 44, in __init__
    self.repo_file_path = convert_to_unix_path(f'/{os.path.relpath(file_abs_path)}')  # matches file paths given in the BC platform and should always be a unix path
  File "C:\Python37\lib\ntpath.py", line 562, in relpath
    path_drive, start_drive))
ValueError: path is on mount 'F:', start on mount 'C:'

**To Reproduce**
Steps to reproduce the behavior:
1. Run checkov on a driver which is not the driver checkov is installed on windows.


**Additional context**
Add any other context about the problem here (e.g. code snippets).



Discussion:
the issue here is the usage of `os.path.relpath()` on a Windows system with different drives. It is no surprise, because there can't be relative path from one drive (ex C) to a different one (ex D).
A possible solution would be to use `pathlib` and check for equality of the used drive, if equal then determine for the relpath. If not, then just remove the drive letter and convert it to a unix style path.
https://docs.python.org/3/library/pathlib.html#pathlib.PurePath.drive
@gruebel @orhovy 

I do not think the root cause of this is running on a drive other than where Checkov is installed. 

There is another interesting similar issue that just got raised yesterday, specifically related to network drive mappings.

It actually comes from [here](https://github.com/bridgecrewio/checkov/blame/master/checkov/terraform/graph_builder/graph_components/blocks.py#L26).

`self.path = os.path.realpath(self.path)`

Say you run `checkov -f f:\\path\to\some\dir\s3.tf`, where F: is mapped to a drive path `\\network\drive`

Before this statement, the path is what you would expect, e.g. `F:\path\to\some\dir`. But then realpath converts it to `\\network\drive\path\to\some\dir`. It results in a similar error message, but a little different: `path is on mount '\\\\network\drive', start on mount 'f:'`

If I replace that line above with `abspath`, then it works fine (despite checkov being on another drive).

(I am not sure whether we really need to use `realpath` in that spot to get the canonical path, or if we can just take the value that we already have. I think it's already an absolute path, but maybe we can use replace `realpath` with `abspath`).


The OP error does seem a little different, though. The error I describe is thrown in a [different place](https://github.com/bridgecrewio/checkov/blob/029deee9f6358888d0d9faebccf4bc928b732c7b/checkov/terraform/graph_builder/graph_to_tf_definitions.py#L26). I am wondering how `C:` gets introduced at all. If I am wrong, and if it is the case that the root cause of the OP error is running on another drive, then we have a separate but related issue with network drive mapping that also needs to be handled as we work on relative paths.

Resolving patch:
diff --git a/checkov/common/output/record.py b/checkov/common/output/record.py
--- a/checkov/common/output/record.py
+++ b/checkov/common/output/record.py
@@ -1,5 +1,7 @@
 import os
 import re
+from pathlib import Path
+from typing import Union
 
 from colorama import init, Fore, Style
 from termcolor import colored
@@ -41,7 +43,7 @@ def __init__(self, check_id, check_name, check_result, code_block, file_path, fi
         self.code_block = code_block
         self.file_path = file_path
         self.file_abs_path = file_abs_path
-        self.repo_file_path = convert_to_unix_path(f'/{os.path.relpath(file_abs_path)}')  # matches file paths given in the BC platform and should always be a unix path
+        self.repo_file_path = self._determine_repo_file_path(file_abs_path)
         self.file_line_range = file_line_range
         self.resource = resource
         self.evaluations = evaluations
@@ -51,6 +53,15 @@ def __init__(self, check_id, check_name, check_result, code_block, file_path, fi
         self.caller_file_path = caller_file_path
         self.caller_file_line_range = caller_file_line_range
 
+    @staticmethod
+    def _determine_repo_file_path(file_path: Union[str, "os.PathLike[str]"]) -> str:
+        # matches file paths given in the BC platform and should always be a unix path
+        repo_file_path = Path(file_path)
+        if Path.cwd().drive == repo_file_path.drive:
+            return convert_to_unix_path(f"/{os.path.relpath(repo_file_path)}").replace("/..", "")
+
+        return f"/{'/'.join(repo_file_path.parts[1:])}"
+
     def set_guideline(self, guideline):
         self.guideline = guideline
 


Test patch:
diff --git a/tests/common/output/test_record.py b/tests/common/output/test_record.py
new file mode 100644
--- /dev/null
+++ b/tests/common/output/test_record.py
@@ -0,0 +1,17 @@
+import pytest
+
+from checkov.common.output.record import Record
+
+
+@pytest.mark.parametrize(
+    "input_path,expected_path",
+    [
+        ("s3\\main.tf", "/s3/main.tf"),
+        ("s3/main.tf", "/s3/main.tf"),
+        ("/abs_path/to/s3/main.tf", "/abs_path/to/s3/main.tf"),
+        ("../../s3/main.tf", "/s3/main.tf"),
+    ],
+    ids=["windows", "rel_path", "abs_path", "recursive_rel_path"],
+)
+def test_determine_repo_file_path(input_path: str, expected_path: str):
+    assert Record._determine_repo_file_path(input_path) == expected_path