mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +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 <E9.h>
|
||||
#include <text.h>
|
||||
#include <util.h>
|
||||
#include <i18n.h>
|
||||
#include <Command.h>
|
||||
#include <cmake.h>
|
||||
|
@ -326,6 +327,8 @@ void Command::filter (std::vector <Task>& output)
|
|||
}
|
||||
else
|
||||
{
|
||||
safety ();
|
||||
|
||||
context.timer_filter.stop ();
|
||||
const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
|
||||
const std::vector <Task>& completed = context.tdb2.completed.get_tasks ();
|
||||
|
@ -406,8 +409,11 @@ void Command::modify_task (
|
|||
const A3& arguments,
|
||||
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;
|
||||
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
|
||||
// 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 (Task&, const A3&, std::string&);
|
||||
|
||||
void safety ();
|
||||
|
||||
A3 group_arguments (const A3&);
|
||||
|
||||
protected:
|
||||
std::string _keyword;
|
||||
std::string _usage;
|
||||
|
|
|
@ -433,6 +433,8 @@
|
|||
#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_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
|
||||
#define STRING_TASKMOD_BAD_INIT "Taskmod::getUuid(): Task object not initialized."
|
||||
|
|
|
@ -28,43 +28,36 @@
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 9;
|
||||
use Test::More tests => 5;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'bug_annotate.rc')
|
||||
if (open my $fh, '>', 'bug.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'bug_annotate.rc', 'Created bug_annotate.rc');
|
||||
ok (-r 'bug.rc', 'Created bug.rc');
|
||||
}
|
||||
|
||||
# Attempt a blank annotation.
|
||||
qx{../src/task rc:bug_annotate.rc add foo};
|
||||
my $output = qx{../src/task rc:bug_annotate.rc 1 annotate};
|
||||
qx{../src/task rc:bug.rc add foo};
|
||||
my $output = qx{../src/task rc:bug.rc 1 annotate};
|
||||
like ($output, qr/Additional text must be provided/, 'failed on blank annotation');
|
||||
|
||||
# Attempt an annotation without ID
|
||||
$output = qx{../src/task rc:bug_annotate.rc annotate bar};
|
||||
like ($output, qr/ID needed to apply an annotation./, 'failed on annotation without ID');
|
||||
$output = qx{echo "-- n" | ../src/task rc:bug.rc annotate bar};
|
||||
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.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
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');
|
||||
unlink qw(pending.data completed.data undo.data backlog.data synch.key bug.rc);
|
||||
ok (! -r 'pending.data' &&
|
||||
! -r 'completed.data' &&
|
||||
! -r 'undo.data' &&
|
||||
! -r 'backlog.data' &&
|
||||
! -r 'synch_key.data' &&
|
||||
! -r 'bug.rc', 'Cleanup');
|
||||
|
||||
exit 0;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue