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:
Paul Beckingham 2011-09-04 08:44:22 -04:00
parent f74c33dc02
commit fa973f734b
4 changed files with 66 additions and 25 deletions

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;

View file

@ -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."

View file

@ -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;