Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -479,20 +479,20 @@ function agents_conversation_sessions_owned_session( string $session_id, array $
if ( $context['store'] instanceof WP_Agent_Principal_Conversation_Session_Reader ) {
$session = $context['store']->get_session_for_owner( $workspace, $context['owner'], $session_id );
if ( ! is_array( $session ) ) {
return new \WP_Error( 'agents_conversation_session_not_found', 'Conversation session not found.' );
return new \WP_Error( 'agents_conversation_session_not_found', 'Conversation session not found.', array( 'status' => 404 ) );
}

return agents_conversation_sessions_array_value( $session );
}

$session = $context['store']->get_session( $session_id );
if ( ! is_array( $session ) ) {
return new \WP_Error( 'agents_conversation_session_not_found', 'Conversation session not found.' );
return new \WP_Error( 'agents_conversation_session_not_found', 'Conversation session not found.', array( 'status' => 404 ) );
}

$session = agents_conversation_sessions_array_value( $session );
if ( ! agents_conversation_sessions_session_matches_owner( $session, $context['owner'] ) && ! agents_conversation_sessions_can_manage_any() ) {
return new \WP_Error( 'agents_conversation_session_forbidden', 'The current principal cannot access this conversation session.' );
return new \WP_Error( 'agents_conversation_session_forbidden', 'The current principal cannot access this conversation session.', array( 'status' => 403 ) );
}

return $session;
Expand Down
6 changes: 5 additions & 1 deletion tests/agents-conversation-session-abilities-smoke.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@

if ( ! class_exists( 'WP_Error' ) ) {
class WP_Error {
public function __construct( private string $code = '', private string $message = '' ) {}
public function __construct( private string $code = '', private string $message = '', private mixed $data = null ) {}
public function get_error_code(): string { return $this->code; }
public function get_error_message(): string { return $this->message; }
public function get_error_data(): mixed { return $this->data; }
}
}

Expand Down Expand Up @@ -255,6 +256,7 @@ public function update_title( string $session_id, string $title ): bool {
$forbidden = agents_get_conversation_session( array( 'principal' => $other_principal, 'session_id' => 's-1' ) );
smoke_assert( true, $forbidden instanceof WP_Error, 'get blocks sessions owned by another user', $failures, $passes );
smoke_assert( 'agents_conversation_session_forbidden', $forbidden instanceof WP_Error ? $forbidden->get_error_code() : '', 'forbidden error code', $failures, $passes );
smoke_assert( 403, $forbidden instanceof WP_Error ? ( $forbidden->get_error_data()['status'] ?? null ) : null, 'forbidden error carries REST status', $failures, $passes );

$audience_without_owner = WP_Agent_Execution_Principal::audience( 'audience:public', 'demo-agent' );
$owner_required = agents_list_conversation_sessions( array( 'principal' => $audience_without_owner ) );
Expand Down Expand Up @@ -369,6 +371,7 @@ public function update_title( string $session_id, string $title ): bool { $this-
$other_audience = WP_Agent_Execution_Principal::audience( 'audience:public', 'demo-agent', WP_Agent_Execution_Principal::REQUEST_CONTEXT_REST, array(), null, null, array(), 'browser:two' );
$blocked_owner = agents_get_conversation_session( array( 'principal' => $other_audience, 'session_id' => 'p-1', 'workspace' => array( 'workspace_type' => 'site', 'workspace_id' => '42' ) ) );
smoke_assert( 'agents_conversation_session_not_found', $blocked_owner instanceof WP_Error ? $blocked_owner->get_error_code() : '', 'principal owner key blocks other audience sessions', $failures, $passes );
smoke_assert( 404, $blocked_owner instanceof WP_Error ? ( $blocked_owner->get_error_data()['status'] ?? null ) : null, 'foreign principal read carries non-enumerating REST status', $failures, $passes );

// REST callers cannot impersonate other owners via the principal field — the
// principal is resolved from the request, not from the body.
Expand All @@ -392,6 +395,7 @@ public function update_title( string $session_id, string $title ): bool { $this-
)
);
smoke_assert( 'agents_conversation_session_not_found', $forged_get instanceof WP_Error ? $forged_get->get_error_code() : '', 'REST principal passthrough is ignored on get', $failures, $passes );
smoke_assert( 404, $forged_get instanceof WP_Error ? ( $forged_get->get_error_data()['status'] ?? null ) : null, 'missing REST session carries not-found status', $failures, $passes );

$forged_list = agents_list_conversation_sessions(
array(
Expand Down