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
73 changes: 38 additions & 35 deletions data-machine-code.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
* Version: 0.47.56
* Requires at least: 6.9
* Requires PHP: 8.2
* Requires Plugins: data-machine
* Author: Chris Huber, extrachill
* Author URI: https://chubes.net
* License: GPL v2 or later
Expand All @@ -25,10 +24,6 @@
// PSR-4 Autoloading.
require_once __DIR__ . '/vendor/autoload.php';

// Bundle artifact types must be registered as soon as the plugin is loaded so
// Data Machine can validate DMC-owned artifacts during early import paths.
( new \DataMachineCode\Bundle\WorkspacePreloadArtifact() )->register();

/**
* Install DMC-owned database tables.
*/
Expand Down Expand Up @@ -63,12 +58,46 @@ function datamachine_code_maybe_upgrade_schema(): void {
}
add_action('plugins_loaded', 'datamachine_code_maybe_upgrade_schema', 5);

/**
* Whether Data Machine-specific integration surfaces are available.
*/
function datamachine_code_has_datamachine_integration(): bool {
return class_exists('DataMachine\Abilities\PermissionHelper');
}

/**
* Register optional Data Machine integrations.
*/
function datamachine_code_register_datamachine_integrations(): void {
static $registered = false;

if ( $registered || ! datamachine_code_has_datamachine_integration() ) {
return;
}

$registered = true;

// Bundle artifact types are Data Machine-specific and are only registered
// when the bundle importer substrate is present.
( new \DataMachineCode\Bundle\WorkspacePreloadArtifact() )->register();

// Project active workspace identity into Data Machine's engine_data snapshot.
\DataMachineCode\Runtime\ActiveWorkspaceProjector::register();

if ( class_exists('DataMachine\Core\Steps\HandlerRegistrationTrait') ) {
new \DataMachineCode\Handlers\GitHub\GitHub();
new \DataMachineCode\Handlers\GitHub\GitHubIssuePublish();
new \DataMachineCode\Handlers\GitHub\GitHubPullRequestPublish();
new \DataMachineCode\Handlers\GitHub\GitHubUpsert();
}
}

/**
* Bootstrap the plugin after all plugins are loaded.
*
* Data Machine core must be active — check at plugins_loaded time
* (not at plugin load time, since load order is alphabetical and
* data-machine-code loads before data-machine).
* Core workspace/GitHub/Agents API surfaces do not require Data Machine.
* Data Machine-specific handlers and memory/runtime hooks register through
* datamachine_code_register_datamachine_integrations() when available.
*/
function datamachine_code_bootstrap() {
static $bootstrapped = false;
Expand All @@ -77,22 +106,6 @@ function datamachine_code_bootstrap() {
return;
}

if ( ! class_exists('DataMachine\Abilities\PermissionHelper') ) {
add_action('init', 'datamachine_code_bootstrap', 1);
add_action('wp_abilities_api_init', 'datamachine_code_bootstrap', 1);

add_action(
'admin_notices', function () {
?>
<div class="notice notice-error">
<p><?php esc_html_e('Data Machine Code requires Data Machine core plugin to be installed and activated.', 'data-machine-code'); ?></p>
</div>
<?php
}
);
return;
}

$bootstrapped = true;

// Load Abilities (they self-register).
Expand All @@ -104,17 +117,7 @@ function datamachine_code_bootstrap() {
new \DataMachineCode\Abilities\WordPressRuntimeAbilities();
\DataMachineCode\SourceInventory\WorkspaceSourceInventory::register();
\DataMachineCode\AgentsApi\WorkspaceExecutorAdapter::register();

// Project active workspace identity into Data Machine's engine_data
// snapshot at job init. Requires DM's datamachine_engine_snapshot
// filter (added in data-machine v0.10.3); no-op on older DM versions.
\DataMachineCode\Runtime\ActiveWorkspaceProjector::register();

// Load Handlers (they self-register).
new \DataMachineCode\Handlers\GitHub\GitHub();
new \DataMachineCode\Handlers\GitHub\GitHubIssuePublish();
new \DataMachineCode\Handlers\GitHub\GitHubPullRequestPublish();
new \DataMachineCode\Handlers\GitHub\GitHubUpsert();
datamachine_code_register_datamachine_integrations();

// Register ability categories on the correct hook (must happen during wp_abilities_api_categories_init).
add_action('wp_abilities_api_categories_init', 'datamachine_code_register_ability_categories');
Expand Down
2 changes: 1 addition & 1 deletion inc/Abilities/CodeTaskAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\CodeTask\CodeTaskCreator;
use DataMachineCode\CodeTask\EvidencePacket;

Expand Down
32 changes: 13 additions & 19 deletions inc/Abilities/GitHubAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachine\Core\PluginSettings;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\Support\PluginSettings;
use DataMachineCode\GitHub\PrReviewEscalationPolicy;
use DataMachineCode\Support\GitHubCredentialResolver;
use DataMachineCode\Support\RunArtifactBundleFileWriter;
Expand Down Expand Up @@ -1930,28 +1930,22 @@ private static function mergeProvenanceLabels( array $labels ): array {
* Resolve the current Data Machine agent slug when running in agent context.
*/
private static function getCurrentAgentSlug(): string {
if ( method_exists(PermissionHelper::class, 'get_runtime_context') ) {
$agent_slug = self::agentSlugFromContext(PermissionHelper::get_runtime_context());
if ( '' !== $agent_slug ) {
return $agent_slug;
}
$agent_slug = self::agentSlugFromContext(PermissionHelper::get_runtime_context());
if ( '' !== $agent_slug ) {
return $agent_slug;
}

if ( method_exists(PermissionHelper::class, 'get_execution_principal') ) {
$principal = PermissionHelper::get_execution_principal();
if ( is_object($principal) ) {
$agent_slug = self::agentSlugFromContext(method_exists($principal, 'to_array') ? $principal->to_array() : get_object_vars($principal));
if ( '' !== $agent_slug ) {
return $agent_slug;
}
$principal = PermissionHelper::get_execution_principal();
if ( is_object($principal) ) {
$agent_slug = self::agentSlugFromContext(method_exists($principal, 'to_array') ? $principal->to_array() : get_object_vars($principal));
if ( '' !== $agent_slug ) {
return $agent_slug;
}
}

if ( method_exists(PermissionHelper::class, 'get_acting_agent_slug') ) {
$agent_slug = PermissionHelper::get_acting_agent_slug();
if ( is_string($agent_slug) && '' !== trim($agent_slug) ) {
return sanitize_text_field($agent_slug);
}
$agent_slug = PermissionHelper::get_acting_agent_slug();
if ( '' !== trim($agent_slug) ) {
return sanitize_text_field($agent_slug);
}

return '';
Expand Down
2 changes: 1 addition & 1 deletion inc/Abilities/GitSyncAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\GitSync\GitSync;

defined('ABSPATH') || exit;
Expand Down
2 changes: 1 addition & 1 deletion inc/Abilities/WordPressRuntimeAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\Runtime\WordPressRuntimeInspector;

defined('ABSPATH') || exit;
Expand Down
2 changes: 1 addition & 1 deletion inc/Abilities/WorkspaceAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\Workspace\CleanupRunService;
use DataMachineCode\Workspace\RemoteWorkspaceBackend;
use DataMachineCode\Workspace\Workspace;
Expand Down
2 changes: 1 addition & 1 deletion inc/Abilities/WorkspaceDiffAbilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DataMachineCode\Abilities;

use DataMachine\Abilities\PermissionHelper;
use DataMachineCode\Support\PermissionHelper;
use DataMachineCode\Workspace\RemoteWorkspaceBackend;
use DataMachineCode\Workspace\WorkspaceDiff;

Expand Down
10 changes: 8 additions & 2 deletions inc/Support/GitHubCredentialResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

namespace DataMachineCode\Support;

use DataMachine\Core\PluginSettings;
use DataMachineCode\Support\PluginSettings;

defined('ABSPATH') || exit;

Expand Down Expand Up @@ -197,7 +197,13 @@ public static function mintJwt( string $app_id, string $private_key, int $now ):
'iss' => $app_id,
);

$unsigned = self::base64UrlEncode(wp_json_encode($header)) . '.' . self::base64UrlEncode(wp_json_encode($payload));
$header_json = wp_json_encode($header);
$payload_json = wp_json_encode($payload);
if ( ! is_string($header_json) || ! is_string($payload_json) ) {
return new \WP_Error('github_app_jwt_encode_failed', 'GitHub App JWT payload could not be encoded.', array( 'status' => 500 ));
}

$unsigned = self::base64UrlEncode($header_json) . '.' . self::base64UrlEncode($payload_json);
$signature = '';
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- openssl_sign emits warnings for invalid keys; callers receive a WP_Error below.
$ok = @openssl_sign($unsigned, $signature, $private_key, OPENSSL_ALGO_SHA256);
Expand Down
2 changes: 1 addition & 1 deletion inc/Support/GitHubCredentialSettingsMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace DataMachineCode\Support;

use DataMachine\Core\PluginSettings;
use DataMachineCode\Support\PluginSettings;

defined('ABSPATH') || exit;

Expand Down
65 changes: 65 additions & 0 deletions inc/Support/PermissionHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* DMC permission facade.
*
* @package DataMachineCode\Support
*/

namespace DataMachineCode\Support;

defined('ABSPATH') || exit;

/**
* Delegates to Data Machine permissions when available, with a WP fallback.
*/
final class PermissionHelper {

public static function can_manage(): bool {
$class = self::data_machine_permission_helper_class();
$callback = array( $class, 'can_manage' );
if ( is_callable($callback) ) {
return (bool) call_user_func($callback);
}

$allowed = function_exists('current_user_can') ? current_user_can('manage_options') : false;
return (bool) apply_filters('datamachine_code_can_manage', $allowed);
}

/** @return array<string,mixed> */
public static function get_runtime_context(): array {
$class = self::data_machine_permission_helper_class();
$callback = array( $class, 'get_runtime_context' );
if ( is_callable($callback) ) {
$context = call_user_func($callback);
return is_array($context) ? $context : array();
}

return array();
}

public static function get_execution_principal(): mixed {
$class = self::data_machine_permission_helper_class();
$callback = array( $class, 'get_execution_principal' );
if ( is_callable($callback) ) {
return call_user_func($callback);
}

return null;
}

public static function get_acting_agent_slug(): string {
$class = self::data_machine_permission_helper_class();
$callback = array( $class, 'get_acting_agent_slug' );
if ( is_callable($callback) ) {
$agent_slug = call_user_func($callback);
return is_string($agent_slug) ? $agent_slug : '';
}

return '';
}

private static function data_machine_permission_helper_class(): string {
$class = apply_filters('datamachine_code_datamachine_permission_helper_class', '\\DataMachine\\Abilities\\PermissionHelper');
return is_string($class) ? $class : '';
}
}
35 changes: 35 additions & 0 deletions inc/Support/PluginSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/**
* DMC settings facade.
*
* @package DataMachineCode\Support
*/

namespace DataMachineCode\Support;

defined('ABSPATH') || exit;

/**
* Delegates to Data Machine PluginSettings when available, with option fallback.
*/
final class PluginSettings {

public static function get( string $key, mixed $fallback = null ): mixed {
$class = self::data_machine_plugin_settings_class();
$callback = array( $class, 'get' );
if ( is_callable($callback) ) {
return call_user_func($callback, $key, $fallback);
}

if ( function_exists('get_option') ) {
return get_option($key, $fallback);
}

return $fallback;
}

private static function data_machine_plugin_settings_class(): string {
$class = apply_filters('datamachine_code_datamachine_plugin_settings_class', '\\DataMachine\\Core\\PluginSettings');
return is_string($class) ? $class : '';
}
}
Loading
Loading