@lamalibre/create-lamaste 4.0.0

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 (270) hide show
  1. package/LICENSE.md +118 -0
  2. package/README.md +114 -0
  3. package/bin/create-lamaste.js +15 -0
  4. package/package.json +54 -0
  5. package/scripts/bundle-vendor.js +110 -0
  6. package/scripts/lamaste-cert-info +62 -0
  7. package/scripts/lamaste-certbot +96 -0
  8. package/scripts/lamaste-priv +693 -0
  9. package/src/index.js +646 -0
  10. package/src/lib/accounts.js +86 -0
  11. package/src/lib/binaries.js +137 -0
  12. package/src/lib/cert-help-page.js +160 -0
  13. package/src/lib/env.js +132 -0
  14. package/src/lib/http-redirect.js +38 -0
  15. package/src/lib/ownership.js +231 -0
  16. package/src/lib/relay-services.js +103 -0
  17. package/src/lib/secrets.js +19 -0
  18. package/src/lib/service-config.js +311 -0
  19. package/src/lib/summary.js +131 -0
  20. package/src/lib/wrappers.js +63 -0
  21. package/src/tasks/gatekeeper.js +233 -0
  22. package/src/tasks/harden.js +293 -0
  23. package/src/tasks/mtls.js +193 -0
  24. package/src/tasks/nginx.js +265 -0
  25. package/src/tasks/node.js +110 -0
  26. package/src/tasks/panel.js +408 -0
  27. package/src/tasks/redeploy.js +438 -0
  28. package/vendor/docs/00-introduction/how-it-works.md +447 -0
  29. package/vendor/docs/00-introduction/quickstart.md +472 -0
  30. package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
  31. package/vendor/docs/01-concepts/authentication.md +464 -0
  32. package/vendor/docs/01-concepts/authorization.md +242 -0
  33. package/vendor/docs/01-concepts/certificates.md +452 -0
  34. package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
  35. package/vendor/docs/01-concepts/mtls.md +490 -0
  36. package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
  37. package/vendor/docs/01-concepts/security-model.md +600 -0
  38. package/vendor/docs/01-concepts/tickets.md +414 -0
  39. package/vendor/docs/01-concepts/tunneling.md +367 -0
  40. package/vendor/docs/02-guides/agent-setup.md +194 -0
  41. package/vendor/docs/02-guides/certificate-management.md +341 -0
  42. package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
  43. package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
  44. package/vendor/docs/02-guides/disaster-recovery.md +464 -0
  45. package/vendor/docs/02-guides/first-tunnel.md +230 -0
  46. package/vendor/docs/02-guides/installation.md +393 -0
  47. package/vendor/docs/02-guides/managing-users.md +255 -0
  48. package/vendor/docs/02-guides/onboarding.md +244 -0
  49. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
  50. package/vendor/docs/02-guides/static-sites.md +364 -0
  51. package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
  52. package/vendor/docs/03-architecture/installer-flow.md +151 -0
  53. package/vendor/docs/03-architecture/installer.md +445 -0
  54. package/vendor/docs/03-architecture/management-flow.md +288 -0
  55. package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
  56. package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
  57. package/vendor/docs/03-architecture/overview.md +541 -0
  58. package/vendor/docs/03-architecture/panel-client.md +416 -0
  59. package/vendor/docs/03-architecture/panel-server.md +695 -0
  60. package/vendor/docs/03-architecture/state-management.md +529 -0
  61. package/vendor/docs/03-architecture/system-overview.md +167 -0
  62. package/vendor/docs/04-api-reference/certificates.md +1141 -0
  63. package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
  64. package/vendor/docs/04-api-reference/onboarding.md +473 -0
  65. package/vendor/docs/04-api-reference/overview.md +404 -0
  66. package/vendor/docs/04-api-reference/services.md +267 -0
  67. package/vendor/docs/04-api-reference/settings.md +343 -0
  68. package/vendor/docs/04-api-reference/sites.md +716 -0
  69. package/vendor/docs/04-api-reference/system.md +268 -0
  70. package/vendor/docs/04-api-reference/tickets.md +618 -0
  71. package/vendor/docs/04-api-reference/tunnels.md +417 -0
  72. package/vendor/docs/04-api-reference/users.md +333 -0
  73. package/vendor/docs/05-operations/backup-and-restore.md +342 -0
  74. package/vendor/docs/05-operations/monitoring.md +285 -0
  75. package/vendor/docs/05-operations/uninstalling.md +344 -0
  76. package/vendor/docs/05-operations/upgrades.md +270 -0
  77. package/vendor/docs/06-reference/config-files.md +1080 -0
  78. package/vendor/docs/06-reference/glossary.md +528 -0
  79. package/vendor/docs/06-reference/installer-flags.md +260 -0
  80. package/vendor/docs/06-reference/ports-and-services.md +244 -0
  81. package/vendor/docs/06-reference/troubleshooting.md +665 -0
  82. package/vendor/docs/_index.json +233 -0
  83. package/vendor/docs/gatekeeper-design.md +953 -0
  84. package/vendor/docs/package.json +15 -0
  85. package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
  86. package/vendor/gatekeeper/dist/boot.d.ts +1 -0
  87. package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
  88. package/vendor/gatekeeper/dist/boot.js +17 -0
  89. package/vendor/gatekeeper/dist/boot.js.map +1 -0
  90. package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
  91. package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
  92. package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
  93. package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
  94. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
  95. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
  96. package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
  97. package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
  98. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
  99. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
  100. package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
  101. package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
  102. package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
  103. package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
  104. package/vendor/gatekeeper/dist/cli/index.js +45 -0
  105. package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
  106. package/vendor/gatekeeper/dist/index.d.ts +9 -0
  107. package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
  108. package/vendor/gatekeeper/dist/index.js +13 -0
  109. package/vendor/gatekeeper/dist/index.js.map +1 -0
  110. package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
  111. package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
  112. package/vendor/gatekeeper/dist/lib/authz.js +42 -0
  113. package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
  114. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
  115. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
  116. package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
  117. package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
  118. package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
  119. package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
  120. package/vendor/gatekeeper/dist/lib/constants.js +79 -0
  121. package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
  122. package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
  123. package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
  124. package/vendor/gatekeeper/dist/lib/grants.js +314 -0
  125. package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
  126. package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
  127. package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
  128. package/vendor/gatekeeper/dist/lib/groups.js +247 -0
  129. package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
  130. package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
  131. package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
  132. package/vendor/gatekeeper/dist/lib/migration.js +79 -0
  133. package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
  134. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
  135. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
  136. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  137. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
  138. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
  139. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  140. package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
  141. package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
  142. package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
  143. package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
  144. package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
  145. package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
  146. package/vendor/gatekeeper/dist/lib/templates.js +151 -0
  147. package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
  148. package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
  149. package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
  150. package/vendor/gatekeeper/dist/lib/types.js +2 -0
  151. package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
  152. package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
  153. package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
  154. package/vendor/gatekeeper/dist/server/index.js +251 -0
  155. package/vendor/gatekeeper/dist/server/index.js.map +1 -0
  156. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
  157. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
  158. package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
  159. package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
  160. package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
  161. package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
  162. package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
  163. package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
  164. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
  165. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
  166. package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
  167. package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
  168. package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
  169. package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
  170. package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
  171. package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
  172. package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
  173. package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
  174. package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
  175. package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
  176. package/vendor/gatekeeper/package.json +49 -0
  177. package/vendor/server/bin/lamaste-server.js +204 -0
  178. package/vendor/server/package.json +31 -0
  179. package/vendor/server/src/commands/certs.js +224 -0
  180. package/vendor/server/src/commands/chisel.js +132 -0
  181. package/vendor/server/src/commands/logs.js +49 -0
  182. package/vendor/server/src/commands/plugins.js +321 -0
  183. package/vendor/server/src/commands/reset-admin.js +478 -0
  184. package/vendor/server/src/commands/restart.js +94 -0
  185. package/vendor/server/src/commands/sites.js +257 -0
  186. package/vendor/server/src/commands/status.js +158 -0
  187. package/vendor/server/src/commands/tunnels.js +365 -0
  188. package/vendor/server/src/commands/uninstall.js +326 -0
  189. package/vendor/server/src/config.js +38 -0
  190. package/vendor/server/src/exec.js +26 -0
  191. package/vendor/server/src/logger.js +39 -0
  192. package/vendor/server/src/ndjson.js +56 -0
  193. package/vendor/server/src/panel-api.js +85 -0
  194. package/vendor/server/src/state.js +45 -0
  195. package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
  196. package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
  197. package/vendor/server-ui/dist/index.html +13 -0
  198. package/vendor/serverd/package.json +44 -0
  199. package/vendor/serverd/src/boot.js +13 -0
  200. package/vendor/serverd/src/index.js +191 -0
  201. package/vendor/serverd/src/lib/app-error.js +14 -0
  202. package/vendor/serverd/src/lib/authelia.js +85 -0
  203. package/vendor/serverd/src/lib/certbot.js +74 -0
  204. package/vendor/serverd/src/lib/chisel-args.js +6 -0
  205. package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
  206. package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
  207. package/vendor/serverd/src/lib/chisel-users.js +109 -0
  208. package/vendor/serverd/src/lib/chisel.js +81 -0
  209. package/vendor/serverd/src/lib/config.js +190 -0
  210. package/vendor/serverd/src/lib/constants.js +8 -0
  211. package/vendor/serverd/src/lib/csr-signing.js +331 -0
  212. package/vendor/serverd/src/lib/enrollment.js +302 -0
  213. package/vendor/serverd/src/lib/files.js +19 -0
  214. package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
  215. package/vendor/serverd/src/lib/invite-page.js +281 -0
  216. package/vendor/serverd/src/lib/ip-utils.js +79 -0
  217. package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
  218. package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
  219. package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
  220. package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
  221. package/vendor/serverd/src/lib/mtls.js +795 -0
  222. package/vendor/serverd/src/lib/nginx.js +1090 -0
  223. package/vendor/serverd/src/lib/pki-paths.js +41 -0
  224. package/vendor/serverd/src/lib/pki-sign.js +103 -0
  225. package/vendor/serverd/src/lib/plugins.js +538 -0
  226. package/vendor/serverd/src/lib/push-install.js +390 -0
  227. package/vendor/serverd/src/lib/revocation.js +112 -0
  228. package/vendor/serverd/src/lib/services.js +131 -0
  229. package/vendor/serverd/src/lib/session.js +151 -0
  230. package/vendor/serverd/src/lib/state-db.js +130 -0
  231. package/vendor/serverd/src/lib/state.js +140 -0
  232. package/vendor/serverd/src/lib/storage.js +63 -0
  233. package/vendor/serverd/src/lib/system-stats.js +58 -0
  234. package/vendor/serverd/src/lib/tickets.js +1556 -0
  235. package/vendor/serverd/src/lib/totp.js +76 -0
  236. package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
  237. package/vendor/serverd/src/lib/user-access-session.js +142 -0
  238. package/vendor/serverd/src/lib/user-access.js +52 -0
  239. package/vendor/serverd/src/middleware/errors.js +63 -0
  240. package/vendor/serverd/src/middleware/mtls.js +120 -0
  241. package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
  242. package/vendor/serverd/src/middleware/role-guard.js +58 -0
  243. package/vendor/serverd/src/middleware/twofa-session.js +65 -0
  244. package/vendor/serverd/src/middleware/user-access-session.js +52 -0
  245. package/vendor/serverd/src/routes/enrollment.js +120 -0
  246. package/vendor/serverd/src/routes/health.js +22 -0
  247. package/vendor/serverd/src/routes/invite.js +163 -0
  248. package/vendor/serverd/src/routes/management/agents.js +182 -0
  249. package/vendor/serverd/src/routes/management/certs.js +911 -0
  250. package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
  251. package/vendor/serverd/src/routes/management/identity.js +107 -0
  252. package/vendor/serverd/src/routes/management/invitations.js +166 -0
  253. package/vendor/serverd/src/routes/management/logs.js +218 -0
  254. package/vendor/serverd/src/routes/management/plugins.js +560 -0
  255. package/vendor/serverd/src/routes/management/services.js +63 -0
  256. package/vendor/serverd/src/routes/management/settings.js +325 -0
  257. package/vendor/serverd/src/routes/management/sites.js +522 -0
  258. package/vendor/serverd/src/routes/management/storage.js +192 -0
  259. package/vendor/serverd/src/routes/management/system.js +201 -0
  260. package/vendor/serverd/src/routes/management/tickets.js +457 -0
  261. package/vendor/serverd/src/routes/management/tunnels.js +709 -0
  262. package/vendor/serverd/src/routes/management/users.js +377 -0
  263. package/vendor/serverd/src/routes/management.js +36 -0
  264. package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
  265. package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
  266. package/vendor/serverd/src/routes/onboarding/index.js +18 -0
  267. package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
  268. package/vendor/serverd/src/routes/onboarding/status.js +12 -0
  269. package/vendor/serverd/src/routes/plugin-router.js +79 -0
  270. package/vendor/serverd/src/routes/user-access.js +389 -0
@@ -0,0 +1,618 @@
1
+ # Tickets API
2
+
3
+ > Endpoints for managing agent-to-agent authorization: scope registration, instance management, assignments, ticket operations, and session management.
4
+
5
+ ## Authentication
6
+
7
+ All ticket endpoints require mTLS authentication. Endpoints marked "Admin" require an admin certificate. Endpoints marked "Admin/Agent" accept both admin certificates and agent certificates with the appropriate capability.
8
+
9
+ Agent-facing endpoints use generic error messages (404 or 401) for all authorization failures to prevent information leakage.
10
+
11
+ ## Scope Management
12
+
13
+ ### Register Scope
14
+
15
+ ```
16
+ POST /api/tickets/scopes
17
+ ```
18
+
19
+ **Auth:** Admin only
20
+
21
+ Register a new ticket scope (capability set with transport configuration).
22
+
23
+ **Request body:**
24
+
25
+ | Field | Type | Required | Description |
26
+ | ------------------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
27
+ | `name` | string | Yes | Lowercase alphanumeric with hyphens (1-50 chars). Cannot use reserved names (`tunnels`, `plugins`, `health`, `tickets`, etc.) |
28
+ | `version` | string | Yes | Version string (1-50 chars) |
29
+ | `description` | string | Yes | Human-readable description (1-500 chars) |
30
+ | `scopes` | array | Yes | Capability declarations (1-50 items) |
31
+ | `scopes[].name` | string | Yes | Capability name (e.g., `shell:connect`) |
32
+ | `scopes[].description` | string | Yes | What this capability grants |
33
+ | `scopes[].instanceScoped` | boolean | Yes | Whether tickets are scoped to instances |
34
+ | `transport` | object | Yes | Transport configuration |
35
+ | `transport.strategies` | string[] | Yes | Array of `"tunnel"`, `"relay"`, `"direct"` |
36
+ | `transport.preferred` | string | Yes | Preferred strategy |
37
+ | `transport.port` | number | Yes | Port number (0 or 1024-65535) |
38
+ | `transport.protocol` | string | Yes | `"wss"` or `"tcp"` |
39
+
40
+ **Response (201):**
41
+
42
+ ```json
43
+ {
44
+ "ok": true,
45
+ "registered": ["shell:connect"]
46
+ }
47
+ ```
48
+
49
+ **Errors:** 409 (scope name already registered), 500 (internal error)
50
+
51
+ ---
52
+
53
+ ### List Scopes
54
+
55
+ ```
56
+ GET /api/tickets/scopes
57
+ ```
58
+
59
+ **Auth:** Admin only
60
+
61
+ Returns all registered scopes, instances, and assignments.
62
+
63
+ **Response (200):**
64
+
65
+ ```json
66
+ {
67
+ "scopes": [...],
68
+ "instances": [...],
69
+ "assignments": [...]
70
+ }
71
+ ```
72
+
73
+ ---
74
+
75
+ ### Delete Scope
76
+
77
+ ```
78
+ DELETE /api/tickets/scopes/:name
79
+ ```
80
+
81
+ **Auth:** Admin only
82
+
83
+ Unregisters a scope and removes its capabilities from the valid capability set.
84
+
85
+ **Response (200):**
86
+
87
+ ```json
88
+ {
89
+ "ok": true,
90
+ "name": "shell"
91
+ }
92
+ ```
93
+
94
+ **Errors:** 404 (scope not found), 500 (internal error)
95
+
96
+ ---
97
+
98
+ ## Instance Management
99
+
100
+ ### Register Instance
101
+
102
+ ```
103
+ POST /api/tickets/instances
104
+ ```
105
+
106
+ **Auth:** Admin or Agent (requires base scope capability)
107
+
108
+ Register an instance offering a specific scope. Idempotent: re-registration with the same scope and agent updates transport and resets the heartbeat.
109
+
110
+ **Request body:**
111
+
112
+ | Field | Type | Required | Description |
113
+ | ----------------------- | -------- | -------- | ---------------------------------------------------------------------------------- |
114
+ | `scope` | string | Yes | Capability name in `scope:action` format (e.g., `shell:connect`) |
115
+ | `transport` | object | Yes | Transport configuration |
116
+ | `transport.strategies` | string[] | Yes | Array of `"tunnel"`, `"relay"`, `"direct"` |
117
+ | `transport.preferred` | string | No | Preferred strategy |
118
+ | `transport.direct` | object | No | Direct connection details |
119
+ | `transport.direct.host` | string | Yes\* | Public hostname or IP (1-255 chars). Private/reserved IPs are rejected (see below) |
120
+ | `transport.direct.port` | number | Yes\* | Port number (1024-65535) |
121
+
122
+ \* Required when `transport.direct` is provided.
123
+
124
+ **Host validation:** The `transport.direct.host` field rejects private and reserved addresses to prevent SSRF. The following are rejected with a 400 error:
125
+
126
+ - Private IPv4 ranges: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
127
+ - Link-local: `169.254.0.0/16`
128
+ - Loopback: `localhost`, `127.0.0.1`, `::1`
129
+ - Metadata endpoints: `169.254.169.254`, `metadata.google.internal`
130
+ - Zero network: `0.0.0.0/8`
131
+
132
+ **Response (201 new, 200 re-registration):**
133
+
134
+ ```json
135
+ {
136
+ "ok": true,
137
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
138
+ "instanceScope": "shell:connect:a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2"
139
+ }
140
+ ```
141
+
142
+ **Errors:** 400 (missing agent label, or private/reserved IP in `transport.direct.host`), 403 (insufficient capability), 404 (scope not found), 503 (hard cap: 200 instances)
143
+
144
+ ---
145
+
146
+ ### Deregister Instance
147
+
148
+ ```
149
+ DELETE /api/tickets/instances/:instanceId
150
+ ```
151
+
152
+ **Auth:** Admin or owning Agent
153
+
154
+ Removes an instance and cleans up related assignments, tickets, and sessions.
155
+
156
+ **Params:** `instanceId` — hex string (1-128 chars)
157
+
158
+ **Response (200):**
159
+
160
+ ```json
161
+ {
162
+ "ok": true,
163
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2"
164
+ }
165
+ ```
166
+
167
+ **Errors:** 404 (not found or unauthorized — same response for both)
168
+
169
+ ---
170
+
171
+ ### Instance Heartbeat
172
+
173
+ ```
174
+ POST /api/tickets/instances/:instanceId/heartbeat
175
+ ```
176
+
177
+ **Auth:** Admin or owning Agent
178
+
179
+ Updates the instance's `lastHeartbeat` timestamp and resets status to active. Re-validates that the owning agent still has the scope capability — returns 404 if the agent is revoked or the capability has been removed.
180
+
181
+ **Response (200):**
182
+
183
+ ```json
184
+ {
185
+ "ok": true
186
+ }
187
+ ```
188
+
189
+ **Errors:** 400 (missing agent label), 404 (not found, or agent revoked/lacks capability)
190
+
191
+ ---
192
+
193
+ ## Assignment Management
194
+
195
+ ### Create Assignment
196
+
197
+ ```
198
+ POST /api/tickets/assignments
199
+ ```
200
+
201
+ **Auth:** Admin only
202
+
203
+ Assign an agent to an instance scope, granting it permission to receive tickets for that instance.
204
+
205
+ **Request body:**
206
+
207
+ | Field | Type | Required | Description |
208
+ | --------------- | ------ | -------- | ----------------------------------------------------------------------------------------------- |
209
+ | `agentLabel` | string | Yes | Agent or plugin-agent certificate label (1-150 chars, allows colons for `plugin-agent:` prefix) |
210
+ | `instanceScope` | string | Yes | Format: `scope:action:instanceid` (1-200 chars) |
211
+
212
+ **Validation:**
213
+
214
+ - Agent must exist and not be revoked
215
+ - Agent must have the base scope capability
216
+ - Instance must exist and not be dead
217
+
218
+ **Response (201 new, 200 existing):**
219
+
220
+ ```json
221
+ {
222
+ "ok": true,
223
+ "assignment": {
224
+ "agentLabel": "linux-agent",
225
+ "instanceScope": "shell:connect:a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
226
+ "assignedAt": "2026-03-26T10:10:00.000Z",
227
+ "assignedBy": "admin"
228
+ }
229
+ }
230
+ ```
231
+
232
+ **Errors:** 400 (agent missing capability), 404 (agent or instance not found)
233
+
234
+ ---
235
+
236
+ ### Delete Assignment
237
+
238
+ ```
239
+ DELETE /api/tickets/assignments/:agentLabel/:instanceScope
240
+ ```
241
+
242
+ **Auth:** Admin only
243
+
244
+ **Response (200):**
245
+
246
+ ```json
247
+ {
248
+ "ok": true
249
+ }
250
+ ```
251
+
252
+ **Errors:** 404 (assignment not found)
253
+
254
+ ---
255
+
256
+ ### List Assignments
257
+
258
+ ```
259
+ GET /api/tickets/assignments
260
+ ```
261
+
262
+ **Auth:** Admin only
263
+
264
+ **Query params:** `agentLabel` (optional), `instanceScope` (optional) — filters.
265
+
266
+ **Response (200):**
267
+
268
+ ```json
269
+ {
270
+ "assignments": [...]
271
+ }
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Ticket Operations
277
+
278
+ ### Request Ticket
279
+
280
+ ```
281
+ POST /api/tickets
282
+ ```
283
+
284
+ **Auth:** Admin or Agent (requires base scope capability)
285
+
286
+ Request a ticket to authorize communication with a target agent.
287
+
288
+ **Request body:**
289
+
290
+ | Field | Type | Required | Description |
291
+ | ------------ | ------ | -------- | ------------------------------------------------ |
292
+ | `scope` | string | Yes | Capability name |
293
+ | `instanceId` | string | Yes | Hex instance ID (1-64 chars) |
294
+ | `target` | string | Yes | Target agent or plugin-agent label (1-150 chars) |
295
+
296
+ **Multi-stage validation:**
297
+
298
+ 1. Source agent has base scope capability
299
+ 2. Target agent has base scope capability and is not revoked
300
+ 3. Source owns the instance
301
+ 4. Instance is active (not stale or dead)
302
+ 5. Source and target are different agents (self-tickets rejected)
303
+ 6. Target is assigned to the instance
304
+
305
+ **Response (201):**
306
+
307
+ ```json
308
+ {
309
+ "ok": true,
310
+ "ticket": {
311
+ "id": "64-hex-char-ticket-id",
312
+ "scope": "shell:connect",
313
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
314
+ "source": "macbook-pro",
315
+ "target": "linux-agent",
316
+ "expiresAt": "2026-03-26T10:15:30.000Z"
317
+ }
318
+ }
319
+ ```
320
+
321
+ **Errors:** 404 (generic — all authorization failures), 429 (rate limit: 10/min per agent), 503 (stale instance or hard cap: 1000 tickets)
322
+
323
+ ---
324
+
325
+ ### Check Inbox
326
+
327
+ ```
328
+ GET /api/tickets/inbox
329
+ ```
330
+
331
+ **Auth:** Admin or Agent (requires `certLabel`)
332
+
333
+ Returns non-expired, unused tickets where the caller is the target.
334
+
335
+ **Response (200):**
336
+
337
+ ```json
338
+ {
339
+ "tickets": [
340
+ {
341
+ "id": "...",
342
+ "scope": "shell:connect",
343
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
344
+ "source": "macbook-pro",
345
+ "expiresAt": "2026-03-26T10:15:30.000Z",
346
+ "transport": {}
347
+ }
348
+ ]
349
+ }
350
+ ```
351
+
352
+ **Errors:** 400 (missing certLabel)
353
+
354
+ ---
355
+
356
+ ### Validate Ticket
357
+
358
+ ```
359
+ POST /api/tickets/validate
360
+ ```
361
+
362
+ **Auth:** Admin or Agent (requires `certLabel`)
363
+
364
+ Validate and consume a ticket. This is an atomic operation — the ticket is marked as used on successful validation.
365
+
366
+ **Request body:**
367
+
368
+ | Field | Type | Required | Description |
369
+ | ---------- | ------ | -------- | --------------------------- |
370
+ | `ticketId` | string | Yes | Hex ticket ID (1-128 chars) |
371
+
372
+ **Response (200):**
373
+
374
+ ```json
375
+ {
376
+ "valid": true,
377
+ "scope": "shell:connect",
378
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
379
+ "source": "macbook-pro",
380
+ "target": "linux-agent",
381
+ "transport": {}
382
+ }
383
+ ```
384
+
385
+ **Errors:** 401 (generic "Invalid ticket" — covers expired, used, wrong target, not found)
386
+
387
+ ---
388
+
389
+ ### List Tickets (Admin)
390
+
391
+ ```
392
+ GET /api/tickets
393
+ ```
394
+
395
+ **Auth:** Admin only
396
+
397
+ Returns all tickets (including expired and used).
398
+
399
+ **Response (200):**
400
+
401
+ ```json
402
+ {
403
+ "tickets": [...]
404
+ }
405
+ ```
406
+
407
+ ---
408
+
409
+ ### Revoke Ticket
410
+
411
+ ```
412
+ DELETE /api/tickets/:ticketId
413
+ ```
414
+
415
+ **Auth:** Admin only
416
+
417
+ Marks a ticket as used and terminates any associated session.
418
+
419
+ **Response (200):**
420
+
421
+ ```json
422
+ {
423
+ "ok": true
424
+ }
425
+ ```
426
+
427
+ **Errors:** 404 (ticket not found)
428
+
429
+ ---
430
+
431
+ ## Session Management
432
+
433
+ ### Create Session
434
+
435
+ ```
436
+ POST /api/tickets/sessions
437
+ ```
438
+
439
+ **Auth:** Admin or Agent (requires `certLabel`)
440
+
441
+ Create a session from a validated (used) ticket. The caller must be the ticket's target. The server generates the `sessionId` — clients do not provide it.
442
+
443
+ **Request body:**
444
+
445
+ | Field | Type | Required | Description |
446
+ | ---------- | ------ | -------- | --------------------------- |
447
+ | `ticketId` | string | Yes | Hex ticket ID (1-128 chars) |
448
+
449
+ **Response (201):**
450
+
451
+ ```json
452
+ {
453
+ "ok": true,
454
+ "session": {
455
+ "sessionId": "...",
456
+ "ticketId": "...",
457
+ "scope": "shell:connect",
458
+ "instanceId": "a7f3b2c9d1e2f3a4b5c6d7e8f9a0b1c2",
459
+ "source": "macbook-pro",
460
+ "target": "linux-agent",
461
+ "createdAt": "2026-03-26T10:15:30.000Z",
462
+ "lastActivityAt": "2026-03-26T10:15:30.000Z",
463
+ "status": "active",
464
+ "reconnectGraceSeconds": 60
465
+ }
466
+ }
467
+ ```
468
+
469
+ **Errors:** 400 (invalid ticket state), 409 (duplicate session for ticket), 503 (hard cap: 500 sessions)
470
+
471
+ ---
472
+
473
+ ### Session Heartbeat
474
+
475
+ ```
476
+ POST /api/tickets/sessions/:sessionId/heartbeat
477
+ ```
478
+
479
+ **Auth:** Admin or Agent (requires `certLabel`)
480
+
481
+ Re-validates the session's authorization and updates activity timestamp.
482
+
483
+ **Validation checks:**
484
+
485
+ 1. Session is not dead
486
+ 2. Source certificate not revoked
487
+ 3. Source has scope capability
488
+ 4. Target certificate not revoked
489
+ 5. Target has scope capability
490
+ 6. Assignment still valid
491
+
492
+ **Response (200):**
493
+
494
+ ```json
495
+ {
496
+ "authorized": true
497
+ }
498
+ ```
499
+
500
+ Or if authorization failed (session is terminated):
501
+
502
+ ```json
503
+ {
504
+ "authorized": false,
505
+ "reason": "capability_removed"
506
+ }
507
+ ```
508
+
509
+ Possible `reason` values: `admin_killed`, `source_revoked`, `capability_removed`, `target_revoked`, `assignment_removed`.
510
+
511
+ **Errors:** 400 (missing certLabel), 404 (session not found)
512
+
513
+ ---
514
+
515
+ ### Update Session
516
+
517
+ ```
518
+ PATCH /api/tickets/sessions/:sessionId
519
+ ```
520
+
521
+ **Auth:** Admin or Agent (requires `certLabel` — caller can be either the session's source or target)
522
+
523
+ Update session status (e.g., entering grace period for reconnection). Re-validates authorization on every status transition: checks that the source certificate is not revoked, source still has the scope capability, and the target's assignment is still valid. If any check fails, the session is terminated and the endpoint returns 409.
524
+
525
+ **Request body:**
526
+
527
+ | Field | Type | Required | Description |
528
+ | -------- | ------ | -------- | ----------------------- |
529
+ | `status` | string | Yes | `"active"` or `"grace"` |
530
+
531
+ The server sets `lastActivityAt` automatically — clients cannot provide or override this field.
532
+
533
+ **Response (200):**
534
+
535
+ ```json
536
+ {
537
+ "ok": true
538
+ }
539
+ ```
540
+
541
+ **Errors:** 400 (missing certLabel), 404 (session not found), 409 (session is terminated — dead, or authorization re-validation failed)
542
+
543
+ ---
544
+
545
+ ### Kill Session
546
+
547
+ ```
548
+ DELETE /api/tickets/sessions/:sessionId
549
+ ```
550
+
551
+ **Auth:** Admin only
552
+
553
+ Immediately terminates a session.
554
+
555
+ **Response (200):**
556
+
557
+ ```json
558
+ {
559
+ "ok": true
560
+ }
561
+ ```
562
+
563
+ **Errors:** 404 (session not found)
564
+
565
+ ---
566
+
567
+ ### List Sessions
568
+
569
+ ```
570
+ GET /api/tickets/sessions
571
+ ```
572
+
573
+ **Auth:** Admin only
574
+
575
+ Returns all sessions (including dead ones pending cleanup).
576
+
577
+ **Response (200):**
578
+
579
+ ```json
580
+ {
581
+ "sessions": [...]
582
+ }
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Rate Limiting
588
+
589
+ Ticket requests are rate-limited to **10 per agent per minute**. The rate counter uses a 1-minute window with periodic cleanup every 2 minutes. Exceeding the limit returns:
590
+
591
+ ```json
592
+ {
593
+ "error": "Rate limit exceeded"
594
+ }
595
+ ```
596
+
597
+ with HTTP 429.
598
+
599
+ ## Hard Caps
600
+
601
+ Resource limits protect the 512 MB server:
602
+
603
+ | Resource | Max | HTTP response when exceeded |
604
+ | --------------- | ---- | --------------------------- |
605
+ | Instances | 200 | 503 |
606
+ | Tickets | 1000 | 503 |
607
+ | Active sessions | 500 | 503 |
608
+
609
+ ## Cleanup Timers
610
+
611
+ The panel server runs periodic cleanup (every 60 seconds):
612
+
613
+ | Item | Condition | Action |
614
+ | --------------- | ---------------------- | ------------------------------------------- |
615
+ | Stale instances | No heartbeat for 5 min | Status → stale (tickets rejected) |
616
+ | Dead instances | No heartbeat for 1 hr | Removed with assignments, tickets, sessions |
617
+ | Expired tickets | Older than 1 hr | Removed from store |
618
+ | Dead sessions | Dead for 24 hr | Removed from store |