/** * Docker plugin handlers. * Gated by ENABLE_PLUGINS=1 (or true). */ import { docker } from '../services/docker.js' import * as validation from '../utils/validation.js' import logger from '../utils/logger.js' export function isPluginsEnabled() { return process.env.ENABLE_PLUGINS === '1' || process.env.ENABLE_PLUGINS === 'true' } function assertPlugins() { if (!isPluginsEnabled()) { const err = new Error('Plugin APIs disabled. Set ENABLE_PLUGINS=1 to enable.') err.code = 'FEATURE_DISABLED' throw err } } export function registerPluginHandlers(session) { session.respond('listPlugins', async () => { assertPlugins() const data = await docker.listPlugins() return { success: true, type: 'plugins', data } }) session.respond('inspectPlugin', async (args) => { assertPlugins() const data = await docker.getPlugin(args.name || args.id).inspect() return { success: true, type: 'plugin', data } }) session.respond('installPlugin', async (args) => { assertPlugins() const name = validation.sanitizeString(args.name || args.remote, 255) if (!name) throw new Error('Plugin name/remote required') const opts = {} if (args.alias) opts.name = validation.sanitizeString(args.alias, 128) // dockerode: docker.pullPlugin or getPlugin().enable after install let plugin if (typeof docker.pullPlugin === 'function') { plugin = await docker.pullPlugin(name, opts) } else { plugin = await new Promise((resolve, reject) => { docker.modem.dial( { path: `/plugins/pull?remote=${encodeURIComponent(name)}`, method: 'POST', statusCodes: { 200: true, 500: 'fatal' }, isStream: true, }, (err, stream) => { if (err) return reject(err) docker.modem.followProgress(stream, (e, res) => (e ? reject(e) : resolve(res || { name }))) } ) }) } return { success: true, message: `Plugin ${name} installed`, data: plugin } }) session.respond('enablePlugin', async (args) => { assertPlugins() const name = args.name || args.id const timeout = args.timeout != null ? Number(args.timeout) : undefined await docker.getPlugin(name).enable(timeout != null ? { timeout } : {}) return { success: true, message: `Plugin ${name} enabled` } }) session.respond('disablePlugin', async (args) => { assertPlugins() const name = args.name || args.id await docker.getPlugin(name).disable({ force: Boolean(args.force) }) return { success: true, message: `Plugin ${name} disabled` } }) session.respond('removePlugin', async (args) => { assertPlugins() const name = args.name || args.id await docker.getPlugin(name).remove({ force: Boolean(args.force) }) return { success: true, message: `Plugin ${name} removed` } }) session.respond('configurePlugin', async (args) => { assertPlugins() const name = args.name || args.id const config = args.config || args.Config || [] if (!Array.isArray(config)) throw new Error('config must be an array of KEY=VALUE strings') await docker.getPlugin(name).configure({ args: config }) return { success: true, message: `Plugin ${name} configured` } }) logger.debug('Plugin handlers registered', { enabled: isPluginsEnabled() }) }