Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Rest_Api_Code_Deployment_Logs_Controller
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 register_routes
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 get_log_entry
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 verify_xml_rpc_signature
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Code Deployment logs REST API endpoint.
4 *
5 * @package endpoints
6 */
7
8/**
9 * Code Deployment logs REST API endpoint.
10 *
11 * @package endpoints
12 */
13class Rest_Api_Code_Deployment_Logs_Controller extends WP_REST_Controller {
14
15    /**
16     * The API namespace.
17     *
18     * @var string
19     */
20    protected $namespace = 'wpcomsh/v1';
21
22    /**
23     * The API REST base URL.
24     *
25     * @var string
26     */
27    protected $rest_base = 'code-deployments';
28
29    /**
30     * Registers the routes for the objects of the controller.
31     */
32    public function register_routes() {
33        // Get a single entry from the log file based on the command identifier.
34        // GET https://<atomic-site-address>/wp-json/wpcomsh/v1/code-deployments/{deployment_id}/runs/{run_id}/logs/{command_identifier}
35        register_rest_route(
36            $this->namespace,
37            '/' . $this->rest_base . '/(?P<deployment_id>\d+)/runs/(?P<run_id>\d+)/logs/(?P<command_identifier>[\w-]+)',
38            array(
39                'methods'             => WP_REST_Server::READABLE,
40                'callback'            => array( $this, 'get_log_entry' ),
41                'permission_callback' => array( $this, 'verify_xml_rpc_signature' ),
42            )
43        );
44    }
45
46    /**
47     * Get a single entry from the log file based on the command identifier.
48     *
49     * @param WP_Rest_Request $request The request object.
50     *
51     * @return WP_Error|WP_REST_Response
52     */
53    public function get_log_entry( WP_Rest_Request $request ) {
54        $log_path = sprintf( '/srv/htdocs/.code-deployments/%s/%s-log.json', $request['deployment_id'], $request['run_id'] );
55        if ( ! file_exists( $log_path ) ) {
56            return new WP_Error( 'file_not_found', 'The log file was not found.', array( 'status' => 404 ) );
57        }
58
59        $logs = json_decode( file_get_contents( $log_path ), true ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
60
61        if ( ! $logs ) {
62            return new WP_Error( 'invalid_json', 'The log file is not valid json.', array( 'status' => 500 ) );
63        }
64
65        foreach ( $logs as $log ) {
66            if ( $log['commandIdentifier'] === $request['command_identifier'] ) {
67                return new WP_REST_Response( $log );
68            }
69        }
70
71        return new WP_Error( 'command_not_found', 'The command identifier was not found in the log.', array( 'status' => 404 ) );
72    }
73
74    /**
75     * Checks if a given request has the correct signature. We only
76     * want to accept "internal" requests from WPCOM.
77     *
78     * @param WP_REST_Request $request Full details about the request.
79     * @return bool True if the request has access, false otherwise.
80     */
81    public function verify_xml_rpc_signature( $request ) { //phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass, VariableAnalysis.CodeAnalysis.VariableAnalysis
82        return method_exists( 'Automattic\Jetpack\Connection\Manager', 'verify_xml_rpc_signature' ) && ( new Automattic\Jetpack\Connection\Manager() )->verify_xml_rpc_signature();
83    }
84}