open-code-review-toolkit 0.2.1__tar.gz → 0.3.1__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.
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/PKG-INFO +4 -3
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/README.md +3 -2
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/pyproject.toml +7 -13
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/_version.py +2 -2
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/cli.py +28 -3
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/manifests.py +27 -15
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/repo.py +4 -2
- open_code_review_toolkit-0.3.1/src/ocr_toolkit/mcp_config.py +479 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/gitlab.py +14 -10
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/markers.py +6 -4
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/workflow.py +6 -31
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/preflight.py +1 -1
- open_code_review_toolkit-0.3.1/src/ocr_toolkit/review_runner.py +117 -0
- open_code_review_toolkit-0.2.1/CHANGELOG.md +0 -61
- open_code_review_toolkit-0.2.1/CONTRIBUTING.md +0 -14
- open_code_review_toolkit-0.2.1/SECURITY.md +0 -13
- open_code_review_toolkit-0.2.1/changelog.d/README.md +0 -3
- open_code_review_toolkit-0.2.1/docs/codex/AGENT_EXECUTION_PITFALLS.md +0 -44
- open_code_review_toolkit-0.2.1/docs/codex/TASKS_BACKLOG.md +0 -336
- open_code_review_toolkit-0.2.1/docs/configuration.md +0 -67
- open_code_review_toolkit-0.2.1/docs/development.md +0 -19
- open_code_review_toolkit-0.2.1/docs/engineering/project_principles.md +0 -30
- open_code_review_toolkit-0.2.1/docs/engineering/toolkit_strategy.md +0 -145
- open_code_review_toolkit-0.2.1/docs/gitlab.md +0 -31
- open_code_review_toolkit-0.2.1/docs/operations.md +0 -83
- open_code_review_toolkit-0.2.1/docs/release.md +0 -49
- open_code_review_toolkit-0.2.1/docs/security.md +0 -29
- open_code_review_toolkit-0.2.1/examples/gitlab/ocr-review.gitlab-ci.yml +0 -84
- open_code_review_toolkit-0.2.1/examples/gitlab/rules.json +0 -33
- open_code_review_toolkit-0.2.1/src/ocr_toolkit/mcp_config.py +0 -257
- open_code_review_toolkit-0.2.1/tests/__init__.py +0 -1
- open_code_review_toolkit-0.2.1/tests/support.py +0 -85
- open_code_review_toolkit-0.2.1/tests/test_cli.py +0 -39
- open_code_review_toolkit-0.2.1/tests/test_common_helpers.py +0 -391
- open_code_review_toolkit-0.2.1/tests/test_context_helpers.py +0 -1946
- open_code_review_toolkit-0.2.1/tests/test_install_local_artifact.py +0 -67
- open_code_review_toolkit-0.2.1/tests/test_operations_docs.py +0 -58
- open_code_review_toolkit-0.2.1/tests/test_posting_helpers.py +0 -1757
- open_code_review_toolkit-0.2.1/tests/test_project_strategy.py +0 -109
- open_code_review_toolkit-0.2.1/tests/test_quality_script.py +0 -12
- open_code_review_toolkit-0.2.1/tests/test_release_authorization.py +0 -107
- open_code_review_toolkit-0.2.1/tests/test_release_notes.py +0 -46
- open_code_review_toolkit-0.2.1/tests/test_release_process_docs.py +0 -30
- open_code_review_toolkit-0.2.1/tests/test_runtime_helpers.py +0 -880
- open_code_review_toolkit-0.2.1/tests/test_testpypi_preview.py +0 -238
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/.gitignore +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/LICENSE +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/__init__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/common/__init__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/common/language.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/common/markdown.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/common/redaction.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/config_writer.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/configure.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/__init__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/__main__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/ansible.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/categorize.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/instructions.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/planner.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/render.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/settings.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/__init__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/__main__.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/comments.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/formatting.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/payloads.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/result.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/settings.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/posting/snapshot.py +0 -0
- {open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: open-code-review-toolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Unofficial GitLab CI integration layer for Open Code Review
|
|
5
5
|
Project-URL: Homepage, https://github.com/xeonvs/open-code-review-toolkit
|
|
6
6
|
Project-URL: Repository, https://github.com/xeonvs/open-code-review-toolkit
|
|
@@ -243,7 +243,8 @@ ocr --version
|
|
|
243
243
|
ocr-ci --help
|
|
244
244
|
```
|
|
245
245
|
|
|
246
|
-
The current compatibility target is OCR `1.
|
|
246
|
+
The current compatibility target is OCR `1.8.0`. CI should pin the release and verify its published checksum before execution.
|
|
247
|
+
The [versioned compatibility policy](docs/compatibility.md) records tested assets and evidence and describes the conservative Dependabot-like qualification workflow for later upstream releases.
|
|
247
248
|
Review output defaults to English. Set `OCR_REVIEW_LANGUAGE=Russian` to use Russian consistently in both OCR configuration and generated review context.
|
|
248
249
|
|
|
249
250
|
Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
|
|
@@ -276,7 +277,7 @@ ocr-ci preflight
|
|
|
276
277
|
ocr-ci configure
|
|
277
278
|
ocr-ci mcp-config
|
|
278
279
|
ocr-ci context --output .review-context/dependencies.md
|
|
279
|
-
|
|
280
|
+
ocr-ci review --result /tmp/ocr-result.json --stderr /tmp/ocr-stderr.log -- ... --format json
|
|
280
281
|
ocr-ci post --result /tmp/ocr-result.json --stderr /tmp/ocr-stderr.log
|
|
281
282
|
```
|
|
282
283
|
|
|
@@ -15,7 +15,8 @@ ocr --version
|
|
|
15
15
|
ocr-ci --help
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
The current compatibility target is OCR `1.
|
|
18
|
+
The current compatibility target is OCR `1.8.0`. CI should pin the release and verify its published checksum before execution.
|
|
19
|
+
The [versioned compatibility policy](docs/compatibility.md) records tested assets and evidence and describes the conservative Dependabot-like qualification workflow for later upstream releases.
|
|
19
20
|
Review output defaults to English. Set `OCR_REVIEW_LANGUAGE=Russian` to use Russian consistently in both OCR configuration and generated review context.
|
|
20
21
|
|
|
21
22
|
Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
|
|
@@ -48,7 +49,7 @@ ocr-ci preflight
|
|
|
48
49
|
ocr-ci configure
|
|
49
50
|
ocr-ci mcp-config
|
|
50
51
|
ocr-ci context --output .review-context/dependencies.md
|
|
51
|
-
|
|
52
|
+
ocr-ci review --result /tmp/ocr-result.json --stderr /tmp/ocr-stderr.log -- ... --format json
|
|
52
53
|
ocr-ci post --result /tmp/ocr-result.json --stderr /tmp/ocr-stderr.log
|
|
53
54
|
```
|
|
54
55
|
|
|
@@ -38,6 +38,7 @@ ocr-ci = "ocr_toolkit.cli:main"
|
|
|
38
38
|
|
|
39
39
|
[dependency-groups]
|
|
40
40
|
dev = [
|
|
41
|
+
"bandit==1.9.4",
|
|
41
42
|
"build>=1.2.2",
|
|
42
43
|
"coverage[toml]>=7.6",
|
|
43
44
|
"hatch-vcs>=0.4",
|
|
@@ -60,19 +61,7 @@ version-file = "src/ocr_toolkit/_version.py"
|
|
|
60
61
|
packages = ["src/ocr_toolkit"]
|
|
61
62
|
|
|
62
63
|
[tool.hatch.build.targets.sdist]
|
|
63
|
-
include = [
|
|
64
|
-
"/src",
|
|
65
|
-
"/tests",
|
|
66
|
-
"/examples",
|
|
67
|
-
"/docs",
|
|
68
|
-
"/changelog.d",
|
|
69
|
-
"/README.md",
|
|
70
|
-
"/CONTRIBUTING.md",
|
|
71
|
-
"/SECURITY.md",
|
|
72
|
-
"/LICENSE",
|
|
73
|
-
"/CHANGELOG.md",
|
|
74
|
-
"/pyproject.toml",
|
|
75
|
-
]
|
|
64
|
+
only-include = ["src", "README.md", "LICENSE", "pyproject.toml"]
|
|
76
65
|
|
|
77
66
|
[tool.hatch.version.raw-options]
|
|
78
67
|
fallback_version = "0.3.0.dev0"
|
|
@@ -101,6 +90,11 @@ exclude = ["src/ocr_toolkit/_version.py"]
|
|
|
101
90
|
warn_unreachable = false
|
|
102
91
|
disable_error_code = ["arg-type", "assignment", "import-not-found", "index", "name-defined", "no-any-return", "no-redef", "union-attr", "unused-ignore", "var-annotated"]
|
|
103
92
|
|
|
93
|
+
[tool.bandit]
|
|
94
|
+
exclude_dirs = ["tests"]
|
|
95
|
+
severity = "medium"
|
|
96
|
+
confidence = "medium"
|
|
97
|
+
|
|
104
98
|
[tool.pytest.ini_options]
|
|
105
99
|
addopts = "--strict-config --strict-markers"
|
|
106
100
|
testpaths = ["tests"]
|
{open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/_version.py
RENAMED
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.3.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
+
import sys
|
|
6
7
|
from collections.abc import Sequence
|
|
8
|
+
from pathlib import Path
|
|
7
9
|
|
|
8
|
-
from ocr_toolkit import configure, mcp_config, preflight
|
|
10
|
+
from ocr_toolkit import configure, mcp_config, preflight, review_runner
|
|
9
11
|
from ocr_toolkit.context import render as context_render
|
|
10
12
|
from ocr_toolkit.posting.workflow import main as posting_main
|
|
11
13
|
|
|
@@ -21,6 +23,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
21
23
|
subparsers.add_parser("preflight", help="Validate OCR, GitLab, and LLM access.")
|
|
22
24
|
subparsers.add_parser("configure", help="Write the OCR runtime configuration.")
|
|
23
25
|
subparsers.add_parser("mcp-config", help="Write OCR MCP server configuration.")
|
|
26
|
+
review_parser = subparsers.add_parser(
|
|
27
|
+
"review", help="Run OCR with private artifacts and safe failure diagnostics."
|
|
28
|
+
)
|
|
29
|
+
review_parser.add_argument("--result", required=True, help="OCR JSON output path.")
|
|
30
|
+
review_parser.add_argument("--stderr", required=True, help="Full OCR stderr artifact path.")
|
|
31
|
+
review_parser.add_argument(
|
|
32
|
+
"ocr_args", nargs=argparse.REMAINDER, help="OCR review arguments after --."
|
|
33
|
+
)
|
|
24
34
|
|
|
25
35
|
context_parser = subparsers.add_parser(
|
|
26
36
|
"context", help="Generate bounded repository review context."
|
|
@@ -33,9 +43,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
33
43
|
|
|
34
44
|
post_parser = subparsers.add_parser("post", help="Publish an OCR result artifact to GitLab.")
|
|
35
45
|
post_parser.add_argument(
|
|
36
|
-
|
|
46
|
+
# The public GitLab example writes this fixed path inside an isolated CI job.
|
|
47
|
+
"--result",
|
|
48
|
+
default="/tmp/ocr-result.json", # nosec B108
|
|
49
|
+
help="OCR JSON result path.",
|
|
50
|
+
)
|
|
51
|
+
post_parser.add_argument(
|
|
52
|
+
# The file contains only the current job's OCR stderr and is never shared.
|
|
53
|
+
"--stderr",
|
|
54
|
+
default="/tmp/ocr-stderr.log", # nosec B108
|
|
55
|
+
help="OCR stderr log path.",
|
|
37
56
|
)
|
|
38
|
-
post_parser.add_argument("--stderr", default="/tmp/ocr-stderr.log", help="OCR stderr log path.")
|
|
39
57
|
return parser
|
|
40
58
|
|
|
41
59
|
|
|
@@ -49,6 +67,13 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
49
67
|
return configure.main()
|
|
50
68
|
if args.command == "mcp-config":
|
|
51
69
|
return mcp_config.configure_mcp_servers()
|
|
70
|
+
if args.command == "review":
|
|
71
|
+
ocr_args = args.ocr_args[1:] if args.ocr_args[:1] == ["--"] else args.ocr_args
|
|
72
|
+
try:
|
|
73
|
+
return review_runner.run_review(Path(args.result), Path(args.stderr), ocr_args)
|
|
74
|
+
except review_runner.ReviewRunnerError as exc:
|
|
75
|
+
print(f"Cannot run Open Code Review: {exc}", file=sys.stderr)
|
|
76
|
+
return 2
|
|
52
77
|
if args.command == "context":
|
|
53
78
|
return context_render.main(["--output", args.output])
|
|
54
79
|
if args.command == "post":
|
|
@@ -196,9 +196,9 @@ def parse_pyproject(path: Path) -> dict[str, Any]:
|
|
|
196
196
|
|
|
197
197
|
try:
|
|
198
198
|
try:
|
|
199
|
-
import tomllib
|
|
199
|
+
import tomllib # type: ignore[import-untyped]
|
|
200
200
|
except ModuleNotFoundError:
|
|
201
|
-
import tomli as tomllib
|
|
201
|
+
import tomli as tomllib
|
|
202
202
|
|
|
203
203
|
data = tomllib.loads(text)
|
|
204
204
|
except ModuleNotFoundError:
|
|
@@ -209,9 +209,12 @@ def parse_pyproject(path: Path) -> dict[str, Any]:
|
|
|
209
209
|
if not isinstance(data, dict):
|
|
210
210
|
return {"present": True, "parse_error": JSON_OBJECT_PARSE_ERROR}
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
raw_project = data.get("project")
|
|
213
|
+
raw_tool = data.get("tool")
|
|
214
|
+
project: dict[Any, Any] = raw_project if isinstance(raw_project, dict) else {}
|
|
215
|
+
tool: dict[Any, Any] = raw_tool if isinstance(raw_tool, dict) else {}
|
|
216
|
+
raw_poetry = tool.get("poetry")
|
|
217
|
+
poetry: dict[Any, Any] = raw_poetry if isinstance(raw_poetry, dict) else {}
|
|
215
218
|
|
|
216
219
|
dependencies: list[str] = []
|
|
217
220
|
if isinstance(project.get("dependencies"), list):
|
|
@@ -233,12 +236,14 @@ def parse_pyproject(path: Path) -> dict[str, Any]:
|
|
|
233
236
|
f"group.{group_name}: {redact_url_userinfo(str(dep))}" for dep in group_deps
|
|
234
237
|
)
|
|
235
238
|
|
|
236
|
-
|
|
239
|
+
raw_poetry_deps = poetry.get("dependencies")
|
|
240
|
+
poetry_deps: dict[Any, Any] = raw_poetry_deps if isinstance(raw_poetry_deps, dict) else {}
|
|
237
241
|
for name, version in poetry_deps.items():
|
|
238
242
|
if str(name).lower() != "python":
|
|
239
243
|
dependencies.append(f"{name}: {redact_url_userinfo(str(version))}")
|
|
240
244
|
|
|
241
|
-
|
|
245
|
+
raw_poetry_groups = poetry.get("group")
|
|
246
|
+
poetry_groups: dict[Any, Any] = raw_poetry_groups if isinstance(raw_poetry_groups, dict) else {}
|
|
242
247
|
for group_name, group_value in poetry_groups.items():
|
|
243
248
|
if not isinstance(group_value, dict):
|
|
244
249
|
continue
|
|
@@ -354,10 +359,14 @@ def parse_composer_json(path: Path) -> dict[str, Any]:
|
|
|
354
359
|
if not isinstance(data, dict):
|
|
355
360
|
return {"present": True, "parse_error": JSON_OBJECT_PARSE_ERROR}
|
|
356
361
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
362
|
+
raw_require = data.get("require")
|
|
363
|
+
raw_require_dev = data.get("require-dev")
|
|
364
|
+
raw_config = data.get("config")
|
|
365
|
+
require: dict[Any, Any] = raw_require if isinstance(raw_require, dict) else {}
|
|
366
|
+
require_dev: dict[Any, Any] = raw_require_dev if isinstance(raw_require_dev, dict) else {}
|
|
367
|
+
config: dict[Any, Any] = raw_config if isinstance(raw_config, dict) else {}
|
|
368
|
+
raw_platform = config.get("platform")
|
|
369
|
+
platform: dict[Any, Any] = raw_platform if isinstance(raw_platform, dict) else {}
|
|
361
370
|
|
|
362
371
|
platform_items, platform_omitted = limited_manifest_items(
|
|
363
372
|
[f"{name}: {version}" for name, version in platform.items()]
|
|
@@ -433,10 +442,13 @@ def parse_package_json(path: Path) -> dict[str, Any]:
|
|
|
433
442
|
if not isinstance(data, dict):
|
|
434
443
|
return {"present": True, "parse_error": JSON_OBJECT_PARSE_ERROR}
|
|
435
444
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
445
|
+
raw_engines = data.get("engines")
|
|
446
|
+
raw_dependencies = data.get("dependencies")
|
|
447
|
+
raw_dev_dependencies = data.get("devDependencies")
|
|
448
|
+
engines: dict[Any, Any] = raw_engines if isinstance(raw_engines, dict) else {}
|
|
449
|
+
dependencies: dict[Any, Any] = raw_dependencies if isinstance(raw_dependencies, dict) else {}
|
|
450
|
+
dev_dependencies: dict[Any, Any] = (
|
|
451
|
+
raw_dev_dependencies if isinstance(raw_dev_dependencies, dict) else {}
|
|
440
452
|
)
|
|
441
453
|
|
|
442
454
|
engines_items, engines_omitted = limited_manifest_items(
|
{open_code_review_toolkit-0.2.1 → open_code_review_toolkit-0.3.1}/src/ocr_toolkit/context/repo.py
RENAMED
|
@@ -162,11 +162,13 @@ def resolve_output_path(value: str) -> Path | None:
|
|
|
162
162
|
requested = Path(value)
|
|
163
163
|
logical_output = requested if requested.is_absolute() else root_lexical / requested
|
|
164
164
|
logical_output = logical_output.absolute()
|
|
165
|
-
|
|
165
|
+
# tempfile supplies the platform temp root; containment and symlink checks follow.
|
|
166
|
+
temp_lexical = Path(tempfile.gettempdir()).absolute() # nosec B108
|
|
166
167
|
allowed_roots = [(root_lexical, root), (root, root)]
|
|
167
168
|
temp_resolved = temp_lexical.resolve()
|
|
168
169
|
allowed_roots.extend([(temp_lexical, temp_resolved), (temp_resolved, temp_resolved)])
|
|
169
|
-
|
|
170
|
+
# POSIX /tmp may be a distinct lexical alias (for example, /private/tmp).
|
|
171
|
+
tmp_path = Path("/tmp") # nosec B108
|
|
170
172
|
if tmp_path.exists():
|
|
171
173
|
tmp_lexical = tmp_path.absolute()
|
|
172
174
|
tmp_resolved = tmp_path.resolve()
|