kekkai-cli 1.0.5__py3-none-any.whl → 1.1.1__py3-none-any.whl
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.
- kekkai/cli.py +789 -19
- kekkai/compliance/__init__.py +68 -0
- kekkai/compliance/hipaa.py +235 -0
- kekkai/compliance/mappings.py +136 -0
- kekkai/compliance/owasp.py +517 -0
- kekkai/compliance/owasp_agentic.py +267 -0
- kekkai/compliance/pci_dss.py +205 -0
- kekkai/compliance/soc2.py +209 -0
- kekkai/dojo.py +91 -14
- kekkai/dojo_import.py +9 -1
- kekkai/fix/__init__.py +47 -0
- kekkai/fix/audit.py +278 -0
- kekkai/fix/differ.py +427 -0
- kekkai/fix/engine.py +500 -0
- kekkai/fix/prompts.py +251 -0
- kekkai/output.py +10 -12
- kekkai/report/__init__.py +41 -0
- kekkai/report/compliance_matrix.py +98 -0
- kekkai/report/generator.py +365 -0
- kekkai/report/html.py +69 -0
- kekkai/report/pdf.py +63 -0
- kekkai/report/unified.py +226 -0
- kekkai/scanners/container.py +33 -3
- kekkai/scanners/gitleaks.py +3 -1
- kekkai/scanners/semgrep.py +1 -1
- kekkai/scanners/trivy.py +1 -1
- kekkai/threatflow/model_adapter.py +143 -1
- kekkai/triage/__init__.py +54 -1
- kekkai/triage/loader.py +196 -0
- kekkai_cli-1.1.1.dist-info/METADATA +379 -0
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/RECORD +34 -33
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/entry_points.txt +0 -1
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/top_level.txt +0 -1
- kekkai_cli-1.0.5.dist-info/METADATA +0 -135
- portal/__init__.py +0 -19
- portal/api.py +0 -155
- portal/auth.py +0 -103
- portal/enterprise/__init__.py +0 -32
- portal/enterprise/audit.py +0 -435
- portal/enterprise/licensing.py +0 -342
- portal/enterprise/rbac.py +0 -276
- portal/enterprise/saml.py +0 -595
- portal/ops/__init__.py +0 -53
- portal/ops/backup.py +0 -553
- portal/ops/log_shipper.py +0 -469
- portal/ops/monitoring.py +0 -517
- portal/ops/restore.py +0 -469
- portal/ops/secrets.py +0 -408
- portal/ops/upgrade.py +0 -591
- portal/tenants.py +0 -340
- portal/uploads.py +0 -259
- portal/web.py +0 -384
- {kekkai_cli-1.0.5.dist-info → kekkai_cli-1.1.1.dist-info}/WHEEL +0 -0
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: kekkai-cli
|
|
3
|
-
Version: 1.0.5
|
|
4
|
-
Summary: Kekkai monorepo (local-first AppSec orchestration + compliance checker)
|
|
5
|
-
Requires-Python: >=3.12
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: rich>=13.0.0
|
|
8
|
-
Requires-Dist: jsonschema>=4.20.0
|
|
9
|
-
Requires-Dist: textual>=0.50.0
|
|
10
|
-
Requires-Dist: httpx>=0.24.0
|
|
11
|
-
|
|
12
|
-
<p align="center">
|
|
13
|
-
<img src="https://raw.githubusercontent.com/kademoslabs/assets/main/logos/kekkai-slim.png" alt="Kekkai CLI Logo" width="250"/>
|
|
14
|
-
</p>
|
|
15
|
-
<p align="center"><i>One command. Clean AppSec reports.</i></p>
|
|
16
|
-
<p align="center">
|
|
17
|
-
<img src="https://img.shields.io/badge/license-MIT-blue.svg"/>
|
|
18
|
-
<img src="https://img.shields.io/badge/status-active-brightgreen"/>
|
|
19
|
-
</p>
|
|
20
|
-
|
|
21
|
-
# Kekkai 🛡️
|
|
22
|
-
|
|
23
|
-
**Security that moves at developer speed.**
|
|
24
|
-
*Local-first orchestration for Trivy, Semgrep, and DefectDojo.*
|
|
25
|
-
|
|
26
|
-

|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## ⚡ Quick Start
|
|
31
|
-
|
|
32
|
-
Stop fighting with Docker Compose. Start scanning in 30 seconds.
|
|
33
|
-
|
|
34
|
-
### Installation
|
|
35
|
-
|
|
36
|
-
**Option 1: pipx (Recommended - Isolated Environment)**
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
pipx install kekkai-cli
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**Option 2: Homebrew (macOS/Linux)**
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
brew tap kademoslabs/tap
|
|
46
|
-
brew install kekkai
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Option 3: Docker (No Python Required)**
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# Build image
|
|
53
|
-
docker build -t kademoslabs/kekkai:latest -f apps/kekkai/Dockerfile .
|
|
54
|
-
|
|
55
|
-
# Run via wrapper script
|
|
56
|
-
./scripts/kekkai-docker --help
|
|
57
|
-
|
|
58
|
-
# Or set up alias
|
|
59
|
-
alias kekkai="$(pwd)/scripts/kekkai-docker"
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Option 4: Scoop (Windows)**
|
|
63
|
-
|
|
64
|
-
```powershell
|
|
65
|
-
scoop bucket add kademoslabs https://github.com/kademoslabs/scoop-bucket
|
|
66
|
-
scoop install kekkai
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
**Option 5: pip (Traditional)**
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
pip install kekkai-cli
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
### 1. Scan your project (Local)
|
|
78
|
-
|
|
79
|
-
Run industry-standard scanners (Trivy, Semgrep, Gitleaks) in unified Docker containers without installing them individually.
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
cd your-repo
|
|
83
|
-
kekkai scan
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 2. Spin up DefectDojo
|
|
88
|
-
|
|
89
|
-
Launch a full local vulnerability management platform (Nginx, Postgres, Redis, Celery) with one command.
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
kekkai dojo up --wait --open
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### 3. Generate a Threat Model (AI)
|
|
97
|
-
|
|
98
|
-
Generate a STRIDE threat model and Data Flow Diagram using your local LLM.
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
kekkai threatflow --repo . --model-mode local
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## 🛑 The Problem vs. Kekkai
|
|
108
|
-
|
|
109
|
-
| Feature | The Old Way | The Kekkai Way |
|
|
110
|
-
| --- | --- | --- |
|
|
111
|
-
| **Tooling** | Manually install/update 5+ tools (Trivy, Semgrep, etc.) | **One Binary.** `kekkai scan` auto-pulls and runs the latest scanner containers. |
|
|
112
|
-
| **Reporting** | Parse 5 different JSON formats manually. | **Unified Output.** One deduplicated `kekkai-report.json` for all findings. |
|
|
113
|
-
| **DefectDojo** | Write a 200-line `docker-compose.yml` and debug networking. | **One Command.** `kekkai dojo up` automates the entire stack setup. |
|
|
114
|
-
| **Threat Modeling** | Expensive consultants or manual whiteboarding. | **AI Agent.** `kekkai threatflow` generates `THREATS.md` locally. |
|
|
115
|
-
| **CI/CD** | Write complex bash scripts to break builds. | **Policy Engine.** `kekkai scan --ci --fail-on high`. |
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## 🔒 Enterprise Features (Portal)
|
|
120
|
-
|
|
121
|
-
For teams that need centralized management, **Kekkai Portal** offers:
|
|
122
|
-
|
|
123
|
-
* **SAML 2.0 SSO** with Replay Protection
|
|
124
|
-
* **Role-Based Access Control (RBAC)**
|
|
125
|
-
* **Cryptographically Signed Audit Logs**
|
|
126
|
-
|
|
127
|
-
*Built by Kademos Labs.*
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 📚 Documentation
|
|
132
|
-
|
|
133
|
-
- **[Automated Distribution Updates](docs/ci/automated-distributions.md)** - CI/CD distribution triggers
|
|
134
|
-
- **[CI Architecture](/.docs/development/ci-architecture.md)** - Developer guide for distribution automation
|
|
135
|
-
- **[Homebrew Maintenance](docs/ci/homebrew-maintenance.md)** - Homebrew tap management
|
portal/__init__.py
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"""Kekkai Hosted Portal - DefectDojo-backed multi-tenant security dashboard."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
__all__ = [
|
|
6
|
-
"AuthMethod",
|
|
7
|
-
"AuthResult",
|
|
8
|
-
"SAMLTenantConfig",
|
|
9
|
-
"Tenant",
|
|
10
|
-
"TenantStore",
|
|
11
|
-
"UploadResult",
|
|
12
|
-
"authenticate_request",
|
|
13
|
-
"process_upload",
|
|
14
|
-
"validate_upload",
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
from .auth import AuthResult, authenticate_request
|
|
18
|
-
from .tenants import AuthMethod, SAMLTenantConfig, Tenant, TenantStore
|
|
19
|
-
from .uploads import UploadResult, process_upload, validate_upload
|
portal/api.py
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
"""Portal API endpoints for programmatic access.
|
|
2
|
-
|
|
3
|
-
Provides REST API endpoints that expose the same data visible in the UI.
|
|
4
|
-
All endpoints require authentication and enforce tenant isolation.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import json
|
|
10
|
-
import logging
|
|
11
|
-
import os
|
|
12
|
-
from dataclasses import dataclass
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
from typing import Any
|
|
15
|
-
|
|
16
|
-
from .tenants import Tenant
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@dataclass(frozen=True)
|
|
22
|
-
class UploadInfo:
|
|
23
|
-
"""Information about an upload."""
|
|
24
|
-
|
|
25
|
-
upload_id: str
|
|
26
|
-
filename: str
|
|
27
|
-
timestamp: str
|
|
28
|
-
file_hash: str
|
|
29
|
-
size_bytes: int
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@dataclass(frozen=True)
|
|
33
|
-
class TenantStats:
|
|
34
|
-
"""Statistics for a tenant."""
|
|
35
|
-
|
|
36
|
-
total_uploads: int
|
|
37
|
-
total_size_bytes: int
|
|
38
|
-
last_upload_time: str | None
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def get_tenant_info(tenant: Tenant) -> dict[str, Any]:
|
|
42
|
-
"""Get tenant information for API response.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
tenant: The authenticated tenant
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
Dictionary containing tenant metadata
|
|
49
|
-
"""
|
|
50
|
-
return {
|
|
51
|
-
"id": tenant.id,
|
|
52
|
-
"name": tenant.name,
|
|
53
|
-
"dojo_product_id": tenant.dojo_product_id,
|
|
54
|
-
"dojo_engagement_id": tenant.dojo_engagement_id,
|
|
55
|
-
"enabled": tenant.enabled,
|
|
56
|
-
"max_upload_size_mb": tenant.max_upload_size_mb,
|
|
57
|
-
"auth_method": tenant.auth_method.value,
|
|
58
|
-
"default_role": tenant.default_role,
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def list_uploads(tenant: Tenant, limit: int = 50) -> list[dict[str, Any]]:
|
|
63
|
-
"""List recent uploads for a tenant.
|
|
64
|
-
|
|
65
|
-
Args:
|
|
66
|
-
tenant: The authenticated tenant
|
|
67
|
-
limit: Maximum number of uploads to return
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
List of upload metadata dictionaries
|
|
71
|
-
"""
|
|
72
|
-
upload_dir = Path(os.environ.get("PORTAL_UPLOAD_DIR", "/var/lib/kekkai-portal/uploads"))
|
|
73
|
-
tenant_dir = upload_dir / tenant.id
|
|
74
|
-
|
|
75
|
-
if not tenant_dir.exists():
|
|
76
|
-
return []
|
|
77
|
-
|
|
78
|
-
uploads: list[dict[str, Any]] = []
|
|
79
|
-
|
|
80
|
-
# Get all upload files for this tenant
|
|
81
|
-
try:
|
|
82
|
-
upload_files = sorted(
|
|
83
|
-
tenant_dir.glob("*.json"),
|
|
84
|
-
key=lambda p: p.stat().st_mtime,
|
|
85
|
-
reverse=True,
|
|
86
|
-
)[:limit]
|
|
87
|
-
|
|
88
|
-
for upload_file in upload_files:
|
|
89
|
-
stat = upload_file.stat()
|
|
90
|
-
uploads.append(
|
|
91
|
-
{
|
|
92
|
-
"upload_id": upload_file.stem,
|
|
93
|
-
"filename": upload_file.name,
|
|
94
|
-
"timestamp": str(int(stat.st_mtime)),
|
|
95
|
-
"size_bytes": stat.st_size,
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
except (OSError, PermissionError) as e:
|
|
99
|
-
logger.warning("Failed to list uploads for tenant %s: %s", tenant.id, e)
|
|
100
|
-
|
|
101
|
-
return uploads
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def get_tenant_stats(tenant: Tenant) -> dict[str, Any]:
|
|
105
|
-
"""Get statistics for a tenant.
|
|
106
|
-
|
|
107
|
-
Args:
|
|
108
|
-
tenant: The authenticated tenant
|
|
109
|
-
|
|
110
|
-
Returns:
|
|
111
|
-
Dictionary containing tenant statistics
|
|
112
|
-
"""
|
|
113
|
-
upload_dir = Path(os.environ.get("PORTAL_UPLOAD_DIR", "/var/lib/kekkai-portal/uploads"))
|
|
114
|
-
tenant_dir = upload_dir / tenant.id
|
|
115
|
-
|
|
116
|
-
if not tenant_dir.exists():
|
|
117
|
-
return {
|
|
118
|
-
"total_uploads": 0,
|
|
119
|
-
"total_size_bytes": 0,
|
|
120
|
-
"last_upload_time": None,
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
total_uploads = 0
|
|
124
|
-
total_size_bytes = 0
|
|
125
|
-
last_upload_time: int | None = None
|
|
126
|
-
|
|
127
|
-
try:
|
|
128
|
-
for upload_file in tenant_dir.glob("*.json"):
|
|
129
|
-
stat = upload_file.stat()
|
|
130
|
-
total_uploads += 1
|
|
131
|
-
total_size_bytes += stat.st_size
|
|
132
|
-
|
|
133
|
-
if last_upload_time is None or stat.st_mtime > last_upload_time:
|
|
134
|
-
last_upload_time = int(stat.st_mtime)
|
|
135
|
-
|
|
136
|
-
except (OSError, PermissionError) as e:
|
|
137
|
-
logger.warning("Failed to get stats for tenant %s: %s", tenant.id, e)
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
"total_uploads": total_uploads,
|
|
141
|
-
"total_size_bytes": total_size_bytes,
|
|
142
|
-
"last_upload_time": str(last_upload_time) if last_upload_time else None,
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def serialize_api_response(data: dict[str, Any]) -> bytes:
|
|
147
|
-
"""Serialize API response to JSON bytes.
|
|
148
|
-
|
|
149
|
-
Args:
|
|
150
|
-
data: Response data dictionary
|
|
151
|
-
|
|
152
|
-
Returns:
|
|
153
|
-
JSON-encoded bytes
|
|
154
|
-
"""
|
|
155
|
-
return json.dumps(data, indent=2).encode("utf-8")
|
portal/auth.py
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"""Authentication middleware for portal API.
|
|
2
|
-
|
|
3
|
-
Security controls:
|
|
4
|
-
- ASVS V16.3.2: Log failed authorization attempts
|
|
5
|
-
- Constant-time API key comparison to prevent timing attacks
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
import re
|
|
12
|
-
from dataclasses import dataclass
|
|
13
|
-
from typing import TYPE_CHECKING
|
|
14
|
-
|
|
15
|
-
from kekkai_core import redact
|
|
16
|
-
|
|
17
|
-
from .tenants import Tenant, TenantStore
|
|
18
|
-
|
|
19
|
-
if TYPE_CHECKING:
|
|
20
|
-
from collections.abc import Mapping
|
|
21
|
-
|
|
22
|
-
logger = logging.getLogger(__name__)
|
|
23
|
-
|
|
24
|
-
BEARER_PATTERN = re.compile(r"^Bearer\s+(\S+)$", re.IGNORECASE)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@dataclass(frozen=True)
|
|
28
|
-
class AuthResult:
|
|
29
|
-
"""Result of authentication attempt."""
|
|
30
|
-
|
|
31
|
-
authenticated: bool
|
|
32
|
-
tenant: Tenant | None = None
|
|
33
|
-
error: str | None = None
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def authenticate_request(
|
|
37
|
-
headers: Mapping[str, str],
|
|
38
|
-
tenant_store: TenantStore,
|
|
39
|
-
client_ip: str = "unknown",
|
|
40
|
-
) -> AuthResult:
|
|
41
|
-
"""Authenticate a request using Bearer token.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
headers: Request headers (case-insensitive lookup)
|
|
45
|
-
tenant_store: Tenant storage for API key verification
|
|
46
|
-
client_ip: Client IP for logging failed attempts
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
AuthResult with tenant if authenticated, error otherwise
|
|
50
|
-
"""
|
|
51
|
-
auth_header = _get_header(headers, "Authorization")
|
|
52
|
-
if not auth_header:
|
|
53
|
-
_log_auth_failure(client_ip, "missing_header")
|
|
54
|
-
return AuthResult(authenticated=False, error="Missing Authorization header")
|
|
55
|
-
|
|
56
|
-
match = BEARER_PATTERN.match(auth_header)
|
|
57
|
-
if not match:
|
|
58
|
-
_log_auth_failure(client_ip, "invalid_format")
|
|
59
|
-
return AuthResult(authenticated=False, error="Invalid Authorization format")
|
|
60
|
-
|
|
61
|
-
api_key = match.group(1)
|
|
62
|
-
if not api_key:
|
|
63
|
-
_log_auth_failure(client_ip, "empty_token")
|
|
64
|
-
return AuthResult(authenticated=False, error="Empty API token")
|
|
65
|
-
|
|
66
|
-
tenant = tenant_store.get_by_api_key(api_key)
|
|
67
|
-
if not tenant:
|
|
68
|
-
_log_auth_failure(client_ip, "invalid_token", api_key_prefix=api_key[:8])
|
|
69
|
-
return AuthResult(authenticated=False, error="Invalid API key")
|
|
70
|
-
|
|
71
|
-
if not tenant.enabled:
|
|
72
|
-
_log_auth_failure(client_ip, "tenant_disabled", tenant_id=tenant.id)
|
|
73
|
-
return AuthResult(authenticated=False, error="Tenant is disabled")
|
|
74
|
-
|
|
75
|
-
logger.info(
|
|
76
|
-
"auth.success client_ip=%s tenant_id=%s",
|
|
77
|
-
redact(client_ip),
|
|
78
|
-
tenant.id,
|
|
79
|
-
)
|
|
80
|
-
return AuthResult(authenticated=True, tenant=tenant)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def _get_header(headers: Mapping[str, str], name: str) -> str | None:
|
|
84
|
-
"""Get header value with case-insensitive lookup."""
|
|
85
|
-
for key, value in headers.items():
|
|
86
|
-
if key.lower() == name.lower():
|
|
87
|
-
return value
|
|
88
|
-
return None
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def _log_auth_failure(
|
|
92
|
-
client_ip: str,
|
|
93
|
-
reason: str,
|
|
94
|
-
tenant_id: str | None = None,
|
|
95
|
-
api_key_prefix: str | None = None,
|
|
96
|
-
) -> None:
|
|
97
|
-
"""Log authentication failure for security monitoring (ASVS V16.3.2)."""
|
|
98
|
-
parts = [f"auth.failure reason={reason}", f"client_ip={redact(client_ip)}"]
|
|
99
|
-
if tenant_id:
|
|
100
|
-
parts.append(f"tenant_id={tenant_id}")
|
|
101
|
-
if api_key_prefix:
|
|
102
|
-
parts.append(f"api_key_prefix={api_key_prefix}...")
|
|
103
|
-
logger.warning(" ".join(parts))
|
portal/enterprise/__init__.py
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"""Enterprise features for Kekkai Portal.
|
|
2
|
-
|
|
3
|
-
Provides:
|
|
4
|
-
- RBAC (Role-Based Access Control)
|
|
5
|
-
- SAML 2.0 SSO integration
|
|
6
|
-
- Audit logging
|
|
7
|
-
- Enterprise license gating
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
from .audit import AuditEvent, AuditEventType, AuditLog
|
|
13
|
-
from .licensing import EnterpriseLicense, LicenseStatus, LicenseValidator
|
|
14
|
-
from .rbac import AuthorizationResult, Permission, RBACManager, Role
|
|
15
|
-
from .saml import SAMLAssertion, SAMLConfig, SAMLError, SAMLProcessor
|
|
16
|
-
|
|
17
|
-
__all__ = [
|
|
18
|
-
"AuditEvent",
|
|
19
|
-
"AuditEventType",
|
|
20
|
-
"AuditLog",
|
|
21
|
-
"AuthorizationResult",
|
|
22
|
-
"EnterpriseLicense",
|
|
23
|
-
"LicenseStatus",
|
|
24
|
-
"LicenseValidator",
|
|
25
|
-
"Permission",
|
|
26
|
-
"RBACManager",
|
|
27
|
-
"Role",
|
|
28
|
-
"SAMLAssertion",
|
|
29
|
-
"SAMLConfig",
|
|
30
|
-
"SAMLError",
|
|
31
|
-
"SAMLProcessor",
|
|
32
|
-
]
|