Repository: fox-it/dissect.target
Pull request #1139: Add Colima children plugin 
Author: login: Zawadidone
Created: 2025-05-09T13:14:21Z | Merged: 2025-05-12T17:12:44Z

Colima is a container runtime for MacOS and Linux.
https://github.com/abiosoft/colima


Diff:
diff --git a/dissect/target/plugins/child/colima.py b/dissect/target/plugins/child/colima.py
new file mode 100644
index 0000000000..ecbf4b3a79
--- /dev/null
+++ b/dissect/target/plugins/child/colima.py
@@ -0,0 +1,54 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+def find_containers(paths: list[Path]) -> Iterator[Path]:
+    for path in paths:
+        for config_path in path.iterdir():
+            if (config_file := config_path.joinpath("colima.yaml")).exists():
+                name = f"-{config_file.parts[-2]}" if config_file.parts[-2] != "default" else ""
+                if (disk_path := path.joinpath("_lima", f"colima{name}", "diffdisk")).exists():
+                    yield disk_path
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima containers.
+
+    Colima is a container runtime for macOS and Linux.
+
+    Resources:
+        - https://github.com/abiosoft/colima/blob/5d2e91c4a491d4ae35d69fb2583f4f959401bc37
+    """
+
+    __type__ = "colima"
+
+    def __init__(self, target: Target):
+        super().__init__(target)
+        self.paths = [
+            path
+            for user in self.target.user_details.all_with_home()
+            if (path := user.home_path.joinpath(".colima")).exists()
+        ]
+
+    def check_compatible(self) -> None:
+        if not self.paths:
+            raise UnsupportedPluginError("No Colima configurations found")
+
+    def list_children(self) -> Iterator[ChildTargetRecord]:
+        for container in find_containers(self.paths):
+            yield ChildTargetRecord(
+                type=self.__type__,
+                path=container,
+                _target=self.target,
+            )
diff --git a/tests/plugins/child/test_colima.py b/tests/plugins/child/test_colima.py
new file mode 100644
index 0000000000..957a9e102f
--- /dev/null
+++ b/tests/plugins/child/test_colima.py
@@ -0,0 +1,29 @@
+from __future__ import annotations
+
+from io import BytesIO
+from typing import TYPE_CHECKING
+
+from dissect.target.plugins.child.colima import ColimaChildTargetPlugin
+
+if TYPE_CHECKING:
+    from dissect.target.filesystem import VirtualFilesystem
+    from dissect.target.target import Target
+
+
+def test_child_colima(target_unix_users: Target, fs_unix: VirtualFilesystem) -> None:
+    fs_unix.map_file_fh("/root/.colima/default/colima.yaml", BytesIO())
+    fs_unix.map_file_fh("/root/.colima/_lima/colima/diffdisk", BytesIO())
+    fs_unix.map_file_fh("/root/.colima/test/colima.yaml", BytesIO())
+    fs_unix.map_file_fh("/root/.colima/_lima/colima-test/diffdisk", BytesIO())
+    fs_unix.map_file_fh("/home/user/.colima/default/colima.yaml", BytesIO())
+    fs_unix.map_file_fh("/home/user/.colima/_lima/colima/diffdisk", BytesIO())
+
+    target_unix_users.add_plugin(ColimaChildTargetPlugin)
+
+    children = list(target_unix_users.list_children())
+
+    assert len(children) == 3
+    assert children[0].type == "colima"
+    assert children[0].path == "/root/.colima/_lima/colima/diffdisk"
+    assert children[1].path == "/root/.colima/_lima/colima-test/diffdisk"
+    assert children[2].path == "/home/user/.colima/_lima/colima/diffdisk"


Reviews:
user: login: Schamper
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-12T12:21:01Z
user: login: Schamper
body: Small nitpick.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-12T15:04:40Z
user: login: Schamper
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-12T15:12:33Z

Review comments:
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
+
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
    Colima is a container runtime for macOS and Linux.

```
created_at: 2025-05-12T12:13:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
+
+    Resources:
+        - https://github.com/abiosoft/colima/blob/5d2e91c4a491d4ae35d69fb2583f4f959401bc37
+    """
+
+    __type__ = "colima"
+
+    def __init__(self, target: Target):
+        super().__init__(target)
+        self.configuration_paths = list(self.find_configurations())
+
+    def find_configurations(self) -> Iterator[Path]:
+        for user_details in self.target.user_details.all_with_home():
+            if (path := user_details.home_path.joinpath(".colima")).exists():
+                yield path
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
        self.paths = [path for user in self.target.user_details.all_with_home() if (path := user.home_path.joinpath(".colima")).exists()]
```
created_at: 2025-05-12T12:15:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
+
+    Resources:
+        - https://github.com/abiosoft/colima/blob/5d2e91c4a491d4ae35d69fb2583f4f959401bc37
+    """
+
+    __type__ = "colima"
+
+    def __init__(self, target: Target):
+        super().__init__(target)
+        self.configuration_paths = list(self.find_configurations())
+
+    def find_configurations(self) -> Iterator[Path]:
+        for user_details in self.target.user_details.all_with_home():
+            if (path := user_details.home_path.joinpath(".colima")).exists():
+                yield path
+
+    def find_vms(self, configuration_paths: list[Path]) -> Iterator[Path]:
+        for config_path in configuration_paths:
+            for path in config_path.iterdir():
+                if (path := path.joinpath("colima.yaml")).exists():
+                    name = f"-{path.parts[-2]}" if path.parts[-2] != "default" else ""
+                    if (disk_path := config_path.joinpath(f"_lima/colima{name}/diffdisk")).exists():
+                        yield disk_path
+
+    def check_compatible(self) -> None:
+        if not self.configuration_paths:
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
        if not self.paths:
```
created_at: 2025-05-12T12:15:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
+
+    Resources:
+        - https://github.com/abiosoft/colima/blob/5d2e91c4a491d4ae35d69fb2583f4f959401bc37
+    """
+
+    __type__ = "colima"
+
+    def __init__(self, target: Target):
+        super().__init__(target)
+        self.configuration_paths = list(self.find_configurations())
+
+    def find_configurations(self) -> Iterator[Path]:
+        for user_details in self.target.user_details.all_with_home():
+            if (path := user_details.home_path.joinpath(".colima")).exists():
+                yield path
+
+    def find_vms(self, configuration_paths: list[Path]) -> Iterator[Path]:
+        for config_path in configuration_paths:
+            for path in config_path.iterdir():
+                if (path := path.joinpath("colima.yaml")).exists():
+                    name = f"-{path.parts[-2]}" if path.parts[-2] != "default" else ""
+                    if (disk_path := config_path.joinpath(f"_lima/colima{name}/diffdisk")).exists():
+                        yield disk_path
+
+    def check_compatible(self) -> None:
+        if not self.configuration_paths:
+            raise UnsupportedPluginError("No Colima configurations found")
+
+    def list_children(self) -> Iterator[ChildTargetRecord]:
+        for vm in self.find_vms(self.configuration_paths):
+            yield ChildTargetRecord(
+                type=self.__type__,
+                path=vm,
+                _target=self.target,
+            )
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
    def list_children(self) -> Iterator[ChildTargetRecord]:
        for container in find_containers(self.paths):
            yield ChildTargetRecord(
                type=self.__type__,
                path=container,
                _target=self.target,
            )
```
created_at: 2025-05-12T12:16:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
+
+    Resources:
+        - https://github.com/abiosoft/colima/blob/5d2e91c4a491d4ae35d69fb2583f4f959401bc37
+    """
+
+    __type__ = "colima"
+
+    def __init__(self, target: Target):
+        super().__init__(target)
+        self.configuration_paths = list(self.find_configurations())
+
+    def find_configurations(self) -> Iterator[Path]:
+        for user_details in self.target.user_details.all_with_home():
+            if (path := user_details.home_path.joinpath(".colima")).exists():
+                yield path
+
+    def find_vms(self, configuration_paths: list[Path]) -> Iterator[Path]:
+        for config_path in configuration_paths:
+            for path in config_path.iterdir():
+                if (path := path.joinpath("colima.yaml")).exists():
+                    name = f"-{path.parts[-2]}" if path.parts[-2] != "default" else ""
+                    if (disk_path := config_path.joinpath(f"_lima/colima{name}/diffdisk")).exists():
+                        yield disk_path
+
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
```
created_at: 2025-05-12T12:17:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion

def find_containers(paths: list[Path]) -> Iterator[Path]:
    for path in paths:
        for config_path in path.iterdir():
            if (config_file := config_path.joinpath("colima.yaml")).exists():
                name = f"-{config_file.parts[-2]}" if config_file.parts[-2] != "default" else ""
                if (disk_path := path.joinpath("_lima", f"colima{name}", "diffdisk")).exists():
                    yield disk_path

```
created_at: 2025-05-12T12:20:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,54 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+
+from dissect.target.exceptions import UnsupportedPluginError
+from dissect.target.helpers.record import ChildTargetRecord
+from dissect.target.plugin import ChildTargetPlugin
+
+if TYPE_CHECKING:
+    from collections.abc import Iterator
+    from pathlib import Path
+
+    from dissect.target import Target
+
+
+def find_containers(paths: list[Path]) -> Iterator[Path]:
+    for path in paths:
+        for config_path in path.iterdir():
+            if (config_file := config_path.joinpath("colima.yaml")).exists():
+                name = f"-{config_file.parts[-2]}" if config_file.parts[-2] != "default" else ""
+                if (disk_path := path.joinpath("_lima", f"colima{name}", "diffdisk")).exists():
+                    yield disk_path
+
+
+class ColimaChildTargetPlugin(ChildTargetPlugin):
+    """Child target plugin that yields Colima configuration.
path: dissect/target/plugins/child/colima.py
user: login: Schamper
body: ```suggestion
    """Child target plugin that yields Colima containers.
```
created_at: 2025-05-12T15:04:02Z
author_association: MEMBER

PR comments:
user: login: Zawadidone
created_at: 2025-05-12T13:07:20Z
body: The PR does not depend on https://github.com/fox-it/dissect.target/pull/1138.
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-05-12T13:28:12Z
body: ## [Codecov](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) Report
Attention: Patch coverage is `88.88889%` with `3 lines` in your changes missing coverage. Please review.
> Project coverage is 77.91%. Comparing base [(`c352ce2`)](https://app.codecov.io/gh/fox-it/dissect.target/commit/c352ce29b419093f6e1f4c151fd9fafc1ad43e9e?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) to head [(`2d26ce2`)](https://app.codecov.io/gh/fox-it/dissect.target/commit/2d26ce248ff50ffe392ea8dd9a805a6dfe05566d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) | Patch % | Lines |
|---|---|---|
| [dissect/target/plugins/child/colima.py](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139?src=pr&el=tree&filepath=dissect%2Ftarget%2Fplugins%2Fchild%2Fcolima.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it#diff-ZGlzc2VjdC90YXJnZXQvcGx1Z2lucy9jaGlsZC9jb2xpbWEucHk=) | 88.88% | [3 Missing :warning: ](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) |

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #1139   +/-   ##
=======================================
  Coverage   77.90%   77.91%           
=======================================
  Files         358      359    +1     
  Lines       32632    32659   +27     
=======================================
+ Hits        25421    25445   +24     
- Misses       7211     7214    +3     
```

| [Flag](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it) | `77.91% <88.88%> (+<0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/fox-it/dissect.target/pull/1139?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=fox-it).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: codspeed-hq[bot]
created_at: 2025-05-12T13:28:27Z
body: <!-- __CODSPEED_PERFORMANCE_REPORT_COMMENT__ -->
<!-- __CODSPEED_INSTRUMENTATION_PERFORMANCE_REPORT_COMMENT__ -->

## [CodSpeed Performance Report](https://codspeed.io/fox-it/dissect.target/branches/Zawadidone%3Afeature%2Fcolima_vms)

### Merging #1139 will **not alter performance**

<sub>Comparing <code>Zawadidone:feature/colima_vms</code> (2d26ce2) with <code>main</code> (c352ce2)</sub>



### Summary

`✅ 3` untouched benchmarks  




author_association: NONE