-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtrait-wp-codebox-abilities-provider-adapter.php
More file actions
139 lines (119 loc) · 6.88 KB
/
Copy pathtrait-wp-codebox-abilities-provider-adapter.php
File metadata and controls
139 lines (119 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php
/**
* WP_Codebox_Abilities_Provider_Adapter implementation.
*
* @package WPCodebox
*/
defined( 'ABSPATH' ) || exit;
trait WP_Codebox_Abilities_Provider_Adapter {
/** @param array<string,mixed> $input Ability input. @return array<string,mixed>|WP_Error */
public static function execute_browser_provider_request( array $input ): array|WP_Error {
$operation = trim( (string) ( $input['operation'] ?? '' ) );
if ( '' === $operation ) {
return new WP_Error( 'wp_codebox_browser_provider_operation_required', 'Browser provider requests must include an operation.', array( 'status' => 400, 'schema' => 'wp-codebox/browser-provider-error/v1' ) );
}
$request_payload = is_array( $input['request'] ?? null ) ? $input['request'] : array();
if ( empty( $request_payload ) ) {
return new WP_Error( 'wp_codebox_browser_provider_request_required', 'Browser provider requests must include a generic request object.', array( 'status' => 400, 'schema' => 'wp-codebox/browser-provider-error/v1' ) );
}
$inheritance_payload = self::browser_inheritance_resolution_payload( $input );
if ( is_wp_error( $inheritance_payload ) ) {
return $inheritance_payload;
}
$inheritance = $inheritance_payload['inheritance'];
$connector = self::browser_provider_request_connector( $input, $inheritance );
if ( empty( $connector ) ) {
return new WP_Error( 'wp_codebox_browser_provider_connector_required', 'Browser provider requests require a resolved connector scope.', array( 'status' => 403, 'schema' => 'wp-codebox/browser-provider-error/v1' ) );
}
$adapter_request = array(
'schema' => 'wp-codebox/browser-provider-adapter-request/v1',
'operation' => $operation,
'provider' => self::browser_provider( $input, $inheritance ),
'model' => self::browser_model( $input, $inheritance ),
'connector' => $connector,
'context' => self::browser_provider_request_context( $input ),
'request' => self::redact_provider_metadata( $request_payload ),
);
/**
* Executes a connector-scoped browser provider request on the parent site.
*
* Adapters must resolve credentials server-side from the connector/context they
* trust. WP Codebox passes only redacted connector provenance and request data;
* raw provider credentials must not be returned in the response envelope.
*
* @param mixed $response Adapter response, or null when unhandled.
* @param array<string,mixed> $adapter_request Generic redacted provider request.
* @param array<string,mixed> $input Original ability input.
*/
$response = apply_filters( 'wp_codebox_browser_provider_request', null, $adapter_request, $input );
if ( null === $response ) {
return new WP_Error( 'wp_codebox_browser_provider_adapter_missing', 'No browser provider adapter handled this connector-scoped request.', array( 'status' => 501, 'schema' => 'wp-codebox/browser-provider-error/v1', 'operation' => $operation, 'provider' => $adapter_request['provider'], 'model' => $adapter_request['model'], 'connector' => $connector ) );
}
if ( is_wp_error( $response ) ) {
return new WP_Error( $response->get_error_code(), $response->get_error_message(), self::redact_provider_metadata( array_merge( array( 'schema' => 'wp-codebox/browser-provider-error/v1' ), is_array( $response->get_error_data() ) ? $response->get_error_data() : array() ) ) );
}
if ( ! is_array( $response ) ) {
return new WP_Error( 'wp_codebox_browser_provider_adapter_invalid_response', 'Browser provider adapters must return an array response envelope or WP_Error.', array( 'status' => 502, 'schema' => 'wp-codebox/browser-provider-error/v1' ) );
}
return self::normalize_browser_provider_response( $response, $adapter_request );
}
/** @param array<string,mixed> $input Ability input. @param array{connectors:array<int,array<string,mixed>>,settings:array<int,array<string,mixed>>} $inheritance @return array<string,mixed> */
private static function browser_provider_request_connector( array $input, array $inheritance ): array {
$requested_name = trim( (string) ( $input['connector'] ?? '' ) );
foreach ( $inheritance['connectors'] as $connector ) {
$name = trim( (string) ( $connector['name'] ?? '' ) );
if ( '' === $name ) {
continue;
}
if ( '' !== $requested_name && $name !== $requested_name ) {
continue;
}
return self::redact_provider_metadata( $connector );
}
return array();
}
/** @param array<string,mixed> $input Ability input. @return array<string,mixed> */
private static function browser_provider_request_context( array $input ): array {
$authorization = self::trusted_orchestrator_authorization( $input, self::BROWSER_CONNECTOR_REQUEST_SCOPE );
$context = array_filter(
array(
'session_id' => trim( (string) ( $input['sandbox_session_id'] ?? $input['session_id'] ?? '' ) ),
'caller_session_id' => trim( (string) ( $input['caller_session_id'] ?? '' ) ),
'job_id' => trim( (string) ( $input['job_id'] ?? '' ) ),
'caller' => (string) ( $authorization['caller'] ?? '' ),
'authorization_scope' => (string) ( $authorization['scope'] ?? '' ),
'orchestrator' => is_array( $input['orchestrator'] ?? null ) ? $input['orchestrator'] : array(),
),
static fn( mixed $value ): bool => '' !== $value && array() !== $value
);
return self::redact_provider_metadata( $context );
}
/** @param array<string,mixed> $response Adapter response. @param array<string,mixed> $adapter_request Adapter request. @return array<string,mixed> */
private static function normalize_browser_provider_response( array $response, array $adapter_request ): array {
$redacted_response = self::redact_provider_metadata( $response );
return array_filter(
array(
'success' => true,
'schema' => 'wp-codebox/browser-provider-adapter-response/v1',
'operation' => $adapter_request['operation'],
'provider' => $adapter_request['provider'],
'model' => $adapter_request['model'],
'connector' => is_array( $adapter_request['connector'] ?? null ) ? $adapter_request['connector'] : array(),
'response' => is_array( $redacted_response['response'] ?? null ) ? $redacted_response['response'] : $redacted_response,
'audit' => array(
'schema' => 'wp-codebox/browser-provider-audit/v1',
'operation' => $adapter_request['operation'],
'provider' => $adapter_request['provider'],
'model' => $adapter_request['model'],
'connector' => is_array( $adapter_request['connector'] ?? null ) ? $adapter_request['connector'] : array(),
'request' => is_array( $adapter_request['request'] ?? null ) ? $adapter_request['request'] : array(),
'response' => $redacted_response,
),
),
static fn( mixed $value ): bool => '' !== $value && array() !== $value
);
}
private static function redact_provider_metadata( mixed $value ): mixed {
return WP_Codebox_Redaction_Policy::redact_array( 'provider_proxy', $value );
}
}