glanzlicht / YouGit-AI

AI-assisted secure code showcases for WordPress — scan, redact and publish GitHub repositories without exposing sensitive IP.

Verified secure showcase
62 Files 855 KB Public size 0 Redacted PHP · Markdown · CSS · JavaScript · PO · YAML

Project overview

YouGit-AI is a verified code showcase with 62 visible project entries across 3 top-level modules. The primary detected language is PHP; protected files remain visible in the structure while their contents stay private.

README

YouGitAI Secure Showcase

AI-assisted secure code showcases for WordPress — scan, redact and publish GitHub repositories without exposing sensitive IP.

YouGitAI Secure Showcase is a WordPress plugin that turns public or private GitHub repositories into employer-friendly portfolio showcases. It combines deterministic secret detection, AI-assisted IP review, manual protection rules, versioned public snapshots and a constrained ChatGPT/MCP review workflow.

The goal is simple: show what you built without turning your portfolio into a blueprint for cloning it.

Highlights

  • GitHub OAuth support for public and private repositories
  • deterministic secret scanning
  • AI-assisted portfolio/IP review
  • manual path, string, regex and symbol-oriented protection rules
  • protected files and folders remain visible as architectural context without exposing their contents
  • visible inline redaction markers in public code views
  • versioned draft/public snapshots
  • human-controlled publication workflow
  • ChatGPT/MCP integration with OAuth
  • OpenAI, Anthropic Claude and Google Gemini support
  • standalone WordPress frontend
  • native Elementor integration
  • German and English localization

Portfolio-aware protection

YouGitAI is designed to distinguish between useful technical evidence and material that should not be public.

Typical review classes include:

ClassTypical handling
Safe portfolio signalShow
Internal schemaAbstract / redact
Private endpointRedact
AI promptRedact / protect
Security implementationAbstract / protect
Proprietary business logicAbstract / protect
Core/reconstructable IPProtect
Secret / credentialRemove

Safe publication model

  1. Import repository content for private review
  2. Detect potential risks
  3. Review scanner/AI suggestions
  4. Approve protection rules
  5. Apply protection to a draft showcase
  6. Verify the resulting snapshot
  7. Publish only after explicit human approval

Sync is not publish. AI review is not publish.

AI/MCP clients do not receive direct publish or restore capabilities.

Protected structure

Files or folders that must not be public can remain visible in the repository tree as protected entries. Visitors can understand that a component exists and where it belongs while the protected source itself is never served publicly.

ChatGPT / MCP

YouGitAI exposes a constrained MCP interface for authorized repository review. It supports repository discovery, paginated tree inspection, selective source review, security findings and protection proposals. Publication remains under WordPress administrator control.

WordPress / Elementor

The plugin works standalone and also provides Elementor widgets.

Typical public routes:

/repositories/
/repositories/{repository-slug}/

Security

The plugin is designed around a strict separation between original repository material and public showcase snapshots. Repository contents are treated as untrusted input, publication requires explicit human approval, and protected content is not returned through the public showcase API.

See [SECURITY.md](yougitai-secure-showcase/SECURITY.md).

Installation

  1. Download or build the plugin directory yougitai-secure-showcase.
  2. Upload it to /wp-content/plugins/ or install the release ZIP in WordPress.
  3. Activate YouGitAI Secure Showcase.
  4. Configure GitHub access and optional AI providers in the WordPress admin.
  5. Import a repository, review protection suggestions and publish an approved showcase snapshot.

Development status

YouGitAI is under active development. This repository contains the actual plugin source. Credentials, API keys and site-specific configuration are intentionally not included and are configured at runtime in WordPress.

Tech

WordPress · PHP · JavaScript · GitHub OAuth · REST · MCP · OAuth 2.0 / PKCE · Elementor · OpenAI · Claude · Gemini

Author

Built by Sascha Haselhuhn / glanzlicht.

Public showcase: https://sascha-haselhuhn.com/repositories/

yougitai-secure-showcase/src/Api/ConnectedAIRoutes.phpPHP
<?php
namespace YougitAI\SecureShowcase\Api;
use YougitAI\SecureShowcase\Audit\Logger;
use YougitAI\SecureShowcase\GitHub\Client;
use YougitAI\SecureShowcase\Repository\RepositoryService;
use YougitAI\SecureShowcase\Security\ConnectionTokenService;
use YougitAI\SecureShowcase\Security\RateLimiter;
use YougitAI\SecureShowcase\Security\OAuthServer;
use YougitAI\SecureShowcase\Security\SecretScanner;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
final class ConnectedAIRoutes {
private ConnectionTokenService $tokens;
private Client $github;
private SecretScanner $scanner;
private Logger $audit;
public function __construct( private RepositoryService $repositories ) {
$this->tokens = new ConnectionTokenService();
$this->github = new Client();
$this->scanner = new SecretScanner();
$this->audit = new Logger();
}
public function register(): void {
add_action( 'rest_api_init', [ $this, 'routes' ] );
add_filter( 'rest_pre_serve_request', [ $this, 'force_oauth_challenge_headers' ], 5, 4 );
}
/**
* Emit the OAuth challenge at the HTTP layer as well as on the WP_REST_Response.
* Some WordPress/server stacks may otherwise lose WWW-Authenticate while serving
* REST errors, which prevents MCP clients such as ChatGPT from discovering OAuth.
*/
public function force_oauth_challenge_headers( $served, $result, WP_REST_Request $request, $server ) {
if ( $request->get_route() !== '/yougitai-secure-showcase/v1/connected-ai/mcp' ) {
return $served;
}
$status = is_object( $result ) && method_exists( $result, 'get_status' ) ? (int) $result->get_status() : 0;
if ( $status !== 401 ) {
return $served;
}
$scopes = implode( ' ', array_filter( OAuthServer::supported_scopes(), static fn( string $scope ): bool => $scope !== 'offline_access' ) );
$challenge = 'Bearer error="invalid_token", error_description="Authorization required", resource_metadata="' . esc_url_raw( OAuthServer::resource_metadata_url() ) . '"';
if ( $scopes !== '' ) {
$challenge .= ', scope="' . esc_attr( $scopes ) . '"';
}
if ( ! headers_sent() ) {
header( 'WWW-Authenticate: ' . $challenge, true );
header( 'Cache-Control: no-store, private, max-age=0', true );
header( 'Pragma: no-cache', true );
header( 'Vary: Authorization', false );
header( 'X-Content-Type-Options: nosniff', true );
}
return $served;
}
public function routes(): void {
register_rest_route( 'yougitai-secure-showcase/v1', '/connected-ai/mcp', [
'methods' => [ 'GET', 'POST' ],
'callback' => [ $this, 'mcp' ],
'permission_callback' => '__return_true',
] );
register_rest_route( 'yougitai-secure-showcase/v1', '/connected-ai/status', [
'methods' => 'GET',
'callback' => static fn(): WP_REST_Response => new WP_REST_Response( [
'name' => 'YougitAI Secure Showcase',
'protocol' => 'mcp-jsonrpc',
'version' => YOUGITAI_SS_VERSION,
'authentication' => 'oauth',
'authorization_server' => OAuthServer::issuer(),
'protected_resource_metadata' => OAuthServer::resource_metadata_url(),
'publish_tool_exposed' => false,
], 200 ),
'permission_callback' => '__return_true',
] );
register_rest_route( 'yougitai-secure-showcase/v1', '/connected-ai/tool-schema', [
'methods' => 'GET',
'callback' => function (): WP_REST_Response {
$tools = $this->tool_definitions();
$tree = null;
foreach ( $tools as $tool ) {
if ( ( $tool['name'] ?? '' ) === 'get_repository_tree' ) {
$tree = $tool;
break;
}
}
return new WP_REST_Response( [
'version' => YOUGITAI_SS_VERSION,
'tool' => $tree,
'parameter_names' => array_keys( (array) ( $tree['inputSchema']['properties'] ?? [] ) ),
'required' => array_values( (array) ( $tree['inputSchema']['required'] ?? [] ) ),
], 200 );
},
'permission_callback' => '__return_true',
] );
}
public function mcp( WP_REST_Request $request ): WP_REST_Response {
$auth = (string) $request->get_header( 'authorization' );
$token = preg_match( '/^Bearer\s+(.+)$/i', $auth, $m ) ? trim( $m[1] ) : '';
$connection = $this->tokens->authenticate( $token );
if ( ! $connection ) {
return $this->oauth_required_response();
}
if ( strtoupper( $request->get_method() ) === 'GET' ) {
$response = new WP_REST_Response( null, 405 );
$response->header( 'Allow', 'POST' );
return $this->secure_response( $response );
}
$limit = (int) apply_filters( 'yougitai_ss_connected_ai_requests_per_minute', 120 );
if ( ! RateLimiter::allow( 'connected-ai:' . (int) $connection['id'], $limit, 60 ) ) {
return $this->rpc_error( null, -32029, __( 'Too many connected-AI requests. Please try again shortly.', 'yougitai-secure-showcase' ), 429 );
}
$body = $request->get_json_params();
if ( ! is_array( $body ) ) {
return $this->rpc_error( null, -32700, __( 'Invalid JSON request.', 'yougitai-secure-showcase' ), 400 );
}
$id = $body['id'] ?? null;
$method = (string) ( $body['method'] ?? '' );
$params = is_array( $body['params'] ?? null ) ? $body['params'] : [];
if ( $method === 'initialize' ) {
return $this->rpc_result( $id, [
'protocolVersion' => '2025-06-18',
'serverInfo' => [ 'name' => 'yougitai-secure-showcase', 'version' => YOUGITAI_SS_VERSION ],
'capabilities' => [ 'tools' => [ 'listChanged' => true ] ],
] );
}
if ( $method === 'notifications/initialized' ) {
return $this->secure_response( new WP_REST_Response( null, 202 ) );
}
if ( $method === 'ping' ) {
return $this->rpc_result( $id, (object) [] );
}
if ( $method === 'tools/list' ) {
return $this->rpc_result( $id, [ 'tools' => $this->tool_definitions() ] );
}
if ( $method !== 'tools/call' ) {
return $this->rpc_error( $id, -32601, __( 'MCP method not supported.', 'yougitai-secure-showcase' ) );
}
$name = sanitize_key( (string) ( $params['name'] ?? '' ) );
$arguments = is_array( $params['arguments'] ?? null ) ? $params['arguments'] : [];
$result = $this->call_tool( $name, $arguments, $connection );
if ( is_wp_error( $result ) ) {
return $this->rpc_result( $id, [
'isError' => true,
'content' => [ [ 'type' => 'text', 'text' => $result->get_error_message() ] ],
] );
}
return $this->rpc_result( $id, [
'content' => [ [ 'type' => 'text', 'text' => wp_json_encode( $result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ] ],
'structuredContent' => $result,
] );
}
private function tool_definitions(): array {
return [
$this->tool( 'get_connection_info', __( 'Describe the current connected-AI session, permissions, and repository restrictions.', 'yougitai-secure-showcase' ), [] ),
$this->tool( 'list_repositories', __( 'List repositories available to this connected-AI session. Returns metadata only.', 'yougitai-secure-showcase' ), [] ),
$this->tool( 'get_review_context', __( 'Get repository review context including protection profile, snapshots, rules, and unresolved finding counts without source code.', 'yougitai-secure-showcase' ), [ 'repository_id' => [ 'type' => 'integer' ] ], [ 'repository_id' ] ),
$this->tool( 'get_portfolio_policy', __( 'Get the portfolio-safety classification policy used to balance skill visibility against IP exposure. Read this before reviewing source.', 'yougitai-secure-showcase' ), [] ),
$this->tool( 'get_repository_tree', __( 'Read a paginated repository tree without file contents. Start without cursor (or with cursor 0), then pass next_cursor from the previous response until has_more is false. Optionally restrict the scan with prefix.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer', 'description' => 'Repository ID returned by list_repositories.' ],
'cursor' => [ 'type' => 'integer', 'minimum' => 0, 'description' => 'Optional zero-based pagination cursor. Omit for the first page; then pass the previous response next_cursor.' ],
'prefix' => [ 'type' => 'string', 'description' => 'Optional path prefix such as backend/, lib/, or test/. Omit for the entire repository.' ],
'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 500, 'description' => 'Optional page size. Defaults to 250 and is capped at 500.' ],
], [ 'repository_id' ] ),
$this->tool( 'get_repository_tree_page', __( 'Compatibility alias for paginated repository tree access. ALWAYS pass cursor (0 first) and prefix (empty string for the whole repository).', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer', 'description' => 'Repository ID returned by list_repositories.' ],
'cursor' => [ 'type' => 'integer', 'minimum' => 0, 'default' => 0, 'description' => 'Zero-based pagination cursor. Pass the previous response next_cursor to continue.' ],
'prefix' => [ 'type' => 'string', 'default' => '', 'description' => 'Path prefix such as lib/ or test/. Pass an empty string for the whole repository.' ],
'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 500, 'default' => 250, 'description' => 'Maximum number of tree entries to return in this page.' ],
], [ 'repository_id', 'cursor', 'prefix' ] ),
$this->tool( 'get_repository_tree_v2', __( 'Paginated repository tree access with explicit cursor and prefix arguments. Use cursor 0 and prefix empty string for the first page, then continue with next_cursor until has_more is false.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer', 'description' => 'Repository ID returned by list_repositories.' ],
'cursor' => [ 'type' => 'integer', 'minimum' => 0, 'description' => 'Zero-based pagination cursor. Use 0 for the first page and then pass the prior next_cursor.' ],
'prefix' => [ 'type' => 'string', 'description' => 'Path prefix filter. Use an empty string for the entire repository.' ],
'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 500, 'default' => 250, 'description' => 'Maximum number of entries to return in this page.' ],
], [ 'repository_id', 'cursor', 'prefix' ] ),
$this->tool( 'get_repository_tree_paginated', __( 'Repository-wide paginated tree access. Use this tool for complete scans: start with cursor 0, then repeat with next_cursor until has_more is false. Prefix may be empty or restrict the scan to a subdirectory.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer', 'description' => 'Repository ID returned by list_repositories.' ],
'cursor' => [ 'type' => 'integer', 'minimum' => 0, 'default' => 0, 'description' => 'Zero-based pagination cursor. Omit or use 0 for the first page; then pass next_cursor from the previous response.' ],
'prefix' => [ 'type' => 'string', 'default' => '', 'description' => 'Optional path prefix such as backend/ or lib/. Omit or pass an empty string for the entire repository.' ],
'limit' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 500, 'default' => 250, 'description' => 'Maximum number of tree entries in this page.' ],
], [ 'repository_id' ] ),
$this->tool( 'get_file_for_review', __( 'Read one text file from the explicitly authorized repository for security review. This is read-only, repository-scoped, and detected secrets are masked before the content leaves WordPress.', 'yougitai-secure-showcase' ), [ 'repository_id' => [ 'type' => 'integer' ], 'path' => [ 'type' => 'string' ] ], [ 'repository_id', 'path' ] ),
$this->tool( 'get_file_excerpt_for_review', __( 'Read a bounded excerpt from one text file in the explicitly authorized repository. This is read-only and masks detected secrets before returning content.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer' ],
'path' => [ 'type' => 'string' ],
'start_line' => [ 'type' => 'integer', 'minimum' => 1, 'default' => 1 ],
'line_count' => [ 'type' => 'integer', 'minimum' => 1, 'maximum' => 200, 'default' => 120 ],
], [ 'repository_id', 'path' ] ),
$this->tool( 'get_files_for_review', __( 'Fetch up to ten source files in one review call. Secrets are masked before content leaves WordPress.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer' ],
'paths' => [ 'type' => 'array', 'items' => [ 'type' => 'string' ], 'minItems' => 1, 'maxItems' => 10 ],
], [ 'repository_id', 'paths' ] ),
$this->tool( 'get_security_findings', __( 'Read security findings for a repository snapshot.', 'yougitai-secure-showcase' ), [ 'repository_id' => [ 'type' => 'integer' ], 'snapshot_id' => [ 'type' => 'integer' ] ], [ 'repository_id', 'snapshot_id' ] ),
$this->tool( 'get_redaction_proposals', __( 'Read existing connected-AI redaction proposals and their approval status.', 'yougitai-secure-showcase' ), [ 'repository_id' => [ 'type' => 'integer' ] ], [ 'repository_id' ] ),
$this->tool( 'create_redaction_proposal', __( 'Create a disabled redaction proposal for human review. This does not publish or expose source.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer' ],
'file_path' => [ 'type' => 'string' ],
'rule_type' => [ 'type' => 'string', 'enum' => [ 'path', 'string', 'regex' ] ],
'target' => [ 'type' => 'string' ],
'action' => [ 'type' => 'string', 'enum' => [ 'hide', 'redact' ] ],
'replacement' => [ 'type' => 'string' ],
'reason' => [ 'type' => 'string' ],
'classification' => [ 'type' => 'string', 'enum' => [ 'secret', 'private_endpoint', 'ai_prompt', 'security_logic', 'business_logic', 'core_ip', 'internal_schema', 'portfolio_safe' ] ],
'decision' => [ 'type' => 'string', 'enum' => [ 'abstract', 'redact', 'hide' ] ],
], [ 'repository_id', 'rule_type', 'target', 'action', 'reason' ] ),
$this->tool( 'create_redaction_proposals', __( 'Create up to fifty disabled redaction proposals in one call for human review.', 'yougitai-secure-showcase' ), [
'repository_id' => [ 'type' => 'integer' ],
'proposals' => [ 'type' => 'array', 'minItems' => 1, 'maxItems' => 50, 'items' => [
'type' => 'object',
'properties' => [
'file_path' => [ 'type' => 'string' ],
'rule_type' => [ 'type' => 'string', 'enum' => [ 'path', 'string', 'regex' ] ],
'target' => [ 'type' => 'string' ],
'action' => [ 'type' => 'string', 'enum' => [ 'hide', 'redact' ] ],
'replacement' => [ 'type' => 'string' ],
'reason' => [ 'type' => 'string' ],
'classification' => [ 'type' => 'string', 'enum' => [ 'secret', 'private_endpoint', 'ai_prompt', 'security_logic', 'business_logic', 'core_ip', 'internal_schema', 'portfolio_safe' ] ],
'decision' => [ 'type' => 'string', 'enum' => [ 'abstract', 'redact', 'hide' ] ],
],
'required' => [ 'rule_type', 'target', 'action', 'reason' ],
'additionalProperties' => false,
] ],
], [ 'repository_id', 'proposals' ] ),
$this->tool( 'build_draft_snapshot', __( 'Create a new secure draft snapshot. It never publishes automatically.', 'yougitai-secure-showcase' ), [ 'repository_id' => [ 'type' => 'integer' ] ], [ 'repository_id' ] ),
];
}
private function tool( string $name, string $description, array $properties, array $required = [] ): array {
$is_write = str_starts_with( $name, 'create_' ) || str_starts_with( $name, 'build_' );
return [
'name' => $name,
'description' => $description,
'inputSchema' => [ 'type' => 'object', 'properties' => (object) $properties, 'required' => $required, 'additionalProperties' => false ],
'outputSchema' => [ 'type' => 'object', 'additionalProperties' => true ],
'annotations' => [
'readOnlyHint' => ! $is_write,
'destructiveHint' => false,
'idempotentHint' => ! $is_write,
'openWorldHint' => false,
],
];
}
private function call_tool( string $name, array $args, array $connection ) {
$scope_map = [
'get_connection_info' => 'repositories:read',
'list_repositories' => 'repositories:read',
'get_review_context' => 'repositories:read',
'get_portfolio_policy' => 'repositories:read',
'get_repository_tree' => 'repositories:read',
'get_repository_tree_page' => 'repositories:read',
'get_repository_tree_v2' => 'repositories:read',
'get_repository_tree_paginated' => 'repositories:read',
'get_file_for_review' => 'source:review',
'get_file_excerpt_for_review' => 'source:review',
'get_files_for_review' => 'source:review',
'get_security_findings' => 'findings:read',
'get_redaction_proposals' => 'findings:read',
'create_redaction_proposal' => 'redactions:propose',
'create_redaction_proposals' => 'redactions:propose',
'build_draft_snapshot' => 'snapshots:create',
];
if ( ! isset( $scope_map[ $name ] ) || ! in_array( $scope_map[ $name ], $connection['scopes'], true ) ) {
return new WP_Error( 'yougitai_scope_denied', __( 'This connection is not allowed to use that tool.', 'yougitai-secure-showcase' ) );
}
$repository_id = absint( $args['repository_id'] ?? 0 );
if ( $repository_id && ! $this->repository_allowed( $repository_id, $connection ) ) {
return new WP_Error( 'yougitai_repository_denied', __( 'This connection is not allowed to access that repository.', 'yougitai-secure-showcase' ) );
}
return match ( $name ) {
'get_connection_info' => $this->connection_info( $connection ),
'list_repositories' => $this->list_repositories( $connection ),
'get_review_context' => $this->review_context( $args ),
'get_portfolio_policy' => $this->portfolio_policy(),
'get_repository_tree' => $this->get_tree( $args ),
'get_repository_tree_page' => $this->get_tree_page( $args ),
'get_repository_tree_v2' => $this->get_tree_page( $args ),
'get_repository_tree_paginated' => $this->get_tree_page( $args ),
'get_file_for_review' => $this->get_file( $args, $connection ),
'get_file_excerpt_for_review' => $this->get_file_excerpt( $args, $connection ),
'get_files_for_review' => $this->get_files( $args, $connection ),
'get_security_findings' => $this->get_findings( $args ),
'get_redaction_proposals' => $this->get_proposals( $args ),
'create_redaction_proposal' => $this->create_proposal( $args, $connection ),
'create_redaction_proposals' => $this->create_proposals( $args, $connection ),
'build_draft_snapshot' => $this->build_snapshot( $args, $connection ),
default => new WP_Error( 'yougitai_unknown_tool', __( 'Unknown tool.', 'yougitai-secure-showcase' ) ),
};
}
private function connection_info( array $connection ): array {
return [
'connection_id' => (int) $connection['id'],
'label' => (string) $connection['label'],
'expires_at' => (string) $connection['expires_at'],
'scopes' => array_values( $connection['scopes'] ?? [] ),
'repository_ids' => array_values( $connection['repository_ids'] ?? [] ),
'all_repositories' => empty( $connection['repository_ids'] ),
'publish_tool_exposed' => false,
'human_approval_required_for_proposals' => true,
'request_count' => (int) ( $connection['request_count'] ?? 0 ),
'source_bytes_used' => (int) ( $connection['source_bytes'] ?? 0 ),
'source_bytes_limit' => (int) apply_filters( 'yougitai_ss_connected_ai_source_budget', 5242880 ),
];
}
private function list_repositories( array $connection ): array {
$rows = array_filter( $this->repositories->all(), fn( array $r ): bool => $this->repository_allowed( (int) $r['id'], $connection ) );
$repositories = array_values( array_map( static fn( array $r ): array => [
'id' => (int) $r['id'], 'title' => $r['title'], 'owner' => $r['owner'], 'repository' => $r['repo'],
'branch' => $r['default_branch'], 'status' => $r['status'], 'protection_profile' => $r['protection_profile'],
'active_snapshot_id' => (int) ( $r['active_snapshot_id'] ?? 0 ),
], $rows ) );
return [ 'repositories' => $repositories, 'count' => count( $repositories ) ];
}
private function portfolio_policy(): array {
return [
'goal' => 'Show enough implementation detail to demonstrate engineering skill without exposing a reproducible product blueprint.',
'classifications' => [
'secret' => [ 'default' => 'redact', 'description' => 'Credentials, tokens, keys, private hosts, or authentication material.' ],
'private_endpoint' => [ 'default' => 'abstract', 'description' => 'Non-public API paths, internal hosts, admin routes, or integration endpoints.' ],
'ai_prompt' => [ 'default' => 'hide', 'description' => 'System prompts, proprietary prompt templates, routing prompts, or evaluation instructions.' ],
'security_logic' => [ 'default' => 'abstract', 'description' => 'Security controls may remain visible conceptually, but bypass conditions and concrete enforcement internals should not.' ],
'business_logic' => [ 'default' => 'abstract', 'description' => 'Domain workflows and rules that reveal how the product makes decisions.' ],
'core_ip' => [ 'default' => 'hide', 'description' => 'Algorithms or implementation details that materially enable reconstruction of the product.' ],
'internal_schema' => [ 'default' => 'abstract', 'description' => 'Internal data models, tenant/session schemas, privileged fields, and non-public contracts.' ],
'portfolio_safe' => [ 'default' => 'show', 'description' => 'Architecture, tests, error handling, UI patterns, public interfaces, and implementation details that demonstrate skill without meaningful copying risk.' ],
],
'decisions' => [
'show' => 'Keep the implementation visible.',
'abstract' => 'Keep structure and intent visible while replacing implementation-specific values or blocks.',
'redact' => 'Mask the sensitive value or narrow code region.',
'hide' => 'Exclude the file or core implementation from the public snapshot.',
],
'review_order' => [ 'metadata', 'repository_tree', 'risk_candidates', 'targeted_source', 'classify', 'propose_redactions', 'build_draft' ],
'constraints' => [ 'never_publish' => true, 'source_minimization' => true, 'human_approval_for_proposals' => true ],
];
}
private function repository_allowed( int $repository_id, array $connection ): bool {
$allowed = array_values( array_filter( array_map( 'absint', $connection['repository_ids'] ?? [] ) ) );
return empty( $allowed ) || in_array( $repository_id, $allowed, true );
}
private function review_context( array $args ) {
$repository_id = absint( $args['repository_id'] ?? 0 );
$repository = $this->repositories->find( $repository_id );
if ( ! $repository ) return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
$snapshots = array_slice( $this->repositories->snapshots( $repository_id ), 0, 10 );
$rules = array_map( static fn( array $rule ): array => [
'id' => (int) $rule['id'],
'file_path' => (string) $rule['file_path'],
'rule_type' => (string) $rule['rule_type'],
'action' => (string) $rule['action'],
'source' => (string) $rule['source'],
'enabled' => (bool) $rule['enabled'],
'notes' => (string) ( $rule['notes'] ?? '' ),
], $this->repositories->rules( $repository_id ) );
return [
'repository' => [
'id' => (int) $repository['id'], 'title' => $repository['title'], 'owner' => $repository['owner'],
'repository' => $repository['repo'], 'branch' => $repository['default_branch'],
'protection_profile' => $repository['protection_profile'], 'is_private' => (bool) $repository['is_private'],
],
'recent_snapshots' => array_map( static fn( array $snapshot ): array => [
'id' => (int) $snapshot['id'], 'source_sha' => (string) $snapshot['source_sha'], 'status' => $snapshot['status'],
'review_status' => $snapshot['review_status'], 'files' => (int) $snapshot['file_count'],
'findings' => (int) $snapshot['finding_count'], 'critical' => (int) $snapshot['critical_count'],
'created_at' => $snapshot['created_at'],
], $snapshots ),
'redaction_rules' => $rules,
'workflow' => [
'source_is_ephemeral' => true,
'proposals_require_human_approval' => true,
'publish_tool_exposed' => false,
],
];
}
private function get_tree( array $args ) {
$repository = $this->repositories->find( absint( $args['repository_id'] ?? 0 ) );
if ( ! $repository ) return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
$tree = $this->github->get_tree( $repository['owner'], $repository['repo'], $repository['default_branch'] );
if ( is_wp_error( $tree ) ) return $tree;
$prefix = ltrim( sanitize_text_field( (string) ( $args['prefix'] ?? '' ) ), '/' );
$cursor = max( 0, absint( $args['cursor'] ?? 0 ) );
$limit = min( 500, max( 1, absint( $args['limit'] ?? 250 ) ) );
$all = [];
foreach ( $tree['tree'] ?? [] as $node ) {
$path = (string) ( $node['path'] ?? '' );
if ( $path === '' || ( $prefix !== '' && ! str_starts_with( $path, $prefix ) ) ) continue;
$all[] = [
'path' => $path,
'type' => (string) ( $node['type'] ?? '' ),
'size' => (int) ( $node['size'] ?? 0 ),
'risk_hints' => $this->portfolio_hints_for_path( $path ),
];
}
$items = array_slice( $all, $cursor, $limit );
$next = $cursor + count( $items );
return [
'repository' => [
'id' => (int) $repository['id'],
'owner' => (string) $repository['owner'],
'name' => (string) $repository['repo'],
'branch' => (string) $repository['default_branch'],
],
'tree' => [
'source_sha' => (string) ( $tree['sha'] ?? '' ),
'prefix' => $prefix,
'items' => $items,
'count' => count( $items ),
'total_matching' => count( $all ),
'cursor' => $cursor,
'next_cursor' => $next < count( $all ) ? $next : null,
'truncated' => ! empty( $tree['truncated'] ) || $next < count( $all ),
],
];
}
private function get_tree_page( array $args ) {
$result = $this->get_tree( $args );
if ( is_wp_error( $result ) ) return $result;
$tree = $result['tree'] ?? [];
$repository = $result['repository'] ?? [];
$next_cursor = $tree['next_cursor'] ?? null;
return [
'repository' => $repository,
'source_sha' => (string) ( $tree['source_sha'] ?? '' ),
'prefix' => (string) ( $tree['prefix'] ?? '' ),
'cursor' => (int) ( $tree['cursor'] ?? 0 ),
'limit' => min( 500, max( 1, absint( $args['limit'] ?? 250 ) ) ),
'items' => array_values( $tree['items'] ?? [] ),
'count' => (int) ( $tree['count'] ?? 0 ),
'total_matching' => (int) ( $tree['total_matching'] ?? 0 ),
'next_cursor' => $next_cursor === null ? null : (int) $next_cursor,
'has_more' => $next_cursor !== null,
'truncated_upstream' => ! empty( $tree['truncated'] ) && $next_cursor === null,
'pagination_hint' => $next_cursor === null ? 'complete' : 'Call get_repository_tree_paginated again with cursor=next_cursor and the same prefix.',
];
}
private function portfolio_hints_for_path( string $path ): array {
$p = strtolower( $path );
$hints = [];
$patterns = [
'ai_prompt' => [ 'prompt', 'system_message', 'llm', 'openai', 'gemini', 'anthropic' ],
'security_logic' => [ 'auth', 'security', 'permission', 'rbac', 'acl', 'policy', 'guard', 'middleware' ],
'private_endpoint' => [ 'route', 'endpoint', 'api', 'controller', 'webhook' ],
'business_logic' => [ 'service', 'workflow', 'billing', 'pricing', 'scoring', 'matching', 'recommend' ],
'internal_schema' => [ 'schema', 'migration', 'model', 'entity', 'tenant', 'session' ],
'core_ip' => [ 'algorithm', 'engine', 'optimizer', 'ranking', 'classifier', 'proprietary' ],
];
foreach ( $patterns as $category => $needles ) {
foreach ( $needles as $needle ) {
if ( str_contains( $p, $needle ) ) { $hints[] = $category; break; }
}
}
return array_values( array_unique( $hints ) );
}
private function get_file( array $args, array $connection ) {
$repository = $this->repositories->find( absint( $args['repository_id'] ?? 0 ) );
if ( ! $repository ) return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
$path = ltrim( sanitize_text_field( (string) ( $args['path'] ?? '' ) ), '/' );
if ( $path === '' || str_contains( $path, '..' ) ) return new WP_Error( 'yougitai_invalid_path', __( 'Invalid repository path.', 'yougitai-secure-showcase' ) );
if ( preg_match( '#(^|/)(\.env(?:\.|$)|id_rsa|id_ed25519|credentials(?:\.|$)|secrets?(?:\.|$)|private[_-]?key)(/|$)#i', $path ) ) {
return new WP_Error( 'yougitai_sensitive_path', __( 'This path is blocked from connected AI review.', 'yougitai-secure-showcase' ) );
}
$file = $this->github->get_file( $repository['owner'], $repository['repo'], $path, $repository['default_branch'] );
if ( is_wp_error( $file ) ) return $file;
if ( (string) ( $file['encoding'] ?? '' ) !== 'base64' || empty( $file['content'] ) ) return new WP_Error( 'yougitai_file_unavailable', __( 'Source file could not be read for review.', 'yougitai-secure-showcase' ) );
$content = base64_decode( preg_replace( '/\s+/', '', (string) $file['content'] ), true );
if ( ! is_string( $content ) || str_contains( substr( $content, 0, 8000 ), "\0" ) ) return new WP_Error( 'yougitai_binary_file', __( 'Binary files cannot be sent for connected AI review.', 'yougitai-secure-showcase' ) );
if ( strlen( $content ) > 250000 ) return new WP_Error( 'yougitai_file_too_large', __( 'This file is too large for connected AI review.', 'yougitai-secure-showcase' ) );
$hits = $this->scanner->scan( $content );
$safe = $this->scanner->redact( $content, $hits );
$budget = (int) apply_filters( 'yougitai_ss_connected_ai_source_budget', 5242880 );
if ( ! $this->tokens->consume_source_bytes( (int) $connection['id'], strlen( $content ), $budget, (string) ( $connection['connection_type'] ?? 'legacy' ) ) ) {
unset( $content, $safe );
return new WP_Error( 'yougitai_source_budget_exceeded', __( 'This connected-AI session has reached its source review limit. Create a new scoped connection to continue.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'connected_ai_source_reviewed', __( 'A connected AI client reviewed a source file.', 'yougitai-secure-showcase' ), (int) $repository['id'], null, [ 'path' => $path, 'secrets_masked' => count( $hits ) ] );
return [ 'repository_id' => (int) $repository['id'], 'path' => $path, 'sha' => (string) ( $file['sha'] ?? '' ), 'content' => $safe, 'secrets_masked' => count( $hits ) ];
}
private function get_file_excerpt( array $args, array $connection ) {
$result = $this->get_file( $args, $connection );
if ( is_wp_error( $result ) ) return $result;
$lines = preg_split( '/\R/', (string) ( $result['content'] ?? '' ) );
if ( ! is_array( $lines ) ) $lines = [];
$start = max( 1, absint( $args['start_line'] ?? 1 ) );
$count = min( 200, max( 1, absint( $args['line_count'] ?? 120 ) ) );
$slice = array_slice( $lines, $start - 1, $count );
unset( $result['content'] );
$result['start_line'] = $start;
$result['end_line'] = $start + max( 0, count( $slice ) - 1 );
$result['total_lines'] = count( $lines );
$result['content_excerpt'] = implode( "\n", $slice );
$result['truncated'] = $result['end_line'] < count( $lines );
return $result;
}
private function get_files( array $args, array $connection ) {
$paths = is_array( $args['paths'] ?? null ) ? array_slice( $args['paths'], 0, 10 ) : [];
if ( empty( $paths ) ) return new WP_Error( 'yougitai_paths_required', __( 'At least one repository path is required.', 'yougitai-secure-showcase' ) );
$items = [];
foreach ( $paths as $path ) {
$result = $this->get_file( [ 'repository_id' => absint( $args['repository_id'] ?? 0 ), 'path' => (string) $path ], $connection );
if ( is_wp_error( $result ) ) {
$items[] = [ 'path' => (string) $path, 'error' => $result->get_error_message() ];
} else {
$items[] = $result;
}
}
return [ 'files' => $items ];
}
private function get_proposals( array $args ): array {
$repository_id = absint( $args['repository_id'] ?? 0 );
return [ 'proposals' => array_values( array_filter( array_map( static function ( array $rule ): ?array {
if ( $rule['source'] !== 'connected_ai' ) return null;
return [
'id' => (int) $rule['id'], 'file_path' => (string) $rule['file_path'], 'rule_type' => $rule['rule_type'],
'target' => (string) $rule['target'], 'action' => $rule['action'], 'replacement' => (string) $rule['replacement'],
'reason' => (string) ( $rule['notes'] ?? '' ), 'enabled' => (bool) $rule['enabled'], 'created_at' => $rule['created_at'],
];
}, $this->repositories->rules( $repository_id ) ) ) ) ];
}
private function create_proposals( array $args, array $connection ) {
$repository_id = absint( $args['repository_id'] ?? 0 );
$proposals = is_array( $args['proposals'] ?? null ) ? array_slice( $args['proposals'], 0, 50 ) : [];
if ( empty( $proposals ) ) return new WP_Error( 'yougitai_proposals_required', __( 'At least one redaction proposal is required.', 'yougitai-secure-showcase' ) );
$created = [];
$errors = [];
foreach ( $proposals as $index => $proposal ) {
if ( ! is_array( $proposal ) ) continue;
$proposal['repository_id'] = $repository_id;
$result = $this->create_proposal( $proposal, $connection );
if ( is_wp_error( $result ) ) {
$errors[] = [ 'index' => $index, 'error' => $result->get_error_message() ];
} else {
$created[] = $result;
}
}
return [ 'created' => $created, 'errors' => $errors, 'requires_human_review' => true ];
}
private function get_findings( array $args ) {
$repository_id = absint( $args['repository_id'] ?? 0 );
$snapshot_id = absint( $args['snapshot_id'] ?? 0 );
$snapshot = $this->repositories->snapshot( $snapshot_id );
if ( ! $snapshot || (int) $snapshot['repository_id'] !== $repository_id ) return new WP_Error( 'yougitai_snapshot_not_found', __( 'Snapshot not found.', 'yougitai-secure-showcase' ) );
return [ 'snapshot' => $snapshot, 'findings' => $this->repositories->findings_for_snapshot( $snapshot_id ) ];
}
private function create_proposal( array $args, array $connection ) {
$repository_id = absint( $args['repository_id'] ?? 0 );
$classification = sanitize_key( (string) ( $args['classification'] ?? '' ) );
$decision = sanitize_key( (string) ( $args['decision'] ?? '' ) );
$reason = (string) ( $args['reason'] ?? '' );
if ( $classification !== '' || $decision !== '' ) {
$reason = trim( '[portfolio classification=' . ( $classification !== '' ? $classification : 'unspecified' ) . '; decision=' . ( $decision !== '' ? $decision : 'unspecified' ) . '] ' . $reason );
}
$replacement = (string) ( $args['replacement'] ?? '[PROTECTED]' );
if ( $decision === 'abstract' && ( $replacement === '' || $replacement === '[PROTECTED]' ) ) {
$replacement = '[PROTECTED IMPLEMENTATION]';
}
$result = $this->repositories->add_ai_rule_proposal( $repository_id, [
'file_path' => (string) ( $args['file_path'] ?? '' ),
'rule_type' => (string) ( $args['rule_type'] ?? '' ),
'target' => (string) ( $args['target'] ?? '' ),
'action' => $decision === 'hide' ? 'hide' : (string) ( $args['action'] ?? '' ),
'replacement' => $replacement,
'reason' => $reason,
] );
if ( is_wp_error( $result ) ) return $result;
$this->audit->log( 'connected_ai_redaction_proposed', __( 'A connected AI client created a redaction proposal.', 'yougitai-secure-showcase' ), $repository_id, null, [ 'rule_id' => (int) $result, 'connection_id' => (int) $connection['id'] ] );
return [ 'rule_id' => (int) $result, 'status' => 'proposal', 'enabled' => false, 'requires_human_review' => true ];
}
private function build_snapshot( array $args, array $connection ) {
$repository_id = absint( $args['repository_id'] ?? 0 );
$result = $this->repositories->import_snapshot( $repository_id );
if ( is_wp_error( $result ) ) return $result;
$this->audit->log( 'connected_ai_snapshot_built', __( 'A connected AI client created a secure draft snapshot.', 'yougitai-secure-showcase' ), $repository_id, (int) $result['snapshot_id'], [ 'connection_id' => (int) $connection['id'] ] );
$result['published'] = false;
return $result;
}
private function oauth_required_response(): WP_REST_Response {
$message = __( 'OAuth authorization is required, or the connection token is invalid, expired, or revoked.', 'yougitai-secure-showcase' );
$response = new WP_REST_Response( [
'error' => 'invalid_token',
'error_description' => $message,
], 401 );
$scopes = implode( ' ', array_filter( OAuthServer::supported_scopes(), static fn( string $scope ): bool => $scope !== 'offline_access' ) );
$challenge = 'Bearer error="invalid_token", error_description="Authorization required", resource_metadata="' . esc_url_raw( OAuthServer::resource_metadata_url() ) . '"';
if ( $scopes !== '' ) {
$challenge .= ', scope="' . esc_attr( $scopes ) . '"';
}
$response->header( 'WWW-Authenticate', $challenge );
return $this->secure_response( $response );
}
private function rpc_result( $id, $result ): WP_REST_Response {
$response = new WP_REST_Response( [ 'jsonrpc' => '2.0', 'id' => $id, 'result' => $result ], 200 );
return $this->secure_response( $response );
}
private function rpc_error( $id, int $code, string $message, int $status = 200 ): WP_REST_Response {
$response = new WP_REST_Response( [ 'jsonrpc' => '2.0', 'id' => $id, 'error' => [ 'code' => $code, 'message' => $message ] ], $status );
return $this->secure_response( $response );
}
private function secure_response( WP_REST_Response $response ): WP_REST_Response {
$response->header( 'Cache-Control', 'no-store, private, max-age=0' );
$response->header( 'Pragma', 'no-cache' );
$response->header( 'X-Content-Type-Options', 'nosniff' );
$response->header( 'Vary', 'Authorization' );
return $response;
}
}

Architecture

High-level modules detected from the verified public snapshot. Protected implementation details are intentionally omitted.

yougitai-secure-showcasemodule
.githubmodule
.vscodemodule

Technology stack

PHPPOPOTCSSMarkdownJavaScript
PHP52.5%
PO26.8%
POT8.2%
CSS6.3%
Markdown4.0%
JavaScript1.4%
TXT0.5%
YAML0.1%