feat: add K8s API server, orchestrator abstraction, and CI pipeline
- Add apps/api/ — Hono REST API server for managing pentest scans via K8s Jobs - POST/GET /api/scans, GET /api/scans/:id, cancel, report endpoints - Bearer token auth, Temporal client integration, K8s Job builder - Dockerfile, Kustomize manifests (Deployment, Service, RBAC) - Add CLI orchestrator abstraction (docker.ts → Orchestrator interface) - DockerOrchestrator and K8sOrchestrator implementations - Backend detection via SHANNON_BACKEND env var or --backend flag - Add CI workflow: type-check + lint on PR, build+push both images on main - Switch all workflows to self-hosted runners (runners-farhoodliquor) - Add shannon-api image build to release and release-beta workflows - Add root infra/kustomization.yaml as Flux entry point - Export PipelineProgress from @shannon/worker/pipeline Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Shannon API Server — entry point.
|
||||
* Connects to Temporal, initializes K8s client, starts the Hono server.
|
||||
*/
|
||||
|
||||
import { serve } from '@hono/node-server';
|
||||
import * as k8s from '@kubernetes/client-node';
|
||||
import { createApp } from './app.js';
|
||||
import { loadConfig } from './config.js';
|
||||
import { connectTemporal, disconnectTemporal } from './services/temporal-client.js';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
// 1. Load configuration
|
||||
const config = loadConfig();
|
||||
|
||||
// 2. Connect to Temporal
|
||||
const temporal = await connectTemporal(config.temporalAddress);
|
||||
|
||||
// 3. Initialize K8s client (in-cluster or from kubeconfig)
|
||||
const kc = new k8s.KubeConfig();
|
||||
try {
|
||||
kc.loadFromCluster();
|
||||
} catch {
|
||||
// Fallback to default kubeconfig (for local development)
|
||||
kc.loadFromDefault();
|
||||
}
|
||||
const batchApi = kc.makeApiClient(k8s.BatchV1Api);
|
||||
const coreApi = kc.makeApiClient(k8s.CoreV1Api);
|
||||
|
||||
// 4. Create app
|
||||
const app = createApp(config, {
|
||||
temporalClient: temporal.client,
|
||||
batchApi,
|
||||
coreApi,
|
||||
});
|
||||
|
||||
// 5. Start server
|
||||
const server = serve({ fetch: app.fetch, port: config.port }, (info) => {
|
||||
console.log(`Shannon API server listening on port ${info.port}`);
|
||||
});
|
||||
|
||||
// 6. Graceful shutdown
|
||||
const shutdown = async (): Promise<void> => {
|
||||
console.log('Shutting down...');
|
||||
server.close();
|
||||
await disconnectTemporal(temporal);
|
||||
process.exit(0);
|
||||
};
|
||||
|
||||
process.on('SIGTERM', shutdown);
|
||||
process.on('SIGINT', shutdown);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Failed to start API server:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user