Ask before running a script, which the page header has always said it did
Run was the only mutating control here that did not confirm, and it is the one that executes shell as root — the library holds cleaners that delete files, and six Run buttons sit a row apart in a dense tree.
This commit is contained in:
@@ -26,6 +26,10 @@
|
|||||||
//
|
//
|
||||||
// OPERATIONAL SAFEGUARDS
|
// OPERATIONAL SAFEGUARDS
|
||||||
// Running a script from the UI is confirmed first. Several of these delete files.
|
// Running a script from the UI is confirmed first. Several of these delete files.
|
||||||
|
// vvConfirmRun() guards all three entry points — the six Run buttons, the direct
|
||||||
|
// by-id run, and Git Pull. This line described intent rather than behaviour until
|
||||||
|
// 2026-08-07: Run was the only mutating control on the page that did not ask, while
|
||||||
|
// being the one that executes shell as root.
|
||||||
//
|
//
|
||||||
// Dry-run is offered alongside run for anything destructive, and its output is shown in
|
// Dry-run is offered alongside run for anything destructive, and its output is shown in
|
||||||
// full rather than summarised — reading the list is the point.
|
// full rather than summarised — reading the list is the point.
|
||||||
@@ -1508,12 +1512,27 @@ function vvSelectLog(btn) {
|
|||||||
vvOpenRight(job.dataset.id);
|
vvOpenRight(job.dataset.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a script by ID directly — no DOM card needed.
|
// Every other mutating control on this page already confirms — save, delete, move, conf save,
|
||||||
function vvRunById(id) {
|
// lock clear. Run did not, and it is the one that executes shell as root: the library holds
|
||||||
|
// cleaners that delete files and the git pull itself, and the six Run buttons sit one row apart
|
||||||
|
// in a dense tree where the row under the cursor is easy to misjudge. The page header has
|
||||||
|
// promised this confirmation since it was written; the code never did it.
|
||||||
|
//
|
||||||
|
// Dry Run is named in the prompt on purpose. For anything destructive it is the actual answer to
|
||||||
|
// "are you sure", and it is the button immediately beside the one that raised the question.
|
||||||
|
function vvConfirmRun(id) {
|
||||||
|
return confirm('Run ' + id + ' now?\n\n'
|
||||||
|
+ 'It starts immediately and as root, with the same effect as a scheduled run.\n'
|
||||||
|
+ 'Use Dry Run first if you want to see what it would change.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The confirm lives in the callers rather than here, so a caller that has already asked — or has
|
||||||
|
// button state to manage on cancel, as the pull does — is not forced to ask twice.
|
||||||
|
function vvRunStart(id, data) {
|
||||||
vvOpenRight(id);
|
vvOpenRight(id);
|
||||||
vvSetDot(id);
|
vvSetDot(id);
|
||||||
vvRunningSet.add(id);
|
vvRunningSet.add(id);
|
||||||
vvPost('/plugins/varaverk/api/run.php', {id, manual: '1'})
|
return vvPost('/plugins/varaverk/api/run.php', data)
|
||||||
.then(d => {
|
.then(d => {
|
||||||
if (!d.ok) {
|
if (!d.ok) {
|
||||||
document.getElementById('vv-log-pre').textContent = '✗ ' + (d.error ?? 'Failed to start');
|
document.getElementById('vv-log-pre').textContent = '✗ ' + (d.error ?? 'Failed to start');
|
||||||
@@ -1523,11 +1542,20 @@ function vvRunById(id) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run a script by ID directly — no DOM card needed.
|
||||||
|
function vvRunById(id) {
|
||||||
|
if (!vvConfirmRun(id)) return;
|
||||||
|
vvRunStart(id, {id, manual: '1'});
|
||||||
|
}
|
||||||
|
|
||||||
function vvGitPull(btn) {
|
function vvGitPull(btn) {
|
||||||
const id = 'git_pull_execute.sh';
|
const id = 'git_pull_execute.sh';
|
||||||
|
// Asked before the button is disabled, so cancelling does not leave it stuck reading "Pulling…"
|
||||||
|
// for the next four seconds while nothing is pulling.
|
||||||
|
if (!vvConfirmRun(id)) return;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.textContent = '⟳ Pulling…';
|
btn.textContent = '⟳ Pulling…';
|
||||||
vvRunById(id);
|
vvRunStart(id, {id, manual: '1'});
|
||||||
// Re-enable once the log poll confirms it's running or done
|
// Re-enable once the log poll confirms it's running or done
|
||||||
setTimeout(() => { btn.disabled = false; btn.textContent = '↻ Git Pull'; }, 4000);
|
setTimeout(() => { btn.disabled = false; btn.textContent = '↻ Git Pull'; }, 4000);
|
||||||
}
|
}
|
||||||
@@ -1535,22 +1563,13 @@ function vvGitPull(btn) {
|
|||||||
function vvRunJob(btn) {
|
function vvRunJob(btn) {
|
||||||
const job = btn.closest('[data-id]');
|
const job = btn.closest('[data-id]');
|
||||||
const id = job.dataset.id;
|
const id = job.dataset.id;
|
||||||
|
if (!vvConfirmRun(id)) return;
|
||||||
const location = job.querySelector('.vv-rsync-location')?.value.trim() || '';
|
const location = job.querySelector('.vv-rsync-location')?.value.trim() || '';
|
||||||
const extra_args = job.querySelector('.vv-script-args')?.value.trim() || '';
|
const extra_args = job.querySelector('.vv-script-args')?.value.trim() || '';
|
||||||
vvOpenRight(id);
|
|
||||||
vvSetDot(id);
|
|
||||||
vvRunningSet.add(id);
|
|
||||||
const data = {id};
|
const data = {id};
|
||||||
if (location) data.location = location;
|
if (location) data.location = location;
|
||||||
if (extra_args) data.extra_args = extra_args;
|
if (extra_args) data.extra_args = extra_args;
|
||||||
vvPost('/plugins/varaverk/api/run.php', data)
|
vvRunStart(id, data);
|
||||||
.then(d => {
|
|
||||||
if (!d.ok) {
|
|
||||||
document.getElementById('vv-log-pre').textContent = '✗ ' + (d.error ?? 'Failed to start');
|
|
||||||
vvClearDot(id);
|
|
||||||
vvRunningSet.delete(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function vvDryRun(btn) {
|
function vvDryRun(btn) {
|
||||||
|
|||||||
Reference in New Issue
Block a user