|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +if ( ! defined('ABSPATH') ) { |
| 6 | + define('ABSPATH', __DIR__ . '/fixtures/'); |
| 7 | +} |
| 8 | + |
| 9 | +final class WP_Error { |
| 10 | + public function __construct( private string $code, private string $message = '', private array $data = array() ) {} |
| 11 | + public function get_error_code(): string { return $this->code; } |
| 12 | +} |
| 13 | + |
| 14 | +function is_wp_error( mixed $value ): bool { |
| 15 | + return $value instanceof WP_Error; |
| 16 | +} |
| 17 | + |
| 18 | +$GLOBALS['workspace_git_identity_filter'] = null; |
| 19 | +function apply_filters( string $hook, mixed $value, mixed ...$args ): mixed { |
| 20 | + $filter = $GLOBALS['workspace_git_identity_filter']; |
| 21 | + return 'datamachine_code_git_identity_policy' === $hook && is_callable($filter) ? $filter($value, ...$args) : $value; |
| 22 | +} |
| 23 | + |
| 24 | +require_once dirname(__DIR__) . '/inc/Support/GitHubRemote.php'; |
| 25 | +require_once dirname(__DIR__) . '/inc/Workspace/WorkspaceGitIdentityPolicy.php'; |
| 26 | + |
| 27 | +use DataMachineCode\Workspace\WorkspaceGitIdentityPolicy; |
| 28 | + |
| 29 | +function identity_policy_assert( bool $condition, string $message ): void { |
| 30 | + if ( ! $condition ) { |
| 31 | + throw new RuntimeException($message); |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +function identity_policy_run( string $path, string $command ): array|WP_Error { |
| 36 | + $lines = array(); |
| 37 | + $status = 0; |
| 38 | + exec('GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null git -C ' . escapeshellarg($path) . ' ' . $command . ' 2>&1', $lines, $status); |
| 39 | + return 0 === $status ? array( 'output' => implode("\n", $lines) ) : new WP_Error('git_failed', implode("\n", $lines)); |
| 40 | +} |
| 41 | + |
| 42 | +function identity_policy_output( array|WP_Error $result ): string { |
| 43 | + return is_wp_error($result) ? '' : (string) ($result['output'] ?? ''); |
| 44 | +} |
| 45 | + |
| 46 | +$harness = new class { |
| 47 | + use WorkspaceGitIdentityPolicy; |
| 48 | + public function enforce( string $path ): ?WP_Error { return $this->enforce_repository_git_identity($path); } |
| 49 | + public function configure( string $path ): ?WP_Error { return $this->configure_repository_git_identity($path); } |
| 50 | + private function run_git( string $path, string $command ): array|WP_Error { return identity_policy_run($path, $command); } |
| 51 | +}; |
| 52 | + |
| 53 | +$root = sys_get_temp_dir() . '/dmc-git-identity-' . getmypid() . '-' . bin2hex(random_bytes(4)); |
| 54 | +$primary = $root . '/primary'; |
| 55 | +$worktree = $root . '/primary@identity'; |
| 56 | + |
| 57 | +try { |
| 58 | + mkdir($primary, 0777, true); |
| 59 | + identity_policy_run($primary, 'init -b main'); |
| 60 | + identity_policy_run($primary, '-c user.name=Fixture -c user.email=fixture@example.test commit --allow-empty -m initial'); |
| 61 | + identity_policy_run($primary, 'remote add origin git@github.com:Example-Owner/example-repo.git'); |
| 62 | + identity_policy_run($primary, 'worktree add -b feature/identity ' . escapeshellarg($worktree)); |
| 63 | + |
| 64 | + $GLOBALS['workspace_git_identity_filter'] = static function ( mixed $identity, array $descriptor, string $remote ): ?array { |
| 65 | + identity_policy_assert('Example-Owner/example-repo' === $descriptor['slug'], 'Policy receives the parsed GitHub remote descriptor.'); |
| 66 | + identity_policy_assert('git@github.com:Example-Owner/example-repo.git' === $remote, 'Policy receives the original remote URL.'); |
| 67 | + return array( 'name' => 'Managed Identity', 'email' => 'managed@example.test' ); |
| 68 | + }; |
| 69 | + identity_policy_assert(null === $harness->configure($worktree), 'Policy-backed managed worktree configures a valid identity.'); |
| 70 | + identity_policy_assert('Managed Identity' === trim(identity_policy_output(identity_policy_run($worktree, 'config --get user.name'))), 'Managed worktree uses the policy name.'); |
| 71 | + identity_policy_assert('managed@example.test' === trim(identity_policy_output(identity_policy_run($worktree, 'config --get user.email'))), 'Managed worktree uses the policy email.'); |
| 72 | + identity_policy_assert('' === trim(identity_policy_output(identity_policy_run($primary, 'config --get user.name'))), 'Worktree policy identity does not alter the primary checkout.'); |
| 73 | + identity_policy_assert(null === $harness->enforce($worktree), 'Configured host accepts its configured effective identity.'); |
| 74 | + |
| 75 | + identity_policy_run($worktree, 'config --worktree user.name ' . escapeshellarg('Wrong Identity')); |
| 76 | + identity_policy_assert('repository_git_identity_mismatch' === $harness->enforce($worktree)?->get_error_code(), 'Configured host rejects a mismatched effective identity.'); |
| 77 | + identity_policy_run($worktree, 'config --worktree --unset user.name'); |
| 78 | + identity_policy_assert('repository_git_identity_mismatch' === $harness->enforce($worktree)?->get_error_code(), 'Configured host rejects a missing effective identity.'); |
| 79 | + |
| 80 | + $GLOBALS['workspace_git_identity_filter'] = null; |
| 81 | + $bare = $root . '/bare'; |
| 82 | + mkdir($bare, 0777, true); |
| 83 | + identity_policy_run($bare, 'init -b main'); |
| 84 | + identity_policy_run($bare, 'remote add origin git@github.com:Example-Owner/unconfigured-repo.git'); |
| 85 | + identity_policy_assert(null === $harness->enforce($bare), 'Unconfigured host preserves ambient Git identity behavior.'); |
| 86 | + |
| 87 | + echo "workspace-git-identity-policy: ok\n"; |
| 88 | +} finally { |
| 89 | + if ( is_dir($root) ) { |
| 90 | + exec('rm -rf ' . escapeshellarg($root)); |
| 91 | + } |
| 92 | +} |
0 commit comments