Completed comprehensive spec-driven documentation: - SPEC.md (222 lines): Project scope, objectives, constraints - ARCHITECTURE.md (290 lines): System design, components, data flow - REQUIREMENTS.md (168 lines): Functional & non-functional requirements - API_SPEC.md (556 lines): 15 API endpoints with schemas - SECURITY.md (188 lines): STRIDE threat model, security controls - ROADMAP.md (203 lines): 5 phases, 8 milestones, risk register Total: 1,627 lines of specification documentation Milestone M1 complete - Ready for Phase 0 (Rust scaffolding)
11 KiB
Linux_Patch_API - API Specification Document
API Overview
Purpose: Secure REST API for remote package and patch management on Linux systems
Design Philosophy:
- Pure REST architecture (resources as nouns, HTTP verbs for actions)
- mTLS certificate-based authentication (no sessions)
- Hybrid execution model (sync for quick ops, async for long ops)
- Real-time status via WebSocket streaming
- JSON request/response with standard envelope
Base Path: /api/v1/
Protocol: HTTPS (TLS 1.3 only)
Port: 12443
Trailing Slashes: Not required
Authentication
Authentication Method
- Type: mTLS Certificate-Based Authentication
- CA: Internal self-hosted Certificate Authority
- Certificate Validity: 1 year maximum
- Client Identity: Unique certificate per client
- Session Management: None (stateless)
Authorization
- Method: IP Whitelist Enforcement
- Default: Deny all (block unless explicitly allowed)
- Permissions: Binary (whitelisted IP + valid cert = full access)
- No Granular Permissions: All authenticated clients have full API access
Connection Requirements
- Valid client certificate signed by internal CA
- Client IP must be in whitelist configuration
- TLS 1.3 only
- Silent drop for non-compliant connections (no response)
Standard Response Envelope
All API responses use this standard structure:
{
"success": true,
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-04-09T13:04:02Z",
"data": {},
"error": null
}
Fields:
| Field | Type | Description |
|---|---|---|
success |
boolean | true for successful requests, false for errors |
request_id |
UUID | Unique identifier for request tracking/auditing |
timestamp |
ISO 8601 | Server timestamp of response |
data |
object | Response payload (null on error) |
error |
object | Error details (null on success) |
Error Response Format
{
"success": false,
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-04-09T13:04:02Z",
"data": null,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description",
"details": {},
"retryable": false
}
}
Error Codes:
| Code | HTTP Status | Description |
|---|---|---|
AUTH_INVALID_CERT |
401 | Certificate validation failed |
AUTH_CERT_EXPIRED |
401 | Certificate has expired |
AUTHZ_IP_DENIED |
403 | IP not in whitelist |
PKG_NOT_FOUND |
404 | Package not found |
PKG_MANAGER_ERROR |
500 | Package manager operation failed |
JOB_NOT_FOUND |
404 | Job ID not found |
JOB_TIMEOUT |
408 | Job exceeded 30-minute timeout |
CONFIG_INVALID |
400 | Configuration validation failed |
SERVICE_UNHEALTHY |
503 | Service not ready |
Endpoints
Package Management Endpoints
POST /api/v1/packages
Description: Install one or more packages (async operation)
Request Body:
{
"packages": [
{
"name": "nginx",
"version": "1.24.0-1"
}
],
"options": {
"force": false,
"no_recommends": true
}
}
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"status": "pending",
"operation": "install",
"packages": ["nginx"]
},
"error": null
}
GET /api/v1/packages
Description: List installed packages with filtering and sorting
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
string | Filter by package name (supports wildcard *) |
status |
string | Filter: installed, upgradable, available |
upgradable |
boolean | true to show only upgradable packages |
sort |
string | Sort field: name, version, status (default: name) |
order |
string | Sort order: asc, desc (default: asc) |
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"packages": [
{
"name": "nginx",
"version": "1.24.0-1",
"status": "installed",
"upgradable": true,
"latest_version": "1.25.0-1",
"description": "High performance web server",
"dependencies": ["libc6", "libssl3"],
"reverse_dependencies": ["nginx-core"]
}
],
"total": 1
},
"error": null
}
GET /api/v1/packages/{name}
Description: Get details of a specific package
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"name": "nginx",
"version": "1.24.0-1",
"status": "installed",
"upgradable": true,
"latest_version": "1.25.0-1",
"description": "High performance web server",
"dependencies": ["libc6", "libssl3"],
"reverse_dependencies": ["nginx-core"],
"install_date": "2026-01-15T10:30:00Z",
"size_installed": "2.5 MB"
},
"error": null
}
PUT /api/v1/packages/{name}
Description: Update a specific package (async operation)
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"status": "pending",
"operation": "update",
"package": "nginx"
},
"error": null
}
DELETE /api/v1/packages/{name}
Description: Remove a package (async operation)
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"status": "pending",
"operation": "remove",
"package": "nginx"
},
"error": null
}
Patch Management Endpoints
GET /api/v1/patches
Description: List available updates/patches
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"patches": [
{
"name": "linux-kernel",
"current_version": "5.15.0-91",
"available_version": "5.15.0-92",
"severity": "critical",
"description": "Security update for kernel vulnerabilities",
"cve_ids": ["CVE-2024-1234"],
"requires_reboot": true
}
],
"total": 1,
"security_updates": 1,
"requires_reboot": true
},
"error": null
}
POST /api/v1/patches/apply
Description: Apply all or specific patches (async operation)
Request Body:
{
"packages": ["linux-kernel", "libc6"], // optional, all if omitted
"reboot": true, // optional, auto-reboot after patching
"reboot_delay_seconds": 60 // optional, delay before reboot
}
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"status": "pending",
"operation": "patch_apply",
"packages_count": 2,
"reboot_scheduled": true
},
"error": null
}
System Endpoints
GET /api/v1/system/info
Description: Get system information
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"hostname": "server01",
"os": "Ubuntu",
"os_version": "22.04 LTS",
"kernel": "5.15.0-91-generic",
"architecture": "x86_64",
"last_update_check": "2026-04-09T12:00:00Z",
"last_update_apply": "2026-04-01T03:00:00Z",
"pending_reboot": false
},
"error": null
}
GET /api/v1/health
Description: Health check endpoint
Response (200 OK - Healthy):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"status": "healthy",
"uptime_seconds": 12345,
"version": "0.0.1"
},
"error": null
}
Response (503 - Unhealthy):
{
"success": false,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": null,
"error": {
"code": "SERVICE_UNHEALTHY",
"message": "Service not ready",
"details": {},
"retryable": true
}
}
POST /api/v1/system/reboot
Description: Reboot the system (async operation)
Request Body:
{
"delay_seconds": 0, // optional, immediate if omitted
"force": false // optional, skip pending job checks
}
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"status": "pending",
"operation": "reboot",
"scheduled_at": "2026-04-09T13:04:02Z"
},
"error": null
}
Job Management Endpoints
GET /api/v1/jobs
Description: List all jobs with optional filtering
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter: pending, running, completed, failed, cancelled |
limit |
integer | Max results (default: 50, no pagination beyond limit) |
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"jobs": [
{
"job_id": "uuid",
"operation": "install",
"status": "completed",
"created_at": "2026-04-09T13:00:00Z",
"completed_at": "2026-04-09T13:02:00Z",
"packages": ["nginx"]
}
],
"total": 1
},
"error": null
}
GET /api/v1/jobs/{id}
Description: Get specific job status
Response (200 OK):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid",
"operation": "install",
"status": "running",
"progress": 45,
"message": "Downloading package...",
"created_at": "2026-04-09T13:00:00Z",
"completed_at": null,
"packages": ["nginx"],
"logs": ["Starting installation...", "Resolving dependencies..."]
},
"error": null
}
POST /api/v1/jobs/{id}/rollback
Description: Rollback a completed/failed job (async, exclusive mode)
Response (202 Accepted):
{
"success": true,
"request_id": "uuid",
"timestamp": "2026-04-09T13:04:02Z",
"data": {
"job_id": "uuid-rollback",
"status": "pending",
"operation": "rollback",
"original_job_id": "uuid",
"exclusive_mode": true
},
"error": null
}
WebSocket: /api/v1/ws/jobs
Description: Real-time job status streaming
Connection: Upgrade HTTP connection with mTLS
Client → Server (subscribe):
{
"action": "subscribe",
"job_id": "uuid" // optional, omit for all jobs
}
Server → Client (status update):
{
"event": "job_status",
"job_id": "uuid",
"status": "running",
"progress": 45,
"message": "Installing package...",
"timestamp": "2026-04-09T13:04:02Z"
}
Server → Client (job complete):
{
"event": "job_complete",
"job_id": "uuid",
"status": "completed",
"progress": 100,
"message": "Installation complete",
"timestamp": "2026-04-09T13:04:02Z"
}
---
## Rate Limiting
**Not Required:** Internal network only with strict IP whitelist
---
## Versioning Strategy
- **Method:** URL Path Versioning (`/api/v1/`)
- **Backward Compatibility:** Breaking changes require new major version
- **Deprecation:** Old versions supported for 6 months after new version release
- **Current Version:** v1
---
*Following kiro spec-driven development standards*