locci 0.1.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 (45) hide show
  1. locci-0.1.0/.gitignore +34 -0
  2. locci-0.1.0/LICENSE +21 -0
  3. locci-0.1.0/PKG-INFO +74 -0
  4. locci-0.1.0/README.md +51 -0
  5. locci-0.1.0/pyproject.toml +39 -0
  6. locci-0.1.0/scripts/stress_test.py +52 -0
  7. locci-0.1.0/src/locci/__init__.py +0 -0
  8. locci-0.1.0/src/locci/analyzer.py +633 -0
  9. locci-0.1.0/src/locci/cache.py +321 -0
  10. locci-0.1.0/src/locci/cli.py +743 -0
  11. locci-0.1.0/src/locci/diagnostics.py +68 -0
  12. locci-0.1.0/src/locci/doctor.py +153 -0
  13. locci-0.1.0/src/locci/exporter.py +161 -0
  14. locci-0.1.0/src/locci/expressions.py +232 -0
  15. locci-0.1.0/src/locci/gh_parser.py +592 -0
  16. locci-0.1.0/src/locci/graph.py +89 -0
  17. locci-0.1.0/src/locci/hooks.py +85 -0
  18. locci-0.1.0/src/locci/orchestrator.py +403 -0
  19. locci-0.1.0/src/locci/parser.py +158 -0
  20. locci-0.1.0/src/locci/remote_cache.py +109 -0
  21. locci-0.1.0/src/locci/safety.py +48 -0
  22. locci-0.1.0/src/locci/sandbox.py +145 -0
  23. locci-0.1.0/src/locci/secrets.py +49 -0
  24. locci-0.1.0/src/locci/setup.py +73 -0
  25. locci-0.1.0/tests/test_analyzer_monorepo.py +56 -0
  26. locci-0.1.0/tests/test_cache.py +71 -0
  27. locci-0.1.0/tests/test_cache_globs.py +38 -0
  28. locci-0.1.0/tests/test_continue_on_error.py +84 -0
  29. locci-0.1.0/tests/test_detectors.py +104 -0
  30. locci-0.1.0/tests/test_exporter.py +51 -0
  31. locci-0.1.0/tests/test_expressions.py +46 -0
  32. locci-0.1.0/tests/test_expressions_outputs.py +57 -0
  33. locci-0.1.0/tests/test_gh_parser.py +91 -0
  34. locci-0.1.0/tests/test_github.py +37 -0
  35. locci-0.1.0/tests/test_graph_affected.py +59 -0
  36. locci-0.1.0/tests/test_integration.py +86 -0
  37. locci-0.1.0/tests/test_orchestrator.py +28 -0
  38. locci-0.1.0/tests/test_parser.py +45 -0
  39. locci-0.1.0/tests/test_remote_cache.py +122 -0
  40. locci-0.1.0/tests/test_sandbox.py +6 -0
  41. locci-0.1.0/tests/test_secret_export_leak.py +55 -0
  42. locci-0.1.0/tests/test_secrets.py +43 -0
  43. locci-0.1.0/tests/test_secrets_broadcast.py +57 -0
  44. locci-0.1.0/tests/test_services.py +56 -0
  45. locci-0.1.0/tests/test_upgrade_mvp.py +340 -0
locci-0.1.0/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ *.egg
8
+ *.egg-info/
9
+ dist/
10
+ build/
11
+ .eggs/
12
+ .venv/
13
+ venv/
14
+ env/
15
+ .env
16
+
17
+ # Locci cache
18
+ .locci/
19
+ .locci_cache/
20
+ ~/.locci/
21
+
22
+ # Editor
23
+ .idea/
24
+ .vscode/
25
+ *.swp
26
+ *.swo
27
+
28
+ # macOS
29
+ .DS_Store
30
+
31
+ # Test artifacts
32
+ .pytest_cache/
33
+ .coverage
34
+ htmlcov/
locci-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Locci Developers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
locci-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: locci
3
+ Version: 0.1.0
4
+ Summary: A fast, local-first CI engine.
5
+ Author: Locci Developers
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.9
8
+ Requires-Dist: networkx>=3.0
9
+ Requires-Dist: pydantic>=2.0.0
10
+ Requires-Dist: pyyaml>=6.0.1
11
+ Requires-Dist: rich>=13.0.0
12
+ Requires-Dist: tomli>=2.0.1; python_version < '3.11'
13
+ Requires-Dist: typer>=0.9.0
14
+ Requires-Dist: watchdog>=3.0.0
15
+ Provides-Extra: ai
16
+ Requires-Dist: anthropic>=0.20.0; extra == 'ai'
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest-asyncio; extra == 'dev'
19
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
20
+ Provides-Extra: s3
21
+ Requires-Dist: boto3>=1.28.0; extra == 's3'
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Locci (Local CI)
25
+
26
+ Locci is a fast, local-first CI preflight tool that runs the safe parts of your CI on your machine before you push. It uses an embedded DAG engine, content-hash caching, GitHub Actions-aware parsing, and clear skip reporting for unsafe or unsupported work.
27
+
28
+ Locci is intentionally host-native for the MVP: it does not claim to replace your hosted CI runner or Docker-isolate production deploys. Instead, it catches the common lint/test/build failures locally and tells you what still needs remote CI.
29
+
30
+ ## Security Caveats
31
+
32
+ **⚠️ Local Safety Heuristics are Best-Effort**
33
+ Locci uses a keyword-based heuristic (looking for words like "deploy", "publish", "release") to identify and skip unsafe side-effect jobs. **This is not a security boundary.** A job that modifies production state without using these specific keywords will still execute locally.
34
+
35
+ **⚠️ Remote Cache Supply Chain Risk**
36
+ When using the `--remote-cache s3://...` feature, Locci pulls and restores cache artifacts directly into your workspace. There is currently no cryptographic signature or authenticity verification on these artifacts. Anyone with write access to the shared cache bucket could plant a malicious payload or falsify a test outcome. Use shared remote caching with trusted teams only.
37
+
38
+ ## Why Python?
39
+
40
+ Locci is distributed via `pip` and written in Python 3.9+. While traditional tools often aim for a single static binary to avoid runtime dependencies, we deliberately chose Python to make installation ubiquitous across all OSes via PyPI, and to allow for rapid iteration and community-driven plugins.
41
+
42
+ **The Tradeoff**: You will need a Python 3.9+ runtime to use Locci, even if your project is written in Node.js, Go, or Rust.
43
+
44
+ **Recommendation**: We strongly recommend installing Locci globally via `pipx` to isolate its dependencies from your system Python:
45
+ ```bash
46
+ pipx install locci
47
+ ```
48
+ This gives you a globally available `locci` command that feels exactly like a static binary, without cluttering your environment.
49
+
50
+ ## Usage
51
+
52
+ ```bash
53
+ # First-time setup in a repo
54
+ locci setup
55
+
56
+ # Daily local CI check
57
+ locci check
58
+
59
+ # Affected pre-push check
60
+ locci preflight
61
+
62
+ # Watch for file changes and incrementally rerun only affected steps
63
+ locci watch
64
+ ```
65
+
66
+ Useful commands:
67
+
68
+ ```bash
69
+ locci setup --preview # print the generated locci.yml without writing
70
+ locci check --dry-run # show the local execution graph
71
+ locci check --strict-coverage
72
+ locci hook install # install a managed pre-push hook
73
+ locci doctor # inspect required local tools
74
+ ```
locci-0.1.0/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Locci (Local CI)
2
+
3
+ Locci is a fast, local-first CI preflight tool that runs the safe parts of your CI on your machine before you push. It uses an embedded DAG engine, content-hash caching, GitHub Actions-aware parsing, and clear skip reporting for unsafe or unsupported work.
4
+
5
+ Locci is intentionally host-native for the MVP: it does not claim to replace your hosted CI runner or Docker-isolate production deploys. Instead, it catches the common lint/test/build failures locally and tells you what still needs remote CI.
6
+
7
+ ## Security Caveats
8
+
9
+ **⚠️ Local Safety Heuristics are Best-Effort**
10
+ Locci uses a keyword-based heuristic (looking for words like "deploy", "publish", "release") to identify and skip unsafe side-effect jobs. **This is not a security boundary.** A job that modifies production state without using these specific keywords will still execute locally.
11
+
12
+ **⚠️ Remote Cache Supply Chain Risk**
13
+ When using the `--remote-cache s3://...` feature, Locci pulls and restores cache artifacts directly into your workspace. There is currently no cryptographic signature or authenticity verification on these artifacts. Anyone with write access to the shared cache bucket could plant a malicious payload or falsify a test outcome. Use shared remote caching with trusted teams only.
14
+
15
+ ## Why Python?
16
+
17
+ Locci is distributed via `pip` and written in Python 3.9+. While traditional tools often aim for a single static binary to avoid runtime dependencies, we deliberately chose Python to make installation ubiquitous across all OSes via PyPI, and to allow for rapid iteration and community-driven plugins.
18
+
19
+ **The Tradeoff**: You will need a Python 3.9+ runtime to use Locci, even if your project is written in Node.js, Go, or Rust.
20
+
21
+ **Recommendation**: We strongly recommend installing Locci globally via `pipx` to isolate its dependencies from your system Python:
22
+ ```bash
23
+ pipx install locci
24
+ ```
25
+ This gives you a globally available `locci` command that feels exactly like a static binary, without cluttering your environment.
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ # First-time setup in a repo
31
+ locci setup
32
+
33
+ # Daily local CI check
34
+ locci check
35
+
36
+ # Affected pre-push check
37
+ locci preflight
38
+
39
+ # Watch for file changes and incrementally rerun only affected steps
40
+ locci watch
41
+ ```
42
+
43
+ Useful commands:
44
+
45
+ ```bash
46
+ locci setup --preview # print the generated locci.yml without writing
47
+ locci check --dry-run # show the local execution graph
48
+ locci check --strict-coverage
49
+ locci hook install # install a managed pre-push hook
50
+ locci doctor # inspect required local tools
51
+ ```
@@ -0,0 +1,39 @@
1
+ [project]
2
+ name = "locci"
3
+ version = "0.1.0"
4
+ description = "A fast, local-first CI engine."
5
+ authors = [{name = "Locci Developers"}]
6
+ readme = "README.md"
7
+ requires-python = ">=3.9"
8
+ dependencies = [
9
+ "typer>=0.9.0",
10
+ "rich>=13.0.0",
11
+ "networkx>=3.0",
12
+ "pyyaml>=6.0.1",
13
+ "pydantic>=2.0.0",
14
+ "watchdog>=3.0.0",
15
+ "tomli>=2.0.1; python_version < '3.11'"
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ ai = [
20
+ "anthropic>=0.20.0"
21
+ ]
22
+ s3 = [
23
+ "boto3>=1.28.0"
24
+ ]
25
+ dev = [
26
+ "pytest>=7.0.0",
27
+ "pytest-asyncio"
28
+ ]
29
+
30
+ [project.scripts]
31
+ locci = "locci.cli:app"
32
+
33
+ [build-system]
34
+ requires = ["hatchling"]
35
+ build-backend = "hatchling.build"
36
+
37
+ [tool.pytest.ini_options]
38
+ pythonpath = ["src"]
39
+ testpaths = ["tests"]
@@ -0,0 +1,52 @@
1
+ import asyncio
2
+ from pathlib import Path
3
+ import random
4
+ import tempfile
5
+ import time
6
+
7
+ from locci.analyzer import Task
8
+ from locci.orchestrator import Orchestrator
9
+
10
+ async def main():
11
+ with tempfile.TemporaryDirectory() as tmp:
12
+ project_root = Path(tmp)
13
+ cache_db = project_root / "cache.db"
14
+
15
+ # Create 500 tasks
16
+ tasks = []
17
+ for i in range(500):
18
+ deps = []
19
+ if i > 0:
20
+ num_deps = random.randint(1, min(i, 3))
21
+ deps = [f"task_{random.randint(0, i-1)}" for _ in range(num_deps)]
22
+
23
+ task = Task(
24
+ name=f"task_{i}",
25
+ cmd=["bash", "-c", f"echo 'Running task {i} with a bunch of output to bloat cache' && sleep 0.1"],
26
+ depends_on=deps,
27
+ input_globs=[]
28
+ )
29
+ tasks.append(task)
30
+
31
+ print(f"Generated {len(tasks)} tasks.")
32
+
33
+ orch = Orchestrator(
34
+ project_root=project_root,
35
+ cache_db=cache_db,
36
+ no_cache=True,
37
+ jobs=100
38
+ )
39
+
40
+ start = time.time()
41
+ success = await orch.run(tasks)
42
+ end = time.time()
43
+
44
+ print(f"Success: {success}")
45
+ print(f"Time: {end - start:.2f}s")
46
+
47
+ if not success:
48
+ import sys
49
+ sys.exit(1)
50
+
51
+ if __name__ == "__main__":
52
+ asyncio.run(main())
File without changes