diff --git a/.github/actions/ubuntu16-build-action/Dockerfile b/.github/actions/ubuntu16-build-action/Dockerfile deleted file mode 100644 index c43e2c564..000000000 --- a/.github/actions/ubuntu16-build-action/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:16.04 - -# Uncomment deb-src lines for all enabled repos. First part of single-quoted -# string (up the the !) is the pattern of the lines that will be ignored. -# Needed for apt-get build-dep call later in script -RUN sed -Ei '/.*partner/! s/^# (deb-src .*)/\1/g' /etc/apt/sources.list - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update -RUN apt-get install -y build-essential - -# PHP dependencies -RUN apt-get build-dep -y php7.0 -RUN apt-get install -y libmysqlclient-dev php-dev libmcrypt-dev libphp7.0-embed - -# Other tools -RUN apt-get install -y curl gdb valgrind libcurl4-openssl-dev pkg-config postgresql python-psycopg2 libpq-dev libedit-dev libreadline-dev git - -COPY build.sh /build.sh - -ENTRYPOINT ["/build.sh"] diff --git a/.github/actions/ubuntu16-build-action/action.yml b/.github/actions/ubuntu16-build-action/action.yml deleted file mode 100644 index 2a01f96da..000000000 --- a/.github/actions/ubuntu16-build-action/action.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: ubuntu16-build-action -description: 'Build the agent on ubuntu 16' -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/.github/actions/ubuntu16-build-action/build.sh b/.github/actions/ubuntu16-build-action/build.sh deleted file mode 100755 index 079de1ba1..000000000 --- a/.github/actions/ubuntu16-build-action/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -make -j $(nproc) all -make -j $(nproc) run_tests - diff --git a/.github/actions/ubuntu18-build-action/Dockerfile b/.github/actions/ubuntu18-build-action/Dockerfile deleted file mode 100644 index b9bb190db..000000000 --- a/.github/actions/ubuntu18-build-action/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:18.04 - -# Uncomment deb-src lines for all enabled repos. First part of single-quoted -# string (up the the !) is the pattern of the lines that will be ignored. -# Needed for apt-get build-dep call later in script -RUN sed -Ei '/.*partner/! s/^# (deb-src .*)/\1/g' /etc/apt/sources.list - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update -RUN apt-get install -y build-essential - -# PHP dependencies -RUN apt-get build-dep -y php7.2 -RUN apt-get install -y libmysqlclient-dev php-dev libmcrypt-dev libphp7.2-embed - -# Other tools -RUN apt-get install -y curl gdb valgrind libcurl4-openssl-dev pkg-config postgresql python-psycopg2 libpq-dev libedit-dev libreadline-dev git - -COPY build.sh /build.sh - -ENTRYPOINT ["/build.sh"] diff --git a/.github/actions/ubuntu18-build-action/action.yml b/.github/actions/ubuntu18-build-action/action.yml deleted file mode 100644 index 5b8fc28d6..000000000 --- a/.github/actions/ubuntu18-build-action/action.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: ubuntu18-build-action -description: 'Build the agent on ubuntu 18' -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/.github/actions/ubuntu18-build-action/build.sh b/.github/actions/ubuntu18-build-action/build.sh deleted file mode 100755 index 079de1ba1..000000000 --- a/.github/actions/ubuntu18-build-action/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -make -j $(nproc) all -make -j $(nproc) run_tests - diff --git a/.github/actions/ubuntu20-build-action/Dockerfile b/.github/actions/ubuntu20-build-action/Dockerfile deleted file mode 100644 index bbd6fe406..000000000 --- a/.github/actions/ubuntu20-build-action/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:20.04 - -# Uncomment deb-src lines for all enabled repos. First part of single-quoted -# string (up the the !) is the pattern of the lines that will be ignored. -# Needed for apt-get build-dep call later in script -RUN sed -Ei '/.*partner/! s/^# (deb-src .*)/\1/g' /etc/apt/sources.list - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update -RUN apt-get install -y build-essential - -# PHP dependencies -RUN apt-get build-dep -y php7.4 -RUN apt-get install -y libmysqlclient-dev php-dev libmcrypt-dev libphp7.4-embed - -# Other tools -RUN apt-get install -y curl gdb valgrind libcurl4-openssl-dev pkg-config postgresql libpq-dev libedit-dev libreadline-dev git - -COPY build.sh /build.sh - -ENTRYPOINT ["/build.sh"] diff --git a/.github/actions/ubuntu20-build-action/action.yml b/.github/actions/ubuntu20-build-action/action.yml deleted file mode 100644 index d42d71cf9..000000000 --- a/.github/actions/ubuntu20-build-action/action.yml +++ /dev/null @@ -1,5 +0,0 @@ -name: ubuntu20-build-action -description: 'Build the agent on ubuntu 20' -runs: - using: 'docker' - image: 'Dockerfile' diff --git a/.github/actions/ubuntu20-build-action/build.sh b/.github/actions/ubuntu20-build-action/build.sh deleted file mode 100755 index 079de1ba1..000000000 --- a/.github/actions/ubuntu20-build-action/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -make -j $(nproc) all -make -j $(nproc) run_tests - diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 000000000..98e8039ba --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,48 @@ +name: Security scan +on: + push: + branches: + - main + - dev + pull_request: + schedule: + - cron: '0 0 * * 0' # Every Sunday at 12:00 AM + +jobs: + trivy-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout newrelic-php-agent code + uses: actions/checkout@v4 + with: + path: php-agent + - name: Run Trivy in table mode + # Table output is only useful when running on a pull request or push. + if: contains(fromJSON('["push", "pull_request"]'), github.event_name) + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: fs + scan-ref: ./php-agent + trivy-config: ./php-agent/trivy.yaml + trivyignores: ./php-agent/.trivyignore + format: table + exit-code: 1 + + - name: Run Trivy in report mode + # Only generate sarif when running nightly on the dev branch. + if: ${{ github.event_name == 'schedule' }} + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: fs + scan-ref: ./php-agent + trivy-config: ./php-agent/trivy.yaml + trivyignores: ./php-agent/.trivyignore + format: sarif + output: trivy-results.sarif + + - name: Upload Trivy scan results to GitHub Security tab + # Only upload sarif when running nightly on the dev branch. + if: ${{ github.event_name == 'schedule' }} + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-results.sarif diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 000000000..01a5782ee --- /dev/null +++ b/.trivyignore @@ -0,0 +1,2 @@ +# Ignore missing HEALTHCHECK in Dockerfile - devenv service from files/Dockerfile doesn't need it: +AVD-DS-0026 diff --git a/Makefile b/Makefile index 0e95237d5..11a871312 100644 --- a/Makefile +++ b/Makefile @@ -475,25 +475,28 @@ test-services-stop: # Docker Development Environment # -dev-shell: - docker compose --profile dev up --build --remove-orphans -d - docker exec -it agent-devenv bash -c "sh files/set_path.sh ; bash" +devenv-image: + @docker compose --profile dev build devenv -dev-build: - docker compose --profile dev up --build --remove-orphans -d - docker exec -it agent-devenv bash -c "sh files/set_path.sh ; make -j4 all" +dev-shell: devenv-image + docker compose --profile dev up --pull missing --remove-orphans -d + docker compose exec -it devenv bash -c "sh files/set_path.sh ; bash" -dev-unit-tests: - docker compose --profile dev up --build --remove-orphans -d - docker exec -it agent-devenv bash -c "sh files/set_path.sh ; make -j4 valgrind" +dev-build: devenv-image + docker compose --profile dev up --pull missing --remove-orphans -d + docker compose exec -it devenv bash -c "sh files/set_path.sh ; make -j4 all" -dev-integration-tests: - docker compose --profile dev up --build --remove-orphans -d - docker exec -it agent-devenv bash -c "sh files/set_path.sh ; ./bin/integration_runner -agent ./agent/.libs/newrelic.so" +dev-unit-tests: devenv-image + docker compose --profile dev up --pull missing --remove-orphans -d + docker compose exec -it devenv bash -c "sh files/set_path.sh ; make -j4 valgrind" -dev-all: - docker compose --profile dev up --build --remove-orphans -d - docker exec -it agent-devenv bash -c "sh files/set_path.sh ; make -j4 all valgrind; ./bin/integration_runner -agent ./agent/.libs/newrelic.so" +dev-integration-tests: devenv-image + docker compose --profile dev up --pull missing --remove-orphans -d + docker compose exec -it devenv bash -c "sh files/set_path.sh ; ./bin/integration_runner -agent ./agent/.libs/newrelic.so" + +dev-all: devenv-image + docker compose --profile dev up --pull missing --remove-orphans -d + docker compose exec -it devenv bash -c "sh files/set_path.sh ; make -j4 all valgrind; ./bin/integration_runner -agent ./agent/.libs/newrelic.so" dev-stop: docker compose --profile dev stop diff --git a/VERSION b/VERSION index f628d2eaf..72773deb8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -11.3.0 +11.4.0 diff --git a/agent/fw_cakephp.c b/agent/fw_cakephp.c index 1dfe88231..572f6f23f 100644 --- a/agent/fw_cakephp.c +++ b/agent/fw_cakephp.c @@ -4,6 +4,7 @@ */ #include "php_agent.h" +#include "php_error.h" #include "php_execute.h" #include "php_user_instrument.h" #include "php_wrapper.h" @@ -12,132 +13,14 @@ #include "util_logging.h" #include "util_memory.h" -nr_framework_classification_t nr_cakephp_special_1( - const char* filename TSRMLS_DC) { - NR_UNUSED_TSRMLS; - - if (nr_strcaseidx(filename, "cake/libs/object.php") >= 0) { - return FRAMEWORK_IS_SPECIAL; - } - - return FRAMEWORK_IS_NORMAL; -} - -nr_framework_classification_t nr_cakephp_special_2( - const char* filename TSRMLS_DC) { - NR_UNUSED_TSRMLS; - - if (nr_strcaseidx(filename, "cake/core/app.php") >= 0) { - return FRAMEWORK_IS_SPECIAL; - } - - return FRAMEWORK_IS_NORMAL; -} - -/* - * For CakePHP 1.2 and 1.3 (and possibly earlier versions too) we hook into - * Component::initialize(). This function takes a controller as a parameter - * and we look into the params array of that controller object, and pick up - * the controller and action out of that array. - * - * CakePHP 1.x is end-of-life and no longer supported by the agent. - * Cake PHP 1.x does not support PHP 8+ and this wrapper is not updated for OAPI - * compatibility. - * - */ -NR_PHP_WRAPPER(nr_cakephp_name_the_wt_pre20) { - zval* arg1 = 0; - zval* params; - zval* czval; - zval* azval; - char* controller = 0; - char* action = 0; - int clen = 0; - int alen = 0; - char* name; - - (void)wraprec; - NR_UNUSED_SPECIALFN; - - NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_CAKEPHP); - - arg1 = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS TSRMLS_CC); - if (!nr_php_is_zval_valid_object(arg1)) { - NR_PHP_WRAPPER_CALL; - goto end; - } - - NR_PHP_WRAPPER_CALL; - - params = nr_php_get_zval_object_property(arg1, "params" TSRMLS_CC); - if (0 == params) { - nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: no params found in component"); - goto end; - } - - if (IS_ARRAY != Z_TYPE_P(params)) { - nrl_verbosedebug(NRL_FRAMEWORK, - "CakePHP: component params is not an array"); - goto end; - } - - czval = nr_php_get_zval_object_property(params, "controller" TSRMLS_CC); - if (0 == czval) { - nrl_verbosedebug(NRL_FRAMEWORK, - "CakePHP: no params['controller'] in component"); - } else { - clen = Z_STRLEN_P(czval); - controller = (char*)nr_alloca(clen + 1); - nr_strxcpy(controller, Z_STRVAL_P(czval), clen); - } - - azval = nr_php_get_zval_object_property(params, "action" TSRMLS_CC); - if (0 == azval) { - nrl_verbosedebug(NRL_FRAMEWORK, - "CakePHP: no params['action'] in component"); - } else { - alen = Z_STRLEN_P(azval); - action = (char*)nr_alloca(alen + 1); - nr_strxcpy(action, Z_STRVAL_P(azval), alen); - } - - if ((0 == clen) && (0 == alen)) { - nrl_verbosedebug(NRL_FRAMEWORK, - "CakePHP: nothing to call the transaction (yet?)"); - goto end; - } - - name = (char*)nr_alloca(alen + clen + 2); - if (clen) { - nr_strcpy(name, controller); - } - if (alen) { - if (clen) { - nr_strcat(name, "/"); - nr_strcat(name, action); - } else { - nr_strcpy(name, action); - } - } - - nr_txn_set_path("CakePHP", NRPRG(txn), name, NR_PATH_TYPE_ACTION, - NR_NOT_OK_TO_OVERWRITE); - -end: - nr_php_arg_release(&arg1); -} -NR_PHP_WRAPPER_END +#define PHP_PACKAGE_NAME "cakephp/cakephp" /* - * For CakePHP 2.0 and on, we do things a little differently as the params - * array doesn't exist in the component any more. Instead we hook the - * Controller's invokeAction method. This gets the request as a parameter - * and we get the action from the params array in that object. The - * controller object ($this) has a name, and that name is used (along - * with the word "Controller" appended which is what the CakePHP code does). - * - * CakePHP 2.x is end-of-life and in maintenance mode (critical bugfixes only). - * As such, functionality added in PHP 7.1+ is not well supported. + * For CakePHP 4.0 and on, we retrieve the current controller object + * and are able to extract the controller name from that. We then + * retrieve the request object from the controller and are able to + * extract the action name from that. We then concatenate the two + * strings to form the transaction name. * * txn naming scheme: * In this case, `nr_txn_set_path` is called after `NR_PHP_WRAPPER_CALL` with @@ -147,8 +30,7 @@ NR_PHP_WRAPPER_END * default way of calling the wrapped function in func_end. * */ -NR_PHP_WRAPPER(nr_cakephp_name_the_wt_2) { - zval* arg1 = 0; +NR_PHP_WRAPPER(nr_cakephp_name_the_wt_4) { zval* this_var = 0; zval* czval = 0; char* controller = 0; @@ -156,8 +38,9 @@ NR_PHP_WRAPPER(nr_cakephp_name_the_wt_2) { int clen = 0; int alen = 0; char* name = 0; - zval* params; - zval* azval; + zval* action_zval = NULL; + zval* request = NULL; + zval action_param; (void)wraprec; NR_UNUSED_SPECIALFN; @@ -193,37 +76,24 @@ NR_PHP_WRAPPER(nr_cakephp_name_the_wt_2) { } } - arg1 = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS TSRMLS_CC); - if (!nr_php_is_zval_valid_object(arg1)) { - NR_PHP_WRAPPER_CALL; - goto end; - } - NR_PHP_WRAPPER_CALL; - params = nr_php_get_zval_object_property(arg1, "params" TSRMLS_CC); - if (0 == params) { - nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: no params found in request"); + request = nr_php_call(this_var, "getRequest"); + if (!nr_php_is_zval_valid_object(request)) { + nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: no request found in controller"); goto end; } - if (IS_ARRAY != Z_TYPE_P(params)) { - nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: request params is not an array"); + nr_php_zval_str(&action_param, "action"); + action_zval = nr_php_call(request, "getParam", &action_param); + zval_dtor(&action_param); + if (!nr_php_is_zval_non_empty_string(action_zval)) { + nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: no action param found in request"); goto end; - } - - azval = nr_php_get_zval_object_property(params, "action" TSRMLS_CC); - if (0 == azval) { - nrl_verbosedebug(NRL_FRAMEWORK, "CakePHP: no params['action'] in request"); } else { - if (!nr_php_is_zval_valid_string(azval)) { - nrl_verbosedebug(NRL_FRAMEWORK, - "CakePHP: no string-valued params['action'] in request"); - } else { - alen = Z_STRLEN_P(azval); - action = (char*)nr_alloca(alen + 1); - nr_strxcpy(action, Z_STRVAL_P(azval), alen); - } + alen = Z_STRLEN_P(action_zval); + action = (char*)nr_alloca(alen + 1); + nr_strxcpy(action, Z_STRVAL_P(action_zval), alen); } if ((0 == clen) && (0 == alen)) { @@ -249,92 +119,64 @@ NR_PHP_WRAPPER(nr_cakephp_name_the_wt_2) { NR_NOT_OK_TO_OVERWRITE); end: - nr_php_arg_release(&arg1); nr_php_scope_release(&this_var); + nr_php_zval_free(&request); + nr_php_zval_free(&action_zval); } NR_PHP_WRAPPER_END /* - * CakePHP 1.2, 1.3 - * - * Dispatch::cakeError will be called if there is a problem during dispatch - * (action or controller not found). - * - * CakePHP 1.x is end-of-life and no longer supported by the agent. - * Cake PHP 1.x does not support PHP 8+ and this wrapper is not updated for OAPI - * compatibility. + * CakePHP 4.0+ * + * Report errors and exceptions caught by CakePHP's error handler. */ -NR_PHP_WRAPPER(nr_cakephp_problem_1) { - const char* name = "Dispatcher::cakeError"; +NR_PHP_WRAPPER(nr_cakephp_error_handler_wrapper) { + zval* exception = NULL; + char* request_uri = nr_php_get_server_global("REQUEST_URI"); - (void)wraprec; NR_UNUSED_SPECIALFN; + (void)wraprec; NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_CAKEPHP); - nr_txn_set_path("CakePHP", NRPRG(txn), name, NR_PATH_TYPE_ACTION, - NR_NOT_OK_TO_OVERWRITE); - - NR_PHP_WRAPPER_CALL; -} -NR_PHP_WRAPPER_END - -/* - * CakePHP 2.0+ - * - * If the action or controller is not found during the dispatch process, the - * appropriate Exception will be created and thrown. We wrap the CakeException - * constructor instead of the Exception handler, since CakePHP allows for the - * handler to be completely replaced. - * - * CakePHP 2.x is end-of-life and in maintenance mode (critical bugfixes only). - * As such, functionality added in PHP 7.1+ is not well supported. - * - * txn naming scheme: - * In this case, `nr_txn_set_path` is called before `NR_PHP_WRAPPER_CALL` with - * `NR_NOT_OK_TO_OVERWRITE` and as this corresponds to calling the wrapped - * function in func_begin it needs to be explicitly set as a before_callback to - * ensure OAPI compatibility. This entails that the first wrapped call gets to - * name the txn. - */ -NR_PHP_WRAPPER(nr_cakephp_problem_2) { - const char* name = "Exception"; - - (void)wraprec; - NR_UNUSED_SPECIALFN; + exception = nr_php_arg_get(1, NR_EXECUTE_ORIG_ARGS); + if (!nr_php_is_zval_valid_object(exception)) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s: exception is NULL or not an object", + __func__); + goto end; + } - NR_PHP_WRAPPER_REQUIRE_FRAMEWORK(NR_FW_CAKEPHP); + if (NR_SUCCESS + != nr_php_error_record_exception( + NRPRG(txn), exception, nr_php_error_get_priority(E_ERROR), true, + "Uncaught exception ", &NRPRG(exception_filters))) { + nrl_verbosedebug(NRL_FRAMEWORK, "%s: unable to record exception", __func__); + } - nr_txn_set_path("CakePHP", NRPRG(txn), name, NR_PATH_TYPE_ACTION, - NR_NOT_OK_TO_OVERWRITE); + if (NULL != request_uri) { + nr_txn_set_path("CakePHP Exception", NRPRG(txn), request_uri, NR_PATH_TYPE_URI, + NR_OK_TO_OVERWRITE); + } else { + nrl_verbosedebug(NRL_FRAMEWORK, "%s: request uri is NULL", __func__); + } - NR_PHP_WRAPPER_CALL; +end: + nr_php_arg_release(&exception); + nr_free(request_uri); } NR_PHP_WRAPPER_END /* - * Enable CakePHP 1.2, 1.3 - */ -void nr_cakephp_enable_1(TSRMLS_D) { - nr_php_wrap_user_function(NR_PSTR("Component::initialize"), - nr_cakephp_name_the_wt_pre20 TSRMLS_CC); - nr_php_wrap_user_function(NR_PSTR("Dispatcher::cakeError"), - nr_cakephp_problem_1 TSRMLS_CC); -} - -/* - * Enable CakePHP 2.0+ + * Enable CakePHP 4.0+ */ -void nr_cakephp_enable_2(TSRMLS_D) { - nr_php_wrap_user_function(NR_PSTR("Controller::invokeAction"), - nr_cakephp_name_the_wt_2 TSRMLS_CC); -#if ZEND_MODULE_API_NO >= ZEND_8_0_X_API_NO \ - && !defined OVERWRITE_ZEND_EXECUTE_DATA - nr_php_wrap_user_function_before_after_clean( - NR_PSTR("CakeException::__construct"), nr_cakephp_problem_2, NULL, NULL); -#else - nr_php_wrap_user_function(NR_PSTR("CakeException::__construct"), - nr_cakephp_problem_2 TSRMLS_CC); -#endif +void nr_cakephp_enable(TSRMLS_D) { + nr_php_wrap_user_function( + NR_PSTR("Cake\\Controller\\Controller::invokeAction"), + nr_cakephp_name_the_wt_4); + nr_php_wrap_user_function( + NR_PSTR( + "Cake\\Error\\Middleware\\ErrorHandlerMiddleware::handleException"), + nr_cakephp_error_handler_wrapper); + nr_txn_suggest_package_supportability_metric(NRPRG(txn), PHP_PACKAGE_NAME, + PHP_PACKAGE_VERSION_UNKNOWN); } diff --git a/agent/fw_hooks.h b/agent/fw_hooks.h index c4500aeb2..711c3b618 100644 --- a/agent/fw_hooks.h +++ b/agent/fw_hooks.h @@ -12,13 +12,7 @@ */ #include "php_execute.h" -extern void nr_cakephp_enable_1(TSRMLS_D); -extern void nr_cakephp_enable_2(TSRMLS_D); -extern nr_framework_classification_t nr_cakephp_special_1( - const char* filename TSRMLS_DC); -extern nr_framework_classification_t nr_cakephp_special_2( - const char* filename TSRMLS_DC); - +extern void nr_cakephp_enable(TSRMLS_D); extern void nr_codeigniter_enable(TSRMLS_D); extern int nr_drupal_is_framework(nrframework_t fw); diff --git a/agent/php_execute.c b/agent/php_execute.c index e8e0db9ca..058fea30c 100644 --- a/agent/php_execute.c +++ b/agent/php_execute.c @@ -331,15 +331,8 @@ typedef struct _nr_framework_table_t { */ // clang-format: off static const nr_framework_table_t all_frameworks[] = { - /* - * Watch out: - * cake1.2 and cake1.3 use a subdirectory named 'cake' (lower case) - * cake2.0 and on use a subdirectory named 'Cake' (upper case file name) - */ - {"CakePHP", "cakephp", NR_PSTR("cake/libs/object.php"), nr_cakephp_special_1, - nr_cakephp_enable_1, NR_FW_CAKEPHP}, - {"CakePHP", "cakephp", NR_PSTR("cake/core/app.php"), nr_cakephp_special_2, - nr_cakephp_enable_2, NR_FW_CAKEPHP}, + {"CakePHP", "cakephp", NR_PSTR("cakephp/src/core/functions.php"), 0, + nr_cakephp_enable, NR_FW_CAKEPHP}, /* * Watch out: frameworks or CMS' build on top of CodeIgniter might not get @@ -522,8 +515,6 @@ static nr_library_table_t libraries[] = { * with other frameworks or even without a framework at all. */ {"Laminas_Http", NR_PSTR("laminas-http/src/client.php"), nr_laminas_http_enable}, - - {"CakePHP3", NR_PSTR("cakephp/src/core/functions.php"), NULL}, }; // clang-format: on diff --git a/axiom/nr_version.c b/axiom/nr_version.c index 2c950be4f..5f09c86a7 100644 --- a/axiom/nr_version.c +++ b/axiom/nr_version.c @@ -23,7 +23,6 @@ /* * Current version naming scheme is gemstones * - * echinacea 03Oct2022 (10.2) * freesia 03Nov2022 (10.3) * goldenrod 12Dec2022 (10.4) * hydrangea 18Jan2023 (10.5) @@ -47,8 +46,9 @@ * zinnia 30Jul2024 (11.0) * amethyst 26Aug2024 (11.1) * bowenite 30Sep2024 (11.2) + * corundum 21Oct2024 (11.3) */ -#define NR_CODENAME "corundum" +#define NR_CODENAME "diamond" const char* nr_version(void) { return NR_STR2(NR_VERSION); diff --git a/docker-compose.yaml b/docker-compose.yaml index 2ea1d11d3..21044c7c7 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -2,7 +2,6 @@ # Copyright 2021 New Relic Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # -version: '3.8' services: # The Database mysqldb: @@ -79,7 +78,8 @@ services: build: context: . dockerfile: files/Dockerfile - user: ${UID}:${GID} + args: + PHP_VER: ${PHP:-8.3} environment: MEMCACHE_HOST: memcached diff --git a/docs/dev_environment.md b/docs/dev_environment.md index 7e6940d05..15948fc9f 100644 --- a/docs/dev_environment.md +++ b/docs/dev_environment.md @@ -6,19 +6,38 @@ The dockerized development environment prototype allows contributors to both dev docker-compose spins up `mysql` and `redis` and other databases in separate containers. -Two environment variables to note: -`NEWRELIC_LICENSE_KEY` is required to run the integration tests and should be set to your NR license key. -If your collector isn’t the default (collector.newrelic.com), set the `NEWRELIC_COLLECTOR_HOST` to the appropriate value. +## Prerequisites -PHP_VER can also be set to vary the PHP version being used. +### 1. Docker Compose -Set all environment variables prior to running the development environment. +Dockerized development environment for the New Relic PHP Agent uses following Docker Compose services as a runtime platform. So you need `docker` with `docker compose` installed. + +### 2. Environment variables + +Dockerized development environment for the New Relic PHP Agent needs a valid license key available in `NEW_RELIC_LICENSE_KEY` environment variable. +This environment variable must be set prior to starting Dockerized development environment for the New Relic PHP Agent. The easiest way to set +`NEW_RELIC_LICENSE_KEY` environment variable is via `.env` file. Simply create `.env` file in the top level directory, and add definition +of `NEW_RELIC_LICENSE_KEY` environment variable there, e.g.: +``` +NEW_RELIC_LICENSE_KEY=... +``` + +The second, optional environment variable, that controls PHP version in Dockerized development environment for the New Relic PHP Agent is `PHP`. `PHP` defaults to latest PHP supported by the agent. +This environment variable can be provided at the time when Dockerized development environment for the New Relic PHP Agent is started, e.g.: +``` +make dev-shell PHP=8.2 +``` ## Options for using the environment -## With a shell environment +### With a shell environment + +To start the dev environment type `make dev-shell`. This will spin up `devenv` service in `agent-devenv` container, with: + - latest PHP supported by the agent (this can be overriden with `PHP` environment variable like this: `make dev-shell PHP=8.2`) + - all the tools needed to build the agent + - all the tools needed to run unit tests + - all the tools and supporting services to run integration tests -To start the dev environment type `make dev-shell`. This will create a set of docker containers. A prompt will open and you’ll be able to compile and run all `make` commands right away with no additional setup (for example: `make -j4 all` or `make -j4 valgrind` or `make -j4 run_tests`). After compiling the agent, the integration tests can be run using the `integration_runner`. @@ -31,27 +50,27 @@ To end the session type `exit`. You can run `make dev-stop` to stop the docker- In the shell, you can run all `make` commands as you normally would. -## Build only +### Build only `make dev-build` -## Unit Tests only +### Unit Tests only `make dev-unit tests` -## Integration Tests only +### Integration Tests only `make dev-integration-tests` -## Build and test all +### Build and test all `make dev-all` -## Stop all containers +### Stop all containers `make dev-stop` -# Next steps and issues +## Next steps and issues -## There is possibly some incompatibility with mysql in the main build container as one of the mysql unit tests fails. Unless this is resolved, It might make sense at a future point to have the integration tests run from a different container than the build container. +### There is possibly some incompatibility with mysql in the main build container as one of the mysql unit tests fails. Unless this is resolved, It might make sense at a future point to have the integration tests run from a different container than the build container. diff --git a/files/Dockerfile b/files/Dockerfile index 4b50bebb8..3081cf1ab 100644 --- a/files/Dockerfile +++ b/files/Dockerfile @@ -14,95 +14,65 @@ FROM php:${PHP_VER:-8.3} RUN docker-php-source extract ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update -RUN apt-get install -y build-essential - -# -# PHP dependencies -# -RUN apt-get update \ - && apt-get -y install gcc git netcat-openbsd \ - libpcre3 libpcre3-dev psmisc automake libtool \ - insserv procps vim ${PHP_USER_SPECIFIED_PACKAGES} \ - zlib1g-dev libmcrypt-dev +RUN apt-get update && apt-get install -y --no-install-recommends \ +# Install build entrypoint - make: + make \ +# Makefile's default shell: + bash \ +# git; techincally not needed to build agent but is required for successfull +# processing of top level Makefile: +# - make/version.mk if GIT_COMMIT is not defined, git is used to compute it: + git \ +# The following are required to build PHP extension: + $PHPIZE_DEPS \ +# valgrind, awk; required for agent-valgrind and axiom-valgrind targets + valgrind gawk \ +# Other useful developer tools: + vim lcov gdb strace ccache procps psmisc curl wget bzip2 zip unzip perl sqlite3 openssl \ +# Other build dependencies: + argon2 \ + automake \ + autotools-dev \ + dnsutils \ + gyp \ + insserv \ + libc6 libc6-dev libc6-dbg \ + libcurl4-openssl-dev \ + libedit-dev \ + libghc-argon2-dev \ + libgtest-dev \ + libmcrypt-dev \ + libonig-dev \ + libpcre3 libpcre3-dev \ + libreadline-dev \ + libssl-dev \ + libsqlite3-dev \ + libtool \ + libxml2 libxml2-dev \ + locales \ + locales-all \ + netcat-openbsd \ + python3-yaml \ + ${PHP_USER_SPECIFIED_PACKAGES} \ + zlib1g-dev # pgsql extension -RUN apt-get install -y libpq-dev +RUN apt-get install -y --no-install-recommends libpq-dev RUN docker-php-ext-install pgsql -# -# Other tools -# -RUN apt-get install -y gdb valgrind libcurl4-openssl-dev pkg-config libpq-dev libedit-dev libreadline-dev git - -# -# Install other packages. -# -RUN apt-get update && apt-get install -y \ - autoconf \ - autotools-dev \ - build-essential \ - bzip2 \ - ccache \ - curl \ - dnsutils \ - git \ - gyp \ - lcov \ - libc6 \ - libc6-dbg \ - libc6-dev \ - libgtest-dev \ - libtool \ - locales \ - locales-all \ - make \ - perl \ - strace \ - python-dev-is-python3 \ - python3-yaml \ - sqlite3 \ - libsqlite3-dev \ - openssl \ - libxml2 \ - libxml2-dev \ - libonig-dev \ - libssl-dev \ - unzip \ - wget \ - zip && apt-get clean - -# -# Download and install Go -# -RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && \ - wget https://go.dev/dl/go1.21.1.linux-${arch}.tar.gz -O- | tar -C /usr/local -zxvf -; - -RUN ln -s /usr/local/go/bin/go /usr/bin/go +# install latest go to work with the daemon +COPY --from=golang /usr/local/go /usr/local/go +ENV PATH /usr/local/go/bin:$PATH # -# If the debian version is jessie, don't install argon2 +# If the debian version is buster, don't install python-dev-is-python3 # -RUN if [ -z "$(grep '^8\.' /etc/debian_version)" ]; then \ - apt-get install -y argon2 libghc-argon2-dev; \ +RUN if [ -z "$(grep '^10\.' /etc/debian_version)" ]; then \ + apt-get install -y --no-install-recommends python-dev-is-python3; \ fi # install composer -WORKDIR /usr/src - -# based on https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md -RUN \ - EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" \ - && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \ - && ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" \ - && if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; \ - then \ - >&2 echo 'ERROR: Invalid installer checksum'; \ - rm composer-setup.php; \ - exit 1; \ - fi \ - && php composer-setup.php \ - && php -r "unlink('composer-setup.php');" +COPY --from=composer ["/usr/bin/composer", "/usr/bin/composer"] # # The explain plan in the sql tests contain partition/filtered properties @@ -121,8 +91,16 @@ RUN \ # the mysql tests a separate machine running mysql server 5.6 is required. RUN docker-php-ext-install pdo pdo_mysql -# redis -RUN pecl install redis && docker-php-ext-enable redis +# install redis extension required by test_redis: +RUN \ + php_cmp=$(php -r "echo version_compare(PHP_VERSION, '7.4.0', '>=');"); \ + if [ "$php_cmp" = 1 ]; then \ + # install latest redis for PHPs >= 7.4 + echo 'no' | pecl install redis; \ + else \ + # install redis-4.3.0 - last one with support for php 7.2 + echo 'no' | pecl install redis-4.3.0; \ + fi && docker-php-ext-enable redis # memcache # Pre 8.0 requires 4.0.5.2 @@ -135,7 +113,7 @@ RUN \ fi # memcached -RUN apt-get install -y libmemcached-dev +RUN apt-get install -y --no-install-recommends libmemcached-dev RUN pecl install memcached && docker-php-ext-enable memcached # uopz @@ -152,13 +130,9 @@ RUN \ # install predis # installation will be in /usr/src/vendor/predis/predis # which is value which should be used for PREDIS_HOME -RUN php composer.phar require "predis/predis" -RUN php composer.phar update - -# -# install composer and make executable so it can be used in dev env -# -RUN cp composer.phar /usr/local/bin/composer && chmod +x /usr/local/bin/composer +WORKDIR /usr/src +RUN composer require "predis/predis" +RUN composer update # # These args need to be repeated so we can propagate the VARS within this build context. @@ -174,5 +148,10 @@ ENV PS1="New Relic > " RUN echo 'alias integ="/usr/src/myapp/bin/integration_runner -agent /usr/src/myapp/agent/.libs/newrelic.so"' >> ~/.bashrc \ && echo 'alias rebuild="make -C agent clean && rm agent/Makefile && make && make tests"' >> ~/.bashrc +ARG USER=developer +ARG UID=501 +ARG GID=20 +RUN useradd --uid ${UID} --gid ${GID} --shell /bin/bash --create-home ${USER} +USER ${USER} WORKDIR /usr/src/myapp CMD ["bash"] diff --git a/files/set_path.sh b/files/set_path.sh index 3a5cc965c..0b9e88c48 100644 --- a/files/set_path.sh +++ b/files/set_path.sh @@ -17,11 +17,6 @@ case ":$PATH:" in *) PATH=/usr/local/bin:$PATH esac -case ":$PATH:" in - *:/usr/local/go/bin:*) ;; - *) PATH=/usr/local/go/bin:$PATH -esac - export PATH diff --git a/trivy.yaml b/trivy.yaml new file mode 100644 index 000000000..e27bd8157 --- /dev/null +++ b/trivy.yaml @@ -0,0 +1,18 @@ +db: + repository: + - mirror.gcr.io/aquasec/trivy-db:2 + +scan: + scanners: + - vuln + - misconfig + skip-dirs: vendor + +severities: + - CRITICAL + - HIGH + - MEDIUM + - LOW + +vulnerability: + ignore-unfixed: true