pactown 0.1.16__tar.gz → 0.1.47__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 (98) hide show
  1. {pactown-0.1.16 → pactown-0.1.47}/.bumpversion.cfg +1 -1
  2. pactown-0.1.47/CHANGELOG.md +92 -0
  3. {pactown-0.1.16 → pactown-0.1.47}/PKG-INFO +5 -1
  4. {pactown-0.1.16 → pactown-0.1.47}/docs/CONFIGURATION.md +5 -1
  5. {pactown-0.1.16 → pactown-0.1.47}/docs/DEPLOYMENT.md +5 -1
  6. {pactown-0.1.16 → pactown-0.1.47}/docs/NETWORK.md +5 -1
  7. {pactown-0.1.16 → pactown-0.1.47}/docs/SPECIFICATION.md +4 -0
  8. pactown-0.1.47/examples/fast-start-demo/README.md +82 -0
  9. pactown-0.1.47/examples/fast-start-demo/demo.py +120 -0
  10. pactown-0.1.47/examples/security-policy/README.md +92 -0
  11. pactown-0.1.47/examples/security-policy/demo.py +105 -0
  12. pactown-0.1.47/examples/user-isolation/README.md +94 -0
  13. pactown-0.1.47/examples/user-isolation/demo.py +110 -0
  14. {pactown-0.1.16 → pactown-0.1.47}/project.functions.toon +303 -85
  15. {pactown-0.1.16 → pactown-0.1.47}/project.toon +143 -17
  16. {pactown-0.1.16 → pactown-0.1.47}/pyproject.toml +9 -1
  17. pactown-0.1.47/src/pactown/__init__.py +197 -0
  18. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/cli.py +272 -0
  19. pactown-0.1.47/src/pactown/events.py +1066 -0
  20. pactown-0.1.47/src/pactown/llm.py +450 -0
  21. pactown-0.1.47/src/pactown/markpact_blocks.py +50 -0
  22. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/network.py +26 -4
  23. pactown-0.1.47/src/pactown/platform.py +146 -0
  24. pactown-0.1.47/src/pactown/runner_api.py +458 -0
  25. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/sandbox_manager.py +253 -11
  26. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/service_runner.py +105 -10
  27. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/user_isolation.py +125 -23
  28. pactown-0.1.47/tests/test_llm.py +311 -0
  29. pactown-0.1.47/tests/test_platform.py +56 -0
  30. pactown-0.1.47/tests/test_runner_api.py +108 -0
  31. pactown-0.1.47/tests/test_service_runner_fast_run_fallback.py +75 -0
  32. pactown-0.1.47/tests/test_user_isolation_manager.py +152 -0
  33. pactown-0.1.16/CHANGELOG.md +0 -36
  34. pactown-0.1.16/src/pactown/__init__.py +0 -91
  35. pactown-0.1.16/src/pactown/markpact_blocks.py +0 -32
  36. {pactown-0.1.16 → pactown-0.1.47}/.gitignore +0 -0
  37. {pactown-0.1.16 → pactown-0.1.47}/LICENSE +0 -0
  38. {pactown-0.1.16 → pactown-0.1.47}/Makefile +0 -0
  39. {pactown-0.1.16 → pactown-0.1.47}/README.md +0 -0
  40. {pactown-0.1.16 → pactown-0.1.47}/TODO.md +0 -0
  41. {pactown-0.1.16 → pactown-0.1.47}/docs/CLOUDFLARE_WORKERS_COMPARISON.md +0 -0
  42. {pactown-0.1.16 → pactown-0.1.47}/docs/FAST_START.md +0 -0
  43. {pactown-0.1.16 → pactown-0.1.47}/docs/GENERATOR.md +0 -0
  44. {pactown-0.1.16 → pactown-0.1.47}/docs/LOGGING.md +0 -0
  45. {pactown-0.1.16 → pactown-0.1.47}/docs/QUADLET.md +0 -0
  46. {pactown-0.1.16 → pactown-0.1.47}/docs/SECURITY.md +0 -0
  47. {pactown-0.1.16 → pactown-0.1.47}/docs/SECURITY_POLICY.md +0 -0
  48. {pactown-0.1.16 → pactown-0.1.47}/docs/USER_ISOLATION.md +0 -0
  49. {pactown-0.1.16 → pactown-0.1.47}/examples/api-gateway-webhooks/README.md +0 -0
  50. {pactown-0.1.16 → pactown-0.1.47}/examples/email-llm-responder/README.md +0 -0
  51. {pactown-0.1.16 → pactown-0.1.47}/examples/microservices/README.md +0 -0
  52. {pactown-0.1.16 → pactown-0.1.47}/examples/microservices/saas.pactown.yaml +0 -0
  53. {pactown-0.1.16 → pactown-0.1.47}/examples/microservices/services/go-gateway/README.md +0 -0
  54. {pactown-0.1.16 → pactown-0.1.47}/examples/microservices/services/node-api/README.md +0 -0
  55. {pactown-0.1.16 → pactown-0.1.47}/examples/microservices/services/python-ml/README.md +0 -0
  56. {pactown-0.1.16 → pactown-0.1.47}/examples/quadlet-vps/README.md +0 -0
  57. {pactown-0.1.16 → pactown-0.1.47}/examples/realtime-notifications/README.md +0 -0
  58. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/README.md +0 -0
  59. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/saas.pactown.yaml +0 -0
  60. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/services/api/README.md +0 -0
  61. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/services/cli/README.md +0 -0
  62. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/services/database/README.md +0 -0
  63. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/services/gateway/README.md +0 -0
  64. {pactown-0.1.16 → pactown-0.1.47}/examples/saas-platform/services/web/README.md +0 -0
  65. {pactown-0.1.16 → pactown-0.1.47}/examples.md +0 -0
  66. {pactown-0.1.16 → pactown-0.1.47}/img.png +0 -0
  67. {pactown-0.1.16 → pactown-0.1.47}/project.sh +0 -0
  68. {pactown-0.1.16 → pactown-0.1.47}/project.toon-schema.json +0 -0
  69. {pactown-0.1.16 → pactown-0.1.47}/saas.pactown.yaml +0 -0
  70. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/config.py +0 -0
  71. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/__init__.py +0 -0
  72. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/base.py +0 -0
  73. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/compose.py +0 -0
  74. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/docker.py +0 -0
  75. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/kubernetes.py +0 -0
  76. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/podman.py +0 -0
  77. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/quadlet.py +0 -0
  78. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/quadlet_api.py +0 -0
  79. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/deploy/quadlet_shell.py +0 -0
  80. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/fast_start.py +0 -0
  81. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/generator.py +0 -0
  82. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/orchestrator.py +0 -0
  83. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/parallel.py +0 -0
  84. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/registry/__init__.py +0 -0
  85. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/registry/client.py +0 -0
  86. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/registry/models.py +0 -0
  87. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/registry/server.py +0 -0
  88. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/resolver.py +0 -0
  89. {pactown-0.1.16 → pactown-0.1.47}/src/pactown/security.py +0 -0
  90. {pactown-0.1.16 → pactown-0.1.47}/tests/__init__.py +0 -0
  91. {pactown-0.1.16 → pactown-0.1.47}/tests/test_config.py +0 -0
  92. {pactown-0.1.16 → pactown-0.1.47}/tests/test_deploy_dockerfile.py +0 -0
  93. {pactown-0.1.16 → pactown-0.1.47}/tests/test_markpact_blocks.py +0 -0
  94. {pactown-0.1.16 → pactown-0.1.47}/tests/test_network.py +0 -0
  95. {pactown-0.1.16 → pactown-0.1.47}/tests/test_parallel.py +0 -0
  96. {pactown-0.1.16 → pactown-0.1.47}/tests/test_quadlet_security.py +0 -0
  97. {pactown-0.1.16 → pactown-0.1.47}/tests/test_registry.py +0 -0
  98. {pactown-0.1.16 → pactown-0.1.47}/tests/test_resolver.py +0 -0
@@ -1,5 +1,5 @@
1
1
  [bumpversion]
2
- current_version = 0.1.16
2
+ current_version = 0.1.47
3
3
  commit = False
4
4
  tag = False
5
5
 
@@ -0,0 +1,92 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.4.0] - 2026-01-16
9
+
10
+ ### Added
11
+
12
+ - **Fast Start Module** (`fast_start.py`)
13
+ - Dependency caching with hash-based venv reuse
14
+ - ~50-100ms startup for cached deps vs ~5-10s fresh
15
+ - `ServiceRunner.fast_run()` method
16
+ - Parallel file writing for sandbox creation
17
+
18
+ - **Security Policy Module** (`security.py`)
19
+ - Rate limiting with token bucket algorithm
20
+ - User profiles with tier-based limits (FREE/BASIC/PRO/ENTERPRISE)
21
+ - Concurrent service limits per user
22
+ - Anomaly logging for admin monitoring
23
+ - Server load throttling
24
+
25
+ - **User Isolation Module** (`user_isolation.py`)
26
+ - Linux user-based sandbox isolation
27
+ - Per-SaaS-user home directories
28
+ - Process isolation with different UIDs
29
+ - Export/import for user data migration
30
+ - REST API endpoints for user management
31
+
32
+ - **Detailed Logging**
33
+ - Structured logging in sandbox_manager
34
+ - STDERR/STDOUT capture on process failure
35
+ - Signal interpretation (SIGTERM, SIGKILL, etc.)
36
+ - Per-service error log files
37
+
38
+ - **New Documentation**
39
+ - `docs/FAST_START.md` - Dependency caching guide
40
+ - `docs/SECURITY_POLICY.md` - Rate limiting and user profiles
41
+ - `docs/USER_ISOLATION.md` - Multi-tenant isolation
42
+ - `docs/LOGGING.md` - Structured logging guide
43
+ - Navigation links across all docs
44
+
45
+ - **New Examples**
46
+ - `examples/fast-start-demo/` - Fast startup with caching
47
+ - `examples/security-policy/` - Rate limiting demo
48
+ - `examples/user-isolation/` - Multi-tenant isolation demo
49
+
50
+ ### Changed
51
+
52
+ - README.md restructured with feature menu and quick navigation
53
+ - All docs updated with cross-links for easier navigation
54
+ - sandbox_manager.py: Better error capture and signal handling
55
+ - service_runner.py: Added delays to prevent race conditions on restart
56
+
57
+ ### Fixed
58
+
59
+ - Process killed by SIGTERM on restart (race condition)
60
+ - Truncated error output from crashed processes
61
+ - **Hardcoded port mismatch** - Auto-replace hardcoded ports (e.g., `--port 8009`) with requested port
62
+ - PORT and MARKPACT_PORT environment variables now always set
63
+
64
+ ## [Unreleased]
65
+
66
+ ### Added
67
+
68
+ - Podman Quadlet deployment backend (`pactown.deploy.quadlet`) with templates, backend operations, and Traefik integration.
69
+ - Interactive Quadlet shell (`pactown quadlet shell`).
70
+ - Quadlet REST API (`pactown quadlet api`) and entrypoint `pactown-quadlet-api`.
71
+ - Security hardening and injection test suite (`tests/test_quadlet_security.py`).
72
+ - Quadlet security guide (`docs/SECURITY.md`).
73
+ - Cloudflare Workers comparison (`docs/CLOUDFLARE_WORKERS_COMPARISON.md`).
74
+ - Practical Quadlet examples in `examples/*` where the user edits only `README.md` (embedded code blocks) and deployment artifacts are generated into `./sandbox`.
75
+
76
+ ### Changed
77
+
78
+ - Dockerfile Python healthcheck now uses `MARKPACT_PORT` with fallback to `PORT` to maintain compatibility.
79
+ - Registry timestamps use timezone-aware datetimes (`datetime.now(timezone.utc)`) to avoid Python 3.13 deprecations.
80
+ - Makefile:
81
+ - Prefers project venv python if present.
82
+ - `lint`/`format` fall back to `pipx run ruff` when ruff is not installed in the interpreter.
83
+ - `test` explicitly loads `pytest_asyncio.plugin` to work with `PYTEST_DISABLE_PLUGIN_AUTOLOAD=1`.
84
+
85
+ ### Fixed
86
+
87
+ - Multiple Quadlet injection vectors (container name, env var, volume, Traefik label, systemd unit) mitigated via input sanitization.
88
+ - Ruff lint issues across `src/` and `tests/`.
89
+
90
+ ## [0.1.5]
91
+
92
+ - Initial public version.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactown
3
- Version: 0.1.16
3
+ Version: 0.1.47
4
4
  Summary: Decentralized Service Ecosystem Orchestrator - Build interconnected microservices from Markdown using markpact
5
5
  Project-URL: Homepage, https://github.com/wronai/pactown
6
6
  Project-URL: Repository, https://github.com/wronai/pactown
@@ -30,6 +30,8 @@ Requires-Dist: pyyaml>=6.0
30
30
  Requires-Dist: rich>=13.0
31
31
  Requires-Dist: uvicorn>=0.20.0
32
32
  Requires-Dist: watchfiles>=0.20.0
33
+ Provides-Extra: all
34
+ Requires-Dist: lolm>=0.1.6; extra == 'all'
33
35
  Provides-Extra: dev
34
36
  Requires-Dist: build; extra == 'dev'
35
37
  Requires-Dist: bump2version>=1.0; extra == 'dev'
@@ -38,6 +40,8 @@ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
38
40
  Requires-Dist: pytest>=7.0; extra == 'dev'
39
41
  Requires-Dist: ruff>=0.1; extra == 'dev'
40
42
  Requires-Dist: twine; extra == 'dev'
43
+ Provides-Extra: llm
44
+ Requires-Dist: lolm>=0.1.6; extra == 'llm'
41
45
  Description-Content-Type: text/markdown
42
46
 
43
47
  ![img.png](img.png)
@@ -1,6 +1,10 @@
1
1
  # Configuration Reference
2
2
 
3
- > **See also:** [README](../README.md) | [Specification](SPECIFICATION.md) | [Network](NETWORK.md) | [Generator](GENERATOR.md)
3
+ [← Back to README](../README.md) | [Specification](SPECIFICATION.md) | [Network](NETWORK.md) | [Deployment →](DEPLOYMENT.md)
4
+
5
+ ---
6
+
7
+ > **Related:** [Generator](GENERATOR.md) | [Fast Start](FAST_START.md) | [Security Policy](SECURITY_POLICY.md)
4
8
 
5
9
  Complete reference for `saas.pactown.yaml` configuration files.
6
10
 
@@ -1,6 +1,10 @@
1
1
  # Production Deployment Guide
2
2
 
3
- > **See also:** [README](../README.md) | [Specification](SPECIFICATION.md) | [Configuration](CONFIGURATION.md) | [Network](NETWORK.md) | [Quadlet](QUADLET.md) | [Security](SECURITY.md)
3
+ [← Back to README](../README.md) | [Configuration](CONFIGURATION.md) | [Quadlet ](QUADLET.md)
4
+
5
+ ---
6
+
7
+ > **Related:** [Network](NETWORK.md) | [Security](SECURITY.md) | [User Isolation](USER_ISOLATION.md)
4
8
 
5
9
  This guide covers deploying pactown ecosystems to production using Docker, Podman, and Kubernetes.
6
10
 
@@ -1,6 +1,10 @@
1
1
  # Network & Service Discovery
2
2
 
3
- > **See also:** [README](../README.md) | [Specification](SPECIFICATION.md) | [Configuration](CONFIGURATION.md) | [Generator](GENERATOR.md)
3
+ [← Back to README](../README.md) | [Configuration](CONFIGURATION.md) | [Deployment →](DEPLOYMENT.md)
4
+
5
+ ---
6
+
7
+ > **Related:** [Specification](SPECIFICATION.md) | [Generator](GENERATOR.md)
4
8
 
5
9
  This document describes pactown's dynamic port allocation and service discovery system.
6
10
 
@@ -1,5 +1,9 @@
1
1
  # Pactown System Specification
2
2
 
3
+ [← Back to README](../README.md) | [Configuration →](CONFIGURATION.md)
4
+
5
+ ---
6
+
3
7
  ## Problem Statement
4
8
 
5
9
  Modern software systems are increasingly composed of multiple independent services that need to work together. However, setting up and managing these systems presents several challenges:
@@ -0,0 +1,82 @@
1
+ # Fast Start Demo
2
+
3
+ This example demonstrates pactown's fast startup capabilities with dependency caching.
4
+
5
+ ## What This Shows
6
+
7
+ - **First run**: Dependencies are installed and cached (~5-10s)
8
+ - **Second run**: Cached venv is reused (~50-100ms)
9
+ - **Same deps = same cache**: Projects with identical dependencies share the cache
10
+
11
+ ## Files
12
+
13
+ - `demo.py` - Python script demonstrating fast_run vs regular run
14
+ - `api/README.md` - Sample FastAPI service
15
+ - `api2/README.md` - Second service with same deps (will use cache)
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Run the demo
21
+ python demo.py
22
+
23
+ # Or use pactown CLI
24
+ pactown up fast-start.pactown.yaml
25
+ ```
26
+
27
+ ## Expected Output
28
+
29
+ ```
30
+ === Fast Start Demo ===
31
+
32
+ Run 1 (fresh):
33
+ Creating sandbox...
34
+ Installing dependencies (fastapi, uvicorn)...
35
+ ✓ Started in 5.2s
36
+
37
+ Run 2 (cached):
38
+ ⚡ Cache hit! Reusing venv
39
+ ✓ Started in 0.08s
40
+
41
+ Speedup: 65x faster!
42
+ ```
43
+
44
+ ## How It Works
45
+
46
+ ```python
47
+ from pactown import ServiceRunner
48
+
49
+ runner = ServiceRunner(enable_fast_start=True)
50
+
51
+ # First run - creates and caches venv
52
+ result1 = await runner.fast_run(
53
+ service_id="api-1",
54
+ content=open("api/README.md").read(),
55
+ port=8001,
56
+ )
57
+
58
+ # Second run - reuses cached venv
59
+ result2 = await runner.fast_run(
60
+ service_id="api-2",
61
+ content=open("api2/README.md").read(), # Same deps!
62
+ port=8002,
63
+ )
64
+ ```
65
+
66
+ ## Cache Location
67
+
68
+ ```
69
+ /tmp/pactown-sandboxes/
70
+ ├── .cache/
71
+ │ └── venvs/
72
+ │ └── venv_a1b2c3d4/ # Cached: fastapi + uvicorn
73
+ ├── api-1/
74
+ │ └── .venv -> ../.cache/venvs/venv_a1b2c3d4
75
+ └── api-2/
76
+ └── .venv -> ../.cache/venvs/venv_a1b2c3d4 # Same cache!
77
+ ```
78
+
79
+ ## Related Documentation
80
+
81
+ - [Fast Start Guide](../../docs/FAST_START.md)
82
+ - [Security Policy](../../docs/SECURITY_POLICY.md)
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Fast Start Demo - Demonstrates dependency caching for fast startup.
4
+
5
+ Usage:
6
+ python demo.py
7
+ """
8
+ import asyncio
9
+ import time
10
+ from pathlib import Path
11
+
12
+ # Add pactown to path if running from source
13
+ import sys
14
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
15
+
16
+ from pactown import ServiceRunner
17
+
18
+
19
+ API_README = '''# Demo API
20
+
21
+ Simple FastAPI service for demonstrating fast start.
22
+
23
+ ```python markpact:deps
24
+ fastapi
25
+ uvicorn
26
+ ```
27
+
28
+ ```python markpact:file path=main.py
29
+ from fastapi import FastAPI
30
+
31
+ app = FastAPI(title="Fast Start Demo")
32
+
33
+ @app.get("/")
34
+ def root():
35
+ return {"message": "Hello from Fast Start Demo!"}
36
+
37
+ @app.get("/health")
38
+ def health():
39
+ return {"status": "ok"}
40
+ ```
41
+
42
+ ```bash markpact:run
43
+ uvicorn main:app --host 0.0.0.0 --port $PORT
44
+ ```
45
+ '''
46
+
47
+
48
+ async def main():
49
+ print("=" * 50)
50
+ print("⚡ Fast Start Demo")
51
+ print("=" * 50)
52
+ print()
53
+
54
+ runner = ServiceRunner(
55
+ sandbox_root="/tmp/fast-start-demo",
56
+ enable_fast_start=True,
57
+ )
58
+
59
+ # Run 1 - First run (cold start)
60
+ print("Run 1 (fresh install):")
61
+ print(" Creating sandbox and installing dependencies...")
62
+
63
+ start = time.time()
64
+ result1 = await runner.fast_run(
65
+ service_id="demo-api-1",
66
+ content=API_README,
67
+ port=10091,
68
+ )
69
+ time1 = time.time() - start
70
+
71
+ if result1.success:
72
+ print(f" ✓ Started in {time1:.2f}s")
73
+ else:
74
+ print(f" ❌ Failed: {result1.message}")
75
+ return
76
+
77
+ # Stop first service
78
+ runner.stop("demo-api-1")
79
+
80
+ print()
81
+
82
+ # Run 2 - Second run (cache hit)
83
+ print("Run 2 (cached):")
84
+ print(" ⚡ Checking cache...")
85
+
86
+ start = time.time()
87
+ result2 = await runner.fast_run(
88
+ service_id="demo-api-2",
89
+ content=API_README, # Same deps!
90
+ port=10092,
91
+ )
92
+ time2 = time.time() - start
93
+
94
+ if result2.success:
95
+ print(f" ✓ Started in {time2:.2f}s")
96
+ else:
97
+ print(f" ❌ Failed: {result2.message}")
98
+
99
+ # Stop second service
100
+ runner.stop("demo-api-2")
101
+
102
+ print()
103
+ print("=" * 50)
104
+ print(f"Results:")
105
+ print(f" First run: {time1:.2f}s")
106
+ print(f" Second run: {time2:.2f}s")
107
+ if time2 > 0:
108
+ print(f" Speedup: {time1/time2:.1f}x faster!")
109
+ print("=" * 50)
110
+
111
+ # Show cache stats
112
+ stats = runner.get_cache_stats()
113
+ print()
114
+ print("Cache Statistics:")
115
+ print(f" Entries: {stats.get('cache_entries', 0)}")
116
+ print(f" Caching enabled: {stats.get('caching_enabled', False)}")
117
+
118
+
119
+ if __name__ == "__main__":
120
+ asyncio.run(main())
@@ -0,0 +1,92 @@
1
+ # Security Policy Demo
2
+
3
+ This example demonstrates pactown's security policy features for multi-tenant SaaS.
4
+
5
+ ## What This Shows
6
+
7
+ - **Rate limiting** - Token bucket algorithm to prevent abuse
8
+ - **User profiles** - Tier-based resource limits (FREE/BASIC/PRO)
9
+ - **Concurrent limits** - Max services per user
10
+ - **Anomaly logging** - Track and alert on security events
11
+
12
+ ## Files
13
+
14
+ - `demo.py` - Python script demonstrating security features
15
+ - `multi_tenant.py` - Multi-tenant SaaS simulation
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Run the demo
21
+ python demo.py
22
+
23
+ # Or run the multi-tenant simulation
24
+ python multi_tenant.py
25
+ ```
26
+
27
+ ## Expected Output
28
+
29
+ ```
30
+ === Security Policy Demo ===
31
+
32
+ Creating user profiles...
33
+ ✓ free_user (FREE tier): max 2 concurrent services
34
+ ✓ pro_user (PRO tier): max 10 concurrent services
35
+
36
+ Testing rate limiting...
37
+ Request 1: ✓ allowed
38
+ Request 2: ✓ allowed
39
+ ...
40
+ Request 21: ✗ rate limited (wait 2.5s)
41
+
42
+ Testing concurrent limits...
43
+ free_user starting service 1: ✓ allowed
44
+ free_user starting service 2: ✓ allowed
45
+ free_user starting service 3: ✗ limit reached (2/2)
46
+
47
+ Anomaly log:
48
+ [RATE_LIMIT_EXCEEDED] free_user - Rate limit exceeded
49
+ [CONCURRENT_LIMIT_EXCEEDED] free_user - Max 2 services
50
+ ```
51
+
52
+ ## User Tiers
53
+
54
+ | Tier | Concurrent | Memory | Requests/min |
55
+ |------|------------|--------|--------------|
56
+ | FREE | 2 | 256MB | 20 |
57
+ | BASIC | 5 | 512MB | 60 |
58
+ | PRO | 10 | 2GB | 120 |
59
+ | ENTERPRISE | 50 | 8GB | 500 |
60
+
61
+ ## Code Example
62
+
63
+ ```python
64
+ from pactown import SecurityPolicy, UserProfile, UserTier
65
+
66
+ # Create security policy
67
+ policy = SecurityPolicy(
68
+ anomaly_log_path=Path("./anomalies.jsonl"),
69
+ default_rate_limit=60,
70
+ )
71
+
72
+ # Create user profile
73
+ profile = UserProfile.from_tier("user123", UserTier.PRO)
74
+ policy.set_user_profile(profile)
75
+
76
+ # Check if user can start service
77
+ result = await policy.check_can_start_service(
78
+ user_id="user123",
79
+ service_id="my-api",
80
+ port=8001,
81
+ )
82
+
83
+ if result.allowed:
84
+ print("✓ Starting service...")
85
+ else:
86
+ print(f"✗ Denied: {result.reason}")
87
+ ```
88
+
89
+ ## Related Documentation
90
+
91
+ - [Security Policy Guide](../../docs/SECURITY_POLICY.md)
92
+ - [User Isolation](../../docs/USER_ISOLATION.md)
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Security Policy Demo - Demonstrates rate limiting and user profiles.
4
+
5
+ Usage:
6
+ python demo.py
7
+ """
8
+ import asyncio
9
+ from pathlib import Path
10
+
11
+ # Add pactown to path if running from source
12
+ import sys
13
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
14
+
15
+ from pactown import SecurityPolicy, UserProfile, UserTier, AnomalyType
16
+
17
+
18
+ async def main():
19
+ print("=" * 50)
20
+ print("🛡️ Security Policy Demo")
21
+ print("=" * 50)
22
+ print()
23
+
24
+ # Create security policy
25
+ policy = SecurityPolicy(
26
+ anomaly_log_path=Path("./demo_anomalies.jsonl"),
27
+ default_rate_limit=20, # 20 requests per minute for demo
28
+ cpu_threshold=80.0,
29
+ memory_threshold=85.0,
30
+ )
31
+
32
+ # Create user profiles
33
+ print("Creating user profiles...")
34
+
35
+ free_user = UserProfile.from_tier("free_user", UserTier.FREE)
36
+ pro_user = UserProfile.from_tier("pro_user", UserTier.PRO)
37
+
38
+ policy.set_user_profile(free_user)
39
+ policy.set_user_profile(pro_user)
40
+
41
+ print(f" ✓ free_user (FREE): max {free_user.max_concurrent_services} services, {free_user.max_requests_per_minute} req/min")
42
+ print(f" ✓ pro_user (PRO): max {pro_user.max_concurrent_services} services, {pro_user.max_requests_per_minute} req/min")
43
+ print()
44
+
45
+ # Test rate limiting
46
+ print("Testing rate limiting (free_user)...")
47
+
48
+ for i in range(25):
49
+ result = await policy.check_can_start_service(
50
+ user_id="free_user",
51
+ service_id=f"test-service-{i}",
52
+ port=10000 + i,
53
+ )
54
+
55
+ if result.allowed:
56
+ print(f" Request {i+1}: ✓ allowed")
57
+ else:
58
+ print(f" Request {i+1}: ✗ {result.reason}")
59
+ if result.wait_seconds:
60
+ print(f" Wait {result.wait_seconds:.1f}s before retry")
61
+ break
62
+
63
+ print()
64
+
65
+ # Test concurrent limits
66
+ print("Testing concurrent service limits (free_user)...")
67
+
68
+ # Simulate starting services
69
+ for i in range(4):
70
+ service_id = f"concurrent-test-{i}"
71
+
72
+ # Check if allowed
73
+ result = await policy.check_can_start_service(
74
+ user_id="free_user",
75
+ service_id=service_id,
76
+ port=11000 + i,
77
+ )
78
+
79
+ if result.allowed:
80
+ # Register the service as running
81
+ policy.register_service("free_user", service_id)
82
+ count = policy.get_user_service_count("free_user")
83
+ print(f" Service {i+1}: ✓ started (running: {count}/{free_user.max_concurrent_services})")
84
+ else:
85
+ print(f" Service {i+1}: ✗ {result.reason}")
86
+
87
+ print()
88
+
89
+ # Show anomaly summary
90
+ print("Anomaly summary:")
91
+ summary = policy.get_anomaly_summary(hours=1)
92
+ print(f" Total events: {summary.get('total_count', 0)}")
93
+
94
+ by_type = summary.get('by_type', {})
95
+ for anomaly_type, count in by_type.items():
96
+ print(f" - {anomaly_type}: {count}")
97
+
98
+ print()
99
+ print("=" * 50)
100
+ print("Demo complete! Check demo_anomalies.jsonl for logged events.")
101
+ print("=" * 50)
102
+
103
+
104
+ if __name__ == "__main__":
105
+ asyncio.run(main())
@@ -0,0 +1,94 @@
1
+ # User Isolation Demo
2
+
3
+ This example demonstrates pactown's Linux user-based sandbox isolation for multi-tenant SaaS.
4
+
5
+ ## What This Shows
6
+
7
+ - **Linux user creation** - Each SaaS user gets a dedicated Linux user
8
+ - **Process isolation** - Different UIDs prevent cross-tenant access
9
+ - **File isolation** - Separate home directories per user
10
+ - **Migration support** - Export/import user data
11
+
12
+ ## Files
13
+
14
+ - `demo.py` - Python script demonstrating user isolation
15
+ - `migration.py` - Demonstrates user data migration
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ # Run the demo (works in non-root mode too)
21
+ python demo.py
22
+
23
+ # Run migration demo
24
+ python migration.py
25
+ ```
26
+
27
+ ## Expected Output
28
+
29
+ ```
30
+ === User Isolation Demo ===
31
+
32
+ Creating isolated users...
33
+ ✓ user_alice -> pactown_a1b2c3d4 (UID: 60001)
34
+ ✓ user_bob -> pactown_e5f6g7h8 (UID: 60002)
35
+
36
+ Creating sandboxes...
37
+ ✓ user_alice/my-api: /home/pactown_users/pactown_a1b2c3d4/sandboxes/my-api
38
+ ✓ user_bob/my-api: /home/pactown_users/pactown_e5f6g7h8/sandboxes/my-api
39
+
40
+ User statistics:
41
+ user_alice: 1 sandbox, 0.5 MB
42
+ user_bob: 1 sandbox, 0.5 MB
43
+
44
+ Total isolated users: 2
45
+ ```
46
+
47
+ ## Architecture
48
+
49
+ ```
50
+ /home/pactown_users/
51
+ ├── pactown_a1b2c3d4/ # user_alice (UID 60001)
52
+ │ ├── sandboxes/
53
+ │ │ └── my-api/
54
+ │ │ ├── main.py
55
+ │ │ └── .venv/
56
+ │ └── .cache/
57
+ └── pactown_e5f6g7h8/ # user_bob (UID 60002)
58
+ ├── sandboxes/
59
+ │ └── my-api/
60
+ └── .cache/
61
+ ```
62
+
63
+ ## Code Example
64
+
65
+ ```python
66
+ from pactown import UserIsolationManager, get_isolation_manager
67
+
68
+ # Get global manager
69
+ manager = get_isolation_manager()
70
+
71
+ # Create isolated user
72
+ user = manager.get_or_create_user("alice@example.com")
73
+ print(f"Linux user: {user.linux_username}")
74
+ print(f"UID: {user.linux_uid}")
75
+ print(f"Home: {user.home_dir}")
76
+
77
+ # Get sandbox path
78
+ sandbox = manager.get_sandbox_path("alice@example.com", "my-api")
79
+
80
+ # Run command as isolated user
81
+ process = manager.run_as_user(
82
+ saas_user_id="alice@example.com",
83
+ command="python main.py",
84
+ cwd=sandbox,
85
+ )
86
+
87
+ # Export for migration
88
+ manager.export_user_data("alice@example.com", Path("/backup/alice.tar.gz"))
89
+ ```
90
+
91
+ ## Related Documentation
92
+
93
+ - [User Isolation Guide](../../docs/USER_ISOLATION.md)
94
+ - [Security Policy](../../docs/SECURITY_POLICY.md)