From eb3f430f9e8ee6ca10787fa3b9ec57808b2ed8bd Mon Sep 17 00:00:00 2001 From: Daniel Lockyer Date: Thu, 5 Oct 2023 11:50:49 +0200 Subject: [PATCH] fix(update): fixed permission issues when linking themes refs https://forum.ghost.org/t/permission-denied-when-updating-source-theme-linking/41651/5 - if we're in an environment that uses the `ghost` user, `ghost-mgr` doesn't have permissions to do these steps after we've already chown'd the folder - in that case, we should sudo to the `ghost` user to run these commands --- lib/commands/update.js | 22 ++++++++++++++++------ test/unit/commands/update-spec.js | 6 ++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/commands/update.js b/lib/commands/update.js index 96c4482fb..0b984e433 100644 --- a/lib/commands/update.js +++ b/lib/commands/update.js @@ -6,6 +6,7 @@ const symlinkSync = require('symlink-or-copy').sync; const {GhostError} = require('../errors'); const Command = require('../command'); const DoctorCommand = require('./doctor'); +const ghostUser = require('../utils/use-ghost-user'); class UpdateCommand extends Command { static configureOptions(commandName, yargs, extensions) { @@ -43,6 +44,7 @@ class UpdateCommand extends Command { instance, force, activeVersion: instance.version, + ui: this.ui, version, zip, v1 @@ -230,7 +232,7 @@ class UpdateCommand extends Command { instance.nodeVersion = process.versions.node; } - linkDefaultThemes({instance, rollback}) { + async linkDefaultThemes({instance, rollback, ui}) { const currentThemesDir = path.join(process.cwd(), 'current', 'content', 'themes'); const contentThemesDir = path.join(instance.config.get('paths.contentPath'), 'themes'); // remove any broken symlinks caused by default themes no longer existing in previous version @@ -239,7 +241,11 @@ class UpdateCommand extends Command { const installedThemes = fs.readdirSync(contentThemesDir); for (const theme of installedThemes) { if (!fs.existsSync(path.join(contentThemesDir, theme))) { - fs.rmSync(path.join(contentThemesDir, theme)); + if (ghostUser.shouldUseGhostUser(contentThemesDir)) { + await ui.sudo(`rm ${path.join(contentThemesDir, theme)}`, {sudoArgs: '-E -u ghost'}); + } else { + fs.unlinkSync(path.join(contentThemesDir, theme)); + } } } } @@ -250,10 +256,14 @@ class UpdateCommand extends Command { const defaultThemes = fs.readdirSync(currentThemesDir); for (const theme of defaultThemes) { if (!fs.existsSync(path.join(contentThemesDir, theme))) { - symlinkSync( - path.join(currentThemesDir, theme), - path.join(contentThemesDir, theme) - ); + if (ghostUser.shouldUseGhostUser(contentThemesDir)) { + await ui.sudo(`ln -s ${path.join(currentThemesDir, theme)} ${path.join(contentThemesDir, theme)}`, {sudoArgs: '-E -u ghost'}); + } else { + symlinkSync( + path.join(currentThemesDir, theme), + path.join(contentThemesDir, theme) + ); + } } } } diff --git a/test/unit/commands/update-spec.js b/test/unit/commands/update-spec.js index b0d70926b..3f22bf06e 100644 --- a/test/unit/commands/update-spec.js +++ b/test/unit/commands/update-spec.js @@ -240,6 +240,7 @@ describe('Unit: Commands > Update', function () { force: false, instance: fakeInstance, activeVersion: '2.0.0', + ui, zip: '', v1: false }); @@ -314,6 +315,7 @@ describe('Unit: Commands > Update', function () { version: '2.0.0', force: false, instance: fakeInstance, + ui, activeVersion: '1.25.0', zip: '', v1: false @@ -357,6 +359,7 @@ describe('Unit: Commands > Update', function () { force: false, instance: fakeInstance, activeVersion: '1.0.0', + ui: ui, zip: '', v1: false }); @@ -424,6 +427,7 @@ describe('Unit: Commands > Update', function () { instance: fakeInstance, activeVersion: '1.1.0', installPath: '/var/www/ghost/versions/1.0.0', + ui: ui, rollback: true, zip: '', v1: false @@ -546,6 +550,7 @@ describe('Unit: Commands > Update', function () { instance: fakeInstance, activeVersion: '1.1.0', installPath: '/var/www/ghost/versions/1.0.0', + ui, rollback: true, zip: '', v1: true @@ -613,6 +618,7 @@ describe('Unit: Commands > Update', function () { instance: fakeInstance, activeVersion: '1.1.0', installPath: '/var/www/ghost/versions/1.0.0', + ui, rollback: true, zip: '', v1: false