*/ public function run(): array { $findings = array(); foreach ( $this->agents->all() as $agent ) { $user = get_userdata( $agent->wp_user_id ); if ( ! $user instanceof \WP_User ) { $findings[] = new Finding( $this->id(), Severity::ATTENTION, __( 'An agent linked to a user who no longer exists', 'agentic-daisy-ai-agent-firewall' ), __( 'This agent cannot act, because the WordPress account it authenticates as has been deleted. Relink it to a user, or remove it.', 'agentic-daisy-ai-agent-firewall' ), $agent->name, 'agents', $this->id() . ':orphaned_agent:' . $agent->id ); continue; } $held = $this->privileged_capabilities( $user ); if ( array() === $held ) { continue; } $findings[] = new Finding( $this->id(), Severity::ATTENTION, __( 'An agent that can change the site itself', 'agentic-daisy-ai-agent-firewall' ), sprintf( /* translators: %s: comma-separated list of WordPress capabilities. */ __( 'The account this agent acts as can %s. Policy can narrow what the agent does, but never past this ceiling. Consider linking it to a user with only the capabilities its work needs.', 'agentic-daisy-ai-agent-firewall' ), implode( ', ', $held ) ), sprintf( /* translators: 1: agent name, 2: the user it acts as. */ __( '%1$s (acting as %2$s)', 'agentic-daisy-ai-agent-firewall' ), $agent->name, (string) $user->display_name ), 'agents', $this->id() . ':privileged_agent:' . $agent->id, self::state( $agent->wp_user_id, $held ) ); } return $findings; } /** * The user acted as and the capabilities held, as the finding's state * for scan history: relinking an agent to another administrator is a * change even when the ceiling is the same. Sorted so a change in the * order checked is not a change. * * @param int $user_id Linked user id. * @param list $held Privileged capabilities held. */ private static function state( int $user_id, array $held ): string { sort( $held ); return 'user ' . $user_id . ': ' . implode( ',', $held ); } /** * Which of the capabilities worth naming this user holds. * * @param \WP_User $user The linked user. * @return list */ private function privileged_capabilities( \WP_User $user ): array { $held = array(); foreach ( self::PRIVILEGED as $capability ) { if ( user_can( $user, $capability ) ) { $held[] = $capability; } } return $held; } }