diff --git a/modules/appmodel/CMakeLists.txt b/modules/appmodel/CMakeLists.txt index 2bb5efe5d1..fee01a875c 100644 --- a/modules/appmodel/CMakeLists.txt +++ b/modules/appmodel/CMakeLists.txt @@ -11,7 +11,9 @@ set (APPMODEL_SOURCES appmodel-context.c app-object-generator.c app-parser-generator.c + app-transform-generator.c application.c + transformation.c ) add_module( diff --git a/modules/appmodel/Makefile.am b/modules/appmodel/Makefile.am index f87ac90a78..5405ef2bb9 100644 --- a/modules/appmodel/Makefile.am +++ b/modules/appmodel/Makefile.am @@ -14,8 +14,12 @@ modules_appmodel_libappmodel_la_SOURCES = \ modules/appmodel/app-object-generator.h \ modules/appmodel/app-parser-generator.c \ modules/appmodel/app-parser-generator.h \ + modules/appmodel/app-transform-generator.c \ + modules/appmodel/app-transform-generator.h \ modules/appmodel/application.c \ modules/appmodel/application.h \ + modules/appmodel/transformation.c \ + modules/appmodel/transformation.h \ modules/appmodel/appmodel-grammar.y modules_appmodel_libappmodel_la_CPPFLAGS = \ diff --git a/modules/appmodel/app-parser-generator.c b/modules/appmodel/app-parser-generator.c index 26821d0c21..0fd1958cf6 100644 --- a/modules/appmodel/app-parser-generator.c +++ b/modules/appmodel/app-parser-generator.c @@ -1,19 +1,19 @@ /* * Copyright (c) 2017 Balabit * Copyright (c) 2017 Balazs Scheidler + * Copyright (c) 2024 Balazs Scheidler * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the @@ -98,18 +98,36 @@ _generate_parser(AppParserGenerator *self, const gchar *parser_expr) " };\n", parser_expr); } +static void +_generate_filterx(AppParserGenerator *self, const gchar *filterx_expr) +{ + if (filterx_expr) + g_string_append_printf(self->block, + " filterx {\n" + " %s\n" + " };\n", filterx_expr); +} + static void _generate_action(AppParserGenerator *self, Application *app) { - if (!self->allow_overlaps) - { - g_string_append_printf(self->block, - " rewrite {\n" - " set-tag('.app.%s');\n" - " set('%s' value('.app.name'));\n" - " };\n", - app->super.name, app->super.name); - } + if (self->allow_overlaps) + return; + + if (app->filterx_expr) + g_string_append_printf(self->block, + " filterx {\n" + " meta.app_name = '%s';\n" + " };\n", + app->super.name); + + else + g_string_append_printf(self->block, + " rewrite {\n" + " set-tag('.app.%s');\n" + " set('%s' value('.app.name'));\n" + " };\n", + app->super.name, app->super.name); } static void @@ -147,6 +165,7 @@ _generate_application(Application *app, gpointer user_data) _generate_filter(self, app->filter_expr); _generate_parser(self, app->parser_expr); + _generate_filterx(self, app->filterx_expr); _generate_action(self, app); g_string_append_printf(self->block, " #End Application %s\n", app->super.name); @@ -175,7 +194,7 @@ _generate_framing(AppParserGenerator *self, GlobalConfig *cfg) g_string_append(self->block, " channel {\n"); g_string_append(self->block, - " filter { tags('.app.doesnotexist'); };\n" + " filterx { false; };\n" " };\n"); } else @@ -190,7 +209,7 @@ _generate_framing(AppParserGenerator *self, GlobalConfig *cfg) static void _generate_empty_frame(AppParserGenerator *self) { - g_string_append(self->block, "channel { filter { tags('.app.doesnotexist'); }; };"); + g_string_append(self->block, "channel { filterx { false; }; };"); } void diff --git a/modules/appmodel/app-parser-generator.h b/modules/appmodel/app-parser-generator.h index ea45d5e468..d3b78157be 100644 --- a/modules/appmodel/app-parser-generator.h +++ b/modules/appmodel/app-parser-generator.h @@ -22,8 +22,8 @@ * */ -#ifndef APPMODEL_APPPARSER_GENERATOR_H_INCLUDED -#define APPMODEL_APPPARSER_GENERATOR_H_INCLUDED +#ifndef APPMODEL_APP_PARSER_GENERATOR_H_INCLUDED +#define APPMODEL_APP_PARSER_GENERATOR_H_INCLUDED #include "plugin.h" diff --git a/modules/appmodel/app-transform-generator.c b/modules/appmodel/app-transform-generator.c new file mode 100644 index 0000000000..7c04a2cb61 --- /dev/null +++ b/modules/appmodel/app-transform-generator.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 Balazs Scheidler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "app-object-generator.h" +#include "appmodel.h" + +/* app-transform() */ + +typedef struct _AppTransformGenerator +{ + AppObjectGenerator super; + const gchar *flavour; + GString *block; +} AppTransformGenerator; + +static gboolean +_parse_transforms_arg(AppTransformGenerator *self, CfgArgs *args, const gchar *reference) +{ + self->flavour = cfg_args_get(args, "flavour"); + if (!self->flavour) + self->flavour = "default"; + return TRUE; +} + +static gboolean +app_transform_generator_parse_arguments(AppObjectGenerator *s, CfgArgs *args, const gchar *reference) +{ + AppTransformGenerator *self = (AppTransformGenerator *) s; + g_assert(args != NULL); + + if (!_parse_transforms_arg(self, args, reference)) + return FALSE; + + if (!app_object_generator_parse_arguments_method(&self->super, args, reference)) + return FALSE; + + return TRUE; +} + +static void +_generate_steps(AppTransformGenerator *self, GList *steps) +{ + for (GList *l = steps; l; l = l->next) + { + TransformationStep *step = l->data; + g_string_append_printf(self->block, " # step: %s", step->name); + g_string_append_printf(self->block, " %s\n", step->expr); + } +} + +static void +_generate_app_transform(Transformation *transformation, gpointer user_data) +{ + AppTransformGenerator *self = (AppTransformGenerator *) user_data; + + if (strcmp(transformation->super.instance, self->flavour) != 0) + return; + + if (!app_object_generator_is_application_included(&self->super, transformation->super.name)) + return; + + if (app_object_generator_is_application_excluded(&self->super, transformation->super.name)) + return; + + g_string_append_printf(self->block, "\n#Start Application %s\n", transformation->super.name); + g_string_append_printf(self->block, " if (meta.app_name == '%s') {\n", transformation->super.name); + for (GList *l = transformation->blocks; l; l = l->next) + { + TransformationBlock *block = l->data; + + _generate_steps(self, block->steps); + } + g_string_append(self->block, " };\n"); + g_string_append_printf(self->block, "\n#End Application %s\n", transformation->super.name); +} + + +static void +app_transform_generate_config(AppObjectGenerator *s, GlobalConfig *cfg, GString *result) +{ + AppTransformGenerator *self = (AppTransformGenerator *) s; + + self->block = result; + g_string_append_printf(result, "## app-transform(flavour(%s))\n" + "channel {\n" + " filterx {\n", self->flavour); + appmodel_iter_transformations(cfg, _generate_app_transform, self); + g_string_append(result, " };\n" + "}"); + self->block = NULL; +} + +CfgBlockGenerator * +app_transform_generator_new(gint context, const gchar *name) +{ + AppTransformGenerator *self = g_new0(AppTransformGenerator, 1); + + app_object_generator_init_instance(&self->super, context, name); + self->super.parse_arguments = app_transform_generator_parse_arguments; + self->super.generate_config = app_transform_generate_config; + return &self->super.super; +} diff --git a/modules/appmodel/app-transform-generator.h b/modules/appmodel/app-transform-generator.h new file mode 100644 index 0000000000..404ec2dfc9 --- /dev/null +++ b/modules/appmodel/app-transform-generator.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Balazs Scheidler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef APPMODEL_APP_TRANSFORM_GENERATOR_H_INCLUDED +#define APPMODEL_APP_TRANSFORM_GENERATOR_H_INCLUDED + +#include "plugin.h" + +CfgBlockGenerator *app_transform_generator_new(gint context, const gchar *name); + +#endif diff --git a/modules/appmodel/application.c b/modules/appmodel/application.c index 11b32ea20d..672ba4d8c9 100644 --- a/modules/appmodel/application.c +++ b/modules/appmodel/application.c @@ -37,12 +37,20 @@ application_set_parser(Application *self, const gchar *parser_expr) self->parser_expr = g_strdup(parser_expr); } +void +application_set_filterx(Application *self, const gchar *filterx_expr) +{ + g_free(self->filterx_expr); + self->filterx_expr = g_strdup(filterx_expr); +} + static void application_free(AppModelObject *s) { Application *self = (Application *) s; g_free(self->filter_expr); g_free(self->parser_expr); + g_free(self->filterx_expr); } Application * diff --git a/modules/appmodel/application.h b/modules/appmodel/application.h index c8dda0cf5a..944f6c63a0 100644 --- a/modules/appmodel/application.h +++ b/modules/appmodel/application.h @@ -33,10 +33,12 @@ typedef struct _Application AppModelObject super; gchar *filter_expr; gchar *parser_expr; + gchar *filterx_expr; } Application; void application_set_filter(Application *self, const gchar *filter_expr); void application_set_parser(Application *self, const gchar *parser_expr); +void application_set_filterx(Application *self, const gchar *parser_expr); Application *application_new(const gchar *name, const gchar *topic); diff --git a/modules/appmodel/appmodel-grammar.ym b/modules/appmodel/appmodel-grammar.ym index 90eb1ca045..d368c9c33c 100644 --- a/modules/appmodel/appmodel-grammar.ym +++ b/modules/appmodel/appmodel-grammar.ym @@ -48,8 +48,12 @@ /* INCLUDE_DECLS */ %token KW_APPLICATION +%token KW_TRANSFORMATION +%token KW_TRANSFORM +%token KW_STEP %type application_definition +%type transformation_definition %% @@ -60,6 +64,12 @@ start *instance = $2; YYACCEPT; } + | LL_CONTEXT_ROOT transformation_definition + { + appmodel_register_transformation(configuration, $2); + *instance = $2; + YYACCEPT; + } ; @@ -84,6 +94,46 @@ application_options application_option : KW_FILTER _block_content_context_push LL_BLOCK _block_content_context_pop { application_set_filter($0, $3); free($3); } | KW_PARSER _block_content_context_push LL_BLOCK _block_content_context_pop { application_set_parser($0, $3); free($3); } + | KW_FILTERX _block_content_context_push LL_BLOCK _block_content_context_pop { application_set_filterx($0, $3); free($3); } + ; + + +transformation_definition + : KW_TRANSFORMATION string '[' string ']' + { + $$ = transformation_new($2, $4); + }[transformation] + '{' { $$ = $transformation; } transformation_options '}' + { + $$ = $transformation; + free($2); + free($4); + } + ; + +transformation_options + : transformation_option semicolons { $$ = $0; } transformation_options + | + ; + +/* $0 is Transformation */ +transformation_option + : KW_TRANSFORM '[' string ']' '{' { $$ = transformation_block_new($3); } transformation_steps '}' + { free($3); transformation_add_block($0, $6); } + ; + +/* $0 is TransformationBlock */ +transformation_steps + : transformation_step semicolons { $$ = $0; } transformation_steps + | + ; + +/* $0 is TransformationBlock */ +transformation_step + : KW_STEP '[' string ']' _block_content_context_push LL_BLOCK _block_content_context_pop + { + transformation_block_add_step($0, $3, $6); free($3); free($6); + } ; /* INCLUDE_RULES */ diff --git a/modules/appmodel/appmodel-parser.c b/modules/appmodel/appmodel-parser.c index c72c14edbc..29310fc6b8 100644 --- a/modules/appmodel/appmodel-parser.c +++ b/modules/appmodel/appmodel-parser.c @@ -31,7 +31,10 @@ int appmodel_parse(CfgLexer *lexer, gpointer *instance, gpointer arg); static CfgLexerKeyword appmodel_keywords[] = { - { "application", KW_APPLICATION }, + { "application", KW_APPLICATION }, + { "transformation", KW_TRANSFORMATION }, + { "transform", KW_TRANSFORM }, + { "step", KW_STEP }, { NULL } }; diff --git a/modules/appmodel/appmodel-plugin.c b/modules/appmodel/appmodel-plugin.c index 7bd8692261..30ba1cbb47 100644 --- a/modules/appmodel/appmodel-plugin.c +++ b/modules/appmodel/appmodel-plugin.c @@ -24,6 +24,7 @@ #include "cfg-parser.h" #include "appmodel-parser.h" #include "app-parser-generator.h" +#include "app-transform-generator.h" #include "block-ref-parser.h" #include "plugin.h" #include "plugin-types.h" @@ -36,6 +37,12 @@ app_parser_construct(Plugin *p) return app_parser_generator_new(p->type, p->name); } +static gpointer +app_transform_construct(Plugin *p) +{ + return app_transform_generator_new(p->type, p->name); +} + static Plugin appmodel_plugins[] = { { @@ -43,11 +50,22 @@ static Plugin appmodel_plugins[] = .name = "application", .parser = &appmodel_parser, }, + { + .type = LL_CONTEXT_ROOT, + .name = "transformation", + .parser = &appmodel_parser, + }, { .type = LL_CONTEXT_PARSER | LL_CONTEXT_FLAG_GENERATOR, .name = "app-parser", .construct = app_parser_construct, .parser = &block_ref_parser + }, + { + .type = LL_CONTEXT_PARSER | LL_CONTEXT_FLAG_GENERATOR, + .name = "app-transform", + .construct = app_transform_construct, + .parser = &block_ref_parser } }; diff --git a/modules/appmodel/appmodel.c b/modules/appmodel/appmodel.c index e94aea1368..dab106ac52 100644 --- a/modules/appmodel/appmodel.c +++ b/modules/appmodel/appmodel.c @@ -53,3 +53,19 @@ appmodel_iter_applications(GlobalConfig *cfg, void (*foreach)(Application *app, AppModelContext *appmodel = appmodel_get_context(cfg); appmodel_context_iter_objects(appmodel, APPLICATION_TYPE_NAME, (AppModelContextIterFunc) foreach, user_data); } + +void +appmodel_register_transformation(GlobalConfig *cfg, Transformation *transformation) +{ + AppModelContext *ac = appmodel_get_context(cfg); + + appmodel_context_register_object(ac, &transformation->super); +} + +void +appmodel_iter_transformations(GlobalConfig *cfg, void (*foreach)(Transformation *transformation, gpointer user_data), + gpointer user_data) +{ + AppModelContext *appmodel = appmodel_get_context(cfg); + appmodel_context_iter_objects(appmodel, TRANSFORMATION_TYPE_NAME, (AppModelContextIterFunc) foreach, user_data); +} diff --git a/modules/appmodel/appmodel.h b/modules/appmodel/appmodel.h index 34b0f3dd7e..f017f63bba 100644 --- a/modules/appmodel/appmodel.h +++ b/modules/appmodel/appmodel.h @@ -25,6 +25,7 @@ #include "module-config.h" #include "application.h" +#include "transformation.h" AppModelContext *appmodel_get_context(GlobalConfig *cfg); void appmodel_register_application(GlobalConfig *cfg, Application *application); @@ -32,4 +33,8 @@ void appmodel_iter_applications(GlobalConfig *cfg, void (*foreach)(Application *app, gpointer user_data), gpointer user_data); +void appmodel_register_transformation(GlobalConfig *cfg, Transformation *transformation); +void appmodel_iter_transformations(GlobalConfig *cfg, void (*foreach)(Transformation *transformation, + gpointer user_data), gpointer user_data); + #endif diff --git a/modules/appmodel/tests/test_app_parser_generator.c b/modules/appmodel/tests/test_app_parser_generator.c index 1fb7e81c60..b08e0eb881 100644 --- a/modules/appmodel/tests/test_app_parser_generator.c +++ b/modules/appmodel/tests/test_app_parser_generator.c @@ -201,7 +201,7 @@ Test(app_parser_generator, app_parser_with_no_apps_registered_generates_empty_fr { _app_parser_generate("port514"); _assert_parser_framing_is_present(); - _assert_snippet_is_present("tags('.app.doesnotexist')"); + _assert_snippet_is_present("filterx { false; }"); _assert_config_is_valid("port514", NULL); } @@ -223,7 +223,7 @@ Test(app_parser_generator, app_parser_is_disabled_if_auto_parse_is_set_to_no) _register_sample_application("bar", "port514"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse", "no", NULL)); - _assert_snippet_is_present("tags('.app.doesnotexist')"); + _assert_snippet_is_present("filterx { false; }"); _app_parser_generate_with_args("port514", _build_cfg_args("auto-parse", "yes", NULL)); _assert_parser_framing_is_present(); diff --git a/modules/appmodel/transformation.c b/modules/appmodel/transformation.c new file mode 100644 index 0000000000..2f6cc0c5cd --- /dev/null +++ b/modules/appmodel/transformation.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Balázs Scheidler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#include "transformation.h" + +/* TransformationStep: a named filterx expression */ + +TransformationStep * +transformation_step_new(const gchar *name, const gchar *expr) +{ + TransformationStep *self = g_new0(TransformationStep, 1); + self->name = g_strdup(name); + self->expr = g_strdup(expr); + return self; +} + +void +transformation_step_free(TransformationStep *self) +{ + g_free(self->name); + g_free(self->expr); +} + +/* TransformationBlock: named list of steps */ + +void +transformation_block_add_step(TransformationBlock *self, const gchar *name, const gchar *expr) +{ + self->steps = g_list_append(self->steps, transformation_step_new(name, expr)); +} + +TransformationBlock * +transformation_block_new(const gchar *name) +{ + TransformationBlock *self = g_new0(TransformationBlock, 1); + self->name = g_strdup(name); + return self; +} + +void +transformation_block_free(TransformationBlock *self) +{ + g_free(self->name); + g_list_free_full(self->steps, (GDestroyNotify) transformation_step_free); + g_free(self); +} + +/* Transformation */ +/* list of blocks */ + +void +transformation_add_block(Transformation *self, TransformationBlock *block) +{ + self->blocks = g_list_append(self->blocks, block); +} + +static void +transformation_free(AppModelObject *s) +{ + Transformation *self = (Transformation *) s; + + g_list_free_full(self->blocks, (GDestroyNotify) transformation_block_free); +} + +Transformation * +transformation_new(const gchar *app, const gchar *flavour) +{ + Transformation *self = g_new0(Transformation, 1); + + appmodel_object_init_instance(&self->super, TRANSFORMATION_TYPE_NAME, app, flavour); + self->super.free_fn = transformation_free; + return self; +} diff --git a/modules/appmodel/transformation.h b/modules/appmodel/transformation.h new file mode 100644 index 0000000000..07aa31cbda --- /dev/null +++ b/modules/appmodel/transformation.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Balázs Scheidler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As an additional exemption you are allowed to compile & link against the + * OpenSSL libraries as published by the OpenSSL project. See the file + * COPYING for details. + * + */ + +#ifndef APPMODEL_TRANSFORMATION_H_INCLUDED +#define APPMODEL_TRANSFORMATION_H_INCLUDED + +#include "appmodel-context.h" + +#define TRANSFORMATION_TYPE_NAME "transformation" + +typedef struct _TransformationStep +{ + gchar *name; + gchar *expr; +} TransformationStep; + +TransformationStep *transformation_step_new(const gchar *name, const gchar *expr); +void transformation_step_free(TransformationStep *self); + + +typedef struct _TransformationBlock +{ + gchar *name; + GList *steps; +} TransformationBlock; + +void transformation_block_add_step(TransformationBlock *self, const gchar *name, const gchar *step); +TransformationBlock *transformation_block_new(const gchar *name); +void transformation_block_free(TransformationBlock *self); + +typedef struct _Transformation +{ + AppModelObject super; + GList *blocks; +} Transformation; + +void transformation_add_block(Transformation *self, TransformationBlock *block); +Transformation *transformation_new(const gchar *app, const gchar *name); + +#endif diff --git a/tests/copyright/policy b/tests/copyright/policy index 999a50192e..3730b3e4a0 100644 --- a/tests/copyright/policy +++ b/tests/copyright/policy @@ -271,6 +271,8 @@ modules/kvformat/filterx-func-parse-kv\.[ch] modules/kvformat/filterx-func-format-kv\.[ch] modules/kvformat/tests/test_filterx_func_parse_kv.c modules/kvformat/tests/test_filterx_func_format_kv.c +modules/appmodel/app-transform-generator\.[ch]$ +modules/appmodel/transformation\.[ch]$ docker/python-modules/webhook/scl/webhook.conf docker/python-modules/webhook/source.py packaging/package-indexer/remote_storage_synchronizer/s3_bucket_synchronizer.py