mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-29 17:07:19 +02:00
Safety Valve
- Added safety valve processing. Whenever a write-command omits a filter, the command will affect every task. This is dangerous. If rc.confirmation is disabled, the command is terminated.
This commit is contained in:
parent
f74c33dc02
commit
fa973f734b
4 changed files with 66 additions and 25 deletions
|
@ -32,6 +32,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <E9.h>
|
#include <E9.h>
|
||||||
#include <text.h>
|
#include <text.h>
|
||||||
|
#include <util.h>
|
||||||
#include <i18n.h>
|
#include <i18n.h>
|
||||||
#include <Command.h>
|
#include <Command.h>
|
||||||
#include <cmake.h>
|
#include <cmake.h>
|
||||||
|
@ -326,6 +327,8 @@ void Command::filter (std::vector <Task>& output)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
safety ();
|
||||||
|
|
||||||
context.timer_filter.stop ();
|
context.timer_filter.stop ();
|
||||||
const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
|
const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
|
||||||
const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
|
const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
|
||||||
|
@ -406,8 +409,11 @@ void Command::modify_task (
|
||||||
const A3& arguments,
|
const A3& arguments,
|
||||||
std::string& description)
|
std::string& description)
|
||||||
{
|
{
|
||||||
|
// Coalesce arguments together into sets to be processed as a batch.
|
||||||
|
A3 grouped_arguments = group_arguments (arguments);
|
||||||
|
|
||||||
std::vector <Arg>::const_iterator arg;
|
std::vector <Arg>::const_iterator arg;
|
||||||
for (arg = arguments.begin (); arg != arguments.end (); ++arg)
|
for (arg = grouped_arguments.begin (); arg != grouped_arguments.end (); ++arg)
|
||||||
{
|
{
|
||||||
// Attributes are essentially name:value pairs, and correspond directly
|
// Attributes are essentially name:value pairs, and correspond directly
|
||||||
// to stored attributes.
|
// to stored attributes.
|
||||||
|
@ -516,3 +522,39 @@ void Command::modify_task (
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Disaster avoidance mechanism.
|
||||||
|
void Command::safety ()
|
||||||
|
{
|
||||||
|
if (! _read_only)
|
||||||
|
{
|
||||||
|
A3 write_filter = context.a3.extract_filter ();
|
||||||
|
if (!write_filter.size ()) // Potential disaster.
|
||||||
|
{
|
||||||
|
// If user is willing to be asked, this can be avoided.
|
||||||
|
if (context.config.getBoolean ("confirmation") &&
|
||||||
|
confirm (STRING_TASK_SAFETY_VALVE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// No.
|
||||||
|
throw std::string (STRING_TASK_SAFETY_FAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
A3 Command::group_arguments (const A3& input)
|
||||||
|
{
|
||||||
|
A3 result;
|
||||||
|
|
||||||
|
std::vector <Arg>::const_iterator arg;
|
||||||
|
for (arg = input.begin (); arg != input.end (); ++arg)
|
||||||
|
{
|
||||||
|
// TODO Create a grouped set of args.
|
||||||
|
|
||||||
|
result.push_back (*arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -63,6 +63,10 @@ protected:
|
||||||
void modify_task_annotate (Task&, const A3&);
|
void modify_task_annotate (Task&, const A3&);
|
||||||
void modify_task (Task&, const A3&, std::string&);
|
void modify_task (Task&, const A3&, std::string&);
|
||||||
|
|
||||||
|
void safety ();
|
||||||
|
|
||||||
|
A3 group_arguments (const A3&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _keyword;
|
std::string _keyword;
|
||||||
std::string _usage;
|
std::string _usage;
|
||||||
|
|
|
@ -433,6 +433,8 @@
|
||||||
#define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid."
|
#define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid."
|
||||||
#define STRING_TASK_VALID_WAIT_RECUR "You cannot create a task that is both waiting and recurring."
|
#define STRING_TASK_VALID_WAIT_RECUR "You cannot create a task that is both waiting and recurring."
|
||||||
#define STRING_TASK_VALID_PRIORITY "Priority values may be 'H', 'M' or 'L', not '{1}'."
|
#define STRING_TASK_VALID_PRIORITY "Priority values may be 'H', 'M' or 'L', not '{1}'."
|
||||||
|
#define STRING_TASK_SAFETY_VALVE "This command has no filter, and will modify all tasks. Are you sure?"
|
||||||
|
#define STRING_TASK_SAFETY_FAIL "Command prevented from running."
|
||||||
|
|
||||||
// Taskmod
|
// Taskmod
|
||||||
#define STRING_TASKMOD_BAD_INIT "Taskmod::getUuid(): Task object not initialized."
|
#define STRING_TASKMOD_BAD_INIT "Taskmod::getUuid(): Task object not initialized."
|
||||||
|
|
|
@ -28,43 +28,36 @@
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More tests => 9;
|
use Test::More tests => 5;
|
||||||
|
|
||||||
# Create the rc file.
|
# Create the rc file.
|
||||||
if (open my $fh, '>', 'bug_annotate.rc')
|
if (open my $fh, '>', 'bug.rc')
|
||||||
{
|
{
|
||||||
print $fh "data.location=.\n";
|
print $fh "data.location=.\n";
|
||||||
close $fh;
|
close $fh;
|
||||||
ok (-r 'bug_annotate.rc', 'Created bug_annotate.rc');
|
ok (-r 'bug.rc', 'Created bug.rc');
|
||||||
}
|
}
|
||||||
|
|
||||||
# Attempt a blank annotation.
|
# Attempt a blank annotation.
|
||||||
qx{../src/task rc:bug_annotate.rc add foo};
|
qx{../src/task rc:bug.rc add foo};
|
||||||
my $output = qx{../src/task rc:bug_annotate.rc 1 annotate};
|
my $output = qx{../src/task rc:bug.rc 1 annotate};
|
||||||
like ($output, qr/Additional text must be provided/, 'failed on blank annotation');
|
like ($output, qr/Additional text must be provided/, 'failed on blank annotation');
|
||||||
|
|
||||||
# Attempt an annotation without ID
|
# Attempt an annotation without ID
|
||||||
$output = qx{../src/task rc:bug_annotate.rc annotate bar};
|
$output = qx{echo "-- n" | ../src/task rc:bug.rc annotate bar};
|
||||||
like ($output, qr/ID needed to apply an annotation./, 'failed on annotation without ID');
|
like ($output, qr/Command prevented from running/, 'Filter-less write command inhibited');
|
||||||
|
|
||||||
|
$output = qx{echo "-- y" | ../src/task rc:bug.rc annotate bar};
|
||||||
|
unlike ($output, qr/Command prevented from running/, 'Filter-less write command permitted');
|
||||||
|
|
||||||
# Cleanup.
|
# Cleanup.
|
||||||
unlink 'pending.data';
|
unlink qw(pending.data completed.data undo.data backlog.data synch.key bug.rc);
|
||||||
ok (!-r 'pending.data', 'Removed pending.data');
|
ok (! -r 'pending.data' &&
|
||||||
|
! -r 'completed.data' &&
|
||||||
unlink 'completed.data';
|
! -r 'undo.data' &&
|
||||||
ok (!-r 'completed.data', 'Removed completed.data');
|
! -r 'backlog.data' &&
|
||||||
|
! -r 'synch_key.data' &&
|
||||||
unlink 'undo.data';
|
! -r 'bug.rc', 'Cleanup');
|
||||||
ok (!-r 'undo.data', 'Removed undo.data');
|
|
||||||
|
|
||||||
unlink 'backlog.data';
|
|
||||||
ok (!-r 'backlog.data', 'Removed backlog.data');
|
|
||||||
|
|
||||||
unlink 'synch.key';
|
|
||||||
ok (!-r 'synch.key', 'Removed synch.key');
|
|
||||||
|
|
||||||
unlink 'bug_annotate.rc';
|
|
||||||
ok (!-r 'bug_annotate.rc', 'Removed bug_annotate.rc');
|
|
||||||
|
|
||||||
exit 0;
|
exit 0;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue