With the advent of actions, there is a more concrete line between
runtime errors (e.g. things that throw exceptions) and errors returned
by actions.
Some of the plugins tests were expecting errors to be returned by
exceptions (e.g. with a leading "Runtime error: and a trailing "
Exiting.").
With actions changes, the errors are just returned directly in
application::run(), so drop the leading and trailing bits in expected
test outputs.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Some objects used by actions (falco outputs, falco_formats, etc) were
using raw pointer references, which isn't great.
So convert use of raw pointers (originally passed from falco_init or
functions it called) with shared_ptr, as they are now held in actions
state.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Changes to the falco::app::application object to support actions:
- State that needs to be shared between applications is in a
falco::app::application::action_state object, accessible via the
method state().
- The application now has an action manager which adds all the action
objects defined in defined_app_actions.h.
- application now has a run() method which simply uses the action
manager to run all the actions. run() returns the result from the
action manager.
- In a few rare cases (signal handlers, etc.) it wasn't possible to
pass around an application reference, so create a singleton
accessible via application::get().
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Move the bulk of the code from falco_init() to individual app action
objects.
To avoid duplicate code for groups, actions derive from one of:
- easyopts_action: returns a group of "easyopts". Includes actions
like options like --version and --help that don't need
anything else.
- init_action: returns a group of "init". Most actions in this group.
- run_action: returns a group of "run". daemonize/inspector open/
event processing are in this group.
Any state that needs to be shared betweeen actions resides in
app::state(), so the moved code stays pretty much as-is, other than
replacing stack variables with member variables in app_state.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
This involves moving the code in falco_init() into individual app
actions. falco_init() simply calls app.run() now. The return value
from the action manager is returned from run() and any error is
printed as-is.
app.run() is still inside a catch block to catch any uncaught
exception.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Has a set of test actions that simply record when they were run, and a
set of tests that run various sets of actions in known orders and
compare the expected run order to the actual run order.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Add an action manager object that ensures that actions run, honoring
prerequsite order, grouping and run_result.
The bulk of the work is in the "sorting" of actions to preserve
prerequsite order. The comparison function checks to see if one is a
prerequsite of another, either directly or recursively.
The actions are run via a run() method, which iterates over groups,
finds the actions for each group, sorts the actions by prerequsites,
and calls each action's run() method.
Based on the run_result, the manager will:
- proceed with no errors
- stop with no errors
- print any returned error string.
The run result from the last action is returned from run().
After all groups have run, all groups are deinit()ed using each
action's deinit() method.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
An "action" is a piece of code that has a name (e.g. "load plugins")
and can name dependencies (depends on "init inspector").
A run() method is called to do the work of the action, and a deinit()
method is called after all actions are complete to tear down any state
outside the object.
actions can be segregated into groups (e.g. "init" vs "run"). All
actions in a given group are run before actions in the next group. The
action manager is configured with the group order.
Actions have access to to command line options via options() and can
share state with other actions via state().
This will help distribute all the many things falco does in falco_init
into smaller components, while retaining a notion of dependencies and
order.
To make testing easier, most of the functionality is in a base class
::runnable_action, which defines the interface. A derived class
::action additionally brings in an application object and the
state()/options() methods.
This makes it easier to write unit tests for the action manager
without bringing in all of application, falco engine, outputs,
inspector, etc.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Add new test cases for a rule with an unknown source *and* an
exception, and a macro with an unknown source.
The first results in a rule warning (and no error), and the second
prints an error and skips.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
Also skip macros with unknown sources. This matters primarily for
macros related to plugins that have a distinct event source.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
If a rule has an unknown source, *and* has exceptions, loading the
rule will result in an error and not skipping the rule. This is
because exceptions are also validated for unknown fields, and that
occurs before the current check for unknown sources.
The fix is to move the check for unknown sources as soon as the rules
object is read.
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
This adds a new macro `user_known_mount_in_privileged_containers` which
allows the easier user-defined exclusions for the "Mount Launched in
Privileged Container" rule.
This would be cleaner with the exclusions feature, but this feature
is not used in the default ruleset yet, if I understand correctly.
Signed-off-by: Matt Moyer <mmoyer@figma.com>