@hivemagnus/magnus-server 0.0.0-stage ā 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +171 -0
- package/LICENSE +202 -0
- package/README.md +169 -2
- package/agent-version.json +1 -0
- package/dist/ai/HEARTBEAT.md +56 -0
- package/dist/ai/IDENTITY.md +54 -0
- package/dist/ai/MEMORY.md +40 -0
- package/dist/ai/TOOLS.md +538 -0
- package/dist/ai/USER.md +32 -0
- package/dist/cli/args.js +62 -0
- package/dist/cli/env-catalog.js +131 -0
- package/dist/cli/preflight.js +89 -0
- package/dist/cli.js +175 -0
- package/dist/config/cors.js +16 -0
- package/dist/config/env.js +392 -0
- package/dist/config/features.js +16 -0
- package/dist/config/index.js +3 -0
- package/dist/config/listener-security.js +38 -0
- package/dist/config/version.js +31 -0
- package/dist/db/client.js +44 -0
- package/dist/db/generated/prisma/browser.js +18 -0
- package/dist/db/generated/prisma/client.js +35 -0
- package/dist/db/generated/prisma/commonInputTypes.js +11 -0
- package/dist/db/generated/prisma/enums.js +42 -0
- package/dist/db/generated/prisma/internal/class.js +50 -0
- package/dist/db/generated/prisma/internal/prismaNamespace.js +1598 -0
- package/dist/db/generated/prisma/internal/prismaNamespaceBrowser.js +1569 -0
- package/dist/db/generated/prisma/models/A2ATask.js +2 -0
- package/dist/db/generated/prisma/models/AdmissionFence.js +2 -0
- package/dist/db/generated/prisma/models/Agent.js +2 -0
- package/dist/db/generated/prisma/models/AiConversation.js +2 -0
- package/dist/db/generated/prisma/models/AiDashboard.js +2 -0
- package/dist/db/generated/prisma/models/AiMemory.js +2 -0
- package/dist/db/generated/prisma/models/AiMessage.js +2 -0
- package/dist/db/generated/prisma/models/AiScheduledOp.js +2 -0
- package/dist/db/generated/prisma/models/AlertConditionState.js +2 -0
- package/dist/db/generated/prisma/models/AlertRule.js +2 -0
- package/dist/db/generated/prisma/models/AlertViolation.js +2 -0
- package/dist/db/generated/prisma/models/AnomalyEvent.js +2 -0
- package/dist/db/generated/prisma/models/ApplicationObservation.js +2 -0
- package/dist/db/generated/prisma/models/ArdentInstallation.js +2 -0
- package/dist/db/generated/prisma/models/ArdentProfile.js +2 -0
- package/dist/db/generated/prisma/models/ArdentScopeEnrollment.js +2 -0
- package/dist/db/generated/prisma/models/CommandResourceFence.js +2 -0
- package/dist/db/generated/prisma/models/CommandResourceLease.js +2 -0
- package/dist/db/generated/prisma/models/CommandResult.js +2 -0
- package/dist/db/generated/prisma/models/CronJob.js +2 -0
- package/dist/db/generated/prisma/models/CronJobExecution.js +2 -0
- package/dist/db/generated/prisma/models/DeployJob.js +2 -0
- package/dist/db/generated/prisma/models/DriftScan.js +2 -0
- package/dist/db/generated/prisma/models/EngineeringMetricSample.js +2 -0
- package/dist/db/generated/prisma/models/EngineeringRecoveryExercise.js +2 -0
- package/dist/db/generated/prisma/models/ExecutionRun.js +2 -0
- package/dist/db/generated/prisma/models/FilePatchTask.js +2 -0
- package/dist/db/generated/prisma/models/GpuSnapshot.js +2 -0
- package/dist/db/generated/prisma/models/HealthSnapshot.js +2 -0
- package/dist/db/generated/prisma/models/HermesCoreRollout.js +2 -0
- package/dist/db/generated/prisma/models/HermesCoreRolloutHost.js +2 -0
- package/dist/db/generated/prisma/models/HermesCredentialPool.js +2 -0
- package/dist/db/generated/prisma/models/HermesCredentialPoolAttachment.js +2 -0
- package/dist/db/generated/prisma/models/HermesCronJob.js +2 -0
- package/dist/db/generated/prisma/models/HermesHook.js +2 -0
- package/dist/db/generated/prisma/models/HermesInstallation.js +2 -0
- package/dist/db/generated/prisma/models/HermesMcpServer.js +2 -0
- package/dist/db/generated/prisma/models/HermesMcpServerAttachment.js +2 -0
- package/dist/db/generated/prisma/models/HermesMessagingBinding.js +2 -0
- package/dist/db/generated/prisma/models/HermesOperationJob.js +2 -0
- package/dist/db/generated/prisma/models/HermesPluginInstall.js +2 -0
- package/dist/db/generated/prisma/models/HermesProfile.js +2 -0
- package/dist/db/generated/prisma/models/HermesProviderConfig.js +2 -0
- package/dist/db/generated/prisma/models/HermesRegistryClient.js +2 -0
- package/dist/db/generated/prisma/models/HermesRegistryInventory.js +2 -0
- package/dist/db/generated/prisma/models/HermesRegistryReceipt.js +2 -0
- package/dist/db/generated/prisma/models/HermesRegistryRevision.js +2 -0
- package/dist/db/generated/prisma/models/HermesRegistryTarget.js +2 -0
- package/dist/db/generated/prisma/models/HermesRole.js +2 -0
- package/dist/db/generated/prisma/models/HermesRoleApplication.js +2 -0
- package/dist/db/generated/prisma/models/HermesSkillAssignment.js +2 -0
- package/dist/db/generated/prisma/models/HermesToolsetPolicy.js +2 -0
- package/dist/db/generated/prisma/models/IncidentLesson.js +2 -0
- package/dist/db/generated/prisma/models/LibraryCategory.js +2 -0
- package/dist/db/generated/prisma/models/LibraryFile.js +2 -0
- package/dist/db/generated/prisma/models/LogEntry.js +2 -0
- package/dist/db/generated/prisma/models/MagnusReleaseCanary.js +2 -0
- package/dist/db/generated/prisma/models/MaintenanceWindow.js +2 -0
- package/dist/db/generated/prisma/models/ManagedCronDefinition.js +2 -0
- package/dist/db/generated/prisma/models/ManagedCronOccurrence.js +2 -0
- package/dist/db/generated/prisma/models/Node.js +2 -0
- package/dist/db/generated/prisma/models/Notification.js +2 -0
- package/dist/db/generated/prisma/models/NotificationPreference.js +2 -0
- package/dist/db/generated/prisma/models/RemediationExecution.js +2 -0
- package/dist/db/generated/prisma/models/RemediationRule.js +2 -0
- package/dist/db/generated/prisma/models/RemoteCommand.js +2 -0
- package/dist/db/generated/prisma/models/ResourceDrainParticipant.js +2 -0
- package/dist/db/generated/prisma/models/ResourceEnrollment.js +2 -0
- package/dist/db/generated/prisma/models/ResourceParticipantWork.js +2 -0
- package/dist/db/generated/prisma/models/Role.js +2 -0
- package/dist/db/generated/prisma/models/RoleApplication.js +2 -0
- package/dist/db/generated/prisma/models/RolloutTarget.js +2 -0
- package/dist/db/generated/prisma/models/SecurityExportOutbox.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionAction.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionActionApproval.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCase.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCaseActivity.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCaseEntity.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCaseEvent.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCaseRelationship.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCollector.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionCommandOutbox.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionDeletionReceipt.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionDelivery.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionEntity.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionEntityAlias.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionEvent.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionEventEntity.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionEvidence.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionInvestigation.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionNonce.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionReceiptChainHead.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionRuleVersion.js +2 -0
- package/dist/db/generated/prisma/models/SecurityFusionSourceState.js +2 -0
- package/dist/db/generated/prisma/models/SecurityServiceState.js +2 -0
- package/dist/db/generated/prisma/models/SharedResourceFence.js +2 -0
- package/dist/db/generated/prisma/models/SharedResourceLease.js +2 -0
- package/dist/db/generated/prisma/models/SharedResourceLeaseResource.js +2 -0
- package/dist/db/generated/prisma/models/SkillInstallation.js +2 -0
- package/dist/db/generated/prisma/models/SkillRegistryEntry.js +2 -0
- package/dist/db/generated/prisma/models/SkillTag.js +2 -0
- package/dist/db/generated/prisma/models/SkillVersion.js +2 -0
- package/dist/db/generated/prisma/models/TeamApprovalDecision.js +2 -0
- package/dist/db/generated/prisma/models/User.js +2 -0
- package/dist/db/generated/prisma/models/WebhookDelivery.js +2 -0
- package/dist/db/generated/prisma/models/WebhookEndpoint.js +2 -0
- package/dist/db/generated/prisma/models.js +2 -0
- package/dist/db/index.js +3 -0
- package/dist/db/read-retry.js +35 -0
- package/dist/db/seed.js +348 -0
- package/dist/index.js +162 -0
- package/dist/middleware/auth.js +361 -0
- package/dist/middleware/body-limit.js +14 -0
- package/dist/middleware/correlation-id.js +13 -0
- package/dist/middleware/error-handler.js +28 -0
- package/dist/middleware/iam-token.js +21 -0
- package/dist/middleware/rate-limit.js +78 -0
- package/dist/middleware/request-logger.js +85 -0
- package/dist/middleware/security-headers.js +23 -0
- package/dist/middleware/tracing.js +120 -0
- package/dist/middleware/user-status.js +33 -0
- package/dist/openapi/spec.js +2656 -0
- package/dist/queue/redis.js +20 -0
- package/dist/queue/requeue.js +27 -0
- package/dist/queue/workers.js +342 -0
- package/dist/routes/ai-schedule.js +73 -0
- package/dist/routes/alerts.js +79 -0
- package/dist/routes/anomalies.js +101 -0
- package/dist/routes/ardent.js +82 -0
- package/dist/routes/assistant.js +417 -0
- package/dist/routes/audit.js +138 -0
- package/dist/routes/codex.js +65 -0
- package/dist/routes/commands.js +226 -0
- package/dist/routes/credentials.js +58 -0
- package/dist/routes/cron.js +292 -0
- package/dist/routes/dependencies.js +49 -0
- package/dist/routes/deploy.js +18 -0
- package/dist/routes/discovery.js +168 -0
- package/dist/routes/docs.js +24 -0
- package/dist/routes/drift.js +126 -0
- package/dist/routes/events-stream.js +87 -0
- package/dist/routes/files.js +214 -0
- package/dist/routes/fleet-checks.js +21 -0
- package/dist/routes/health.js +133 -0
- package/dist/routes/heartbeat.js +545 -0
- package/dist/routes/hermes-registry.js +278 -0
- package/dist/routes/hermes.js +61 -0
- package/dist/routes/library.js +402 -0
- package/dist/routes/logs.js +172 -0
- package/dist/routes/managed-cron.js +23 -0
- package/dist/routes/mcp.js +39 -0
- package/dist/routes/metrics.js +187 -0
- package/dist/routes/nodes.js +951 -0
- package/dist/routes/notifications.js +130 -0
- package/dist/routes/ops.js +258 -0
- package/dist/routes/orchestra.js +430 -0
- package/dist/routes/predictions.js +23 -0
- package/dist/routes/profiling.js +68 -0
- package/dist/routes/quick-command.js +72 -0
- package/dist/routes/remediation.js +111 -0
- package/dist/routes/resource-leases.js +297 -0
- package/dist/routes/roles.js +370 -0
- package/dist/routes/rollout.js +124 -0
- package/dist/routes/scan.js +116 -0
- package/dist/routes/security-backup.js +58 -0
- package/dist/routes/security-fusion.js +605 -0
- package/dist/routes/security-integration.js +71 -0
- package/dist/routes/self-update.js +129 -0
- package/dist/routes/shared-resource-leases.js +78 -0
- package/dist/routes/skills.js +485 -0
- package/dist/routes/stats.js +96 -0
- package/dist/routes/team-approvals.js +23 -0
- package/dist/routes/terminal-ticket.js +15 -0
- package/dist/routes/terminal.js +17 -0
- package/dist/routes/topology.js +37 -0
- package/dist/routes/users.js +219 -0
- package/dist/routes/webhooks.js +137 -0
- package/dist/schemas/command-reconciliation.js +14 -0
- package/dist/schemas/commands.js +51 -0
- package/dist/schemas/cron.js +33 -0
- package/dist/schemas/deploy.js +20 -0
- package/dist/schemas/files.js +14 -0
- package/dist/schemas/hermes.js +69 -0
- package/dist/schemas/index.js +11 -0
- package/dist/schemas/library.js +48 -0
- package/dist/schemas/logs.js +35 -0
- package/dist/schemas/managed-cron.js +127 -0
- package/dist/schemas/node-responses.js +87 -0
- package/dist/schemas/node-session-receipt.js +84 -0
- package/dist/schemas/nodes.js +36 -0
- package/dist/schemas/orchestra.js +118 -0
- package/dist/schemas/resource-participant-reconciliation.js +99 -0
- package/dist/schemas/roles.js +54 -0
- package/dist/schemas/shared-resource-lease.js +132 -0
- package/dist/schemas/skills.js +44 -0
- package/dist/schemas/users.js +28 -0
- package/dist/scripts/run-disposable-recovery-exercise.js +39 -0
- package/dist/sdk/index.js +2 -0
- package/dist/sdk/node-api-client.js +474 -0
- package/dist/security/approval-assertion.js +66 -0
- package/dist/security/command-completion-registry.js +35 -0
- package/dist/security/command-request.js +12 -0
- package/dist/security/command-result-signature.js +34 -0
- package/dist/security/managed-http.js +45 -0
- package/dist/security/native-completion-registry.js +44 -0
- package/dist/server.js +178 -0
- package/dist/services/admission-fence.js +71 -0
- package/dist/services/ai-assistant-service.js +2523 -0
- package/dist/services/ai-correlation-service.js +225 -0
- package/dist/services/ai-export-service.js +141 -0
- package/dist/services/ai-insights-service.js +219 -0
- package/dist/services/ai-schedule-service.js +145 -0
- package/dist/services/ai-scratchpad-service.js +222 -0
- package/dist/services/ai-tools.js +1343 -0
- package/dist/services/alert-service.js +313 -0
- package/dist/services/anomaly-detector.js +419 -0
- package/dist/services/api-local-work.js +79 -0
- package/dist/services/application-probes.js +309 -0
- package/dist/services/ardent-scope-enrollment.js +123 -0
- package/dist/services/ardent-service.js +86 -0
- package/dist/services/audit-service.js +308 -0
- package/dist/services/codex-service.js +209 -0
- package/dist/services/command-lifecycle.js +60 -0
- package/dist/services/command-resource-leases.js +305 -0
- package/dist/services/control-host-node.js +242 -0
- package/dist/services/credential-rotation-service.js +294 -0
- package/dist/services/dependency-service.js +145 -0
- package/dist/services/disposable-recovery-runner.js +595 -0
- package/dist/services/docker-group-health.js +121 -0
- package/dist/services/engineering-assurance.js +492 -0
- package/dist/services/engineering-evidence-ledger.js +94 -0
- package/dist/services/engineering-metric-evidence.js +26 -0
- package/dist/services/event-bus.js +227 -0
- package/dist/services/fleet-check-log.js +102 -0
- package/dist/services/forecast-service.js +154 -0
- package/dist/services/health-retention.js +175 -0
- package/dist/services/heartbeat-stream.js +63 -0
- package/dist/services/hermes-catalog-import.js +62 -0
- package/dist/services/hermes-cli-parser.js +671 -0
- package/dist/services/hermes-core-rollout.js +90 -0
- package/dist/services/hermes-dashboard-endpoint.js +13 -0
- package/dist/services/hermes-plugin-source.js +149 -0
- package/dist/services/hermes-registry-service.js +258 -0
- package/dist/services/hermes-service.js +566 -0
- package/dist/services/hivemem-client.js +85 -0
- package/dist/services/host-local-writer.js +82 -0
- package/dist/services/incident-evidence.js +110 -0
- package/dist/services/incident-lessons.js +186 -0
- package/dist/services/llm-providers/anthropic.js +143 -0
- package/dist/services/llm-providers/index.js +7 -0
- package/dist/services/llm-providers/llama-cpp.js +237 -0
- package/dist/services/llm-providers/ollama.js +292 -0
- package/dist/services/llm-providers/openai-compatible.js +200 -0
- package/dist/services/llm-providers/provider-error.js +36 -0
- package/dist/services/llm-providers/registry.js +45 -0
- package/dist/services/llm-providers/types.js +2 -0
- package/dist/services/log-emitter.js +19 -0
- package/dist/services/log-retention.js +66 -0
- package/dist/services/maintenance-service.js +29 -0
- package/dist/services/managed-cron.js +493 -0
- package/dist/services/managed-ssh-admission.js +68 -0
- package/dist/services/monitor-pulse.js +10 -0
- package/dist/services/node-issue-monitor.js +71 -0
- package/dist/services/node-service.js +35 -0
- package/dist/services/notification-retention.js +51 -0
- package/dist/services/notification-service.js +94 -0
- package/dist/services/operational-observations.js +112 -0
- package/dist/services/operations-config.js +67 -0
- package/dist/services/ops-service.js +491 -0
- package/dist/services/orchestra-extras-service.js +370 -0
- package/dist/services/orchestra-resources-service.js +530 -0
- package/dist/services/os-scheduler-writer.js +73 -0
- package/dist/services/password-service.js +22 -0
- package/dist/services/prediction-service.js +284 -0
- package/dist/services/recovery-exercises.js +682 -0
- package/dist/services/remediation-service.js +325 -0
- package/dist/services/resource-enrollment.js +433 -0
- package/dist/services/resource-node-lock.js +18 -0
- package/dist/services/resource-participant-work.js +302 -0
- package/dist/services/role-service.js +388 -0
- package/dist/services/rollout-service.js +440 -0
- package/dist/services/security-export.js +185 -0
- package/dist/services/security-fusion-actions.js +22 -0
- package/dist/services/security-fusion-approvals.js +83 -0
- package/dist/services/security-fusion-evidence-integrity.js +144 -0
- package/dist/services/security-fusion-ingest.js +101 -0
- package/dist/services/security-fusion-outbox.js +185 -0
- package/dist/services/security-fusion-receipt-chain.js +134 -0
- package/dist/services/security-fusion-service.js +751 -0
- package/dist/services/security-fusion-verification.js +50 -0
- package/dist/services/self-update-service.js +200 -0
- package/dist/services/shared-resource-leases.js +413 -0
- package/dist/services/skill-publication-bundle.js +90 -0
- package/dist/services/skill-publication-settlement.js +36 -0
- package/dist/services/skill-publication-state.js +40 -0
- package/dist/services/skill-registry-service.js +327 -0
- package/dist/services/skill-service.js +148 -0
- package/dist/services/ssh-exec-service.js +139 -0
- package/dist/services/ssh-host-verification.js +27 -0
- package/dist/services/tailscale-node-key-service.js +75 -0
- package/dist/services/team-approvals.js +118 -0
- package/dist/services/topology-service.js +138 -0
- package/dist/services/transfer-authority-snapshot.js +151 -0
- package/dist/services/webhook-credential-migration.js +97 -0
- package/dist/services/webhook-security.js +242 -0
- package/dist/services/webhook-service.js +494 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/library.js +3 -0
- package/dist/types/notifications.js +3 -0
- package/dist/types/roles.js +3 -0
- package/dist/types/shared-contracts.js +3 -0
- package/dist/utils/env.js +141 -0
- package/dist/utils/heartbeat-peer.js +19 -0
- package/dist/utils/idempotency.js +45 -0
- package/dist/utils/ip.js +25 -0
- package/dist/utils/json-fields.js +94 -0
- package/dist/utils/local-tls.js +39 -0
- package/dist/utils/magnus-home.js +15 -0
- package/dist/utils/node-url.js +59 -0
- package/dist/utils/redact.js +26 -0
- package/dist/utils/safe-equal.js +13 -0
- package/dist/utils/sentinel-nodes.js +16 -0
- package/dist/utils/validate.js +41 -0
- package/package.json +119 -4
- package/prisma/migrations/20261031000000_baseline/migration.sql +2935 -0
- package/prisma/migrations/migration_lock.toml +3 -0
- package/prisma/schema.prisma +2185 -0
- package/prisma.config.ts +14 -0
package/dist/db/seed.js
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base data every installation needs: the internal system actor (never a
|
|
3
|
+
* login-capable administrator), the sentinel nodes that internal log sources
|
|
4
|
+
* reference, and the starter library. Safe to run repeatedly; `magnus-server
|
|
5
|
+
* migrate` runs it after applying migrations.
|
|
6
|
+
*/
|
|
7
|
+
import { randomBytes } from 'node:crypto';
|
|
8
|
+
import argon2 from 'argon2';
|
|
9
|
+
/** Argon2id config per project security conventions. */
|
|
10
|
+
const ARGON2_OPTIONS = {
|
|
11
|
+
type: argon2.argon2id,
|
|
12
|
+
memoryCost: 65536,
|
|
13
|
+
timeCost: 3,
|
|
14
|
+
parallelism: 4,
|
|
15
|
+
};
|
|
16
|
+
async function hashPassword(password) {
|
|
17
|
+
return argon2.hash(password, ARGON2_OPTIONS);
|
|
18
|
+
}
|
|
19
|
+
/** Idempotently create the system actor, sentinel nodes and library content. */
|
|
20
|
+
export async function seedDatabase(prisma, log = console.log) {
|
|
21
|
+
log('š± Seeding databaseā¦');
|
|
22
|
+
// āā System user (used by API-secret / agent auth) āā
|
|
23
|
+
let systemUser = await prisma.user.findUnique({ where: { id: 'system' } });
|
|
24
|
+
if (!systemUser) {
|
|
25
|
+
systemUser = await prisma.user.findUnique({ where: { email: 'system@magnus.local' } });
|
|
26
|
+
}
|
|
27
|
+
if (!systemUser) {
|
|
28
|
+
systemUser = await prisma.user.create({
|
|
29
|
+
data: {
|
|
30
|
+
id: 'system',
|
|
31
|
+
email: 'system@magnus.local',
|
|
32
|
+
name: 'System',
|
|
33
|
+
password: await hashPassword(randomBytes(32).toString('hex')),
|
|
34
|
+
role: 'ADMIN',
|
|
35
|
+
active: true,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
log(` ā User: ${systemUser.email} (${systemUser.role}) [system actor]`);
|
|
40
|
+
// āā Sentinel nodes for internal log sources āā
|
|
41
|
+
// These virtual nodes allow Control API and Dashboard logs to use the
|
|
42
|
+
// same logEntry table with referential integrity intact.
|
|
43
|
+
const sentinelNodes = [
|
|
44
|
+
{
|
|
45
|
+
id: '__control-api__',
|
|
46
|
+
name: '__control-api__',
|
|
47
|
+
hostname: '__control-api__',
|
|
48
|
+
ipAddress: '127.0.0.1',
|
|
49
|
+
port: 4000,
|
|
50
|
+
os: 'internal',
|
|
51
|
+
arch: 'internal',
|
|
52
|
+
token: `sentinel-control-api-${randomBytes(16).toString('hex')}`,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: '__dashboard__',
|
|
56
|
+
name: '__dashboard__',
|
|
57
|
+
hostname: '__dashboard__',
|
|
58
|
+
ipAddress: '127.0.0.1',
|
|
59
|
+
port: 3000,
|
|
60
|
+
os: 'internal',
|
|
61
|
+
arch: 'internal',
|
|
62
|
+
token: `sentinel-dashboard-${randomBytes(16).toString('hex')}`,
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
for (const sentinel of sentinelNodes) {
|
|
66
|
+
const existing = await prisma.node.findUnique({ where: { id: sentinel.id } });
|
|
67
|
+
if (!existing) {
|
|
68
|
+
await prisma.node.create({
|
|
69
|
+
data: {
|
|
70
|
+
id: sentinel.id,
|
|
71
|
+
name: sentinel.name,
|
|
72
|
+
hostname: sentinel.hostname,
|
|
73
|
+
ipAddress: sentinel.ipAddress,
|
|
74
|
+
port: sentinel.port,
|
|
75
|
+
status: 'ONLINE',
|
|
76
|
+
os: sentinel.os,
|
|
77
|
+
arch: sentinel.arch,
|
|
78
|
+
token: sentinel.token,
|
|
79
|
+
metadata: '{"sentinel":true}',
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
log(` ā Sentinel Node: ${sentinel.name}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
log(` ā Sentinel Node: ${sentinel.name} (already exists)`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// āā Library: Categories āā
|
|
89
|
+
const personalityCat = await prisma.libraryCategory.upsert({
|
|
90
|
+
where: { name: 'Personality' },
|
|
91
|
+
update: {},
|
|
92
|
+
create: {
|
|
93
|
+
name: 'Personality',
|
|
94
|
+
description: 'Core identity and personality files for Orchestra agents',
|
|
95
|
+
color: '#6366f1',
|
|
96
|
+
sortOrder: 0,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
log(` ā Library Category: ${personalityCat.name}`);
|
|
100
|
+
const knowledgeCat = await prisma.libraryCategory.upsert({
|
|
101
|
+
where: { name: 'Knowledge' },
|
|
102
|
+
update: {},
|
|
103
|
+
create: {
|
|
104
|
+
name: 'Knowledge',
|
|
105
|
+
description: 'Knowledge bases and reference material',
|
|
106
|
+
color: '#3b82f6',
|
|
107
|
+
sortOrder: 1,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
log(` ā Library Category: ${knowledgeCat.name}`);
|
|
111
|
+
const templatesCat = await prisma.libraryCategory.upsert({
|
|
112
|
+
where: { name: 'Templates' },
|
|
113
|
+
update: {},
|
|
114
|
+
create: {
|
|
115
|
+
name: 'Templates',
|
|
116
|
+
description: 'Reusable file templates and boilerplates',
|
|
117
|
+
color: '#22c55e',
|
|
118
|
+
sortOrder: 2,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
log(` ā Library Category: ${templatesCat.name}`);
|
|
122
|
+
const configCat = await prisma.libraryCategory.upsert({
|
|
123
|
+
where: { name: 'Config' },
|
|
124
|
+
update: {},
|
|
125
|
+
create: {
|
|
126
|
+
name: 'Config',
|
|
127
|
+
description: 'Configuration files and system settings',
|
|
128
|
+
color: '#f59e0b',
|
|
129
|
+
sortOrder: 3,
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
log(` ā Library Category: ${configCat.name}`);
|
|
133
|
+
// āā Library: Standard Agent Files āā
|
|
134
|
+
const agentFiles = [
|
|
135
|
+
{
|
|
136
|
+
name: 'SOUL',
|
|
137
|
+
fileName: 'SOUL.md',
|
|
138
|
+
mimeType: 'text/markdown',
|
|
139
|
+
categoryId: personalityCat.id,
|
|
140
|
+
tags: '["personality","core","identity"]',
|
|
141
|
+
content: `# SOUL.md ā Agent Personality Definition
|
|
142
|
+
|
|
143
|
+
## Identity
|
|
144
|
+
You are a Magnus fleet node agent ā a helpful, precise, and security-conscious AI assistant that manages Linux systems.
|
|
145
|
+
|
|
146
|
+
## Core Traits
|
|
147
|
+
- **Reliable**: Always follow through on tasks and provide accurate status updates
|
|
148
|
+
- **Security-First**: Never expose secrets, tokens, or sensitive data in logs or responses
|
|
149
|
+
- **Transparent**: Explain what you're doing and why before executing commands
|
|
150
|
+
- **Cautious**: Warn about destructive operations and request confirmation
|
|
151
|
+
- **Efficient**: Minimize resource usage and prefer lightweight solutions
|
|
152
|
+
|
|
153
|
+
## Communication Style
|
|
154
|
+
- Clear, concise responses without unnecessary verbosity
|
|
155
|
+
- Technical accuracy with appropriate detail level
|
|
156
|
+
- Use markdown formatting for structured output
|
|
157
|
+
- Include relevant context without overwhelming the operator
|
|
158
|
+
|
|
159
|
+
## Boundaries
|
|
160
|
+
- Never modify system files without explicit authorization
|
|
161
|
+
- Always validate inputs before executing commands
|
|
162
|
+
- Respect resource limits and timeout constraints
|
|
163
|
+
- Escalate unknown situations rather than guessing
|
|
164
|
+
`,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'MEMORY',
|
|
168
|
+
fileName: 'MEMORY.md',
|
|
169
|
+
mimeType: 'text/markdown',
|
|
170
|
+
categoryId: personalityCat.id,
|
|
171
|
+
tags: '["memory","context","state"]',
|
|
172
|
+
content: `# MEMORY.md ā Agent Memory & Context
|
|
173
|
+
|
|
174
|
+
## Operational Context
|
|
175
|
+
- Managed by Magnus Fleet Management Platform
|
|
176
|
+
- Reports to control-api via heartbeat every 30 seconds
|
|
177
|
+
- Executes commands dispatched through BullMQ queue
|
|
178
|
+
|
|
179
|
+
## Known Facts
|
|
180
|
+
- Operating system details are collected via HealthCollector
|
|
181
|
+
- Disk, CPU, memory, and network stats are monitored continuously
|
|
182
|
+
- Cron jobs are managed with MAGNUS: markers in system crontab
|
|
183
|
+
|
|
184
|
+
## Session History
|
|
185
|
+
<!-- This file is updated as the agent learns and remembers -->
|
|
186
|
+
- Initial deployment: Agent installed and registered with control plane
|
|
187
|
+
- Health monitoring: Active and reporting nominal metrics
|
|
188
|
+
|
|
189
|
+
## Important Notes
|
|
190
|
+
- File sync operations require checksum verification
|
|
191
|
+
- Skill installations go to /opt/magnus/skills/
|
|
192
|
+
- Self-updates require systemd restart scheduling
|
|
193
|
+
`,
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: 'KNOWLEDGE',
|
|
197
|
+
fileName: 'KNOWLEDGE.md',
|
|
198
|
+
mimeType: 'text/markdown',
|
|
199
|
+
categoryId: knowledgeCat.id,
|
|
200
|
+
tags: '["knowledge","reference","docs"]',
|
|
201
|
+
content: `# KNOWLEDGE.md ā Agent Knowledge Base
|
|
202
|
+
|
|
203
|
+
## System Administration
|
|
204
|
+
- Package management: apt/dnf depending on distro
|
|
205
|
+
- Service management: systemctl for systemd services
|
|
206
|
+
- Log management: journalctl for system logs
|
|
207
|
+
- Network: ip, ss, netstat for network diagnostics
|
|
208
|
+
- Disk: df, du, lsblk for storage management
|
|
209
|
+
|
|
210
|
+
## Magnus Platform
|
|
211
|
+
- Control API runs on port 4000
|
|
212
|
+
- Node Manager agents run on port 4100
|
|
213
|
+
- Dashboard available on port 3000
|
|
214
|
+
- Redis on port 6379 for queues and caching
|
|
215
|
+
|
|
216
|
+
## Security Practices
|
|
217
|
+
- Tokens are JWT-signed with HS256
|
|
218
|
+
- Node authentication via x-node-token header
|
|
219
|
+
- All state changes are audit-logged
|
|
220
|
+
- Secrets are never logged or returned in API responses
|
|
221
|
+
|
|
222
|
+
## Common Tasks
|
|
223
|
+
- Health check: GET /health
|
|
224
|
+
- Command execution: POST /execute with timeout
|
|
225
|
+
- File sync: POST /files/update with checksum
|
|
226
|
+
- Cron management: POST /cron with MAGNUS markers
|
|
227
|
+
`,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'SKILLS',
|
|
231
|
+
fileName: 'SKILLS.md',
|
|
232
|
+
mimeType: 'text/markdown',
|
|
233
|
+
categoryId: knowledgeCat.id,
|
|
234
|
+
tags: '["skills","capabilities","reference"]',
|
|
235
|
+
content: `# SKILLS.md ā Agent Capabilities
|
|
236
|
+
|
|
237
|
+
## Core Skills
|
|
238
|
+
1. **System Monitoring** ā Collect and report CPU, memory, disk, network metrics
|
|
239
|
+
2. **Command Execution** ā Run shell commands with timeout and output capture
|
|
240
|
+
3. **Cron Management** ā Create, update, delete cron jobs with tracking markers
|
|
241
|
+
4. **File Sync** ā Read and write files with checksum verification
|
|
242
|
+
5. **Skill Installation** ā Download, verify, and install skill bundles
|
|
243
|
+
6. **Self-Update** ā Download new agent version and schedule restart
|
|
244
|
+
|
|
245
|
+
## Monitoring Capabilities
|
|
246
|
+
- CPU usage percentage and load averages
|
|
247
|
+
- Memory and swap utilization
|
|
248
|
+
- Disk usage per mount point
|
|
249
|
+
- Network interface statistics
|
|
250
|
+
- Service status via systemctl
|
|
251
|
+
- Cockpit availability detection
|
|
252
|
+
|
|
253
|
+
## Execution Constraints
|
|
254
|
+
- Maximum command timeout: configurable (default 300s)
|
|
255
|
+
- Output size limit: 1MB per command
|
|
256
|
+
- Concurrent executions: limited by BullMQ concurrency
|
|
257
|
+
- Risk assessment: low/medium/high classification
|
|
258
|
+
`,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: 'RULES',
|
|
262
|
+
fileName: 'RULES.md',
|
|
263
|
+
mimeType: 'text/markdown',
|
|
264
|
+
categoryId: personalityCat.id,
|
|
265
|
+
tags: '["rules","constraints","safety"]',
|
|
266
|
+
content: `# RULES.md ā Agent Operating Rules
|
|
267
|
+
|
|
268
|
+
## Critical Rules (Never Violate)
|
|
269
|
+
1. **Never expose secrets** ā tokens, passwords, API keys must never appear in logs or responses
|
|
270
|
+
2. **Never execute without authorization** ā all commands must come through the authenticated control plane
|
|
271
|
+
3. **Always verify checksums** ā file sync and skill installations must verify integrity
|
|
272
|
+
4. **Respect timeouts** ā kill processes that exceed their timeout limit
|
|
273
|
+
5. **Audit everything** ā all state-changing operations must be logged
|
|
274
|
+
|
|
275
|
+
## Operational Rules
|
|
276
|
+
1. Report health status every 30 seconds via heartbeat
|
|
277
|
+
2. Update agent status when starting/stopping operations
|
|
278
|
+
3. Use idempotency keys to prevent duplicate command execution
|
|
279
|
+
4. Preserve existing cron jobs that don't have MAGNUS markers
|
|
280
|
+
5. Back up files before overwriting when previousChecksum exists
|
|
281
|
+
|
|
282
|
+
## Safety Rules
|
|
283
|
+
1. Warn before executing destructive commands (rm -rf, format, etc.)
|
|
284
|
+
2. Validate file paths to prevent directory traversal attacks
|
|
285
|
+
3. Sanitize command output to strip potential secrets
|
|
286
|
+
4. Limit resource consumption (CPU, memory, disk I/O)
|
|
287
|
+
5. Gracefully handle network failures with retry logic
|
|
288
|
+
`,
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: 'GOALS',
|
|
292
|
+
fileName: 'GOALS.md',
|
|
293
|
+
mimeType: 'text/markdown',
|
|
294
|
+
categoryId: personalityCat.id,
|
|
295
|
+
tags: '["goals","objectives","mission"]',
|
|
296
|
+
content: `# GOALS.md ā Agent Objectives
|
|
297
|
+
|
|
298
|
+
## Primary Mission
|
|
299
|
+
Maintain the health, security, and operational readiness of the assigned Linux system as part of the Magnus fleet.
|
|
300
|
+
|
|
301
|
+
## Ongoing Goals
|
|
302
|
+
1. **Uptime** ā Maximize system availability and minimize unplanned downtime
|
|
303
|
+
2. **Security** ā Keep the system patched, monitored, and free of vulnerabilities
|
|
304
|
+
3. **Performance** ā Optimize resource utilization and identify bottlenecks
|
|
305
|
+
4. **Compliance** ā Ensure all operations follow the rules defined in RULES.md
|
|
306
|
+
5. **Reporting** ā Provide accurate, timely health and status information
|
|
307
|
+
|
|
308
|
+
## Success Metrics
|
|
309
|
+
- Heartbeat consistency: >99.9% on-time delivery
|
|
310
|
+
- Command execution: <5s average response time
|
|
311
|
+
- Health monitoring: No gaps in metric collection
|
|
312
|
+
- File sync: 100% checksum verification pass rate
|
|
313
|
+
- Skill installations: Zero failed deployments
|
|
314
|
+
|
|
315
|
+
## Growth Objectives
|
|
316
|
+
- Learn from operational patterns to improve efficiency
|
|
317
|
+
- Adapt to new skill bundles and capabilities
|
|
318
|
+
- Provide proactive alerts and recommendations
|
|
319
|
+
`,
|
|
320
|
+
},
|
|
321
|
+
];
|
|
322
|
+
for (const file of agentFiles) {
|
|
323
|
+
const existing = await prisma.libraryFile.findFirst({
|
|
324
|
+
where: { fileName: file.fileName },
|
|
325
|
+
});
|
|
326
|
+
if (!existing) {
|
|
327
|
+
await prisma.libraryFile.create({
|
|
328
|
+
data: {
|
|
329
|
+
name: file.name,
|
|
330
|
+
fileName: file.fileName,
|
|
331
|
+
mimeType: file.mimeType,
|
|
332
|
+
content: file.content,
|
|
333
|
+
sizeBytes: Buffer.byteLength(file.content, 'utf-8'),
|
|
334
|
+
categoryId: file.categoryId,
|
|
335
|
+
tags: file.tags,
|
|
336
|
+
createdBy: systemUser.id,
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
log(` ā Library File: ${file.fileName}`);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
log(` ā Library File: ${file.fileName} (already exists)`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// āā Skills are now file-based (see skills/ directory) ā no DB seeding needed āā
|
|
346
|
+
log('ā
Seed complete.');
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=seed.js.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { config } from 'dotenv';
|
|
2
|
+
import { resolve, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
5
|
+
import { createServer } from 'node:https';
|
|
6
|
+
import { resolveListenerSecurity } from './config/listener-security.js';
|
|
7
|
+
// Load the env file before any other imports read process.env. The CLI passes
|
|
8
|
+
// `--env-file` through MAGNUS_ENV_FILE; otherwise the package-level .env is used
|
|
9
|
+
// when present. Variables already set in the environment always win.
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const envFile = process.env['MAGNUS_ENV_FILE'] ? resolve(process.env['MAGNUS_ENV_FILE']) : resolve(__dirname, '../.env');
|
|
12
|
+
if (existsSync(envFile))
|
|
13
|
+
config({ path: envFile, quiet: true });
|
|
14
|
+
// Validate required secrets before starting anything
|
|
15
|
+
const { validateSecrets } = await import('./utils/env.js');
|
|
16
|
+
validateSecrets();
|
|
17
|
+
const { securityFusionLocal, securityFusionMode, startSecurityExporter, stopSecurityExporter } = await import('./services/security-export.js');
|
|
18
|
+
const { featureFlags } = await import('./config/features.js');
|
|
19
|
+
const { serve } = await import('@hono/node-server');
|
|
20
|
+
const { app } = await import('./server.js');
|
|
21
|
+
const { startRolloutReconciler, stopRolloutReconciler } = await import('./services/rollout-service.js');
|
|
22
|
+
const { startApplicationProbes, stopApplicationProbes } = await import('./services/application-probes.js');
|
|
23
|
+
const { startNodeIssueMonitor } = await import('./services/node-issue-monitor.js');
|
|
24
|
+
const { stopNodeIssueMonitor } = await import('./services/node-issue-monitor.js');
|
|
25
|
+
const { startLogRetention } = await import('./services/log-retention.js');
|
|
26
|
+
const { stopLogRetention } = await import('./services/log-retention.js');
|
|
27
|
+
const { startHealthRetention } = await import('./services/health-retention.js');
|
|
28
|
+
const { stopHealthRetention } = await import('./services/health-retention.js');
|
|
29
|
+
const { startNotificationRetention, stopNotificationRetention } = await import('./services/notification-retention.js');
|
|
30
|
+
const { startSecurityFusionRetention, stopSecurityFusionRetention } = await import('./services/security-fusion-service.js');
|
|
31
|
+
const { reconcileSecurityFusionEvidence } = await import('./services/security-fusion-evidence-integrity.js');
|
|
32
|
+
const { startSecurityFusionOutboxDispatcher, stopSecurityFusionOutboxDispatcher, } = await import('./services/security-fusion-outbox.js');
|
|
33
|
+
const { startCommandWorker, closeCommandQueue } = await import('./queue/workers.js');
|
|
34
|
+
const { startWebhookWorker, closeWebhookQueue } = await import('./services/webhook-service.js');
|
|
35
|
+
const { setupTerminalWebSocket } = await import('./routes/terminal.js');
|
|
36
|
+
const { disconnectRedis } = await import('./queue/redis.js');
|
|
37
|
+
const { eventBus } = await import('./services/event-bus.js');
|
|
38
|
+
const { disconnectDb } = await import('./db/index.js');
|
|
39
|
+
const { startCodexFleetMonitor, stopCodexFleetMonitor } = await import('./services/codex-service.js');
|
|
40
|
+
const { startExtensionSourceMonitor, stopExtensionSourceMonitor } = await import('./services/hermes-plugin-source.js');
|
|
41
|
+
const { importPackageSkills } = await import('./services/hermes-catalog-import.js');
|
|
42
|
+
const port = Number(process.env['CONTROL_API_PORT'] ?? 4000);
|
|
43
|
+
const features = featureFlags();
|
|
44
|
+
console.log(`[startup] security-fusion=${securityFusionMode()} hermes-registry=${features.hermesRegistry ? 'on' : 'off'} `
|
|
45
|
+
+ `plugin-api=${features.pluginApi ? 'on' : 'off'} iam=${features.iam ? 'on' : 'off'}`);
|
|
46
|
+
if (securityFusionLocal()) {
|
|
47
|
+
const evidenceReconciliation = await reconcileSecurityFusionEvidence();
|
|
48
|
+
console.log(`[security-fusion] evidence reconciliation checked=${evidenceReconciliation.checked} `
|
|
49
|
+
+ `updated=${evidenceReconciliation.updated} quarantined=${evidenceReconciliation.quarantined} `
|
|
50
|
+
+ `mismatched_cases=${evidenceReconciliation.mismatchedCases}`);
|
|
51
|
+
}
|
|
52
|
+
/** Background services shared by the TLS and development listeners. */
|
|
53
|
+
function startBackgroundServices() {
|
|
54
|
+
startNodeIssueMonitor();
|
|
55
|
+
startApplicationProbes();
|
|
56
|
+
startLogRetention();
|
|
57
|
+
startHealthRetention();
|
|
58
|
+
startNotificationRetention();
|
|
59
|
+
if (securityFusionLocal()) {
|
|
60
|
+
startSecurityFusionRetention();
|
|
61
|
+
startSecurityFusionOutboxDispatcher();
|
|
62
|
+
}
|
|
63
|
+
startSecurityExporter();
|
|
64
|
+
startCommandWorker();
|
|
65
|
+
startRolloutReconciler();
|
|
66
|
+
startWebhookWorker();
|
|
67
|
+
startCodexFleetMonitor();
|
|
68
|
+
if (features.hermesRegistry) {
|
|
69
|
+
startExtensionSourceMonitor();
|
|
70
|
+
void importPackageSkills().then(result => console.log(`[hermes-registry] catalog import: ${JSON.stringify(result)}`))
|
|
71
|
+
.catch(error => console.error('[hermes-registry] catalog import failed', error));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Relative TLS paths resolve against the working directory; prefer absolute paths.
|
|
75
|
+
const repoRoot = process.cwd();
|
|
76
|
+
const certPath = process.env['TLS_CERT_PATH']
|
|
77
|
+
? resolve(repoRoot, process.env['TLS_CERT_PATH'])
|
|
78
|
+
: undefined;
|
|
79
|
+
const keyPath = process.env['TLS_KEY_PATH']
|
|
80
|
+
? resolve(repoRoot, process.env['TLS_KEY_PATH'])
|
|
81
|
+
: undefined;
|
|
82
|
+
const listener = resolveListenerSecurity({
|
|
83
|
+
nodeEnv: process.env['NODE_ENV'] ?? 'development',
|
|
84
|
+
allowInsecureHttp: (process.env['ALLOW_INSECURE_HTTP'] ?? 'false').toLowerCase() === 'true',
|
|
85
|
+
bindHost: process.env['CONTROL_API_BIND_HOST'],
|
|
86
|
+
certPath,
|
|
87
|
+
keyPath,
|
|
88
|
+
pathExists: existsSync,
|
|
89
|
+
});
|
|
90
|
+
const server = listener.useTls
|
|
91
|
+
? serve({
|
|
92
|
+
fetch: app.fetch,
|
|
93
|
+
port,
|
|
94
|
+
hostname: listener.hostname,
|
|
95
|
+
createServer,
|
|
96
|
+
serverOptions: {
|
|
97
|
+
key: readFileSync(keyPath),
|
|
98
|
+
cert: readFileSync(certPath),
|
|
99
|
+
},
|
|
100
|
+
}, (info) => {
|
|
101
|
+
console.log(`š Magnus server listening on https://${listener.hostname}:${info.port}`);
|
|
102
|
+
startBackgroundServices();
|
|
103
|
+
})
|
|
104
|
+
: serve({ fetch: app.fetch, port, hostname: listener.hostname }, (info) => {
|
|
105
|
+
console.log(`š Magnus server listening on http://${listener.hostname}:${info.port} (development opt-in)`);
|
|
106
|
+
startBackgroundServices();
|
|
107
|
+
});
|
|
108
|
+
const terminalWss = setupTerminalWebSocket(server);
|
|
109
|
+
// āā Graceful shutdown āā
|
|
110
|
+
let shuttingDown = false;
|
|
111
|
+
async function shutdown(signal) {
|
|
112
|
+
if (shuttingDown)
|
|
113
|
+
return;
|
|
114
|
+
shuttingDown = true;
|
|
115
|
+
console.log(`\nš ${signal} received ā shutting down Magnus server...`);
|
|
116
|
+
const timeoutMs = Number(process.env['SHUTDOWN_TIMEOUT_MS'] ?? 15_000);
|
|
117
|
+
let deadlineTimer;
|
|
118
|
+
const deadline = new Promise((_, reject) => {
|
|
119
|
+
deadlineTimer = setTimeout(() => reject(new Error(`shutdown exceeded ${timeoutMs}ms`)), timeoutMs);
|
|
120
|
+
});
|
|
121
|
+
let exitCode = 0;
|
|
122
|
+
try {
|
|
123
|
+
await Promise.race([(async () => {
|
|
124
|
+
stopRolloutReconciler();
|
|
125
|
+
stopNodeIssueMonitor();
|
|
126
|
+
stopApplicationProbes();
|
|
127
|
+
stopLogRetention();
|
|
128
|
+
stopHealthRetention();
|
|
129
|
+
stopNotificationRetention();
|
|
130
|
+
stopSecurityFusionRetention();
|
|
131
|
+
stopSecurityExporter();
|
|
132
|
+
stopSecurityFusionOutboxDispatcher();
|
|
133
|
+
stopCodexFleetMonitor();
|
|
134
|
+
stopExtensionSourceMonitor();
|
|
135
|
+
for (const client of terminalWss.clients)
|
|
136
|
+
client.terminate();
|
|
137
|
+
const httpClosed = new Promise((resolvePromise) => server.close(() => resolvePromise()));
|
|
138
|
+
server.closeAllConnections?.();
|
|
139
|
+
const webSocketsClosed = new Promise((resolvePromise) => terminalWss.close(() => resolvePromise()));
|
|
140
|
+
await Promise.all([httpClosed, webSocketsClosed]);
|
|
141
|
+
await closeCommandQueue();
|
|
142
|
+
await closeWebhookQueue();
|
|
143
|
+
await eventBus.close();
|
|
144
|
+
await disconnectRedis();
|
|
145
|
+
await disconnectDb();
|
|
146
|
+
})(), deadline]);
|
|
147
|
+
console.log(' ā HTTP, WebSockets, monitors, queues, Redis, and database closed');
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
console.error(' ā Graceful shutdown failed:', err);
|
|
151
|
+
exitCode = 1;
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
if (deadlineTimer)
|
|
155
|
+
clearTimeout(deadlineTimer);
|
|
156
|
+
}
|
|
157
|
+
console.log('ā
Magnus server shutdown complete');
|
|
158
|
+
process.exit(exitCode);
|
|
159
|
+
}
|
|
160
|
+
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
|
161
|
+
process.on('SIGINT', () => void shutdown('SIGINT'));
|
|
162
|
+
//# sourceMappingURL=index.js.map
|