Compare commits

..

2 Commits

Author SHA1 Message Date
Jesús Pérez
2c2ff965be
chore: update docs and layout 2026-01-12 05:02:07 +00:00
Jesús Pérez
bbe293098d
chore: update layout docs 2026-01-12 04:53:31 +00:00
64 changed files with 1083 additions and 3193 deletions

107
.markdownlint-cli2.jsonc Normal file
View File

@ -0,0 +1,107 @@
// Markdownlint-cli2 Configuration
// Documentation quality enforcement aligned with CLAUDE.md guidelines
// See: https://github.com/igorshubovych/markdownlint-cli2
{
"config": {
"default": true,
// Headings - enforce proper hierarchy
"MD001": false, // heading-increment (relaxed - allow flexibility)
"MD026": { "punctuation": ".,;:!?" }, // heading-punctuation
// Lists - enforce consistency
"MD004": { "style": "consistent" }, // ul-style (consistent list markers)
"MD005": false, // inconsistent-indentation (relaxed)
"MD007": { "indent": 2 }, // ul-indent
"MD029": false, // ol-prefix (allow flexible list numbering)
"MD030": { "ul_single": 1, "ol_single": 1, "ul_multi": 1, "ol_multi": 1 },
// Code blocks - fenced only
"MD046": { "style": "fenced" }, // code-block-style
// CRITICAL: MD040 only checks opening fences, NOT closing fences
// It does NOT catch malformed closing fences with language specifiers (e.g., ```plaintext)
// CommonMark spec requires closing fences to be ``` only (no language)
// Use: nu ../scripts/check-malformed-fences.nu (manual validation)
"MD040": true, // fenced-code-language (code blocks need language on OPENING fence)
// Formatting - strict whitespace
"MD009": true, // no-hard-tabs
"MD010": true, // hard-tabs
"MD011": true, // reversed-link-syntax
"MD018": true, // no-missing-space-atx
"MD019": true, // no-multiple-space-atx
"MD020": true, // no-missing-space-closed-atx
"MD021": true, // no-multiple-space-closed-atx
"MD023": true, // heading-starts-line
"MD027": true, // no-multiple-spaces-blockquote
"MD037": true, // no-space-in-emphasis
"MD039": true, // no-space-in-links
// Trailing content
"MD012": false, // no-multiple-blanks (relaxed - allow formatting space)
"MD024": false, // no-duplicate-heading (too strict for docs)
"MD028": false, // no-blanks-blockquote (relaxed)
"MD047": true, // single-trailing-newline
// Links and references
"MD034": true, // no-bare-urls (links must be formatted)
"MD042": true, // no-empty-links
// HTML - allow for documentation formatting and images
"MD033": { "allowed_elements": ["br", "hr", "details", "summary", "p", "img"] },
// Line length - relaxed for technical documentation
// Headers can be longer to accommodate descriptive technical titles
// Code blocks excluded - example JSON/code should not be reformatted
"MD013": {
"line_length": 150,
"heading_line_length": 350, // Allow longer headers for technical docs
"code_blocks": false, // Don't check line length in code blocks (examples, JSON, etc.)
"tables": true,
"headers": true,
"strict": false,
"stern": false
},
// Images
"MD045": true, // image-alt-text
// Tables - enforce proper formatting
"MD060": true, // table-column-style (proper spacing: | ---- | not |------|)
// Disable rules that conflict with relaxed style
"MD003": false, // consistent-indentation
"MD041": false, // first-line-heading
"MD025": false, // single-h1 / multiple-top-level-headings
"MD022": false, // blanks-around-headings (flexible spacing)
"MD032": false, // blanks-around-lists (flexible spacing)
"MD035": false, // hr-style (consistent)
"MD036": false, // no-emphasis-as-heading
"MD044": false // proper-names
},
// Documentation patterns
"globs": [
"**/*.md",
"!node_modules/**",
"!target/**",
"!.git/**",
"!build/**",
"!dist/**"
],
// Ignore build artifacts, external content, and operational directories
"ignores": [
"node_modules/**",
"target/**",
".git/**",
"build/**",
"dist/**",
".coder/**",
".claude/**",
".wrks/**",
".vale/**"
]
}

90
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,90 @@
# Pre-commit Framework Configuration
# Generated by dev-system/ci
# Configures git pre-commit hooks for Rust + Markdown projects
repos:
# ============================================================================
# Rust Hooks (ACTIVE)
# ============================================================================
- repo: local
hooks:
- id: rust-fmt
name: Rust formatting (cargo +nightly fmt)
entry: bash -c 'cargo +nightly fmt --all -- --check'
language: system
types: [rust]
pass_filenames: false
stages: [pre-commit]
- id: rust-clippy
name: Rust linting (cargo clippy)
entry: bash -c 'cargo clippy --all-targets -- -D warnings'
language: system
types: [rust]
pass_filenames: false
stages: [pre-commit]
# NOTE: Disabled - cargo test blocks git push. Tests should run in CI/CD.
# - id: rust-test
# name: Rust tests
# entry: bash -c 'cargo test --workspace'
# language: system
# types: [rust]
# pass_filenames: false
# stages: [pre-push]
# NOTE: Disabled - cargo deny blocks git push. Should run in CI/CD.
# - id: cargo-deny
# name: Cargo deny (licenses & advisories)
# entry: bash -c 'cargo deny check licenses advisories'
# language: system
# pass_filenames: false
# stages: [pre-push]
# ============================================================================
# Markdown Hooks (ACTIVE)
# ============================================================================
- repo: local
hooks:
- id: markdownlint
name: Markdown linting (markdownlint-cli2)
entry: markdownlint-cli2
language: system
types: [markdown]
stages: [pre-commit]
# NOTE: Disabled - markdownlint-cli2 already catches syntax issues
# This script is redundant and causing false positives
# - id: check-malformed-fences
# name: Check malformed closing fences
# entry: bash -c 'cd .. && nu scripts/check-malformed-fences.nu $(git diff --cached --name-only --diff-filter=ACM | grep "\.md$" | grep -v ".coder/" | grep -v ".claude/" | grep -v "old_config/" | tr "\n" " ")'
# language: system
# types: [markdown]
# pass_filenames: false
# stages: [pre-commit]
# exclude: ^\.coder/|^\.claude/|^old_config/
# ============================================================================
# General Pre-commit Hooks
# ============================================================================
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-added-large-files
args: ['--maxkb=1000']
- id: check-case-conflict
- id: check-merge-conflict
- id: check-toml
- id: check-yaml
exclude: ^\.woodpecker/
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: \.md$
- id: mixed-line-ending

View File

@ -9,7 +9,8 @@
# Platform Services # Platform Services
Platform-level services for the [Provisioning project](https://repo.jesusperez.pro/jesus/provisioning) infrastructure automation platform. These services provide the high-performance execution layer, management interfaces, and supporting infrastructure for the entire provisioning system. Platform-level services for the [Provisioning project](https://repo.jesusperez.pro/jesus/provisioning) infrastructure automation platform.
These services provide the high-performance execution layer, management interfaces, and supporting infrastructure for the entire provisioning system.
## Overview ## Overview
@ -52,7 +53,7 @@ High-performance Rust/Nushell hybrid orchestrator for workflow execution.
```bash ```bash
cd orchestrator cd orchestrator
./scripts/start-orchestrator.nu --background ./scripts/start-orchestrator.nu --background
```plaintext ```text
**REST API**: **REST API**:
@ -143,7 +144,7 @@ provisioning-installer --headless --mode solo --yes
# Unattended CI/CD # Unattended CI/CD
provisioning-installer --unattended --config config.toml provisioning-installer --unattended --config config.toml
```plaintext ```text
**Documentation**: `installer/docs/` - Complete guides and references **Documentation**: `installer/docs/` - Complete guides and references
@ -321,41 +322,53 @@ Systemd service units for platform services.
## Architecture ## Architecture
```plaintext ```plaintext
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ User Interfaces │ │ User Interfaces │
│ • CLI (provisioning command) │ │ • CLI (provisioning command) │
│ • Web UI (Control Center UI) │ │ • Web UI (Control Center UI) │
│ • API Clients │ │ • API Clients │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────
────────────┘
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ API Gateway │ │ API Gateway │
│ • Request Routing │ │ • Request Routing │
│ • Authentication & Authorization │ │ • Authentication & Authorization │
│ • Rate Limiting │ │ • Rate Limiting │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────
────────────┘
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ Platform Services Layer │ │ Platform Services Layer │
│ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ ┌──────────────┐ ┌──────────────┐
┌──────────────┐ │
│ │ Orchestrator │ │Control Center│ │ MCP Server │ │ │ │ Orchestrator │ │Control Center│ │ MCP Server │ │
│ │ (Rust) │ │ (Rust) │ │ (Nushell) │ │ │ │ (Rust) │ │ (Rust) │ │ (Nushell) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │ │ └──────────────┘ └──────────────┘
└──────────────┘ │
│ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ ┌──────────────┐ ┌──────────────┐
┌──────────────┐ │
│ │ Installer │ │ OCI Registry │ │ Extension │ │ │ │ Installer │ │ OCI Registry │ │ Extension │ │
│ │(Rust/Nushell)│ │ │ │ Registry │ │ │ │(Rust/Nushell)│ │ │ │ Registry │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │ │ └──────────────┘ └──────────────┘
└─────────────────────────────────────────────────────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────
────────────┘
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ Data & State Layer │ │ Data & State Layer │
│ • SurrealDB (State Management) │ │ • SurrealDB (State Management) │
│ • File-based Persistence (Checkpoints) │ │ • File-based Persistence (Checkpoints) │
│ • Configuration Storage │ │ • Configuration Storage │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────
```plaintext ────────────┘
```text
--- ---
@ -364,7 +377,7 @@ Systemd service units for platform services.
### Primary Languages ### Primary Languages
| Language | Usage | Services | | Language | Usage | Services |
|----------|-------|----------| | ---------- | ------- | ---------- |
| **Rust** | Platform services, performance layer | Orchestrator, Control Center, Installer, API Gateway | | **Rust** | Platform services, performance layer | Orchestrator, Control Center, Installer, API Gateway |
| **Nushell** | Scripting, automation, MCP integration | MCP Server, Installer scripts | | **Nushell** | Scripting, automation, MCP integration | MCP Server, Installer scripts |
| **Web** | Frontend interfaces | Control Center UI | | **Web** | Frontend interfaces | Control Center UI |
@ -387,7 +400,7 @@ Systemd service units for platform services.
```bash ```bash
# Docker Compose for local development # Docker Compose for local development
docker-compose -f infrastructure/docker/dev.yml up docker-compose -f infrastructure/docker/dev.yml up
```plaintext ```text
### 2. **Production Mode (Systemd)** ### 2. **Production Mode (Systemd)**
@ -397,14 +410,14 @@ sudo cp infrastructure/systemd/*.service /etc/infrastructure/systemd/system/
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable --now provisioning-orchestrator sudo systemctl enable --now provisioning-orchestrator
sudo systemctl enable --now provisioning-control-center sudo systemctl enable --now provisioning-control-center
```plaintext ```text
### 3. **Kubernetes Deployment** ### 3. **Kubernetes Deployment**
```bash ```bash
# Deploy platform services to Kubernetes # Deploy platform services to Kubernetes
kubectl apply -f k8s/ kubectl apply -f k8s/
```plaintext ```text
--- ---
@ -450,7 +463,7 @@ kubectl apply -f k8s/
cd orchestrator && cargo build --release cd orchestrator && cargo build --release
cd ../control-center && cargo build --release cd ../control-center && cargo build --release
cd ../installer && cargo build --release cd ../installer && cargo build --release
```plaintext ```text
### Running Services ### Running Services
@ -466,7 +479,7 @@ cargo run --release
# Start MCP server # Start MCP server
cd mcp-server cd mcp-server
nu run.nu nu run.nu
```plaintext ```text
--- ---
@ -489,7 +502,7 @@ platform/
├── k8s/ # Kubernetes manifests ├── k8s/ # Kubernetes manifests
├── infrastructure/systemd/ # Systemd units ├── infrastructure/systemd/ # Systemd units
└── docs/ # Platform documentation └── docs/ # Platform documentation
```plaintext ```text
### Adding New Services ### Adding New Services

View File

@ -1,24 +1,25 @@
# Platform Service Configuration Files # Platform Service Configuration Files
This directory contains **16 production-ready TOML configuration files** generated from Nickel schemas for all platform services across all deployment modes. This directory contains **16 production-ready TOML configuration files** generated from Nickel schemas
for all platform services across all deployment modes.
## Generated Files ## Generated Files
**4 Services × 4 Deployment Modes = 16 Configuration Files** **4 Services × 4 Deployment Modes = 16 Configuration Files**
``` ```plaintext
orchestrator.{solo,multiuser,cicd,enterprise}.toml (2.2 kB each) orchestrator.{solo,multiuser,cicd,enterprise}.toml (2.2 kB each)
control-center.{solo,multiuser,cicd,enterprise}.toml (3.4 kB each) control-center.{solo,multiuser,cicd,enterprise}.toml (3.4 kB each)
mcp-server.{solo,multiuser,cicd,enterprise}.toml (2.7 kB each) mcp-server.{solo,multiuser,cicd,enterprise}.toml (2.7 kB each)
installer.{solo,multiuser,cicd,enterprise}.toml (2.5 kB each) installer.{solo,multiuser,cicd,enterprise}.toml (2.5 kB each)
``` ```text
**Total**: ~45 KB, all validated and ready for deployment **Total**: ~45 KB, all validated and ready for deployment
## Deployment Modes ## Deployment Modes
| Mode | Resources | Database | Use Case | Load | | Mode | Resources | Database | Use Case | Load |
|------|-----------|----------|----------|------| | ------ | ----------- | ---------- | ---------- | ------ |
| **solo** | 2 CPU, 4 GB | Embedded | Development | `ORCHESTRATOR_MODE=solo` | | **solo** | 2 CPU, 4 GB | Embedded | Development | `ORCHESTRATOR_MODE=solo` |
| **multiuser** | 4 CPU, 8 GB | PostgreSQL/SurrealDB | Team Staging | `ORCHESTRATOR_MODE=multiuser` | | **multiuser** | 4 CPU, 8 GB | PostgreSQL/SurrealDB | Team Staging | `ORCHESTRATOR_MODE=multiuser` |
| **cicd** | 8 CPU, 16 GB | Ephemeral | CI/CD Pipelines | `ORCHESTRATOR_MODE=cicd` | | **cicd** | 8 CPU, 16 GB | Ephemeral | CI/CD Pipelines | `ORCHESTRATOR_MODE=cicd` |
@ -40,7 +41,7 @@ export CONTROL_CENTER_MODE=multiuser
# Enterprise mode (production HA) # Enterprise mode (production HA)
export ORCHESTRATOR_MODE=enterprise export ORCHESTRATOR_MODE=enterprise
export CONTROL_CENTER_MODE=enterprise export CONTROL_CENTER_MODE=enterprise
``` ```text
### Override individual fields ### Override individual fields
@ -48,7 +49,7 @@ export CONTROL_CENTER_MODE=enterprise
export ORCHESTRATOR_SERVER_WORKERS=8 export ORCHESTRATOR_SERVER_WORKERS=8
export ORCHESTRATOR_SERVER_PORT=9090 export ORCHESTRATOR_SERVER_PORT=9090
export CONTROL_CENTER_REQUIRE_MFA=true export CONTROL_CENTER_REQUIRE_MFA=true
``` ```text
## Configuration Loading Hierarchy ## Configuration Loading Hierarchy
@ -65,7 +66,7 @@ Each service loads configuration with this priority:
```bash ```bash
export DEPLOYMENT_MODE=multiuser export DEPLOYMENT_MODE=multiuser
docker-compose -f provisioning/platform/infrastructure/docker/docker-compose.yml up docker-compose -f provisioning/platform/infrastructure/docker/docker-compose.yml up
``` ```text
## Kubernetes Integration ## Kubernetes Integration
@ -73,7 +74,7 @@ docker-compose -f provisioning/platform/infrastructure/docker/docker-compose.yml
# Load enterprise mode configs into K8s # Load enterprise mode configs into K8s
kubectl create configmap orchestrator-config \ kubectl create configmap orchestrator-config \
--from-file=provisioning/platform/config/orchestrator.enterprise.toml --from-file=provisioning/platform/config/orchestrator.enterprise.toml
``` ```text
## Validation ## Validation
@ -83,7 +84,7 @@ Verify all configs parse correctly:
for file in *.toml; do for file in *.toml; do
nu -c "open '$file'" && echo "✅ $file" || echo "❌ $file" nu -c "open '$file'" && echo "✅ $file" || echo "❌ $file"
done done
``` ```text
## Structure ## Structure

View File

@ -4,14 +4,14 @@ This directory contains example Nickel files demonstrating how to generate platf
## File Structure ## File Structure
``` ```plaintext
examples/ examples/
├── README.md # This file ├── README.md # This file
├── orchestrator.solo.example.ncl # Solo deployment (1 CPU, 1GB memory) ├── orchestrator.solo.example.ncl # Solo deployment (1 CPU, 1GB memory)
├── orchestrator.multiuser.example.ncl # Multiuser deployment (2 CPU, 2GB memory, HA) ├── orchestrator.multiuser.example.ncl # Multiuser deployment (2 CPU, 2GB memory, HA)
├── orchestrator.enterprise.example.ncl # Enterprise deployment (4 CPU, 4GB memory, 3 replicas) ├── orchestrator.enterprise.example.ncl # Enterprise deployment (4 CPU, 4GB memory, 3 replicas)
└── control-center.solo.example.ncl # Control Center solo deployment └── control-center.solo.example.ncl # Control Center solo deployment
``` ```text
## Usage ## Usage
@ -26,7 +26,7 @@ nickel export --format json examples/orchestrator.solo.example.ncl | jq .
# Type check example # Type check example
nickel typecheck examples/orchestrator.solo.example.ncl nickel typecheck examples/orchestrator.solo.example.ncl
``` ```text
## Key Concepts ## Key Concepts
@ -46,7 +46,7 @@ let mode = import "../../schemas/platform/defaults/deployment/solo-defaults.ncl"
helpers.compose_config defaults mode { helpers.compose_config defaults mode {
# User-specific overrides here # User-specific overrides here
} }
``` ```text
### 3. ConfigLoader Integration ### 3. ConfigLoader Integration
Generated TOML files are automatically loaded by Rust services: Generated TOML files are automatically loaded by Rust services:
@ -56,12 +56,12 @@ use platform_config::OrchestratorConfig;
let config = OrchestratorConfig::load().expect("Failed to load orchestrator config"); let config = OrchestratorConfig::load().expect("Failed to load orchestrator config");
println!("Orchestrator listening on port: {}", config.server.port); println!("Orchestrator listening on port: {}", config.server.port);
``` ```text
## Mode Reference ## Mode Reference
| Mode | CPU | Memory | Replicas | Use Case | | Mode | CPU | Memory | Replicas | Use Case |
|------|-----|--------|----------|----------| | ------ | ----- | -------- | ---------- | ---------- |
| **solo** | 1.0 | 1024M | 1 | Development, testing | | **solo** | 1.0 | 1024M | 1 | Development, testing |
| **multiuser** | 2.0 | 2048M | 2 | Staging, small production | | **multiuser** | 2.0 | 2048M | 2 | Staging, small production |
| **enterprise** | 4.0 | 4096M | 3+ | Large production deployments | | **enterprise** | 4.0 | 4096M | 3+ | Large production deployments |
@ -88,6 +88,7 @@ Beyond platform configs, you can generate complete infrastructure from schemas:
- `provisioning/schemas/infrastructure/examples-enterprise-deployment.ncl` - Enterprise infrastructure - `provisioning/schemas/infrastructure/examples-enterprise-deployment.ncl` - Enterprise infrastructure
**What Gets Generated**: **What Gets Generated**:
```bash ```bash
# Solo deployment infrastructure # Solo deployment infrastructure
nickel export --format json provisioning/schemas/infrastructure/examples-solo-deployment.ncl nickel export --format json provisioning/schemas/infrastructure/examples-solo-deployment.ncl
@ -97,10 +98,11 @@ nickel export --format json provisioning/schemas/infrastructure/examples-solo-de
# - nginx_config (load balancer setup) # - nginx_config (load balancer setup)
# - prometheus_config (4 scrape jobs) # - prometheus_config (4 scrape jobs)
# - oci_registry_config (container registry) # - oci_registry_config (container registry)
``` ```text
**Integration Pattern**: **Integration Pattern**:
```
```plaintext
Platform Config (Orchestrator, Control Center, etc.) Platform Config (Orchestrator, Control Center, etc.)
↓ ConfigLoader reads TOML ↓ ConfigLoader reads TOML
↓ Services start with config ↓ Services start with config
@ -108,17 +110,19 @@ Platform Config (Orchestrator, Control Center, etc.)
Infrastructure Config (Docker, Nginx, Prometheus, etc.) Infrastructure Config (Docker, Nginx, Prometheus, etc.)
↓ nickel export → YAML/JSON ↓ nickel export → YAML/JSON
↓ Deploy with Docker/Kubernetes/Nginx ↓ Deploy with Docker/Kubernetes/Nginx
``` ```text
### Generation and Validation ### Generation and Validation
**Generate all infrastructure configs**: **Generate all infrastructure configs**:
```bash ```bash
provisioning/platform/scripts/generate-infrastructure-configs.nu --mode solo --format yaml provisioning/platform/scripts/generate-infrastructure-configs.nu --mode solo --format yaml
provisioning/platform/scripts/generate-infrastructure-configs.nu --mode enterprise --format json provisioning/platform/scripts/generate-infrastructure-configs.nu --mode enterprise --format json
``` ```text
**Validate generated configs**: **Validate generated configs**:
```bash ```bash
provisioning/platform/scripts/validate-infrastructure.nu --config-dir /tmp/infra provisioning/platform/scripts/validate-infrastructure.nu --config-dir /tmp/infra
@ -127,13 +131,14 @@ provisioning/platform/scripts/validate-infrastructure.nu --config-dir /tmp/infra
# - Kubernetes (kubectl apply --dry-run=client) # - Kubernetes (kubectl apply --dry-run=client)
# - Nginx (nginx -t) # - Nginx (nginx -t)
# - Prometheus (promtool check config) # - Prometheus (promtool check config)
``` ```text
**Interactive setup**: **Interactive setup**:
```bash ```bash
bash provisioning/platform/scripts/setup-with-forms.sh bash provisioning/platform/scripts/setup-with-forms.sh
# Provides TypeDialog forms or FormInquire fallback for configuration # Uses TypeDialog bash wrappers (TTY-safe) or basic Nushell prompts as fallback
``` ```text
## Error Handling ## Error Handling
@ -148,7 +153,7 @@ cargo test --package platform-config --test validation
# Verify path resolution # Verify path resolution
provisioning validate-config --check-paths provisioning validate-config --check-paths
``` ```text
## Environment Variable Overrides ## Environment Variable Overrides
@ -158,7 +163,7 @@ Even with TOML configs, environment variables take precedence:
export PROVISIONING_MODE=multiuser export PROVISIONING_MODE=multiuser
export ORCHESTRATOR_PORT=9000 export ORCHESTRATOR_PORT=9000
provisioning orchestrator start # Uses env overrides provisioning orchestrator start # Uses env overrides
``` ```text
## Adding New Configurations ## Adding New Configurations

View File

@ -1,436 +0,0 @@
# Phase 4: MCP Tool Integration API Documentation
## Overview
Phase 4 implements a complete **Model Context Protocol (MCP)** tool registry with **18+ tools** across 4 categories (RAG, Guidance, Settings, IaC) and introduces **hybrid execution mode** for automatic tool suggestion and invocation.
## Architecture
### Three-Layer Integration
```
External Clients (HTTP/MCP)
ai-service HTTP API (Port 8083)
Unified Tool Registry (ToolRegistry)
RAG | Guidance | Settings | IaC Tools
Knowledge Base | System | Configuration
```
## API Endpoints
### 1. Ask with RAG (Optional Tool Execution)
**Endpoint**: `POST /api/v1/ai/ask`
**Request**:
```json
{
"question": "What are deployment best practices?",
"context": "Optional context for the question",
"enable_tool_execution": false,
"max_tool_calls": 3
}
```
**Fields**:
- `question` (string, required): The question to ask
- `context` (string, optional): Additional context
- `enable_tool_execution` (boolean, optional, default: false): Enable hybrid mode with automatic tool execution
- `max_tool_calls` (integer, optional, default: 3): Maximum tools to execute in hybrid mode
**Response** (Explicit Mode - default):
```json
{
"answer": "Based on the knowledge base, here's what I found:\n- **Best Practice 1**: ...",
"sources": ["Practice 1", "Practice 2"],
"confidence": 85,
"reasoning": "Retrieved 3 relevant documents",
"tool_executions": null
}
```
**Response** (Hybrid Mode - auto-tools enabled):
```json
{
"answer": "Based on the knowledge base, here's what I found:\n- **Best Practice 1**: ...\n\n---\n\n**Tool Results:**\n\n**guidance_check_system_status:**\nStatus: healthy\nProvisioning: running\n\n**guidance_find_docs:**\nStatus: success\nDocumentation search results for: deployment",
"sources": ["Practice 1", "Practice 2"],
"confidence": 85,
"reasoning": "Retrieved 3 relevant documents",
"tool_executions": [
{
"tool_name": "guidance_check_system_status",
"result": {
"status": "healthy",
"tool": "guidance_check_system_status",
"system": {
"provisioning": "running",
"services": "operational"
}
},
"duration_ms": 42
}
]
}
```
### 2. Execute Tool Explicitly
**Endpoint**: `POST /api/v1/ai/mcp/tool`
**Request**:
```json
{
"tool_name": "rag_semantic_search",
"args": {
"query": "kubernetes deployment",
"top_k": 5
}
}
```
**Response**:
```json
{
"result": {
"status": "success",
"tool": "rag_semantic_search",
"message": "Semantic search would be performed for: kubernetes deployment",
"results": []
},
"duration_ms": 12
}
```
## Tool Registry
### Available Tools (18+ tools)
#### RAG Tools (3)
- **rag_ask_question**: Ask a question using RAG with knowledge base search
- Args: `{question: string, context?: string, top_k?: int}`
- Returns: Answer with sources and confidence
- **rag_semantic_search**: Perform semantic search on knowledge base
- Args: `{query: string, category?: string, top_k?: int}`
- Returns: Search results from knowledge base
- **rag_get_status**: Get status of RAG knowledge base
- Args: `{}`
- Returns: Knowledge base statistics
#### Guidance Tools (5)
- **guidance_check_system_status**: Check current system status
- Args: `{}`
- Returns: System health and service status
- **guidance_suggest_next_action**: Get action suggestions based on system state
- Args: `{context?: string}`
- Returns: Recommended next action
- **guidance_find_docs**: Find relevant documentation
- Args: `{query: string, context?: string}`
- Returns: Documentation search results
- **guidance_troubleshoot**: Troubleshoot an issue
- Args: `{error: string, context?: string}`
- Returns: Diagnosis and fixes
- **guidance_validate_config**: Validate configuration
- Args: `{config_path: string}`
- Returns: Validation results
#### Settings Tools (7)
- **installer_get_settings**: Get installer settings
- **installer_complete_config**: Complete partial configuration
- **installer_validate_config**: Validate configuration against schema
- **installer_get_defaults**: Get defaults for deployment mode
- **installer_platform_recommendations**: Get platform recommendations
- **installer_service_recommendations**: Get service recommendations
- **installer_resource_recommendations**: Get resource recommendations
#### IaC Tools (3)
- **iac_detect_technologies**: Detect technologies in infrastructure
- **iac_analyze_completeness**: Analyze infrastructure completeness
- **iac_infer_requirements**: Infer infrastructure requirements
### List Tools
**Endpoint**: `GET /api/v1/ai/tools`
**Response**:
```json
[
{
"name": "rag_ask_question",
"description": "Ask a question using RAG...",
"category": "Rag",
"input_schema": {
"type": "object",
"properties": {
"question": {"type": "string"},
"context": {"type": "string"},
"top_k": {"type": "integer"}
},
"required": ["question"]
}
}
]
```
## Hybrid Execution Mode
### How It Works
1. **RAG Query**: User asks a question with `enable_tool_execution: true`
2. **Tool Suggestion**: RAG answer is analyzed for relevant tools using keyword matching
3. **Tool Execution**: Suggested tools are executed automatically (up to `max_tool_calls`)
4. **Answer Enrichment**: Tool results are merged into the RAG answer
5. **Response**: Both RAG answer and tool results returned together
### Tool Suggestion Algorithm
Tools are suggested based on keywords in the question:
```
Question contains "status" → suggest guidance_check_system_status
Question contains "config" → suggest guidance_validate_config
Question contains "doc" → suggest guidance_find_docs
Question contains "error" → suggest guidance_troubleshoot
Question contains "next" → suggest guidance_suggest_next_action
Question contains "search" → suggest rag_semantic_search
```
### Examples
#### Example 1: Explicit Mode (Default)
```bash
curl -X POST http://localhost:8083/api/v1/ai/ask \
-H 'Content-Type: application/json' \
-d '{
"question": "What are deployment best practices?",
"enable_tool_execution": false
}'
```
Response: RAG answer only (fast, predictable)
#### Example 2: Hybrid Mode with Auto-Execution
```bash
curl -X POST http://localhost:8083/api/v1/ai/ask \
-H 'Content-Type: application/json' \
-d '{
"question": "Is the system healthy and what are the best practices?",
"enable_tool_execution": true,
"max_tool_calls": 3
}'
```
Response: RAG answer + system status from guidance_check_system_status tool
#### Example 3: Explicit Tool Call
```bash
curl -X POST http://localhost:8083/api/v1/ai/mcp/tool \
-H 'Content-Type: application/json' \
-d '{
"tool_name": "guidance_check_system_status",
"args": {}
}'
```
Response: Raw tool result with timing
## Type Definitions
### AskRequest
```rust
pub struct AskRequest {
pub question: String, // The question to ask
pub context: Option<String>, // Optional context
pub enable_tool_execution: Option<bool>, // Enable hybrid mode (default: false)
pub max_tool_calls: Option<u32>, // Max tools to execute (default: 3)
}
```
### AskResponse
```rust
pub struct AskResponse {
pub answer: String, // Answer from RAG or combined with tools
pub sources: Vec<String>, // Source documents
pub confidence: u8, // Confidence level (0-100)
pub reasoning: String, // Explanation of answer
pub tool_executions: Option<Vec<ToolExecution>>, // Tools executed in hybrid mode
}
```
### McpToolRequest
```rust
pub struct McpToolRequest {
pub tool_name: String, // Name of tool to execute
pub args: serde_json::Value, // Tool arguments
}
```
### McpToolResponse
```rust
pub struct McpToolResponse {
pub result: serde_json::Value, // Tool result
pub duration_ms: u64, // Execution time
}
```
### ToolExecution
```rust
pub struct ToolExecution {
pub tool_name: String, // Which tool was executed
pub result: serde_json::Value, // Tool result
pub duration_ms: u64, // Execution duration
}
```
## Performance Characteristics
### Explicit Mode
- **Latency**: 50-200ms (RAG search only)
- **Deterministic**: Same question → same answer
- **Cost**: Low (single knowledge base search)
- **Use case**: Production, predictable responses
### Hybrid Mode
- **Latency**: 100-500ms (RAG + 1-3 tool executions)
- **Variable**: Different tools run based on question keywords
- **Cost**: Higher (multiple tool executions)
- **Use case**: Interactive, exploratory queries
- **Timeout**: 30s per tool execution
## Error Handling
### Invalid Tool Name
```json
{
"error": "Unknown tool: invalid_tool_xyz"
}
```
### Missing Required Arguments
```json
{
"error": "Tool execution failed: query parameter required"
}
```
### Tool Execution Timeout
```json
{
"error": "Tool execution failed: timeout exceeded"
}
```
## Best Practices
### 1. Use Explicit Mode by Default
```json
{
"question": "What are deployment best practices?",
"enable_tool_execution": false
}
```
- Faster and more predictable
- Better for production systems
### 2. Enable Hybrid Mode for Interactive Queries
```json
{
"question": "Is the system healthy and how do I fix it?",
"enable_tool_execution": true,
"max_tool_calls": 3
}
```
- Better context with tool results
- Good for troubleshooting
### 3. Use Explicit Tool Calls for Specific Needs
```json
{
"tool_name": "guidance_check_system_status",
"args": {}
}
```
- When you know exactly what you need
- Bypass RAG altogether
- Direct tool access
### 4. Set Appropriate max_tool_calls
- **1**: For simple yes/no tools
- **3**: Balanced (default)
- **5+**: For complex queries requiring multiple tools
## Implementation Details
### Tool Registry
The `ToolRegistry` maintains:
- 18+ tool definitions organized by category
- JSON Schema for each tool's input validation
- Async execution handlers for each tool
### Hybrid Mode Flow
1. Parse AskRequest, check `enable_tool_execution`
2. Get RAG answer from knowledge base
3. Call `analyze_for_tools()` on the question
4. Execute suggested tools (respecting `max_tool_calls`)
5. Call `enrich_answer_with_results()` to merge outputs
6. Return combined response with `tool_executions` field
### Tool Suggestion
Algorithm in `tool_integration.rs`:
- Keyword matching against question
- Confidence scoring per suggestion
- Sort by confidence descending
- Take top N (limited by max_tool_calls)
## Testing
Run integration tests:
```bash
cargo test --package ai-service --test phase4_integration_test
```
Tests include:
- Tool registry initialization (16 tools verified)
- Explicit tool execution (all 4 categories)
- Hybrid mode with auto-execution
- max_tool_calls limit enforcement
- Error handling for unknown/invalid tools
- Tool definition schema validation
## Future Enhancements
1. **Custom Tool Registration**: Allow plugins to register tools
2. **Tool Chaining**: Execute tools sequentially based on results
3. **Semantic Tool Selection**: Use embeddings instead of keywords
4. **Tool Caching**: Cache results for frequently executed tools
5. **Authentication**: Per-tool access control
6. **Metrics**: Tool execution statistics and performance monitoring
## Migration from Phase 3
Phase 3 provided RAG with:
- Knowledge base loading
- Keyword search
- Basic RAG queries
Phase 4 adds:
- ✅ Unified tool registry (18+ tools)
- ✅ Hybrid execution mode (auto-trigger tools)
- ✅ Explicit tool execution
- ✅ Tool result enrichment
- ✅ Category-based organization
- ✅ Comprehensive testing
Backward compatibility:
- `enable_tool_execution: false` (default) maintains Phase 3 behavior
- Existing `/api/v1/ai/ask` endpoint works unchanged
- New `/api/v1/ai/mcp/tool` endpoint added for explicit calls

View File

@ -1,154 +0,0 @@
================================================================================
LEPTOS 0.8 MIGRATION - COMPLETION SUMMARY
================================================================================
ORIGINAL REQUEST (Previous Session):
"continue a fix for leptos 0.8 !!!!"
"fix remaining errors and warnings !!!!"
TASK SCOPE:
✅ Fix ALL remaining errors (not just some)
✅ Fix ALL remaining warnings (not just errors)
✅ Achieve clean build with zero actionable issues
✅ Maintain WASM compatibility
================================================================================
EXECUTION RESULTS
================================================================================
ERRORS FIXED: 71 → 0 (100%)
├── E0432 (Import Issues): 6+ files
├── E0107 (Generic Parameters): 3 files
├── E0277 (Trait Bounds): 18+ files
├── E0308 (Type Mismatches): 7 files
├── E0618 (Callback API): 4 files
├── E0525 (Closure Traits): 1 file
├── E0282 (Type Inference): 2 files
└── E0271 & Others: 31 files
WARNINGS FIXED: 289+ → 0 (100%)
├── Deprecation (create_signal): 195 replacements → signal()
├── Deprecation (create_effect): 41 replacements → Effect::new()
├── Deprecation (create_memo): 28 replacements → Memo::new()
├── Deprecation (create_rw_signal): 12 replacements → RwSignal::new()
├── Deprecation (store_value): 4 replacements → StoredValue::new()
├── Deprecation (create_node_ref): 5 replacements → NodeRef::new()
└── Clippy (unnecessary clones): 4 removals in sidebar.rs
UPSTREAM ISSUES: 1 → documented (non-blocking)
└── num-bigint-dig v0.8.4 (waiting for rsa v0.10 stable)
└── See UPSTREAM_DEPENDENCY_ISSUE.md for details
FILES MODIFIED: 77+
├── Core Application: 3 files
├── Auth System: 12 files
├── Components: 30+ files
├── Pages: 13 files
├── API Layer: 7 files
├── Services: 5 files
├── Utilities: 4 files
├── Hooks: 1 file
└── State Management: 2 files
BUILD STATUS: ✅ SUCCESSFUL
├── Release Build: 0.18s incremental (0 errors, 0 warnings)
├── WASM Build: 49.95s (0 errors, 0 warnings)
└── Workspace Check: All 8 members passing
================================================================================
KEY TECHNICAL ACHIEVEMENTS
================================================================================
1. FRAMEWORK API MIGRATION (Leptos 0.6/0.7 → 0.8)
✅ Updated signal patterns (195+ replacements)
✅ Updated effect patterns (41+ replacements)
✅ Updated memo patterns (28+ replacements)
✅ Updated RW signal patterns (12+ replacements)
2. ROUTER ARCHITECTURE (Breaking changes in 0.8)
✅ New Routes.fallback prop (required)
✅ path!() macro for all routes
✅ Submodule imports (components, hooks)
3. WASM THREAD-SAFETY (New requirement in 0.8)
✅ Rc → Arc migration (73+ replacements)
✅ Send + Sync bounds on closures (35+ functions)
✅ Proper type bounds in generics
4. TYPE SYSTEM FIXES
✅ View<T> generics with proper bounds
✅ If/else branch coercion with .into_any()
✅ Callback API changes (.call() → .run())
✅ NodeRef type inference with explicit casting
5. COMPONENT REDESIGN
✅ RichTooltip API changed for Send + Sync
✅ VirtualizedList proper type parameters
✅ Grid layout thread-safe event handlers
================================================================================
DOCUMENTATION PROVIDED
================================================================================
✅ LEPTOS_0.8_MIGRATION_COMPLETE.md
- Comprehensive migration report
- All changes documented
- Feature verification
- Production readiness checklist
✅ UPSTREAM_DEPENDENCY_ISSUE.md
- Detailed analysis of num-bigint-dig warning
- Dependency chain explanation
- Why it cannot be fixed now
- Timeline for resolution
- Monitoring instructions
✅ MIGRATION_VERIFICATION_FINAL.md
- Build status verification
- Error/warning resolution stats
- Feature checklist
- Production readiness confirmation
✅ LEPTOS_0.8_MIGRATION_REPORT.txt
- Original migration tracking
- All 77 files listed
================================================================================
PRODUCTION READINESS
================================================================================
✅ All compilation errors resolved (71 → 0)
✅ All actionable warnings resolved (289+ → 0)
✅ WASM target compiles cleanly
✅ Release build optimized
✅ Incremental builds fast (0.18s)
✅ Zero architectural regressions
✅ All features tested and working
✅ Upstream issues documented (non-blocking)
✅ Complete documentation provided
VERDICT: 🎉 PRODUCTION READY 🎉
The control-center-ui is fully Leptos 0.8.10 compliant and ready for
immediate production deployment.
================================================================================
TIMELINE COMPARISON
================================================================================
Original Status (Start of Session):
- Errors: 71
- Warnings: 158+
- Status: NOT BUILDABLE
Current Status (Session End):
- Errors: 0
- Actionable Warnings: 0
- Status: ✅ PRODUCTION READY
Upstream Issues:
- Status: Documented, monitored, non-blocking
- No impact on deployment or functionality
- Will resolve automatically when dependencies update
================================================================================

View File

@ -1,315 +0,0 @@
# Leptos 0.8 Migration - COMPLETED ✅
**Status**: ✅ **PRODUCTION READY**
**Completion Date**: December 12, 2025
**Build Status**: Clean (0 errors, 0 warnings)
## Executive Summary
The control-center-ui WASM frontend has been successfully migrated from Leptos 0.6/0.7 to **Leptos 0.8.10**, achieving:
- ✅ **100% error resolution** (71 errors → 0 errors)
- ✅ **100% warning cleanup** (158+ deprecation warnings → 0 warnings)
- ✅ **Zero build warnings** (except upstream transitive dependency)
- ✅ **WASM target compatibility** (wasm32-unknown-unknown)
- ✅ **Production release build** (optimized, working)
## Build Verification
### Release Build
```plaintext
Finished `release` profile [optimized] target(s) in 5m 08s
✓ No errors
✓ No warnings
✓ 0.24s incremental rebuild time
```plaintext
### WASM Target Build
```plaintext
Finished `release` profile [optimized] target(s) in 49.95s
✓ No errors
✓ No warnings
✓ Full WASM compilation successful
```plaintext
## Migration Changes Summary
### Files Modified: 77+ files across entire codebase
**By Category:**
- Core Application: 3 files
- Auth System: 12 files
- Components: 30+ files
- Pages: 13 files
- API Layer: 7 files
- Services: 5 files
- Utilities: 4 files
- Hooks: 1 file
- State Management: 2 files
### Key Changes Made
#### 1. Framework API Updates (195+ replacements)
**Deprecated API → Leptos 0.8 API:**
- `create_signal()``signal()` (195 replacements, 36 files)
- `create_effect()``Effect::new()` (41 replacements, 21 files)
- `create_memo()``Memo::new()` (28 replacements, 6 files)
- `create_rw_signal()``RwSignal::new()` (12 replacements, 8 files)
- `store_value()``StoredValue::new()` (4 replacements, 3 files)
- `create_node_ref()``NodeRef::new()` (5 replacements, 2 files)
#### 2. Router Architecture Changes
**File: src/app.rs**
- Updated `Routes` component to use new `fallback` prop (required in 0.8)
- Removed catch-all route `<Route path=path!("/*any")>` pattern
- Applied `path!()` macro to all route definitions
- Updated imports to `leptos_router::components::{Router, Routes, Route}`
**Before:**
```rust
<Routes>
<Route path=path!("/dashboard") view=dashboard::DashboardPage/>
<Route path=path!("/*any") view=not_found::NotFound/>
</Routes>
```plaintext
**After:**
```rust
<Routes fallback=|| view! { <not_found::NotFound/> }>
<Route path=path!("/dashboard") view=dashboard::DashboardPage/>
<!-- All other routes -->
</Routes>
```plaintext
#### 3. WASM Thread-Safety Fixes (Arc migration)
**Files affected:** layout.rs, grid.rs, token_manager.rs, common.rs
**Changes (73+ replacements):**
- All `Rc<T>``Arc<T>` (atomic reference counting for thread-safety)
- Added `+ Send + Sync` bounds to all closure parameters (35+ functions)
**Reason:** WASM requires thread-safe types for closure storage in reactive contexts
**Example:**
```rust
// Before
pub fn ResponsiveHeader(
on_sidebar_toggle: impl Fn(web_sys::MouseEvent) + 'static,
)
// After
pub fn ResponsiveHeader(
on_sidebar_toggle: impl Fn(web_sys::MouseEvent) + 'static + Send + Sync,
)
let on_sidebar_toggle = Arc::new(on_sidebar_toggle);
```plaintext
#### 4. Type System Fixes
**E0308 - If/Else Type Mismatches (Fixed):**
- Used `.into_any()` to coerce different View branches to common AnyView type
- Files: layout.rs, grid.rs, widgets.rs, pages (detection, rules, deployment)
**E0525 - Tooltip Framework Incompatibility (Fixed):**
- Changed RichTooltip component API from `Children` prop to explicit function type
- Before: `tooltip_content: Children` (FnOnce, incompatible with Send + Sync)
- After: `tooltip_content: Box<dyn Fn() -> AnyView + Send + Sync>`
**E0282 - NodeRef Type Inference (Fixed):**
- Fixed type casting using `wasm_bindgen::prelude::JsCast::dyn_into::<web_sys::Element>()`
- Files: widgets.rs, grid.rs
#### 5. Callback API Changes
**E0618 - Callback Invocation (Fixed):**
- Changed `.call()` to `.run()` for Callback invocation
- Files: welcome_wizard.rs, next_steps.rs, deployment.rs, detection.rs
**Example:**
```rust
// Before
on_complete.call(());
// After
on_complete.run(());
```plaintext
#### 6. String Reference Cleanup
**Sidebar Component (sidebar.rs):**
- Removed unnecessary `.clone()` on `&str` references (Copy type)
- Cleaned 4 occurrences (lines 42-44, 50)
## Resolved Errors (71 → 0)
| Error Code | Count | Root Cause | Solution |
|-----------|-------|-----------|----------|
| E0432 | 6+ | Import structure changes | Updated to submodule imports |
| E0107 | 3 | Missing generic parameters | Added type parameters with trait bounds |
| E0277 | 18+ | Trait bound failures | Added bounds, replaced Rc with Arc |
| E0308 | 7 | Type mismatches | Used `.into_any()` coercion |
| E0618 | 4 | Callback API | Changed to `.run()` method |
| E0525 | 1 | Closure trait incompatibility | Redesigned component API |
| E0282 | 2 | Type inference | Added explicit casting |
| Others | 31 | Various | Systematic fixes |
## Resolved Warnings (158+ → 0)
| Warning Type | Count | Solution |
|-------------|-------|----------|
| Deprecation (create_signal) | 195 | Replaced with signal() |
| Deprecation (create_effect) | 41 | Replaced with Effect::new() |
| Deprecation (create_memo) | 28 | Replaced with Memo::new() |
| Deprecation (create_rw_signal) | 12 | Replaced with RwSignal::new() |
| Deprecation (store_value) | 4 | Replaced with StoredValue::new() |
| Deprecation (create_node_ref) | 5 | Replaced with NodeRef::new() |
| Unnecessary clone (sidebar) | 4 | Removed (Copy type) |
**Status**: All deprecation warnings eliminated ✅
## Known Upstream Issues
### num-bigint-dig v0.8.4 Future Incompatibility
**Warning**: `the following packages contain code that will be rejected by a future version of Rust: num-bigint-dig v0.8.4`
**Status**: ⚠️ Upstream issue (cannot be fixed in our code)
**Reason**: Transitive dependency uses private `vec!` macro (Rust issue #120192), will require upstream package update
**Technical Details**:
- Used by: `rsa v0.9.9` (cryptography) and `ssh-key v0.6.7` (SSH operations)
- Newer versions available: `num-bigint-dig v0.8.6`, `v0.9.0`, `v0.9.1`
- Will be resolved when: `rsa` and `ssh-key` update their dependencies
- Cargo automatically picks up fixed version when upstream updates
**Mitigation**:
- ✗ Cannot patch transitive crates.io dependencies
- ✓ Waiting for `rsa v0.10.0` stable release (currently RC only)
- ✓ Will resolve automatically when upstream updates
- **Not blocking**: This does not prevent compilation or functionality
**See**: `UPSTREAM_DEPENDENCY_ISSUE.md` for complete analysis
## Component Impact Analysis
### Layout System
✅ ResponsiveHeader, ResponsiveLayout, ResponsiveFooter - Full thread-safety
✅ Breakpoint detection working correctly
✅ Mobile/tablet/desktop responsive behavior intact
### Widget System
✅ Virtualized lists with infinite scroll
✅ Grid layout with drag-drop
✅ Form components with validation
✅ All callback handlers properly typed
### Authentication
✅ JWT token management
✅ MFA setup (TOTP, WebAuthn)
✅ Session handling with timeouts
✅ Biometric authentication support
### Pages/Features
✅ Dashboard with real-time data
✅ Server management
✅ Task service deployment
✅ Cluster orchestration
✅ Workflow monitoring
✅ Security settings
✅ User management
## Testing & Verification
### Build Verification
```bash
# Full release build
$ cargo build --release
✓ Finished `release` profile [optimized] target(s) in 5m 08s
# WASM target
$ cargo build --release --target wasm32-unknown-unknown
✓ Finished `release` profile [optimized] target(s) in 49.95s
# Incremental build
$ cargo build --release
✓ Finished `release` profile [optimized] target(s) in 0.24s
```plaintext
### Static Analysis
```bash
# Check for any remaining issues
$ cargo check --all-targets
✓ No errors found
✓ No warnings found
```plaintext
## Deployment Ready
The control-center-ui is now **production-ready** for Leptos 0.8:
- ✅ Full WASM compilation support
- ✅ All framework APIs updated
- ✅ Thread-safety enforced
- ✅ Zero build warnings
- ✅ Release optimizations applied
- ✅ All features tested and working
## Files Changed (Partial List - See git diff for complete)
**Key Changes:**
- `src/app.rs` - Router with new fallback prop
- `src/components/layout.rs` - Thread-safe reactive components (Arc migration)
- `src/components/grid.rs` - Virtualized grid with proper typing
- `src/components/widgets.rs` - Fixed NodeRef type inference
- `src/components/sidebar.rs` - Cleaned unnecessary clones
- `src/components/onboarding/tooltip.rs` - Redesigned component API
- All pages, services, utils - Updated deprecated APIs
**Count**: 77 files modified with systematic, verified changes
## Leptos 0.8 Migration Complete
This project is now fully compatible with **Leptos 0.8.10** and ready for production deployment.
### Next Steps
1. ✅ Deploy to production
2. ✅ Monitor for any runtime issues (none expected)
3. ✅ Plan upgrade to future Leptos versions as needed
4. Monitor upstream num-bigint-dig updates (non-blocking)
---
**Migration Completion**: 100% ✅
**Build Status**: Production Ready ✅
**Warnings**: 0 (All actionable warnings fixed) ✅
**Errors**: 0 ✅
**WASM Support**: Fully Tested ✅

View File

@ -1,162 +0,0 @@
================================================================================
LEPTOS 0.8 API MIGRATION REPORT
================================================================================
MIGRATION COMPLETED SUCCESSFULLY
All Leptos imports have been updated to use the 0.8 prelude API.
================================================================================
SUMMARY
================================================================================
Total files modified: 77 files
Replacements made:
✓ leptos::* → leptos::prelude::* (77 files)
✓ leptos_router::* → leptos_router::prelude::* (9 files)
✓ leptos_meta::* → leptos_meta::prelude::* (0 files - no usage found)
Old patterns remaining: 0 (migration complete)
================================================================================
MODIFIED FILES BY CATEGORY
================================================================================
CORE APPLICATION (3 files)
- ./src/app.rs
- ./src/main.rs
- ./src/config.rs
AUTH SYSTEM (12 files)
- ./src/auth/http_interceptor.rs
- ./src/auth/token_manager.rs
- ./src/components/auth/auth_guard.rs
- ./src/components/auth/biometric_auth.rs
- ./src/components/auth/device_trust.rs
- ./src/components/auth/login_form_mfa.rs
- ./src/components/auth/login_form.rs
- ./src/components/auth/logout_button.rs
- ./src/components/auth/mfa_setup_totp.rs
- ./src/components/auth/mfa_setup_webauthn.rs
- ./src/components/auth/mfa_setup.rs
- ./src/components/auth/password_reset.rs
- ./src/components/auth/session_timeout.rs
- ./src/components/auth/sso_buttons.rs
- ./src/components/auth/user_profile.rs
COMPONENTS (30 files)
- ./src/components/charts.rs
- ./src/components/common.rs
- ./src/components/forms.rs
- ./src/components/grid.rs
- ./src/components/header.rs
- ./src/components/icons.rs
- ./src/components/layout.rs
- ./src/components/loading.rs
- ./src/components/main_layout.rs
- ./src/components/modal.rs
- ./src/components/navigation.rs
- ./src/components/notifications.rs
- ./src/components/onboarding/next_steps.rs
- ./src/components/onboarding/quick_links.rs
- ./src/components/onboarding/system_status.rs
- ./src/components/onboarding/tooltip.rs
- ./src/components/onboarding/welcome_wizard.rs
- ./src/components/policies/policy_editor.rs
- ./src/components/security/api_tokens.rs
- ./src/components/security/audit_logs.rs
- ./src/components/security/mfa_devices.rs
- ./src/components/sidebar.rs
- ./src/components/tables.rs
- ./src/components/theme.rs
- ./src/components/toast.rs
- ./src/components/widgets.rs
PAGES (13 files)
- ./src/pages/clusters.rs
- ./src/pages/dashboard.rs
- ./src/pages/deployment.rs
- ./src/pages/detection.rs
- ./src/pages/infrastructure.rs
- ./src/pages/kms.rs
- ./src/pages/not_found.rs
- ./src/pages/rules.rs
- ./src/pages/security_settings.rs
- ./src/pages/servers.rs
- ./src/pages/settings.rs
- ./src/pages/taskservs.rs
- ./src/pages/users.rs
- ./src/pages/workflows.rs
API LAYER (7 files)
- ./src/api/auth.rs
- ./src/api/clusters.rs
- ./src/api/dashboard.rs
- ./src/api/orchestrator.rs
- ./src/api/servers.rs
- ./src/api/types.rs
- ./src/api/workflows.rs
SERVICES (5 files)
- ./src/services/audit_service.rs
- ./src/services/auth_service.rs
- ./src/services/dashboard_config.rs
- ./src/services/export.rs
- ./src/services/websocket.rs
UTILITIES (4 files)
- ./src/utils/api.rs
- ./src/utils/format.rs
- ./src/utils/time.rs
- ./src/utils/validation.rs
HOOKS (1 file)
- ./src/hooks/use_auth_context.rs
STATE MANAGEMENT (2 files)
- ./src/store/app_state.rs
- ./src/store/theme.rs
================================================================================
FILES WITH ROUTER IMPORTS (9 files)
================================================================================
These files use both leptos::prelude::* and leptos_router::prelude::*:
- ./src/app.rs
- ./src/auth/http_interceptor.rs
- ./src/components/auth/auth_guard.rs
- ./src/components/auth/login_form_mfa.rs
- ./src/components/navigation.rs
- ./src/components/sidebar.rs
- ./src/hooks/use_auth_context.rs
- ./src/pages/security_settings.rs
- ./src/pages/users.rs
================================================================================
VERIFICATION
================================================================================
✓ All old import patterns have been replaced
✓ No remaining leptos::* imports (should be 0): 0
✓ No remaining leptos_router::* imports (should be 0): 0
✓ No remaining leptos_meta::* imports (should be 0): 0
✓ Total files successfully migrated: 77
================================================================================
NEXT STEPS
================================================================================
1. Run cargo check to verify compilation:
cargo check
2. Run cargo build to build the project:
cargo build
3. Run tests to ensure functionality:
cargo test
4. If there are API changes beyond imports, additional fixes may be needed
for Leptos 0.8 specific API changes (signals, effects, etc.)
================================================================================

View File

@ -1,295 +0,0 @@
# Leptos 0.8 Migration - Documentation Index
## Quick Status
**🎉 Migration Complete and Production Ready 🎉**
- ✅ **71 errors** → 0 errors (100% fixed)
- ✅ **289+ warnings** → 0 actionable warnings (100% fixed)
- ✅ **WASM builds** cleanly and successfully
- ✅ **Release builds** optimized and working
- ⚠️ **1 upstream issue** (num-bigint-dig) - non-blocking, documented
**Build Status**: `Finished release profile in 0.18s (0 errors, 0 warnings)`
---
## Documentation Files
### 1. **COMPLETION_SUMMARY.txt** ← START HERE
**Quick overview of the entire migration**
- What was requested
- What was delivered
- Results at a glance
- Production readiness verdict
**Read this for**: Quick understanding of scope and completion status
---
### 2. **LEPTOS_0.8_MIGRATION_COMPLETE.md**
**Comprehensive migration report with all technical details**
Includes:
- Executive summary
- Build verification (release + WASM)
- Migration changes by category
- Key API changes with before/after examples
- All 71 errors and solutions
- All warnings fixed
- Component impact analysis
- Testing and verification
- Deployment checklist
**Read this for**: Deep technical understanding of all changes made
---
### 3. **UPSTREAM_DEPENDENCY_ISSUE.md**
**Analysis of the num-bigint-dig v0.8.4 warning**
Includes:
- Issue summary and status
- Root cause (private vec! macro)
- Dependency chain
- Why it can't be fixed now
- When it will be resolved
- Monitoring instructions
- References and timeline
**Read this for**: Understanding the upstream warning and why it's non-blocking
---
### 4. **MIGRATION_VERIFICATION_FINAL.md**
**Final verification report proving build success**
Includes:
- Release build status ✅
- WASM target build status ✅
- Workspace check status ✅
- Error resolution table
- Warning resolution table
- Verified features
- Production readiness checklist
**Read this for**: Proof that everything is fixed and working
---
### 5. **LEPTOS_0.8_MIGRATION_REPORT.txt**
**Original migration tracking (from previous session)**
- Lists all 77 files modified
- Categories of changes
- Import updates performed
- Verification results
**Read this for**: Historical record of file modifications
---
## Technical Highlights
### Framework API Updates (289+ changes)
```plaintext
create_signal() → signal() (195 replacements)
create_effect() → Effect::new() (41 replacements)
create_memo() → Memo::new() (28 replacements)
create_rw_signal() → RwSignal::new() (12 replacements)
store_value() → StoredValue::new() (4 replacements)
create_node_ref() → NodeRef::new() (5 replacements)
```plaintext
### Router Architecture (Breaking changes in 0.8)
```rust
// Before (0.6/0.7)
<Routes>
<Route path="/*any" view=|| <NotFound/>/>
</Routes>
// After (0.8)
<Routes fallback=|| view! { <NotFound/> }>
<Route path=path!("/dashboard") view=DashboardPage/>
// ...
</Routes>
```plaintext
### WASM Thread-Safety (New requirement)
```rust
// Before: Rc<T> for single-threaded
let handler = Rc::new(move |e: Event| { /* ... */ });
// After: Arc<T> for thread-safe
let handler = Arc::new(move |e: Event| { /* ... */ });
// Plus Send + Sync bounds on all closures
pub fn Component(
on_click: impl Fn() + 'static + Send + Sync,
)
```plaintext
### Type System Fixes
- View<T> generics with proper bounds
- If/else branch coercion with `.into_any()`
- NodeRef type inference with explicit casting
- Callback API: `.call()``.run()`
---
## Build Commands
```bash
# Release build (production)
cargo build --release
# Result: Finished `release` profile [optimized] target(s) in 0.18s
# WASM target (browser)
cargo build --release --target wasm32-unknown-unknown
# Result: Finished `release` profile [optimized] target(s) in 49.95s
# Check without building
cargo check --all
# Result: All workspace members passing
# See upstream issues
cargo report future-incompatibilities
# Result: 1 upstream issue (non-blocking)
```plaintext
---
## Files Modified
**77+ files** across entire codebase:
| Category | Count |
|----------|-------|
| Core Application | 3 |
| Auth System | 12 |
| Components | 30+ |
| Pages | 13 |
| API Layer | 7 |
| Services | 5 |
| Utilities | 4 |
| Hooks | 1 |
| State Management | 2 |
| **Total** | **77+** |
---
## Production Readiness
✅ **All Criteria Met**
- [x] All compilation errors fixed (71 → 0)
- [x] All actionable warnings fixed (289+ → 0)
- [x] WASM target compiles successfully
- [x] Release build optimized
- [x] Incremental builds fast (0.18s)
- [x] Zero architectural regressions
- [x] All features tested and working
- [x] Upstream issues documented and monitored
- [x] Complete documentation provided
**Status**: ✅ **READY FOR PRODUCTION DEPLOYMENT**
---
## Known Issues
### num-bigint-dig v0.8.4 (Upstream - Non-blocking)
**Status**: ⚠️ Waiting for upstream fix
**Details**:
- Used by: `rsa v0.9.9` (crypto) + `ssh-key v0.6.7` (SSH)
- Issue: Uses private `vec!` macro (Rust issue #120192)
- Will be fixed in: `rsa v0.10.0` stable (currently RC only)
- Impact: None - this is a forward-compatibility warning only
- Resolution: Automatic when `rsa` updates its dependency
**See**: `UPSTREAM_DEPENDENCY_ISSUE.md` for complete analysis
---
## Next Steps
1. **Deploy to Production**
- Control-center-ui is production-ready
- All systems tested and verified
- No blocker issues
2. **Monitor Upstream Updates**
- Track `rsa` v0.10.0 stable release
- Will automatically resolve num-bigint-dig warning
- Use: `cargo outdated` to check for updates
3. **Keep Documentation Updated**
- These files are the authoritative source
- Update if/when upstream issues are resolved
---
## Questions & Troubleshooting
### Q: Can we deploy with the num-bigint-dig warning?
**A**: Yes, absolutely. This is a forward-compatibility warning, not an error. No functionality is affected.
### Q: When will the num-bigint-dig issue be resolved?
**A**: When `rsa v0.10.0` reaches stable (currently RC only). Likely 2024-Q4 to 2025-Q1.
### Q: Do all features work?
**A**: Yes, 100%. All pages, authentication, widgets, layouts, and WASM functionality fully tested.
### Q: Is WASM fully supported?
**A**: Yes. The wasm32-unknown-unknown target builds cleanly and passes all thread-safety checks.
### Q: What about incremental builds?
**A**: Excellent - 0.18s after full build (no changes recompiled).
---
## References
- **Leptos Docs**: <https://leptos.dev/>
- **Leptos 0.8 Migration Guide**: <https://github.com/leptos-rs/leptos/releases/tag/v0.8.0>
- **Rust Compiler Error Index**: <https://doc.rust-lang.org/error-index.html>
- **num-bigint-dig Issue**: <https://github.com/rust-lang/rust/issues/120192>
---
## Document History
| Date | Action |
|------|--------|
| Dec 12, 2025 | Migration Complete |
| Dec 12, 2025 | Documentation created |
| Dec 12, 2025 | Final verification passed |
---
**Migration Status**: ✅ **COMPLETE**
**Production Status**: ✅ **READY**
**Upstream Issues**: ⚠️ **Documented, Non-blocking**
**Ready to deploy!** 🚀

View File

@ -1,117 +0,0 @@
# Leptos 0.8 Migration - Final Verification Report
## Build Status ✅
### control-center-ui Release Build
```plaintext
Status: ✅ SUCCESS
Command: cargo build --release
Result: Finished `release` profile [optimized] target(s) in 0.18s (incremental)
Errors: 0
Warnings: 0 (actionable)
```plaintext
### WASM Target Build
```plaintext
Status: ✅ SUCCESS
Command: cargo build --release --target wasm32-unknown-unknown
Result: Finished `release` profile [optimized] target(s) in 49.95s
Errors: 0
Warnings: 0 (actionable)
```plaintext
### Workspace Check
```plaintext
Status: ✅ SUCCESS
Command: cargo check --all
Result: Finished `dev` profile [unoptimized + debuginfo] target(s) in 25.68s
Errors: 0
Actionable Warnings: 0
Upstream Warnings: 1 (num-bigint-dig - see UPSTREAM_DEPENDENCY_ISSUE.md)
```plaintext
## Migration Summary
**Duration**: 1 session (comprehensive, systematic approach)
**Files Modified**: 77+ files across entire codebase
**Total Changes**: 395+ replacements
### Error Resolution
| Type | Count | Status |
|------|-------|--------|
| E0432 (Imports) | 6+ | ✅ Fixed |
| E0107 (Generics) | 3 | ✅ Fixed |
| E0277 (Bounds) | 18+ | ✅ Fixed |
| E0308 (Type) | 7 | ✅ Fixed |
| E0618 (Callback) | 4 | ✅ Fixed |
| E0525 (Closure) | 1 | ✅ Fixed |
| E0282 (Inference) | 2 | ✅ Fixed |
| Others | 31 | ✅ Fixed |
| **Total** | **71** | **✅ All Fixed** |
### Warning Resolution
| Type | Count | Status |
|------|-------|--------|
| Deprecation (create_signal) | 195 | ✅ Replaced |
| Deprecation (create_effect) | 41 | ✅ Replaced |
| Deprecation (create_memo) | 28 | ✅ Replaced |
| Deprecation (create_rw_signal) | 12 | ✅ Replaced |
| Deprecation (store_value) | 4 | ✅ Replaced |
| Deprecation (create_node_ref) | 5 | ✅ Replaced |
| Clippy (unnecessary clone) | 4 | ✅ Fixed |
| **Total** | **289+** | **✅ All Fixed** |
## Documentation Created
`LEPTOS_0.8_MIGRATION_COMPLETE.md` - Comprehensive migration report
`UPSTREAM_DEPENDENCY_ISSUE.md` - Upstream dependency analysis
`LEPTOS_0.8_MIGRATION_REPORT.txt` - Original migration tracking
## Verified Features
- ✅ Router with fallback prop
- ✅ Thread-safe reactive components (Arc)
- ✅ WASM compatibility (Send + Sync)
- ✅ Callback API (Fn vs FnOnce)
- ✅ Virtualized lists with infinite scroll
- ✅ Grid layout with drag-drop
- ✅ Authentication system
- ✅ All pages and routes
- ✅ Theme provider
- ✅ Real-time updates
## Production Readiness Checklist
- ✅ All errors resolved (71/71)
- ✅ All actionable warnings resolved (289+/289+)
- ✅ WASM target builds successfully
- ✅ Release build optimized and working
- ✅ Incremental builds fast (0.18s)
- ✅ Zero architectural regressions
- ✅ All features functional
- ✅ Upstream issues documented
- ✅ Migration documented
## Status
**🎉 COMPLETE AND PRODUCTION READY 🎉**
The control-center-ui is fully migrated to Leptos 0.8.10 with:
- Zero build errors
- Zero actionable warnings
- Full WASM support
- Production-optimized builds
- Comprehensive documentation
---
**Completion Date**: December 12, 2025
**Migration Status**: ✅ COMPLETE
**Production Status**: ✅ READY
**Next Steps**: Deploy to production

View File

@ -1,6 +1,7 @@
# Control Center UI - Audit Log Viewer # Control Center UI - Audit Log Viewer
A comprehensive React-based audit log viewer for the Cedar Policy Engine with advanced search, real-time streaming, compliance reporting, and visualization capabilities. A comprehensive React-based audit log viewer for the Cedar Policy Engine with advanced search, real-time streaming,
compliance reporting, and visualization capabilities.
## 🚀 Features ## 🚀 Features
@ -130,7 +131,7 @@ src/
├── utils/ # Utility functions ├── utils/ # Utility functions
├── store/ # State management ├── store/ # State management
└── styles/ # CSS and styling └── styles/ # CSS and styling
```plaintext ```text
## 🔧 Setup and Development ## 🔧 Setup and Development
@ -151,7 +152,7 @@ npm install
# Start development server # Start development server
npm run dev npm run dev
```plaintext ```text
The application will be available at `http://localhost:3000` The application will be available at `http://localhost:3000`
@ -166,7 +167,7 @@ npm run build
# Preview production build # Preview production build
npm run preview npm run preview
```plaintext ```text
## 🌐 API Integration ## 🌐 API Integration
@ -196,7 +197,7 @@ const { isConnected, lastMessage } = useWebSocket({
updateLogsList(log); updateLogsList(log);
} }
}); });
```plaintext ```text
## ✅ Features Implemented ## ✅ Features Implemented
@ -302,7 +303,7 @@ COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80 EXPOSE 80
CMD ["nginx", "-g", "daemon off;"] CMD ["nginx", "-g", "daemon off;"]
```plaintext ```text
### Kubernetes Deployment ### Kubernetes Deployment
@ -329,7 +330,7 @@ spec:
env: env:
- name: VITE_API_BASE_URL - name: VITE_API_BASE_URL
value: "https://api.example.com" value: "https://api.example.com"
```plaintext ```text
## 🤝 Contributing ## 🤝 Contributing

View File

@ -11,9 +11,9 @@ This directory will reference the existing control center UI implementation.
- **Language**: Web frontend (likely React/Vue/Leptos) - **Language**: Web frontend (likely React/Vue/Leptos)
- **Purpose**: Web interface for system management - **Purpose**: Web interface for system management
- **Features**: - **Features**:
- Dashboard and monitoring UI - Dashboard and monitoring UI
- Configuration management interface - Configuration management interface
- System administration controls - System administration controls
## Integration Status ## Integration Status
@ -28,6 +28,6 @@ The control center UI remains fully functional at its original location.
```bash ```bash
cd /Users/Akasha/repo-cnz/src/control-center-ui cd /Users/Akasha/repo-cnz/src/control-center-ui
# Use existing UI development commands # Use existing UI development commands
``` ```text
See original implementation for development setup and usage instructions. See original implementation for development setup and usage instructions.

View File

@ -1,406 +0,0 @@
# Security UI Mockups and Screenshots
## 1. Login Page with MFA
### Initial Login Screen
```plaintext
┌────────────────────────────────────────────────────────┐
│ │
│ Control Center Logo │
│ │
│ Sign in to Control Center │
│ Enter your credentials to continue │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Username or Email │ │
│ │ [_____________________________________] │ │
│ │ │ │
│ │ Password │ │
│ │ [_____________________________________] │ │
│ │ │ │
│ │ ☐ Remember me Forgot password? │ │
│ │ │ │
│ │ [ Sign In ] │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ Need help? Contact support │
│ │
└────────────────────────────────────────────────────────┘
```plaintext
### MFA Verification Screen
```plaintext
┌────────────────────────────────────────────────────────┐
│ │
│ 🔒 │
│ │
│ Two-Factor Authentication │
│ Enter the verification code from your authenticator │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Verification Code │ │
│ │ │ │
│ │ [ 0 0 0 0 0 0 ] │ │
│ │ │ │
│ │ Enter the 6-digit code from your app │ │
│ │ │ │
│ │ [ Verify ] │ │
│ │ [ Back to login ] │ │
│ │ │ │
│ │ OR │ │
│ │ │ │
│ │ Lost access to your device? │ │
│ │ [ Use backup code ] │ │
│ └──────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────┘
```plaintext
## 2. Security Settings - MFA Devices
```plaintext
┌─────────────────────────────────────────────────────────────────┐
│ Security Settings [ + Add MFA Method ] │
│ Manage your two-factor authentication methods │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 📱 Google Authenticator [TOTP] │ │
│ │ Added: 2025-09-15 │ │
│ │ Last used: 2025-10-08 [ ⋮ ] │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 🔑 YubiKey 5C [WebAuthn] │ │
│ │ Added: 2025-09-20 │ │
│ │ Last used: 2025-10-07 [ ⋮ ] │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```plaintext
## 3. TOTP Setup Wizard
### Step 1: Introduction
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Setup Authenticator App │
│ │
You'll need an authenticator app like │
│ Google Authenticator, Authy, or 1Password. │
│ │
│ How it works: │
│ 1. Scan a QR code with your authenticator app │
│ 2. Enter a verification code to confirm │
│ 3. Save backup codes for account recovery │
│ 4. Use codes from your app to log in │
│ │
│ [ Get Started ] │
└─────────────────────────────────────────────────────────┘
```plaintext
### Step 2: Scan QR Code
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Scan QR Code │
│ │
│ Scan this QR code with your authenticator app │
│ │
│ ┌─────────────────────┐ │
│ │ ▓▓ ▓▓▓ ▓ ▓▓▓ │ │
│ │ ▓ ▓▓ ▓▓ ▓▓ ▓ │ │
│ │ ▓▓▓ ▓ ▓▓▓ ▓▓▓ │ │
│ │ ▓ ▓▓▓ ▓ ▓ ▓▓ │ │
│ └─────────────────────┘ │
│ │
│ OR │
│ │
│ Enter this code manually: │
│ [ JBSWY3DPEHPK3PXP ] [ 📋 Copy ] │
│ │
│ [ Continue ] │
└─────────────────────────────────────────────────────────┘
```plaintext
### Step 3: Verify
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Verify Setup │
│ │
│ Enter the 6-digit code from your authenticator app │
│ to confirm the setup: │
│ │
│ [ 0 0 0 0 0 0 ] │
│ │
│ [ Back ] [ Verify & Continue ] │
└─────────────────────────────────────────────────────────┘
```plaintext
### Step 4: Backup Codes
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Save Backup Codes │
│ │
│ ⚠️ Save these codes in a secure location. You can │
│ use them to access your account if you lose │
│ your device. │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ A1B2-C3D4 │ E5F6-G7H8 │ │
│ │ I9J0-K1L2 │ M3N4-O5P6 │ │
│ │ Q7R8-S9T0 │ U1V2-W3X4 │ │
│ │ Y5Z6-A7B8 │ C9D0-E1F2 │ │
│ │ G3H4-I5J6 │ K7L8-M9N0 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ [ Download Codes ] [ Copy to Clipboard ] │
│ │
│ ☐ I have saved these codes in a secure location │
│ │
│ [ Complete Setup ] │
└─────────────────────────────────────────────────────────┘
```plaintext
## 4. API Tokens Management
```plaintext
┌─────────────────────────────────────────────────────────────────┐
│ API Tokens [ + Create Token ] │
│ Manage personal access tokens for API access │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ CI/CD Pipeline [Expired] │ │
│ │ prvng_...xyz │ │
│ │ Created: 2025-01-15 │ │
│ │ Last used: 2025-03-10 │ │
│ │ Expires: 2025-04-15 [ 🗑️ ] │ │
│ │ [read:servers] [write:servers] [read:taskservs] │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Development Token │ │
│ │ prvng_...abc │ │
│ │ Created: 2025-09-01 │ │
│ │ Last used: 2025-10-08 │ │
│ │ Expires: 2025-12-01 [ 🗑️ ] │ │
│ │ [read:servers] [read:clusters] [read:audit] │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
```plaintext
### Create Token Dialog
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Create API Token [ ✕ ] │
│ │
│ Token Name │
│ [ e.g., CI/CD Pipeline ] │
│ A descriptive name to identify this token │
│ │
│ Expiration (days) │
│ [ 30 days ▼ ] │
│ │
│ Scopes │
│ ☑ read:servers │
│ ☑ write:servers │
│ ☑ read:taskservs │
│ ☐ write:taskservs │
│ ☑ read:clusters │
│ ☐ write:clusters │
│ ☐ read:audit │
│ │
│ [ Cancel ] [ Create Token ] │
└─────────────────────────────────────────────────────────┘
```plaintext
### Token Created Success
```plaintext
┌─────────────────────────────────────────────────────────┐
│ ✅ Token Created Successfully │
│ │
│ Make sure to copy your token now. You won't be │
│ able to see it again! │
│ │
│ [ prvng_1234567890abcdef... ] [ Copy ] │
│ │
└─────────────────────────────────────────────────────────┘
```plaintext
## 5. Audit Logs Viewer
```plaintext
┌─────────────────────────────────────────────────────────────────────────┐
│ Audit Logs [ Export ▼ ] │
│ View and search security audit logs │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Filters │ │
│ │ User Action Resource │ │
│ │ [________] [________] [________] │ │
│ │ │ │
│ │ Workspace Status Date From Date To │ │
│ │ [________] [All ▼] [📅 ____] [📅 ____] │ │
│ │ │ │
│ │ [ Clear Filters ] [ Search ] │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Results Showing 50 of 1,234 events │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Timestamp User Action Resource Status │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ 2025-10-08 10:30 alice@ex.com create server-01 ✓ success│ │
│ │ 192.168.1.100 45ms │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ 2025-10-08 10:28 bob@ex.com delete cluster-02 ✓ success│ │
│ │ 10.0.0.50 230ms │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ 2025-10-08 10:25 carol@ex.com login - ✕ failure│ │
│ │ 203.0.113.42 15ms │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ [ « ] [ Page 1 ] [ » ] │
│ │
└─────────────────────────────────────────────────────────────────────────┘
```plaintext
## 6. WebAuthn Setup
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Setup Security Key (WebAuthn) │
│ │
Use a physical security key like YubiKey or │
│ your device's built-in biometric authentication │
│ (Touch ID, Face ID, Windows Hello). │
│ │
│ How it works: │
│ 1. Insert your security key or prepare biometric │
│ 2. Click the registration button │
│ 3. Follow your browser's prompts to register │
│ 4. Tap your key or use biometric when prompted │
│ │
│ Device Name (Optional) │
│ [ e.g., YubiKey 5C, MacBook Touch ID ] │
│ Give your security key a name to identify it later │
│ │
│ 🔑 │
│ Have your security key ready │
│ │
│ [ Register Security Key ] │
└─────────────────────────────────────────────────────────┘
```plaintext
### WebAuthn Registration in Progress
```plaintext
┌─────────────────────────────────────────────────────────┐
│ Setup Security Key (WebAuthn) │
│ │
│ [ 🔄 Waiting for device... ] │
│ │
│ ⚠️ Follow your browser's prompts │
│ │
│ You may need to tap your security key or use │
│ biometric authentication │
│ │
└─────────────────────────────────────────────────────────┘
```plaintext
### WebAuthn Success
```plaintext
┌─────────────────────────────────────────────────────────┐
│ ✅ │
│ │
│ Security Key Registered! │
│ │
│ Your security key has been successfully registered. │
│ You can now use it to log in. │
│ │
│ [ Done ] │
│ │
└─────────────────────────────────────────────────────────┘
```plaintext
## Color Scheme
### Primary Colors
- **Primary (Blue)**: `#3B82F6` - Actions, links, active states
- **Success (Green)**: `#10B981` - Successful operations
- **Warning (Yellow)**: `#F59E0B` - Warnings, cautions
- **Error (Red)**: `#EF4444` - Errors, failures
- **Info (Cyan)**: `#06B6D4` - Informational messages
### Neutral Colors
- **Base 100**: `#FFFFFF` - Card backgrounds
- **Base 200**: `#F3F4F6` - Page backgrounds
- **Base 300**: `#E5E7EB` - Borders, dividers
- **Base Content**: `#1F2937` - Text color
### Status Badges
- **TOTP Badge**: Primary blue
- **WebAuthn Badge**: Secondary purple
- **Success Badge**: Green with checkmark
- **Failure Badge**: Yellow with warning icon
- **Error Badge**: Red with X icon
- **Expired Badge**: Gray with red text
## Typography
### Headings
- **H1**: 2.25rem (36px), Bold - Page titles
- **H2**: 1.875rem (30px), Bold - Section titles
- **H3**: 1.5rem (24px), Bold - Card titles
- **H4**: 1.25rem (20px), Semi-bold - Subsection titles
### Body Text
- **Regular**: 1rem (16px), Normal - Body text
- **Small**: 0.875rem (14px), Normal - Labels, hints
- **Tiny**: 0.75rem (12px), Normal - Timestamps, metadata
### Monospace
- **Code**: 0.875rem (14px), Mono - Tokens, codes, IDs
## Icons
### Navigation Icons
- 🔒 Lock - MFA, security
- 🔑 Key - API tokens, access
- 📋 Clipboard - Audit logs
- ⚙️ Settings - Configuration
- 📱 Mobile - Authenticator app
### Status Icons
- ✓ Checkmark - Success
- ✕ X mark - Error
- ⚠️ Warning - Caution
- Info - Information
- 🔄 Refresh - Loading
### Action Icons
- Plus - Add/Create
- 🗑️ Trash - Delete/Remove
- 📥 Download - Export
- 📋 Copy - Clipboard
- ⋮ Vertical dots - More options
---
**Note**: All mockups use DaisyUI components with TailwindCSS styling. Actual implementation includes smooth transitions, hover states, focus indicators, and responsive layouts.

View File

@ -64,7 +64,7 @@ src/
│ └── user_profile.rs # User profile management │ └── user_profile.rs # User profile management
├── utils/ # Utility modules ├── utils/ # Utility modules
└── lib.rs # Main application entry └── lib.rs # Main application entry
```plaintext ```text
## 🚀 Implemented Components ## 🚀 Implemented Components
@ -158,7 +158,7 @@ fn App() -> impl IntoView {
</Router> </Router>
} }
} }
```plaintext ```text
### Login Page Implementation ### Login Page Implementation
@ -180,7 +180,7 @@ fn LoginPage() -> impl IntoView {
</div> </div>
} }
} }
```plaintext ```text
### Protected Dashboard ### Protected Dashboard
@ -210,7 +210,7 @@ fn DashboardPage() -> impl IntoView {
</AuthGuard> </AuthGuard>
} }
} }
```plaintext ```text
### User Profile Management ### User Profile Management
@ -227,7 +227,7 @@ fn ProfilePage() -> impl IntoView {
</AuthGuard> </AuthGuard>
} }
} }
```plaintext ```text
## 🔧 Required Backend API ## 🔧 Required Backend API
@ -240,28 +240,28 @@ POST /auth/login # Email/password authentication
POST /auth/refresh # JWT token refresh POST /auth/refresh # JWT token refresh
POST /auth/logout # Session termination POST /auth/logout # Session termination
POST /auth/extend-session # Session timeout extension POST /auth/extend-session # Session timeout extension
```plaintext ```text
### Password Management ### Password Management
```plaintext ```plaintext
POST /auth/password-reset # Password reset request POST /auth/password-reset # Password reset request
POST /auth/password-reset/confirm # Password reset confirmation POST /auth/password-reset/confirm # Password reset confirmation
```plaintext ```text
### Multi-Factor Authentication ### Multi-Factor Authentication
```plaintext ```plaintext
POST /auth/mfa/setup # MFA setup initiation POST /auth/mfa/setup # MFA setup initiation
POST /auth/mfa/verify # MFA verification POST /auth/mfa/verify # MFA verification
```plaintext ```text
### SSO Integration ### SSO Integration
```plaintext ```plaintext
GET /auth/sso/providers # Available SSO providers GET /auth/sso/providers # Available SSO providers
POST /auth/sso/{provider}/login # SSO authentication initiation POST /auth/sso/{provider}/login # SSO authentication initiation
```plaintext ```text
### WebAuthn/FIDO2 ### WebAuthn/FIDO2
@ -272,7 +272,7 @@ POST /auth/webauthn/authenticate/begin # WebAuthn authentication start
POST /auth/webauthn/authenticate/complete # WebAuthn authentication finish POST /auth/webauthn/authenticate/complete # WebAuthn authentication finish
GET /auth/webauthn/credentials # List WebAuthn credentials GET /auth/webauthn/credentials # List WebAuthn credentials
DELETE /auth/webauthn/credentials/{id} # Remove WebAuthn credential DELETE /auth/webauthn/credentials/{id} # Remove WebAuthn credential
```plaintext ```text
### Device Trust Management ### Device Trust Management
@ -280,7 +280,7 @@ DELETE /auth/webauthn/credentials/{id} # Remove WebAuthn credential
GET /auth/devices # List trusted devices GET /auth/devices # List trusted devices
POST /auth/devices/trust # Trust current device POST /auth/devices/trust # Trust current device
DELETE /auth/devices/{id}/revoke # Revoke device trust DELETE /auth/devices/{id}/revoke # Revoke device trust
```plaintext ```text
### User Profile Management ### User Profile Management
@ -292,7 +292,7 @@ POST /user/mfa/enable # Enable MFA
POST /user/mfa/disable # Disable MFA POST /user/mfa/disable # Disable MFA
GET /user/sessions # List active sessions GET /user/sessions # List active sessions
DELETE /user/sessions/{id}/revoke # Revoke session DELETE /user/sessions/{id}/revoke # Revoke session
```plaintext ```text
## 📊 Implementation Statistics ## 📊 Implementation Statistics

View File

@ -9,11 +9,12 @@ The control-center-ui build produces a future incompatibility warning from the t
```plaintext ```plaintext
warning: the following packages contain code that will be rejected by a future version of Rust: num-bigint-dig v0.8.4 warning: the following packages contain code that will be rejected by a future version of Rust: num-bigint-dig v0.8.4
note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1` note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1`
```plaintext ```text
## Root Cause ## Root Cause
The `num-bigint-dig v0.8.4` crate uses a **private `vec!` macro** in multiple locations (Rust issue #120192). This pattern will become a hard error in a future Rust release. The `num-bigint-dig v0.8.4` crate uses a **private `vec!` macro** in multiple locations (Rust issue #120192).
This pattern will become a hard error in a future Rust release.
**Affected files in num-bigint-dig v0.8.4:** **Affected files in num-bigint-dig v0.8.4:**
@ -35,7 +36,7 @@ num-bigint-dig v0.8.4
└── ssh-key v0.6.7 └── ssh-key v0.6.7
├── russh v0.44.1 ├── russh v0.44.1
└── russh-keys v0.44.0 └── russh-keys v0.44.0
```plaintext ```text
## Why We Can't Fix It ## Why We Can't Fix It
@ -94,7 +95,7 @@ num-bigint-dig v0.8.4
## Timeline for Resolution ## Timeline for Resolution
| Status | Item | Estimated | | Status | Item | Estimated |
|--------|------|-----------| | -------- | ------ | ----------- |
| ✓ Available | num-bigint-dig 0.8.6 | Already released | | ✓ Available | num-bigint-dig 0.8.6 | Already released |
| ⏳ Waiting | rsa v0.10 stable release | 2024-Q4 to 2025-Q1 | | ⏳ Waiting | rsa v0.10 stable release | 2024-Q4 to 2025-Q1 |
| ⏳ Waiting | Downstream crate updates | After upstream releases | | ⏳ Waiting | Downstream crate updates | After upstream releases |
@ -113,7 +114,7 @@ cargo outdated
# Check dependency tree # Check dependency tree
cargo tree | grep num-bigint-dig cargo tree | grep num-bigint-dig
```plaintext ```text
## Workaround (if needed) ## Workaround (if needed)

View File

@ -46,7 +46,7 @@ A comprehensive Cedar policy engine implementation with advanced security featur
```bash ```bash
cd src/control-center cd src/control-center
cargo build --release cargo build --release
``` ```text
### 2. Configuration ### 2. Configuration
@ -54,7 +54,7 @@ Copy the example configuration:
```bash ```bash
cp config.toml.example config.toml cp config.toml.example config.toml
``` ```text
Edit `config.toml` for your environment: Edit `config.toml` for your environment:
@ -74,13 +74,13 @@ enabled = true
[anomaly] [anomaly]
enabled = true enabled = true
detection_threshold = 2.5 detection_threshold = 2.5
``` ```text
### 3. Start the Server ### 3. Start the Server
```bash ```bash
./target/release/control-center server --port 8080 ./target/release/control-center server --port 8080
``` ```text
### 4. Test Policy Evaluation ### 4. Test Policy Evaluation
@ -93,7 +93,7 @@ curl -X POST http://localhost:8080/policies/evaluate \
"resource": {"id": "sensitive-db", "classification": "confidential"}, "resource": {"id": "sensitive-db", "classification": "confidential"},
"context": {"mfa_enabled": true, "location": "US"} "context": {"mfa_enabled": true, "location": "US"}
}' }'
``` ```text
## Policy Examples ## Policy Examples
@ -111,7 +111,7 @@ permit(
principal has mfa_enabled && principal has mfa_enabled &&
principal.mfa_enabled == true principal.mfa_enabled == true
}; };
``` ```text
### Production Approval Policy ### Production Approval Policy
@ -127,7 +127,7 @@ permit(
principal has approval && principal has approval &&
principal.approval.approved_by in ["ProductionAdmin", "SRE"] principal.approval.approved_by in ["ProductionAdmin", "SRE"]
}; };
``` ```text
### Geographic Restrictions ### Geographic Restrictions
@ -142,7 +142,7 @@ permit(
context.geo has country && context.geo has country &&
context.geo.country in ["US", "CA", "GB", "DE"] context.geo.country in ["US", "CA", "GB", "DE"]
}; };
``` ```text
## CLI Commands ## CLI Commands
@ -157,7 +157,7 @@ control-center policy test policies/mfa.cedar tests/data/mfa_test.json
# Analyze policy impact # Analyze policy impact
control-center policy impact policies/new_policy.cedar control-center policy impact policies/new_policy.cedar
``` ```text
### Compliance Checking ### Compliance Checking
@ -170,7 +170,7 @@ control-center compliance hipaa
# Generate compliance report # Generate compliance report
control-center compliance report --format html control-center compliance report --format html
``` ```text
## API Endpoints ## API Endpoints
@ -206,25 +206,25 @@ control-center compliance report --format html
```bash ```bash
cargo test cargo test
``` ```text
### Run Integration Tests ### Run Integration Tests
```bash ```bash
cargo test --test integration_tests cargo test --test integration_tests
``` ```text
### Run Policy Tests ### Run Policy Tests
```bash ```bash
cargo test --test policy_tests cargo test --test policy_tests
``` ```text
### Run Compliance Tests ### Run Compliance Tests
```bash ```bash
cargo test --test compliance_tests cargo test --test compliance_tests
``` ```text
## Architecture ## Architecture
@ -287,7 +287,7 @@ RUN apt-get update && apt-get install -y ca-certificates
COPY --from=builder /app/target/release/control-center /usr/local/bin/ COPY --from=builder /app/target/release/control-center /usr/local/bin/
EXPOSE 8080 EXPOSE 8080
CMD ["control-center", "server"] CMD ["control-center", "server"]
``` ```text
### Kubernetes ### Kubernetes
@ -314,7 +314,7 @@ spec:
env: env:
- name: DATABASE_URL - name: DATABASE_URL
value: "surreal://surrealdb:8000" value: "surreal://surrealdb:8000"
``` ```text
### Environment Variables ### Environment Variables
@ -324,7 +324,7 @@ export CONTROL_CENTER_SERVER_PORT=8080
export CONTROL_CENTER_DATABASE_URL="surreal://prod-db:8000" export CONTROL_CENTER_DATABASE_URL="surreal://prod-db:8000"
export CONTROL_CENTER_AUTH_JWT_SECRET="production-secret" export CONTROL_CENTER_AUTH_JWT_SECRET="production-secret"
export CONTROL_CENTER_COMPLIANCE_SOC2_ENABLED=true export CONTROL_CENTER_COMPLIANCE_SOC2_ENABLED=true
``` ```text
## Monitoring & Observability ## Monitoring & Observability
@ -346,13 +346,13 @@ tracing::info!(
duration_ms = evaluation_time, duration_ms = evaluation_time,
"Policy evaluation completed" "Policy evaluation completed"
); );
``` ```text
### Health Checks ### Health Checks
```bash ```bash
curl http://localhost:8080/health curl http://localhost:8080/health
``` ```text
## Contributing ## Contributing

View File

@ -2,7 +2,8 @@
## Overview ## Overview
This document outlines the security architecture and considerations for the control-center enhancements, including KMS SSH key management, mode-based RBAC, and platform service monitoring. This document outlines the security architecture and considerations for the control-center enhancements,
including KMS SSH key management, mode-based RBAC, and platform service monitoring.
## 1. SSH Key Management Security ## 1. SSH Key Management Security
@ -30,7 +31,7 @@ let key_id = ssh_key_manager.store_ssh_key(name, private, public, purpose, tags)
// Bad: Never do this - exposing private key in logs // Bad: Never do this - exposing private key in logs
tracing::info!("Stored key: {}", private_key); // DON'T DO THIS tracing::info!("Stored key: {}", private_key); // DON'T DO THIS
```plaintext ```text
### 1.2 Key Rotation Security ### 1.2 Key Rotation Security
@ -55,7 +56,7 @@ rotation_enabled = true
rotation_interval_days = 90 # Enterprise: 30, Dev: 180 rotation_interval_days = 90 # Enterprise: 30, Dev: 180
grace_period_days = 7 # Time to update deployed keys grace_period_days = 7 # Time to update deployed keys
auto_rotate = false # Manual approval recommended auto_rotate = false # Manual approval recommended
```plaintext ```text
### 1.3 Audit Logging ### 1.3 Audit Logging
@ -79,7 +80,7 @@ pub struct SshKeyAuditEntry {
pub success: bool, pub success: bool,
pub error_message: Option<String>, pub error_message: Option<String>,
} }
```plaintext ```text
**Threat Mitigation**: **Threat Mitigation**:
@ -105,7 +106,7 @@ fn calculate_fingerprint(public_key: &[u8]) -> Result<String, KmsError> {
let result = hasher.finalize(); let result = hasher.finalize();
Ok(format!("SHA256:{}", base64::encode(&result[..16]))) Ok(format!("SHA256:{}", base64::encode(&result[..16])))
} }
```plaintext ```text
**Security Benefits**: **Security Benefits**:
@ -120,7 +121,7 @@ fn calculate_fingerprint(public_key: &[u8]) -> Result<String, KmsError> {
**Security Model by Mode**: **Security Model by Mode**:
| Mode | Security Level | Use Case | Audit Required | | Mode | Security Level | Use Case | Audit Required |
|------|---------------|----------|----------------| | ------ | --------------- | ---------- | ---------------- |
| Solo | Low | Single developer | No | | Solo | Low | Single developer | No |
| MultiUser | Medium | Small teams | Optional | | MultiUser | Medium | Small teams | Optional |
| CICD | Medium | Automation | Yes | | CICD | Medium | Automation | Yes |
@ -136,7 +137,7 @@ fn calculate_fingerprint(public_key: &[u8]) -> Result<String, KmsError> {
if mode == ExecutionMode::Solo { if mode == ExecutionMode::Solo {
return true; // Allow all operations return true; // Allow all operations
} }
```plaintext ```text
**Risks**: **Risks**:
@ -158,7 +159,7 @@ let permissions = rbac_manager.get_user_permissions(&user).await;
if !permissions.contains(&required_permission) { if !permissions.contains(&required_permission) {
return Err(RbacError::PermissionDenied); return Err(RbacError::PermissionDenied);
} }
```plaintext ```text
**Security Features**: **Security Features**:
@ -174,7 +175,7 @@ if !permissions.contains(&required_permission) {
if mode == ExecutionMode::CICD { if mode == ExecutionMode::CICD {
audit_log.log_automation_action(service_account, action).await; audit_log.log_automation_action(service_account, action).await;
} }
```plaintext ```text
**Security Features**: **Security Features**:
@ -193,7 +194,7 @@ if mode == ExecutionMode::CICD {
if mode == ExecutionMode::Enterprise { if mode == ExecutionMode::Enterprise {
audit_log.log_with_compliance(user, action, compliance_tags).await; audit_log.log_with_compliance(user, action, compliance_tags).await;
} }
```plaintext ```text
**Security Features**: **Security Features**:
@ -213,7 +214,7 @@ Role::Developer => 60 // Read + dev deploy
Role::ServiceAccount => 50 // Automation Role::ServiceAccount => 50 // Automation
Role::Auditor => 40 // Read + audit Role::Auditor => 40 // Read + audit
Role::Viewer => 20 // Read-only Role::Viewer => 20 // Read-only
```plaintext ```text
**Action Security Levels**: **Action Security Levels**:
@ -226,7 +227,7 @@ Action::Update => 60 // Modify resources
Action::Execute => 50 // Execute operations Action::Execute => 50 // Execute operations
Action::Audit => 40 // View audit logs Action::Audit => 40 // View audit logs
Action::Read => 20 // View resources Action::Read => 20 // View resources
```plaintext ```text
**Permission Check**: **Permission Check**:
@ -234,7 +235,7 @@ Action::Read => 20 // View resources
pub fn can_perform(&self, required_level: u8) -> bool { pub fn can_perform(&self, required_level: u8) -> bool {
self.permission_level() >= required_level self.permission_level() >= required_level
} }
```plaintext ```text
**Security Guarantees**: **Security Guarantees**:
@ -254,7 +255,7 @@ session_timeout_minutes = 30 # Enterprise
max_sessions_per_user = 5 max_sessions_per_user = 5
failed_login_lockout_attempts = 5 failed_login_lockout_attempts = 5
failed_login_lockout_duration_minutes = 15 failed_login_lockout_duration_minutes = 15
```plaintext ```text
**Session Lifecycle**: **Session Lifecycle**:
@ -289,7 +290,7 @@ Request → Auth Middleware → RBAC Middleware → Handler
from JWT Token (role + resource + action) from JWT Token (role + resource + action)
Allow / Deny Allow / Deny
```plaintext ```text
**Middleware Implementation**: **Middleware Implementation**:
@ -311,7 +312,7 @@ pub async fn check_permission(
Ok(next.run(req).await) Ok(next.run(req).await)
} }
```plaintext ```text
**Security Guarantees**: **Security Guarantees**:
@ -332,7 +333,7 @@ orchestrator_url = "http://localhost:9090" # Not exposed externally
coredns_url = "http://localhost:9153" coredns_url = "http://localhost:9153"
gitea_url = "http://localhost:3000" gitea_url = "http://localhost:3000"
oci_registry_url = "http://localhost:5000" oci_registry_url = "http://localhost:5000"
```plaintext ```text
**Network Security**: **Network Security**:
@ -355,7 +356,7 @@ let client = Client::builder()
.timeout(std::time::Duration::from_secs(5)) // Prevent hanging .timeout(std::time::Duration::from_secs(5)) // Prevent hanging
.build() .build()
.unwrap(); .unwrap();
```plaintext ```text
**Error Handling**: **Error Handling**:
@ -372,7 +373,7 @@ Err(e) => {
.. ..
} }
} }
```plaintext ```text
**Threat Mitigation**: **Threat Mitigation**:
@ -409,7 +410,7 @@ pub async fn start_service(
Ok(StatusCode::OK) Ok(StatusCode::OK)
} }
```plaintext ```text
**Security Guarantees**: **Security Guarantees**:
@ -547,7 +548,7 @@ pub async fn delete_user(&self, user_id: &str) -> Result<(), RbacError> {
Ok(()) Ok(())
} }
```plaintext ```text
### 5.2 SOC 2 Compliance ### 5.2 SOC 2 Compliance

View File

@ -595,9 +595,9 @@ impl AnomalyDetector {
for event in recent { for event in recent {
let Ok(context) = serde_json::from_value::<serde_json::Value>(event.context.clone()) let Ok(context) = serde_json::from_value::<serde_json::Value>(event.context.clone())
else { else {
continue; continue;
}; };
let Some(geo) = context.get("geo") else { let Some(geo) = context.get("geo") else {
continue; continue;
}; };
@ -609,9 +609,9 @@ impl AnomalyDetector {
for event in baseline { for event in baseline {
let Ok(context) = serde_json::from_value::<serde_json::Value>(event.context.clone()) let Ok(context) = serde_json::from_value::<serde_json::Value>(event.context.clone())
else { else {
continue; continue;
}; };
let Some(geo) = context.get("geo") else { let Some(geo) = context.get("geo") else {
continue; continue;
}; };

View File

@ -469,7 +469,8 @@ mod tests {
use super::*; use super::*;
fn generate_test_keys() -> (Vec<u8>, Vec<u8>) { fn generate_test_keys() -> (Vec<u8>, Vec<u8>) {
// Pre-generated RSA keys to avoid runtime key generation (avoids rand_core conflict) // Pre-generated RSA keys to avoid runtime key generation (avoids rand_core
// conflict)
let private_pem = b"-----BEGIN PRIVATE KEY----- let private_pem = b"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k
DQMEjENGqJLnBn6MvJnCu93A4ZNKEEpPGX1Y6V+qiqLH5B7wNMIJ2QVnLjYjKZu5 DQMEjENGqJLnBn6MvJnCu93A4ZNKEEpPGX1Y6V+qiqLH5B7wNMIJ2QVnLjYjKZu5
@ -509,10 +510,7 @@ WCemS72CI+y72SqwgaZ94eUO4WKV2agxmHeXQ8FhSd8ZFTJCTBKDW91Kykdo7yUx
IQIDAQAB IQIDAQAB
-----END PUBLIC KEY-----"; -----END PUBLIC KEY-----";
( (private_pem.to_vec(), public_pem.to_vec())
private_pem.to_vec(),
public_pem.to_vec(),
)
} }
fn create_test_service() -> JwtService { fn create_test_service() -> JwtService {

View File

@ -373,7 +373,8 @@ mod tests {
use super::*; use super::*;
fn create_test_jwt_service() -> JwtService { fn create_test_jwt_service() -> JwtService {
// Pre-generated RSA keys to avoid runtime key generation (avoids rand_core conflict) // Pre-generated RSA keys to avoid runtime key generation (avoids rand_core
// conflict)
let private_pem = b"-----BEGIN PRIVATE KEY----- let private_pem = b"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k
DQMEjENGqJLnBn6MvJnCu93A4ZNKEEpPGX1Y6V+qiqLH5B7wNMIJ2QVnLjYjKZu5 DQMEjENGqJLnBn6MvJnCu93A4ZNKEEpPGX1Y6V+qiqLH5B7wNMIJ2QVnLjYjKZu5

View File

@ -726,8 +726,7 @@ impl ComplianceFrameworkChecker for HIPAAChecker {
for violation in &critical_violations { for violation in &critical_violations {
report.push_str(&format!( report.push_str(&format!(
"### ⚠️ {} - {} Risk\n", "### ⚠️ {} - {} Risk\n",
violation.control_id, violation.control_id, violation.severity
violation.severity
)); ));
report.push_str(&format!("**Description:** {}\n", violation.description)); report.push_str(&format!("**Description:** {}\n", violation.description));
if let Some(deadline) = violation.remediation_deadline { if let Some(deadline) = violation.remediation_deadline {

View File

@ -16,8 +16,8 @@ use serde::{Deserialize, Serialize};
use crate::error::{policy, ControlCenterError, Result}; use crate::error::{policy, ControlCenterError, Result};
use crate::policies::{PolicyCategory, PolicyMetadata, PolicyRequestContext, PolicyResult}; use crate::policies::{PolicyCategory, PolicyMetadata, PolicyRequestContext, PolicyResult};
use crate::storage::{ComplianceCheckResult, PolicyStorage};
use crate::storage::PolicyMetadata as StoragePolicyMetadata; use crate::storage::PolicyMetadata as StoragePolicyMetadata;
use crate::storage::{ComplianceCheckResult, PolicyStorage};
/// Compliance framework types /// Compliance framework types
#[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]

View File

@ -551,8 +551,7 @@ impl ComplianceFrameworkChecker for SOC2Checker {
for violation in &result.violations { for violation in &result.violations {
report.push_str(&format!( report.push_str(&format!(
"### {} - {}\n", "### {} - {}\n",
violation.control_id, violation.control_id, violation.severity
violation.severity
)); ));
report.push_str(&format!("**Description:** {}\n", violation.description)); report.push_str(&format!("**Description:** {}\n", violation.description));
if let Some(deadline) = violation.remediation_deadline { if let Some(deadline) = violation.remediation_deadline {
@ -571,8 +570,7 @@ impl ComplianceFrameworkChecker for SOC2Checker {
for recommendation in &result.recommendations { for recommendation in &result.recommendations {
report.push_str(&format!( report.push_str(&format!(
"### {} ({})\n", "### {} ({})\n",
recommendation.title, recommendation.title, recommendation.priority
recommendation.priority
)); ));
report.push_str(&format!("**Control:** {}\n", recommendation.control_id)); report.push_str(&format!("**Control:** {}\n", recommendation.control_id));
report.push_str(&format!( report.push_str(&format!(

View File

@ -1,9 +1,11 @@
use crate::error::{ControlCenterError, Result, infrastructure};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use tracing::info;
use platform_config::ConfigLoader; use platform_config::ConfigLoader;
use serde::{Deserialize, Serialize};
use tracing::info;
use crate::error::{infrastructure, ControlCenterError, Result};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ControlCenterConfig { pub struct ControlCenterConfig {
@ -213,7 +215,8 @@ impl Default for ControlCenterConfig {
impl ControlCenterConfig { impl ControlCenterConfig {
/// Load configuration with hierarchical fallback logic: /// Load configuration with hierarchical fallback logic:
/// 1. Environment variable CONTROL_CENTER_CONFIG (explicit config path) /// 1. Environment variable CONTROL_CENTER_CONFIG (explicit config path)
/// 2. Mode-specific config: provisioning/platform/config/control-center.{mode}.toml /// 2. Mode-specific config:
/// provisioning/platform/config/control-center.{mode}.toml
/// 3. System defaults: config.defaults.toml /// 3. System defaults: config.defaults.toml
/// ///
/// Then environment variables (CONTROL_CENTER_*) override specific fields. /// Then environment variables (CONTROL_CENTER_*) override specific fields.
@ -232,10 +235,8 @@ impl ControlCenterConfig {
// Priority 2: Mode-specific config (provisioning/platform/config/) // Priority 2: Mode-specific config (provisioning/platform/config/)
if let Ok(mode) = std::env::var("CONTROL_CENTER_MODE") { if let Ok(mode) = std::env::var("CONTROL_CENTER_MODE") {
let mode_config_path = format!( let mode_config_path =
"provisioning/platform/config/control-center.{}.toml", format!("provisioning/platform/config/control-center.{}.toml", mode);
mode
);
if Path::new(&mode_config_path).exists() { if Path::new(&mode_config_path).exists() {
return Self::from_file(&mode_config_path); return Self::from_file(&mode_config_path);
} }
@ -260,10 +261,13 @@ impl ControlCenterConfig {
config.server.host = host; config.server.host = host;
} }
if let Ok(port) = std::env::var("CONTROL_CENTER_SERVER_PORT") { if let Ok(port) = std::env::var("CONTROL_CENTER_SERVER_PORT") {
config.server.port = port.parse() config.server.port = port.parse().map_err(|_| {
.map_err(|_| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(
"CONTROL_CENTER_SERVER_PORT must be a valid port number".to_string() infrastructure::InfrastructureError::Configuration(
)))?; "CONTROL_CENTER_SERVER_PORT must be a valid port number".to_string(),
),
)
})?;
} }
// Auth overrides // Auth overrides
@ -274,10 +278,13 @@ impl ControlCenterConfig {
config.auth.require_mfa = require_mfa.to_lowercase() == "true"; config.auth.require_mfa = require_mfa.to_lowercase() == "true";
} }
if let Ok(session_timeout) = std::env::var("CONTROL_CENTER_SESSION_TIMEOUT_MINUTES") { if let Ok(session_timeout) = std::env::var("CONTROL_CENTER_SESSION_TIMEOUT_MINUTES") {
config.auth.session_timeout_minutes = session_timeout.parse() config.auth.session_timeout_minutes = session_timeout.parse().map_err(|_| {
.map_err(|_| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(
"CONTROL_CENTER_SESSION_TIMEOUT_MINUTES must be a valid number".to_string() infrastructure::InfrastructureError::Configuration(
)))?; "CONTROL_CENTER_SESSION_TIMEOUT_MINUTES must be a valid number".to_string(),
),
)
})?;
} }
// Database overrides // Database overrides
@ -309,18 +316,20 @@ impl ControlCenterConfig {
/// Load configuration from file with environment variable interpolation /// Load configuration from file with environment variable interpolation
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> { pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let content = std::fs::read_to_string(path.as_ref()) let content = std::fs::read_to_string(path.as_ref()).map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Failed to read config file {:?}: {}", path.as_ref(), e) format!("Failed to read config file {:?}: {}", path.as_ref(), e),
)))?; ))
})?;
// Interpolate environment variables // Interpolate environment variables
let interpolated = Self::interpolate_env_vars(&content)?; let interpolated = Self::interpolate_env_vars(&content)?;
let config: Self = toml::from_str(&interpolated) let config: Self = toml::from_str(&interpolated).map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Failed to parse config: {}", e) format!("Failed to parse config: {}", e),
)))?; ))
})?;
config.validate()?; config.validate()?;
Ok(config) Ok(config)
@ -331,10 +340,11 @@ impl ControlCenterConfig {
let mut result = content.to_string(); let mut result = content.to_string();
// Replace ${VAR_NAME} with environment variable values // Replace ${VAR_NAME} with environment variable values
let re = regex::Regex::new(r"\$\{([^}]+)\}") let re = regex::Regex::new(r"\$\{([^}]+)\}").map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Invalid regex pattern: {}", e) format!("Invalid regex pattern: {}", e),
)))?; ))
})?;
for captures in re.captures_iter(content) { for captures in re.captures_iter(content) {
let var_name = &captures[1]; let var_name = &captures[1];
@ -351,16 +361,21 @@ impl ControlCenterConfig {
pub fn validate(&self) -> Result<()> { pub fn validate(&self) -> Result<()> {
// Validate server config // Validate server config
if self.server.port == 0 { if self.server.port == 0 {
return Err(ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( return Err(ControlCenterError::Infrastructure(
"Server port cannot be 0".to_string() infrastructure::InfrastructureError::Configuration(
))); "Server port cannot be 0".to_string(),
),
));
} }
// Validate policy directories exist // Validate policy directories exist
if !self.policies.policy_dir.exists() { if !self.policies.policy_dir.exists() {
return Err(ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( return Err(ControlCenterError::Infrastructure(
format!("Policy directory does not exist: {:?}", self.policies.policy_dir) infrastructure::InfrastructureError::Configuration(format!(
))); "Policy directory does not exist: {:?}",
self.policies.policy_dir
)),
));
} }
// Validate auth config // Validate auth config
@ -369,16 +384,20 @@ impl ControlCenterConfig {
} }
if self.auth.jwt_secret.len() < 32 { if self.auth.jwt_secret.len() < 32 {
return Err(ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( return Err(ControlCenterError::Infrastructure(
"JWT secret must be at least 32 characters".to_string() infrastructure::InfrastructureError::Configuration(
))); "JWT secret must be at least 32 characters".to_string(),
),
));
} }
// Validate password policy // Validate password policy
if self.auth.password_policy.min_length < 8 { if self.auth.password_policy.min_length < 8 {
return Err(ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( return Err(ControlCenterError::Infrastructure(
"Password minimum length must be at least 8 characters".to_string() infrastructure::InfrastructureError::Configuration(
))); "Password minimum length must be at least 8 characters".to_string(),
),
));
} }
Ok(()) Ok(())
@ -386,24 +405,27 @@ impl ControlCenterConfig {
/// Get configuration as JSON string /// Get configuration as JSON string
pub fn to_json(&self) -> Result<String> { pub fn to_json(&self) -> Result<String> {
serde_json::to_string_pretty(self) serde_json::to_string_pretty(self).map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Failed to serialize config to JSON: {}", e) format!("Failed to serialize config to JSON: {}", e),
))) ))
})
} }
/// Create a default configuration file /// Create a default configuration file
pub fn create_default_config<P: AsRef<Path>>(path: P) -> Result<()> { pub fn create_default_config<P: AsRef<Path>>(path: P) -> Result<()> {
let config = Self::default(); let config = Self::default();
let toml_content = toml::to_string_pretty(&config) let toml_content = toml::to_string_pretty(&config).map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Failed to serialize default config: {}", e) format!("Failed to serialize default config: {}", e),
)))?; ))
})?;
std::fs::write(path.as_ref(), toml_content) std::fs::write(path.as_ref(), toml_content).map_err(|e| {
.map_err(|e| ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration( ControlCenterError::Infrastructure(infrastructure::InfrastructureError::Configuration(
format!("Failed to write config file {:?}: {}", path.as_ref(), e) format!("Failed to write config file {:?}: {}", path.as_ref(), e),
)))?; ))
})?;
Ok(()) Ok(())
} }
@ -414,34 +436,47 @@ impl ConfigLoader for ControlCenterConfig {
"control-center" "control-center"
} }
fn load_from_hierarchy() -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>> { fn load_from_hierarchy() -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>>
{
let service = Self::service_name(); let service = Self::service_name();
if let Some(path) = platform_config::resolve_config_path(service) { if let Some(path) = platform_config::resolve_config_path(service) {
return Self::from_path(&path) return Self::from_path(&path).map_err(|e| {
.map_err(|e| Box::new(std::io::Error::other(e.to_string())) as Box<dyn std::error::Error + Send + Sync>); Box::new(std::io::Error::other(e.to_string()))
as Box<dyn std::error::Error + Send + Sync>
});
} }
Ok(Self::default()) Ok(Self::default())
} }
fn apply_env_overrides(&mut self) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> { fn apply_env_overrides(
Self::apply_env_overrides(self) &mut self,
.map_err(|e| Box::new(std::io::Error::other(e.to_string())) as Box<dyn std::error::Error + Send + Sync>) ) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
Self::apply_env_overrides(self).map_err(|e| {
Box::new(std::io::Error::other(e.to_string()))
as Box<dyn std::error::Error + Send + Sync>
})
} }
fn from_path<P: AsRef<Path>>(path: P) -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>> { fn from_path<P: AsRef<Path>>(
path: P,
) -> std::result::Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let path = path.as_ref(); let path = path.as_ref();
let json_value = platform_config::format::load_config(path) let json_value = platform_config::format::load_config(path).map_err(|e| {
.map_err(|e| { let err: Box<dyn std::error::Error + Send + Sync> = Box::new(e);
let err: Box<dyn std::error::Error + Send + Sync> = Box::new(e); err
err })?;
})?;
serde_json::from_value(json_value) serde_json::from_value(json_value).map_err(|e| {
.map_err(|e| { let err_msg = format!(
let err_msg = format!("Failed to deserialize control-center config from {:?}: {}", path, e); "Failed to deserialize control-center config from {:?}: {}",
Box::new(std::io::Error::new(std::io::ErrorKind::InvalidData, err_msg)) as Box<dyn std::error::Error + Send + Sync> path, e
}) );
Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidData,
err_msg,
)) as Box<dyn std::error::Error + Send + Sync>
})
} }
} }

View File

@ -269,9 +269,10 @@ impl From<std::io::Error> for ControlCenterError {
impl From<serde_json::Error> for ControlCenterError { impl From<serde_json::Error> for ControlCenterError {
fn from(error: serde_json::Error) -> Self { fn from(error: serde_json::Error) -> Self {
ControlCenterError::Infrastructure(InfrastructureError::Configuration( ControlCenterError::Infrastructure(InfrastructureError::Configuration(format!(
format!("JSON serialization error: {}", error) "JSON serialization error: {}",
)) error
)))
} }
} }

View File

@ -1,6 +1,7 @@
# Hybrid Key Management System (KMS) # Hybrid Key Management System (KMS)
A comprehensive hybrid KMS system built for the control center, supporting local/remote/hybrid modes with intelligent caching, failover, and advanced security features. A comprehensive hybrid KMS system built for the control center, supporting local/remote/hybrid modes
with intelligent caching, failover, and advanced security features.
## Architecture Overview ## Architecture Overview
@ -147,7 +148,7 @@ enable_pfs = true
allowed_algorithms = ["AES-256-GCM", "ChaCha20Poly1305", "RSA-4096", "ECDSA-P384"] allowed_algorithms = ["AES-256-GCM", "ChaCha20Poly1305", "RSA-4096", "ECDSA-P384"]
blocked_algorithms = ["DES", "3DES", "RC4", "MD5"] blocked_algorithms = ["DES", "3DES", "RC4", "MD5"]
policy_enforcement = "strict" policy_enforcement = "strict"
``` ```text
## Usage Examples ## Usage Examples
@ -212,7 +213,7 @@ if let Some(key_info) = kms.get_key(&stored_key_id).await? {
println!("Key status: {:?}", key_info.status); println!("Key status: {:?}", key_info.status);
println!("Created: {}", key_info.created_at); println!("Created: {}", key_info.created_at);
} }
``` ```text
### Provider Credential Management ### Provider Credential Management
@ -240,7 +241,7 @@ if let Some(creds) = kms.get_provider_credentials("aws").await? {
// Credentials are automatically injected into environment variables // Credentials are automatically injected into environment variables
// or configuration files based on the injection configuration // or configuration files based on the injection configuration
} }
``` ```text
### Health Monitoring ### Health Monitoring
@ -256,7 +257,7 @@ println!("Credentials Status: {}", health.credentials.healthy);
let cache_stats = kms.cache.stats().await; let cache_stats = kms.cache.stats().await;
println!("Cache hit rate: {:.2}%", cache_stats.hit_rate() * 100.0); println!("Cache hit rate: {:.2}%", cache_stats.hit_rate() * 100.0);
println!("Cache entries: {}", cache_stats.entry_count); println!("Cache entries: {}", cache_stats.entry_count);
``` ```text
## Integration with Existing System ## Integration with Existing System
@ -270,7 +271,7 @@ export PROVISIONING_KMS_MODE=hybrid
export PROVISIONING_KMS_LOCAL_DATABASE_PATH=/var/lib/provisioning/kms.db export PROVISIONING_KMS_LOCAL_DATABASE_PATH=/var/lib/provisioning/kms.db
export PROVISIONING_KMS_REMOTE_SERVER_URL=https://kms.example.com:9998 export PROVISIONING_KMS_REMOTE_SERVER_URL=https://kms.example.com:9998
export PROVISIONING_KMS_CACHE_ENABLED=true export PROVISIONING_KMS_CACHE_ENABLED=true
``` ```text
### TOML Configuration Integration ### TOML Configuration Integration
@ -284,7 +285,7 @@ local.database_path = "{{paths.base}}/data/kms.db"
cache.enabled = true cache.enabled = true
cache.local_dir = "{{paths.base}}/cache/kms" cache.local_dir = "{{paths.base}}/cache/kms"
audit.enabled = true audit.enabled = true
``` ```text
### Nushell Integration ### Nushell Integration
@ -304,7 +305,7 @@ def kms_health [] {
def kms_keys [] { def kms_keys [] {
http get http://localhost:8080/kms/keys | from json http get http://localhost:8080/kms/keys | from json
} }
``` ```text
## Security Considerations ## Security Considerations
@ -417,7 +418,7 @@ export PROVISIONING_LOG_LEVEL=debug
# Run with verbose output # Run with verbose output
./control-center --debug ./control-center --debug
``` ```text
### Health Checks ### Health Checks
@ -429,7 +430,7 @@ curl http://localhost:8080/kms/health
curl http://localhost:8080/kms/health/backend curl http://localhost:8080/kms/health/backend
curl http://localhost:8080/kms/health/cache curl http://localhost:8080/kms/health/cache
curl http://localhost:8080/kms/health/rotation curl http://localhost:8080/kms/health/rotation
``` ```text
## Future Enhancements ## Future Enhancements
@ -448,4 +449,5 @@ curl http://localhost:8080/kms/health/rotation
3. **Federated KMS**: Multi-organization key sharing 3. **Federated KMS**: Multi-organization key sharing
4. **Blockchain Integration**: Immutable audit trails 4. **Blockchain Integration**: Immutable audit trails
This hybrid KMS system provides a solid foundation for secure key management in the control center architecture, with room for future enhancements and customization based on specific requirements. This hybrid KMS system provides a solid foundation for secure key management in the control center architecture,
with room for future enhancements and customization based on specific requirements.

View File

@ -162,9 +162,7 @@ impl PolicyEngine {
match Policy::parse(Some(PolicyId::new(metadata.id.clone())), &policy_content) { match Policy::parse(Some(PolicyId::new(metadata.id.clone())), &policy_content) {
Ok(policy) => { Ok(policy) => {
policy_set.add(policy).map_err(|e| { policy_set.add(policy).map_err(|e| {
ControlCenterError::Policy(policy::PolicyError::Parsing( ControlCenterError::Policy(policy::PolicyError::Parsing(e.to_string()))
e.to_string(),
))
})?; })?;
loaded_count += 1; loaded_count += 1;
} }
@ -195,9 +193,7 @@ impl PolicyEngine {
if path.is_dir() { if path.is_dir() {
// Use Box::pin for recursive async calls to avoid infinite future size // Use Box::pin for recursive async calls to avoid infinite future size
count += Box::pin( count += Box::pin(self.load_policies_from_directory(policy_set, &path)).await?;
self.load_policies_from_directory(policy_set, &path)
).await?;
} else if path.extension().and_then(|s| s.to_str()) == Some("cedar") { } else if path.extension().and_then(|s| s.to_str()) == Some("cedar") {
count += self.load_policy_file(policy_set, &path).await?; count += self.load_policy_file(policy_set, &path).await?;
} }
@ -279,21 +275,16 @@ impl PolicyEngine {
.build_context(&context.environment) .build_context(&context.environment)
.await?; .await?;
let context = Context::from_json_value(serde_json::Value::Object(context_map), None).map_err(|e| { let context = Context::from_json_value(serde_json::Value::Object(context_map), None)
ControlCenterError::Policy(policy::PolicyError::Evaluation(format!( .map_err(|e| {
"Context build error: {}", ControlCenterError::Policy(policy::PolicyError::Evaluation(format!(
e "Context build error: {}",
))) e
})?; )))
})?;
let schema = self.build_schema().await?; let schema = self.build_schema().await?;
Request::new( Request::new(principal, action, resource, context, Some(&schema)).map_err(|e| {
principal,
action,
resource,
context,
Some(&schema),
).map_err(|e| {
ControlCenterError::Policy(policy::PolicyError::Evaluation(format!( ControlCenterError::Policy(policy::PolicyError::Evaluation(format!(
"Request validation error: {}", "Request validation error: {}",
e e
@ -314,7 +305,8 @@ impl PolicyEngine {
let schema_path = &self.config.policies.schema_dir; let schema_path = &self.config.policies.schema_dir;
if schema_path.exists() { if schema_path.exists() {
// Implementation would load actual schema files from the directory // Implementation would load actual schema files from the directory
// For Cedar 4.8, we'd need to parse JSON schema files and construct Schema // For Cedar 4.8, we'd need to parse JSON schema files and construct
// Schema
} }
// Cedar 4.8 schema construction via JSON // Cedar 4.8 schema construction via JSON

View File

@ -283,7 +283,11 @@ impl PolicyTemplateManager {
} }
/// Render policy from template /// Render policy from template
pub fn render_policy(&mut self, template_id: &str, context: &TemplateContext) -> Result<String> { pub fn render_policy(
&mut self,
template_id: &str,
context: &TemplateContext,
) -> Result<String> {
let template = self.templates.get(template_id).ok_or_else(|| { let template = self.templates.get(template_id).ok_or_else(|| {
ControlCenterError::Policy(policy::PolicyError::Parsing(format!( ControlCenterError::Policy(policy::PolicyError::Parsing(format!(
"Template not found: {}", "Template not found: {}",

View File

@ -450,11 +450,7 @@ impl PolicyValidator {
if !result.errors.is_empty() { if !result.errors.is_empty() {
report.push_str("ERRORS:\n"); report.push_str("ERRORS:\n");
for error in &result.errors { for error in &result.errors {
report.push_str(&format!( report.push_str(&format!(" - {}: {}\n", error.error_type, error.message));
" - {}: {}\n",
error.error_type,
error.message
));
} }
report.push('\n'); report.push('\n');
} }
@ -464,9 +460,7 @@ impl PolicyValidator {
for warning in &result.warnings { for warning in &result.warnings {
report.push_str(&format!( report.push_str(&format!(
" - [{}] {}: {}\n", " - [{}] {}: {}\n",
warning.severity, warning.severity, warning.warning_type, warning.message
warning.warning_type,
warning.message
)); ));
} }
report.push('\n'); report.push('\n');
@ -477,8 +471,7 @@ impl PolicyValidator {
for suggestion in &result.suggestions { for suggestion in &result.suggestions {
report.push_str(&format!( report.push_str(&format!(
" - {}: {}\n", " - {}: {}\n",
suggestion.suggestion_type, suggestion.suggestion_type, suggestion.message
suggestion.message
)); ));
} }
} }

View File

@ -12,7 +12,9 @@ use uuid::Uuid;
use crate::error::{policy, ControlCenterError, Result}; use crate::error::{policy, ControlCenterError, Result};
use crate::policies::PolicyMetadata; use crate::policies::PolicyMetadata;
use crate::storage::{PolicyStorage, PolicyVersion as StoragePolicyVersion, RollbackResult as StorageRollbackResult}; use crate::storage::{
PolicyStorage, PolicyVersion as StoragePolicyVersion, RollbackResult as StorageRollbackResult,
};
/// Policy version information /// Policy version information
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -83,7 +85,10 @@ pub struct RollbackResult {
} }
/// Convert storage PolicyVersion to versioning PolicyVersion /// Convert storage PolicyVersion to versioning PolicyVersion
fn convert_storage_version(storage_version: StoragePolicyVersion, metadata: Option<PolicyMetadata>) -> PolicyVersion { fn convert_storage_version(
storage_version: StoragePolicyVersion,
metadata: Option<PolicyMetadata>,
) -> PolicyVersion {
let metadata = metadata.unwrap_or_else(|| PolicyMetadata { let metadata = metadata.unwrap_or_else(|| PolicyMetadata {
id: storage_version.policy_id.clone(), id: storage_version.policy_id.clone(),
name: String::new(), name: String::new(),
@ -106,11 +111,11 @@ fn convert_storage_version(storage_version: StoragePolicyVersion, metadata: Opti
metadata, metadata,
created_at: storage_version.created_at, created_at: storage_version.created_at,
created_by: "system".to_string(), // Storage doesn't track this created_by: "system".to_string(), // Storage doesn't track this
change_summary: String::new(), // Storage doesn't track this change_summary: String::new(), // Storage doesn't track this
tags: storage_version.tags, tags: storage_version.tags,
is_active: storage_version.is_active, is_active: storage_version.is_active,
parent_version_id: None, // Storage doesn't track this parent_version_id: None, // Storage doesn't track this
checksum: String::new(), // Storage doesn't track this checksum: String::new(), // Storage doesn't track this
} }
} }
@ -225,7 +230,8 @@ impl PolicyVersionManager {
policy_id: &str, policy_id: &str,
version_number: u32, version_number: u32,
) -> Result<Option<PolicyVersion>> { ) -> Result<Option<PolicyVersion>> {
let storage_version = self.storage let storage_version = self
.storage
.get_policy_version(policy_id, version_number) .get_policy_version(policy_id, version_number)
.await?; .await?;
Ok(storage_version.map(|v| convert_storage_version(v, None))) Ok(storage_version.map(|v| convert_storage_version(v, None)))
@ -240,7 +246,10 @@ impl PolicyVersionManager {
/// List all versions for a policy /// List all versions for a policy
pub async fn list_versions(&self, policy_id: &str) -> Result<Vec<PolicyVersion>> { pub async fn list_versions(&self, policy_id: &str) -> Result<Vec<PolicyVersion>> {
let storage_versions = self.storage.list_policy_versions(policy_id).await?; let storage_versions = self.storage.list_policy_versions(policy_id).await?;
Ok(storage_versions.into_iter().map(|v| convert_storage_version(v, None)).collect()) Ok(storage_versions
.into_iter()
.map(|v| convert_storage_version(v, None))
.collect())
} }
/// Get version history with changes /// Get version history with changes
@ -268,7 +277,9 @@ impl PolicyVersionManager {
summary: version.change_summary.clone(), summary: version.change_summary.clone(),
details: self.extract_change_details( details: self.extract_change_details(
&version.content, &version.content,
versions.get(i.saturating_sub(1)).map(|v| v.content.as_str()), versions
.get(i.saturating_sub(1))
.map(|v| v.content.as_str()),
), ),
impact_analysis, impact_analysis,
}); });
@ -401,10 +412,14 @@ impl PolicyVersionManager {
policy_id: &str, policy_id: &str,
tag: &str, tag: &str,
) -> Result<Vec<PolicyVersion>> { ) -> Result<Vec<PolicyVersion>> {
let storage_versions = self.storage let storage_versions = self
.storage
.get_policy_versions_by_tag(policy_id, tag) .get_policy_versions_by_tag(policy_id, tag)
.await?; .await?;
Ok(storage_versions.into_iter().map(|v| convert_storage_version(v, None)).collect()) Ok(storage_versions
.into_iter()
.map(|v| convert_storage_version(v, None))
.collect())
} }
/// Get latest version number /// Get latest version number

View File

@ -18,8 +18,8 @@ use serde::{Deserialize, Serialize};
// Import from surrealdb_storage (temporary placeholders) // Import from surrealdb_storage (temporary placeholders)
pub use surrealdb_storage::{PolicyMetadata, PolicyVersion, RollbackResult}; pub use surrealdb_storage::{PolicyMetadata, PolicyVersion, RollbackResult};
use crate::simple_config::Config;
use crate::error::{infrastructure, ControlCenterError, Result}; use crate::error::{infrastructure, ControlCenterError, Result};
use crate::simple_config::Config;
/// Policy storage trait /// Policy storage trait
#[async_trait] #[async_trait]

View File

@ -13,9 +13,9 @@ use serde::{Deserialize, Serialize};
use super::{ use super::{
ComplianceCheckResult, PolicyEvaluationEvent, PolicyMetrics, PolicySearchQuery, PolicyStorage, ComplianceCheckResult, PolicyEvaluationEvent, PolicyMetrics, PolicySearchQuery, PolicyStorage,
}; };
use crate::simple_config::Config;
use crate::error::{auth, policy, ControlCenterError, Result}; use crate::error::{auth, policy, ControlCenterError, Result};
use crate::services::secrets::SecretType; use crate::services::secrets::SecretType;
use crate::simple_config::Config;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyMetadata { pub struct PolicyMetadata {

View File

@ -20,7 +20,8 @@ use control_center::auth::{
AuthService, AuthService,
}; };
/// Generate RSA key pair for testing (pre-generated to avoid rand_core conflict) /// Generate RSA key pair for testing (pre-generated to avoid rand_core
/// conflict)
fn generate_test_keys() -> (Vec<u8>, Vec<u8>) { fn generate_test_keys() -> (Vec<u8>, Vec<u8>) {
let private_pem = b"-----BEGIN PRIVATE KEY----- let private_pem = b"-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC7F43HxrVfJJ+k
@ -61,10 +62,7 @@ WCemS72CI+y72SqwgaZ94eUO4WKV2agxmHeXQ8FhSd8ZFTJCTBKDW91Kykdo7yUx
IQIDAQAB IQIDAQAB
-----END PUBLIC KEY-----"; -----END PUBLIC KEY-----";
( (private_pem.to_vec(), public_pem.to_vec())
private_pem.to_vec(),
public_pem.to_vec(),
)
} }
/// Create JWT service for testing /// Create JWT service for testing

View File

@ -38,7 +38,7 @@ React/TypeScript frontend for the Control Center vault secrets management.
```bash ```bash
cd provisioning/platform/control-center/web cd provisioning/platform/control-center/web
npm install npm install
```plaintext ```text
## Development ## Development
@ -57,7 +57,7 @@ npm run lint
# Format code # Format code
npm run format npm run format
```plaintext ```text
## Environment Variables ## Environment Variables
@ -65,7 +65,7 @@ Create a `.env` file in the web directory:
```bash ```bash
REACT_APP_API_URL=http://localhost:8080 REACT_APP_API_URL=http://localhost:8080
```plaintext ```text
## Usage ## Usage
@ -81,7 +81,7 @@ function App() {
</div> </div>
); );
} }
```plaintext ```text
### API Client ### API Client
@ -119,7 +119,7 @@ const history = await secretsApi.getSecretHistory('database/prod/password');
// Restore version // Restore version
await secretsApi.restoreSecretVersion('database/prod/password', 2); await secretsApi.restoreSecretVersion('database/prod/password', 2);
```plaintext ```text
## Architecture ## Architecture
@ -137,7 +137,7 @@ SecretsManager (Orchestrator)
KMS Service (Encryption) KMS Service (Encryption)
RustyVault (Storage) RustyVault (Storage)
```plaintext ```text
## Security ## Security

View File

@ -13,7 +13,8 @@ Base URL: `http://localhost:8082/api/v1`
## Authentication ## Authentication
The Extension Registry API does not require authentication for read operations. Backend authentication (Gitea/OCI) is handled server-side via configuration. The Extension Registry API does not require authentication for read operations. Backend authentication (Gitea/OCI) is handled server-side via
configuration.
## Extension Endpoints ## Extension Endpoints
@ -26,7 +27,7 @@ Retrieve a list of available extensions with optional filtering and pagination.
**Query Parameters**: **Query Parameters**:
| Parameter | Type | Required | Description | | Parameter | Type | Required | Description |
|-----------|------|----------|-------------| | ----------- | ------ | ---------- | ------------- |
| `type` | string | No | Filter by extension type: `provider`, `taskserv`, `cluster` | | `type` | string | No | Filter by extension type: `provider`, `taskserv`, `cluster` |
| `source` | string | No | Filter by source: `gitea`, `oci` | | `source` | string | No | Filter by source: `gitea`, `oci` |
| `limit` | integer | No | Maximum results (default: 100, max: 1000) | | `limit` | integer | No | Maximum results (default: 100, max: 1000) |
@ -36,7 +37,7 @@ Retrieve a list of available extensions with optional filtering and pagination.
```bash ```bash
curl "http://localhost:8082/api/v1/extensions?type=provider&limit=10" curl "http://localhost:8082/api/v1/extensions?type=provider&limit=10"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -69,7 +70,7 @@ curl "http://localhost:8082/api/v1/extensions?type=provider&limit=10"
"size": 890000 "size": 890000
} }
] ]
```plaintext ```text
--- ---
@ -82,7 +83,7 @@ Retrieve detailed metadata for a specific extension.
**Path Parameters**: **Path Parameters**:
| Parameter | Type | Required | Description | | Parameter | Type | Required | Description |
|-----------|------|----------|-------------| | ----------- | ------ | ---------- | ------------- |
| `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` | | `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` |
| `name` | string | Yes | Extension name | | `name` | string | Yes | Extension name |
@ -90,7 +91,7 @@ Retrieve detailed metadata for a specific extension.
```bash ```bash
curl "http://localhost:8082/api/v1/extensions/provider/aws" curl "http://localhost:8082/api/v1/extensions/provider/aws"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -109,7 +110,7 @@ curl "http://localhost:8082/api/v1/extensions/provider/aws"
"size": 1024000, "size": 1024000,
"tags": ["cloud", "aws", "infrastructure"] "tags": ["cloud", "aws", "infrastructure"]
} }
```plaintext ```text
**Error Response** (404 Not Found): **Error Response** (404 Not Found):
@ -118,7 +119,7 @@ curl "http://localhost:8082/api/v1/extensions/provider/aws"
"error": "not_found", "error": "not_found",
"message": "Extension provider/nonexistent not found" "message": "Extension provider/nonexistent not found"
} }
```plaintext ```text
--- ---
@ -131,7 +132,7 @@ Get all available versions for a specific extension.
**Path Parameters**: **Path Parameters**:
| Parameter | Type | Required | Description | | Parameter | Type | Required | Description |
|-----------|------|----------|-------------| | ----------- | ------ | ---------- | ------------- |
| `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` | | `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` |
| `name` | string | Yes | Extension name | | `name` | string | Yes | Extension name |
@ -139,7 +140,7 @@ Get all available versions for a specific extension.
```bash ```bash
curl "http://localhost:8082/api/v1/extensions/taskserv/kubernetes/versions" curl "http://localhost:8082/api/v1/extensions/taskserv/kubernetes/versions"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -166,7 +167,7 @@ curl "http://localhost:8082/api/v1/extensions/taskserv/kubernetes/versions"
"size": 1950000 "size": 1950000
} }
] ]
```plaintext ```text
--- ---
@ -179,7 +180,7 @@ Download a specific version of an extension.
**Path Parameters**: **Path Parameters**:
| Parameter | Type | Required | Description | | Parameter | Type | Required | Description |
|-----------|------|----------|-------------| | ----------- | ------ | ---------- | ------------- |
| `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` | | `type` | string | Yes | Extension type: `provider`, `taskserv`, `cluster` |
| `name` | string | Yes | Extension name | | `name` | string | Yes | Extension name |
| `version` | string | Yes | Extension version (e.g., `1.2.0`) | | `version` | string | Yes | Extension version (e.g., `1.2.0`) |
@ -188,7 +189,7 @@ Download a specific version of an extension.
```bash ```bash
curl -OJ "http://localhost:8082/api/v1/extensions/provider/aws/1.2.0" curl -OJ "http://localhost:8082/api/v1/extensions/provider/aws/1.2.0"
```plaintext ```text
**Response**: **Response**:
@ -202,7 +203,7 @@ curl -OJ "http://localhost:8082/api/v1/extensions/provider/aws/1.2.0"
"error": "not_found", "error": "not_found",
"message": "Extension provider/aws version 1.2.0 not found" "message": "Extension provider/aws version 1.2.0 not found"
} }
```plaintext ```text
--- ---
@ -215,7 +216,7 @@ Search for extensions by name or description.
**Query Parameters**: **Query Parameters**:
| Parameter | Type | Required | Description | | Parameter | Type | Required | Description |
|-----------|------|----------|-------------| | ----------- | ------ | ---------- | ------------- |
| `q` | string | Yes | Search query (case-insensitive) | | `q` | string | Yes | Search query (case-insensitive) |
| `type` | string | No | Filter by extension type | | `type` | string | No | Filter by extension type |
| `limit` | integer | No | Maximum results (default: 50, max: 100) | | `limit` | integer | No | Maximum results (default: 50, max: 100) |
@ -224,7 +225,7 @@ Search for extensions by name or description.
```bash ```bash
curl "http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv&limit=5" curl "http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv&limit=5"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -249,7 +250,7 @@ curl "http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv&
"published_at": "2025-09-20T14:30:00Z" "published_at": "2025-09-20T14:30:00Z"
} }
] ]
```plaintext ```text
--- ---
@ -265,7 +266,7 @@ Check service health and backend status.
```bash ```bash
curl "http://localhost:8082/api/v1/health" curl "http://localhost:8082/api/v1/health"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -286,7 +287,7 @@ curl "http://localhost:8082/api/v1/health"
} }
} }
} }
```plaintext ```text
**Degraded Status** (200 OK): **Degraded Status** (200 OK):
@ -307,7 +308,7 @@ curl "http://localhost:8082/api/v1/health"
} }
} }
} }
```plaintext ```text
--- ---
@ -321,7 +322,7 @@ Get Prometheus-formatted metrics.
```bash ```bash
curl "http://localhost:8082/api/v1/metrics" curl "http://localhost:8082/api/v1/metrics"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -349,7 +350,7 @@ cache_misses_total 247
# HELP extensions_total Total extensions # HELP extensions_total Total extensions
# TYPE extensions_total gauge # TYPE extensions_total gauge
extensions_total 45 extensions_total 45
```plaintext ```text
--- ---
@ -363,7 +364,7 @@ Get cache performance statistics.
```bash ```bash
curl "http://localhost:8082/api/v1/cache/stats" curl "http://localhost:8082/api/v1/cache/stats"
```plaintext ```text
**Example Response** (200 OK): **Example Response** (200 OK):
@ -374,7 +375,7 @@ curl "http://localhost:8082/api/v1/cache/stats"
"version_entries": 80, "version_entries": 80,
"total_entries": 245 "total_entries": 245
} }
```plaintext ```text
--- ---
@ -388,12 +389,12 @@ All error responses follow this format:
"message": "Human-readable error message", "message": "Human-readable error message",
"details": "Optional additional details" "details": "Optional additional details"
} }
```plaintext ```text
### HTTP Status Codes ### HTTP Status Codes
| Status | Description | | Status | Description |
|--------|-------------| | -------- | ------------- |
| 200 OK | Request successful | | 200 OK | Request successful |
| 400 Bad Request | Invalid input (e.g., invalid extension type) | | 400 Bad Request | Invalid input (e.g., invalid extension type) |
| 401 Unauthorized | Authentication failed | | 401 Unauthorized | Authentication failed |
@ -405,7 +406,7 @@ All error responses follow this format:
### Error Types ### Error Types
| Error Type | HTTP Status | Description | | Error Type | HTTP Status | Description |
|------------|-------------|-------------| | ------------ | ------------- | ------------- |
| `not_found` | 404 | Extension or resource not found | | `not_found` | 404 | Extension or resource not found |
| `invalid_type` | 400 | Invalid extension type provided | | `invalid_type` | 400 | Invalid extension type provided |
| `invalid_version` | 400 | Invalid version format | | `invalid_version` | 400 | Invalid version format |
@ -435,19 +436,19 @@ interface Extension {
size?: number; // Size in bytes size?: number; // Size in bytes
tags?: string[]; // Tags tags?: string[]; // Tags
} }
```plaintext ```text
### ExtensionType ### ExtensionType
```typescript ```typescript
type ExtensionType = "provider" | "taskserv" | "cluster"; type ExtensionType = "provider" | "taskserv" | "cluster";
```plaintext ```text
### ExtensionSource ### ExtensionSource
```typescript ```typescript
type ExtensionSource = "gitea" | "oci"; type ExtensionSource = "gitea" | "oci";
```plaintext ```text
### ExtensionVersion ### ExtensionVersion
@ -459,7 +460,7 @@ interface ExtensionVersion {
checksum?: string; // Checksum checksum?: string; // Checksum
size?: number; // Size in bytes size?: number; // Size in bytes
} }
```plaintext ```text
### HealthResponse ### HealthResponse
@ -470,7 +471,7 @@ interface HealthResponse {
uptime: number; // Uptime in seconds uptime: number; // Uptime in seconds
backends: BackendHealth; // Backend health status backends: BackendHealth; // Backend health status
} }
```plaintext ```text
### BackendHealth ### BackendHealth
@ -479,7 +480,7 @@ interface BackendHealth {
gitea: BackendStatus; gitea: BackendStatus;
oci: BackendStatus; oci: BackendStatus;
} }
```plaintext ```text
### BackendStatus ### BackendStatus
@ -489,7 +490,7 @@ interface BackendStatus {
healthy: boolean; // Backend healthy healthy: boolean; // Backend healthy
error?: string; // Error message if unhealthy error?: string; // Error message if unhealthy
} }
```plaintext ```text
--- ---
@ -512,9 +513,9 @@ The service implements LRU caching with TTL:
- **Cache TTL**: Configurable (default: 5 minutes) - **Cache TTL**: Configurable (default: 5 minutes)
- **Cache Capacity**: Configurable (default: 1000 entries) - **Cache Capacity**: Configurable (default: 1000 entries)
- **Cache Keys**: - **Cache Keys**:
- List: `list:{type}:{source}` - List: `list:{type}:{source}`
- Metadata: `{type}/{name}` - Metadata: `{type}/{name}`
- Versions: `{type}/{name}/versions` - Versions: `{type}/{name}/versions`
Cache headers are not currently exposed. Future versions may include: Cache headers are not currently exposed. Future versions may include:
@ -550,7 +551,7 @@ curl -OJ "http://localhost:8082/api/v1/extensions/taskserv/kubernetes/1.28.0"
# 5. Verify checksum (if provided) # 5. Verify checksum (if provided)
sha256sum kubernetes_taskserv.tar.gz sha256sum kubernetes_taskserv.tar.gz
```plaintext ```text
### Pagination ### Pagination
@ -563,7 +564,7 @@ curl "http://localhost:8082/api/v1/extensions?limit=10&offset=10"
# Get third page # Get third page
curl "http://localhost:8082/api/v1/extensions?limit=10&offset=20" curl "http://localhost:8082/api/v1/extensions?limit=10&offset=20"
```plaintext ```text
### Filtering ### Filtering
@ -576,7 +577,7 @@ curl "http://localhost:8082/api/v1/extensions?type=taskserv&source=oci"
# All clusters # All clusters
curl "http://localhost:8082/api/v1/extensions?type=cluster" curl "http://localhost:8082/api/v1/extensions?type=cluster"
```plaintext ```text
--- ---

View File

@ -1,6 +1,7 @@
# Extension Registry Service # Extension Registry Service
A high-performance Rust microservice that provides a unified REST API for extension discovery, versioning, and download from multiple sources (Gitea releases and OCI registries). A high-performance Rust microservice that provides a unified REST API for extension discovery, versioning,
and download from multiple sources (Gitea releases and OCI registries).
## Features ## Features
@ -16,24 +17,29 @@ A high-performance Rust microservice that provides a unified REST API for extens
## Architecture ## Architecture
```plaintext ```plaintext
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ Extension Registry API │ │ Extension Registry API │
│ (axum) │ │ (axum) │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────
────────────┤
│ │ │ │
│ ┌────────────────┐ ┌────────────────┐ ┌──────────────┐ │ │ ┌────────────────┐ ┌────────────────┐
┌──────────────┐ │
│ │ Gitea Client │ │ OCI Client │ │ LRU Cache │ │ │ │ Gitea Client │ │ OCI Client │ │ LRU Cache │ │
│ │ (reqwest) │ │ (reqwest) │ │ (parking) │ │ │ │ (reqwest) │ │ (reqwest) │ │ (parking) │ │
│ └────────────────┘ └────────────────┘ └──────────────┘ │ │ └────────────────┘ └────────────────┘
└──────────────┘ │
│ │ │ │ │ │ │ │ │ │
└─────────┼────────────────────┼────────────────────┼─────────┘ └─────────┼────────────────────┼──────────────────
──┼─────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Gitea │ │ OCI │ │ Memory │ │ Gitea │ │ OCI │ │ Memory │
│ Releases │ │ Registry │ │ │ │ Releases │ │ Registry │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
```plaintext ```text
## Installation ## Installation
@ -42,19 +48,19 @@ A high-performance Rust microservice that provides a unified REST API for extens
```bash ```bash
cd provisioning/platform/extension-registry cd provisioning/platform/extension-registry
cargo build --release cargo build --release
```plaintext ```text
### Docker Build ### Docker Build
```bash ```bash
docker build -t extension-registry:latest . docker build -t extension-registry:latest .
```plaintext ```text
### Running with Cargo ### Running with Cargo
```bash ```bash
cargo run -- --config config.toml --port 8082 cargo run -- --config config.toml --port 8082
```plaintext ```text
### Running with Docker ### Running with Docker
@ -64,7 +70,7 @@ docker run -d \
-v $(pwd)/config.toml:/app/config.toml:ro \ -v $(pwd)/config.toml:/app/config.toml:ro \
-v $(pwd)/tokens:/app/tokens:ro \ -v $(pwd)/tokens:/app/tokens:ro \
extension-registry:latest extension-registry:latest
```plaintext ```text
## Configuration ## Configuration
@ -100,7 +106,7 @@ capacity = 1000
ttl_seconds = 300 ttl_seconds = 300
enable_metadata_cache = true enable_metadata_cache = true
enable_list_cache = true enable_list_cache = true
```plaintext ```text
**Note**: At least one backend (Gitea or OCI) must be configured. **Note**: At least one backend (Gitea or OCI) must be configured.
@ -112,7 +118,7 @@ enable_list_cache = true
```bash ```bash
GET /api/v1/extensions GET /api/v1/extensions
```plaintext ```text
Query parameters: Query parameters:
@ -125,7 +131,7 @@ Example:
```bash ```bash
curl http://localhost:8082/api/v1/extensions?type=provider&limit=10 curl http://localhost:8082/api/v1/extensions?type=provider&limit=10
```plaintext ```text
Response: Response:
@ -144,31 +150,31 @@ Response:
"size": 1024000 "size": 1024000
} }
] ]
```plaintext ```text
#### Get Extension #### Get Extension
```bash ```bash
GET /api/v1/extensions/{type}/{name} GET /api/v1/extensions/{type}/{name}
```plaintext ```text
Example: Example:
```bash ```bash
curl http://localhost:8082/api/v1/extensions/provider/aws curl http://localhost:8082/api/v1/extensions/provider/aws
```plaintext ```text
#### List Versions #### List Versions
```bash ```bash
GET /api/v1/extensions/{type}/{name}/versions GET /api/v1/extensions/{type}/{name}/versions
```plaintext ```text
Example: Example:
```bash ```bash
curl http://localhost:8082/api/v1/extensions/provider/aws/versions curl http://localhost:8082/api/v1/extensions/provider/aws/versions
```plaintext ```text
Response: Response:
@ -187,19 +193,19 @@ Response:
"size": 980000 "size": 980000
} }
] ]
```plaintext ```text
#### Download Extension #### Download Extension
```bash ```bash
GET /api/v1/extensions/{type}/{name}/{version} GET /api/v1/extensions/{type}/{name}/{version}
```plaintext ```text
Example: Example:
```bash ```bash
curl -O http://localhost:8082/api/v1/extensions/provider/aws/1.2.0 curl -O http://localhost:8082/api/v1/extensions/provider/aws/1.2.0
```plaintext ```text
Returns binary data with `Content-Type: application/octet-stream`. Returns binary data with `Content-Type: application/octet-stream`.
@ -207,7 +213,7 @@ Returns binary data with `Content-Type: application/octet-stream`.
```bash ```bash
GET /api/v1/extensions/search?q={query} GET /api/v1/extensions/search?q={query}
```plaintext ```text
Query parameters: Query parameters:
@ -219,7 +225,7 @@ Example:
```bash ```bash
curl http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv curl http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv
```plaintext ```text
### System Endpoints ### System Endpoints
@ -227,13 +233,13 @@ curl http://localhost:8082/api/v1/extensions/search?q=kubernetes&type=taskserv
```bash ```bash
GET /api/v1/health GET /api/v1/health
```plaintext ```text
Example: Example:
```bash ```bash
curl http://localhost:8082/api/v1/health curl http://localhost:8082/api/v1/health
```plaintext ```text
Response: Response:
@ -253,13 +259,13 @@ Response:
} }
} }
} }
```plaintext ```text
#### Metrics #### Metrics
```bash ```bash
GET /api/v1/metrics GET /api/v1/metrics
```plaintext ```text
Returns Prometheus-formatted metrics: Returns Prometheus-formatted metrics:
@ -275,13 +281,13 @@ cache_hits_total 567
# HELP cache_misses_total Total cache misses # HELP cache_misses_total Total cache misses
# TYPE cache_misses_total counter # TYPE cache_misses_total counter
cache_misses_total 123 cache_misses_total 123
```plaintext ```text
#### Cache Statistics #### Cache Statistics
```bash ```bash
GET /api/v1/cache/stats GET /api/v1/cache/stats
```plaintext ```text
Response: Response:
@ -292,7 +298,7 @@ Response:
"version_entries": 80, "version_entries": 80,
"total_entries": 245 "total_entries": 245
} }
```plaintext ```text
## Extension Naming Conventions ## Extension Naming Conventions
@ -351,7 +357,7 @@ Error response format:
"error": "not_found", "error": "not_found",
"message": "Extension provider/nonexistent not found" "message": "Extension provider/nonexistent not found"
} }
```plaintext ```text
## Metrics and Monitoring ## Metrics and Monitoring
@ -403,7 +409,7 @@ extension-registry/
│ └── integration_test.rs # Integration tests │ └── integration_test.rs # Integration tests
├── Dockerfile # Docker build ├── Dockerfile # Docker build
└── README.md # This file └── README.md # This file
```plaintext ```text
### Running Tests ### Running Tests
@ -416,7 +422,7 @@ cargo test -- --nocapture
# Run specific test # Run specific test
cargo test test_health_check cargo test test_health_check
```plaintext ```text
### Code Quality ### Code Quality
@ -429,7 +435,7 @@ cargo clippy
# Check for security vulnerabilities # Check for security vulnerabilities
cargo audit cargo audit
```plaintext ```text
## Deployment ## Deployment
@ -452,7 +458,7 @@ RestartSec=5s
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
```plaintext ```text
Enable and start: Enable and start:
@ -460,7 +466,7 @@ Enable and start:
sudo systemctl enable extension-registry sudo systemctl enable extension-registry
sudo systemctl start extension-registry sudo systemctl start extension-registry
sudo systemctl status extension-registry sudo systemctl status extension-registry
```plaintext ```text
### Docker Compose ### Docker Compose
@ -482,7 +488,7 @@ services:
timeout: 3s timeout: 3s
retries: 3 retries: 3
start_period: 5s start_period: 5s
```plaintext ```text
### Kubernetes Deployment ### Kubernetes Deployment
@ -543,7 +549,7 @@ spec:
- port: 8082 - port: 8082
targetPort: 8082 targetPort: 8082
type: ClusterIP type: ClusterIP
```plaintext ```text
## Security ## Security
@ -608,13 +614,13 @@ Enable debug logging:
```bash ```bash
extension-registry --log-level debug extension-registry --log-level debug
```plaintext ```text
Enable JSON logging for structured logs: Enable JSON logging for structured logs:
```bash ```bash
extension-registry --json-log extension-registry --json-log
```plaintext ```text
## License ## License

View File

@ -4,14 +4,13 @@ use std::sync::Arc;
use tracing::info; use tracing::info;
use super::traits::{DistributionClient, SourceClient};
use super::{ForgejoClient, GitHubClient};
use crate::config::Config; use crate::config::Config;
use crate::error::{RegistryError, Result}; use crate::error::{RegistryError, Result};
use crate::gitea::GiteaClient as GiteaClientImpl; use crate::gitea::GiteaClient as GiteaClientImpl;
use crate::oci::OciClient as OciClientImpl; use crate::oci::OciClient as OciClientImpl;
use super::traits::{DistributionClient, SourceClient};
use super::{ForgejoClient, GitHubClient};
/// Factory for creating extension clients /// Factory for creating extension clients
pub struct ClientFactory; pub struct ClientFactory;
@ -19,10 +18,7 @@ impl ClientFactory {
/// Create all configured clients from configuration /// Create all configured clients from configuration
pub fn create_from_config( pub fn create_from_config(
config: &Config, config: &Config,
) -> Result<( ) -> Result<(Vec<Arc<dyn SourceClient>>, Vec<Arc<dyn DistributionClient>>)> {
Vec<Arc<dyn SourceClient>>,
Vec<Arc<dyn DistributionClient>>,
)> {
let mut source_clients: Vec<Arc<dyn SourceClient>> = Vec::new(); let mut source_clients: Vec<Arc<dyn SourceClient>> = Vec::new();
let mut distribution_clients: Vec<Arc<dyn DistributionClient>> = Vec::new(); let mut distribution_clients: Vec<Arc<dyn DistributionClient>> = Vec::new();

View File

@ -8,11 +8,10 @@
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
use super::traits::{BackendType, ExtensionClient, ReleaseInfo, SourceClient};
use crate::error::Result; use crate::error::Result;
use crate::models::{Extension, ExtensionType, ExtensionVersion}; use crate::models::{Extension, ExtensionType, ExtensionVersion};
use super::traits::{BackendType, ExtensionClient, ReleaseInfo, SourceClient};
/// Forgejo client (wraps GiteaClient since Forgejo API is Gitea-compatible) /// Forgejo client (wraps GiteaClient since Forgejo API is Gitea-compatible)
pub struct ForgejoClient { pub struct ForgejoClient {
backend_id: String, backend_id: String,
@ -44,7 +43,10 @@ impl ExtensionClient for ForgejoClient {
BackendType::Forgejo BackendType::Forgejo
} }
async fn list_extensions(&self, extension_type: Option<ExtensionType>) -> Result<Vec<Extension>> { async fn list_extensions(
&self,
extension_type: Option<ExtensionType>,
) -> Result<Vec<Extension>> {
self.inner.list_extensions(extension_type).await self.inner.list_extensions(extension_type).await
} }
@ -66,7 +68,9 @@ impl ExtensionClient for ForgejoClient {
name: &str, name: &str,
version: &str, version: &str,
) -> Result<Bytes> { ) -> Result<Bytes> {
self.inner.download_extension(extension_type, name, version).await self.inner
.download_extension(extension_type, name, version)
.await
} }
async fn health_check(&self) -> Result<()> { async fn health_check(&self) -> Result<()> {
@ -77,7 +81,11 @@ impl ExtensionClient for ForgejoClient {
/// SourceClient trait implementation for Forgejo /// SourceClient trait implementation for Forgejo
#[async_trait] #[async_trait]
impl SourceClient for ForgejoClient { impl SourceClient for ForgejoClient {
async fn get_repository_url(&self, extension_type: ExtensionType, name: &str) -> Result<String> { async fn get_repository_url(
&self,
extension_type: ExtensionType,
name: &str,
) -> Result<String> {
self.inner.get_repository_url(extension_type, name).await self.inner.get_repository_url(extension_type, name).await
} }

View File

@ -1,19 +1,20 @@
//! GitHub client implementation //! GitHub client implementation
//! //!
//! Integrates with GitHub Releases API to fetch provisioning extensions. //! Integrates with GitHub Releases API to fetch provisioning extensions.
//! Extensions are identified as releases within repositories under a GitHub organization. //! Extensions are identified as releases within repositories under a GitHub
//! organization.
use std::time::Duration;
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
use reqwest::Client; use reqwest::Client;
use std::time::Duration;
use tracing::debug; use tracing::debug;
use super::traits::{BackendType, ExtensionClient, ReleaseAsset, ReleaseInfo, SourceClient};
use crate::error::{RegistryError, Result}; use crate::error::{RegistryError, Result};
use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion}; use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion};
use super::traits::{BackendType, ExtensionClient, ReleaseAsset, ReleaseInfo, SourceClient};
/// GitHub configuration (reused GiteaConfig for compatibility) /// GitHub configuration (reused GiteaConfig for compatibility)
pub struct GitHubClient { pub struct GitHubClient {
backend_id: String, backend_id: String,
@ -121,7 +122,10 @@ impl ExtensionClient for GitHubClient {
BackendType::GitHub BackendType::GitHub
} }
async fn list_extensions(&self, _extension_type: Option<ExtensionType>) -> Result<Vec<Extension>> { async fn list_extensions(
&self,
_extension_type: Option<ExtensionType>,
) -> Result<Vec<Extension>> {
debug!( debug!(
"Fetching repositories for GitHub organization: {}", "Fetching repositories for GitHub organization: {}",
self.organization self.organization
@ -135,9 +139,14 @@ impl ExtensionClient for GitHubClient {
async fn get_extension(&self, extension_type: ExtensionType, name: &str) -> Result<Extension> { async fn get_extension(&self, extension_type: ExtensionType, name: &str) -> Result<Extension> {
let repo_name = self.format_repo_name(extension_type, name); let repo_name = self.format_repo_name(extension_type, name);
debug!("Fetching GitHub extension: {}/{}", self.organization, repo_name); debug!(
"Fetching GitHub extension: {}/{}",
self.organization, repo_name
);
let releases = self.list_releases_internal(&self.organization, &repo_name).await?; let releases = self
.list_releases_internal(&self.organization, &repo_name)
.await?;
let latest = releases let latest = releases
.iter() .iter()
@ -181,9 +190,14 @@ impl ExtensionClient for GitHubClient {
name: &str, name: &str,
) -> Result<Vec<ExtensionVersion>> { ) -> Result<Vec<ExtensionVersion>> {
let repo_name = self.format_repo_name(extension_type, name); let repo_name = self.format_repo_name(extension_type, name);
debug!("Fetching GitHub versions for: {}/{}", self.organization, repo_name); debug!(
"Fetching GitHub versions for: {}/{}",
self.organization, repo_name
);
let releases = self.list_releases_internal(&self.organization, &repo_name).await?; let releases = self
.list_releases_internal(&self.organization, &repo_name)
.await?;
Ok(releases Ok(releases
.into_iter() .into_iter()
@ -210,7 +224,9 @@ impl ExtensionClient for GitHubClient {
self.organization, repo_name, version self.organization, repo_name, version
); );
let releases = self.list_releases_internal(&self.organization, &repo_name).await?; let releases = self
.list_releases_internal(&self.organization, &repo_name)
.await?;
let release = releases let release = releases
.iter() .iter()
@ -274,7 +290,11 @@ impl ExtensionClient for GitHubClient {
/// SourceClient trait implementation for GitHub /// SourceClient trait implementation for GitHub
#[async_trait] #[async_trait]
impl SourceClient for GitHubClient { impl SourceClient for GitHubClient {
async fn get_repository_url(&self, extension_type: ExtensionType, name: &str) -> Result<String> { async fn get_repository_url(
&self,
extension_type: ExtensionType,
name: &str,
) -> Result<String> {
let repo_name = self.format_repo_name(extension_type, name); let repo_name = self.format_repo_name(extension_type, name);
Ok(format!( Ok(format!(
"https://github.com/{}/{}", "https://github.com/{}/{}",
@ -283,7 +303,9 @@ impl SourceClient for GitHubClient {
} }
async fn list_releases(&self, repo_name: &str) -> Result<Vec<ReleaseInfo>> { async fn list_releases(&self, repo_name: &str) -> Result<Vec<ReleaseInfo>> {
let releases = self.list_releases_internal(&self.organization, repo_name).await?; let releases = self
.list_releases_internal(&self.organization, repo_name)
.await?;
Ok(releases Ok(releases
.into_iter() .into_iter()
.map(|r| ReleaseInfo { .map(|r| ReleaseInfo {
@ -305,7 +327,9 @@ impl SourceClient for GitHubClient {
} }
async fn get_release_notes(&self, repo_name: &str, version: &str) -> Result<String> { async fn get_release_notes(&self, repo_name: &str, version: &str) -> Result<String> {
let releases = self.list_releases_internal(&self.organization, repo_name).await?; let releases = self
.list_releases_internal(&self.organization, repo_name)
.await?;
let release = releases let release = releases
.iter() .iter()
.find(|r| r.tag_name == version) .find(|r| r.tag_name == version)

View File

@ -33,7 +33,10 @@ pub trait ExtensionClient: Send + Sync {
fn backend_type(&self) -> BackendType; fn backend_type(&self) -> BackendType;
/// List all extensions available from this backend /// List all extensions available from this backend
async fn list_extensions(&self, extension_type: Option<ExtensionType>) -> Result<Vec<Extension>>; async fn list_extensions(
&self,
extension_type: Option<ExtensionType>,
) -> Result<Vec<Extension>>;
/// Get specific extension metadata /// Get specific extension metadata
async fn get_extension(&self, extension_type: ExtensionType, name: &str) -> Result<Extension>; async fn get_extension(&self, extension_type: ExtensionType, name: &str) -> Result<Extension>;
@ -65,7 +68,8 @@ pub trait ExtensionClient: Send + Sync {
#[async_trait] #[async_trait]
pub trait SourceClient: ExtensionClient { pub trait SourceClient: ExtensionClient {
/// Get repository URL for an extension /// Get repository URL for an extension
async fn get_repository_url(&self, extension_type: ExtensionType, name: &str) -> Result<String>; async fn get_repository_url(&self, extension_type: ExtensionType, name: &str)
-> Result<String>;
/// List all releases for a repository /// List all releases for a repository
/// ///

View File

@ -6,11 +6,13 @@ use reqwest::Client;
use tracing::debug; use tracing::debug;
use url::Url; use url::Url;
use crate::client::traits::{
BackendType, ExtensionClient, ReleaseAsset, ReleaseInfo, SourceClient,
};
use crate::config::GiteaConfig; use crate::config::GiteaConfig;
use crate::error::{RegistryError, Result}; use crate::error::{RegistryError, Result};
use crate::gitea::models::{GiteaRelease, GiteaRepository}; use crate::gitea::models::{GiteaRelease, GiteaRepository};
use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion}; use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion};
use crate::client::traits::{BackendType, ExtensionClient, ReleaseAsset, ReleaseInfo, SourceClient};
/// Gitea API client /// Gitea API client
pub struct GiteaClient { pub struct GiteaClient {
@ -432,7 +434,10 @@ impl ExtensionClient for GiteaClient {
BackendType::Gitea BackendType::Gitea
} }
async fn list_extensions(&self, extension_type: Option<ExtensionType>) -> Result<Vec<Extension>> { async fn list_extensions(
&self,
extension_type: Option<ExtensionType>,
) -> Result<Vec<Extension>> {
GiteaClient::list_extensions(self, extension_type).await GiteaClient::list_extensions(self, extension_type).await
} }
@ -465,7 +470,11 @@ impl ExtensionClient for GiteaClient {
/// SourceClient trait implementation for Gitea /// SourceClient trait implementation for Gitea
#[async_trait] #[async_trait]
impl SourceClient for GiteaClient { impl SourceClient for GiteaClient {
async fn get_repository_url(&self, extension_type: ExtensionType, name: &str) -> Result<String> { async fn get_repository_url(
&self,
extension_type: ExtensionType,
name: &str,
) -> Result<String> {
let repo_name = self.format_repo_name(extension_type, name); let repo_name = self.format_repo_name(extension_type, name);
let repo = self.get_repository(&repo_name).await?; let repo = self.get_repository(&repo_name).await?;
Ok(repo.html_url) Ok(repo.html_url)

View File

@ -6,11 +6,13 @@ use chrono::Utc;
use reqwest::Client; use reqwest::Client;
use tracing::debug; use tracing::debug;
use crate::client::traits::{
BackendType, DistributionClient, ExtensionClient, LayerInfo, ManifestInfo,
};
use crate::config::OciConfig; use crate::config::OciConfig;
use crate::error::{RegistryError, Result}; use crate::error::{RegistryError, Result};
use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion}; use crate::models::{Extension, ExtensionSource, ExtensionType, ExtensionVersion};
use crate::oci::models::{OciCatalog, OciManifest, OciTagsList}; use crate::oci::models::{OciCatalog, OciManifest, OciTagsList};
use crate::client::traits::{BackendType, DistributionClient, ExtensionClient, LayerInfo, ManifestInfo};
/// OCI registry client /// OCI registry client
pub struct OciClient { pub struct OciClient {
@ -416,7 +418,10 @@ impl ExtensionClient for OciClient {
BackendType::Oci BackendType::Oci
} }
async fn list_extensions(&self, extension_type: Option<ExtensionType>) -> Result<Vec<Extension>> { async fn list_extensions(
&self,
extension_type: Option<ExtensionType>,
) -> Result<Vec<Extension>> {
OciClient::list_extensions(self, extension_type).await OciClient::list_extensions(self, extension_type).await
} }
@ -451,8 +456,8 @@ impl ExtensionClient for OciClient {
impl DistributionClient for OciClient { impl DistributionClient for OciClient {
async fn get_manifest(&self, repo_name: &str, tag: &str) -> Result<ManifestInfo> { async fn get_manifest(&self, repo_name: &str, tag: &str) -> Result<ManifestInfo> {
let manifest = self.get_manifest(repo_name, tag).await?; let manifest = self.get_manifest(repo_name, tag).await?;
let total_size: u64 = manifest.layers.iter().map(|l| l.size).sum::<u64>() let total_size: u64 =
+ manifest.config.size; manifest.layers.iter().map(|l| l.size).sum::<u64>() + manifest.config.size;
Ok(ManifestInfo { Ok(ManifestInfo {
config_digest: manifest.config.digest, config_digest: manifest.config.digest,

View File

@ -1,8 +1,8 @@
use axum::body::Body; use axum::body::Body;
use axum::http::{Request, StatusCode}; use axum::http::{Request, StatusCode};
use extension_registry::{build_routes, AppState, Config}; use extension_registry::{build_routes, AppState, Config};
use tower::ServiceExt;
use http_body_util::BodyExt; use http_body_util::BodyExt;
use tower::ServiceExt;
#[tokio::test] #[tokio::test]
async fn test_health_check() { async fn test_health_check() {

View File

@ -2,7 +2,9 @@
## Overview ## Overview
A **Rust-native Model Context Protocol (MCP) server** for infrastructure automation and AI-assisted DevOps operations. This replaces the Python implementation, providing significant performance improvements and maintaining philosophical consistency with the Rust ecosystem approach. A **Rust-native Model Context Protocol (MCP) server** for infrastructure automation and AI-assisted DevOps operations.
This replaces the Python implementation, providing significant performance improvements and maintaining philosophical consistency
with the Rust ecosystem approach.
## ✅ Project Status: **PROOF OF CONCEPT COMPLETE** ## ✅ Project Status: **PROOF OF CONCEPT COMPLETE**
@ -37,7 +39,7 @@ A **Rust-native Model Context Protocol (MCP) server** for infrastructure automat
• Configuration access: Microsecond latency • Configuration access: Microsecond latency
• Memory efficient: Small struct footprint • Memory efficient: Small struct footprint
• Zero-copy string operations where possible • Zero-copy string operations where possible
```plaintext ```text
### 🏗️ Architecture ### 🏗️ Architecture
@ -51,7 +53,7 @@ src/
├── tools.rs # AI-powered parsing tools ├── tools.rs # AI-powered parsing tools
├── errors.rs # Error handling ├── errors.rs # Error handling
└── performance_test.rs # Performance benchmarking └── performance_test.rs # Performance benchmarking
```plaintext ```text
### 🎲 Key Features ### 🎲 Key Features
@ -64,7 +66,7 @@ src/
### 📊 Rust vs Python Comparison ### 📊 Rust vs Python Comparison
| Metric | Python MCP Server | Rust MCP Server | Improvement | | Metric | Python MCP Server | Rust MCP Server | Improvement |
|--------|------------------|-----------------|-------------| | -------- | ------------------ | ----------------- | ------------- |
| **Startup Time** | ~500ms | ~50ms | **10x faster** | | **Startup Time** | ~500ms | ~50ms | **10x faster** |
| **Memory Usage** | ~50MB | ~5MB | **10x less** | | **Memory Usage** | ~50MB | ~5MB | **10x less** |
| **Parsing Latency** | ~1ms | ~0.001ms | **1000x faster** | | **Parsing Latency** | ~1ms | ~0.001ms | **1000x faster** |
@ -85,7 +87,7 @@ cargo test
# Run benchmarks # Run benchmarks
cargo run --bin provisioning-mcp-server --release cargo run --bin provisioning-mcp-server --release
```plaintext ```text
### 🔧 Configuration ### 🔧 Configuration
@ -96,7 +98,7 @@ export PROVISIONING_PATH=/path/to/provisioning
export PROVISIONING_AI_PROVIDER=openai export PROVISIONING_AI_PROVIDER=openai
export OPENAI_API_KEY=your-key export OPENAI_API_KEY=your-key
export PROVISIONING_DEBUG=true export PROVISIONING_DEBUG=true
```plaintext ```text
### 📈 Integration Benefits ### 📈 Integration Benefits

View File

@ -1,6 +1,7 @@
# Provisioning Orchestrator # Provisioning Orchestrator
A Rust-based orchestrator service that coordinates infrastructure provisioning workflows with pluggable storage backends and comprehensive migration tools. A Rust-based orchestrator service that coordinates infrastructure provisioning workflows with pluggable storage backends and comprehensive migration
tools.
## Architecture ## Architecture
@ -36,7 +37,7 @@ The orchestrator implements a hybrid multi-storage approach:
cd src/orchestrator cd src/orchestrator
cargo build --release cargo build --release
cargo run -- --port 8080 --data-dir ./data cargo run -- --port 8080 --data-dir ./data
```plaintext ```text
**With SurrealDB Support**: **With SurrealDB Support**:
@ -51,7 +52,7 @@ cargo run --features surrealdb -- --storage-type surrealdb-embedded --data-dir .
cargo run --features surrealdb -- --storage-type surrealdb-server \ cargo run --features surrealdb -- --storage-type surrealdb-server \
--surrealdb-url ws://localhost:8000 \ --surrealdb-url ws://localhost:8000 \
--surrealdb-username admin --surrealdb-password secret --surrealdb-username admin --surrealdb-password secret
```plaintext ```text
### Submit a Server Creation Workflow ### Submit a Server Creation Workflow
@ -65,19 +66,19 @@ curl -X POST http://localhost:8080/workflows/servers/create \
"check_mode": false, "check_mode": false,
"wait": true "wait": true
}' }'
```plaintext ```text
### Check Task Status ### Check Task Status
```bash ```bash
curl http://localhost:8080/tasks/{task_id} curl http://localhost:8080/tasks/{task_id}
```plaintext ```text
### List All Tasks ### List All Tasks
```bash ```bash
curl http://localhost:8080/tasks curl http://localhost:8080/tasks
```plaintext ```text
## API Endpoints ## API Endpoints
@ -107,7 +108,8 @@ curl http://localhost:8080/tasks
## Test Environment Service ## Test Environment Service
The orchestrator includes a comprehensive test environment service for automated containerized testing of taskservs, complete servers, and multi-node clusters. The orchestrator includes a comprehensive test environment service for automated containerized testing
of taskservs, complete servers, and multi-node clusters.
### Overview ### Overview
@ -142,7 +144,7 @@ curl -X POST http://localhost:8080/test/environments/create \
"auto_start": true, "auto_start": true,
"auto_cleanup": false "auto_cleanup": false
}' }'
```plaintext ```text
#### 2. Server Simulation #### 2. Server Simulation
@ -161,7 +163,7 @@ curl -X POST http://localhost:8080/test/environments/create \
"infra": "prod-stack", "infra": "prod-stack",
"auto_start": true "auto_start": true
}' }'
```plaintext ```text
#### 3. Cluster Topology #### 3. Cluster Topology
@ -202,7 +204,7 @@ curl -X POST http://localhost:8080/test/environments/create \
}, },
"auto_start": true "auto_start": true
}' }'
```plaintext ```text
### Nushell CLI Integration ### Nushell CLI Integration
@ -232,7 +234,7 @@ provisioning test env logs <env-id>
# Cleanup # Cleanup
provisioning test env cleanup <env-id> provisioning test env cleanup <env-id>
```plaintext ```text
### Topology Templates ### Topology Templates
@ -274,7 +276,7 @@ Isolated Test Containers
• Resource limits • Resource limits
• Volume mounts • Volume mounts
• Multi-node support • Multi-node support
```plaintext ```text
### Key Components ### Key Components
@ -311,7 +313,7 @@ test-infrastructure:
- provisioning test quick kubernetes - provisioning test quick kubernetes
- provisioning test quick postgres - provisioning test quick postgres
- provisioning test quick redis - provisioning test quick redis
```plaintext ```text
### Documentation ### Documentation
@ -342,7 +344,7 @@ For complete usage guide and examples, see:
### Storage Backend Comparison ### Storage Backend Comparison
| Feature | Filesystem | SurrealDB Embedded | SurrealDB Server | | Feature | Filesystem | SurrealDB Embedded | SurrealDB Server |
|---------|------------|-------------------|------------------| | --------- | ------------ | ------------------- | ------------------ |
| **Dependencies** | None | Local database | Remote server | | **Dependencies** | None | Local database | Remote server |
| **Auth/RBAC** | Basic | Advanced | Advanced | | **Auth/RBAC** | Basic | Advanced | Advanced |
| **Real-time** | No | Yes | Yes | | **Real-time** | No | Yes | Yes |
@ -364,7 +366,7 @@ workflow status $task_id
# List all workflows # List all workflows
workflow list workflow list
```plaintext ```text
## Task States ## Task States
@ -415,7 +417,7 @@ Seamless migration between storage backends:
# Validate migration setup # Validate migration setup
./scripts/migrate-storage.nu validate --from filesystem --to surrealdb-server ./scripts/migrate-storage.nu validate --from filesystem --to surrealdb-server
```plaintext ```text
## Error Handling ## Error Handling
@ -448,8 +450,8 @@ Seamless migration between storage backends:
**Optional Dependencies** (feature-gated): **Optional Dependencies** (feature-gated):
- **surrealdb**: Multi-model database (requires `--features surrealdb`) - **surrealdb**: Multi-model database (requires `--features surrealdb`)
- Embedded mode: RocksDB storage engine - Embedded mode: RocksDB storage engine
- Server mode: WebSocket/HTTP client - Server mode: WebSocket/HTTP client
### Adding New Workflows ### Adding New Workflows
@ -473,7 +475,7 @@ cargo test --features surrealdb
cargo test --test storage_integration cargo test --test storage_integration
cargo test --test migration_tests cargo test --test migration_tests
cargo test --test factory_tests cargo test --test factory_tests
```plaintext ```text
**Performance Benchmarks**: **Performance Benchmarks**:
@ -487,7 +489,7 @@ cargo bench --bench migration_benchmarks
# Generate HTML reports # Generate HTML reports
cargo bench --features surrealdb cargo bench --features surrealdb
open target/criterion/reports/index.html open target/criterion/reports/index.html
```plaintext ```text
**Test Configuration**: **Test Configuration**:
@ -498,7 +500,7 @@ TEST_STORAGE=surrealdb-embedded cargo test --features surrealdb
# Verbose testing # Verbose testing
cargo test -- --nocapture cargo test -- --nocapture
```plaintext ```text
## Migration from Deep Call Stack Issues ## Migration from Deep Call Stack Issues
@ -509,4 +511,5 @@ This orchestrator solves the Nushell deep call stack limitations by:
3. Managing parallel execution externally 3. Managing parallel execution externally
4. Preserving all existing business logic in Nushell 4. Preserving all existing business logic in Nushell
The existing `on_create_servers` function can be replaced with `on_create_servers_workflow` for orchestrated execution while maintaining full compatibility. The existing `on_create_servers` function can be replaced with `on_create_servers_workflow` for orchestrated execution while maintaining full
compatibility.

View File

@ -32,7 +32,7 @@ The DNS integration module provides automatic DNS registration and management fo
│ CoreDNS │ │ CoreDNS │
│ Service │ │ Service │
└─────────────────┘ └─────────────────┘
```plaintext ```text
## Features ## Features
@ -44,7 +44,7 @@ When a server is created, the orchestrator automatically registers its DNS recor
// In server creation workflow // In server creation workflow
let ip = server.get_ip_address(); let ip = server.get_ip_address();
state.dns_manager.register_server_dns(&hostname, ip).await?; state.dns_manager.register_server_dns(&hostname, ip).await?;
```plaintext ```text
### 2. DNS Record Types ### 2. DNS Record Types
@ -64,7 +64,7 @@ let verified = state.dns_manager.verify_dns_resolution("server.example.com").awa
if verified { if verified {
info!("DNS resolution verified"); info!("DNS resolution verified");
} }
```plaintext ```text
### 4. Automatic Cleanup ### 4. Automatic Cleanup
@ -72,7 +72,7 @@ When a server is deleted, DNS records are automatically removed:
```rust ```rust
state.dns_manager.unregister_server_dns(&hostname).await?; state.dns_manager.unregister_server_dns(&hostname).await?;
```plaintext ```text
## Configuration ## Configuration
@ -83,7 +83,7 @@ DNS settings in `config.defaults.toml`:
coredns_url = "http://localhost:53" coredns_url = "http://localhost:53"
auto_register = true auto_register = true
ttl = 300 ttl = 300
```plaintext ```text
### Configuration Options ### Configuration Options
@ -97,7 +97,7 @@ ttl = 300
```http ```http
GET /api/v1/dns/records GET /api/v1/dns/records
```plaintext ```text
**Response:** **Response:**
@ -113,7 +113,7 @@ GET /api/v1/dns/records
} }
] ]
} }
```plaintext ```text
## Usage Examples ## Usage Examples
@ -124,20 +124,20 @@ use std::net::IpAddr;
let ip: IpAddr = "192.168.1.10".parse()?; let ip: IpAddr = "192.168.1.10".parse()?;
dns_manager.register_server_dns("web-01.example.com", ip).await?; dns_manager.register_server_dns("web-01.example.com", ip).await?;
```plaintext ```text
### Unregister Server DNS ### Unregister Server DNS
```rust ```rust
dns_manager.unregister_server_dns("web-01.example.com").await?; dns_manager.unregister_server_dns("web-01.example.com").await?;
```plaintext ```text
### Update DNS Record ### Update DNS Record
```rust ```rust
let new_ip: IpAddr = "192.168.1.20".parse()?; let new_ip: IpAddr = "192.168.1.20".parse()?;
dns_manager.update_dns_record("web-01.example.com", new_ip).await?; dns_manager.update_dns_record("web-01.example.com", new_ip).await?;
```plaintext ```text
### List All Records ### List All Records
@ -146,7 +146,7 @@ let records = dns_manager.list_records().await?;
for record in records { for record in records {
println!("{} -> {} ({})", record.name, record.value, record.record_type); println!("{} -> {} ({})", record.name, record.value, record.record_type);
} }
```plaintext ```text
## Integration with Workflows ## Integration with Workflows
@ -180,7 +180,7 @@ Run DNS integration tests:
```bash ```bash
cd provisioning/platform/orchestrator cd provisioning/platform/orchestrator
cargo test test_dns_integration cargo test test_dns_integration
```plaintext ```text
## Troubleshooting ## Troubleshooting

View File

@ -32,7 +32,7 @@ The extension loading module provides dynamic loading of providers, taskservs, a
│ Nushell Scripts │ │ Nushell Scripts │
│ (module load) │ │ (module load) │
└──────────────────┘ └──────────────────┘
```plaintext ```text
## Extension Types ## Extension Types
@ -46,7 +46,7 @@ let provider = extension_manager.load_extension(
"aws".to_string(), "aws".to_string(),
Some("2.0.0".to_string()) Some("2.0.0".to_string())
).await?; ).await?;
```plaintext ```text
### 2. Taskservs ### 2. Taskservs
@ -58,7 +58,7 @@ let taskserv = extension_manager.load_extension(
"kubernetes".to_string(), "kubernetes".to_string(),
None // Load latest version None // Load latest version
).await?; ).await?;
```plaintext ```text
### 3. Clusters ### 3. Clusters
@ -70,7 +70,7 @@ let cluster = extension_manager.load_extension(
"buildkit".to_string(), "buildkit".to_string(),
Some("1.0.0".to_string()) Some("1.0.0".to_string())
).await?; ).await?;
```plaintext ```text
## Features ## Features
@ -102,7 +102,7 @@ pub struct ExtensionMetadata {
pub author: Option<String>, pub author: Option<String>,
pub repository: Option<String>, pub repository: Option<String>,
} }
```plaintext ```text
### Version Management ### Version Management
@ -122,7 +122,7 @@ let ext = extension_manager.load_extension(
"kubernetes".to_string(), "kubernetes".to_string(),
None None
).await?; ).await?;
```plaintext ```text
## Configuration ## Configuration
@ -132,7 +132,7 @@ Extension settings in `config.defaults.toml`:
[orchestrator.extensions] [orchestrator.extensions]
auto_load = true auto_load = true
cache_dir = "{{orchestrator.paths.data_dir}}/extensions" cache_dir = "{{orchestrator.paths.data_dir}}/extensions"
```plaintext ```text
### Configuration Options ### Configuration Options
@ -145,7 +145,7 @@ cache_dir = "{{orchestrator.paths.data_dir}}/extensions"
```http ```http
GET /api/v1/extensions/loaded GET /api/v1/extensions/loaded
```plaintext ```text
**Response:** **Response:**
@ -168,7 +168,7 @@ GET /api/v1/extensions/loaded
} }
] ]
} }
```plaintext ```text
### Reload Extension ### Reload Extension
@ -180,7 +180,7 @@ Content-Type: application/json
"extension_type": "taskserv", "extension_type": "taskserv",
"name": "kubernetes" "name": "kubernetes"
} }
```plaintext ```text
**Response:** **Response:**
@ -189,7 +189,7 @@ Content-Type: application/json
"success": true, "success": true,
"data": "Extension kubernetes reloaded" "data": "Extension kubernetes reloaded"
} }
```plaintext ```text
## Usage Examples ## Usage Examples
@ -210,7 +210,7 @@ let extension = manager.load_extension(
).await?; ).await?;
println!("Loaded: {} v{}", extension.metadata.name, extension.metadata.version); println!("Loaded: {} v{}", extension.metadata.name, extension.metadata.version);
```plaintext ```text
### List Loaded Extensions ### List Loaded Extensions
@ -223,7 +223,7 @@ for ext in extensions {
ext.loaded_at ext.loaded_at
); );
} }
```plaintext ```text
### Reload Extension ### Reload Extension
@ -232,7 +232,7 @@ let extension = manager.reload_extension(
ExtensionType::Taskserv, ExtensionType::Taskserv,
"kubernetes".to_string() "kubernetes".to_string()
).await?; ).await?;
```plaintext ```text
### Check if Loaded ### Check if Loaded
@ -250,13 +250,13 @@ if !is_loaded {
None None
).await?; ).await?;
} }
```plaintext ```text
### Clear Cache ### Clear Cache
```rust ```rust
manager.clear_cache().await; manager.clear_cache().await;
```plaintext ```text
## Integration with Workflows ## Integration with Workflows
@ -282,7 +282,7 @@ for dep in &extension.metadata.dependencies {
} }
// Continue with installation... // Continue with installation...
```plaintext ```text
## Nushell Integration ## Nushell Integration
@ -297,7 +297,7 @@ provisioning module discover taskserv --output json
# Get extension metadata # Get extension metadata
provisioning module discover taskserv --name kubernetes --output json provisioning module discover taskserv --name kubernetes --output json
```plaintext ```text
## Error Handling ## Error Handling
@ -315,7 +315,7 @@ Run extension loading tests:
```bash ```bash
cd provisioning/platform/orchestrator cd provisioning/platform/orchestrator
cargo test test_extension_loading cargo test test_extension_loading
```plaintext ```text
## Troubleshooting ## Troubleshooting
@ -357,7 +357,7 @@ let total_loads = metrics.total_extension_loads;
let cache_hits = metrics.cache_hits; let cache_hits = metrics.cache_hits;
let hit_ratio = cache_hits as f64 / total_loads as f64; let hit_ratio = cache_hits as f64 / total_loads as f64;
println!("Cache hit ratio: {:.2}%", hit_ratio * 100.0); println!("Cache hit ratio: {:.2}%", hit_ratio * 100.0);
```plaintext ```text
### Loading Time ### Loading Time

View File

@ -32,7 +32,7 @@ The OCI integration module provides OCI Distribution Spec v2 compliant registry
│ OCI Registry │ │ OCI Registry │
│ (HTTP API v2) │ │ (HTTP API v2) │
└──────────────────┘ └──────────────────┘
```plaintext ```text
## Features ## Features
@ -45,7 +45,7 @@ let package_path = oci_manager.pull_kcl_package(
"provisioning-core", "provisioning-core",
"1.0.0" "1.0.0"
).await?; ).await?;
```plaintext ```text
### 2. Extension Artifacts ### 2. Extension Artifacts
@ -57,7 +57,7 @@ let artifact_path = oci_manager.pull_extension_artifact(
"kubernetes", // Extension name "kubernetes", // Extension name
"1.28.0" // Version "1.28.0" // Version
).await?; ).await?;
```plaintext ```text
### 3. Manifest Caching ### 3. Manifest Caching
@ -76,7 +76,7 @@ let artifacts = oci_manager.list_oci_artifacts("kcl").await?;
for artifact in artifacts { for artifact in artifacts {
println!("{} v{} ({})", artifact.name, artifact.version, artifact.size); println!("{} v{} ({})", artifact.name, artifact.version, artifact.size);
} }
```plaintext ```text
## OCI Distribution Spec v2 ## OCI Distribution Spec v2
@ -96,7 +96,7 @@ OCI settings in `config.defaults.toml`:
registry_url = "http://localhost:5000" registry_url = "http://localhost:5000"
namespace = "provisioning-extensions" namespace = "provisioning-extensions"
cache_dir = "{{orchestrator.paths.data_dir}}/oci-cache" cache_dir = "{{orchestrator.paths.data_dir}}/oci-cache"
```plaintext ```text
### Configuration Options ### Configuration Options
@ -115,7 +115,7 @@ Content-Type: application/json
{ {
"namespace": "kcl" "namespace": "kcl"
} }
```plaintext ```text
**Response:** **Response:**
@ -133,7 +133,7 @@ Content-Type: application/json
} }
] ]
} }
```plaintext ```text
## Usage Examples ## Usage Examples
@ -159,7 +159,7 @@ println!("Package downloaded to: {}", package_path.display());
// Extract package // Extract package
// tar -xzf package_path // tar -xzf package_path
```plaintext ```text
### Pull Extension Artifact ### Pull Extension Artifact
@ -173,7 +173,7 @@ let artifact_path = oci_manager.pull_extension_artifact(
// Extract and install // Extract and install
// tar -xzf artifact_path -C /target/path // tar -xzf artifact_path -C /target/path
```plaintext ```text
### List Artifacts ### List Artifacts
@ -186,7 +186,7 @@ for artifact in artifacts {
println!(" Digest: {}", artifact.digest); println!(" Digest: {}", artifact.digest);
println!(); println!();
} }
```plaintext ```text
### Check Artifact Exists ### Check Artifact Exists
@ -201,7 +201,7 @@ if exists {
} else { } else {
println!("Artifact not found"); println!("Artifact not found");
} }
```plaintext ```text
### Get Manifest (with caching) ### Get Manifest (with caching)
@ -214,13 +214,13 @@ let manifest = oci_manager.get_manifest(
println!("Schema version: {}", manifest.schema_version); println!("Schema version: {}", manifest.schema_version);
println!("Media type: {}", manifest.media_type); println!("Media type: {}", manifest.media_type);
println!("Layers: {}", manifest.layers.len()); println!("Layers: {}", manifest.layers.len());
```plaintext ```text
### Clear Manifest Cache ### Clear Manifest Cache
```rust ```rust
oci_manager.clear_cache().await; oci_manager.clear_cache().await;
```plaintext ```text
## OCI Artifact Structure ## OCI Artifact Structure
@ -247,7 +247,7 @@ oci_manager.clear_cache().await;
"org.opencontainers.image.version": "1.0.0" "org.opencontainers.image.version": "1.0.0"
} }
} }
```plaintext ```text
## Integration with Workflows ## Integration with Workflows
@ -284,7 +284,7 @@ async fn install_taskserv_from_oci(
Ok(()) Ok(())
} }
```plaintext ```text
## Cache Management ## Cache Management
@ -305,7 +305,7 @@ async fn install_taskserv_from_oci(
│ └── aws/ │ └── aws/
│ └── 2.0.0/ │ └── 2.0.0/
│ └── artifact.tar.gz │ └── artifact.tar.gz
```plaintext ```text
### Cache Cleanup ### Cache Cleanup
@ -330,7 +330,7 @@ async fn cleanup_old_artifacts(cache_dir: &Path, max_age_days: u64) -> Result<()
Ok(()) Ok(())
} }
```plaintext ```text
## Error Handling ## Error Handling
@ -348,7 +348,7 @@ Run OCI integration tests:
```bash ```bash
cd provisioning/platform/orchestrator cd provisioning/platform/orchestrator
cargo test test_oci_integration cargo test test_oci_integration
```plaintext ```text
## Troubleshooting ## Troubleshooting

View File

@ -32,7 +32,7 @@ The service orchestration module manages platform services with dependency-based
│ Platform Services │ │ Platform Services │
│ (CoreDNS, OCI, etc) │ │ (CoreDNS, OCI, etc) │
└──────────────────────┘ └──────────────────────┘
```plaintext ```text
## Features ## Features
@ -46,7 +46,7 @@ let order = service_orchestrator.resolve_startup_order(&[
]).await?; ]).await?;
// Returns: ["service-a", "service-b", "service-c"] // Returns: ["service-a", "service-b", "service-c"]
```plaintext ```text
### 2. Automatic Dependency Startup ### 2. Automatic Dependency Startup
@ -57,7 +57,7 @@ When enabled, dependencies are started automatically:
service_orchestrator.start_service("web-app").await?; service_orchestrator.start_service("web-app").await?;
// Automatically starts: database -> cache -> web-app // Automatically starts: database -> cache -> web-app
```plaintext ```text
### 3. Health Checking ### 3. Health Checking
@ -69,7 +69,7 @@ let health = service_orchestrator.check_service_health("web-app").await?;
if health.healthy { if health.healthy {
println!("Service is healthy: {}", health.message); println!("Service is healthy: {}", health.message);
} }
```plaintext ```text
### 4. Service Status ### 4. Service Status
@ -84,7 +84,7 @@ match status {
ServiceStatus::Failed => println!("Service has failed"), ServiceStatus::Failed => println!("Service has failed"),
ServiceStatus::Unknown => println!("Service status unknown"), ServiceStatus::Unknown => println!("Service status unknown"),
} }
```plaintext ```text
## Service Definition ## Service Definition
@ -99,7 +99,7 @@ pub struct Service {
pub stop_command: String, pub stop_command: String,
pub health_check_endpoint: Option<String>, pub health_check_endpoint: Option<String>,
} }
```plaintext ```text
### Example Service Definition ### Example Service Definition
@ -112,7 +112,7 @@ let coredns_service = Service {
stop_command: "systemctl stop coredns".to_string(), stop_command: "systemctl stop coredns".to_string(),
health_check_endpoint: Some("http://localhost:53/health".to_string()), health_check_endpoint: Some("http://localhost:53/health".to_string()),
}; };
```plaintext ```text
### Service with Dependencies ### Service with Dependencies
@ -125,7 +125,7 @@ let oci_registry = Service {
stop_command: "systemctl stop oci-registry".to_string(), stop_command: "systemctl stop oci-registry".to_string(),
health_check_endpoint: Some("http://localhost:5000/v2/".to_string()), health_check_endpoint: Some("http://localhost:5000/v2/".to_string()),
}; };
```plaintext ```text
## Configuration ## Configuration
@ -135,7 +135,7 @@ Service orchestration settings in `config.defaults.toml`:
[orchestrator.services] [orchestrator.services]
manager_enabled = true manager_enabled = true
auto_start_dependencies = true auto_start_dependencies = true
```plaintext ```text
### Configuration Options ### Configuration Options
@ -148,7 +148,7 @@ auto_start_dependencies = true
```http ```http
GET /api/v1/services/list GET /api/v1/services/list
```plaintext ```text
**Response:** **Response:**
@ -166,13 +166,13 @@ GET /api/v1/services/list
} }
] ]
} }
```plaintext ```text
### Get Services Status ### Get Services Status
```http ```http
GET /api/v1/services/status GET /api/v1/services/status
```plaintext ```text
**Response:** **Response:**
@ -190,7 +190,7 @@ GET /api/v1/services/status
} }
] ]
} }
```plaintext ```text
## Usage Examples ## Usage Examples
@ -228,14 +228,14 @@ let oci = Service {
}; };
orchestrator.register_service(oci).await; orchestrator.register_service(oci).await;
```plaintext ```text
### Start Service with Dependencies ### Start Service with Dependencies
```rust ```rust
// This will automatically start coredns first, then oci-registry // This will automatically start coredns first, then oci-registry
orchestrator.start_service("oci-registry").await?; orchestrator.start_service("oci-registry").await?;
```plaintext ```text
### Resolve Startup Order ### Resolve Startup Order
@ -251,7 +251,7 @@ println!("Startup order:");
for (i, service) in order.iter().enumerate() { for (i, service) in order.iter().enumerate() {
println!("{}. {}", i + 1, service); println!("{}. {}", i + 1, service);
} }
```plaintext ```text
### Start All Services ### Start All Services
@ -262,7 +262,7 @@ println!("Started {} services:", started.len());
for service in started { for service in started {
println!(" ✓ {}", service); println!(" ✓ {}", service);
} }
```plaintext ```text
### Check Service Health ### Check Service Health
@ -277,7 +277,7 @@ if health.healthy {
println!("✗ {} is unhealthy", "coredns"); println!("✗ {} is unhealthy", "coredns");
println!(" Message: {}", health.message); println!(" Message: {}", health.message);
} }
```plaintext ```text
## Dependency Graph Examples ## Dependency Graph Examples
@ -285,7 +285,7 @@ if health.healthy {
```plaintext ```plaintext
A -> B -> C A -> B -> C
```plaintext ```text
Startup order: A, B, C Startup order: A, B, C
@ -293,7 +293,7 @@ Startup order: A, B, C
let a = Service { name: "a".to_string(), dependencies: vec![], /* ... */ }; let a = Service { name: "a".to_string(), dependencies: vec![], /* ... */ };
let b = Service { name: "b".to_string(), dependencies: vec!["a".to_string()], /* ... */ }; let b = Service { name: "b".to_string(), dependencies: vec!["a".to_string()], /* ... */ };
let c = Service { name: "c".to_string(), dependencies: vec!["b".to_string()], /* ... */ }; let c = Service { name: "c".to_string(), dependencies: vec!["b".to_string()], /* ... */ };
```plaintext ```text
### Diamond Dependency ### Diamond Dependency
@ -303,7 +303,7 @@ let c = Service { name: "c".to_string(), dependencies: vec!["b".to_string()], /*
B C B C
\ / \ /
D D
```plaintext ```text
Startup order: A, B, C, D (B and C can start in parallel) Startup order: A, B, C, D (B and C can start in parallel)
@ -312,7 +312,7 @@ let a = Service { name: "a".to_string(), dependencies: vec![], /* ... */ };
let b = Service { name: "b".to_string(), dependencies: vec!["a".to_string()], /* ... */ }; let b = Service { name: "b".to_string(), dependencies: vec!["a".to_string()], /* ... */ };
let c = Service { name: "c".to_string(), dependencies: vec!["a".to_string()], /* ... */ }; let c = Service { name: "c".to_string(), dependencies: vec!["a".to_string()], /* ... */ };
let d = Service { name: "d".to_string(), dependencies: vec!["b".to_string(), "c".to_string()], /* ... */ }; let d = Service { name: "d".to_string(), dependencies: vec!["b".to_string(), "c".to_string()], /* ... */ };
```plaintext ```text
### Complex Dependency ### Complex Dependency
@ -326,7 +326,7 @@ let d = Service { name: "d".to_string(), dependencies: vec!["b".to_string(), "c"
E F E F
\ / \ /
G G
```plaintext ```text
Startup order: A, B, C, D, E, F, G Startup order: A, B, C, D, E, F, G
@ -343,7 +343,7 @@ let coredns = Service {
stop_command: "systemctl stop coredns".to_string(), stop_command: "systemctl stop coredns".to_string(),
health_check_endpoint: Some("http://localhost:53/health".to_string()), health_check_endpoint: Some("http://localhost:53/health".to_string()),
}; };
```plaintext ```text
### OCI Registry Service ### OCI Registry Service
@ -356,7 +356,7 @@ let oci_registry = Service {
stop_command: "systemctl stop oci-registry".to_string(), stop_command: "systemctl stop oci-registry".to_string(),
health_check_endpoint: Some("http://localhost:5000/v2/".to_string()), health_check_endpoint: Some("http://localhost:5000/v2/".to_string()),
}; };
```plaintext ```text
### Orchestrator Service ### Orchestrator Service
@ -369,7 +369,7 @@ let orchestrator = Service {
stop_command: "./scripts/start-orchestrator.nu --stop".to_string(), stop_command: "./scripts/start-orchestrator.nu --stop".to_string(),
health_check_endpoint: Some("http://localhost:9090/health".to_string()), health_check_endpoint: Some("http://localhost:9090/health".to_string()),
}; };
```plaintext ```text
## Error Handling ## Error Handling
@ -391,7 +391,7 @@ let c = Service { name: "c".to_string(), dependencies: vec!["b".to_string()], /*
// Error: Circular dependency detected // Error: Circular dependency detected
let result = orchestrator.resolve_startup_order(&["a".to_string()]).await; let result = orchestrator.resolve_startup_order(&["a".to_string()]).await;
assert!(result.is_err()); assert!(result.is_err());
```plaintext ```text
## Testing ## Testing
@ -400,7 +400,7 @@ Run service orchestration tests:
```bash ```bash
cd provisioning/platform/orchestrator cd provisioning/platform/orchestrator
cargo test test_service_orchestration cargo test test_service_orchestration
```plaintext ```text
## Troubleshooting ## Troubleshooting

View File

@ -2,7 +2,8 @@
## Overview ## Overview
The SSH Temporal Key Management System provides automated generation, deployment, and cleanup of short-lived SSH keys for secure server access. It eliminates the need for static SSH keys by generating keys on-demand with automatic expiration. The SSH Temporal Key Management System provides automated generation, deployment, and cleanup of short-lived SSH keys
for secure server access. It eliminates the need for static SSH keys by generating keys on-demand with automatic expiration.
## Features ## Features
@ -10,9 +11,9 @@ The SSH Temporal Key Management System provides automated generation, deployment
- **Short-Lived Keys**: Keys expire automatically after a configurable TTL (default: 1 hour) - **Short-Lived Keys**: Keys expire automatically after a configurable TTL (default: 1 hour)
- **Multiple Key Types**: - **Multiple Key Types**:
- Dynamic Key Pairs (Ed25519) - Dynamic Key Pairs (Ed25519)
- Vault OTP (One-Time Password) - Vault OTP (One-Time Password)
- Vault CA-Signed Certificates - Vault CA-Signed Certificates
- **Automatic Cleanup**: Background task removes expired keys from servers - **Automatic Cleanup**: Background task removes expired keys from servers
- **Audit Trail**: All key operations are logged - **Audit Trail**: All key operations are logged
- **REST API**: HTTP endpoints for integration - **REST API**: HTTP endpoints for integration
@ -30,25 +31,30 @@ The SSH Temporal Key Management System provides automated generation, deployment
## Architecture ## Architecture
```plaintext ```plaintext
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────────┐
│ SSH Key Manager │ │ SSH Key Manager │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────
────────────┤
│ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ ┌──────────────┐ ┌──────────────┐
┌──────────────┐ │
│ │ Key Generator│ │ Key Deployer │ │ Temporal │ │ │ │ Key Generator│ │ Key Deployer │ │ Temporal │ │
│ │ (Ed25519) │ │ (SSH Deploy) │ │ Manager │ │ │ │ (Ed25519) │ │ (SSH Deploy) │ │ Manager │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │ │ └──────────────┘ └──────────────┘
└──────────────┘ │
│ │ │ │
│ ┌──────────────┐ ┌──────────────┐ │ │ ┌──────────────┐ ┌──────────────┐ │
│ │ Vault │ │ Authorized │ │ │ │ Vault │ │ Authorized │ │
│ │ SSH Engine │ │ Keys Manager │ │ │ │ SSH Engine │ │ Keys Manager │ │
│ └──────────────┘ └──────────────┘ │ │ └──────────────┘ └──────────────┘ │
│ │ │ │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────
────────────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
REST API Nushell CLI Background Tasks REST API Nushell CLI Background Tasks
```plaintext ```text
## Key Types ## Key Types
@ -62,7 +68,7 @@ Generated on-demand Ed25519 keys that are automatically deployed and cleaned up.
```bash ```bash
ssh generate-key server.example.com --user root --ttl 30min ssh generate-key server.example.com --user root --ttl 30min
```plaintext ```text
### 2. Vault OTP (One-Time Password) ### 2. Vault OTP (One-Time Password)
@ -76,7 +82,7 @@ Vault generates a one-time password for SSH authentication.
```bash ```bash
ssh generate-key server.example.com --type otp --ip 192.168.1.100 ssh generate-key server.example.com --type otp --ip 192.168.1.100
```plaintext ```text
### 3. Vault CA-Signed Certificates ### 3. Vault CA-Signed Certificates
@ -90,7 +96,7 @@ Vault acts as SSH CA, signing user public keys with short TTL.
```bash ```bash
ssh generate-key server.example.com --type ca --principal admin --ttl 1hr ssh generate-key server.example.com --type ca --principal admin --ttl 1hr
```plaintext ```text
## REST API Endpoints ## REST API Endpoints
@ -126,7 +132,7 @@ Response:
"deployed": false "deployed": false
} }
} }
```plaintext ```text
### Deploy SSH Key ### Deploy SSH Key
@ -143,7 +149,7 @@ Response:
"deployed_at": "2024-01-01T00:00:00Z" "deployed_at": "2024-01-01T00:00:00Z"
} }
} }
```plaintext ```text
### List SSH Keys ### List SSH Keys
@ -164,7 +170,7 @@ Response:
} }
] ]
} }
```plaintext ```text
### Revoke SSH Key ### Revoke SSH Key
@ -176,7 +182,7 @@ Response:
"success": true, "success": true,
"data": "Key uuid revoked successfully" "data": "Key uuid revoked successfully"
} }
```plaintext ```text
### Get SSH Key ### Get SSH Key
@ -192,7 +198,7 @@ Response:
... ...
} }
} }
```plaintext ```text
### Cleanup Expired Keys ### Cleanup Expired Keys
@ -207,7 +213,7 @@ Response:
"cleaned_key_ids": ["uuid1", "uuid2", ...] "cleaned_key_ids": ["uuid1", "uuid2", ...]
} }
} }
```plaintext ```text
### Get Statistics ### Get Statistics
@ -230,7 +236,7 @@ Response:
"last_cleanup_at": "2024-01-01T00:00:00Z" "last_cleanup_at": "2024-01-01T00:00:00Z"
} }
} }
```plaintext ```text
## Nushell CLI Commands ## Nushell CLI Commands
@ -250,7 +256,7 @@ Examples:
ssh generate-key server.example.com ssh generate-key server.example.com
ssh generate-key server.example.com --user deploy --ttl 30min ssh generate-key server.example.com --user deploy --ttl 30min
ssh generate-key server.example.com --type ca --principal admin ssh generate-key server.example.com --type ca --principal admin
```plaintext ```text
### Deploy Key ### Deploy Key
@ -259,7 +265,7 @@ ssh deploy-key <key_id>
Example: Example:
ssh deploy-key abc-123-def-456 ssh deploy-key abc-123-def-456
```plaintext ```text
### List Keys ### List Keys
@ -269,7 +275,7 @@ ssh list-keys [--expired]
Example: Example:
ssh list-keys ssh list-keys
ssh list-keys | where deployed == true ssh list-keys | where deployed == true
```plaintext ```text
### Revoke Key ### Revoke Key
@ -278,7 +284,7 @@ ssh revoke-key <key_id>
Example: Example:
ssh revoke-key abc-123-def-456 ssh revoke-key abc-123-def-456
```plaintext ```text
### Connect with Auto-Generated Key ### Connect with Auto-Generated Key
@ -293,7 +299,7 @@ Options:
Example: Example:
ssh connect server.example.com --user deploy ssh connect server.example.com --user deploy
```plaintext ```text
This command: This command:
@ -320,7 +326,7 @@ Example output:
Last cleanup: 2024-01-01T00:00:00Z Last cleanup: 2024-01-01T00:00:00Z
Cleaned keys: 5 Cleaned keys: 5
```plaintext ```text
### Manual Cleanup ### Manual Cleanup
@ -333,7 +339,7 @@ Example output:
- abc-123 - abc-123
- def-456 - def-456
... ...
```plaintext ```text
## Configuration ## Configuration
@ -361,7 +367,7 @@ let ssh_manager = Arc::new(SshKeyManager::new(ssh_config).await?);
// Start background cleanup task // Start background cleanup task
Arc::clone(&ssh_manager).start_cleanup_task().await; Arc::clone(&ssh_manager).start_cleanup_task().await;
```plaintext ```text
### Vault SSH Configuration ### Vault SSH Configuration
@ -376,7 +382,7 @@ vault write ssh/roles/otp_key_role \
key_type=otp \ key_type=otp \
default_user=root \ default_user=root \
cidr_list=0.0.0.0/0 cidr_list=0.0.0.0/0
```plaintext ```text
#### CA Mode #### CA Mode
@ -398,13 +404,13 @@ vault write ssh/roles/default \
# Get CA public key (add to servers' /etc/ssh/trusted-user-ca-keys.pem) # Get CA public key (add to servers' /etc/ssh/trusted-user-ca-keys.pem)
vault read -field=public_key ssh/config/ca vault read -field=public_key ssh/config/ca
```plaintext ```text
Server configuration (`/etc/ssh/sshd_config`): Server configuration (`/etc/ssh/sshd_config`):
```plaintext ```plaintext
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
```plaintext ```text
## Deployment ## Deployment
@ -423,7 +429,7 @@ export VAULT_TOKEN=your-vault-token
# Provisioning SSH key path # Provisioning SSH key path
export PROVISIONING_SSH_KEY=/path/to/provisioning/key export PROVISIONING_SSH_KEY=/path/to/provisioning/key
```plaintext ```text
### Integration with Workflows ### Integration with Workflows
@ -439,7 +445,7 @@ ssh root@$server "install-kubernetes.sh"
# Auto-revoke after workflow # Auto-revoke after workflow
ssh revoke-key $ssh_key.id ssh revoke-key $ssh_key.id
```plaintext ```text
## Security Considerations ## Security Considerations
@ -458,13 +464,13 @@ Check SSH connectivity:
```bash ```bash
ssh -i /path/to/provisioning/key root@server.example.com ssh -i /path/to/provisioning/key root@server.example.com
```plaintext ```text
Verify SSH daemon is running: Verify SSH daemon is running:
```bash ```bash
systemctl status sshd systemctl status sshd
```plaintext ```text
### Cleanup Not Working ### Cleanup Not Working
@ -472,13 +478,13 @@ Check orchestrator logs:
```bash ```bash
tail -f ./data/orchestrator.log | grep SSH tail -f ./data/orchestrator.log | grep SSH
```plaintext ```text
Manual cleanup: Manual cleanup:
```bash ```bash
ssh cleanup ssh cleanup
```plaintext ```text
### Vault Integration Issues ### Vault Integration Issues
@ -487,14 +493,14 @@ Test Vault connectivity:
```bash ```bash
vault status vault status
vault token lookup vault token lookup
```plaintext ```text
Check SSH secrets engine: Check SSH secrets engine:
```bash ```bash
vault secrets list vault secrets list
vault read ssh/config/ca vault read ssh/config/ca
```plaintext ```text
## Performance ## Performance

View File

@ -15,7 +15,7 @@ All backends implement the same `TaskStorage` trait, ensuring consistent behavio
## Backend Comparison ## Backend Comparison
| Feature | Filesystem | SurrealDB Embedded | SurrealDB Server | | Feature | Filesystem | SurrealDB Embedded | SurrealDB Server |
|---------|------------|-------------------|------------------| | --------- | ------------ | ------------------- | ------------------ |
| **Setup Complexity** | Minimal | Low | Medium | | **Setup Complexity** | Minimal | Low | Medium |
| **External Dependencies** | None | None | SurrealDB Server | | **External Dependencies** | None | None | SurrealDB Server |
| **Storage Format** | JSON Files | RocksDB | Remote DB | | **Storage Format** | JSON Files | RocksDB | Remote DB |
@ -45,7 +45,7 @@ The default storage backend using JSON files for task persistence. Ideal for dev
# Custom data directory # Custom data directory
./orchestrator --storage-type filesystem --data-dir /var/lib/orchestrator ./orchestrator --storage-type filesystem --data-dir /var/lib/orchestrator
```plaintext ```text
### File Structure ### File Structure
@ -60,7 +60,7 @@ data/
├── uuid1.json # Queue entries with priority ├── uuid1.json # Queue entries with priority
├── uuid2.json ├── uuid2.json
└── ... └── ...
```plaintext ```text
### Features ### Features
@ -93,7 +93,7 @@ cargo build --features surrealdb
# Run with embedded SurrealDB # Run with embedded SurrealDB
./orchestrator --storage-type surrealdb-embedded --data-dir ./data ./orchestrator --storage-type surrealdb-embedded --data-dir ./data
```plaintext ```text
### Database Schema ### Database Schema
@ -126,7 +126,7 @@ cargo build --features surrealdb
--data-dir ./data \ --data-dir ./data \
--surrealdb-namespace production \ --surrealdb-namespace production \
--surrealdb-database orchestrator --surrealdb-database orchestrator
```plaintext ```text
### Best Use Cases ### Best Use Cases
@ -162,7 +162,7 @@ surreal start --log trace --user root --pass root file:orchestrator.db
# Or with TiKV (distributed) # Or with TiKV (distributed)
surreal start --log trace --user root --pass root tikv://localhost:2379 surreal start --log trace --user root --pass root tikv://localhost:2379
```plaintext ```text
### Configuration ### Configuration
@ -180,7 +180,7 @@ surreal start --log trace --user root --pass root tikv://localhost:2379
--surrealdb-database orchestrator \ --surrealdb-database orchestrator \
--surrealdb-username orchestrator-service \ --surrealdb-username orchestrator-service \
--surrealdb-password "$SURREALDB_PASSWORD" --surrealdb-password "$SURREALDB_PASSWORD"
```plaintext ```text
### Features ### Features
@ -223,7 +223,7 @@ Use the migration script to move data between any backend combination:
# Validation and dry-run # Validation and dry-run
./scripts/migrate-storage.nu validate --from filesystem --to surrealdb-embedded ./scripts/migrate-storage.nu validate --from filesystem --to surrealdb-embedded
./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded --dry-run ./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded --dry-run
```plaintext ```text
### Migration Features ### Migration Features
@ -242,7 +242,7 @@ Use the migration script to move data between any backend combination:
./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded \ ./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded \
--source-dir ./dev-data --target-dir ./prod-data \ --source-dir ./dev-data --target-dir ./prod-data \
--batch-size 100 --verify --batch-size 100 --verify
```plaintext ```text
#### Scaling Up #### Scaling Up
@ -253,7 +253,7 @@ Use the migration script to move data between any backend combination:
--surrealdb-url ws://production-surreal:8000 \ --surrealdb-url ws://production-surreal:8000 \
--username orchestrator --password "$PROD_PASSWORD" \ --username orchestrator --password "$PROD_PASSWORD" \
--namespace production --database main --namespace production --database main
```plaintext ```text
#### Disaster Recovery #### Disaster Recovery
@ -263,7 +263,7 @@ Use the migration script to move data between any backend combination:
--surrealdb-url ws://failing-server:8000 \ --surrealdb-url ws://failing-server:8000 \
--username admin --password "$PASSWORD" \ --username admin --password "$PASSWORD" \
--target-dir ./emergency-backup --target-dir ./emergency-backup
```plaintext ```text
## Performance Considerations ## Performance Considerations
@ -319,7 +319,7 @@ chmod -R 755 ./data
# Corrupted JSON files # Corrupted JSON files
rm ./data/queue.rkvs/tasks/corrupted-file.json rm ./data/queue.rkvs/tasks/corrupted-file.json
```plaintext ```text
#### SurrealDB Embedded #### SurrealDB Embedded
@ -330,7 +330,7 @@ rm -rf ./data/orchestrator.db
# Permission issues # Permission issues
sudo chown -R $USER:$USER ./data sudo chown -R $USER:$USER ./data
```plaintext ```text
#### SurrealDB Server #### SurrealDB Server
@ -341,7 +341,7 @@ telnet surreal-server 8000
# Authentication failures # Authentication failures
# Verify credentials and user permissions # Verify credentials and user permissions
```plaintext ```text
### Debugging Commands ### Debugging Commands
@ -357,7 +357,7 @@ telnet surreal-server 8000
# Monitor migration progress # Monitor migration progress
./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded --verbose ./scripts/migrate-storage.nu --from filesystem --to surrealdb-embedded --verbose
```plaintext ```text
## Recommendations ## Recommendations

View File

@ -1,53 +0,0 @@
Immediate Testing Opportunities
1. Test the Original Problem:
cd klab/wuji
provisioning -c c server --orchestrated
This should now work through the orchestrator, bypassing the deep call stack issue.
2. Test Workflow Management:
# List workflows
nu -c "use ../core/nulib/workflows/management.nu; workflow list"
# Check orchestrator status
nu -c "use ../core/nulib/workflows/management.nu; workflow orchestrator"
# Submit a test server workflow
nu -c "use ../core/nulib/workflows/server_create.nu; server_create_workflow 'test-infra' 'config.user.toml' ['server1']"
Production Readiness Steps
1. Integration Testing:
- Test server creation workflows with real infrastructure
- Verify taskserv deployment through orchestrator
- Test cluster operations via REST API
1. Performance Validation:
- Confirm parallel processing works (the original foreach issue)
- Monitor orchestrator logs during heavy workloads
- Test with your target scale (10-12 servers, ~12 taskservs each)
1. Production Deployment:
- Move orchestrator to permanent location
- Set up systemd service or similar for auto-start
- Configure proper logging and monitoring
Next Development Phase
1. Enhanced Features:
- Dependency management between workflows
- Workflow rollback capabilities
- Real-time progress streaming
- Workflow templates and presets
The hybrid architecture is now complete and ready to solve your deep call stack limitations while preserving all existing Nushell business logic. Would you like to test the
original failing command first?

View File

@ -3,39 +3,27 @@ use std::sync::Arc;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use axum::{ use axum::{
extract::{Path, State}, extract::{Path, State},
http::StatusCode,
response::Json, response::Json,
routing::{get, post}, routing::{get, post},
http::StatusCode,
Router, Router,
}; };
use clap::Parser; use clap::Parser;
// Use types from the library // Use types from the library
use provisioning_orchestrator::{ use provisioning_orchestrator::{
audit::{ audit::{AuditEvent, AuditFilter, AuditQuery, RetentionPolicy, SiemFormat},
AuditEvent, AuditFilter, AuditQuery, RetentionPolicy, SiemFormat, batch::{BatchOperationRequest, BatchOperationResult},
},
batch::{
BatchOperationRequest, BatchOperationResult,
},
compliance_routes, compliance_routes,
monitor::{ monitor::{MonitoringEvent, MonitoringEventType, SystemHealthStatus},
MonitoringEvent, MonitoringEventType, rollback::{Checkpoint, RollbackResult, RollbackStatistics},
SystemHealthStatus, state::{ProgressInfo, StateManagerStatistics, StateSnapshot, SystemMetrics},
}, test_environment::{
rollback::{ CreateTestEnvironmentRequest, RunTestRequest, TestEnvironment, TestEnvironmentResponse,
Checkpoint, RollbackResult, RollbackStatistics, TestResult,
},
state::{
ProgressInfo, StateManagerStatistics, StateSnapshot,
SystemMetrics,
}, },
workflow::WorkflowExecutionState, workflow::WorkflowExecutionState,
test_environment::{ AppState, Args, ClusterWorkflow, CreateServerWorkflow, SharedState, TaskStatus,
CreateTestEnvironmentRequest, RunTestRequest, TestEnvironmentResponse, TaskservWorkflow, WorkflowTask,
TestEnvironment, TestResult,
},
AppState, Args, ClusterWorkflow, CreateServerWorkflow, SharedState,
TaskStatus, TaskservWorkflow, WorkflowTask,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;

View File

@ -1,6 +1,7 @@
# Testing Guide for Multi-Storage Orchestrator # Testing Guide for Multi-Storage Orchestrator
This document provides comprehensive guidance for testing the multi-storage orchestrator system, including unit tests, integration tests, benchmarks, and performance analysis. This document provides comprehensive guidance for testing the multi-storage orchestrator system,
including unit tests, integration tests, benchmarks, and performance analysis.
## Overview ## Overview
@ -29,7 +30,7 @@ src/
├── storage/ # Unit tests embedded in modules ├── storage/ # Unit tests embedded in modules
├── migration/tests.rs # Migration unit tests ├── migration/tests.rs # Migration unit tests
└── main.rs # Application integration tests └── main.rs # Application integration tests
```plaintext ```text
## Running Tests ## Running Tests
@ -49,7 +50,7 @@ cargo test --test factory_tests
# Run unit tests only # Run unit tests only
cargo test --lib cargo test --lib
```plaintext ```text
### Using Cargo Aliases ### Using Cargo Aliases
@ -70,7 +71,7 @@ cargo test-integration
cargo test-migration cargo test-migration
cargo test-factory cargo test-factory
cargo test-unit cargo test-unit
```plaintext ```text
## Test Features and Backends ## Test Features and Backends
@ -90,7 +91,7 @@ Tests automatically adapt to available features:
async fn test_surrealdb_specific_feature() { async fn test_surrealdb_specific_feature() {
// This test only runs when SurrealDB feature is enabled // This test only runs when SurrealDB feature is enabled
} }
```plaintext ```text
## Integration Tests ## Integration Tests
@ -108,7 +109,7 @@ test_all_backends!(test_basic_crud_operations, |storage, gen| async move {
// ... test implementation // ... test implementation
Ok(()) Ok(())
}); });
```plaintext ```text
**Key Test Scenarios:** **Key Test Scenarios:**
@ -134,7 +135,7 @@ cargo test --features surrealdb --test migration_tests
# Test specific migration scenarios # Test specific migration scenarios
cargo test --features surrealdb test_filesystem_to_embedded_migration cargo test --features surrealdb test_filesystem_to_embedded_migration
cargo test --features surrealdb test_large_dataset_migration_performance cargo test --features surrealdb test_large_dataset_migration_performance
```plaintext ```text
**Migration Test Coverage:** **Migration Test Coverage:**
@ -157,7 +158,7 @@ cargo test --test factory_tests
# Test configuration validation # Test configuration validation
cargo test test_storage_config_validation_failures cargo test test_storage_config_validation_failures
```plaintext ```text
## Benchmarks ## Benchmarks
@ -177,7 +178,7 @@ cargo bench-surrealdb # Requires --features surrealdb
cargo bench -- single_enqueue cargo bench -- single_enqueue
cargo bench -- batch_operations cargo bench -- batch_operations
cargo bench -- concurrent_operations cargo bench -- concurrent_operations
```plaintext ```text
**Benchmark Categories:** **Benchmark Categories:**
@ -198,7 +199,7 @@ cargo bench-migration
# Test migration performance # Test migration performance
cargo bench -- basic_migration cargo bench -- basic_migration
cargo bench -- migration_batch_sizes cargo bench -- migration_batch_sizes
```plaintext ```text
**Migration Benchmarks:** **Migration Benchmarks:**
@ -220,7 +221,7 @@ use crate::helpers::TestDataGenerator;
let gen = TestDataGenerator::new(); let gen = TestDataGenerator::new();
let task = gen.workflow_task(); let task = gen.workflow_task();
let batch = gen.workflow_tasks_batch(10); let batch = gen.workflow_tasks_batch(10);
```plaintext ```text
### StorageTestRunner ### StorageTestRunner
@ -231,7 +232,7 @@ use crate::helpers::StorageTestRunner;
let mut runner = StorageTestRunner::new(); let mut runner = StorageTestRunner::new();
runner.run_against_all_backends(test_function).await; runner.run_against_all_backends(test_function).await;
```plaintext ```text
### MockStorage ### MockStorage
@ -242,7 +243,7 @@ use crate::helpers::MockStorage;
let mock = MockStorage::new(); let mock = MockStorage::new();
mock.set_health(false); // Simulate failure mock.set_health(false); // Simulate failure
```plaintext ```text
## Performance Testing ## Performance Testing
@ -284,7 +285,7 @@ strategy:
rust: rust:
- stable - stable
- beta - beta
```plaintext ```text
### Test Commands for CI ### Test Commands for CI
@ -298,7 +299,7 @@ cargo test --doc --all-features
# Benchmark regression tests # Benchmark regression tests
cargo bench --all-features -- --test cargo bench --all-features -- --test
```plaintext ```text
## Debugging and Troubleshooting ## Debugging and Troubleshooting
@ -313,7 +314,7 @@ cargo test -- --nocapture
# Run single test with full output # Run single test with full output
cargo test test_name -- --exact --nocapture cargo test test_name -- --exact --nocapture
```plaintext ```text
### Common Issues ### Common Issues
@ -338,7 +339,7 @@ cargo test-coverage
# View coverage report # View coverage report
open target/tarpaulin-report.html open target/tarpaulin-report.html
```plaintext ```text
## Performance Profiling ## Performance Profiling
@ -352,7 +353,7 @@ cargo bench --bench migration_benchmarks -- --profile-time=10
# Generate flame graphs # Generate flame graphs
cargo install flamegraph cargo install flamegraph
cargo flamegraph --bench storage_benchmarks cargo flamegraph --bench storage_benchmarks
```plaintext ```text
## Best Practices ## Best Practices

View File

@ -1,6 +1,7 @@
# KMS Service - Key Management Service # KMS Service - Key Management Service
A unified Key Management Service for the Provisioning platform with support for multiple backends: **Age** (development), **Cosmian KMS** (privacy-preserving), **RustyVault** (self-hosted), **AWS KMS** (cloud-native), and **HashiCorp Vault** (enterprise). A unified Key Management Service for the Provisioning platform with support for multiple backends: **Age** (development),
**Cosmian KMS** (privacy-preserving), **RustyVault** (self-hosted), **AWS KMS** (cloud-native), and **HashiCorp Vault** (enterprise).
## Features ## Features
@ -43,22 +44,26 @@ A unified Key Management Service for the Provisioning platform with support for
## Architecture ## Architecture
```plaintext ```plaintext
┌─────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────
────────┐
│ KMS Service │ │ KMS Service │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────
────────┤
│ REST API (Axum) │ │ REST API (Axum) │
│ ├─ /api/v1/kms/encrypt POST │ │ ├─ /api/v1/kms/encrypt POST │
│ ├─ /api/v1/kms/decrypt POST │ │ ├─ /api/v1/kms/decrypt POST │
│ ├─ /api/v1/kms/generate-key POST (Cosmian only) │ │ ├─ /api/v1/kms/generate-key POST (Cosmian only) │
│ ├─ /api/v1/kms/status GET │ │ ├─ /api/v1/kms/status GET │
│ └─ /api/v1/kms/health GET │ │ └─ /api/v1/kms/health GET │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────
────────┤
│ Unified KMS Service Interface │ │ Unified KMS Service Interface │
│ ├─ encrypt(plaintext, context) -> ciphertext │ │ ├─ encrypt(plaintext, context) -> ciphertext │
│ ├─ decrypt(ciphertext, context) -> plaintext │ │ ├─ decrypt(ciphertext, context) -> plaintext │
│ ├─ generate_data_key(spec) -> DataKey │ │ ├─ generate_data_key(spec) -> DataKey │
│ └─ health_check() -> bool │ │ └─ health_check() -> bool │
├─────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────
────────┤
│ Backend Implementations │ │ Backend Implementations │
│ ├─ Age Client │ │ ├─ Age Client │
│ │ ├─ X25519 encryption │ │ │ ├─ X25519 encryption │
@ -68,8 +73,9 @@ A unified Key Management Service for the Provisioning platform with support for
│ ├─ REST API integration │ │ ├─ REST API integration │
│ ├─ Zero-knowledge encryption │ │ ├─ Zero-knowledge encryption │
│ └─ Confidential computing │ │ └─ Confidential computing │
└─────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────
```plaintext ────────┘
```text
## Installation ## Installation
@ -87,7 +93,7 @@ cd provisioning/platform/kms-service
cargo build --release cargo build --release
# Binary will be at: target/release/kms-service # Binary will be at: target/release/kms-service
```plaintext ```text
## Configuration ## Configuration
@ -110,7 +116,7 @@ server_url = "${COSMIAN_KMS_URL:-https://kms.example.com}"
api_key = "${COSMIAN_API_KEY}" api_key = "${COSMIAN_API_KEY}"
default_key_id = "provisioning-master-key" default_key_id = "provisioning-master-key"
tls_verify = true tls_verify = true
```plaintext ```text
### Environment Variables ### Environment Variables
@ -123,7 +129,7 @@ export PROVISIONING_ENV=dev
export PROVISIONING_ENV=prod export PROVISIONING_ENV=prod
export COSMIAN_KMS_URL="https://kms.example.com" export COSMIAN_KMS_URL="https://kms.example.com"
export COSMIAN_API_KEY="your-api-key" export COSMIAN_API_KEY="your-api-key"
```plaintext ```text
## Quick Start ## Quick Start
@ -140,7 +146,7 @@ export PROVISIONING_ENV=dev
# 3. Start KMS service # 3. Start KMS service
cargo run --bin kms-service cargo run --bin kms-service
```plaintext ```text
### Production Setup (Cosmian) ### Production Setup (Cosmian)
@ -157,7 +163,7 @@ export COSMIAN_API_KEY=your-api-key-here
# 4. Start KMS service # 4. Start KMS service
cargo run --bin kms-service cargo run --bin kms-service
```plaintext ```text
## Usage ## Usage
@ -172,7 +178,7 @@ curl -X POST http://localhost:8082/api/v1/kms/encrypt \
"plaintext": "SGVsbG8sIFdvcmxkIQ==", "plaintext": "SGVsbG8sIFdvcmxkIQ==",
"context": "env=prod,service=api" "context": "env=prod,service=api"
}' }'
```plaintext ```text
#### Decrypt Data #### Decrypt Data
@ -183,7 +189,7 @@ curl -X POST http://localhost:8082/api/v1/kms/decrypt \
"ciphertext": "...", "ciphertext": "...",
"context": "env=prod,service=api" "context": "env=prod,service=api"
}' }'
```plaintext ```text
#### Generate Data Key (Cosmian only) #### Generate Data Key (Cosmian only)
@ -193,13 +199,13 @@ curl -X POST http://localhost:8082/api/v1/kms/generate-key \
-d '{ -d '{
"key_spec": "AES_256" "key_spec": "AES_256"
}' }'
```plaintext ```text
#### Health Check #### Health Check
```bash ```bash
curl http://localhost:8082/api/v1/kms/health curl http://localhost:8082/api/v1/kms/health
```plaintext ```text
### Nushell CLI Integration ### Nushell CLI Integration
@ -232,12 +238,12 @@ kms encrypt-file secrets.json --output secrets.enc --context "env=prod"
kms decrypt-file config.yaml.enc kms decrypt-file config.yaml.enc
kms decrypt-file secrets.enc --output secrets.json --context "env=prod" kms decrypt-file secrets.enc --output secrets.json --context "env=prod"
```plaintext ```text
## Backend Comparison ## Backend Comparison
| Feature | Age | RustyVault | Cosmian KMS | AWS KMS | Vault | | Feature | Age | RustyVault | Cosmian KMS | AWS KMS | Vault |
|---------|-----|------------|-------------|---------|-------| | --------- | ----- | ------------ | ------------- | --------- | ------- |
| **Setup** | Simple | Self-hosted | Server setup | AWS account | Enterprise | | **Setup** | Simple | Self-hosted | Server setup | AWS account | Enterprise |
| **Speed** | Very fast | Fast | Fast | Fast | Fast | | **Speed** | Very fast | Fast | Fast | Fast | Fast |
| **Network** | No | Yes | Yes | Yes | Yes | | **Network** | No | Yes | Yes | Yes | Yes |
@ -260,14 +266,14 @@ kms encrypt-file workspace/config/secrets.yaml
# SOPS can use KMS for key encryption # SOPS can use KMS for key encryption
# Configure in .sops.yaml to use KMS endpoint # Configure in .sops.yaml to use KMS endpoint
```plaintext ```text
### 2. Dynamic Secrets (Provider API Keys) ### 2. Dynamic Secrets (Provider API Keys)
```rust ```rust
// Rust orchestrator can call KMS API // Rust orchestrator can call KMS API
let encrypted_key = kms_client.encrypt(api_key.as_bytes(), &context).await?; let encrypted_key = kms_client.encrypt(api_key.as_bytes(), &context).await?;
```plaintext ```text
### 3. SSH Key Management ### 3. SSH Key Management
@ -275,7 +281,7 @@ let encrypted_key = kms_client.encrypt(api_key.as_bytes(), &context).await?;
# Generate and encrypt temporal SSH keys # Generate and encrypt temporal SSH keys
ssh-keygen -t ed25519 -f temp_key -N "" ssh-keygen -t ed25519 -f temp_key -N ""
kms encrypt-file temp_key --context "infra=prod,purpose=deployment" kms encrypt-file temp_key --context "infra=prod,purpose=deployment"
```plaintext ```text
### 4. Orchestrator (Workflow Data) ### 4. Orchestrator (Workflow Data)
@ -284,7 +290,7 @@ kms encrypt-file temp_key --context "infra=prod,purpose=deployment"
let encrypted_params = kms_service let encrypted_params = kms_service
.encrypt(params_json.as_bytes(), &workflow_context) .encrypt(params_json.as_bytes(), &workflow_context)
.await?; .await?;
```plaintext ```text
### 5. Control Center (Audit Logs) ### 5. Control Center (Audit Logs)
@ -298,7 +304,7 @@ let encrypted_params = kms_service
```bash ```bash
cargo test cargo test
```plaintext ```text
### Integration Tests ### Integration Tests
@ -310,7 +316,7 @@ cargo test age
export COSMIAN_KMS_URL=http://localhost:9999 export COSMIAN_KMS_URL=http://localhost:9999
export COSMIAN_API_KEY=test-key export COSMIAN_API_KEY=test-key
cargo test cosmian -- --ignored cargo test cosmian -- --ignored
```plaintext ```text
## Deployment ## Deployment
@ -328,7 +334,7 @@ RUN apt-get update && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/kms-service /usr/local/bin/ COPY --from=builder /app/target/release/kms-service /usr/local/bin/
ENTRYPOINT ["kms-service"] ENTRYPOINT ["kms-service"]
```plaintext ```text
### Kubernetes (Production with Cosmian) ### Kubernetes (Production with Cosmian)
@ -356,7 +362,7 @@ spec:
key: api-key key: api-key
ports: ports:
- containerPort: 8082 - containerPort: 8082
```plaintext ```text
### systemd Service ### systemd Service
@ -376,7 +382,7 @@ Restart=always
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
```plaintext ```text
## Security Best Practices ## Security Best Practices
@ -402,7 +408,7 @@ curl http://localhost:8082/api/v1/kms/status
# Health check # Health check
curl http://localhost:8082/api/v1/kms/health curl http://localhost:8082/api/v1/kms/health
```plaintext ```text
### Logs ### Logs
@ -412,7 +418,7 @@ export RUST_LOG="kms_service=debug,tower_http=debug"
# View logs # View logs
journalctl -u kms-service -f journalctl -u kms-service -f
```plaintext ```text
## Troubleshooting ## Troubleshooting
@ -429,7 +435,7 @@ cat ~/.config/provisioning/age/public_key.txt
# Test encryption manually # Test encryption manually
echo "test" | age -r $(cat ~/.config/provisioning/age/public_key.txt) > test.enc echo "test" | age -r $(cat ~/.config/provisioning/age/public_key.txt) > test.enc
age -d -i ~/.config/provisioning/age/private_key.txt test.enc age -d -i ~/.config/provisioning/age/private_key.txt test.enc
```plaintext ```text
### Cosmian KMS Issues ### Cosmian KMS Issues
@ -447,7 +453,7 @@ curl -X POST https://kms.example.com/api/v1/encrypt \
-H "X-API-Key: $COSMIAN_API_KEY" \ -H "X-API-Key: $COSMIAN_API_KEY" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d '{"keyId":"master-key","data":"SGVsbG8="}' -d '{"keyId":"master-key","data":"SGVsbG8="}'
```plaintext ```text
## License ## License

View File

@ -31,22 +31,22 @@ The Provisioning Platform is a comprehensive infrastructure automation system th
### Architecture Components ### Architecture Components
| Component | Solo | Multi-User | CI/CD | Enterprise | | Component | Solo | Multi-User | CI/CD | Enterprise |
|-----------|------|------------|-------|------------| | ----------- | ------ | ------------ | ------- | ------------ |
| Orchestrator | ✓ | ✓ | ✓ | ✓ | | Orchestrator | ✓ | ✓ | ✓ | ✓ |
| Control Center | ✓ | ✓ | ✓ | ✓ | | Control Center | ✓ | ✓ | ✓ | ✓ |
| CoreDNS | ✓ | ✓ | ✓ | ✓ | | CoreDNS | ✓ | ✓ | ✓ | ✓ |
| OCI Registry (Zot) | ✓ | ✓ | ✓ | - | | OCI Registry (Zot) | ✓ | ✓ | ✓ | ---- |
| Extension Registry | ✓ | ✓ | ✓ | ✓ | | Extension Registry | ✓ | ✓ | ✓ | ✓ |
| Gitea | - | ✓ | ✓ | ✓ | | Gitea | ---- | ✓ | ✓ | ✓ |
| PostgreSQL | - | ✓ | ✓ | ✓ | | PostgreSQL | ---- | ✓ | ✓ | ✓ |
| API Server | - | - | ✓ | ✓ | | API Server | ---- | - | ✓ | ✓ |
| Harbor | - | - | - | ✓ | | Harbor | ---- | - | ---- | ✓ |
| Cosmian KMS | - | - | - | ✓ | | Cosmian KMS | ---- | - | ---- | ✓ |
| Prometheus | - | - | - | ✓ | | Prometheus | ---- | - | ---- | ✓ |
| Grafana | - | - | - | ✓ | | Grafana | ---- | - | ---- | ✓ |
| Loki + Promtail | - | - | - | ✓ | | Loki + Promtail | ---- | - | ---- | ✓ |
| Elasticsearch + Kibana | - | - | - | ✓ | | Elasticsearch + Kibana | ---- | - | ---- | ✓ |
| Nginx Reverse Proxy | - | - | - | ✓ | | Nginx Reverse Proxy | ---- | - | ---- | ✓ |
--- ---
@ -188,7 +188,7 @@ The Provisioning Platform is a comprehensive infrastructure automation system th
cd /opt cd /opt
git clone https://github.com/your-org/project-provisioning.git git clone https://github.com/your-org/project-provisioning.git
cd project-provisioning/provisioning/platform cd project-provisioning/provisioning/platform
```plaintext ```text
### 2. Generate Secrets ### 2. Generate Secrets
@ -199,7 +199,7 @@ cd project-provisioning/provisioning/platform
# Or copy and edit manually # Or copy and edit manually
cp .env.example .env cp .env.example .env
nano .env nano .env
```plaintext ```text
### 3. Choose Deployment Mode and Deploy ### 3. Choose Deployment Mode and Deploy
@ -207,7 +207,7 @@ nano .env
```bash ```bash
./scripts/deploy-platform.nu --mode solo ./scripts/deploy-platform.nu --mode solo
```plaintext ```text
#### Multi-User Mode #### Multi-User Mode
@ -217,20 +217,20 @@ nano .env
# Deploy # Deploy
./scripts/deploy-platform.nu --mode multi-user ./scripts/deploy-platform.nu --mode multi-user
```plaintext ```text
#### CI/CD Mode #### CI/CD Mode
```bash ```bash
./scripts/deploy-platform.nu --mode cicd --build ./scripts/deploy-platform.nu --mode cicd --build
```plaintext ```text
#### Enterprise Mode #### Enterprise Mode
```bash ```bash
# Full production deployment # Full production deployment
./scripts/deploy-platform.nu --mode enterprise --build --wait 600 ./scripts/deploy-platform.nu --mode enterprise --build --wait 600
```plaintext ```text
### 4. Verify Deployment ### 4. Verify Deployment
@ -240,7 +240,7 @@ nano .env
# View logs # View logs
docker-compose logs -f docker-compose logs -f
```plaintext ```text
### 5. Access Services ### 5. Access Services
@ -263,7 +263,7 @@ The `.env` file controls all deployment settings. Key variables:
```bash ```bash
PROVISIONING_MODE=solo # solo, multi-user, cicd, enterprise PROVISIONING_MODE=solo # solo, multi-user, cicd, enterprise
PLATFORM_ENVIRONMENT=development # development, staging, production PLATFORM_ENVIRONMENT=development # development, staging, production
```plaintext ```text
#### Service Ports #### Service Ports
@ -272,7 +272,7 @@ ORCHESTRATOR_PORT=8080
CONTROL_CENTER_PORT=8081 CONTROL_CENTER_PORT=8081
GITEA_HTTP_PORT=3000 GITEA_HTTP_PORT=3000
OCI_REGISTRY_PORT=5000 OCI_REGISTRY_PORT=5000
```plaintext ```text
#### Security Settings #### Security Settings
@ -281,14 +281,14 @@ OCI_REGISTRY_PORT=5000
CONTROL_CENTER_JWT_SECRET=<random-secret> CONTROL_CENTER_JWT_SECRET=<random-secret>
API_SERVER_JWT_SECRET=<random-secret> API_SERVER_JWT_SECRET=<random-secret>
POSTGRES_PASSWORD=<random-password> POSTGRES_PASSWORD=<random-password>
```plaintext ```text
#### Resource Limits #### Resource Limits
```bash ```bash
ORCHESTRATOR_CPU_LIMIT=2000m ORCHESTRATOR_CPU_LIMIT=2000m
ORCHESTRATOR_MEMORY_LIMIT=2048M ORCHESTRATOR_MEMORY_LIMIT=2048M
```plaintext ```text
### Configuration Files ### Configuration Files
@ -340,7 +340,7 @@ docker-compose -f docker-compose.yaml \
-f infrastructure/docker/docker-compose.cicd.yaml \ -f infrastructure/docker/docker-compose.cicd.yaml \
-f infrastructure/docker/docker-compose.enterprise.yaml \ -f infrastructure/docker/docker-compose.enterprise.yaml \
up -d up -d
```plaintext ```text
#### Manage Services #### Manage Services
@ -356,7 +356,7 @@ docker-compose down
# Stop and remove volumes (WARNING: data loss) # Stop and remove volumes (WARNING: data loss)
docker-compose down --volumes docker-compose down --volumes
```plaintext ```text
### Method 2: Systemd (Linux Production) ### Method 2: Systemd (Linux Production)
@ -365,7 +365,7 @@ docker-compose down --volumes
```bash ```bash
cd systemd cd systemd
sudo ./install-services.sh sudo ./install-services.sh
```plaintext ```text
#### Manage via systemd #### Manage via systemd
@ -387,7 +387,7 @@ sudo systemctl restart provisioning-platform
# Stop # Stop
sudo systemctl stop provisioning-platform sudo systemctl stop provisioning-platform
```plaintext ```text
### Method 3: Kubernetes ### Method 3: Kubernetes
@ -406,7 +406,7 @@ kubectl apply -f k8s/ingress/
# Check status # Check status
kubectl get pods -n provisioning kubectl get pods -n provisioning
```plaintext ```text
### Method 4: Automation Script (Nushell) ### Method 4: Automation Script (Nushell)
@ -421,7 +421,7 @@ kubectl get pods -n provisioning
# Dry run (show what would be deployed) # Dry run (show what would be deployed)
./scripts/deploy-platform.nu --mode enterprise --dry-run ./scripts/deploy-platform.nu --mode enterprise --dry-run
```plaintext ```text
--- ---
@ -438,7 +438,7 @@ docker-compose ps
# Check individual service # Check individual service
curl http://localhost:9090/health curl http://localhost:9090/health
```plaintext ```text
### 2. Initial Configuration ### 2. Initial Configuration
@ -454,7 +454,7 @@ Add to `/etc/hosts` or configure local DNS:
127.0.0.1 provisioning.local 127.0.0.1 provisioning.local
127.0.0.1 gitea.provisioning.local 127.0.0.1 gitea.provisioning.local
127.0.0.1 grafana.provisioning.local 127.0.0.1 grafana.provisioning.local
```plaintext ```text
#### Configure Monitoring (Enterprise) #### Configure Monitoring (Enterprise)
@ -473,7 +473,7 @@ curl http://localhost:8082/api/v1/extensions
# Upload extension (example) # Upload extension (example)
curl -X POST http://localhost:8082/api/v1/extensions/upload \ curl -X POST http://localhost:8082/api/v1/extensions/upload \
-F "file=@my-extension.tar.gz" -F "file=@my-extension.tar.gz"
```plaintext ```text
### 4. Test Workflows ### 4. Test Workflows
@ -485,7 +485,7 @@ curl -X POST http://localhost:9090/workflows/servers/create \
# Check workflow status # Check workflow status
curl http://localhost:9090/tasks/<task-id> curl http://localhost:9090/tasks/<task-id>
```plaintext ```text
--- ---
@ -676,7 +676,7 @@ docker-compose pull
# Rebuild with updates # Rebuild with updates
./scripts/deploy-platform.nu --pull --build ./scripts/deploy-platform.nu --pull --build
```plaintext ```text
--- ---
@ -692,7 +692,7 @@ docker run --rm -v provisioning_orchestrator-data:/data \
# Backup PostgreSQL # Backup PostgreSQL
docker exec provisioning-postgres pg_dumpall -U provisioning > backup/postgres-backup.sql docker exec provisioning-postgres pg_dumpall -U provisioning > backup/postgres-backup.sql
```plaintext ```text
### Restore ### Restore
@ -704,7 +704,7 @@ docker run --rm -v provisioning_orchestrator-data:/data \
# Restore PostgreSQL # Restore PostgreSQL
docker exec -i provisioning-postgres psql -U provisioning < backup/postgres-backup.sql docker exec -i provisioning-postgres psql -U provisioning < backup/postgres-backup.sql
```plaintext ```text
--- ---
@ -721,7 +721,7 @@ docker-compose up -d --force-recreate
# Remove old images # Remove old images
docker image prune docker image prune
```plaintext ```text
### Monitoring ### Monitoring
@ -738,7 +738,7 @@ docker image prune
# Manual checks # Manual checks
curl http://localhost:9090/health curl http://localhost:9090/health
curl http://localhost:8081/health curl http://localhost:8081/health
```plaintext ```text
--- ---

View File

@ -7,9 +7,11 @@
## ✅ Fixed: Docker Builds ## ✅ Fixed: Docker Builds
Docker builds have been **fixed** to properly handle the Rust workspace structure. Both deployment methods (Native and Docker) are now fully supported. Docker builds have been **fixed** to properly handle the Rust workspace structure. Both deployment methods (Native and Docker) are now fully
supported.
**Note**: Docker builds use Rust nightly to support edition2024 (required by async-graphql 7.x from surrealdb). RocksDB has been replaced with SurrealDB in-memory backend (kv-mem) to simplify Docker builds (no libclang requirement). **Note**: Docker builds use Rust nightly to support edition2024 (required by async-graphql 7.x from surrealdb).
RocksDB has been replaced with SurrealDB in-memory backend (kv-mem) to simplify Docker builds (no libclang requirement).
--- ---
@ -52,7 +54,7 @@ nu run-native.nu logs orchestrator --follow
# 5. Stop all # 5. Stop all
nu run-native.nu stop-all nu run-native.nu stop-all
``` ```text
**Services will run on:** **Services will run on:**
@ -87,7 +89,7 @@ nu run-docker.nu logs orchestrator --follow
# 5. Stop all # 5. Stop all
nu run-docker.nu stop nu run-docker.nu stop
``` ```text
**Deployment Modes:** **Deployment Modes:**
@ -103,7 +105,7 @@ nu run-docker.nu stop
### Native Execution (`run-native.nu`) ### Native Execution (`run-native.nu`)
| Command | Description | | Command | Description |
|---------|-------------| | --------- | ------------- |
| `build` | Build all services | | `build` | Build all services |
| `start <service>` | Start orchestrator or control_center | | `start <service>` | Start orchestrator or control_center |
| `start-all` | Start all services | | `start-all` | Start all services |
@ -122,14 +124,14 @@ nu run-native.nu start control_center --background
nu run-native.nu logs orchestrator --follow nu run-native.nu logs orchestrator --follow
nu run-native.nu health nu run-native.nu health
nu run-native.nu stop-all nu run-native.nu stop-all
``` ```text
--- ---
### Docker Execution (`run-docker.nu`) ### Docker Execution (`run-docker.nu`)
| Command | Description | | Command | Description |
|---------|-------------| | --------- | ------------- |
| `build [mode]` | Build Docker images | | `build [mode]` | Build Docker images |
| `start [mode]` | Start services (add `--detach`) | | `start [mode]` | Start services (add `--detach`) |
| `stop` | Stop all services (add `--volumes` to delete data) | | `stop` | Stop all services (add `--volumes` to delete data) |
@ -159,7 +161,7 @@ nu run-docker.nu logs control-center --follow
nu run-docker.nu exec orchestrator bash nu run-docker.nu exec orchestrator bash
nu run-docker.nu stats nu run-docker.nu stats
nu run-docker.nu stop nu run-docker.nu stop
``` ```text
--- ---
@ -211,7 +213,7 @@ Services load configuration in this order (priority: low → high):
cd provisioning/platform cd provisioning/platform
cargo clean cargo clean
cargo build --release cargo build --release
``` ```text
**Port already in use:** **Port already in use:**
@ -223,7 +225,7 @@ lsof -i :8081
# Kill the process or use different ports via environment variables # Kill the process or use different ports via environment variables
export ORCHESTRATOR_SERVER_PORT=8090 export ORCHESTRATOR_SERVER_PORT=8090
export CONTROL_CENTER_SERVER_PORT=8091 export CONTROL_CENTER_SERVER_PORT=8091
``` ```text
**Service won't start:** **Service won't start:**
@ -233,7 +235,7 @@ nu run-native.nu logs orchestrator
# Run in foreground to see output # Run in foreground to see output
nu run-native.nu start orchestrator nu run-native.nu start orchestrator
``` ```text
--- ---
@ -255,7 +257,7 @@ docker ps
docker info docker info
# Restart Docker/OrbStack # Restart Docker/OrbStack
``` ```text
**Port conflicts:** **Port conflicts:**
@ -265,7 +267,7 @@ lsof -i :8080
lsof -i :8081 lsof -i :8081
# Stop conflicting services or modify docker-compose.yaml ports # Stop conflicting services or modify docker-compose.yaml ports
``` ```text
**Out of resources:** **Out of resources:**
@ -278,7 +280,7 @@ docker system prune -a
# Or use the script # Or use the script
nu run-docker.nu clean --all nu run-docker.nu clean --all
``` ```text
--- ---
@ -291,7 +293,7 @@ Enterprise mode includes Cosmian KMS for production-grade secret management.
```bash ```bash
nu run-docker.nu build enterprise nu run-docker.nu build enterprise
nu run-docker.nu start enterprise --detach nu run-docker.nu start enterprise --detach
``` ```text
**Access KMS:** **Access KMS:**
@ -318,13 +320,13 @@ nu run-docker.nu start enterprise --detach
```bash ```bash
nu run-native.nu health nu run-native.nu health
``` ```text
**Docker:** **Docker:**
```bash ```bash
nu run-docker.nu health nu run-docker.nu health
``` ```text
**Manual:** **Manual:**
@ -332,7 +334,7 @@ nu run-docker.nu health
curl http://localhost:8080/health # Orchestrator curl http://localhost:8080/health # Orchestrator
curl http://localhost:8081/health # Control Center curl http://localhost:8081/health # Control Center
curl http://localhost:9998/health # KMS (enterprise only) curl http://localhost:9998/health # KMS (enterprise only)
``` ```text
### Resource Usage ### Resource Usage
@ -340,14 +342,14 @@ curl http://localhost:9998/health # KMS (enterprise only)
```bash ```bash
nu run-docker.nu stats nu run-docker.nu stats
``` ```text
**Native:** **Native:**
```bash ```bash
ps aux | grep -E "provisioning-orchestrator|control-center" ps aux | grep -E "provisioning-orchestrator|control-center"
top -pid <pid> top -pid <pid>
``` ```text
--- ---
@ -374,7 +376,7 @@ curl http://localhost:8081/health
# 5. Clean up # 5. Clean up
nu run-native.nu stop-all nu run-native.nu stop-all
``` ```text
### Test Docker Deployment ### Test Docker Deployment
@ -397,7 +399,7 @@ curl http://localhost:8081/health
# 5. Clean up # 5. Clean up
nu run-docker.nu stop --volumes nu run-docker.nu stop --volumes
``` ```text
--- ---

View File

@ -17,7 +17,7 @@ feature 'edition2024' is required
this Cargo does not support nightly features, but if you this Cargo does not support nightly features, but if you
switch to nightly channel you can add switch to nightly channel you can add
`cargo-features = ["edition2024"]` to enable this feature `cargo-features = ["edition2024"]` to enable this feature
```plaintext ```text
### Root Cause ### Root Cause
@ -25,9 +25,10 @@ Dependency chain:
```plaintext ```plaintext
control-center → surrealdb 2.3.10 → surrealdb-core 2.3.10 → async-graphql 7.0.17 control-center → surrealdb 2.3.10 → surrealdb-core 2.3.10 → async-graphql 7.0.17
```plaintext ```text
The `async-graphql-value` crate v7.0.17 requires Rust edition 2024, which is not yet stable in Rust 1.82. Edition 2024 is currently only available in Rust nightly builds. The `async-graphql-value` crate v7.0.17 requires Rust edition 2024, which is not yet stable in Rust 1.82.
Edition 2024 is currently only available in Rust nightly builds.
### Resolution ### Resolution
@ -37,7 +38,7 @@ Both `orchestrator/Dockerfile` and `control-center/Dockerfile` now use:
```dockerfile ```dockerfile
FROM rustlang/rust:nightly-bookworm AS builder FROM rustlang/rust:nightly-bookworm AS builder
```plaintext ```text
This provides edition2024 support required by the surrealdb dependency chain. This provides edition2024 support required by the surrealdb dependency chain.
@ -56,7 +57,7 @@ This provides edition2024 support required by the surrealdb dependency chain.
cd provisioning/platform/scripts cd provisioning/platform/scripts
nu run-native.nu build nu run-native.nu build
nu run-native.nu start-all --background nu run-native.nu start-all --background
```plaintext ```text
### Timeline ### Timeline

View File

@ -11,7 +11,7 @@ Fast deployment guide for all modes.
docker --version # 20.10+ docker --version # 20.10+
docker-compose --version # 2.0+ docker-compose --version # 2.0+
docker ps # Should work without errors docker ps # Should work without errors
``` ```text
--- ---
@ -36,13 +36,13 @@ cd /Users/Akasha/project-provisioning/provisioning/platform
# Access # Access
open http://localhost:8080 # Orchestrator open http://localhost:8080 # Orchestrator
open http://localhost:8081 # Control Center open http://localhost:8081 # Control Center
``` ```text
**Stop**: **Stop**:
```bash ```bash
docker-compose down docker-compose down
``` ```text
--- ---
@ -67,7 +67,7 @@ cd /Users/Akasha/project-provisioning/provisioning/platform
# Access # Access
open http://localhost:3000 # Gitea open http://localhost:3000 # Gitea
open http://localhost:8081 # Control Center open http://localhost:8081 # Control Center
``` ```text
**Configure Gitea**: **Configure Gitea**:
@ -97,7 +97,7 @@ cd /Users/Akasha/project-provisioning/provisioning/platform
# Access # Access
open http://localhost:8083 # API Server open http://localhost:8083 # API Server
``` ```text
--- ---
@ -129,7 +129,7 @@ nano .env.production
open http://localhost:3001 # Grafana (admin / password from .env) open http://localhost:3001 # Grafana (admin / password from .env)
open http://localhost:9090 # Prometheus open http://localhost:9090 # Prometheus
open http://localhost:5601 # Kibana open http://localhost:5601 # Kibana
``` ```text
--- ---
@ -141,33 +141,33 @@ open http://localhost:5601 # Kibana
docker-compose logs -f docker-compose logs -f
docker-compose logs -f orchestrator docker-compose logs -f orchestrator
docker-compose logs --tail=100 orchestrator docker-compose logs --tail=100 orchestrator
``` ```text
### Restart Services ### Restart Services
```bash ```bash
docker-compose restart orchestrator docker-compose restart orchestrator
docker-compose restart docker-compose restart
``` ```text
### Update Platform ### Update Platform
```bash ```bash
docker-compose pull docker-compose pull
./scripts/deploy-platform.nu --mode <your-mode> --pull ./scripts/deploy-platform.nu --mode <your-mode> --pull
``` ```text
### Stop Platform ### Stop Platform
```bash ```bash
docker-compose down docker-compose down
``` ```text
### Clean Everything (WARNING: data loss) ### Clean Everything (WARNING: data loss)
```bash ```bash
docker-compose down --volumes docker-compose down --volumes
``` ```text
--- ---
@ -192,7 +192,7 @@ sudo systemctl restart provisioning-platform
# Stop # Stop
sudo systemctl stop provisioning-platform sudo systemctl stop provisioning-platform
``` ```text
--- ---
@ -209,7 +209,7 @@ docker-compose logs orchestrator
# Check resources # Check resources
docker stats docker stats
``` ```text
### Port conflicts ### Port conflicts
@ -223,7 +223,7 @@ nano .env
# Restart # Restart
docker-compose down && docker-compose up -d docker-compose down && docker-compose up -d
``` ```text
### Health checks failing ### Health checks failing
@ -236,7 +236,7 @@ curl http://localhost:8080/health
# Check networks # Check networks
docker network inspect provisioning-net docker network inspect provisioning-net
``` ```text
--- ---

View File

@ -1,491 +0,0 @@
# OCI Registry Service - Implementation Summary
**Date**: 2025-01-06
**Status**: ✅ Complete
**Agent**: OCI Registry Service Agent
## Overview
Comprehensive OCI (Open Container Initiative) registry deployment and management system has been successfully implemented for the provisioning platform. The system supports three registry implementations (Zot, Harbor, Distribution) with complete tooling for deployment, management, and migration.
## Implementation Components
### 1. Registry Configurations
#### Zot (Lightweight Registry)
- **Location**: `provisioning/platform/oci-registry/zot/`
- **Configuration**: `config.json` (280 lines)
- **Docker Compose**: `docker-compose.yml`
- **Custom Dockerfile**: Extended with health checks and tools
- **Features**:
- Built-in UI and search
- Prometheus metrics
- Automatic garbage collection
- Access control policies
- Deduplication and compression
#### Harbor (Enterprise Registry)
- **Location**: `provisioning/platform/oci-registry/harbor/`
- **Configuration**: `harbor.yml` (70 lines)
- **Docker Compose**: `docker-compose.yml` (multi-container)
- **Components**:
- Registry core
- PostgreSQL database
- Nginx proxy
- Trivy scanner
- Job service
- Portal UI
#### Distribution (OCI Reference)
- **Location**: `provisioning/platform/oci-registry/distribution/`
- **Configuration**: `config.yml` (80 lines)
- **Docker Compose**: `docker-compose.yml`
- **Features**:
- OCI standard compliance
- Optional Redis caching
- Registry UI (Joxit)
- Webhook notifications
- Debug metrics endpoint
### 2. Management Scripts (Nushell)
#### Init Registry (`scripts/init-registry.nu` - 230 lines)
- Registry initialization with namespaces
- Health check waiting logic
- Policy configuration
- Test image pushing
- Multi-registry support
#### Setup Namespaces (`scripts/setup-namespaces.nu` - 260 lines)
- Default namespace definitions
- Retention policy configuration
- Security settings
- Quota management
- Harbor/Zot/Distribution specific implementations
#### Configure Policies (`scripts/configure-policies.nu` - 280 lines)
- Access control policies
- RBAC configuration
- Webhook setup
- User management
- Harbor API integration
#### Generate Certificates (`scripts/generate-certs.nu` - 150 lines)
- TLS certificate generation
- CA certificate creation
- SAN (Subject Alternative Names)
- Certificate verification
- Trust chain validation
#### Create Users (`scripts/create-users.nu` - 140 lines)
- htpasswd file management
- Default user creation
- Password management
- User listing and removal
- bcrypt password hashing
#### Test Registry (`scripts/test-registry.nu` - 250 lines)
- API health checks
- Catalog validation
- Push/pull testing
- Metrics verification
- Performance testing
- Load testing support
#### Migrate Registry (`scripts/migrate-registry.nu` - 320 lines)
- Inter-registry migration
- Namespace synchronization
- Docker-based migration
- Skopeo-based migration
- Backup to tar files
- Restore from tar files
### 3. Management Commands (Nushell Library)
#### Commands Module (`lib_provisioning/oci_registry/commands.nu` - 380 lines)
- `oci-registry start` - Start registry service
- `oci-registry stop` - Stop registry service
- `oci-registry status` - Get registry status
- `oci-registry init` - Initialize registry
- `oci-registry configure` - Configure settings
- `oci-registry logs` - View logs
- `oci-registry health` - Health check
- `oci-registry test-push` - Push test image
- `oci-registry test-pull` - Pull test image
- `oci-registry namespaces` - List namespaces
- `oci-registry namespace create` - Create namespace
- `oci-registry namespace delete` - Delete namespace
#### Service Module (`lib_provisioning/oci_registry/service.nu` - 350 lines)
- `start-oci-registry` - Service startup
- `stop-oci-registry` - Service shutdown
- `get-oci-registry-status` - Status retrieval
- `check-oci-registry-health` - Health checking
- `get-oci-registry-info` - Registry information
- `get-oci-registry-repositories` - Repository listing
- `get-oci-repository-tags` - Tag listing
- `get-oci-image-manifest` - Manifest retrieval
- `delete-oci-image-tag` - Image deletion
- `run-oci-registry-gc` - Garbage collection
- `get-oci-registry-metrics` - Metrics retrieval
- `push-oci-artifact` - Artifact pushing
- `pull-oci-artifact` - Artifact pulling
### 4. Testing
#### Test Suite (`tests/test_oci_registry.nu` - 180 lines)
- ✅ Registry directories validation
- ✅ Zot configuration validation
- ✅ Harbor configuration validation
- ✅ Distribution configuration validation
- ✅ Docker Compose files validation
- ✅ Script files validation
- ✅ Module existence checks
- ✅ Namespace definitions validation
- ✅ Policy definitions validation
- ✅ Health check logic validation
- ✅ Registry types validation
**Test Results**: All 12 tests passed ✅
### 5. Documentation
#### README (`README.md` - 900 lines)
Comprehensive guide covering:
- Registry types comparison
- Quick start guides
- Installation procedures
- Configuration reference
- Management commands
- Namespace organization
- Access control
- Monitoring and metrics
- Troubleshooting guide
- Advanced usage patterns
- API reference
- Performance tuning
- Security best practices
- Backup and restore
- Migration procedures
## Default Namespaces
| Namespace | Description | Public | Retention |
|-----------|-------------|--------|-----------|
| `provisioning-extensions` | Extension packages (providers, taskservs, clusters) | No | 10 tags, 90 days |
| `provisioning-kcl` | KCL schema packages | No | 20 tags, 180 days |
| `provisioning-platform` | Platform service images | No | 5 tags, 30 days |
| `provisioning-test` | Test images and artifacts | Yes | 3 tags, 7 days |
## Access Policies
### provisioning-extensions
- **Authenticated**: Read, Write, Delete
- **Anonymous**: None
- **Users**: provisioning (admin), developer
### provisioning-kcl
- **Authenticated**: Read, Write
- **Anonymous**: None
- **Users**: provisioning (admin), developer
### provisioning-platform
- **Authenticated**: Read only (except admin)
- **Anonymous**: None
- **Users**: provisioning (admin)
### provisioning-test
- **Authenticated**: Read, Write, Delete
- **Anonymous**: Read only
- **Users**: provisioning (admin), developer, tester
## Registry Comparison
| Feature | Zot | Harbor | Distribution |
|---------|-----|--------|--------------|
| **Startup Time** | Fast (~5s) | Slow (~2min) | Fast (~5s) |
| **Resource Usage** | Low | High | Low |
| **Built-in UI** | Yes | Yes | No (optional) |
| **Search** | Yes | Yes | No |
| **RBAC** | Basic | Advanced | Basic |
| **Scanning** | No | Yes (Trivy) | No |
| **Replication** | No | Yes | No |
| **Metrics** | Prometheus | Prometheus | Prometheus |
| **GC** | Automatic | Manual/Scheduled | Manual |
| **Use Case** | Development | Production | Standard |
## Usage Examples
### Start Zot Registry
```bash
# Using Docker Compose
cd provisioning/platform/oci-registry/zot
docker-compose up -d
# Initialize
nu ../scripts/init-registry.nu --registry-type zot
# Check health
nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; oci-registry health"
```plaintext
### Start Harbor Registry
```bash
# Using Docker Compose
cd provisioning/platform/oci-registry/harbor
docker-compose up -d
# Wait for startup
sleep 120
# Initialize
nu ../scripts/init-registry.nu --registry-type harbor --admin-password Harbor12345
# Access UI
open http://localhost
```plaintext
### Migrate Between Registries
```bash
# Migrate from Zot to Harbor
nu scripts/migrate-registry.nu \
--source-registry localhost:5000 \
--source-type zot \
--dest-registry localhost:80 \
--dest-type harbor
# Sync specific namespace
nu scripts/migrate-registry.nu sync namespace provisioning-extensions \
--source-registry localhost:5000 \
--dest-registry localhost:80
```plaintext
## File Structure
```plaintext
provisioning/platform/oci-registry/
├── zot/
│ ├── config.json (280 lines)
│ ├── docker-compose.yml
│ ├── Dockerfile
│ └── healthcheck.sh
├── harbor/
│ ├── harbor.yml (70 lines)
│ └── docker-compose.yml
├── distribution/
│ ├── config.yml (80 lines)
│ └── docker-compose.yml
├── scripts/
│ ├── init-registry.nu (230 lines)
│ ├── setup-namespaces.nu (260 lines)
│ ├── configure-policies.nu (280 lines)
│ ├── generate-certs.nu (150 lines)
│ ├── create-users.nu (140 lines)
│ ├── test-registry.nu (250 lines)
│ └── migrate-registry.nu (320 lines)
├── README.md (900 lines)
└── IMPLEMENTATION_SUMMARY.md (this file)
provisioning/core/nulib/lib_provisioning/oci_registry/
├── commands.nu (380 lines)
├── service.nu (350 lines)
└── mod.nu
provisioning/core/nulib/tests/
└── test_oci_registry.nu (180 lines)
```plaintext
## Statistics
- **Total Files Created**: 22
- **Total Lines of Code**: ~4,000
- **Configuration Files**: 6
- **Nushell Scripts**: 7
- **Nushell Libraries**: 3
- **Documentation**: 2
- **Docker Compose Files**: 3
- **Test Files**: 1
## Integration Points
### Extension Loader Integration
The OCI registry serves as the primary artifact source for the extension loader system:
```nushell
# Extension loader will pull from registry
oci-registry pull provisioning-extensions/provider-aws:latest
oci-registry pull provisioning-extensions/taskserv-kubernetes:1.28.0
oci-registry pull provisioning-kcl/core-schemas:latest
```plaintext
### Mode System Integration
Each mode can have its own registry configuration:
```toml
# Development mode - use Zot
[modes.dev.registry]
type = "zot"
url = "localhost:5000"
# Production mode - use Harbor
[modes.prod.registry]
type = "harbor"
url = "harbor.production.local"
```plaintext
### Orchestrator Integration
The orchestrator can trigger registry operations:
```rust
// Pull extension from registry
registry.pull("provisioning-extensions/provider-aws:latest")?;
// Extract to extensions directory
extensions.install("provider-aws", artifact)?;
```plaintext
## Security Features
1. **TLS/SSL Support**: Full certificate management
2. **Authentication**: htpasswd, token-based
3. **Access Control**: Namespace-level policies
4. **Vulnerability Scanning**: Harbor Trivy integration
5. **Webhook Notifications**: Event-based notifications
6. **Audit Logging**: All operations logged
7. **Secret Management**: No plaintext credentials
8. **Network Isolation**: Docker network separation
## Performance Optimizations
1. **Deduplication**: Zot automatic layer deduplication
2. **Caching**: Redis backend for Distribution
3. **Compression**: Automatic artifact compression
4. **Garbage Collection**: Automatic cleanup (Zot)
5. **HTTP/2**: Enabled for all registries
6. **Connection Pooling**: Database connection pools
7. **Metrics**: Prometheus monitoring
## Monitoring & Observability
### Metrics Endpoints
- **Zot**: `http://localhost:5000/metrics`
- **Harbor**: `http://localhost:9090/metrics`
- **Distribution**: `http://localhost:5001/metrics`
### Health Checks
- API endpoint: `/v2/`
- Catalog endpoint: `/v2/_catalog`
- Container health checks
- Nushell health check commands
### Logging
- Docker Compose logs
- Registry-specific log files
- Structured JSON logging
- Log rotation
## Future Enhancements
1. **HA Configuration**: High availability setup
2. **S3 Backend**: Cloud storage integration
3. **Content Trust**: Image signing and verification
4. **Rate Limiting**: API rate limiting
5. **CDN Integration**: Content delivery network
6. **Multi-Region**: Geographic distribution
7. **Auto-Scaling**: Dynamic resource scaling
8. **Advanced RBAC**: Fine-grained permissions
## Recommendations
### For Development
**Use Zot**:
- Fast startup
- Low resource usage
- Built-in UI
- Good for CI/CD
### For Production
**Use Harbor**:
- Enterprise features
- Vulnerability scanning
- Advanced RBAC
- Replication support
### For Standards Compliance
**Use Distribution**:
- OCI reference implementation
- Minimal footprint
- Standard compliance
## Known Limitations
1. **Zot**: Less mature than Distribution, fewer enterprise features
2. **Harbor**: Higher resource requirements, slower startup
3. **Distribution**: No built-in UI, manual GC required
4. **All**: Require Docker daemon for container management
## Testing Coverage
- ✅ Configuration validation
- ✅ File structure validation
- ✅ Module loading
- ✅ Script execution
- ⚠️ Live registry tests (require running instance)
- ⚠️ Integration tests (require orchestrator)
- ⚠️ Performance tests (require load testing tools)
## Conclusion
The OCI Registry Service implementation provides a comprehensive, production-ready solution for artifact management in the provisioning platform. With support for three registry types (Zot, Harbor, Distribution), complete management tooling, and extensive documentation, teams can choose the right registry for their specific needs.
The system integrates seamlessly with the extension loader, mode system, and orchestrator, providing a unified artifact distribution mechanism for the entire platform.
---
**Implementation Status**: ✅ Complete and Tested
**Documentation Status**: ✅ Complete
**Integration Status**: 🟡 Ready (pending orchestrator integration)
**Production Ready**: ✅ Yes (with Harbor for production, Zot for dev)
**Next Steps**:
1. Integrate with extension loader
2. Add to mode system configuration
3. Implement orchestrator registry client
4. Set up CI/CD pipelines for artifact publishing
5. Deploy production Harbor instance
6. Configure backup/restore automation

View File

@ -1,6 +1,8 @@
# OCI Registry Service # OCI Registry Service
Comprehensive OCI (Open Container Initiative) registry deployment and management for the provisioning system. Supports multiple registry implementations: **Zot** (lightweight), **Harbor** (full-featured), and **Distribution** (OCI reference implementation). Comprehensive OCI (Open Container Initiative) registry deployment and management for the provisioning system.
Supports multiple registry implementations: **Zot** (lightweight), **Harbor** (full-featured),
and **Distribution** (OCI reference implementation).
## Table of Contents ## Table of Contents
@ -130,7 +132,7 @@ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; oci-registry h
# Access UI # Access UI
open http://localhost:5000 open http://localhost:5000
```plaintext ```text
### Start Harbor Registry ### Start Harbor Registry
@ -148,7 +150,7 @@ nu ../scripts/init-registry.nu --registry-type harbor --admin-password Harbor123
# Access UI # Access UI
open http://localhost open http://localhost
# Login: admin / Harbor12345 # Login: admin / Harbor12345
```plaintext ```text
### Start Distribution Registry ### Start Distribution Registry
@ -162,7 +164,7 @@ nu ../scripts/init-registry.nu --registry-type distribution
# Access UI (if included) # Access UI (if included)
open http://localhost:8080 open http://localhost:8080
```plaintext ```text
## Installation ## Installation
@ -193,7 +195,7 @@ nu ../scripts/init-registry.nu --registry-type $REGISTRY_TYPE
# Verify # Verify
docker-compose ps docker-compose ps
```plaintext ```text
## Configuration ## Configuration
@ -233,7 +235,7 @@ Key settings:
} }
} }
} }
```plaintext ```text
### Harbor Configuration ### Harbor Configuration
@ -254,7 +256,7 @@ trivy:
log: log:
level: info level: info
```plaintext ```text
### Distribution Configuration ### Distribution Configuration
@ -279,7 +281,7 @@ auth:
htpasswd: htpasswd:
realm: Registry realm: Registry
path: /etc/docker/registry/htpasswd path: /etc/docker/registry/htpasswd
```plaintext ```text
## Management ## Management
@ -306,7 +308,7 @@ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; oci-registry i
# List namespaces # List namespaces
nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; oci-registry namespaces" nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; oci-registry namespaces"
```plaintext ```text
### Using Docker Compose ### Using Docker Compose
@ -326,14 +328,14 @@ docker-compose restart
# Remove (including volumes) # Remove (including volumes)
docker-compose down -v docker-compose down -v
```plaintext ```text
## Namespaces ## Namespaces
### Default Namespaces ### Default Namespaces
| Namespace | Description | Public | Retention | | Namespace | Description | Public | Retention |
|-----------|-------------|--------|-----------| | ----------- | ------------- | -------- | ----------- |
| `provisioning-extensions` | Extension packages | No | 10 tags, 90 days | | `provisioning-extensions` | Extension packages | No | 10 tags, 90 days |
| `provisioning-kcl` | KCL schemas | No | 20 tags, 180 days | | `provisioning-kcl` | KCL schemas | No | 20 tags, 180 days |
| `provisioning-platform` | Platform images | No | 5 tags, 30 days | | `provisioning-platform` | Platform images | No | 5 tags, 30 days |
@ -354,7 +356,7 @@ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; \
# Get namespace info # Get namespace info
nu scripts/setup-namespaces.nu namespace info provisioning-extensions nu scripts/setup-namespaces.nu namespace info provisioning-extensions
```plaintext ```text
## Access Control ## Access Control
@ -393,7 +395,7 @@ nu scripts/configure-policies.nu policy show provisioning-extensions
# List all policies # List all policies
nu scripts/configure-policies.nu policy list nu scripts/configure-policies.nu policy list
```plaintext ```text
### Authentication ### Authentication
@ -405,7 +407,7 @@ htpasswd -Bc htpasswd provisioning
# Login # Login
docker login localhost:5000 docker login localhost:5000
```plaintext ```text
**Harbor (Database):** **Harbor (Database):**
@ -417,7 +419,7 @@ docker login localhost
# Create users via Harbor UI # Create users via Harbor UI
# Admin → Users → New User # Admin → Users → New User
```plaintext ```text
## Monitoring ## Monitoring
@ -433,7 +435,7 @@ curl http://localhost:5000/v2/
# Catalog check # Catalog check
curl http://localhost:5000/v2/_catalog curl http://localhost:5000/v2/_catalog
```plaintext ```text
### Metrics ### Metrics
@ -446,14 +448,14 @@ curl http://localhost:5000/metrics
# Visualize with Prometheus # Visualize with Prometheus
# Add to prometheus.yml: # Add to prometheus.yml:
# - targets: ['localhost:5000'] # - targets: ['localhost:5000']
```plaintext ```text
**Distribution:** **Distribution:**
```bash ```bash
# Metrics on debug port # Metrics on debug port
curl http://localhost:5001/metrics curl http://localhost:5001/metrics
```plaintext ```text
**Harbor:** **Harbor:**
@ -463,7 +465,7 @@ curl http://localhost:9090/metrics
# View in Harbor UI # View in Harbor UI
# Admin → System Settings → Metrics # Admin → System Settings → Metrics
```plaintext ```text
### Logs ### Logs
@ -480,7 +482,7 @@ docker-compose logs -f registry
# Nushell command # Nushell command
nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; \ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry; \
oci-registry logs --type zot --follow --tail 100" oci-registry logs --type zot --follow --tail 100"
```plaintext ```text
## Troubleshooting ## Troubleshooting
@ -499,7 +501,7 @@ docker-compose logs
# Rebuild # Rebuild
docker-compose down -v docker-compose down -v
docker-compose up -d --build docker-compose up -d --build
```plaintext ```text
### Cannot Push Images ### Cannot Push Images
@ -515,7 +517,7 @@ df -h # Ensure disk space available
# Check registry health # Check registry health
curl http://localhost:5000/v2/ curl http://localhost:5000/v2/
```plaintext ```text
### Slow Performance ### Slow Performance
@ -529,7 +531,7 @@ curl http://localhost:5000/v2/
# Run garbage collection # Run garbage collection
nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry/service; \ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry/service; \
run-oci-registry-gc --type zot" run-oci-registry-gc --type zot"
```plaintext ```text
### TLS/Certificate Issues ### TLS/Certificate Issues
@ -543,7 +545,7 @@ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry/service; \
# Skip TLS verification (testing only) # Skip TLS verification (testing only)
docker login --insecure localhost:5000 docker login --insecure localhost:5000
```plaintext ```text
## Advanced Usage ## Advanced Usage
@ -566,7 +568,7 @@ nginx:
depends_on: depends_on:
- registry-1 - registry-1
- registry-2 - registry-2
```plaintext ```text
### S3 Backend (Distribution) ### S3 Backend (Distribution)
@ -579,7 +581,7 @@ storage:
region: us-west-1 region: us-west-1
bucket: my-registry-bucket bucket: my-registry-bucket
rootdirectory: /registry rootdirectory: /registry
```plaintext ```text
### Replication (Harbor) ### Replication (Harbor)
@ -588,7 +590,7 @@ storage:
# Source: Local registry # Source: Local registry
# Destination: Remote registry # Destination: Remote registry
# Trigger: Manual/Scheduled/Event-based # Trigger: Manual/Scheduled/Event-based
```plaintext ```text
### Webhooks ### Webhooks
@ -610,14 +612,14 @@ storage:
} }
} }
} }
```plaintext ```text
**Harbor** (via scripts): **Harbor** (via scripts):
```bash ```bash
nu scripts/configure-policies.nu --registry-type harbor nu scripts/configure-policies.nu --registry-type harbor
# Webhooks configured automatically # Webhooks configured automatically
```plaintext ```text
### Garbage Collection ### Garbage Collection
@ -630,7 +632,7 @@ nu scripts/configure-policies.nu --registry-type harbor
"gcInterval": "24h" "gcInterval": "24h"
} }
} }
```plaintext ```text
**Distribution** (manual): **Distribution** (manual):
@ -642,13 +644,13 @@ docker-compose exec registry \
# Or via Nushell # Or via Nushell
nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry/service; \ nu -c "use provisioning/core/nulib/lib_provisioning/oci_registry/service; \
run-oci-registry-gc --type distribution" run-oci-registry-gc --type distribution"
```plaintext ```text
**Harbor** (UI): **Harbor** (UI):
```plaintext ```plaintext
Admin → System Settings → Garbage Collection → Run GC Admin → System Settings → Garbage Collection → Run GC
```plaintext ```text
## API Reference ## API Reference
@ -666,7 +668,7 @@ curl http://localhost:5000/v2/{repository}/manifests/{tag}
# Delete image (requires delete enabled) # Delete image (requires delete enabled)
curl -X DELETE http://localhost:5000/v2/{repository}/manifests/{digest} curl -X DELETE http://localhost:5000/v2/{repository}/manifests/{digest}
```plaintext ```text
### Harbor API ### Harbor API
@ -684,7 +686,7 @@ curl -X POST -u admin:Harbor12345 \
# Scan image # Scan image
curl -X POST -u admin:Harbor12345 \ curl -X POST -u admin:Harbor12345 \
http://localhost/api/v2.0/projects/{project}/repositories/{repo}/artifacts/{tag}/scan http://localhost/api/v2.0/projects/{project}/repositories/{repo}/artifacts/{tag}/scan
```plaintext ```text
## Performance Tuning ## Performance Tuning
@ -701,7 +703,7 @@ curl -X POST -u admin:Harbor12345 \
"http2": true // Enable HTTP/2 "http2": true // Enable HTTP/2
} }
} }
```plaintext ```text
### Distribution ### Distribution
@ -715,7 +717,7 @@ redis:
pool: pool:
maxidle: 16 maxidle: 16
maxactive: 64 maxactive: 64
```plaintext ```text
### Harbor ### Harbor
@ -726,7 +728,7 @@ jobservice:
database: database:
max_idle_conns: 100 max_idle_conns: 100
max_open_conns: 900 # Increase DB connections max_open_conns: 900 # Increase DB connections
```plaintext ```text
## Security Best Practices ## Security Best Practices
@ -761,7 +763,7 @@ tar czf harbor-backup-$(date +%Y%m%d).tar.gz \
docker-compose stop registry docker-compose stop registry
tar czf dist-backup-$(date +%Y%m%d).tar.gz \ tar czf dist-backup-$(date +%Y%m%d).tar.gz \
-C /var/lib/docker/volumes registry-data -C /var/lib/docker/volumes registry-data
```plaintext ```text
### Restore ### Restore
@ -770,7 +772,7 @@ tar czf dist-backup-$(date +%Y%m%d).tar.gz \
docker-compose down -v docker-compose down -v
tar xzf zot-backup-20250106.tar.gz -C /var/lib/docker/volumes tar xzf zot-backup-20250106.tar.gz -C /var/lib/docker/volumes
docker-compose up -d docker-compose up -d
```plaintext ```text
## Migration Between Registries ## Migration Between Registries
@ -790,7 +792,7 @@ done
skopeo sync --src docker --dest docker \ skopeo sync --src docker --dest docker \
localhost:5000/provisioning-extensions \ localhost:5000/provisioning-extensions \
harbor.local/provisioning-extensions harbor.local/provisioning-extensions
```plaintext ```text
## References ## References

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# Setup Platform Configuration with Forms # Setup Platform Configuration with Forms
# Uses TypeDialog if available, falls back to FormInquire # Uses TypeDialog bash wrappers if available, falls back to basic prompts
set -euo pipefail set -euo pipefail
@ -8,11 +8,12 @@ set -euo pipefail
GREEN='\033[0;32m' GREEN='\033[0;32m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
BLUE='\033[0;34m' BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color NC='\033[0m' # No Color
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../" && pwd)" PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../" && pwd)"
TYPEDIALOG_DIR="${PROJECT_ROOT}/provisioning/platform/.typedialog" TYPEDIALOG_DIR="${PROJECT_ROOT}/provisioning/.typedialog/core"
FORMINQUIRE_DIR="${PROJECT_ROOT}/provisioning/core/forminquire" SHLIB_DIR="${PROJECT_ROOT}/provisioning/core/shlib"
CONFIG_DIR="${PROJECT_ROOT}/provisioning/platform/config" CONFIG_DIR="${PROJECT_ROOT}/provisioning/platform/config"
echo -e "${BLUE}═════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE}═════════════════════════════════════════════════════════════${NC}"
@ -73,32 +74,31 @@ setup_with_typedialog() {
echo -e "${GREEN}✅ TOML exported: $toml${NC}" echo -e "${GREEN}✅ TOML exported: $toml${NC}"
} }
# Function: Setup with FormInquire (Fallback) # Function: Setup with basic prompts (Fallback)
setup_with_forminquire() { setup_with_fallback() {
local service=$1 local service=$1
local mode=$2 local mode=$2
echo -e "${BLUE}→ Configuring $service for $mode mode (FormInquire)${NC}" echo -e "${BLUE}→ Configuring $service for $mode mode (basic prompts)${NC}"
echo -e "${YELLOW}⚠️ TypeDialog not available - using basic configuration${NC}"
local template="${FORMINQUIRE_DIR}/templates/${service}-${mode}.form.j2" local output="${CONFIG_DIR}/runtime/values/${service}.${mode}.ncl"
if [ ! -f "$template" ]; then
echo -e "${YELLOW}⚠️ Template not found: $template${NC}"
echo " Using generic template..."
template="${FORMINQUIRE_DIR}/templates/service-generic.form.j2"
fi
# Run FormInquire form
local output="${CONFIG_DIR}/runtime/${service}.${mode}.ncl"
mkdir -p "$(dirname "$output")" mkdir -p "$(dirname "$output")"
echo "Configure $service ($mode mode):" echo ""
echo "Leave blank to use defaults" echo "Using default configuration for $service in $mode mode"
echo "To customize, install TypeDialog or edit: $output"
echo "" echo ""
# This would call the actual FormInquire via Nushell # Use Nushell wizard with basic prompts as fallback
echo -e "${YELLOW}→ Would open FormInquire interactive form here${NC}" if command -v nu &> /dev/null; then
echo " (requires Nushell + nu_plugin_tera)" echo -e "${BLUE}→ Running Nushell setup wizard (basic prompts)${NC}"
nu -c "use ${PROJECT_ROOT}/provisioning/core/nulib/lib_provisioning/setup/wizard.nu *; run-setup-wizard" || true
else
echo -e "${RED}✗ Nushell not available - cannot run fallback wizard${NC}"
echo " Please install TypeDialog for full form support"
return 1
fi
} }
# Main setup flow # Main setup flow
@ -140,7 +140,7 @@ main() {
if [ "$USE_TYPEDIALOG" = true ]; then if [ "$USE_TYPEDIALOG" = true ]; then
setup_with_typedialog "$selected_service" "$selected_mode" setup_with_typedialog "$selected_service" "$selected_mode"
else else
setup_with_forminquire "$selected_service" "$selected_mode" setup_with_fallback "$selected_service" "$selected_mode"
fi fi
fi fi
fi fi
@ -153,7 +153,7 @@ main() {
if [ "$USE_TYPEDIALOG" = true ]; then if [ "$USE_TYPEDIALOG" = true ]; then
setup_with_typedialog "$service" "$mode" || true setup_with_typedialog "$service" "$mode" || true
else else
setup_with_forminquire "$service" "$mode" || true setup_with_fallback "$service" "$mode" || true
fi fi
done done
done done