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/Repository/RepositoryService.phpPHP
<?php
namespace YougitAI\SecureShowcase\Repository;
use YougitAI\SecureShowcase\AI\ProviderFactory;
use YougitAI\SecureShowcase\Audit\Logger;
use YougitAI\SecureShowcase\Database\Schema;
use YougitAI\SecureShowcase\GitHub\Client;
use YougitAI\SecureShowcase\Review\FindingService;
use YougitAI\SecureShowcase\Security\SnapshotVerifier;
use YougitAI\SecureShowcase\Security\SecretVault;
use WP_Error;
final class RepositoryService {
private Client $github;
private RedactionEngine $redactor;
private FindingService $findings;
private Logger $audit;
public function __construct() {
$this->github = new Client();
$this->redactor = new RedactionEngine();
$this->findings = new FindingService();
$this->audit = new Logger();
}
public function all(): array {
global $wpdb;
return $wpdb->get_results( 'SELECT * FROM ' . Schema::table( 'repositories' ) . ' ORDER BY updated_at DESC', ARRAY_A ) ?: [];
}
public function find( int $id ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . Schema::table( 'repositories' ) . ' WHERE id = %d', $id ), ARRAY_A );
return $row ?: null;
}
public function find_by_slug( string $slug ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . Schema::table( 'repositories' ) . ' WHERE slug = %s', $slug ), ARRAY_A );
return $row ?: null;
}
public function create_from_github_url( string $url, string $profile = 'balanced' ) {
$parts = $this->parse_github_url( $url );
if ( is_wp_error( $parts ) ) {
return $parts;
}
[ $owner, $repo ] = $parts;
$meta = $this->github->get_repository( $owner, $repo );
if ( is_wp_error( $meta ) ) {
return $meta;
}
$allowed_profiles = [ 'portfolio', 'balanced', 'investor', 'maximum' ];
$profile = in_array( $profile, $allowed_profiles, true ) ? $profile : 'balanced';
global $wpdb;
$now = current_time( 'mysql' );
$slug = sanitize_title( $repo );
$base = $slug;
$i = 2;
while ( $this->find_by_slug( $slug ) ) {
$slug = $base . '-' . $i++;
}
$wpdb->insert( Schema::table( 'repositories' ), [
'owner' => sanitize_text_field( $owner ),
'repo' => sanitize_text_field( $repo ),
'slug' => $slug,
'title' => sanitize_text_field( $meta['name'] ?? $repo ),
'description' => sanitize_textarea_field( $meta['description'] ?? '' ),
'default_branch' => sanitize_text_field( $meta['default_branch'] ?? 'main' ),
'github_url' => esc_url_raw( $meta['html_url'] ?? $url ),
'visibility' => 'public',
'status' => 'draft',
'protection_profile' => $profile,
'show_original' => 0,
'is_private' => ! empty( $meta['private'] ) ? 1 : 0,
'sync_mode' => 'manual',
'created_at' => $now,
'updated_at' => $now,
] );
if ( ! $wpdb->insert_id ) {
return new WP_Error( 'yougitai_db_error', __( 'The repository could not be saved.', 'yougitai-secure-showcase' ) );
}
$id = (int) $wpdb->insert_id;
$this->audit->log( 'repository_created', __( 'Repository created.', 'yougitai-secure-showcase' ), $id, null, [ 'owner' => $owner, 'repo' => $repo ] );
return $id;
}
/**
* Refresh repository-level GitHub metadata before a real GitHub sync.
*
* Snapshot rebuilds that only apply already-approved protection rules do not
* call this method and therefore remain fully local/GitHub-free.
*
* @return array<string,mixed>|WP_Error
*/
public function refresh_github_metadata( int $repository_id ) {
$repository = $this->find( $repository_id );
if ( ! $repository ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$meta = $this->github->get_repository( (string) $repository['owner'], (string) $repository['repo'] );
if ( is_wp_error( $meta ) ) {
return $meta;
}
$description = sanitize_textarea_field( (string) ( $meta['description'] ?? '' ) );
$default_branch = sanitize_text_field( (string) ( $meta['default_branch'] ?? $repository['default_branch'] ?? 'main' ) );
$github_url = esc_url_raw( (string) ( $meta['html_url'] ?? $repository['github_url'] ?? '' ) );
$is_private = ! empty( $meta['private'] ) ? 1 : 0;
$now = current_time( 'mysql' );
global $wpdb;
$updated = $wpdb->update( Schema::table( 'repositories' ), [
'description' => $description,
'default_branch' => $default_branch,
'github_url' => $github_url,
'is_private' => $is_private,
'updated_at' => $now,
], [ 'id' => $repository_id ] );
if ( $updated === false ) {
return new WP_Error( 'yougitai_metadata_update_failed', __( 'GitHub repository metadata could not be refreshed.', 'yougitai-secure-showcase' ) );
}
$repository['description'] = $description;
$repository['default_branch'] = $default_branch;
$repository['github_url'] = $github_url;
$repository['is_private'] = $is_private;
$repository['updated_at'] = $now;
$this->audit->log(
'repository_metadata_refreshed',
__( 'GitHub repository metadata refreshed.', 'yougitai-secure-showcase' ),
$repository_id,
null,
[ 'description_updated' => true, 'default_branch' => $default_branch ]
);
return $repository;
}
public function snapshots( int $repository_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare(
'SELECT * FROM ' . Schema::table( 'snapshots' ) . ' WHERE repository_id=%d ORDER BY id DESC',
$repository_id
), ARRAY_A ) ?: [];
}
public function snapshot( int $snapshot_id ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare( 'SELECT * FROM ' . Schema::table( 'snapshots' ) . ' WHERE id=%d', $snapshot_id ), ARRAY_A );
return $row ?: null;
}
public function import_snapshot( int $repository_id ) {
$repository = $this->refresh_github_metadata( $repository_id );
if ( is_wp_error( $repository ) ) {
return $repository;
}
$tree = $this->github->get_tree( $repository['owner'], $repository['repo'], $repository['default_branch'] );
if ( is_wp_error( $tree ) ) {
return $tree;
}
global $wpdb;
$now = current_time( 'mysql' );
$wpdb->insert( Schema::table( 'snapshots' ), [
'repository_id' => $repository_id,
'source_ref' => $repository['default_branch'],
'source_sha' => sanitize_text_field( $tree['sha'] ?? '' ),
'status' => 'draft',
'review_status' => 'pending',
'show_original' => ! empty( $repository['show_original'] ) ? 1 : 0,
'created_at' => $now,
] );
$snapshot_id = (int) $wpdb->insert_id;
if ( ! $snapshot_id ) {
return new WP_Error( 'yougitai_snapshot_error', __( 'Snapshot could not be created.', 'yougitai-secure-showcase' ) );
}
$count = 0;
$finding_count = 0;
$critical_count = 0;
$max_files = (int) apply_filters( 'yougitai_ss_import_file_limit', 500 );
$max_file_size = (int) apply_filters( 'yougitai_ss_import_max_file_size', 300000 );
$rules = $this->rules( $repository_id );
$show_original = ! empty( $repository['show_original'] );
$ai = ProviderFactory::make();
$ai_enabled = ! $show_original && $ai->is_configured();
foreach ( $tree['tree'] ?? [] as $node ) {
if ( $count >= $max_files ) {
break;
}
if ( ( $node['type'] ?? '' ) !== 'blob' ) {
continue;
}
$path = (string) ( $node['path'] ?? '' );
$size = (int) ( $node['size'] ?? 0 );
if ( $path === '' || $size > $max_file_size || $this->ignored_path( $path ) ) {
continue;
}
// Secure mode fails closed without fetching known-sensitive files.
// Original mode is an explicit opt-out: text source is intentionally copied into the public draft.
if ( ! $show_original && $this->redactor->is_blocked_path( $path ) ) {
$public = $this->redactor->build_public_content( $path, '', $rules );
$file_id = $this->insert_public_file( $repository_id, $snapshot_id, $path, $size, $node, $public, $now );
foreach ( $public['findings'] as $finding ) {
$this->findings->add( $repository_id, $snapshot_id, $file_id, $path, $finding );
$finding_count++;
if ( ( $finding['severity'] ?? '' ) === 'critical' ) {
$critical_count++;
}
}
$count++;
continue;
}
$file = $this->github->get_file( $repository['owner'], $repository['repo'], $path, $repository['default_branch'] );
if ( is_wp_error( $file ) || ( $file['encoding'] ?? '' ) !== 'base64' ) {
continue;
}
$content = base64_decode( preg_replace( '/\s+/', '', (string) $file['content'] ), true );
if ( $content === false || $this->looks_binary( $content ) ) {
continue;
}
// SECURITY BOUNDARY: original source only exists in this local variable.
// It is never inserted into WordPress tables, options, transients, logs, or public APIs.
$ai_findings = [];
if ( $ai_enabled && $this->should_ai_review( $path, $content, (string) $repository['protection_profile'] ) ) {
$analysis = $ai->analyze_file( $path, $content, [
'profile' => $repository['protection_profile'],
'repository' => $repository['owner'] . '/' . $repository['repo'],
] );
if ( ! is_wp_error( $analysis ) ) {
$ai_findings = is_array( $analysis['findings'] ?? null ) ? $analysis['findings'] : [];
}
}
if ( $show_original ) {
$public = [
'content' => $content,
'visibility' => 'public',
'risk_score' => 0,
'notes' => [ __( 'Original source mode: no redaction rules, secret scanning, or AI protection were applied to this file.', 'yougitai-secure-showcase' ) ],
'findings' => [],
];
} else {
$public = $this->redactor->build_public_content( $path, $content, $rules, $ai_findings );
}
unset( $content, $file );
$file_id = $this->insert_public_file( $repository_id, $snapshot_id, $path, $size, $node, $public, $now );
foreach ( $public['findings'] as $finding ) {
$this->findings->add( $repository_id, $snapshot_id, $file_id, $path, $finding );
$finding_count++;
if ( ( $finding['severity'] ?? '' ) === 'critical' ) {
$critical_count++;
}
}
$count++;
}
$review_status = $critical_count > 0 || $finding_count > 0 ? 'needs_review' : 'ready';
$wpdb->update( Schema::table( 'snapshots' ), [
'file_count' => $count,
'finding_count' => $finding_count,
'critical_count' => $critical_count,
'review_status' => $review_status,
], [ 'id' => $snapshot_id ] );
$wpdb->update( Schema::table( 'repositories' ), [ 'updated_at' => $now ], [ 'id' => $repository_id ] );
$this->audit->log( 'snapshot_imported', __( 'Secure snapshot imported.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [
'files' => $count,
'findings' => $finding_count,
'critical' => $critical_count,
'ai_enabled' => $ai_enabled,
'show_original' => $show_original,
] );
return [
'snapshot_id' => $snapshot_id,
'files' => $count,
'findings' => $finding_count,
'critical' => $critical_count,
'review_status' => $review_status,
];
}
/**
* Build a new protected draft from an already stored safe snapshot.
* This never contacts GitHub and never reconstructs original source.
*/
public function rebuild_protected_snapshot( int $repository_id, int $base_snapshot_id = 0 ) {
$repository = $this->find( $repository_id );
if ( ! $repository ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
if ( ! empty( $repository['show_original'] ) ) {
return new WP_Error( 'yougitai_original_mode', __( 'Protection rules cannot be applied while Original source mode is active.', 'yougitai-secure-showcase' ) );
}
$snapshots = $this->snapshots( $repository_id );
$base = $base_snapshot_id > 0 ? $this->snapshot( $base_snapshot_id ) : ( $snapshots[0] ?? null );
if ( ! $base || (int) $base['repository_id'] !== $repository_id ) {
return new WP_Error( 'yougitai_snapshot_not_found', __( 'No existing draft is available to protect.', 'yougitai-secure-showcase' ) );
}
global $wpdb;
$base_files = $wpdb->get_results( $wpdb->prepare(
'SELECT * FROM ' . Schema::table( 'files' ) . ' WHERE repository_id=%d AND snapshot_id=%d ORDER BY path ASC',
$repository_id,
(int) $base['id']
), ARRAY_A ) ?: [];
if ( ! $base_files ) {
return new WP_Error( 'yougitai_snapshot_empty', __( 'The selected draft contains no files.', 'yougitai-secure-showcase' ) );
}
$now = current_time( 'mysql' );
$wpdb->insert( Schema::table( 'snapshots' ), [
'repository_id' => $repository_id,
'source_ref' => (string) $base['source_ref'],
'source_sha' => (string) $base['source_sha'],
'status' => 'draft',
'review_status' => 'pending',
'show_original' => 0,
'created_at' => $now,
] );
$snapshot_id = (int) $wpdb->insert_id;
if ( ! $snapshot_id ) {
return new WP_Error( 'yougitai_snapshot_error', __( 'Protected draft could not be created.', 'yougitai-secure-showcase' ) );
}
$rules = $this->rules( $repository_id );
$active_rules = array_values( array_filter( $rules, static fn( array $rule ): bool => ! empty( $rule['enabled'] ) ) );
if ( ! $active_rules ) {
$wpdb->delete( Schema::table( 'snapshots' ), [ 'id' => $snapshot_id ] );
return new WP_Error( 'yougitai_no_active_rules', __( 'There are no active protection rules to apply.', 'yougitai-secure-showcase' ) );
}
$rules = $active_rules;
$count = 0;
$finding_count = 0;
$critical_count = 0;
foreach ( $base_files as $file ) {
$path = (string) $file['path'];
// A previously hidden file stays hidden. Rebuilding protection must never expose it again.
if ( (string) $file['visibility'] === 'hidden' ) {
$public = [
'content' => '',
'visibility' => 'hidden',
'risk_score' => max( 80, (int) $file['risk_score'] ),
'notes' => [ __( 'Already protected in the source draft.', 'yougitai-secure-showcase' ) ],
'findings' => [],
'redactions' => [],
];
} else {
// SECURITY: this is already-sanitized snapshot content, never original GitHub source.
$public = $this->redactor->build_public_content( $path, (string) $file['content'], $rules, [] );
$existing_manifest = json_decode( (string) ( $file['redaction_manifest'] ?? '' ), true );
if ( is_array( $existing_manifest ) && $existing_manifest ) {
$public['redactions'] = array_merge( $existing_manifest, is_array( $public['redactions'] ?? null ) ? $public['redactions'] : [] );
if ( (string) $file['visibility'] === 'redacted' && (string) ( $public['visibility'] ?? 'public' ) === 'public' ) {
$public['visibility'] = 'redacted';
}
}
}
$node = [ 'sha' => (string) $file['source_sha'] ];
$file_id = $this->insert_public_file( $repository_id, $snapshot_id, $path, (int) $file['size'], $node, $public, $now );
foreach ( $public['findings'] as $finding ) {
$this->findings->add( $repository_id, $snapshot_id, $file_id, $path, $finding );
$finding_count++;
if ( ( $finding['severity'] ?? '' ) === 'critical' ) $critical_count++;
}
$count++;
}
$review_status = $critical_count > 0 || $finding_count > 0 ? 'needs_review' : 'ready';
$wpdb->update( Schema::table( 'snapshots' ), [
'file_count' => $count,
'finding_count' => $finding_count,
'critical_count' => $critical_count,
'review_status' => $review_status,
], [ 'id' => $snapshot_id ] );
$wpdb->update( Schema::table( 'repositories' ), [ 'updated_at' => $now ], [ 'id' => $repository_id ] );
$this->audit->log( 'snapshot_protection_rebuilt', __( 'Active protection rules were applied to an existing safe draft without contacting GitHub.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'base_snapshot_id' => (int) $base['id'] ] );
return [
'snapshot_id' => $snapshot_id,
'base_snapshot_id' => (int) $base['id'],
'files' => $count,
'findings' => $finding_count,
'critical' => $critical_count,
'review_status' => $review_status,
'github_contacted' => false,
];
}
public function approve_snapshot_review( int $repository_id, int $snapshot_id ) {
global $wpdb;
$snapshot = $this->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' ) );
}
$open_critical = (int) $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM " . Schema::table( 'findings' ) . " WHERE snapshot_id=%d AND severity='critical' AND status='open'",
$snapshot_id
) );
if ( $open_critical > 0 ) {
return new WP_Error( 'yougitai_review_blocked', __( 'Critical findings must be resolved or explicitly accepted before approval.', 'yougitai-secure-showcase' ) );
}
$wpdb->update( Schema::table( 'snapshots' ), [
'review_status' => 'approved',
'reviewed_at' => current_time( 'mysql' ),
], [ 'id' => $snapshot_id ] );
$this->audit->log( 'snapshot_review_approved', __( 'Snapshot review approved.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id );
return true;
}
public function publish_snapshot( int $repository_id, int $snapshot_id ) {
global $wpdb;
$snapshot = $this->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' ) );
}
if ( $snapshot['review_status'] !== 'approved' && $snapshot['review_status'] !== 'ready' ) {
return new WP_Error( 'yougitai_publish_review_required', __( 'The snapshot must pass review before it can be published.', 'yougitai-secure-showcase' ) );
}
$verifier = new SnapshotVerifier();
$verification = $verifier->verify( $snapshot_id );
if ( ! $verification['ok'] ) {
$this->audit->log( 'snapshot_verification_failed', __( 'Final snapshot verification failed.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'issues' => $verification['issues'] ] );
return new WP_Error( 'yougitai_publish_blocked', sprintf(
__( 'Publishing was blocked by the final leak scan: %s', 'yougitai-secure-showcase' ),
implode( ' | ', $verification['issues'] )
) );
}
$now = current_time( 'mysql' );
$wpdb->update( Schema::table( 'snapshots' ), [
'status' => 'published',
'published_at' => $now,
'verification_hash' => $verification['verification_hash'],
], [ 'id' => $snapshot_id ] );
$wpdb->update( Schema::table( 'repositories' ), [
'active_snapshot_id' => $snapshot_id,
'status' => 'published',
'updated_at' => $now,
], [ 'id' => $repository_id ] );
$this->audit->log( 'snapshot_published', __( 'Verified snapshot published.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'verification_hash' => $verification['verification_hash'] ] );
return true;
}
public function findings_for_snapshot( int $snapshot_id ): array {
return $this->findings->for_snapshot( $snapshot_id );
}
public function resolve_finding( int $repository_id, int $snapshot_id, int $finding_id, string $status ) {
global $wpdb;
$finding = $wpdb->get_row( $wpdb->prepare(
'SELECT * FROM ' . Schema::table( 'findings' ) . ' WHERE id=%d AND repository_id=%d AND snapshot_id=%d',
$finding_id, $repository_id, $snapshot_id
), ARRAY_A );
if ( ! $finding ) {
return new WP_Error( 'yougitai_finding_not_found', __( 'Finding not found.', 'yougitai-secure-showcase' ) );
}
if ( ! $this->findings->resolve( $finding_id, $status ) ) {
return new WP_Error( 'yougitai_finding_update_failed', __( 'Finding could not be updated.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'finding_' . $status, __( 'Security finding reviewed.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'finding_id' => $finding_id ] );
return true;
}
public function rules( int $repository_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare(
'SELECT * FROM ' . Schema::table( 'rules' ) . ' WHERE repository_id=%d ORDER BY id ASC',
$repository_id
), ARRAY_A ) ?: [];
}
public function add_ai_rule_proposal( int $repository_id, array $data ) {
if ( ! $this->find( $repository_id ) ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$type = sanitize_key( (string) ( $data['rule_type'] ?? '' ) );
$action = sanitize_key( (string) ( $data['action'] ?? '' ) );
if ( ! in_array( $type, [ 'path', 'string', 'regex' ], true ) || ! in_array( $action, [ 'hide', 'redact' ], true ) ) {
return new WP_Error( 'yougitai_invalid_rule', __( 'Invalid protection rule.', 'yougitai-secure-showcase' ) );
}
$target = trim( (string) ( $data['target'] ?? '' ) );
if ( $target === '' || ( $type === 'regex' && @preg_match( $target, '' ) === false ) ) {
return new WP_Error( 'yougitai_invalid_rule', __( 'A protection proposal needs a valid target.', 'yougitai-secure-showcase' ) );
}
global $wpdb;
$now = current_time( 'mysql' );
$reason = sanitize_textarea_field( (string) ( $data['reason'] ?? '' ) );
$replacement = sanitize_textarea_field( (string) ( $data['replacement'] ?? '[PROTECTED]' ) );
$payload = $replacement;
if ( $reason !== '' ) {
$payload .= "
[AI proposal reason] " . $reason;
}
$wpdb->insert( Schema::table( 'rules' ), [
'repository_id' => $repository_id,
'file_path' => sanitize_text_field( (string) ( $data['file_path'] ?? '' ) ),
'rule_type' => $type,
'target' => $type === 'regex' ? $target : sanitize_textarea_field( $target ),
'action' => $action,
'replacement' => $replacement,
'notes' => $reason,
'source' => 'connected_ai',
'confidence' => null,
'enabled' => 0,
'created_at' => $now,
'updated_at' => $now,
] );
if ( ! $wpdb->insert_id ) {
return new WP_Error( 'yougitai_rule_save_failed', __( 'Protection proposal could not be saved.', 'yougitai-secure-showcase' ) );
}
return (int) $wpdb->insert_id;
}
public function set_rule_enabled( int $repository_id, int $rule_id, bool $enabled ) {
global $wpdb;
$rule = $wpdb->get_row( $wpdb->prepare(
'SELECT * FROM ' . Schema::table( 'rules' ) . ' WHERE id=%d AND repository_id=%d',
$rule_id,
$repository_id
), ARRAY_A );
if ( ! $rule ) {
return new WP_Error( 'yougitai_rule_not_found', __( 'Protection rule not found.', 'yougitai-secure-showcase' ) );
}
if ( $enabled && $rule['source'] === 'connected_ai' ) {
$this->audit->log( 'connected_ai_redaction_approved', __( 'Connected AI redaction proposal approved by a WordPress administrator.', 'yougitai-secure-showcase' ), $repository_id, null, [ 'rule_id' => $rule_id ] );
}
$ok = $wpdb->update( Schema::table( 'rules' ), [ 'enabled' => $enabled ? 1 : 0, 'updated_at' => current_time( 'mysql' ) ], [ 'id' => $rule_id, 'repository_id' => $repository_id ] );
return $ok !== false ? true : new WP_Error( 'yougitai_rule_update_failed', __( 'Protection rule could not be updated.', 'yougitai-secure-showcase' ) );
}
public function add_rule( int $repository_id, array $data ) {
if ( ! $this->find( $repository_id ) ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$type = sanitize_key( (string) ( $data['rule_type'] ?? 'path' ) );
$action = sanitize_key( (string) ( $data['action'] ?? 'hide' ) );
if ( ! in_array( $type, [ 'path', 'string', 'regex', 'line_range', 'symbol' ], true ) || ! in_array( $action, [ 'hide', 'redact' ], true ) ) {
return new WP_Error( 'yougitai_invalid_rule', __( 'Invalid protection rule.', 'yougitai-secure-showcase' ) );
}
$target = trim( (string) ( $data['target'] ?? '' ) );
if ( $target === '' ) {
return new WP_Error( 'yougitai_invalid_rule', __( 'A protection rule needs a target.', 'yougitai-secure-showcase' ) );
}
if ( $type === 'line_range' ) {
$decoded = json_decode( $target, true );
if ( ! is_array( $decoded ) || empty( $decoded['start'] ) || empty( $decoded['end'] ) || empty( $decoded['hash'] ) || (int) $decoded['start'] > (int) $decoded['end'] ) {
return new WP_Error( 'yougitai_invalid_line_rule', __( 'The line protection rule is invalid.', 'yougitai-secure-showcase' ) );
}
}
if ( $type === 'regex' && @preg_match( $target, '' ) === false ) {
return new WP_Error( 'yougitai_invalid_regex', __( 'The regular expression is invalid.', 'yougitai-secure-showcase' ) );
}
global $wpdb;
$now = current_time( 'mysql' );
$wpdb->insert( Schema::table( 'rules' ), [
'repository_id' => $repository_id,
'file_path' => sanitize_text_field( (string) ( $data['file_path'] ?? '' ) ),
'rule_type' => $type,
'target' => in_array( $type, [ 'regex', 'line_range', 'symbol' ], true ) ? $target : sanitize_textarea_field( $target ),
'action' => $action,
'replacement' => sanitize_textarea_field( (string) ( $data['replacement'] ?? '[PROTECTED]' ) ),
'source' => 'manual',
'confidence' => 100,
'enabled' => 1,
'created_at' => $now,
'updated_at' => $now,
] );
if ( ! $wpdb->insert_id ) {
return new WP_Error( 'yougitai_rule_save_failed', __( 'Protection rule could not be saved.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'rule_created', __( 'Protection rule created.', 'yougitai-secure-showcase' ), $repository_id, null, [ 'rule_id' => (int) $wpdb->insert_id ] );
return (int) $wpdb->insert_id;
}
public function admin_file( int $repository_id, int $snapshot_id, int $file_id ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare(
'SELECT id,path,filename,language,content,visibility,risk_score,source_sha FROM ' . Schema::table( 'files' ) . ' WHERE id=%d AND repository_id=%d AND snapshot_id=%d',
$file_id, $repository_id, $snapshot_id
), ARRAY_A );
return $row ?: null;
}
public function add_line_rule_from_snapshot( int $repository_id, int $snapshot_id, int $file_id, int $start, int $end, string $replacement ) {
$file = $this->admin_file( $repository_id, $snapshot_id, $file_id );
if ( ! $file || $file['visibility'] === 'hidden' || $file['content'] === '' ) {
return new WP_Error( 'yougitai_file_unavailable', __( 'This file cannot be used for a line protection rule.', 'yougitai-secure-showcase' ) );
}
$lines = preg_split( '/\R/', (string) $file['content'] );
$count = is_array( $lines ) ? count( $lines ) : 0;
if ( $start < 1 || $end < $start || $end > $count ) {
return new WP_Error( 'yougitai_invalid_line_range', __( 'Please enter a valid line range.', 'yougitai-secure-showcase' ) );
}
$segment = implode( "\n", array_slice( $lines, $start - 1, $end - $start + 1 ) );
$target = wp_json_encode( [
'start' => $start,
'end' => $end,
'hash' => hash( 'sha256', $segment ),
'source_sha' => (string) $file['source_sha'],
] );
return $this->add_rule( $repository_id, [
'rule_type' => 'line_range',
'file_path' => (string) $file['path'],
'target' => $target,
'action' => 'redact',
'replacement' => $replacement !== '' ? $replacement : '[PROTECTED]',
] );
}
public function add_symbol_rule_from_snapshot( int $repository_id, int $snapshot_id, int $file_id, string $symbol, string $replacement ) {
$file = $this->admin_file( $repository_id, $snapshot_id, $file_id );
if ( ! $file || $file['visibility'] === 'hidden' || $file['content'] === '' ) {
return new WP_Error( 'yougitai_file_unavailable', __( 'This file cannot be used for a symbol protection rule.', 'yougitai-secure-showcase' ) );
}
$locator = new SymbolLocator();
$located = $locator->locate( (string) $file['path'], (string) $file['content'], $symbol );
if ( ! $located ) {
return new WP_Error( 'yougitai_symbol_not_unique', __( 'The symbol could not be located uniquely in this file.', 'yougitai-secure-showcase' ) );
}
$target = wp_json_encode( [
'symbol' => trim( $symbol ),
'kind' => $located['kind'],
'signature_hash' => hash( 'sha256', $located['signature'] ),
'source_sha' => (string) $file['source_sha'],
] );
return $this->add_rule( $repository_id, [
'rule_type' => 'symbol',
'file_path' => (string) $file['path'],
'target' => $target,
'action' => 'redact',
'replacement' => $replacement !== '' ? $replacement : '[PROTECTED SYMBOL]',
] );
}
public function reactivate_published_snapshot( int $repository_id, int $snapshot_id ) {
global $wpdb;
$snapshot = $this->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' ) );
}
if ( $snapshot['status'] !== 'published' || empty( $snapshot['verification_hash'] ) ) {
return new WP_Error( 'yougitai_snapshot_not_verified', __( 'Only previously published and verified snapshots can be restored.', 'yougitai-secure-showcase' ) );
}
$verifier = new SnapshotVerifier();
$verification = $verifier->verify( $snapshot_id );
if ( ! $verification['ok'] ) {
$this->audit->log( 'snapshot_rollback_blocked', __( 'Snapshot restore was blocked by verification.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'issues' => $verification['issues'] ] );
return new WP_Error( 'yougitai_snapshot_restore_blocked', sprintf(
__( 'Restore was blocked by the final leak scan: %s', 'yougitai-secure-showcase' ),
implode( ' | ', $verification['issues'] )
) );
}
if ( ! hash_equals( (string) $snapshot['verification_hash'], (string) $verification['verification_hash'] ) ) {
$this->audit->log( 'snapshot_rollback_hash_mismatch', __( 'Snapshot restore was blocked because its verification hash changed.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id );
return new WP_Error( 'yougitai_snapshot_hash_changed', __( 'Restore was blocked because the stored public snapshot has changed since verification.', 'yougitai-secure-showcase' ) );
}
$ok = $wpdb->update( Schema::table( 'repositories' ), [
'active_snapshot_id' => $snapshot_id,
'status' => 'published',
'updated_at' => current_time( 'mysql' ),
], [ 'id' => $repository_id ] );
if ( $ok === false ) {
return new WP_Error( 'yougitai_snapshot_restore_failed', __( 'The snapshot could not be restored.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'snapshot_reactivated', __( 'Previously verified snapshot restored.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id, [ 'verification_hash' => $verification['verification_hash'] ] );
return true;
}
public function set_publication_state( int $repository_id, string $status, string $access_mode = 'public', string $password = '' ) {
$repository = $this->find( $repository_id );
if ( ! $repository ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$allowed_status = [ 'draft', 'published' ];
$allowed_access = [ 'public', 'private', 'password' ];
if ( ! in_array( $status, $allowed_status, true ) || ! in_array( $access_mode, $allowed_access, true ) ) {
return new WP_Error( 'yougitai_invalid_publication_state', __( 'Invalid publication state.', 'yougitai-secure-showcase' ) );
}
if ( $status === 'published' && empty( $repository['active_snapshot_id'] ) ) {
return new WP_Error( 'yougitai_no_active_snapshot', __( 'Publish a verified snapshot before changing the public access mode.', 'yougitai-secure-showcase' ) );
}
$data = [ 'status' => $status, 'access_mode' => $access_mode, 'updated_at' => current_time( 'mysql' ) ];
if ( $access_mode === 'password' ) {
if ( $password !== '' ) {
$data['access_password_hash'] = wp_hash_password( $password );
} elseif ( empty( $repository['access_password_hash'] ) ) {
return new WP_Error( 'yougitai_password_required', __( 'Enter a password for password-protected access.', 'yougitai-secure-showcase' ) );
}
} else {
$data['access_password_hash'] = null;
}
global $wpdb;
if ( $wpdb->update( Schema::table( 'repositories' ), $data, [ 'id' => $repository_id ] ) === false ) {
return new WP_Error( 'yougitai_publication_state_failed', __( 'The showcase visibility could not be updated.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'showcase_access_changed', __( 'Showcase publication state changed.', 'yougitai-secure-showcase' ), $repository_id, $repository['active_snapshot_id'] ? (int) $repository['active_snapshot_id'] : null, [ 'status' => $status, 'access_mode' => $access_mode ] );
return true;
}
public function set_sync_mode( int $repository_id, string $mode ): bool {
if ( ! in_array( $mode, [ 'manual', 'webhook', 'hourly', 'daily' ], true ) ) {
$mode = 'manual';
}
global $wpdb;
return $wpdb->update( Schema::table( 'repositories' ), [ 'sync_mode' => $mode, 'updated_at' => current_time( 'mysql' ) ], [ 'id' => $repository_id ] ) !== false;
}
public function set_show_original( int $repository_id, bool $show_original ): bool {
if ( ! $this->find( $repository_id ) ) {
return false;
}
global $wpdb;
$ok = $wpdb->update( Schema::table( 'repositories' ), [
'show_original' => $show_original ? 1 : 0,
'updated_at' => current_time( 'mysql' ),
], [ 'id' => $repository_id ] );
if ( $ok !== false ) {
$this->audit->log(
$show_original ? 'original_mode_enabled' : 'secure_mode_enabled',
$show_original ? __( 'Original source mode enabled.', 'yougitai-secure-showcase' ) : __( 'Secure showcase mode enabled.', 'yougitai-secure-showcase' ),
$repository_id
);
}
return $ok !== false;
}
public function regenerate_webhook_secret( int $repository_id ) {
if ( ! $this->find( $repository_id ) ) {
return new WP_Error( 'yougitai_not_found', __( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$secret = SecretVault::random_secret();
$encrypted = SecretVault::encrypt( $secret );
if ( $encrypted === '' ) {
return new WP_Error( 'yougitai_secret_storage_failed', __( 'The webhook secret could not be encrypted on this server.', 'yougitai-secure-showcase' ) );
}
global $wpdb;
$ok = $wpdb->update( Schema::table( 'repositories' ), [
'webhook_secret' => $encrypted,
'sync_mode' => 'webhook',
'updated_at' => current_time( 'mysql' ),
], [ 'id' => $repository_id ] );
if ( $ok === false ) {
return new WP_Error( 'yougitai_webhook_save_failed', __( 'Webhook settings could not be saved.', 'yougitai-secure-showcase' ) );
}
$this->audit->log( 'webhook_secret_rotated', __( 'GitHub webhook secret rotated.', 'yougitai-secure-showcase' ), $repository_id );
return $secret;
}
public function webhook_configured( array $repository ): bool {
return ! empty( $repository['webhook_secret'] );
}
public function files_for_snapshot( int $repository_id, int $snapshot_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare(
'SELECT id,path,filename,extension,language,size,visibility,risk_score,redaction_manifest FROM ' . Schema::table( 'files' ) . ' WHERE repository_id=%d AND snapshot_id=%d ORDER BY path ASC',
$repository_id, $snapshot_id
), ARRAY_A ) ?: [];
}
public function files_for_public_repository( int $repository_id, int $snapshot_id ): array {
global $wpdb;
return $wpdb->get_results( $wpdb->prepare(
'SELECT f.id,f.path,f.filename,f.extension,f.language,f.size,f.visibility,f.risk_score,f.redaction_manifest,(SELECT COUNT(*) FROM ' . Schema::table( 'findings' ) . ' x WHERE x.file_id=f.id AND x.snapshot_id=f.snapshot_id AND x.recommendation IN (\'redact\',\'hide\')) AS protection_finding_count FROM ' . Schema::table( 'files' ) . ' f WHERE f.repository_id=%d AND f.snapshot_id=%d ORDER BY f.path ASC',
$repository_id,
$snapshot_id
), ARRAY_A ) ?: [];
}
public function public_showcase_profile( int $repository_id, int $snapshot_id ): array {
global $wpdb;
$repository = $this->find( $repository_id );
if ( ! $repository ) return [];
$files = $wpdb->get_results( $wpdb->prepare(
'SELECT id,path,filename,extension,language,size,visibility,risk_score,redaction_manifest FROM ' . Schema::table( 'files' ) . ' WHERE repository_id=%d AND snapshot_id=%d ORDER BY path ASC',
$repository_id, $snapshot_id
), ARRAY_A ) ?: [];
return ( new ShowcaseAnalyzer() )->analyze( $repository, $files );
}
public function public_readme( int $repository_id, int $snapshot_id ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare(
"SELECT id,path,filename,language,content,visibility,redaction_manifest FROM " . Schema::table( 'files' ) . " WHERE repository_id=%d AND snapshot_id=%d AND visibility != %s AND (LOWER(filename)='readme.md' OR LOWER(filename)='readme') ORDER BY CHAR_LENGTH(path) ASC LIMIT 1",
$repository_id, $snapshot_id, 'hidden'
), ARRAY_A );
return $row ?: null;
}
public function public_file( int $repository_id, int $snapshot_id, int $file_id ): ?array {
global $wpdb;
$row = $wpdb->get_row( $wpdb->prepare(
"SELECT id,path,filename,language,CASE WHEN visibility='hidden' THEN '' ELSE content END AS content,visibility,redaction_manifest FROM " . Schema::table( 'files' ) . ' WHERE id=%d AND repository_id=%d AND snapshot_id=%d',
$file_id, $repository_id, $snapshot_id
), ARRAY_A );
return $row ?: null;
}
private function insert_public_file( int $repository_id, int $snapshot_id, string $path, int $size, array $node, array $public, string $now ): int {
global $wpdb;
$filename = basename( $path );
$extension = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
$content = (string) ( $public['content'] ?? '' );
$wpdb->insert( Schema::table( 'files' ), [
'repository_id' => $repository_id,
'snapshot_id' => $snapshot_id,
'path' => $path,
'path_hash' => hash( 'sha256', $path ),
'filename' => $filename,
'extension' => $extension,
'language' => $this->language_for_extension( $extension ),
'size' => strlen( $content ),
'source_sha' => sanitize_text_field( $node['sha'] ?? '' ),
'visibility' => $public['visibility'],
'risk_score' => min( 100, max( 0, (int) $public['risk_score'] ) ),
'content' => $content,
'redaction_manifest' => wp_json_encode( array_values( is_array( $public['redactions'] ?? null ) ? $public['redactions'] : [] ) ),
'content_hash' => hash( 'sha256', $content ),
'created_at' => $now,
'updated_at' => $now,
] );
return (int) $wpdb->insert_id;
}
private function should_ai_review( string $path, string $content, string $profile ): bool {
if ( strlen( $content ) < 80 ) {
return false;
}
$extension = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
$code_extensions = [ 'php', 'js', 'jsx', 'ts', 'tsx', 'py', 'java', 'kt', 'swift', 'dart', 'go', 'rb', 'rs', 'cs', 'sql', 'md', 'json', 'yml', 'yaml' ];
if ( ! in_array( $extension, $code_extensions, true ) ) {
return false;
}
if ( $profile === 'maximum' || $profile === 'investor' ) {
return true;
}
return (bool) preg_match( '#(^|/)(ai|ml|payment|billing|auth|security|service|engine|core|api|config|database|models?)(/|\.|$)#i', $path );
}
private function parse_github_url( string $url ) {
$host = wp_parse_url( $url, PHP_URL_HOST );
$path = trim( (string) wp_parse_url( $url, PHP_URL_PATH ), '/' );
if ( ! in_array( strtolower( (string) $host ), [ 'github.com', 'www.github.com' ], true ) ) {
return new WP_Error( 'yougitai_invalid_url', __( 'Please enter a valid GitHub repository URL.', 'yougitai-secure-showcase' ) );
}
$parts = explode( '/', preg_replace( '/\.git$/', '', $path ) );
if ( count( $parts ) < 2 || ! $parts[0] || ! $parts[1] ) {
return new WP_Error( 'yougitai_invalid_url', __( 'Please enter a valid GitHub repository URL.', 'yougitai-secure-showcase' ) );
}
return [ sanitize_text_field( $parts[0] ), sanitize_text_field( $parts[1] ) ];
}
private function ignored_path( string $path ): bool {
return (bool) preg_match( '#(^|/)(node_modules|vendor|dist|build|coverage|\.git|\.next|\.cache)(/|$)#i', $path );
}
private function looks_binary( string $content ): bool {
return strpos( substr( $content, 0, 8000 ), "\0" ) !== false;
}
private function language_for_extension( string $ext ): string {
$map = [ 'php'=>'PHP','js'=>'JavaScript','jsx'=>'JavaScript','ts'=>'TypeScript','tsx'=>'TypeScript','html'=>'HTML','css'=>'CSS','scss'=>'SCSS','json'=>'JSON','yml'=>'YAML','yaml'=>'YAML','md'=>'Markdown','py'=>'Python','java'=>'Java','kt'=>'Kotlin','swift'=>'Swift','sql'=>'SQL','sh'=>'Shell','dart'=>'Dart','xml'=>'XML','go'=>'Go','rb'=>'Ruby','rs'=>'Rust','cs'=>'C#' ];
return $map[ $ext ] ?? strtoupper( $ext ?: 'text' );
}
}

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%