fluidattacks-core 5.1.0__tar.gz → 6.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/PKG-INFO +3 -3
  2. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/aio/tasks.py +19 -12
  3. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/cpg/__init__.py +3 -2
  4. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/filesystem/__init__.py +60 -63
  5. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/download_file.py +20 -13
  6. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/download_repo.py +6 -5
  7. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core.egg-info/PKG-INFO +3 -3
  8. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core.egg-info/SOURCES.txt +0 -3
  9. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core.egg-info/requires.txt +2 -3
  10. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/pyproject.toml +7 -8
  11. fluidattacks_core-5.1.0/fluidattacks_core/authz/types.py +0 -75
  12. fluidattacks_core-5.1.0/fluidattacks_core/py.typed +0 -0
  13. fluidattacks_core-5.1.0/fluidattacks_core/serializers/__init__.py +0 -0
  14. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/README.md +0 -0
  15. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/__init__.py +0 -0
  16. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/aio/__init__.py +0 -0
  17. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/aio/processes.py +0 -0
  18. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/aio/runners.py +0 -0
  19. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/aio/threads.py +0 -0
  20. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/cpg/joern.py +0 -0
  21. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/filesystem/defaults.py +0 -0
  22. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/__init__.py +0 -0
  23. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/classes.py +0 -0
  24. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/clone.py +0 -0
  25. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/codecommit_utils.py +0 -0
  26. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/constants.py +0 -0
  27. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/delete_files.py +0 -0
  28. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/https_utils.py +0 -0
  29. {fluidattacks_core-5.1.0/fluidattacks_core/authz → fluidattacks_core-6.0.0/fluidattacks_core/git}/py.typed +0 -0
  30. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/remote.py +0 -0
  31. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/ssh_utils.py +0 -0
  32. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/utils.py +0 -0
  33. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/git/warp.py +0 -0
  34. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/http/__init__.py +0 -0
  35. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/http/client.py +0 -0
  36. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/http/validations.py +0 -0
  37. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/__init__.py +0 -0
  38. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/filters.py +0 -0
  39. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/formatters.py +0 -0
  40. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/handlers.py +0 -0
  41. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/presets.py +0 -0
  42. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/sources/__init__.py +0 -0
  43. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/sources/types.py +0 -0
  44. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/sources/utils.py +0 -0
  45. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/logging/utils.py +0 -0
  46. {fluidattacks_core-5.1.0/fluidattacks_core/git → fluidattacks_core-6.0.0/fluidattacks_core}/py.typed +0 -0
  47. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/sarif/__init__.py +0 -0
  48. {fluidattacks_core-5.1.0/fluidattacks_core/authz → fluidattacks_core-6.0.0/fluidattacks_core/semver}/__init__.py +0 -0
  49. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/semver/match_versions.py +0 -0
  50. {fluidattacks_core-5.1.0/fluidattacks_core/semver → fluidattacks_core-6.0.0/fluidattacks_core/serializers}/__init__.py +0 -0
  51. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/serializers/snippet.py +0 -0
  52. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core/serializers/syntax.py +0 -0
  53. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core.egg-info/dependency_links.txt +0 -0
  54. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/fluidattacks_core.egg-info/top_level.txt +0 -0
  55. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/setup.cfg +0 -0
  56. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_aio_tasks.py +0 -0
  57. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_extract_db.py +0 -0
  58. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_language_detection.py +0 -0
  59. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_logging.py +0 -0
  60. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_make_snippet.py +0 -0
  61. {fluidattacks_core-5.1.0 → fluidattacks_core-6.0.0}/test/test_match_versions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fluidattacks-core
3
- Version: 5.1.0
3
+ Version: 6.0.0
4
4
  Summary: Fluid Attacks Core Library
5
5
  Author-email: Development <development@fluidattacks.com>
6
6
  License: MPL-2.0
@@ -14,10 +14,10 @@ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  Provides-Extra: aio
16
16
  Requires-Dist: uvloop>=0.21.0; extra == "aio"
17
- Provides-Extra: authz
18
17
  Provides-Extra: git
19
18
  Requires-Dist: aiohttp>=3.10.0; extra == "git"
20
19
  Requires-Dist: aiofiles>=23.2.1; extra == "git"
20
+ Requires-Dist: anyio>=4.7.0; extra == "git"
21
21
  Requires-Dist: boto3>=1.34; extra == "git"
22
22
  Requires-Dist: botocore>=1.40.18; extra == "git"
23
23
  Requires-Dist: GitPython>=3.1.41; extra == "git"
@@ -48,6 +48,7 @@ Requires-Dist: tree-sitter>=0.25.2; extra == "serializers"
48
48
  Requires-Dist: tree-sitter-dart-orchard==0.3.2; extra == "serializers"
49
49
  Provides-Extra: cpg
50
50
  Requires-Dist: aioboto3>=13.3.0; extra == "cpg"
51
+ Requires-Dist: anyio>=4.7.0; extra == "cpg"
51
52
  Requires-Dist: platformdirs>=4.3.8; extra == "cpg"
52
53
  Provides-Extra: filesystem
53
54
  Provides-Extra: sarif
@@ -55,7 +56,6 @@ Requires-Dist: pydantic>=2.12.3; extra == "sarif"
55
56
  Provides-Extra: semver
56
57
  Provides-Extra: all
57
58
  Requires-Dist: fluidattacks-core[aio]; extra == "all"
58
- Requires-Dist: fluidattacks-core[authz]; extra == "all"
59
59
  Requires-Dist: fluidattacks-core[cpg]; extra == "all"
60
60
  Requires-Dist: fluidattacks-core[filesystem]; extra == "all"
61
61
  Requires-Dist: fluidattacks-core[git]; extra == "all"
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
  import logging
3
- from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Coroutine, Iterable
3
+ from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Coroutine, Iterable, Iterator
4
4
  from contextlib import suppress
5
5
  from typing import Any, Literal, TypeVar, cast, overload
6
6
 
@@ -134,6 +134,23 @@ async def _consume_generator(
134
134
  await queue.put(_GENERATOR_DONE_SENTINEL)
135
135
 
136
136
 
137
+ def _start_initial_generator_tasks(
138
+ gen_iter: Iterator[AsyncGenerator[T, None]],
139
+ limit: int,
140
+ queue: asyncio.Queue[T | object],
141
+ active_generators: list[int],
142
+ ) -> list[asyncio.Task[None]]:
143
+ tasks: list[asyncio.Task[None]] = []
144
+ # Start initial tasks up to the limit
145
+ for _ in range(limit):
146
+ try:
147
+ gen = next(gen_iter)
148
+ tasks.append(asyncio.create_task(_consume_generator(gen, queue, active_generators)))
149
+ except StopIteration:
150
+ break
151
+ return tasks
152
+
153
+
137
154
  async def merge_async_generators(
138
155
  generators: Iterable[AsyncGenerator[T, None]],
139
156
  limit: int,
@@ -170,18 +187,8 @@ async def merge_async_generators(
170
187
 
171
188
  queue: asyncio.Queue[T | object] = asyncio.Queue()
172
189
  active_generators = [0] # Use list to allow modification in nested function
173
- tasks: list[asyncio.Task[None]] = []
174
-
175
190
  gen_iter = iter(generators)
176
-
177
- # Start initial tasks up to the limit
178
- for _ in range(limit):
179
- try:
180
- gen = next(gen_iter)
181
- tasks.append(asyncio.create_task(_consume_generator(gen, queue, active_generators)))
182
- except StopIteration:
183
- break
184
-
191
+ tasks = _start_initial_generator_tasks(gen_iter, limit, queue, active_generators)
185
192
  # Keep track of how many generators we expect to finish
186
193
  expected_done_signals = len(tasks)
187
194
  done_signals_received = 0
@@ -3,6 +3,7 @@ import hashlib
3
3
  from contextlib import suppress
4
4
  from pathlib import Path
5
5
 
6
+ import anyio
6
7
  from aioboto3 import Session
7
8
  from platformdirs import user_cache_dir
8
9
 
@@ -83,7 +84,7 @@ async def generate_cpg(
83
84
  exclude: list[Path] | None = None,
84
85
  ) -> Path | None:
85
86
  cache_dir = Path(user_cache_dir("sifts"))
86
- cache_dir.mkdir(parents=True, exist_ok=True)
87
+ await anyio.Path(cache_dir).mkdir(parents=True, exist_ok=True)
87
88
  try:
88
89
  relative_path = working_dir.relative_to(await _get_repo_top_level(working_dir))
89
90
  except ValueError:
@@ -134,7 +135,7 @@ async def get_cpg(
134
135
  repo_nickname: str,
135
136
  ) -> Path | None:
136
137
  cache_dir = Path(user_cache_dir("sifts"))
137
- cache_dir.mkdir(parents=True, exist_ok=True)
138
+ await anyio.Path(cache_dir).mkdir(parents=True, exist_ok=True)
138
139
  try:
139
140
  relative_path = working_dir.relative_to(await _get_repo_top_level(working_dir))
140
141
  except ValueError:
@@ -17,6 +17,61 @@ if TYPE_CHECKING:
17
17
  from collections.abc import Iterable
18
18
 
19
19
 
20
+ # Language priority mapping (higher number = higher priority)
21
+ # This helps resolve conflicts between similar languages
22
+ _LANGUAGE_PRIORITIES = {
23
+ Language.TypeScript: 10, # TypeScript has priority over JavaScript
24
+ Language.JavaScript: 5,
25
+ Language.Kotlin: 8, # Kotlin has priority over Java
26
+ Language.Java: 6,
27
+ Language.Rust: 9, # Rust has priority over C
28
+ Language.C: 4,
29
+ Language.Scala: 7, # Scala has priority over Java
30
+ Language.Dart: 8, # Dart has priority over JavaScript
31
+ Language.Python: 7,
32
+ Language.Go: 8,
33
+ Language.PHP: 6,
34
+ Language.Ruby: 6,
35
+ Language.CSharp: 7,
36
+ Language.Swift: 8,
37
+ }
38
+
39
+
40
+ def _calculate_language_score(
41
+ names: set[str],
42
+ markers: dict[str, set[str] | list[str]],
43
+ ) -> int:
44
+ exacts: set[str] = {n.casefold() for n in markers["names"]}
45
+ patterns: list[str] = list(markers["globs"])
46
+ # Check exact name matches (higher confidence)
47
+ score = len([n for n in exacts if n in names]) * 10
48
+ # Check glob pattern matches (lower confidence)
49
+ glob_matches = sum(1 for f in names if any(fnmatch(f, pat) for pat in patterns))
50
+ return score + glob_matches * 5
51
+
52
+
53
+ def _resolve_language_conflicts(
54
+ hits: list[Language],
55
+ language_scores: dict[Language, int],
56
+ ) -> list[Language]:
57
+ # Resolve conflicts using priority system.
58
+ if len(hits) <= 1:
59
+ return hits
60
+ # Sort by priority (descending) and then by confidence score (descending)
61
+ hits.sort(
62
+ key=lambda lang: (_LANGUAGE_PRIORITIES.get(lang, 0), language_scores.get(lang, 0)),
63
+ reverse=True,
64
+ )
65
+ # Remove lower priority languages that conflict with higher priority ones
66
+ resolved_hits: list[Language] = []
67
+ for lang in hits:
68
+ # Check if this language conflicts with any already resolved language
69
+ conflicts = _get_language_conflicts(lang)
70
+ if not any(conflict in resolved_hits for conflict in conflicts):
71
+ resolved_hits.append(lang)
72
+ return resolved_hits
73
+
74
+
20
75
  def _detect_languages_in_dir(files: Iterable[str]) -> list[Language]:
21
76
  """Return programming languages detected in a directory via exact filenames or glob patterns.
22
77
 
@@ -24,74 +79,15 @@ def _detect_languages_in_dir(files: Iterable[str]) -> list[Language]:
24
79
  """
25
80
  names = {f.casefold() for f in files}
26
81
  hits: list[Language] = []
27
-
28
- # Language priority mapping (higher number = higher priority)
29
- # This helps resolve conflicts between similar languages
30
- language_priorities = {
31
- Language.TypeScript: 10, # TypeScript has priority over JavaScript
32
- Language.JavaScript: 5,
33
- Language.Kotlin: 8, # Kotlin has priority over Java
34
- Language.Java: 6,
35
- Language.Rust: 9, # Rust has priority over C
36
- Language.C: 4,
37
- Language.Scala: 7, # Scala has priority over Java
38
- Language.Dart: 8, # Dart has priority over JavaScript
39
- Language.Python: 7,
40
- Language.Go: 8,
41
- Language.PHP: 6,
42
- Language.Ruby: 6,
43
- Language.CSharp: 7,
44
- Language.Swift: 8,
45
- }
46
-
47
- # Track confidence scores for each language
48
82
  language_scores: dict[Language, int] = {}
49
83
 
50
84
  for lang, markers in CONFIG_MARKERS.items():
51
- exacts: set[str] = {n.casefold() for n in markers["names"]}
52
- patterns: list[str] = list(markers["globs"])
53
-
54
- score = 0
55
-
56
- # Check exact name matches (higher confidence)
57
- exact_matches = [n for n in exacts if n in names]
58
- if exact_matches:
59
- score += len(exact_matches) * 10 # Each exact match adds 10 points
60
-
61
- # Check glob pattern matches (lower confidence)
62
- glob_matches = 0
63
- for f in names:
64
- if any(fnmatch(f, pat) for pat in patterns):
65
- glob_matches += 1
66
- if glob_matches:
67
- score += glob_matches * 5 # Each glob match adds 5 points
68
-
85
+ score = _calculate_language_score(names, markers)
69
86
  if score > 0:
70
87
  language_scores[lang] = score
71
88
  hits.append(lang)
72
89
 
73
- # Resolve conflicts using priority system
74
- if len(hits) > 1:
75
- # Sort by priority (descending) and then by confidence score (descending)
76
- hits.sort(
77
- key=lambda lang: (
78
- language_priorities.get(lang, 0),
79
- language_scores.get(lang, 0),
80
- ),
81
- reverse=True,
82
- )
83
-
84
- # Remove lower priority languages that conflict with higher priority ones
85
- resolved_hits = []
86
- for lang in hits:
87
- # Check if this language conflicts with any already resolved language
88
- conflicts = _get_language_conflicts(lang)
89
- if not any(conflict in resolved_hits for conflict in conflicts):
90
- resolved_hits.append(lang)
91
-
92
- hits = resolved_hits
93
-
94
- return hits
90
+ return _resolve_language_conflicts(hits, language_scores)
95
91
 
96
92
 
97
93
  def _get_language_conflicts(lang: Language) -> set[Language]:
@@ -181,8 +177,9 @@ def _scan_dir(
181
177
 
182
178
  if langs:
183
179
  language = langs[0] if len(langs) == 1 else Language.Unknown
184
- exclusions = [sp[0].relative_to(dir_path).as_posix() for sp in subprojects]
185
- exclusions = _optimize_exclusions(exclusions)
180
+ exclusions = _optimize_exclusions(
181
+ [sp[0].relative_to(dir_path).as_posix() for sp in subprojects]
182
+ )
186
183
  return [(dir_path, language, exclusions), *subprojects]
187
184
 
188
185
  # if there is no project here, simply propagate the subprojects
@@ -1,14 +1,32 @@
1
1
  import logging
2
- from pathlib import Path
3
2
 
4
3
  import aiofiles
5
4
  import aiohttp
5
+ import anyio
6
6
 
7
7
  from .constants import DEFAULT_DOWNLOAD_BUFFER_SIZE
8
8
 
9
9
  LOGGER = logging.getLogger(__name__)
10
10
 
11
11
 
12
+ async def _write_response_to_file(
13
+ response: aiohttp.ClientResponse,
14
+ destination_path: str,
15
+ download_buffer_size: int,
16
+ ) -> bool:
17
+ async with aiofiles.open(destination_path, "wb") as file:
18
+ while True:
19
+ try:
20
+ chunk = await response.content.read(download_buffer_size)
21
+ except TimeoutError:
22
+ LOGGER.exception("Read timeout for path %s", destination_path)
23
+ return False
24
+ if not chunk:
25
+ break
26
+ await file.write(chunk)
27
+ return await anyio.Path(destination_path).exists()
28
+
29
+
12
30
  async def download_file(
13
31
  *,
14
32
  url: str,
@@ -26,15 +44,4 @@ async def download_file(
26
44
  )
27
45
  return False
28
46
 
29
- async with aiofiles.open(destination_path, "wb") as file:
30
- while True:
31
- try:
32
- chunk = await response.content.read(download_buffer_size)
33
- except TimeoutError:
34
- LOGGER.exception("Read timeout for path %s", destination_path)
35
- return False
36
- if not chunk:
37
- break
38
- await file.write(chunk)
39
-
40
- return Path(destination_path).exists()
47
+ return await _write_response_to_file(response, destination_path, download_buffer_size)
@@ -5,6 +5,7 @@ import tarfile
5
5
  import tempfile
6
6
  from pathlib import Path
7
7
 
8
+ import anyio
8
9
  from git import GitError
9
10
  from git.cmd import Git
10
11
  from git.repo import Repo
@@ -87,7 +88,7 @@ async def download_repo_from_s3(
87
88
  *,
88
89
  download_buffer_size: int = DEFAULT_DOWNLOAD_BUFFER_SIZE,
89
90
  ) -> bool:
90
- destination_path.parent.mkdir(parents=True, exist_ok=True)
91
+ await anyio.Path(destination_path.parent).mkdir(parents=True, exist_ok=True)
91
92
  with tempfile.TemporaryDirectory(prefix="fluidattacks_", ignore_cleanup_errors=True) as tmpdir:
92
93
  tmp_path = Path(tmpdir)
93
94
  file_path = tmp_path / "repo.tar.gz"
@@ -104,7 +105,7 @@ async def download_repo_from_s3(
104
105
  with tarfile.open(file_path, "r:gz") as tar_handler:
105
106
  _safe_extract_tar(tar_handler, tmp_path)
106
107
 
107
- extracted_dirs = [d for d in tmp_path.iterdir() if d.is_dir()]
108
+ extracted_dirs = [d async for d in anyio.Path(tmp_path).iterdir() if await d.is_dir()]
108
109
  if not extracted_dirs:
109
110
  LOGGER.error("No directory found in the extracted archive: %s", destination_path)
110
111
  return False
@@ -116,7 +117,7 @@ async def download_repo_from_s3(
116
117
  )
117
118
  extracted_dir = extracted_dirs[0]
118
119
 
119
- if destination_path.exists():
120
+ if await anyio.Path(destination_path).exists():
120
121
  shutil.rmtree(destination_path)
121
122
 
122
123
  shutil.move(extracted_dir, destination_path)
@@ -127,10 +128,10 @@ async def download_repo_from_s3(
127
128
  )
128
129
  return False
129
130
 
130
- if not await reset_repo(str(destination_path.absolute())):
131
+ if not await reset_repo(str(destination_path)):
131
132
  shutil.rmtree(destination_path, ignore_errors=True)
132
133
  return False
133
134
 
134
- delete_out_of_scope_files(git_ignore or [], str(destination_path.absolute()))
135
+ delete_out_of_scope_files(git_ignore or [], str(destination_path))
135
136
 
136
137
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fluidattacks-core
3
- Version: 5.1.0
3
+ Version: 6.0.0
4
4
  Summary: Fluid Attacks Core Library
5
5
  Author-email: Development <development@fluidattacks.com>
6
6
  License: MPL-2.0
@@ -14,10 +14,10 @@ Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown
15
15
  Provides-Extra: aio
16
16
  Requires-Dist: uvloop>=0.21.0; extra == "aio"
17
- Provides-Extra: authz
18
17
  Provides-Extra: git
19
18
  Requires-Dist: aiohttp>=3.10.0; extra == "git"
20
19
  Requires-Dist: aiofiles>=23.2.1; extra == "git"
20
+ Requires-Dist: anyio>=4.7.0; extra == "git"
21
21
  Requires-Dist: boto3>=1.34; extra == "git"
22
22
  Requires-Dist: botocore>=1.40.18; extra == "git"
23
23
  Requires-Dist: GitPython>=3.1.41; extra == "git"
@@ -48,6 +48,7 @@ Requires-Dist: tree-sitter>=0.25.2; extra == "serializers"
48
48
  Requires-Dist: tree-sitter-dart-orchard==0.3.2; extra == "serializers"
49
49
  Provides-Extra: cpg
50
50
  Requires-Dist: aioboto3>=13.3.0; extra == "cpg"
51
+ Requires-Dist: anyio>=4.7.0; extra == "cpg"
51
52
  Requires-Dist: platformdirs>=4.3.8; extra == "cpg"
52
53
  Provides-Extra: filesystem
53
54
  Provides-Extra: sarif
@@ -55,7 +56,6 @@ Requires-Dist: pydantic>=2.12.3; extra == "sarif"
55
56
  Provides-Extra: semver
56
57
  Provides-Extra: all
57
58
  Requires-Dist: fluidattacks-core[aio]; extra == "all"
58
- Requires-Dist: fluidattacks-core[authz]; extra == "all"
59
59
  Requires-Dist: fluidattacks-core[cpg]; extra == "all"
60
60
  Requires-Dist: fluidattacks-core[filesystem]; extra == "all"
61
61
  Requires-Dist: fluidattacks-core[git]; extra == "all"
@@ -12,9 +12,6 @@ fluidattacks_core/aio/processes.py
12
12
  fluidattacks_core/aio/runners.py
13
13
  fluidattacks_core/aio/tasks.py
14
14
  fluidattacks_core/aio/threads.py
15
- fluidattacks_core/authz/__init__.py
16
- fluidattacks_core/authz/py.typed
17
- fluidattacks_core/authz/types.py
18
15
  fluidattacks_core/cpg/__init__.py
19
16
  fluidattacks_core/cpg/joern.py
20
17
  fluidattacks_core/filesystem/__init__.py
@@ -4,7 +4,6 @@ uvloop>=0.21.0
4
4
 
5
5
  [all]
6
6
  fluidattacks-core[aio]
7
- fluidattacks-core[authz]
8
7
  fluidattacks-core[cpg]
9
8
  fluidattacks-core[filesystem]
10
9
  fluidattacks-core[git]
@@ -14,10 +13,9 @@ fluidattacks-core[sarif]
14
13
  fluidattacks-core[semver]
15
14
  fluidattacks-core[serializers]
16
15
 
17
- [authz]
18
-
19
16
  [cpg]
20
17
  aioboto3>=13.3.0
18
+ anyio>=4.7.0
21
19
  platformdirs>=4.3.8
22
20
 
23
21
  [filesystem]
@@ -25,6 +23,7 @@ platformdirs>=4.3.8
25
23
  [git]
26
24
  aiohttp>=3.10.0
27
25
  aiofiles>=23.2.1
26
+ anyio>=4.7.0
28
27
  boto3>=1.34
29
28
  botocore>=1.40.18
30
29
  GitPython>=3.1.41
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fluidattacks-core"
3
- version = "5.1.0"
3
+ version = "6.0.0"
4
4
  description = "Fluid Attacks Core Library"
5
5
  authors = [{ name = "Development", email = "development@fluidattacks.com" }]
6
6
  license = { text = "MPL-2.0" }
@@ -21,10 +21,10 @@ dependencies = []
21
21
 
22
22
  [project.optional-dependencies]
23
23
  aio = ["uvloop>=0.21.0"]
24
- authz = []
25
24
  git = [
26
25
  "aiohttp>=3.10.0",
27
26
  "aiofiles>=23.2.1",
27
+ "anyio>=4.7.0",
28
28
  "boto3>=1.34",
29
29
  "botocore>=1.40.18",
30
30
  "GitPython>=3.1.41",
@@ -50,13 +50,12 @@ serializers = [
50
50
  "tree-sitter>=0.25.2",
51
51
  "tree-sitter-dart-orchard==0.3.2",
52
52
  ]
53
- cpg = ["aioboto3>=13.3.0", "platformdirs>=4.3.8"]
53
+ cpg = ["aioboto3>=13.3.0", "anyio>=4.7.0", "platformdirs>=4.3.8"]
54
54
  filesystem = []
55
55
  sarif = ["pydantic>=2.12.3"]
56
56
  semver = []
57
57
  all = [
58
58
  "fluidattacks-core[aio]",
59
- "fluidattacks-core[authz]",
60
59
  "fluidattacks-core[cpg]",
61
60
  "fluidattacks-core[filesystem]",
62
61
  "fluidattacks-core[git]",
@@ -73,11 +72,11 @@ dev = [
73
72
  "botocore-stubs==1.35.71",
74
73
  "datamodel-code-generator>=0.35.0",
75
74
  "deptry==0.24.0",
76
- "import-linter==2.5.2",
77
- "mypy==1.18.2",
75
+ "import-linter==2.9",
76
+ "mypy==1.19.1",
78
77
  "pytest-asyncio>=1.1.0",
79
- "pytest==8.4.1",
80
- "ruff==0.14.0",
78
+ "pytest==9.0.2",
79
+ "ruff==0.15.0",
81
80
  "types-aioboto3[s3]>=15.1.0",
82
81
  "types-aiofiles==24.1.0.20240626",
83
82
  "types-simplejson>=3.20.0.20250822",
@@ -1,75 +0,0 @@
1
- from __future__ import (
2
- annotations,
3
- )
4
-
5
- from dataclasses import (
6
- dataclass,
7
- )
8
- from typing import (
9
- Literal,
10
- TypedDict,
11
- )
12
-
13
- AuthzType = Literal[
14
- "admin",
15
- "user",
16
- "organization",
17
- "group",
18
- "root",
19
- ]
20
-
21
- AuthzRelation = Literal[
22
- "admin",
23
- "parent",
24
- "customer_manage",
25
- "customer_write",
26
- "customer_read",
27
- "fluid_manage",
28
- "fluid_write",
29
- "fluid_read",
30
- "manage",
31
- "write",
32
- "read",
33
- ]
34
-
35
-
36
- @dataclass(frozen=True, kw_only=True)
37
- class AuthzConditionFluidEmail:
38
- email: str
39
-
40
- class _ReturnTypeContext(TypedDict):
41
- email: str
42
-
43
- class _ReturnType(TypedDict):
44
- name: Literal["fluid_email"]
45
- context: AuthzConditionFluidEmail._ReturnTypeContext
46
-
47
- def __call__(self) -> _ReturnType:
48
- return {
49
- "name": "fluid_email",
50
- "context": {"email": self.email},
51
- }
52
-
53
-
54
- @dataclass(frozen=True, kw_only=True)
55
- class AuthzTuple:
56
- user_type: AuthzType
57
- user: str
58
- relation: AuthzRelation
59
- object_type: AuthzType
60
- object: str
61
- condition: AuthzConditionFluidEmail | None = None
62
-
63
- class _ReturnType(TypedDict):
64
- user: str
65
- relation: AuthzRelation
66
- object: str
67
- condition: AuthzConditionFluidEmail._ReturnType | None
68
-
69
- def __call__(self) -> _ReturnType:
70
- return {
71
- "user": f"{self.user_type}:{self.user}",
72
- "relation": self.relation,
73
- "object": f"{self.object_type}:{self.object}",
74
- "condition": self.condition() if self.condition else None,
75
- }
File without changes