@lamalibre/create-lamaste 4.5.0 → 4.6.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 (105) hide show
  1. package/package.json +2 -2
  2. package/scripts/lamaste-priv +34 -2
  3. package/vendor/docs/00-introduction/how-it-works.md +2 -2
  4. package/vendor/docs/00-introduction/quickstart.md +5 -5
  5. package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
  6. package/vendor/docs/01-concepts/certificates.md +3 -3
  7. package/vendor/docs/01-concepts/mtls.md +2 -2
  8. package/vendor/docs/01-concepts/security-model.md +2 -2
  9. package/vendor/docs/01-concepts/tickets.md +2 -2
  10. package/vendor/docs/01-concepts/tunneling.md +4 -4
  11. package/vendor/docs/02-guides/agent-setup.md +5 -5
  12. package/vendor/docs/02-guides/certificate-management.md +2 -2
  13. package/vendor/docs/02-guides/cloud-provisioning.md +3 -3
  14. package/vendor/docs/02-guides/desktop-app-setup.md +10 -10
  15. package/vendor/docs/02-guides/installation.md +3 -3
  16. package/vendor/docs/02-guides/onboarding.md +2 -2
  17. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
  18. package/vendor/docs/02-guides/static-sites.md +4 -0
  19. package/vendor/docs/03-architecture/installer-flow.md +2 -2
  20. package/vendor/docs/03-architecture/installer.md +4 -4
  21. package/vendor/docs/03-architecture/management-flow.md +1 -1
  22. package/vendor/docs/03-architecture/nginx-configuration.md +65 -7
  23. package/vendor/docs/03-architecture/overview.md +5 -5
  24. package/vendor/docs/03-architecture/panel-client.md +6 -6
  25. package/vendor/docs/03-architecture/panel-server.md +2 -2
  26. package/vendor/docs/03-architecture/state-management.md +2 -2
  27. package/vendor/docs/03-architecture/system-overview.md +1 -1
  28. package/vendor/docs/04-api-reference/agent-hosted-plugins.md +112 -37
  29. package/vendor/docs/04-api-reference/app-host.md +3 -3
  30. package/vendor/docs/04-api-reference/gatekeeper.md +19 -1
  31. package/vendor/docs/04-api-reference/lifecycle-hooks.md +4 -4
  32. package/vendor/docs/04-api-reference/onboarding.md +1 -1
  33. package/vendor/docs/04-api-reference/sites.md +4 -0
  34. package/vendor/docs/04-api-reference/tunnels.md +21 -19
  35. package/vendor/docs/05-operations/backup-and-restore.md +1 -1
  36. package/vendor/docs/05-operations/uninstalling.md +1 -1
  37. package/vendor/docs/05-operations/upgrades.md +15 -6
  38. package/vendor/docs/06-reference/config-files.md +19 -15
  39. package/vendor/docs/06-reference/glossary.md +3 -3
  40. package/vendor/docs/06-reference/installer-flags.md +13 -13
  41. package/vendor/docs/06-reference/ports-and-services.md +1 -1
  42. package/vendor/docs/06-reference/troubleshooting.md +8 -8
  43. package/vendor/docs/gatekeeper-design.md +8 -8
  44. package/vendor/docs/identity-directory-design.md +3 -3
  45. package/vendor/docs/package.json +1 -1
  46. package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
  47. package/vendor/gatekeeper/dist/cli/index.js +0 -0
  48. package/vendor/gatekeeper/dist/index.d.ts +3 -3
  49. package/vendor/gatekeeper/dist/index.d.ts.map +1 -1
  50. package/vendor/gatekeeper/dist/index.js +2 -2
  51. package/vendor/gatekeeper/dist/index.js.map +1 -1
  52. package/vendor/gatekeeper/dist/lib/authz.d.ts +9 -0
  53. package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -1
  54. package/vendor/gatekeeper/dist/lib/authz.js +31 -0
  55. package/vendor/gatekeeper/dist/lib/authz.js.map +1 -1
  56. package/vendor/gatekeeper/dist/lib/constants.d.ts +5 -2
  57. package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -1
  58. package/vendor/gatekeeper/dist/lib/constants.js +5 -2
  59. package/vendor/gatekeeper/dist/lib/constants.js.map +1 -1
  60. package/vendor/gatekeeper/dist/lib/tunnels.d.ts +3 -6
  61. package/vendor/gatekeeper/dist/lib/tunnels.d.ts.map +1 -1
  62. package/vendor/gatekeeper/dist/lib/tunnels.js +4 -16
  63. package/vendor/gatekeeper/dist/lib/tunnels.js.map +1 -1
  64. package/vendor/gatekeeper/dist/lib/types.d.ts +0 -19
  65. package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -1
  66. package/vendor/gatekeeper/dist/server/index.d.ts +2 -1
  67. package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -1
  68. package/vendor/gatekeeper/dist/server/index.js +29 -10
  69. package/vendor/gatekeeper/dist/server/index.js.map +1 -1
  70. package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -1
  71. package/vendor/gatekeeper/dist/server/routes/authz.js +103 -22
  72. package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -1
  73. package/vendor/gatekeeper/package.json +2 -2
  74. package/vendor/server/package.json +2 -2
  75. package/vendor/server/src/commands/plugin-web-surface.js +269 -0
  76. package/vendor/server/src/commands/plugins.js +63 -6
  77. package/vendor/server/src/commands/sites.js +15 -1
  78. package/vendor/server/src/plugin-approval.js +80 -1
  79. package/vendor/server/src/plugin-web-surface.js +307 -0
  80. package/vendor/server-ui/dist/assets/index-BZwQ_aQc.css +1 -0
  81. package/vendor/server-ui/dist/assets/index-BvEfCZYS.js +84 -0
  82. package/vendor/server-ui/dist/index.html +2 -2
  83. package/vendor/serverd/package.json +2 -2
  84. package/vendor/serverd/src/index.js +9 -4
  85. package/vendor/serverd/src/lib/chisel-runtime.js +18 -6
  86. package/vendor/serverd/src/lib/chisel.js +10 -2
  87. package/vendor/serverd/src/lib/gatekeeper-client.js +18 -7
  88. package/vendor/serverd/src/lib/hook-pipelines.js +8 -3
  89. package/vendor/serverd/src/lib/migrations/state/0015_plugin_web_surface.sql +14 -0
  90. package/vendor/serverd/src/lib/nginx.js +269 -2
  91. package/vendor/serverd/src/lib/plugin-hooks.js +40 -11
  92. package/vendor/serverd/src/lib/plugin-lifecycle.js +128 -5
  93. package/vendor/serverd/src/lib/plugin-packages.js +74 -2
  94. package/vendor/serverd/src/lib/plugins.js +39 -6
  95. package/vendor/serverd/src/lib/state.js +18 -0
  96. package/vendor/serverd/src/lib/user-surface.js +48 -27
  97. package/vendor/serverd/src/lib/vhost-reconcile.js +5 -3
  98. package/vendor/serverd/src/lib/web-surface.js +766 -0
  99. package/vendor/serverd/src/routes/management/plugin-web-surface.js +151 -0
  100. package/vendor/serverd/src/routes/management/plugins.js +2 -0
  101. package/vendor/serverd/src/routes/management/sites.js +143 -65
  102. package/vendor/serverd/src/routes/management/tunnels.js +11 -20
  103. package/vendor/serverd/src/routes/management.js +2 -0
  104. package/vendor/server-ui/dist/assets/index-D-fer5ef.css +0 -1
  105. package/vendor/server-ui/dist/assets/index-DSaDPJaw.js +0 -84
@@ -4,14 +4,14 @@
4
4
 
5
5
  ## In Plain English
6
6
 
7
- When you run `npx @lamalibre/create-lamaste@4.5.0` on a fresh VPS, the installer takes over and does everything automatically: hardens the OS, installs dependencies, generates security certificates, configures nginx, deploys the panel, and starts the service. It prints a summary with instructions for downloading your client certificate and accessing the panel. No prompts, no questions, no configuration files to edit.
7
+ When you run `npx @lamalibre/create-lamaste@4.6.0` on a fresh VPS, the installer takes over and does everything automatically: hardens the OS, installs dependencies, generates security certificates, configures nginx, deploys the panel, and starts the service. It prints a summary with instructions for downloading your client certificate and accessing the panel. No prompts, no questions, no configuration files to edit.
8
8
 
9
9
  The installer is deliberately limited in scope. It sets up just enough to serve the panel UI over a secure connection. Everything else — domain configuration, tunnel setup, user management — happens through the browser-based onboarding wizard after the installer finishes.
10
10
 
11
11
  ## Overview
12
12
 
13
13
  ```
14
- npx @lamalibre/create-lamaste@4.5.0
14
+ npx @lamalibre/create-lamaste@4.6.0
15
15
  │
16
16
  ├── bin/create-lamaste.js ← CLI entry point
17
17
  │ └── calls main() from src/index.js
@@ -181,7 +181,7 @@ Six task groups run sequentially through Listr2:
181
181
  **Chisel and Authelia** (`lib/relay-services.js`, run on install and on every redeploy):
182
182
 
183
183
  - Creates the `lamaste-chisel` group (and adds `lamaste` to it) and the `lamaste-authelia` system account (no login shell, no home)
184
- - Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.5.0` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`) before anything is unpacked, staged in a `mkdtemp` directory and renamed into place. A binary already at the pinned version is left alone; an Authelia **newer** than the pin is kept, never downgraded (its database may use a schema the pinned release cannot read)
184
+ - Installs Chisel 1.12.0 and Authelia 4.39.28 to `/usr/local/bin` (`lib/binaries.js`): downloaded from fixed release URLs, verified against the SHA-256 digests pinned in `@lamalibre/lamaste@4.6.0` (`CHISEL_RELEASE`, `AUTHELIA_RELEASE`) before anything is unpacked, staged in a `mkdtemp` directory and renamed into place. A binary already at the pinned version is left alone; an Authelia **newer** than the pin is kept, never downgraded (its database may use a schema the pinned release cannot read)
185
185
  - Writes `/etc/systemd/system/chisel.service` (`User=nobody`, `Group=lamaste-chisel`) and `/etc/systemd/system/authelia.service` (`User=lamaste-authelia`, `UMask=027`, `Environment=X_AUTHELIA_CONFIG_FILTERS=template`, `ProtectSystem=strict` with `ReadWritePaths=/etc/authelia /var/log/authelia`, `SystemCallFilter=@system-service`, empty `CapabilityBoundingSet`, `NoNewPrivileges`); both are enabled and started later by onboarding
186
186
  - Generates the OpenID Connect issuer key `/etc/authelia/oidc-issuer.pem` if it is missing (`lib/oidc-issuer-key.js`): RSA 4096 generated in the installer process, written by a child process running as `lamaste-authelia` (`wx`, 0600, renamed into place) so root never writes through `/etc/authelia`. The panel references it from Authelia's configuration with a `{{ secret "…" }}` template expression — which is why the unit and `lamaste-priv authelia-totp` set the `template` configuration filter — and can never read it. A key owned by anyone else is replaced; one owned by the Authelia account is kept (its mode fixed through a descriptor if it drifted)
187
187
  - Sets ownership (`lib/ownership.js`): `/var/www/lamaste` `lamaste:www-data 2750`; `/etc/authelia` `lamaste:lamaste-authelia 2770` (setgid) with `configuration.yml` `0640`, `users.yml` `0660`, `.secrets.json` `0600` (lamaste), `db.sqlite3*` and `notifications.txt` `lamaste-authelia 0600`; `/var/log/authelia` `lamaste-authelia 0750`; `chisel-server.key` (if present) `lamaste:lamaste-chisel 0640`; the PKI directory `lamaste:lamaste` (the panel is the CA)
@@ -253,7 +253,7 @@ When the installer detects an existing Lamaste installation (`/etc/lamalibre/lam
253
253
 
254
254
  Redeploy mode stops the panel and gatekeeper, secures the install directory (a non-root-owned tree is moved aside and removed at the end), redeploys the panel server, `lamaste-server` CLI, UI, docs, gatekeeper and cert help page, merges `panel.json`, runs the same Chisel/Authelia step as a fresh install (stopping a running Authelia while its files change hands), rewrites the panel's systemd unit, the root-owned programs and the sudoers rules, ensures the port-80 redirect, then restarts Chisel if its binary or unit changed, starts Authelia and the gatekeeper if they were running, and restarts the panel. It does not touch OS hardening, mTLS certificates or the panel's vhosts. The panel's self-update (`sudo lamaste-priv self-update <version>`) runs this path as root, so it never writes through a path the `lamaste` user controls.
255
255
 
256
- This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.5.0` on an existing installation updates the code and the pinned services while preserving all configuration and certificates. Use `--force-full` to bypass this and run the complete installer.
256
+ This provides a fast upgrade path: re-running `npx @lamalibre/create-lamaste@4.6.0` on an existing installation updates the code and the pinned services while preserving all configuration and certificates. Use `--force-full` to bypass this and run the complete installer.
257
257
 
258
258
  The redeploy logic lives in `tasks/redeploy.js`, with shared systemd unit and sudoers content generators in `lib/service-config.js`.
259
259
 
@@ -278,7 +278,7 @@ Everything else the panel does needs no rule: the PKI directory (agent CSR signi
278
278
 
279
279
  The certbot wrappers accept only lowercase DNS hostnames (no wildcards or path characters, at most 100 per certificate) and a syntactically valid email address. Renewals the panel triggers pass `--no-random-sleep-on-renew`, because certbot otherwise sleeps up to about 8 minutes before a non-interactive renewal (a delay meant for `certbot.timer`) while an operator waits.
280
280
 
281
- Redeploying (`npx @lamalibre/create-lamaste@4.5.0` on an existing install) reinstalls the programs, removes retired ones (`lamaste-sign-csr`, `lamaste-pki-rename`), and replaces this file atomically after `visudo -c` accepts it, so upgrades pick up new rules.
281
+ Redeploying (`npx @lamalibre/create-lamaste@4.6.0` on an existing install) reinstalls the programs, removes retired ones (`lamaste-sign-csr`, `lamaste-pki-rename`), and replaces this file atomically after `visudo -c` accepts it, so upgrades pick up new rules.
282
282
 
283
283
  ## File Operation Safety
284
284
 
@@ -410,6 +410,64 @@ Optional Authelia protection is controlled by the `autheliaProtected` flag on th
410
410
 
411
411
  A custom-domain site may list `aliases` (e.g. `www.myblog.net`). They are served by a second server block that answers with a 301 to the primary host. One certificate lineage, named after the site's domain (`certbot certonly --nginx --cert-name <fqdn> -d <fqdn> -d <alias> ...`), covers the primary name and every alias, so both blocks point at the same `live/<fqdn>/` directory.
412
412
 
413
+ ### Web-surface vhosts
414
+
415
+ A site a plugin owns for its [web surface](../04-api-reference/agent-hosted-plugins.md#web-surface) has a vhost of its own kind under the site name (`lamalibre-lamaste-site-<id>`), rendered by the panel from the plugin's state (`renderWebSurfaceVhost`) — never by the static-site generator. While the surface is served:
416
+
417
+ ```nginx
418
+ server {
419
+ listen 443 ssl;
420
+ server_name piyasa.example.com;
421
+ ssl_certificate /etc/letsencrypt/live/piyasa.example.com/fullchain.pem;
422
+ ssl_certificate_key /etc/letsencrypt/live/piyasa.example.com/privkey.pem;
423
+
424
+ root /var/www/lamaste/apps/market-indicators/current;
425
+ index index.html;
426
+
427
+ # Every path of the shell: Gatekeeper first (the API's locations ask on their own)
428
+ auth_request /internal/lamaste/shell-authz;
429
+ error_page 401 =302 https://auth.example.com/?rd=https://piyasa.example.com$request_uri;
430
+ error_page 403 = /internal/lamaste/shell-authz;
431
+
432
+ location = /internal/lamaste/shell-authz {
433
+ internal;
434
+ auth_request off;
435
+ proxy_pass http://127.0.0.1:9294/authz/user-surface-shell/piyasa.example.com;
436
+ # ... as every Gatekeeper subrequest
437
+ }
438
+
439
+ # /internal/lamaste/user-surface-authz, -401 and the /api/market-indicators/app
440
+ # locations — exactly the user-surface locations of a bound tunnel
441
+
442
+ # A script, style, font or image the current tree lacks: the previous
443
+ # tree's (a page still running the old shell), else 404
444
+ location ~* [.](?:js|mjs|css|woff2?|ttf|otf|png|jpe?g|gif|webp|avif|ico)$ {
445
+ if ($request_method !~ ^(GET|HEAD)$) { return 405; }
446
+ if ($http_service_worker) { return 404; }
447
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
448
+ # X-Content-Type-Options, X-Frame-Options DENY, Referrer-Policy, COOP, CORP, Cache-Control no-cache
449
+ types { text/javascript js mjs; text/css css; ... } # core WEB_TREE_CONTENT_TYPES
450
+ try_files $uri @previous;
451
+ }
452
+
453
+ # Everything else: the current tree's file, else the shell
454
+ location / {
455
+ # the same method check, worker refusal, headers and types
456
+ try_files $uri /index.html;
457
+ }
458
+
459
+ location @previous {
460
+ # the same headers and types
461
+ root /var/www/lamaste/apps/market-indicators/previous;
462
+ try_files $uri =404;
463
+ }
464
+ }
465
+ ```
466
+
467
+ `auth_request` sits at server level so every location of the shell asks Gatekeeper — the API's locations name their own subrequest, and the internal ones turn it `off`. The API's prefix location is `^~`, so the subresource regex never takes an API path. The shell's headers are set in its locations only: the API's answers are the panel's to head. A document, an SVG or a manifest is never served from the previous tree, and a service worker's script (`Service-Worker: script`) is always `404` — a worker would outlive the tree that installed it. The `types` block names each extension's content type from core's list (`lamaste-priv` accepts a `types` block in a location — `media/type ext…` entries only, no `include`) rather than trust the host's `mime.types`, which differs between nginx versions. `current` and `previous` are links the panel switches with a rename (see [Serving the tree](../04-api-reference/agent-hosted-plugins.md#serving-the-tree)); nginx follows them per request. While the surface is not served, the vhost answers everything with `503` (`Cache-Control: no-store`, a worker's script `404`) — and, once the plugin is uninstalled, `Clear-Site-Data: "storage"`.
468
+
469
+ Moving a bound tunnel's host to a web surface hands the hostname over in **one reload**: the tunnel's vhost is unlinked, the site's written and linked, `nginx -t` run, nginx reloaded once; the tunnel's file stays installed, unlinked, so the tunnel can be enabled again once the site is deleted. On a failed test both are put back.
470
+
413
471
  ### 7. Public Tunnel Vhost (`lamalibre-lamaste-app-<name>`, access mode: public)
414
472
 
415
473
  Created when a tunnel is configured with public access. Direct proxy with no authentication.
@@ -642,7 +700,7 @@ An `authenticated` or `restricted` app tunnel bound as the user surface of agent
642
700
  # The user surface of plugin "market-indicators"
643
701
  location = /api/market-indicators/app { ... } # the same block as below
644
702
 
645
- location /api/market-indicators/app/ {
703
+ location ^~ /api/market-indicators/app/ {
646
704
  auth_request /internal/lamaste/user-surface-authz;
647
705
  auth_request_set $relay_assertion $upstream_http_x_lamalibre_relay_assertion;
648
706
 
@@ -852,12 +910,12 @@ nginx's master process runs as root and opens the files a configuration names
852
910
  - its **name** is one the panel manages: `lamalibre-lamaste-panel-domain`, `-auth`, `-tunnel`, `-app-<subdomain>`, `-agent-panel-<label>` or `-site-<uuid>`. `lamalibre-lamaste-panel-ip` (written by the installer) may only be enabled or disabled — which is how panel 2FA turns the IP vhost off;
853
911
  - every **directive** is on the allow-list for its context, with arguments that cannot name a file outside what Lamaste serves:
854
912
 
855
- | Context | Allowed |
856
- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
857
- | top level | `server`, `map` (plain `key value;` entries, no `include`), `limit_req_zone` |
858
- | `server` | `listen 443` / `[::]:443` with optional `ssl` / `http2`; `server_name` (hostnames); `ssl_certificate(_key)` only `/etc/letsencrypt/live/<name>/{fullchain,privkey}.pem`; `include` only `/etc/nginx/snippets/lamalibre-lamaste-*.conf`; `root` only under `/var/www/lamaste/`; `ssl_protocols`, `ssl_ciphers`, `ssl_prefer_server_ciphers`, `client_max_body_size`, `index`, `add_header`, `proxy_set_header`, `error_page`, `return`, `rewrite`, `location` |
859
- | `location` | `proxy_pass` only `http://127.0.0.1:<port>[/path]`; `root` / `alias` only under `/var/www/lamaste/`; `proxy_set_header`, `proxy_http_version`, `proxy_read_timeout`, `proxy_send_timeout`, `proxy_buffers`, `proxy_next_upstream`, `proxy_pass_request_body`, `auth_request`, `auth_request_set`, `limit_req`, `try_files`, `index`, `add_header`, `error_page`, `client_max_body_size`, `internal`, `return`, `rewrite`, `if`, nested `location` |
860
- | `if` | `return`, `rewrite` |
913
+ | Context | Allowed |
914
+ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
915
+ | top level | `server`, `map` (plain `key value;` entries, no `include`), `limit_req_zone` |
916
+ | `server` | `listen 443` / `[::]:443` with optional `ssl` / `http2`; `server_name` (hostnames); `ssl_certificate(_key)` only `/etc/letsencrypt/live/<name>/{fullchain,privkey}.pem`; `include` only `/etc/nginx/snippets/lamalibre-lamaste-*.conf`; `root` only under `/var/www/lamaste/`; `auth_request` only a URI of the server or `off`; `ssl_protocols`, `ssl_ciphers`, `ssl_prefer_server_ciphers`, `client_max_body_size`, `index`, `add_header`, `proxy_set_header`, `error_page`, `return`, `rewrite`, `location` (a path, or a named location `@name`) |
917
+ | `location` | `proxy_pass` only `http://127.0.0.1:<port>[/path]`; `root` / `alias` only under `/var/www/lamaste/`; `proxy_set_header`, `proxy_http_version`, `proxy_read_timeout`, `proxy_send_timeout`, `proxy_buffers`, `proxy_next_upstream`, `proxy_pass_request_body`, `auth_request`, `auth_request_set`, `limit_req`, `try_files` (the last argument may name a location, `@name`), `index`, `add_header`, `error_page`, `client_max_body_size`, `internal`, `return`, `rewrite`, `if`, nested `location` |
918
+ | `if` | `return`, `rewrite` |
861
919
 
862
920
  Port 80 is not allowed: it belongs to the installer's HTTPS redirect and to certbot's HTTP-01 challenges. Backslashes, `${`, control characters and non-ASCII text outside comments are refused rather than interpreted, as is any directive not listed — including ones nginx would accept (`access_log`, `log_format`, `ssl_*` files elsewhere, `proxy_pass` to another host, ...). A refused `write` fails with `nginx site write failed for <name>: lamaste-priv: vhost line <n>: ...` and leaves the previous vhost in place.
863
921
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  Lamaste has three main pieces:
8
8
 
9
- 1. **The Installer** (`npx @lamalibre/create-lamaste@4.5.0`) — a one-shot script you run once on a fresh VPS. It sets up nginx, generates security certificates, and deploys a web-based control panel. After it finishes, you never SSH into the server again.
9
+ 1. **The Installer** (`npx @lamalibre/create-lamaste@4.6.0`) — a one-shot script you run once on a fresh VPS. It sets up nginx, generates security certificates, and deploys a web-based control panel. After it finishes, you never SSH into the server again.
10
10
 
11
11
  2. **The Panel** (browser UI + backend API) — a management interface protected by a client certificate. Through it, you configure your domain, create tunnels, manage users, and monitor services.
12
12
 
@@ -318,7 +318,7 @@ lamaste/
318
318
  │ │ ├── files.js ← Static site file operations (upload, delete, list)
319
319
  │ │ └── app-error.js ← Operational error class (AppError)
320
320
  │ │
321
- │ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.5.0)
321
+ │ ├── lamaste-server-ui/ ← React 18 + Vite + Tailwind SPA + shared admin components (@lamalibre/lamaste-server-ui@4.6.0)
322
322
  │ │ └── src/
323
323
  │ │ ├── index.js ← Package exports (pages, context, utilities)
324
324
  │ │ ├── context/
@@ -334,7 +334,7 @@ lamaste/
334
334
  │ │ │ └── formatters.js ← Byte, uptime, relative time formatters
335
335
  │ │ └── pages/ ← Admin pages (Dashboard, Tunnels, Sites, Users, Certs, Services, Plugins, Tickets, Settings)
336
336
  │ │
337
- │ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.5.0)
337
+ │ ├── lamaste-agent-ui/ ← Shared React agent UI (pages, context, components) (@lamalibre/lamaste-agent-ui@4.6.0)
338
338
  │ │
339
339
  │ ├── lamaste-tickets/ ← Agent-to-agent authorization SDK (mTLS, undici)
340
340
  │ │ └── src/
@@ -374,7 +374,7 @@ lamaste/
374
374
  │ │ │ └── CompleteStep.jsx ← Credentials + TOTP QR + next steps
375
375
  │ │ ├── management/ ← Legacy standalone implementations (kept for reference)
376
376
  │ │ │ ├── Certificates.jsx ← Standalone certificates page (dead code)
377
- │ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.5.0)
377
+ │ │ │ ├── Dashboard.jsx ← Standalone dashboard (not imported — App.jsx uses @lamalibre/lamaste-server-ui@4.6.0)
378
378
  │ │ │ ├── Plugins.jsx ← Standalone plugins page (dead code)
379
379
  │ │ │ ├── Services.jsx ← Standalone services page (dead code)
380
380
  │ │ │ ├── Settings.jsx ← Standalone settings page (dead code)
@@ -483,7 +483,7 @@ The Panel Server runs as the `lamaste` user with minimal privileges and cannot b
483
483
  The full lifecycle of a Lamaste installation:
484
484
 
485
485
  ```
486
- Phase 1: Installation (npx @lamalibre/create-lamaste@4.5.0)
486
+ Phase 1: Installation (npx @lamalibre/create-lamaste@4.6.0)
487
487
  └─ OS hardening, Node.js, mTLS certs, nginx, panel deploy
488
488
  └─ Result: Panel accessible at https://<ip>:9292
489
489
 
@@ -10,9 +10,9 @@ The client has two modes. On first visit, it shows an onboarding wizard that wal
10
10
 
11
11
  ## Shared Panel Packages
12
12
 
13
- The management-mode admin pages (Dashboard, Tunnels, Sites, Users, Certificates, Services, Plugins, Tickets, Logs, Settings) live in `@lamalibre/lamaste-server-ui@4.5.0`. This package provides both the browser SPA build and the shared admin components consumed by `lamaste-desktop` (Tauri app).
13
+ The management-mode admin pages (Dashboard, Tunnels, Sites, Users, Certificates, Services, Plugins, Tickets, Logs, Settings) live in `@lamalibre/lamaste-server-ui@4.6.0`. This package provides both the browser SPA build and the shared admin components consumed by `lamaste-desktop` (Tauri app).
14
14
 
15
- The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are extracted into a separate shared package: `@lamalibre/lamaste-agent-ui@4.5.0`. This package is consumed by `lamaste-desktop` for agent mode.
15
+ The agent-mode pages (Dashboard, Tunnels, Services, Plugins, Logs, Settings) are extracted into a separate shared package: `@lamalibre/lamaste-agent-ui@4.6.0`. This package is consumed by `lamaste-desktop` for agent mode.
16
16
 
17
17
  The shared package exposes an `AdminClientContext` abstraction that decouples admin UI pages from their data transport. Each host provides its own client implementation:
18
18
 
@@ -118,7 +118,7 @@ The shell renders the appropriate step component and shows a progress indicator
118
118
 
119
119
  ### Management Mode
120
120
 
121
- React Router handles navigation within the `Layout` component (sidebar + content area). Management page components are imported from the shared `@lamalibre/lamaste-server-ui@4.5.0` package and wrapped with the `AdminClientProvider` (which supplies the web-specific data client):
121
+ React Router handles navigation within the `Layout` component (sidebar + content area). Management page components are imported from the shared `@lamalibre/lamaste-server-ui@4.6.0` package and wrapped with the `AdminClientProvider` (which supplies the web-specific data client):
122
122
 
123
123
  | Path | Component | Description |
124
124
  | ------------------------ | ------------------- | ------------------------------------------------------------------- |
@@ -350,9 +350,9 @@ The app root wraps all content in five providers:
350
350
  ```
351
351
 
352
352
  1. **QueryClientProvider** — react-query cache with global defaults (`retry: 1`, `refetchOnWindowFocus: false`)
353
- 2. **AdminClientProvider** — from `@lamalibre/lamaste-server-ui@4.5.0`, supplies the host-specific data client (`webAdminClient` for browser fetch, Tauri `invoke` for desktop)
354
- 3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.5.0`, notification toast system
355
- 4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.5.0`, handles 2FA verification prompts when the panel has 2FA enabled
353
+ 2. **AdminClientProvider** — from `@lamalibre/lamaste-server-ui@4.6.0`, supplies the host-specific data client (`webAdminClient` for browser fetch, Tauri `invoke` for desktop)
354
+ 3. **ToastProvider** — from `@lamalibre/lamaste-server-ui@4.6.0`, notification toast system
355
+ 4. **TwoFaProvider** — from `@lamalibre/lamaste-server-ui@4.6.0`, handles 2FA verification prompts when the panel has 2FA enabled
356
356
  5. **BrowserRouter** — React Router for client-side navigation
357
357
 
358
358
  ## Documentation Viewer
@@ -453,7 +453,7 @@ See [nginx-configuration.md](./nginx-configuration.md) for detailed coverage.
453
453
 
454
454
  ### chisel-users.js — Chisel Credentials and Grants
455
455
 
456
- - Thin shim over `@lamalibre/lamaste@4.5.0/server`: per-agent credentials in `chisel-credentials.json` (0600)
456
+ - Thin shim over `@lamalibre/lamaste@4.6.0/server`: per-agent credentials in `chisel-credentials.json` (0600)
457
457
  - Renders the authfile `chisel-users` from the credentials and `tunnels.json`: each `agent-<label>` may bind exactly `^R:127\.0\.0\.1:<port>$` for its enabled tunnels
458
458
  - Adds the `lamaste-no-grants` sentinel user (password in `chisel-sentinel`, 0600) so the authfile is never empty — Chisel disables authentication on an empty authfile
459
459
  - Never grants a reserved port (3100, 9090, 9091, 9292, 9294) or a port claimed by two tunnels
@@ -536,7 +536,7 @@ Agent-to-agent authorization with scopes, instances, tickets, and sessions. Prov
536
536
  - **Periodic cleanup** — stale/dead instances, expired tickets, dead sessions
537
537
  - **Concurrency** — promise-chain mutex with atomic file writes (temp → fsync → rename)
538
538
 
539
- Client SDK: `@lamalibre/lamaste-tickets@4.5.0` (TypeScript, undici) provides `TicketClient`, `TicketInstanceManager` (source side), and `TicketSessionManager` (target side) for plugin integration.
539
+ Client SDK: `@lamalibre/lamaste-tickets@4.6.0` (TypeScript, undici) provides `TicketClient`, `TicketInstanceManager` (source side), and `TicketSessionManager` (target side) for plugin integration.
540
540
 
541
541
  State files: `/etc/lamalibre/lamaste/ticket-scopes.json` (scopes, instances, assignments) and `/etc/lamalibre/lamaste/tickets.json` (tickets, sessions).
542
542
 
@@ -329,7 +329,7 @@ Read returns `[]` for missing files (ENOENT), enabling the system to start with
329
329
  5. `DELETE /api/certs/agent/:label` (revocation) — the agent's app and plugin tunnels lose their `agentLabel` (unassigned), and its `agent-<label>` panel tunnel is removed
330
330
  6. At startup (background, fail closed): an ownerless `agent-<label>` panel tunnel is bound to the agent it names when that agent is active; other ownerless tunnels (from versions before tunnel ownership) are bound to the sole active agent, or left unassigned when there are several. Then the pinned Chisel binary, the unit and the authfile are re-established — and Chisel is stopped if they cannot be
331
331
 
332
- Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.5.0/server`), with its validation inside the lock.
332
+ Every one of these workflows runs under the single tunnel lock (`withTunnelLock` in `@lamalibre/lamaste@4.6.0/server`), with its validation inside the lock.
333
333
 
334
334
  ## Site State (`sites.json`)
335
335
 
@@ -482,7 +482,7 @@ The PKI directory belongs to `lamaste` because the panel is the CA (it signs age
482
482
 
483
483
  The Panel Server is a single-process Node.js application, but a single-threaded event loop does not serialize asynchronous workflows: two requests that each read `tunnels.json`, await a certificate or an nginx test, and then write it back would interleave, and both could pass the same uniqueness check. Serialization is therefore explicit:
484
484
 
485
- **Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.5.0/server`'s `tunnels.ts`. Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH /api/tunnels/:id`, releasing a revoked agent's tunnels, and startup reconciliation — takes it for its whole duration, and does its validation (subdomain and port uniqueness, reserved ports, agent checks, authorization against the current entry) inside it.
485
+ **Tunnel state** is guarded by one promise-chain lock, `withTunnelLock` in `@lamalibre/lamaste@4.6.0/server`'s `tunnels.ts`. Every tunnel workflow — create, delete, toggle, assign, reconfigure, the combined `PATCH /api/tunnels/:id`, releasing a revoked agent's tunnels, and startup reconciliation — takes it for its whole duration, and does its validation (subdomain and port uniqueness, reserved ports, agent checks, authorization against the current entry) inside it.
486
486
 
487
487
  **Chisel authfile renders** are serialized by a promise-chain mutex in `chisel-users.ts`, keyed by the credentials file, around every render (enroll, revoke, rotate, tunnel change). The daemon's `syncChisel()` renders after the tunnel state is written and restarts Chisel (`systemctl try-restart`) only when the render withdrew something.
488
488
 
@@ -58,7 +58,7 @@
58
58
  │ │ │ │
59
59
  │ │ Lamaste Desktop (Tauri v2) — dual mode │ │
60
60
  │ │ ├─ Agent mode: service discovery + tunnel management │ │
61
- │ │ │ (pages from @lamalibre/lamaste-agent-ui@4.5.0) │ │
61
+ │ │ │ (pages from @lamalibre/lamaste-agent-ui@4.6.0) │ │
62
62
  │ │ ├─ Server mode: full admin panel (via lamaste-server-ui) │ │
63
63
  │ │ ├─ Multi-server registry (~/.lamalibre/lamaste/servers.json) │ │
64
64
  │ │ ├─ Cloud provisioning (DigitalOcean via lamaste-cloud) │ │