@hivemagnus/magnus-agent 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.
Files changed (154) hide show
  1. package/.env.example +115 -0
  2. package/LICENSE +202 -0
  3. package/README.md +194 -2
  4. package/deploy/magnus-agent-unprivileged.service +61 -0
  5. package/deploy/magnus-agent.service +33 -0
  6. package/deploy/magnus-hermes-sync.service +22 -0
  7. package/deploy/magnus-hermes-sync.timer +14 -0
  8. package/dist/agent.d.ts +11 -0
  9. package/dist/agent.js +162 -0
  10. package/dist/cli-args.d.ts +12 -0
  11. package/dist/cli-args.js +34 -0
  12. package/dist/collectors/docker-group.d.ts +7 -0
  13. package/dist/collectors/docker-group.js +181 -0
  14. package/dist/collectors/drift-collector.d.ts +29 -0
  15. package/dist/collectors/drift-collector.js +181 -0
  16. package/dist/collectors/drift-routes.d.ts +3 -0
  17. package/dist/collectors/drift-routes.js +34 -0
  18. package/dist/collectors/gpu-collector.d.ts +23 -0
  19. package/dist/collectors/gpu-collector.js +213 -0
  20. package/dist/collectors/health-collector.d.ts +18 -0
  21. package/dist/collectors/health-collector.js +331 -0
  22. package/dist/collectors/health-routes.d.ts +3 -0
  23. package/dist/collectors/health-routes.js +22 -0
  24. package/dist/collectors/log-collector.d.ts +39 -0
  25. package/dist/collectors/log-collector.js +268 -0
  26. package/dist/collectors/network-info.d.ts +9 -0
  27. package/dist/collectors/network-info.js +120 -0
  28. package/dist/collectors/otel-collector.d.ts +90 -0
  29. package/dist/collectors/otel-collector.js +273 -0
  30. package/dist/collectors/otel-middleware.d.ts +9 -0
  31. package/dist/collectors/otel-middleware.js +34 -0
  32. package/dist/collectors/otel-routes.d.ts +10 -0
  33. package/dist/collectors/otel-routes.js +28 -0
  34. package/dist/collectors/profiling-collector.d.ts +56 -0
  35. package/dist/collectors/profiling-collector.js +77 -0
  36. package/dist/collectors/profiling-routes.d.ts +3 -0
  37. package/dist/collectors/profiling-routes.js +24 -0
  38. package/dist/collectors/storage-evidence.d.ts +35 -0
  39. package/dist/collectors/storage-evidence.js +76 -0
  40. package/dist/collectors/system-updates.d.ts +15 -0
  41. package/dist/collectors/system-updates.js +125 -0
  42. package/dist/collectors/tailscale-node-key.d.ts +5 -0
  43. package/dist/collectors/tailscale-node-key.js +98 -0
  44. package/dist/credential-renewal.d.ts +11 -0
  45. package/dist/credential-renewal.js +381 -0
  46. package/dist/discovery.d.ts +36 -0
  47. package/dist/discovery.js +143 -0
  48. package/dist/env-catalog.d.ts +28 -0
  49. package/dist/env-catalog.js +63 -0
  50. package/dist/env.d.ts +20 -0
  51. package/dist/env.js +118 -0
  52. package/dist/executors/ardent-manager.d.ts +18 -0
  53. package/dist/executors/ardent-manager.js +556 -0
  54. package/dist/executors/codex-manager.d.ts +58 -0
  55. package/dist/executors/codex-manager.js +742 -0
  56. package/dist/executors/command-executor.d.ts +104 -0
  57. package/dist/executors/command-executor.js +327 -0
  58. package/dist/executors/command-ledger.d.ts +316 -0
  59. package/dist/executors/command-ledger.js +467 -0
  60. package/dist/executors/cron-manager.d.ts +25 -0
  61. package/dist/executors/cron-manager.js +392 -0
  62. package/dist/executors/enrollment-drain.d.ts +5 -0
  63. package/dist/executors/enrollment-drain.js +115 -0
  64. package/dist/executors/execution-supervisor-state.d.ts +62 -0
  65. package/dist/executors/execution-supervisor-state.js +62 -0
  66. package/dist/executors/execution-supervisor-worker.d.ts +2 -0
  67. package/dist/executors/execution-supervisor-worker.js +57 -0
  68. package/dist/executors/execution-supervisor.d.ts +100 -0
  69. package/dist/executors/execution-supervisor.js +403 -0
  70. package/dist/executors/file-sync-executor.d.ts +5 -0
  71. package/dist/executors/file-sync-executor.js +152 -0
  72. package/dist/executors/hermes-dashboard-discovery.d.ts +17 -0
  73. package/dist/executors/hermes-dashboard-discovery.js +159 -0
  74. package/dist/executors/hermes-manager.d.ts +116 -0
  75. package/dist/executors/hermes-manager.js +1078 -0
  76. package/dist/executors/historical-mutation-cli.d.ts +2 -0
  77. package/dist/executors/historical-mutation-cli.js +113 -0
  78. package/dist/executors/historical-mutation.d.ts +254 -0
  79. package/dist/executors/historical-mutation.js +89 -0
  80. package/dist/executors/hivemem-token.d.ts +8 -0
  81. package/dist/executors/hivemem-token.js +61 -0
  82. package/dist/executors/managed-http.d.ts +30 -0
  83. package/dist/executors/managed-http.js +249 -0
  84. package/dist/executors/managed-scheduler.d.ts +286 -0
  85. package/dist/executors/managed-scheduler.js +507 -0
  86. package/dist/executors/mutation-barrier.d.ts +107 -0
  87. package/dist/executors/mutation-barrier.js +378 -0
  88. package/dist/executors/scheduler-authority.d.ts +12 -0
  89. package/dist/executors/scheduler-authority.js +111 -0
  90. package/dist/executors/scheduler-discovery.d.ts +56 -0
  91. package/dist/executors/scheduler-discovery.js +700 -0
  92. package/dist/executors/scheduler-drain.d.ts +12 -0
  93. package/dist/executors/scheduler-drain.js +98 -0
  94. package/dist/executors/scheduler-inventory.d.ts +45 -0
  95. package/dist/executors/scheduler-inventory.js +249 -0
  96. package/dist/executors/scheduler-runner.d.ts +3 -0
  97. package/dist/executors/scheduler-runner.js +39 -0
  98. package/dist/executors/scheduler-status.d.ts +36 -0
  99. package/dist/executors/scheduler-status.js +39 -0
  100. package/dist/executors/skill-bundle.d.ts +7 -0
  101. package/dist/executors/skill-bundle.js +105 -0
  102. package/dist/executors/skill-manager.d.ts +9 -0
  103. package/dist/executors/skill-manager.js +186 -0
  104. package/dist/executors/skill-publication.d.ts +78 -0
  105. package/dist/executors/skill-publication.js +670 -0
  106. package/dist/executors/workspace-manager.d.ts +3 -0
  107. package/dist/executors/workspace-manager.js +112 -0
  108. package/dist/fqdn.d.ts +11 -0
  109. package/dist/fqdn.js +32 -0
  110. package/dist/hermes-sync.d.ts +21 -0
  111. package/dist/hermes-sync.js +857 -0
  112. package/dist/index.d.ts +3 -0
  113. package/dist/index.js +102 -0
  114. package/dist/listener-security.d.ts +15 -0
  115. package/dist/listener-security.js +33 -0
  116. package/dist/middleware.d.ts +13 -0
  117. package/dist/middleware.js +38 -0
  118. package/dist/privileged.d.ts +30 -0
  119. package/dist/privileged.js +42 -0
  120. package/dist/routes/user-manager.d.ts +7 -0
  121. package/dist/routes/user-manager.js +109 -0
  122. package/dist/security/command-completion-registry.d.ts +23 -0
  123. package/dist/security/command-completion-registry.js +35 -0
  124. package/dist/security/command-result-signature.d.ts +46 -0
  125. package/dist/security/command-result-signature.js +50 -0
  126. package/dist/security/managed-context.d.ts +13 -0
  127. package/dist/security/managed-context.js +4 -0
  128. package/dist/security/managed-http.d.ts +30 -0
  129. package/dist/security/managed-http.js +26 -0
  130. package/dist/security/native-completion-registry.d.ts +91 -0
  131. package/dist/security/native-completion-registry.js +44 -0
  132. package/dist/security/node-session-receipt.d.ts +54 -0
  133. package/dist/security/node-session-receipt.js +89 -0
  134. package/dist/server.d.ts +14 -0
  135. package/dist/server.js +217 -0
  136. package/dist/start.d.ts +2 -0
  137. package/dist/start.js +114 -0
  138. package/dist/tls.d.ts +9 -0
  139. package/dist/tls.js +47 -0
  140. package/dist/types/index.d.ts +2 -0
  141. package/dist/types/index.js +3 -0
  142. package/dist/types/shared-contracts.d.ts +578 -0
  143. package/dist/types/shared-contracts.js +3 -0
  144. package/dist/updater/self-updater.d.ts +3 -0
  145. package/dist/updater/self-updater.js +15 -0
  146. package/dist/utils/child-env.d.ts +10 -0
  147. package/dist/utils/child-env.js +25 -0
  148. package/dist/utils/child-timeout.d.ts +9 -0
  149. package/dist/utils/child-timeout.js +26 -0
  150. package/dist/utils/logger.d.ts +20 -0
  151. package/dist/utils/logger.js +36 -0
  152. package/dist/version.d.ts +2 -0
  153. package/dist/version.js +16 -0
  154. package/package.json +72 -4
package/.env.example ADDED
@@ -0,0 +1,115 @@
1
+ # ──────────────────────────────────────────────────────────────────────
2
+ # magnus-agent environment
3
+ # ──────────────────────────────────────────────────────────────────────
4
+ # Copy to $AGENT_INSTALL_DIR/.env (default /opt/magnus-agent/.env), or pass
5
+ # `--env-file <path>`, and keep it mode 0600. Variables already present in the
6
+ # environment take precedence. `magnus-agent env-schema` prints every key and
7
+ # `magnus-agent check` validates the result without starting.
8
+
9
+ # ══ Required ══════════════════════════════════════════════════════════
10
+
11
+ # magnus-server Control API this node enrolls with.
12
+ CONTROL_API_URL=https://magnus.example.com:4000
13
+ # Node credential shared with the Control API (32+ characters). Generate with
14
+ # `openssl rand -hex 32` and register the same value for this node on the server.
15
+ NODE_MANAGER_SECRET=
16
+ # Independent command-result signing key (32+ characters). Never reuse
17
+ # NODE_MANAGER_SECRET.
18
+ RESULT_SIGNING_SECRET=
19
+
20
+ # Listener TLS (absolute, or relative to AGENT_INSTALL_DIR). Required when
21
+ # NODE_ENV=production; configured but missing files fail closed.
22
+ TLS_CERT_PATH=/opt/magnus-agent/certs/agent.crt
23
+ TLS_KEY_PATH=/opt/magnus-agent/certs/agent.key
24
+
25
+ NODE_ENV=production
26
+
27
+ # Privileged mode (default true) runs as root with every executor; startup
28
+ # fails if the process is not root. Set false to run as an ordinary account:
29
+ # cron, users, system updates, docker-group remediation, Ardent management,
30
+ # credential renewal and the execution supervisor are then disabled and their
31
+ # routes return 403 AGENT_NOT_PRIVILEGED.
32
+ MAGNUS_AGENT_PRIVILEGED=true
33
+
34
+ # ══ Optional ══════════════════════════════════════════════════════════
35
+
36
+ # ── Identity and listener ────────────────────────────────────────────
37
+ # Host identity reported to the Control API (default: `hostname --fqdn`).
38
+ # HOST_FQDN=node-1.example.com
39
+ # NODE_MANAGER_PORT=4100
40
+ # TLS listens on all interfaces by default; development HTTP on loopback.
41
+ # NODE_MANAGER_BIND_HOST=0.0.0.0
42
+ # Development only: plain HTTP on loopback. Rejected in production.
43
+ # ALLOW_INSECURE_HTTP=false
44
+ # PEM CA bundle for a private-CA Control API. The URL hostname must be in the
45
+ # certificate SAN; verification is never disabled.
46
+ # CONTROL_API_CA_PATH=/etc/magnus-agent/control-api-ca.pem
47
+ # Renew a Tailscale-issued listener certificate with `tailscale cert`.
48
+ # MAGNUS_AGENT_TLS_RENEWAL=tailscale
49
+
50
+ # ── Command execution ────────────────────────────────────────────────
51
+ # ENABLE_NODE_MANAGEMENT=true
52
+ # Durable execution supervisor for commands (off until your server enables it).
53
+ # MAGNUS_EXECUTION_SUPERVISOR_ENABLED=false
54
+ # Independent key for explicit command-receipt reconciliation. Leave unset unless
55
+ # your control plane uses it. Linux /usr/bin/flock is required for commands.
56
+ # COMMAND_RECONCILIATION_SECRET=
57
+ # Rotation windows: previous values accepted alongside the current ones.
58
+ # NODE_MANAGER_SECRET_PREVIOUS=
59
+ # RESULT_SIGNING_PREVIOUS_SECRET=
60
+
61
+ # ── Authenticated UDP discovery (default off) ────────────────────────
62
+ # ENABLE_AGENT_DISCOVERY=false
63
+ # AGENT_DISCOVERY_SECRET=
64
+ # Explicit IPv4 interface address; wildcard binds are rejected.
65
+ # AGENT_DISCOVERY_BIND_ADDRESS=192.0.2.10
66
+
67
+ # ── Logs and traces ──────────────────────────────────────────────────
68
+ # ENABLE_LOG_FORWARDING=false
69
+ # LOG_INGEST_TOKEN=
70
+ # LOG_UNITS=magnus-agent.service
71
+ # OTEL_ENABLED=true
72
+ # OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com:4318
73
+ LOG_LEVEL=info
74
+
75
+ # ── Skills ───────────────────────────────────────────────────────────
76
+ # SKILLS_DIR=/opt/magnus-agent/skills
77
+ # SKILLS_EXTRA_DIRS=
78
+
79
+ # ── Hermes Agent (optional) ──────────────────────────────────────────
80
+ # Local account that owns Hermes Agent (~/.hermes). Leave unset when Hermes is
81
+ # not installed.
82
+ # HERMES_USER=operator
83
+ # 64-hex token issued by the Control API for this node's magnus-hermes-sync job.
84
+ # HERMES_REGISTRY_TOKEN=
85
+ # Let magnus-hermes-sync apply desired state from the registry.
86
+ # MAGNUS_HERMES_SYNC_PULL=false
87
+
88
+ # ── Codex CLI (optional) ─────────────────────────────────────────────
89
+ # Account whose Codex CLI and ChatGPT login are managed (default: HERMES_USER,
90
+ # then the invoking user). Credentials stay in that user's Codex home.
91
+ # CODEX_USER=operator
92
+ # CODEX_BIN=/usr/local/bin/codex
93
+ # CODEX_HOME=/home/operator/.codex
94
+
95
+ # ── Ardent (optional) ────────────────────────────────────────────────
96
+ # ARDENT_OWNER_USER=operator
97
+ # ARDENT_STAGED_PACKAGE=/opt/magnus-agent/ardent-package.tgz
98
+
99
+ # ── HiveMem credential renewal (optional, all lists empty by default) ─
100
+ # Entries live in a root-owned 0600 JSON file; the lists below bound what the
101
+ # entries may touch.
102
+ # MAGNUS_AGENT_RENEWAL_CONFIG=/opt/magnus-agent/credential-renewal.json
103
+ # MAGNUS_AGENT_RENEWAL_ENDPOINTS=https://hivemem.example.com
104
+ # MAGNUS_AGENT_RENEWAL_UNITS=hermes-gateway.service
105
+ # MAGNUS_AGENT_RENEWAL_USERS=operator
106
+ # MAGNUS_AGENT_RENEWAL_ARDENT_PROFILES=
107
+ # MAGNUS_AGENT_RENEWAL_TOKEN_FILES=
108
+ # MAGNUS_AGENT_RENEWAL_SIGNING_ENV_FILES=
109
+
110
+ # ── Runtime ──────────────────────────────────────────────────────────
111
+ # Installation directory (set by the systemd unit).
112
+ # AGENT_INSTALL_DIR=/opt/magnus-agent
113
+ # MAGNUS_AGENT_WORKSPACE_ROOT=/var/lib/magnus-agent/workspaces
114
+ # Account the docker-group heartbeat check verifies (default: the agent's own user).
115
+ # MAGNUS_AGENT_DOCKER_USER=operator
package/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
package/README.md CHANGED
@@ -1,3 +1,195 @@
1
- # Temporary Holding Version
1
+ # @hivemagnus/magnus-agent
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The Magnus node agent. It is a small daemon that runs on each Linux host you
4
+ manage. It enrolls with a [magnus-server](https://github.com/ChefTaco/magnus/tree/main/services/control-api)
5
+ Control API, sends heartbeats, and serves authenticated management routes for
6
+ the server and the Magnus console.
7
+
8
+ The agent is infrastructure, not an LLM runtime. It can manage Hermes Agent,
9
+ the Codex CLI and Ardent when they are installed on the host. Each of these
10
+ integrations is optional and stays inert until you configure it.
11
+
12
+ ## Features
13
+
14
+ - Heartbeat with CPU, memory, disk, network, services, GPU, Docker group
15
+ services, Wazuh and Tailscale node-key posture.
16
+ - Health checks (`/api/v1/health/check`) and an unauthenticated readiness probe
17
+ (`/api/v1/ping`).
18
+ - Command execution with timeouts, signed results and a durable command ledger.
19
+ - Cron management, including finite managed schedules (see
20
+ [MANAGED_SCHEDULER.md](https://github.com/ChefTaco/magnus/blob/main/packages/agent/MANAGED_SCHEDULER.md)).
21
+ - File read and write with symlink-resolved path checks. Agent state and
22
+ secrets can never be read or written through the API.
23
+ - Skill publication, listing and removal, for example from
24
+ [`@hivemagnus/magnus-skills`](https://github.com/ChefTaco/magnus/tree/main/packages/skills).
25
+ - Drift, profiling, trace, workspace, network information and local user routes.
26
+ - Optional OpenTelemetry trace export and journald log forwarding.
27
+ - Optional authenticated UDP discovery of the control node (off by default).
28
+
29
+ Optional executors:
30
+
31
+ | Executor | Routes | Active when |
32
+ | --- | --- | --- |
33
+ | Hermes Agent | `/api/v1/hermes/*`, `magnus-hermes-sync` | the `hermes` CLI is installed for `HERMES_USER` |
34
+ | Codex CLI | `/api/v1/codex/*` | a Codex CLI is found for `CODEX_USER` |
35
+ | Ardent | `/api/v1/ardent/*` | `ARDENT_OWNER_USER` is set and Ardent is installed |
36
+ | HiveMem credential renewal | background | a renewal config file and allowlists exist |
37
+
38
+ ## Requirements
39
+
40
+ - Linux with systemd. By default the agent runs as root (privileged mode). You
41
+ can also run it as an ordinary account with fewer features; see
42
+ [Privileged and unprivileged mode](#privileged-and-unprivileged-mode).
43
+ - Node.js `^24.22.1` or `^26.13.0`.
44
+ - `/usr/bin/flock` (util-linux) for command execution.
45
+ - A reachable magnus-server Control API.
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ sudo npm install --prefix /opt/magnus-agent @hivemagnus/magnus-agent
51
+ sudo install -m 0600 /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/.env.example /opt/magnus-agent/.env
52
+ ```
53
+
54
+ For a quick trial you can also install it globally with
55
+ `npm i -g @hivemagnus/magnus-agent` and run `magnus-agent --env-file ./agent.env`.
56
+ For production, install it below a stable directory such as `/opt/magnus-agent`,
57
+ as shown above. The managed scheduler finds its private `.env` and state there
58
+ across upgrades.
59
+
60
+ ## Enroll with a magnus-server
61
+
62
+ 1. In the Magnus console or through the Control API, register the node. Use
63
+ the host's FQDN and a node secret, for example from `openssl rand -hex 32`.
64
+ 2. Edit `/opt/magnus-agent/.env`:
65
+
66
+ ```bash
67
+ CONTROL_API_URL=https://magnus.example.com:4000
68
+ NODE_MANAGER_SECRET=<the node secret registered on the server>
69
+ RESULT_SIGNING_SECRET=<openssl rand -hex 32>
70
+ TLS_CERT_PATH=/opt/magnus-agent/certs/agent.crt
71
+ TLS_KEY_PATH=/opt/magnus-agent/certs/agent.key
72
+ NODE_ENV=production
73
+ ```
74
+
75
+ 3. Validate the configuration, then install the example unit:
76
+
77
+ ```bash
78
+ cd /opt/magnus-agent
79
+ sudo node node_modules/@hivemagnus/magnus-agent/dist/index.js check
80
+ sudo cp node_modules/@hivemagnus/magnus-agent/deploy/magnus-agent.service /etc/systemd/system/
81
+ sudo systemctl daemon-reload
82
+ sudo systemctl enable --now magnus-agent
83
+ ```
84
+
85
+ 4. Within a heartbeat interval (30 seconds), the node shows as online on the
86
+ server.
87
+
88
+ Use a certificate whose SAN matches the address the server uses to reach the
89
+ agent. If the Control API uses a private CA, set `CONTROL_API_CA_PATH`. TLS
90
+ verification is never disabled.
91
+
92
+ ## Privileged and unprivileged mode
93
+
94
+ `MAGNUS_AGENT_PRIVILEGED` (default `true`) selects the mode.
95
+
96
+ - **Privileged (`true`):** the agent runs as root and every feature is
97
+ available. If the process is not root, startup fails with a clear message,
98
+ and so does `magnus-agent check`. The agent never half-runs as a normal user
99
+ and never escalates through `sudo`. Use `deploy/magnus-agent.service`.
100
+ - **Unprivileged (`false`):** the agent runs as an ordinary account, such as a
101
+ dedicated `magnus-agent` user. The features below are switched off at
102
+ startup. Their routes answer `403` with error code `AGENT_NOT_PRIVILEGED`,
103
+ and `magnus-agent check` lists them as disabled. Use
104
+ `deploy/magnus-agent-unprivileged.service`, which also applies systemd
105
+ hardening. Run the listener on a port above 1023 and make sure the TLS key is
106
+ readable by that account.
107
+
108
+ | Feature | Needs privileged mode | Unprivileged behaviour |
109
+ | --- | --- | --- |
110
+ | Heartbeat, health, drift, profiling, traces, network info | no | available |
111
+ | Command execution (`/api/v1/commands`) | no | runs as the agent's account |
112
+ | File read/write (`/api/v1/files`) | no | limited to what the account may access |
113
+ | Skill publication (`/api/v1/skills`) | no | into a skills dir the account owns |
114
+ | Workspace routes | no | below `MAGNUS_AGENT_WORKSPACE_ROOT` |
115
+ | Hermes Agent and Codex CLI management | no | for the agent's own account only |
116
+ | Cron and managed schedules (`/api/v1/cron/*`) | **yes** | 403 `AGENT_NOT_PRIVILEGED` |
117
+ | Local users and passwords (`/api/v1/users/*`) | **yes** | 403 `AGENT_NOT_PRIVILEGED` |
118
+ | Automatic system updates (`POST /api/v1/health/system-updates/enable`) | **yes** | 403 `AGENT_NOT_PRIVILEGED` |
119
+ | Docker group remediation (heartbeat) | **yes** | membership is reported, never changed |
120
+ | Ardent management (`POST /api/v1/ardent/action`) | **yes** | 403 `AGENT_NOT_PRIVILEGED`; state stays readable |
121
+ | HiveMem credential and certificate renewal | **yes** | not started |
122
+ | Execution supervisor (`MAGNUS_EXECUTION_SUPERVISOR_ENABLED`) | **yes** | configuration error if enabled |
123
+
124
+ ## CLI
125
+
126
+ ```text
127
+ magnus-agent [start] [--env-file <path>] Start the agent (default)
128
+ magnus-agent check [--json] [--env-file <path>] Validate configuration without starting
129
+ magnus-agent env-schema Print the configuration schema as JSON
130
+ magnus-agent --help | --version
131
+ ```
132
+
133
+ Variables already set in the environment win over `--env-file`. The agent also
134
+ reads `$AGENT_INSTALL_DIR/.env` (default `./.env`).
135
+
136
+ ## Configuration
137
+
138
+ [`.env.example`](./.env.example) groups every key into Required and Optional,
139
+ and `magnus-agent env-schema` prints them as JSON.
140
+
141
+ | Variable | Purpose |
142
+ | --- | --- |
143
+ | `CONTROL_API_URL` | magnus-server Control API (required) |
144
+ | `NODE_MANAGER_SECRET` | Node credential shared with the server (required, 32+ characters) |
145
+ | `RESULT_SIGNING_SECRET` | Independent result-signing key (required, 32+ characters) |
146
+ | `TLS_CERT_PATH` / `TLS_KEY_PATH` | Listener TLS, required in production |
147
+ | `HOST_FQDN` | Host identity override (default `hostname --fqdn`) |
148
+ | `NODE_MANAGER_PORT` / `NODE_MANAGER_BIND_HOST` | Listener port (default `4100`) and address |
149
+ | `CONTROL_API_CA_PATH` | CA bundle for a private-CA Control API |
150
+ | `SKILLS_DIR` / `SKILLS_EXTRA_DIRS` | Skill directories |
151
+ | `HERMES_USER`, `HERMES_REGISTRY_TOKEN`, `MAGNUS_HERMES_SYNC_PULL` | Hermes Agent management and registry sync |
152
+ | `CODEX_USER`, `CODEX_BIN`, `CODEX_HOME` | Codex CLI management |
153
+ | `ARDENT_OWNER_USER`, `ARDENT_STAGED_PACKAGE` | Ardent management |
154
+ | `MAGNUS_AGENT_RENEWAL_*` | HiveMem credential renewal allowlists (empty by default) |
155
+ | `MAGNUS_AGENT_TLS_RENEWAL=tailscale` | Renew a Tailscale listener certificate |
156
+ | `MAGNUS_AGENT_PRIVILEGED` | Privileged (root, default `true`) or unprivileged mode |
157
+ | `MAGNUS_AGENT_DOCKER_USER` | Account the docker-group check verifies |
158
+ | `ENABLE_AGENT_DISCOVERY`, `AGENT_DISCOVERY_*` | Authenticated UDP discovery |
159
+
160
+ ### HiveMem credential renewal
161
+
162
+ When HiveMem is part of your stack, the agent can renew HiveMem tokens before
163
+ they expire. Put the entries in a root-owned `0600` JSON file
164
+ (`MAGNUS_AGENT_RENEWAL_CONFIG`, default `$AGENT_INSTALL_DIR/credential-renewal.json`).
165
+ The entries can only touch what the comma-separated allowlists name:
166
+ `MAGNUS_AGENT_RENEWAL_ENDPOINTS`, `_UNITS`, `_USERS`, `_ARDENT_PROFILES`,
167
+ `_TOKEN_FILES` and `_SIGNING_ENV_FILES`. Every list is empty by default, so
168
+ renewal does nothing until you configure it.
169
+
170
+ ### Hermes registry sync
171
+
172
+ `deploy/magnus-hermes-sync.service` and its timer run `dist/hermes-sync.js`
173
+ every five minutes. Without `HERMES_REGISTRY_TOKEN` the job does nothing.
174
+ With `--submit-only` it only reports the local Hermes inventory. Applying the
175
+ server's desired skills, plugins and MCP releases also needs
176
+ `MAGNUS_HERMES_SYNC_PULL=true`.
177
+
178
+ ## Development
179
+
180
+ ```bash
181
+ npm install # at the repository root
182
+ npm run dev --workspace @hivemagnus/magnus-agent
183
+ npm run typecheck --workspace @hivemagnus/magnus-agent
184
+ npm test --workspace @hivemagnus/magnus-agent
185
+ npm run build --workspace @hivemagnus/magnus-agent
186
+ ```
187
+
188
+ To run the agent locally as your own user, set `MAGNUS_AGENT_PRIVILEGED=false`.
189
+ For local development without certificates, set `ALLOW_INSECURE_HTTP=true`.
190
+ The agent then serves plain HTTP on loopback only. This is rejected in
191
+ production.
192
+
193
+ ## License
194
+
195
+ Apache-2.0
@@ -0,0 +1,61 @@
1
+ # Example systemd unit for magnus-agent in unprivileged mode.
2
+ #
3
+ # The agent runs as the dedicated magnus-agent account. Root-only features
4
+ # (cron, local users, system updates, docker-group remediation, Ardent
5
+ # management, credential renewal, the execution supervisor) are disabled and
6
+ # their routes answer 403 AGENT_NOT_PRIVILEGED. See the README for the full list.
7
+ #
8
+ # sudo useradd --system --home-dir /opt/magnus-agent --shell /usr/sbin/nologin magnus-agent
9
+ # sudo npm install --prefix /opt/magnus-agent @hivemagnus/magnus-agent
10
+ # sudo install -o magnus-agent -g magnus-agent -m 0600 \
11
+ # /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/.env.example /opt/magnus-agent/.env
12
+ # sudo chown -R magnus-agent:magnus-agent /opt/magnus-agent
13
+ #
14
+ # Use a NODE_MANAGER_PORT above 1023, and make the TLS key readable by
15
+ # magnus-agent. Install this file as /etc/systemd/system/magnus-agent.service.
16
+ [Unit]
17
+ Description=Magnus Agent (unprivileged)
18
+ After=network-online.target
19
+ Wants=network-online.target
20
+
21
+ [Service]
22
+ Type=simple
23
+ User=magnus-agent
24
+ Group=magnus-agent
25
+ WorkingDirectory=/opt/magnus-agent
26
+ Environment=AGENT_INSTALL_DIR=/opt/magnus-agent
27
+ Environment=MAGNUS_AGENT_PRIVILEGED=false
28
+ EnvironmentFile=/opt/magnus-agent/.env
29
+ ExecStart=/usr/bin/node /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/dist/index.js start
30
+ Restart=always
31
+ RestartSec=5
32
+ StandardOutput=journal
33
+ StandardError=journal
34
+ UMask=0077
35
+
36
+ # Hardening. The agent writes only below its install directory and
37
+ # /var/lib/magnus-agent (workspace routes, created by StateDirectory).
38
+ NoNewPrivileges=true
39
+ CapabilityBoundingSet=
40
+ AmbientCapabilities=
41
+ PrivateTmp=true
42
+ PrivateDevices=true
43
+ ProtectSystem=strict
44
+ ReadWritePaths=/opt/magnus-agent
45
+ StateDirectory=magnus-agent
46
+ ProtectHome=read-only
47
+ ProtectKernelTunables=true
48
+ ProtectKernelModules=true
49
+ ProtectKernelLogs=true
50
+ ProtectControlGroups=true
51
+ ProtectClock=true
52
+ ProtectHostname=true
53
+ RestrictSUIDSGID=true
54
+ RestrictRealtime=true
55
+ RestrictNamespaces=true
56
+ LockPersonality=true
57
+ RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
58
+ SystemCallArchitectures=native
59
+
60
+ [Install]
61
+ WantedBy=multi-user.target
@@ -0,0 +1,33 @@
1
+ # Example systemd unit for magnus-agent.
2
+ #
3
+ # Install the package below a stable directory so its private .env and
4
+ # .magnus state survive upgrades:
5
+ # sudo npm install --prefix /opt/magnus-agent @hivemagnus/magnus-agent
6
+ # sudo install -m 0600 /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/.env.example /opt/magnus-agent/.env
7
+ #
8
+ # The agent runs as root because it manages system cron, systemd units, files
9
+ # and local accounts on the host. Limit what it may do through server-side
10
+ # policy and the agent's own allowlists. This is privileged mode
11
+ # (MAGNUS_AGENT_PRIVILEGED=true, the default); to run without root, use
12
+ # magnus-agent-unprivileged.service instead.
13
+ [Unit]
14
+ Description=Magnus Agent
15
+ After=network-online.target
16
+ Wants=network-online.target
17
+
18
+ [Service]
19
+ Type=simple
20
+ WorkingDirectory=/opt/magnus-agent
21
+ Environment=AGENT_INSTALL_DIR=/opt/magnus-agent
22
+ EnvironmentFile=/opt/magnus-agent/.env
23
+ ExecStart=/usr/bin/node /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/dist/index.js start
24
+ Restart=always
25
+ RestartSec=5
26
+ StandardOutput=journal
27
+ StandardError=journal
28
+ NoNewPrivileges=true
29
+ PrivateTmp=true
30
+ UMask=0077
31
+
32
+ [Install]
33
+ WantedBy=multi-user.target
@@ -0,0 +1,22 @@
1
+ # Example oneshot unit for optional Hermes Agent registry reconciliation.
2
+ # It needs HERMES_REGISTRY_TOKEN in /opt/magnus-agent/.env and is started by
3
+ # magnus-hermes-sync.timer. Applying desired state also needs
4
+ # MAGNUS_HERMES_SYNC_PULL=true; append --submit-only to ExecStart to report the
5
+ # local inventory only.
6
+ [Unit]
7
+ Description=Magnus Hermes registry reconciliation
8
+ After=network-online.target magnus-agent.service
9
+ Wants=network-online.target
10
+
11
+ [Service]
12
+ Type=oneshot
13
+ WorkingDirectory=/opt/magnus-agent
14
+ Environment=AGENT_INSTALL_DIR=/opt/magnus-agent
15
+ EnvironmentFile=/opt/magnus-agent/.env
16
+ ExecStart=/usr/bin/flock -n /run/magnus-hermes-sync.lock /usr/bin/node /opt/magnus-agent/node_modules/@hivemagnus/magnus-agent/dist/hermes-sync.js
17
+ TimeoutStartSec=2h
18
+ NoNewPrivileges=true
19
+ PrivateTmp=true
20
+ ProtectSystem=strict
21
+ ReadWritePaths=/home /root /run
22
+ UMask=0077
@@ -0,0 +1,14 @@
1
+ # Example timer for the optional magnus-hermes-sync.service.
2
+ [Unit]
3
+ Description=Check Magnus Hermes registry every five minutes
4
+
5
+ [Timer]
6
+ OnBootSec=2min
7
+ OnUnitInactiveSec=5min
8
+ RandomizedDelaySec=45sec
9
+ AccuracySec=15sec
10
+ Persistent=true
11
+ Unit=magnus-hermes-sync.service
12
+
13
+ [Install]
14
+ WantedBy=timers.target
@@ -0,0 +1,11 @@
1
+ export declare function getHeartbeatStatus(): {
2
+ running: boolean;
3
+ lastAcceptedAt: string | null;
4
+ lastError: string | null;
5
+ consecutiveFailures: number;
6
+ };
7
+ /** Stop the heartbeat loop. */
8
+ export declare function stopHeartbeatLoop(): void;
9
+ /** Periodically send heartbeats + health data to the control API. */
10
+ export declare function startHeartbeatLoop(): void;
11
+ //# sourceMappingURL=agent.d.ts.map