@lamalibre/create-lamaste 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/scripts/bundle-vendor.js +13 -8
- package/scripts/lamaste-priv +205 -2
- package/src/index.js +8 -4
- package/src/lib/node-version.js +114 -0
- package/src/lib/panel-pin.js +41 -0
- package/src/lib/relay-services.js +15 -1
- package/src/lib/service-config.js +113 -0
- package/src/tasks/gatekeeper.js +8 -3
- package/src/tasks/node.js +34 -75
- package/src/tasks/redeploy.js +36 -0
- package/vendor/docs/00-introduction/how-it-works.md +2 -2
- package/vendor/docs/00-introduction/quickstart.md +5 -5
- package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
- package/vendor/docs/01-concepts/authentication.md +6 -3
- package/vendor/docs/01-concepts/authorization.md +29 -17
- package/vendor/docs/01-concepts/certificates.md +3 -3
- package/vendor/docs/01-concepts/mtls.md +2 -2
- package/vendor/docs/01-concepts/nginx-reverse-proxy.md +8 -3
- package/vendor/docs/01-concepts/security-model.md +110 -35
- package/vendor/docs/01-concepts/tickets.md +2 -2
- package/vendor/docs/01-concepts/tunneling.md +4 -4
- package/vendor/docs/02-guides/agent-setup.md +34 -16
- package/vendor/docs/02-guides/certificate-management.md +2 -2
- package/vendor/docs/02-guides/cloud-provisioning.md +4 -4
- package/vendor/docs/02-guides/desktop-app-setup.md +11 -10
- package/vendor/docs/02-guides/installation.md +3 -3
- package/vendor/docs/02-guides/onboarding.md +2 -2
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
- package/vendor/docs/03-architecture/installer-flow.md +2 -2
- package/vendor/docs/03-architecture/installer.md +4 -4
- package/vendor/docs/03-architecture/management-flow.md +1 -1
- package/vendor/docs/03-architecture/nginx-configuration.md +91 -26
- package/vendor/docs/03-architecture/overview.md +8 -8
- package/vendor/docs/03-architecture/panel-client.md +6 -6
- package/vendor/docs/03-architecture/panel-server.md +2 -2
- package/vendor/docs/03-architecture/state-management.md +2 -2
- package/vendor/docs/03-architecture/system-overview.md +1 -1
- package/vendor/docs/04-api-reference/agent-hosted-plugins.md +407 -0
- package/vendor/docs/04-api-reference/app-host.md +360 -0
- package/vendor/docs/04-api-reference/audit-and-notifications.md +57 -0
- package/vendor/docs/04-api-reference/certificates.md +95 -38
- package/vendor/docs/04-api-reference/gatekeeper.md +5 -3
- package/vendor/docs/04-api-reference/lifecycle-hooks.md +333 -0
- package/vendor/docs/04-api-reference/onboarding.md +1 -1
- package/vendor/docs/04-api-reference/overview.md +137 -111
- package/vendor/docs/04-api-reference/registry-and-oidc.md +8 -4
- package/vendor/docs/04-api-reference/tunnels.md +15 -13
- package/vendor/docs/05-operations/backup-and-restore.md +3 -1
- package/vendor/docs/05-operations/uninstalling.md +1 -1
- package/vendor/docs/05-operations/upgrades.md +25 -20
- package/vendor/docs/06-reference/config-files.md +195 -97
- package/vendor/docs/06-reference/glossary.md +3 -3
- package/vendor/docs/06-reference/installer-flags.md +13 -13
- package/vendor/docs/06-reference/ports-and-services.md +1 -1
- package/vendor/docs/06-reference/troubleshooting.md +33 -8
- package/vendor/docs/_index.json +20 -0
- package/vendor/docs/gatekeeper-design.md +22 -19
- package/vendor/docs/identity-directory-design.md +57 -56
- package/vendor/docs/package.json +1 -1
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
- package/vendor/gatekeeper/dist/cli/index.js +0 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts +12 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/index.d.ts +2 -0
- package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/index.js +47 -8
- package/vendor/gatekeeper/dist/server/index.js.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.js +233 -141
- package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -1
- package/vendor/gatekeeper/package.json +4 -3
- package/vendor/server/bin/lamaste-server.js +25 -1
- package/vendor/server/package.json +2 -2
- package/vendor/server/src/commands/audit.js +60 -0
- package/vendor/server/src/commands/panel-pin.js +40 -0
- package/vendor/server/src/commands/plugins.js +963 -12
- package/vendor/server/src/commands/push-install.js +317 -0
- package/vendor/server/src/commands/registry-credential.js +2 -1
- package/vendor/server/src/commands/uninstall.js +28 -1
- package/vendor/server/src/ndjson.js +4 -2
- package/vendor/server/src/panel-api.js +277 -34
- package/vendor/server/src/panel-identity.js +165 -0
- package/vendor/server-ui/dist/assets/index-BTlBt_cD.js +84 -0
- package/vendor/server-ui/dist/assets/index-Bc5NCMSv.css +1 -0
- package/vendor/server-ui/dist/index.html +2 -2
- package/vendor/serverd/package.json +2 -2
- package/vendor/serverd/src/index.js +56 -4
- package/vendor/serverd/src/lib/actor.js +24 -0
- package/vendor/serverd/src/lib/agent-jobs.js +330 -0
- package/vendor/serverd/src/lib/app-error.js +10 -0
- package/vendor/serverd/src/lib/audit.js +145 -0
- package/vendor/serverd/src/lib/hook-effects.js +123 -0
- package/vendor/serverd/src/lib/hook-pipelines.js +902 -0
- package/vendor/serverd/src/lib/migrations/state/0006_plugin_agent.sql +4 -0
- package/vendor/serverd/src/lib/migrations/state/0007_audit_and_notifications.sql +29 -0
- package/vendor/serverd/src/lib/migrations/state/0008_plugin_hooks.sql +70 -0
- package/vendor/serverd/src/lib/migrations/state/0009_plugin_agent_half.sql +53 -0
- package/vendor/serverd/src/lib/migrations/state/0010_plugin_routes_and_retained_data.sql +47 -0
- package/vendor/serverd/src/lib/migrations/state/0011_agent_job_signature.sql +14 -0
- package/vendor/serverd/src/lib/mtls.js +89 -8
- package/vendor/serverd/src/lib/nginx.js +298 -44
- package/vendor/serverd/src/lib/notifications.js +107 -0
- package/vendor/serverd/src/lib/plugin-hooks.js +560 -0
- package/vendor/serverd/src/lib/plugin-hosting.js +688 -0
- package/vendor/serverd/src/lib/plugin-lifecycle.js +603 -0
- package/vendor/serverd/src/lib/plugin-operations.js +295 -0
- package/vendor/serverd/src/lib/plugin-packages.js +249 -0
- package/vendor/serverd/src/lib/plugins.js +298 -68
- package/vendor/serverd/src/lib/push-install.js +88 -2
- package/vendor/serverd/src/lib/relay-hooks.js +100 -0
- package/vendor/serverd/src/lib/relay-signing.js +43 -0
- package/vendor/serverd/src/lib/request-hooks.js +79 -0
- package/vendor/serverd/src/lib/retained-data.js +99 -0
- package/vendor/serverd/src/lib/trust-proxy.js +34 -0
- package/vendor/serverd/src/lib/tunnel-hooks.js +88 -0
- package/vendor/serverd/src/lib/vhost-reconcile.js +260 -0
- package/vendor/serverd/src/middleware/twofa-session.js +11 -1
- package/vendor/serverd/src/routes/agent-forwarder.js +37 -0
- package/vendor/serverd/src/routes/management/agent-panel-authz.js +97 -0
- package/vendor/serverd/src/routes/management/agents.js +262 -1
- package/vendor/serverd/src/routes/management/audit.js +81 -0
- package/vendor/serverd/src/routes/management/certs.js +1 -15
- package/vendor/serverd/src/routes/management/plugins.js +569 -54
- package/vendor/serverd/src/routes/management/tunnels.js +26 -0
- package/vendor/serverd/src/routes/management.js +4 -0
- package/vendor/server-ui/dist/assets/index-B5Wp8lu-.js +0 -257
- package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +0 -1
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lamaste-server push-install — Push install: what lets the panel install,
|
|
3
|
+
* update and remove what Lamaste installs on an agent (the agent half of an
|
|
4
|
+
* app plugin) while that agent's window is open, within its policy.
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* status The switch, the default policy, the policies, every
|
|
8
|
+
* machine agent's window (the default subcommand)
|
|
9
|
+
* on | off Turn push install on or off for this relay
|
|
10
|
+
* default-policy <id> The policy a window gets when none is named
|
|
11
|
+
* open <agent> [--minutes <n>] [--policy <id>]
|
|
12
|
+
* Open an agent's window for n minutes (default 30,
|
|
13
|
+
* within the bounds the panel reports)
|
|
14
|
+
* close <agent> Close an agent's window
|
|
15
|
+
*
|
|
16
|
+
* Every subcommand goes through the running panel (`/api/plugins/push-install/*`
|
|
17
|
+
* and `/api/certs/agent`, admin certificate). The panel checks a push's
|
|
18
|
+
* source address against the agent's policy: pushes this CLI starts come
|
|
19
|
+
* from 127.0.0.1.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import { panelRequest } from '../panel-api.js';
|
|
24
|
+
import { emit, emitComplete, emitError } from '../ndjson.js';
|
|
25
|
+
|
|
26
|
+
/** How long a window opens for when `--minutes` is not given. */
|
|
27
|
+
export const DEFAULT_WINDOW_MINUTES = 30;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The arguments of `open <agent> [--minutes <n>] [--policy <id>]`, checked
|
|
31
|
+
* against the window bounds the panel reports. Pure, exported for tests.
|
|
32
|
+
*
|
|
33
|
+
* @param {string[]} args what follows `open`
|
|
34
|
+
* @param {{ min: number, max: number }} bounds
|
|
35
|
+
* @returns {{ ok: true, label: string, minutes: number, policyId: string | null } | { ok: false, error: string }}
|
|
36
|
+
*/
|
|
37
|
+
export function parseOpenArgs(args, bounds) {
|
|
38
|
+
const usage = 'Usage: lamaste-server push-install open <agent> [--minutes <n>] [--policy <id>]';
|
|
39
|
+
let label = null;
|
|
40
|
+
let minutesText = null;
|
|
41
|
+
let policyId = null;
|
|
42
|
+
for (let i = 0; i < args.length; i++) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
if (arg === '--minutes' || arg === '--policy') {
|
|
45
|
+
const value = args[i + 1];
|
|
46
|
+
if (value === undefined || value.startsWith('--')) {
|
|
47
|
+
return { ok: false, error: `${arg} needs a value — ${usage}` };
|
|
48
|
+
}
|
|
49
|
+
if (arg === '--minutes') minutesText = value;
|
|
50
|
+
else policyId = value;
|
|
51
|
+
i++;
|
|
52
|
+
} else if (arg.startsWith('--')) {
|
|
53
|
+
return { ok: false, error: `Unknown option ${arg} — ${usage}` };
|
|
54
|
+
} else if (label === null) {
|
|
55
|
+
label = arg;
|
|
56
|
+
} else {
|
|
57
|
+
return { ok: false, error: `Unexpected argument "${arg}" — ${usage}` };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (label === null) return { ok: false, error: usage };
|
|
61
|
+
const minutes = minutesText === null ? DEFAULT_WINDOW_MINUTES : Number(minutesText);
|
|
62
|
+
if (
|
|
63
|
+
(minutesText !== null && !/^\d+$/.test(minutesText)) ||
|
|
64
|
+
minutes < bounds.min ||
|
|
65
|
+
minutes > bounds.max
|
|
66
|
+
) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
error: `A push-install window is open ${bounds.min} to ${bounds.max} minutes (whole minutes)`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return { ok: true, label, minutes, policyId };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Each machine agent's push-install window, as `status` lists it: open
|
|
77
|
+
* until a time under a policy, or closed. Revoked agents and plugin-agent
|
|
78
|
+
* certificates have none. Pure, exported for tests.
|
|
79
|
+
*
|
|
80
|
+
* @param {Array<Record<string, unknown>>} agents GET /api/certs/agent
|
|
81
|
+
* @param {number} now
|
|
82
|
+
*/
|
|
83
|
+
export function agentWindows(agents, now) {
|
|
84
|
+
return agents
|
|
85
|
+
.filter(
|
|
86
|
+
(a) => !a.revoked && typeof a.label === 'string' && !a.label.startsWith('plugin-agent:'),
|
|
87
|
+
)
|
|
88
|
+
.map((a) => {
|
|
89
|
+
const until =
|
|
90
|
+
typeof a.pushInstallEnabledUntil === 'string' ? a.pushInstallEnabledUntil : null;
|
|
91
|
+
const open = until !== null && Date.parse(until) > now;
|
|
92
|
+
return {
|
|
93
|
+
label: a.label,
|
|
94
|
+
open,
|
|
95
|
+
until: open ? until : null,
|
|
96
|
+
policy: open ? (a.pushInstallPolicy ?? null) : null,
|
|
97
|
+
};
|
|
98
|
+
})
|
|
99
|
+
.sort((a, b) => a.label.localeCompare(b.label));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {string[]} args Subcommand args: [] | ['status'] | ['on'] | ['open', '<agent>', …] | …
|
|
104
|
+
* @param {{ json: boolean }} options
|
|
105
|
+
*/
|
|
106
|
+
export async function runPushInstall(args, { json }) {
|
|
107
|
+
const sub = args[0] ?? 'status';
|
|
108
|
+
switch (sub) {
|
|
109
|
+
case 'status':
|
|
110
|
+
return statusCmd({ json });
|
|
111
|
+
case 'on':
|
|
112
|
+
case 'off':
|
|
113
|
+
return switchCmd(sub === 'on', { json });
|
|
114
|
+
case 'default-policy':
|
|
115
|
+
return defaultPolicyCmd(args[1], { json });
|
|
116
|
+
case 'open':
|
|
117
|
+
return openCmd(args.slice(1), { json });
|
|
118
|
+
case 'close':
|
|
119
|
+
return closeCmd(args[1], { json });
|
|
120
|
+
default:
|
|
121
|
+
printUsage();
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function printUsage() {
|
|
127
|
+
const b = chalk.bold;
|
|
128
|
+
const c = chalk.cyan;
|
|
129
|
+
console.log(`
|
|
130
|
+
${b('Usage:')} lamaste-server push-install <subcommand>
|
|
131
|
+
|
|
132
|
+
${b('Subcommands:')}
|
|
133
|
+
${c('status')} The switch, default policy, policies and every agent's window
|
|
134
|
+
${c('on')} | ${c('off')} Turn push install on or off for this relay
|
|
135
|
+
${c('default-policy <id>')} The policy a window gets when none is named
|
|
136
|
+
${c('open <agent> [--minutes <n>] [--policy <id>]')}
|
|
137
|
+
Open an agent's window (default ${DEFAULT_WINDOW_MINUTES} minutes)
|
|
138
|
+
${c('close <agent>')} Close an agent's window
|
|
139
|
+
`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Exit with a usage or panel error, as text or NDJSON.
|
|
144
|
+
*
|
|
145
|
+
* @param {string} message
|
|
146
|
+
* @param {boolean} json
|
|
147
|
+
* @returns {never}
|
|
148
|
+
*/
|
|
149
|
+
function fail(message, json) {
|
|
150
|
+
if (json) emitError(message);
|
|
151
|
+
else console.error(`\n ${chalk.red(message)}\n`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The panel's push-install config, or exit with its error. */
|
|
156
|
+
async function readConfig(json) {
|
|
157
|
+
try {
|
|
158
|
+
return await panelRequest('GET', '/api/plugins/push-install/config');
|
|
159
|
+
} catch (err) {
|
|
160
|
+
fail(err.message, json);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @param {{ json: boolean }} options
|
|
166
|
+
*/
|
|
167
|
+
async function statusCmd({ json }) {
|
|
168
|
+
const config = await readConfig(json);
|
|
169
|
+
let agents;
|
|
170
|
+
try {
|
|
171
|
+
({ agents = [] } = await panelRequest('GET', '/api/certs/agent'));
|
|
172
|
+
} catch (err) {
|
|
173
|
+
fail(err.message, json);
|
|
174
|
+
}
|
|
175
|
+
const windows = agentWindows(agents, Date.now());
|
|
176
|
+
if (json) {
|
|
177
|
+
emit({
|
|
178
|
+
enabled: config.enabled,
|
|
179
|
+
defaultPolicy: config.defaultPolicy,
|
|
180
|
+
windowMinutes: config.windowMinutes,
|
|
181
|
+
policies: config.policies,
|
|
182
|
+
agents: windows,
|
|
183
|
+
});
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const b = chalk.bold;
|
|
188
|
+
const c = chalk.cyan;
|
|
189
|
+
const d = chalk.dim;
|
|
190
|
+
console.log('');
|
|
191
|
+
console.log(b(' Push install'));
|
|
192
|
+
console.log(d(' ' + '─'.repeat(40)));
|
|
193
|
+
console.log(
|
|
194
|
+
` switch: ${config.enabled ? chalk.green('on') : chalk.red('off')}${config.enabled ? '' : d(' — every push is refused')}`,
|
|
195
|
+
);
|
|
196
|
+
console.log(` default policy: ${c(config.defaultPolicy)}`);
|
|
197
|
+
console.log(
|
|
198
|
+
` window: ${config.windowMinutes.min} to ${config.windowMinutes.max} minutes`,
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
console.log(b('\n Policies'));
|
|
202
|
+
for (const p of config.policies) {
|
|
203
|
+
const all = d('(any)');
|
|
204
|
+
console.log(` ${c(p.id)} ${p.name}${p.id === config.defaultPolicy ? d(' (default)') : ''}`);
|
|
205
|
+
console.log(` actions: ${p.allowedActions?.length ? p.allowedActions.join(', ') : all}`);
|
|
206
|
+
console.log(` packages: ${p.allowedPlugins?.length ? p.allowedPlugins.join(', ') : all}`);
|
|
207
|
+
console.log(` from: ${p.allowedIps?.length ? p.allowedIps.join(', ') : all}`);
|
|
208
|
+
if (p.deniedIps?.length) console.log(` not from: ${p.deniedIps.join(', ')}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(b('\n Agent windows'));
|
|
212
|
+
if (windows.length === 0) console.log(d(' No enrolled machine agent.'));
|
|
213
|
+
const width = Math.max(5, ...windows.map((w) => w.label.length));
|
|
214
|
+
for (const w of windows) {
|
|
215
|
+
console.log(
|
|
216
|
+
` ${c(w.label.padEnd(width))} ${w.open ? chalk.green(`open until ${w.until}`) + d(` (policy ${w.policy})`) : d('closed')}`,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
console.log('');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @param {boolean} enabled
|
|
224
|
+
* @param {{ json: boolean }} options
|
|
225
|
+
*/
|
|
226
|
+
async function switchCmd(enabled, { json }) {
|
|
227
|
+
let config;
|
|
228
|
+
try {
|
|
229
|
+
config = await panelRequest('PATCH', '/api/plugins/push-install/config', { enabled });
|
|
230
|
+
} catch (err) {
|
|
231
|
+
fail(err.message, json);
|
|
232
|
+
}
|
|
233
|
+
if (json) {
|
|
234
|
+
emitComplete({ enabled: config.enabled });
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
console.log(
|
|
238
|
+
`\n Push install is ${config.enabled ? chalk.green('on') : chalk.red('off')}${
|
|
239
|
+
config.enabled
|
|
240
|
+
? ` — open an agent's window with ${chalk.cyan('lamaste-server push-install open <agent>')}`
|
|
241
|
+
: ': every push is refused (open windows stay recorded but let nothing through)'
|
|
242
|
+
}.\n`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* @param {string | undefined} policyId
|
|
248
|
+
* @param {{ json: boolean }} options
|
|
249
|
+
*/
|
|
250
|
+
async function defaultPolicyCmd(policyId, { json }) {
|
|
251
|
+
if (!policyId) fail('Usage: lamaste-server push-install default-policy <id>', json);
|
|
252
|
+
let config;
|
|
253
|
+
try {
|
|
254
|
+
config = await panelRequest('PATCH', '/api/plugins/push-install/config', {
|
|
255
|
+
defaultPolicy: policyId,
|
|
256
|
+
});
|
|
257
|
+
} catch (err) {
|
|
258
|
+
fail(err.message, json);
|
|
259
|
+
}
|
|
260
|
+
if (json) emitComplete({ defaultPolicy: config.defaultPolicy });
|
|
261
|
+
else console.log(`\n Default push-install policy: ${chalk.cyan(config.defaultPolicy)}\n`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @param {string[]} args
|
|
266
|
+
* @param {{ json: boolean }} options
|
|
267
|
+
*/
|
|
268
|
+
async function openCmd(args, { json }) {
|
|
269
|
+
const config = await readConfig(json);
|
|
270
|
+
const parsed = parseOpenArgs(args, config.windowMinutes);
|
|
271
|
+
if (!parsed.ok) fail(parsed.error, json);
|
|
272
|
+
if (!config.enabled) {
|
|
273
|
+
fail(
|
|
274
|
+
'Push install is off for this relay — turn it on first: lamaste-server push-install on',
|
|
275
|
+
json,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
let result;
|
|
279
|
+
try {
|
|
280
|
+
result = await panelRequest(
|
|
281
|
+
'POST',
|
|
282
|
+
`/api/plugins/push-install/enable/${encodeURIComponent(parsed.label)}`,
|
|
283
|
+
{
|
|
284
|
+
durationMinutes: parsed.minutes,
|
|
285
|
+
...(parsed.policyId ? { policyId: parsed.policyId } : {}),
|
|
286
|
+
},
|
|
287
|
+
);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
fail(err.message, json);
|
|
290
|
+
}
|
|
291
|
+
if (json) {
|
|
292
|
+
emitComplete({
|
|
293
|
+
label: result.label,
|
|
294
|
+
pushInstallEnabledUntil: result.pushInstallEnabledUntil,
|
|
295
|
+
pushInstallPolicy: result.pushInstallPolicy,
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
console.log(
|
|
300
|
+
`\n Push install open for ${chalk.cyan(result.label)} until ${result.pushInstallEnabledUntil} (policy ${chalk.cyan(result.pushInstallPolicy)}).\n`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* @param {string | undefined} label
|
|
306
|
+
* @param {{ json: boolean }} options
|
|
307
|
+
*/
|
|
308
|
+
async function closeCmd(label, { json }) {
|
|
309
|
+
if (!label) fail('Usage: lamaste-server push-install close <agent>', json);
|
|
310
|
+
try {
|
|
311
|
+
await panelRequest('DELETE', `/api/plugins/push-install/enable/${encodeURIComponent(label)}`);
|
|
312
|
+
} catch (err) {
|
|
313
|
+
fail(err.message, json);
|
|
314
|
+
}
|
|
315
|
+
if (json) emitComplete({ label, closed: true });
|
|
316
|
+
else console.log(`\n Push install closed for ${chalk.cyan(label)}.\n`);
|
|
317
|
+
}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* registry-credential set --url <registry> --oidc
|
|
8
8
|
* The panel authenticates as its own `lamaste-server` OIDC client on
|
|
9
9
|
* the relay's Authelia (client-credentials grant, Feria login). Nothing
|
|
10
|
-
* to paste; Feria's auth.json must
|
|
10
|
+
* to paste; Feria's auth.json must grant the relay's lamaste-server client
|
|
11
|
+
* through a "workloads" rule on its groups issuer for the relay Authelia.
|
|
11
12
|
* registry-credential set --url <registry> [--token-stdin]
|
|
12
13
|
* A long-lived Feria token, read from LAMASTE_REGISTRY_TOKEN or from
|
|
13
14
|
* stdin with --token-stdin. Never accepted as a command-line argument.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Requires root access. Interactive confirmation unless --force is passed.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { readFile } from 'node:fs/promises';
|
|
19
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
20
20
|
import { createInterface } from 'node:readline';
|
|
21
21
|
import chalk from 'chalk';
|
|
22
22
|
import { execa } from 'execa';
|
|
@@ -117,7 +117,32 @@ export async function runUninstall(args, { json }) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/** Relay hook runner instances (`lamalibre-lamaste-hooks@<route>`), one per plugin with relay hooks. */
|
|
121
|
+
const HOOKS_UNIT_PREFIX = 'lamalibre-lamaste-hooks';
|
|
122
|
+
|
|
123
|
+
async function stopHookRunners() {
|
|
124
|
+
let enabled = [];
|
|
125
|
+
try {
|
|
126
|
+
enabled = (await readdir('/etc/systemd/system/sockets.target.wants')).filter((name) =>
|
|
127
|
+
/^lamalibre-lamaste-hooks@[a-z0-9-]+\.socket$/.test(name),
|
|
128
|
+
);
|
|
129
|
+
} catch {
|
|
130
|
+
// No socket units enabled
|
|
131
|
+
}
|
|
132
|
+
for (const socket of enabled) {
|
|
133
|
+
await execa('systemctl', ['disable', '--now', socket], { timeout: 15000 }).catch(() => {});
|
|
134
|
+
}
|
|
135
|
+
await execa(
|
|
136
|
+
'systemctl',
|
|
137
|
+
['stop', `${HOOKS_UNIT_PREFIX}@*.service`, `${HOOKS_UNIT_PREFIX}@*.socket`],
|
|
138
|
+
{
|
|
139
|
+
timeout: 15000,
|
|
140
|
+
},
|
|
141
|
+
).catch(() => {});
|
|
142
|
+
}
|
|
143
|
+
|
|
120
144
|
async function stopServices() {
|
|
145
|
+
await stopHookRunners();
|
|
121
146
|
for (const service of [PANEL_SERVICE, GATEKEEPER_SERVICE, 'chisel']) {
|
|
122
147
|
try {
|
|
123
148
|
await execa('systemctl', ['stop', service], { timeout: 15000 });
|
|
@@ -138,6 +163,8 @@ async function removeServices() {
|
|
|
138
163
|
`/etc/systemd/system/${GATEKEEPER_SERVICE}.service`,
|
|
139
164
|
'/etc/systemd/system/chisel.service',
|
|
140
165
|
'/etc/systemd/system/authelia.service',
|
|
166
|
+
`/etc/systemd/system/${HOOKS_UNIT_PREFIX}@.socket`,
|
|
167
|
+
`/etc/systemd/system/${HOOKS_UNIT_PREFIX}@.service`,
|
|
141
168
|
];
|
|
142
169
|
|
|
143
170
|
for (const file of serviceFiles) {
|
|
@@ -31,9 +31,11 @@ export function emitStep(step, status, detail) {
|
|
|
31
31
|
* Emit an error event.
|
|
32
32
|
* @param {string} message
|
|
33
33
|
* @param {boolean} [recoverable]
|
|
34
|
+
* @param {Record<string, unknown>} [details] what a consumer acts on beyond
|
|
35
|
+
* the message — a refused plugin operation's `code` and `reasons`
|
|
34
36
|
*/
|
|
35
|
-
export function emitError(message, recoverable = false) {
|
|
36
|
-
emit({ event: 'error', message, recoverable });
|
|
37
|
+
export function emitError(message, recoverable = false, details = {}) {
|
|
38
|
+
emit({ event: 'error', message, recoverable, ...details });
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/**
|