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/Admin/Admin.phpPHP
<?php
namespace YougitAI\SecureShowcase\Admin;
use YougitAI\SecureShowcase\Repository\RepositoryService;
use YougitAI\SecureShowcase\Audit\Logger;
use YougitAI\SecureShowcase\Security\SecretVault;
use YougitAI\SecureShowcase\Security\ConnectionTokenService;
use YougitAI\SecureShowcase\Sync\SyncManager;
use YougitAI\SecureShowcase\GitHub\OAuth as GitHubOAuth;
use YougitAI\SecureShowcase\GitHub\Client as GitHubClient;
use YougitAI\SecureShowcase\Support\SystemStatus;
use YougitAI\SecureShowcase\AI\ProviderFactory;
final class Admin {
public function __construct( private RepositoryService $repositories, private SyncManager $sync ) {}
public function register(): void {
add_action( 'admin_menu', [ $this, 'menu' ] );
add_action( 'admin_post_yougitai_ss_add_repository', [ $this, 'add_repository' ] );
add_action( 'admin_post_yougitai_ss_import_selected_repositories', [ $this, 'import_selected_repositories' ] );
add_action( 'admin_post_yougitai_ss_refresh_github_repositories', [ $this, 'refresh_github_repositories' ] );
add_action( 'admin_post_yougitai_ss_import_snapshot', [ $this, 'import_snapshot' ] );
add_action( 'admin_post_yougitai_ss_apply_protection_rules', [ $this, 'apply_protection_rules' ] );
add_action( 'admin_post_yougitai_ss_approve_snapshot', [ $this, 'approve_snapshot' ] );
add_action( 'admin_post_yougitai_ss_publish_snapshot', [ $this, 'publish_snapshot' ] );
add_action( 'admin_post_yougitai_ss_set_publication_state', [ $this, 'set_publication_state' ] );
add_action( 'admin_post_yougitai_ss_resolve_finding', [ $this, 'resolve_finding' ] );
add_action( 'admin_post_yougitai_ss_bulk_findings', [ $this, 'bulk_findings' ] );
add_action( 'admin_post_yougitai_ss_bulk_files', [ $this, 'bulk_files' ] );
add_action( 'admin_post_yougitai_ss_ai_protect_snapshot', [ $this, 'ai_protect_snapshot' ] );
add_action( 'admin_post_yougitai_ss_add_rule', [ $this, 'add_rule' ] );
add_action( 'admin_post_yougitai_ss_add_line_rule', [ $this, 'add_line_rule' ] );
add_action( 'admin_post_yougitai_ss_add_symbol_rule', [ $this, 'add_symbol_rule' ] );
add_action( 'admin_post_yougitai_ss_restore_snapshot', [ $this, 'restore_snapshot' ] );
add_action( 'admin_post_yougitai_ss_queue_sync', [ $this, 'queue_sync' ] );
add_action( 'admin_post_yougitai_ss_rotate_webhook', [ $this, 'rotate_webhook' ] );
add_action( 'admin_post_yougitai_ss_set_sync_mode', [ $this, 'set_sync_mode' ] );
add_action( 'admin_post_yougitai_ss_set_display_mode', [ $this, 'set_display_mode' ] );
add_action( 'admin_post_yougitai_ss_save_settings', [ $this, 'save_settings' ] );
add_action( 'admin_post_yougitai_ss_create_connection', [ $this, 'create_connection' ] );
add_action( 'admin_post_yougitai_ss_revoke_connection', [ $this, 'revoke_connection' ] );
add_action( 'admin_post_yougitai_ss_revoke_oauth_connection', [ $this, 'revoke_oauth_connection' ] );
add_action( 'admin_post_yougitai_ss_toggle_rule', [ $this, 'toggle_rule' ] );
add_action( 'admin_post_yougitai_ss_bulk_approve_rules', [ $this, 'bulk_approve_rules' ] );
add_action( 'admin_post_yougitai_ss_github_oauth_start', [ $this, 'github_oauth_start' ] );
add_action( 'admin_post_yougitai_ss_github_oauth_callback', [ $this, 'github_oauth_callback' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'assets' ] );
}
public function menu(): void {
add_menu_page(
__( 'YougitAI Showcases', 'yougitai-secure-showcase' ),
__( 'YougitAI', 'yougitai-secure-showcase' ),
'manage_options',
'yougitai-secure-showcase',
[ $this, 'screen' ],
'dashicons-lock',
58
);
add_submenu_page(
'yougitai-secure-showcase',
__( 'Repositories', 'yougitai-secure-showcase' ),
__( 'Repositories', 'yougitai-secure-showcase' ),
'manage_options',
'yougitai-secure-showcase',
[ $this, 'screen' ]
);
add_submenu_page(
'yougitai-secure-showcase',
__( 'Settings', 'yougitai-secure-showcase' ),
__( 'Settings', 'yougitai-secure-showcase' ),
'manage_options',
'yougitai-secure-showcase-settings',
[ $this, 'settings_screen' ]
);
}
public function assets( string $hook ): void {
if ( ! str_contains( $hook, 'yougitai-secure-showcase' ) ) {
return;
}
wp_enqueue_style( 'yougitai-ss-admin', YOUGITAI_SS_URL . 'assets/css/admin.css', [], YOUGITAI_SS_VERSION );
wp_enqueue_script( 'yougitai-ss-admin', YOUGITAI_SS_URL . 'assets/js/admin.js', [], YOUGITAI_SS_VERSION, true );
}
public function screen(): void {
$this->guard();
$repository_id = isset( $_GET['repository_id'] ) ? absint( $_GET['repository_id'] ) : 0;
$message = isset( $_GET['yougitai_message'] ) ? sanitize_text_field( wp_unslash( $_GET['yougitai_message'] ) ) : '';
$error = isset( $_GET['yougitai_error'] ) ? sanitize_text_field( wp_unslash( $_GET['yougitai_error'] ) ) : '';
if ( $repository_id ) {
$repository = $this->repositories->find( $repository_id );
if ( ! $repository ) {
wp_die( esc_html__( 'Repository not found.', 'yougitai-secure-showcase' ) );
}
$snapshots = $this->repositories->snapshots( $repository_id );
$rules = $this->repositories->rules( $repository_id );
$selected_snapshot_id = isset( $_GET['snapshot_id'] ) ? absint( $_GET['snapshot_id'] ) : (int) ( $snapshots[0]['id'] ?? 0 );
$selected_snapshot = $selected_snapshot_id ? $this->repositories->snapshot( $selected_snapshot_id ) : null;
$findings = $selected_snapshot_id ? $this->repositories->findings_for_snapshot( $selected_snapshot_id ) : [];
$files = $selected_snapshot_id ? $this->repositories->files_for_snapshot( $repository_id, $selected_snapshot_id ) : [];
$selected_file_id = isset( $_GET['file_id'] ) ? absint( $_GET['file_id'] ) : 0;
$selected_file = ( $selected_snapshot_id && $selected_file_id ) ? $this->repositories->admin_file( $repository_id, $selected_snapshot_id, $selected_file_id ) : null;
$audit_events = ( new Logger() )->recent_for_repository( $repository_id, 30 );
$webhook_url = rest_url( 'yougitai-secure-showcase/v1/github/webhook/' . $repository_id );
$ai_provider = sanitize_key( (string) get_option( 'yougitai_ss_ai_provider', 'openai' ) );
$ai_external_enabled = (bool) get_option( 'yougitai_ss_external_ai_enabled', false );
$ai_runtime = ProviderFactory::make();
$ai_configured = $ai_runtime->is_configured();
$webhook_secret_once = get_transient( 'yougitai_ss_webhook_secret_' . get_current_user_id() . '_' . $repository_id );
if ( $webhook_secret_once ) {
delete_transient( 'yougitai_ss_webhook_secret_' . get_current_user_id() . '_' . $repository_id );
}
include YOUGITAI_SS_DIR . 'templates/admin-repository.php';
return;
}
$repositories = $this->repositories->all();
$github_repositories = [];
$github_repository_error = '';
$github_connected = SecretVault::decrypt( (string) get_option( 'yougitai_ss_github_token', '' ) ) !== '';
if ( $github_connected ) {
$github_repositories_result = ( new GitHubClient() )->list_repositories();
if ( is_wp_error( $github_repositories_result ) ) {
$github_repository_error = $github_repositories_result->get_error_message();
} else {
$github_repositories = $github_repositories_result;
}
}
$imported_github_repositories = [];
foreach ( $repositories as $existing_repository ) {
$imported_github_repositories[ strtolower( (string) $existing_repository['owner'] . '/' . (string) $existing_repository['repo'] ) ] = (int) $existing_repository['id'];
}
include YOUGITAI_SS_DIR . 'templates/admin-repositories.php';
}
public function settings_screen(): void {
$this->guard();
$message = isset( $_GET['yougitai_message'] ) ? sanitize_text_field( wp_unslash( $_GET['yougitai_message'] ) ) : '';
$error = isset( $_GET['yougitai_error'] ) ? sanitize_text_field( wp_unslash( $_GET['yougitai_error'] ) ) : '';
$connection_tokens = new ConnectionTokenService();
$connections = $connection_tokens->active();
$oauth_connections = $connection_tokens->active_oauth();
$connection_token_once = get_transient( 'yougitai_ss_connection_token_' . get_current_user_id() );
if ( $connection_token_once ) { delete_transient( 'yougitai_ss_connection_token_' . get_current_user_id() ); }
$connected_ai_mcp_url = rest_url( 'yougitai-secure-showcase/v1/connected-ai/mcp' );
$available_repositories = $this->repositories->all();
$system_checks = ( new SystemStatus() )->checks();
$settings = [
'showcase_slug' => (string) get_option( 'yougitai_ss_showcase_slug', 'repositories' ),
'index_title_de' => (string) get_option( 'yougitai_ss_index_title_de', '' ),
'index_description_de' => (string) get_option( 'yougitai_ss_index_description_de', '' ),
'index_title_en' => (string) get_option( 'yougitai_ss_index_title_en', '' ),
'index_description_en' => (string) get_option( 'yougitai_ss_index_description_en', '' ),
'external_ai_enabled' => (bool) get_option( 'yougitai_ss_external_ai_enabled', false ),
'ai_provider' => (string) get_option( 'yougitai_ss_ai_provider', 'openai' ),
'openai_model' => (string) get_option( 'yougitai_ss_openai_model', 'gpt-5.6-luna' ),
'anthropic_model' => (string) get_option( 'yougitai_ss_anthropic_model', 'claude-sonnet-5' ),
'gemini_model' => (string) get_option( 'yougitai_ss_gemini_model', 'gemini-3.8-flash' ),
'has_openai_key' => $this->stored_secret_present( 'yougitai_ss_openai_api_key' ),
'has_anthropic_key' => $this->stored_secret_present( 'yougitai_ss_anthropic_api_key' ),
'has_gemini_key' => $this->stored_secret_present( 'yougitai_ss_gemini_api_key' ),
'has_github_token' => SecretVault::decrypt( (string) get_option( 'yougitai_ss_github_token', '' ) ) !== '',
'github_auth_method' => (string) get_option( 'yougitai_ss_github_auth_method', 'token' ),
'github_oauth_client_id' => (string) get_option( 'yougitai_ss_github_oauth_client_id', '' ),
'has_github_oauth_secret' => $this->stored_secret_present( 'yougitai_ss_github_oauth_client_secret' ),
'github_oauth_callback' => ( new GitHubOAuth() )->callback_url(),
'delete_data_on_uninstall' => (bool) get_option( 'yougitai_ss_delete_data_on_uninstall', false ),
'color_surface' => (string) get_option( 'yougitai_ss_color_surface', '#0d1117' ),
'color_panel' => (string) get_option( 'yougitai_ss_color_panel', '#161b22' ),
'color_code' => (string) get_option( 'yougitai_ss_color_code', '#0d1117' ),
'color_border' => (string) get_option( 'yougitai_ss_color_border', '#30363d' ),
'color_text' => (string) get_option( 'yougitai_ss_color_text', '#c9d1d9' ),
'color_muted' => (string) get_option( 'yougitai_ss_color_muted', '#8b949e' ),
'color_accent' => (string) get_option( 'yougitai_ss_color_accent', '#58a6ff' ),
'color_accent_hover' => (string) get_option( 'yougitai_ss_color_accent_hover', '#79c0ff' ),
'color_nav_hover' => (string) get_option( 'yougitai_ss_color_nav_hover', '#79c0ff' ),
'color_nav_underline' => (string) get_option( 'yougitai_ss_color_nav_underline', '#79c0ff' ),
'color_tree_hover_bg' => (string) get_option( 'yougitai_ss_color_tree_hover_bg', '#161b22' ),
'color_tree_hover_text' => (string) get_option( 'yougitai_ss_color_tree_hover_text', '#f0f6fc' ),
'color_tree_active_bg' => (string) get_option( 'yougitai_ss_color_tree_active_bg', '#1f2328' ),
'color_tree_active_marker' => (string) get_option( 'yougitai_ss_color_tree_active_marker', '#8b949e' ),
'color_focus' => (string) get_option( 'yougitai_ss_color_focus', '#f0f6fc' ),
'color_progress' => (string) get_option( 'yougitai_ss_color_progress', '#3fb950' ),
'color_progress_track' => (string) get_option( 'yougitai_ss_color_progress_track', '#21262d' ),
'color_selected' => (string) get_option( 'yougitai_ss_color_selected', '#1f2d3d' ),
'color_warning_bg' => (string) get_option( 'yougitai_ss_color_warning_bg', '#3b2f0b' ),
'color_warning_border' => (string) get_option( 'yougitai_ss_color_warning_border', '#9e6a03' ),
'color_warning_text' => (string) get_option( 'yougitai_ss_color_warning_text', '#e3b341' ),
'color_blackout' => (string) get_option( 'yougitai_ss_color_blackout', '#020409' ),
'color_blackout_edge' => (string) get_option( 'yougitai_ss_color_blackout_edge', '#30363d' ),
];
include YOUGITAI_SS_DIR . 'templates/admin-settings.php';
}
public function add_repository(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_add_repository' );
$url = isset( $_POST['github_url'] ) ? esc_url_raw( wp_unslash( $_POST['github_url'] ) ) : '';
$profile = isset( $_POST['protection_profile'] ) ? sanitize_key( wp_unslash( $_POST['protection_profile'] ) ) : 'balanced';
$result = $this->repositories->create_from_github_url( $url, $profile );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message() );
}
$this->redirect_repository( (int) $result, __( 'Repository added.', 'yougitai-secure-showcase' ) );
}
public function import_selected_repositories(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_import_selected_repositories' );
$selected_ids = isset( $_POST['github_repository_ids'] ) && is_array( $_POST['github_repository_ids'] )
? array_values( array_unique( array_filter( array_map( 'absint', wp_unslash( $_POST['github_repository_ids'] ) ) ) ) )
: [];
if ( empty( $selected_ids ) ) {
$this->redirect_error( __( 'Select at least one GitHub repository to import.', 'yougitai-secure-showcase' ) );
}
$profile = isset( $_POST['protection_profile'] ) ? sanitize_key( wp_unslash( $_POST['protection_profile'] ) ) : 'balanced';
$client = new GitHubClient();
$available = $client->list_repositories();
if ( is_wp_error( $available ) ) {
$this->redirect_error( $available->get_error_message() );
}
$available_by_id = [];
foreach ( $available as $repository ) {
$available_by_id[ (int) $repository['id'] ] = $repository;
}
$imported = 0;
$skipped = 0;
$errors = [];
$existing = [];
foreach ( $this->repositories->all() as $repository ) {
$existing[ strtolower( (string) $repository['owner'] . '/' . (string) $repository['repo'] ) ] = true;
}
foreach ( $selected_ids as $github_id ) {
if ( empty( $available_by_id[ $github_id ] ) ) {
$errors[] = __( 'A selected repository is no longer available through the connected GitHub account.', 'yougitai-secure-showcase' );
continue;
}
$repository = $available_by_id[ $github_id ];
$key = strtolower( (string) $repository['full_name'] );
if ( isset( $existing[ $key ] ) ) {
$skipped++;
continue;
}
$result = $this->repositories->create_from_github_url( (string) $repository['html_url'], $profile );
if ( is_wp_error( $result ) ) {
$errors[] = sprintf( '%s: %s', (string) $repository['full_name'], $result->get_error_message() );
continue;
}
$existing[ $key ] = true;
$imported++;
}
if ( $imported === 0 && ! empty( $errors ) ) {
$this->redirect_error( implode( ' | ', array_slice( $errors, 0, 3 ) ) );
}
$message = sprintf(
__( '%1$d GitHub repositories imported. %2$d already existed and were skipped.', 'yougitai-secure-showcase' ),
$imported,
$skipped
);
if ( ! empty( $errors ) ) {
$message .= ' ' . sprintf( __( '%d repositories could not be imported.', 'yougitai-secure-showcase' ), count( $errors ) );
}
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase', 'yougitai_message' => rawurlencode( $message ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function refresh_github_repositories(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_refresh_github_repositories' );
( new GitHubClient() )->clear_repository_cache();
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase', 'yougitai_message' => rawurlencode( __( 'GitHub repository list refreshed.', 'yougitai-secure-showcase' ) ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function import_snapshot(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_import_snapshot_' . $repository_id );
$result = $this->repositories->import_snapshot( $repository_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id );
}
$message = sprintf(
__( 'Snapshot imported: %1$d files processed, %2$d findings detected.', 'yougitai-secure-showcase' ),
(int) $result['files'],
(int) $result['findings']
);
$this->redirect_repository( $repository_id, $message, (int) $result['snapshot_id'] );
}
public function apply_protection_rules(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$base_snapshot_id = isset( $_POST['base_snapshot_id'] ) ? absint( $_POST['base_snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_apply_protection_rules_' . $repository_id );
$result = $this->repositories->rebuild_protected_snapshot( $repository_id, $base_snapshot_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $base_snapshot_id );
}
$this->redirect_repository(
$repository_id,
__( 'Protection applied. A new review draft was created from the existing safe snapshot; GitHub was not contacted.', 'yougitai-secure-showcase' ),
(int) $result['snapshot_id']
);
}
public function approve_snapshot(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_approve_snapshot_' . $snapshot_id );
$result = $this->repositories->approve_snapshot_review( $repository_id, $snapshot_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Snapshot review approved.', 'yougitai-secure-showcase' ), $snapshot_id );
}
public function publish_snapshot(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_publish_snapshot_' . $snapshot_id );
$snapshot = $this->repositories->snapshot( $snapshot_id );
if ( $snapshot && ! in_array( (string) $snapshot['review_status'], [ 'approved', 'ready' ], true ) ) {
$approval = $this->repositories->approve_snapshot_review( $repository_id, $snapshot_id );
if ( is_wp_error( $approval ) ) {
$this->redirect_error( $approval->get_error_message(), $repository_id, $snapshot_id );
}
}
$result = $this->repositories->publish_snapshot( $repository_id, $snapshot_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Verified snapshot published.', 'yougitai-secure-showcase' ), $snapshot_id );
}
public function set_publication_state(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_set_publication_state_' . $repository_id );
$status = isset( $_POST['publication_status'] ) ? sanitize_key( wp_unslash( $_POST['publication_status'] ) ) : 'draft';
$access_mode = isset( $_POST['access_mode'] ) ? sanitize_key( wp_unslash( $_POST['access_mode'] ) ) : 'public';
$password = isset( $_POST['access_password'] ) ? (string) wp_unslash( $_POST['access_password'] ) : '';
$result = $this->repositories->set_publication_state( $repository_id, $status, $access_mode, $password );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id );
}
$this->redirect_repository( $repository_id, __( 'Showcase visibility updated.', 'yougitai-secure-showcase' ) );
}
public function resolve_finding(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
$finding_id = isset( $_POST['finding_id'] ) ? absint( $_POST['finding_id'] ) : 0;
$status = isset( $_POST['finding_status'] ) ? sanitize_key( wp_unslash( $_POST['finding_status'] ) ) : 'resolved';
check_admin_referer( 'yougitai_ss_finding_' . $finding_id );
$result = $this->repositories->resolve_finding( $repository_id, $snapshot_id, $finding_id, $status );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Finding updated.', 'yougitai-secure-showcase' ), $snapshot_id );
}
public function bulk_findings(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_bulk_findings_' . $snapshot_id );
$status = isset( $_POST['finding_status'] ) ? sanitize_key( wp_unslash( $_POST['finding_status'] ) ) : 'resolved';
if ( ! in_array( $status, [ 'resolved', 'accepted', 'ignored' ], true ) ) {
$status = 'resolved';
}
$groups = isset( $_POST['finding_groups'] ) && is_array( $_POST['finding_groups'] ) ? wp_unslash( $_POST['finding_groups'] ) : [];
$ids = [];
foreach ( $groups as $group ) {
foreach ( explode( ',', (string) $group ) as $id ) {
$id = absint( $id );
if ( $id ) $ids[ $id ] = $id;
}
}
if ( empty( $ids ) ) {
$this->redirect_error( __( 'Select at least one finding group first.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id );
}
$updated = 0;
foreach ( $ids as $finding_id ) {
$result = $this->repositories->resolve_finding( $repository_id, $snapshot_id, $finding_id, $status );
if ( ! is_wp_error( $result ) ) $updated++;
}
$this->redirect_repository( $repository_id, sprintf( __( '%d findings updated.', 'yougitai-secure-showcase' ), $updated ), $snapshot_id );
}
public function bulk_files(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_bulk_files_' . $snapshot_id );
$file_ids = isset( $_POST['file_ids'] ) && is_array( $_POST['file_ids'] ) ? array_values( array_filter( array_map( 'absint', wp_unslash( $_POST['file_ids'] ) ) ) ) : [];
if ( empty( $file_ids ) ) {
$this->redirect_error( __( 'Select at least one file first.', 'yougitai-secure-showcase' ), $repository_id, $snapshot_id );
}
$added = 0;
foreach ( $file_ids as $file_id ) {
$file = $this->repositories->admin_file( $repository_id, $snapshot_id, $file_id );
if ( ! $file ) continue;
$result = $this->repositories->add_rule( $repository_id, [
'rule_type' => 'path',
'file_path' => '',
'target' => (string) $file['path'],
'action' => 'hide',
'replacement' => '[PROTECTED]',
] );
if ( ! is_wp_error( $result ) ) $added++;
}
$this->redirect_repository( $repository_id, sprintf( __( '%d files will be hidden on the next import.', 'yougitai-secure-showcase' ), $added ), $snapshot_id );
}
public function ai_protect_snapshot(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_ai_protect_snapshot_' . $repository_id );
$repository = $this->repositories->find( $repository_id );
if ( ! $repository ) {
$this->redirect_error( __( 'Repository not found.', 'yougitai-secure-showcase' ), $repository_id );
}
if ( ! empty( $repository['show_original'] ) ) {
$this->redirect_error( __( 'AI protection is disabled while Original source mode is active.', 'yougitai-secure-showcase' ), $repository_id );
}
$provider = sanitize_key( (string) get_option( 'yougitai_ss_ai_provider', 'openai' ) );
if ( $provider === 'direct' ) {
$this->redirect_error( __( 'ChatGPT (DIRECT) runs from a connected ChatGPT conversation. Open Settings for the DIRECT connection instructions.', 'yougitai-secure-showcase' ), $repository_id );
}
$ai = ProviderFactory::make();
if ( ! $ai->is_configured() ) {
$this->redirect_error( __( 'Configure and enable an AI provider in Settings before starting AI protection.', 'yougitai-secure-showcase' ), $repository_id );
}
$result = $this->repositories->import_snapshot( $repository_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id );
}
$this->redirect_repository( $repository_id, __( 'A new secure draft was created with AI-assisted review enabled. Review its findings before publishing.', 'yougitai-secure-showcase' ), (int) $result['snapshot_id'] );
}
public function add_rule(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_add_rule_' . $repository_id );
$result = $this->repositories->add_rule( $repository_id, [
'rule_type' => isset( $_POST['rule_type'] ) ? sanitize_key( wp_unslash( $_POST['rule_type'] ) ) : 'path',
'file_path' => isset( $_POST['file_path'] ) ? sanitize_text_field( wp_unslash( $_POST['file_path'] ) ) : '',
'target' => isset( $_POST['target'] ) ? wp_unslash( $_POST['target'] ) : '',
'action' => isset( $_POST['rule_action'] ) ? sanitize_key( wp_unslash( $_POST['rule_action'] ) ) : 'hide',
'replacement' => isset( $_POST['replacement'] ) ? wp_unslash( $_POST['replacement'] ) : '[PROTECTED]',
] );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id );
}
$this->redirect_repository( $repository_id, __( 'Protection rule added. Import a new snapshot to apply it.', 'yougitai-secure-showcase' ) );
}
public function add_line_rule(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
$file_id = isset( $_POST['file_id'] ) ? absint( $_POST['file_id'] ) : 0;
check_admin_referer( 'yougitai_ss_add_line_rule_' . $file_id );
$start = isset( $_POST['line_start'] ) ? absint( $_POST['line_start'] ) : 0;
$end = isset( $_POST['line_end'] ) ? absint( $_POST['line_end'] ) : 0;
$replacement = isset( $_POST['replacement'] ) ? sanitize_textarea_field( wp_unslash( $_POST['replacement'] ) ) : '[PROTECTED]';
$result = $this->repositories->add_line_rule_from_snapshot( $repository_id, $snapshot_id, $file_id, $start, $end, $replacement );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Line protection rule added. Import a new snapshot to apply it safely.', 'yougitai-secure-showcase' ), $snapshot_id, $file_id );
}
public function add_symbol_rule(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
$file_id = isset( $_POST['file_id'] ) ? absint( $_POST['file_id'] ) : 0;
check_admin_referer( 'yougitai_ss_add_symbol_rule_' . $file_id );
$symbol = isset( $_POST['symbol'] ) ? sanitize_text_field( wp_unslash( $_POST['symbol'] ) ) : '';
$replacement = isset( $_POST['replacement'] ) ? sanitize_textarea_field( wp_unslash( $_POST['replacement'] ) ) : '[PROTECTED SYMBOL]';
$result = $this->repositories->add_symbol_rule_from_snapshot( $repository_id, $snapshot_id, $file_id, $symbol, $replacement );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Symbol protection rule added. Import a new snapshot to apply it safely.', 'yougitai-secure-showcase' ), $snapshot_id, $file_id );
}
public function restore_snapshot(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$snapshot_id = isset( $_POST['snapshot_id'] ) ? absint( $_POST['snapshot_id'] ) : 0;
check_admin_referer( 'yougitai_ss_restore_snapshot_' . $snapshot_id );
$result = $this->repositories->reactivate_published_snapshot( $repository_id, $snapshot_id );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id, $snapshot_id );
}
$this->redirect_repository( $repository_id, __( 'Previously verified snapshot restored.', 'yougitai-secure-showcase' ), $snapshot_id );
}
public function queue_sync(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_queue_sync_' . $repository_id );
if ( ! $this->repositories->find( $repository_id ) || ! $this->sync->enqueue( $repository_id ) ) {
$this->redirect_error( __( 'The secure sync could not be queued.', 'yougitai-secure-showcase' ), $repository_id );
}
$this->redirect_repository( $repository_id, __( 'Secure sync queued. It will create a draft snapshot and will not publish automatically.', 'yougitai-secure-showcase' ) );
}
public function rotate_webhook(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_rotate_webhook_' . $repository_id );
$secret = $this->repositories->regenerate_webhook_secret( $repository_id );
if ( is_wp_error( $secret ) ) {
$this->redirect_error( $secret->get_error_message(), $repository_id );
}
set_transient( 'yougitai_ss_webhook_secret_' . get_current_user_id() . '_' . $repository_id, $secret, 120 );
$this->redirect_repository( $repository_id, __( 'Webhook secret generated. Copy it now; it will only be shown once.', 'yougitai-secure-showcase' ) );
}
public function set_sync_mode(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_set_sync_mode_' . $repository_id );
$mode = isset( $_POST['sync_mode'] ) ? sanitize_key( wp_unslash( $_POST['sync_mode'] ) ) : 'manual';
if ( ! $this->repositories->set_sync_mode( $repository_id, $mode ) ) {
$this->redirect_error( __( 'Sync mode could not be saved.', 'yougitai-secure-showcase' ), $repository_id );
}
$this->sync->configure_schedule( $repository_id, $mode );
$this->redirect_repository( $repository_id, __( 'Sync mode saved.', 'yougitai-secure-showcase' ) );
}
public function set_display_mode(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_set_display_mode_' . $repository_id );
$mode = isset( $_POST['display_mode'] ) ? sanitize_key( wp_unslash( $_POST['display_mode'] ) ) : 'secure';
$show_original = $mode === 'original';
if ( $show_original && empty( $_POST['confirm_original'] ) ) {
$this->redirect_error( __( 'Confirm that you understand the full repository source will be stored in the public snapshot and can be viewed by visitors.', 'yougitai-secure-showcase' ), $repository_id );
}
if ( ! $this->repositories->set_show_original( $repository_id, $show_original ) ) {
$this->redirect_error( __( 'Display mode could not be saved.', 'yougitai-secure-showcase' ), $repository_id );
}
$this->redirect_repository( $repository_id, $show_original
? __( 'Original source mode enabled. Import a new snapshot before publishing the unredacted version.', 'yougitai-secure-showcase' )
: __( 'Secure showcase mode enabled. Protection rules will be applied to the next imported snapshot.', 'yougitai-secure-showcase' )
);
}
public function create_connection(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_create_connection' );
$label = isset( $_POST['connection_label'] ) ? sanitize_text_field( wp_unslash( $_POST['connection_label'] ) ) : '';
$ttl = isset( $_POST['connection_ttl'] ) ? absint( $_POST['connection_ttl'] ) : DAY_IN_SECONDS;
if ( ! in_array( $ttl, [ HOUR_IN_SECONDS, DAY_IN_SECONDS, 7 * DAY_IN_SECONDS ], true ) ) {
$ttl = DAY_IN_SECONDS;
}
$all_repositories = ! empty( $_POST['connection_all_repositories'] );
$repository_ids = isset( $_POST['connection_repository_ids'] ) && is_array( $_POST['connection_repository_ids'] )
? array_values( array_filter( array_map( 'absint', wp_unslash( $_POST['connection_repository_ids'] ) ) ) )
: [];
$valid_repository_ids = array_map( static fn( array $row ): int => (int) $row['id'], $this->repositories->all() );
$repository_ids = array_values( array_intersect( $repository_ids, $valid_repository_ids ) );
if ( ! $all_repositories && ! empty( $valid_repository_ids ) && empty( $repository_ids ) ) {
$this->redirect_settings_error( __( 'Select at least one repository or explicitly allow all repositories for this connection.', 'yougitai-secure-showcase' ) );
}
if ( $all_repositories ) {
$repository_ids = [];
}
$service = new ConnectionTokenService();
$created = $service->create( get_current_user_id(), $label, $ttl, $repository_ids );
if ( ! $created ) {
$this->redirect_settings_error( __( 'Connected AI token could not be created.', 'yougitai-secure-showcase' ) );
}
set_transient( 'yougitai_ss_connection_token_' . get_current_user_id(), $created, 120 );
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase-settings', 'yougitai_message' => rawurlencode( __( 'Connected AI token created. Copy it now; it will only be shown once.', 'yougitai-secure-showcase' ) ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function revoke_connection(): void {
$this->guard();
$id = isset( $_POST['connection_id'] ) ? absint( $_POST['connection_id'] ) : 0;
check_admin_referer( 'yougitai_ss_revoke_connection_' . $id );
( new ConnectionTokenService() )->revoke( $id );
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase-settings', 'yougitai_message' => rawurlencode( __( 'Connected AI token revoked.', 'yougitai-secure-showcase' ) ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function revoke_oauth_connection(): void {
$this->guard();
$id = isset( $_POST['connection_id'] ) ? absint( $_POST['connection_id'] ) : 0;
check_admin_referer( 'yougitai_ss_revoke_oauth_connection_' . $id );
if ( $id <= 0 || ! ( new ConnectionTokenService() )->revoke_oauth( $id ) ) {
$this->redirect_settings_error( __( 'OAuth connection could not be revoked.', 'yougitai-secure-showcase' ) );
}
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase-settings', 'yougitai_message' => rawurlencode( __( 'OAuth connection revoked.', 'yougitai-secure-showcase' ) ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function toggle_rule(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
$rule_id = isset( $_POST['rule_id'] ) ? absint( $_POST['rule_id'] ) : 0;
check_admin_referer( 'yougitai_ss_toggle_rule_' . $rule_id );
$enabled = ! empty( $_POST['enabled'] );
$result = $this->repositories->set_rule_enabled( $repository_id, $rule_id, $enabled );
if ( is_wp_error( $result ) ) {
$this->redirect_error( $result->get_error_message(), $repository_id );
}
$this->redirect_repository( $repository_id, $enabled ? __( 'Protection proposal approved. Use “Apply protection now” to create a new protected review draft without re-importing GitHub.', 'yougitai-secure-showcase' ) : __( 'Protection rule disabled.', 'yougitai-secure-showcase' ) );
}
public function bulk_approve_rules(): void {
$this->guard();
$repository_id = isset( $_POST['repository_id'] ) ? absint( $_POST['repository_id'] ) : 0;
check_admin_referer( 'yougitai_ss_bulk_approve_rules_' . $repository_id );
$single_rule_id = isset( $_POST['single_rule_id'] ) ? absint( $_POST['single_rule_id'] ) : 0;
$rule_ids = $single_rule_id > 0
? [ $single_rule_id ]
: ( isset( $_POST['rule_ids'] ) && is_array( $_POST['rule_ids'] )
? array_values( array_unique( array_filter( array_map( 'absint', wp_unslash( $_POST['rule_ids'] ) ) ) ) )
: [] );
if ( empty( $rule_ids ) ) {
$this->redirect_error( __( 'Select at least one protection proposal.', 'yougitai-secure-showcase' ), $repository_id );
}
$approved = 0;
foreach ( $rule_ids as $rule_id ) {
$result = $this->repositories->set_rule_enabled( $repository_id, $rule_id, true );
if ( ! is_wp_error( $result ) ) {
$approved++;
}
}
if ( $approved === 0 ) {
$this->redirect_error( __( 'No protection proposals could be approved.', 'yougitai-secure-showcase' ), $repository_id );
}
$this->redirect_repository( $repository_id, sprintf( _n( '%d protection proposal approved. Apply protection now to create a new review draft.', '%d protection proposals approved. Apply protection now to create a new review draft.', $approved, 'yougitai-secure-showcase' ), $approved ) );
}
public function github_oauth_start(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_github_oauth_start' );
$url = ( new GitHubOAuth() )->authorization_url( get_current_user_id() );
if ( is_wp_error( $url ) ) $this->redirect_settings_error( $url->get_error_message() );
wp_redirect( $url ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
exit;
}
public function github_oauth_callback(): void {
$this->guard();
$code = isset( $_GET['code'] ) ? sanitize_text_field( wp_unslash( $_GET['code'] ) ) : '';
$state = isset( $_GET['state'] ) ? sanitize_text_field( wp_unslash( $_GET['state'] ) ) : '';
if ( $code === '' ) $this->redirect_settings_error( __( 'GitHub did not return an authorization code.', 'yougitai-secure-showcase' ) );
$result = ( new GitHubOAuth() )->exchange( get_current_user_id(), $code, $state );
if ( is_wp_error( $result ) ) $this->redirect_settings_error( $result->get_error_message() );
( new GitHubClient() )->clear_repository_cache();
wp_safe_redirect( add_query_arg( [ 'page' => 'yougitai-secure-showcase', 'yougitai_message' => rawurlencode( __( 'GitHub OAuth connected successfully. Select the repositories you want to import below.', 'yougitai-secure-showcase' ) ) ], admin_url( 'admin.php' ) ) );
exit;
}
public function save_settings(): void {
$this->guard();
check_admin_referer( 'yougitai_ss_save_settings' );
$old_slug = (string) get_option( 'yougitai_ss_showcase_slug', 'repositories' );
$slug = isset( $_POST['showcase_slug'] ) ? sanitize_title( wp_unslash( $_POST['showcase_slug'] ) ) : 'repositories';
if ( $slug === '' ) {
$slug = 'repositories';
}
update_option( 'yougitai_ss_showcase_slug', $slug );
update_option( 'yougitai_ss_index_title_de', isset( $_POST['index_title_de'] ) ? sanitize_text_field( wp_unslash( $_POST['index_title_de'] ) ) : '', false );
update_option( 'yougitai_ss_index_description_de', isset( $_POST['index_description_de'] ) ? sanitize_textarea_field( wp_unslash( $_POST['index_description_de'] ) ) : '', false );
update_option( 'yougitai_ss_index_title_en', isset( $_POST['index_title_en'] ) ? sanitize_text_field( wp_unslash( $_POST['index_title_en'] ) ) : '', false );
update_option( 'yougitai_ss_index_description_en', isset( $_POST['index_description_en'] ) ? sanitize_textarea_field( wp_unslash( $_POST['index_description_en'] ) ) : '', false );
update_option( 'yougitai_ss_delete_data_on_uninstall', isset( $_POST['delete_data_on_uninstall'] ) ? 1 : 0, false );
$color_defaults = [
'color_surface' => '#0d1117',
'color_panel' => '#161b22',
'color_code' => '#0d1117',
'color_border' => '#30363d',
'color_text' => '#c9d1d9',
'color_muted' => '#8b949e',
'color_accent' => '#58a6ff',
'color_accent_hover' => '#79c0ff',
'color_nav_hover' => '#79c0ff',
'color_nav_underline' => '#79c0ff',
'color_tree_hover_bg' => '#161b22',
'color_tree_hover_text' => '#f0f6fc',
'color_tree_active_bg' => '#1f2328',
'color_tree_active_marker' => '#8b949e',
'color_focus' => '#f0f6fc',
'color_progress' => '#3fb950',
'color_progress_track' => '#21262d',
'color_selected' => '#1f2d3d',
'color_warning_bg' => '#3b2f0b',
'color_warning_border' => '#9e6a03',
'color_warning_text' => '#e3b341',
'color_blackout' => '#020409',
'color_blackout_edge' => '#30363d',
];
foreach ( $color_defaults as $field => $default_color ) {
$raw_color = isset( $_POST[ $field ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field ] ) ) : $default_color;
$color = sanitize_hex_color( $raw_color );
update_option( 'yougitai_ss_' . $field, $color ?: $default_color, false );
}
$provider = isset( $_POST['ai_provider'] ) ? sanitize_key( wp_unslash( $_POST['ai_provider'] ) ) : 'openai';
if ( ! in_array( $provider, [ 'direct', 'openai', 'anthropic', 'gemini' ], true ) ) {
$provider = 'openai';
}
update_option( 'yougitai_ss_ai_provider', $provider );
update_option( 'yougitai_ss_external_ai_enabled', $provider !== 'direct' && isset( $_POST['external_ai_enabled'] ) ? 1 : 0 );
$provider_settings = [
'openai' => [ 'model' => 'gpt-5.6-luna', 'option' => 'yougitai_ss_openai_api_key' ],
'anthropic' => [ 'model' => 'claude-sonnet-5', 'option' => 'yougitai_ss_anthropic_api_key' ],
'gemini' => [ 'model' => 'gemini-3.8-flash', 'option' => 'yougitai_ss_gemini_api_key' ],
];
foreach ( $provider_settings as $slug => $config ) {
$model_field = $slug . '_model';
$key_field = $slug . '_api_key';
$remove_field = 'remove_' . $slug . '_api_key';
$model = isset( $_POST[ $model_field ] ) ? sanitize_text_field( wp_unslash( $_POST[ $model_field ] ) ) : $config['model'];
update_option( 'yougitai_ss_' . $slug . '_model', $model );
$key = isset( $_POST[ $key_field ] ) ? trim( (string) wp_unslash( $_POST[ $key_field ] ) ) : '';
if ( $key !== '' ) {
$encrypted_key = SecretVault::encrypt( $key );
if ( $encrypted_key === '' ) {
$this->redirect_settings_error( __( 'AI API key could not be encrypted on this server.', 'yougitai-secure-showcase' ) );
}
update_option( $config['option'], $encrypted_key, false );
}
if ( isset( $_POST[ $remove_field ] ) ) {
delete_option( $config['option'] );
}
}
$github_oauth_client_id = isset( $_POST['github_oauth_client_id'] ) ? sanitize_text_field( wp_unslash( $_POST['github_oauth_client_id'] ) ) : '';
update_option( 'yougitai_ss_github_oauth_client_id', $github_oauth_client_id, false );
$github_oauth_secret = isset( $_POST['github_oauth_client_secret'] ) ? trim( (string) wp_unslash( $_POST['github_oauth_client_secret'] ) ) : '';
if ( $github_oauth_secret !== '' ) {
$encrypted_oauth_secret = SecretVault::encrypt( $github_oauth_secret );
if ( $encrypted_oauth_secret === '' ) $this->redirect_settings_error( __( 'GitHub OAuth client secret could not be encrypted on this server.', 'yougitai-secure-showcase' ) );
update_option( 'yougitai_ss_github_oauth_client_secret', $encrypted_oauth_secret, false );
}
if ( isset( $_POST['remove_github_oauth_client_secret'] ) ) delete_option( 'yougitai_ss_github_oauth_client_secret' );
$github_token = isset( $_POST['github_token'] ) ? trim( (string) wp_unslash( $_POST['github_token'] ) ) : '';
if ( $github_token !== '' ) {
$encrypted = SecretVault::encrypt( $github_token );
if ( $encrypted === '' ) {
$this->redirect_settings_error( __( 'GitHub token could not be encrypted on this server.', 'yougitai-secure-showcase' ) );
}
update_option( 'yougitai_ss_github_token', $encrypted, false );
}
if ( isset( $_POST['remove_github_token'] ) ) {
delete_option( 'yougitai_ss_github_token' );
}
if ( $old_slug !== $slug ) {
// Renderer registered the old slug earlier in this request. Defer
// flushing until the next init so the new slug is registered first.
update_option( 'yougitai_ss_rewrite_flush_needed', 1, false );
update_option( 'yougitai_ss_rewrite_version', 0, false );
}
wp_safe_redirect( add_query_arg( [
'page' => 'yougitai-secure-showcase-settings',
'yougitai_message' => rawurlencode( __( 'Settings saved.', 'yougitai-secure-showcase' ) ),
], admin_url( 'admin.php' ) ) );
exit;
}
private function stored_secret_present( string $option ): bool {
$stored = trim( (string) get_option( $option, '' ) );
if ( $stored === '' ) {
return false;
}
if ( str_starts_with( $stored, 'sodium:' ) || str_starts_with( $stored, 'openssl:' ) ) {
return SecretVault::decrypt( $stored ) !== '';
}
return true;
}
private function guard(): void {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You are not allowed to perform this action.', 'yougitai-secure-showcase' ) );
}
}
private function redirect_repository( int $repository_id, string $message, int $snapshot_id = 0, int $file_id = 0 ): void {
$args = [
'page' => 'yougitai-secure-showcase',
'repository_id' => $repository_id,
'yougitai_message' => rawurlencode( $message ),
];
if ( $snapshot_id ) {
$args['snapshot_id'] = $snapshot_id;
}
if ( $file_id ) {
$args['file_id'] = $file_id;
}
wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) );
exit;
}
private function redirect_settings_error( string $message ): void {
wp_safe_redirect( add_query_arg( [
'page' => 'yougitai-secure-showcase-settings',
'yougitai_error' => rawurlencode( $message ),
], admin_url( 'admin.php' ) ) );
exit;
}
private function redirect_error( string $message, int $repository_id = 0, int $snapshot_id = 0 ): void {
$args = [
'page' => 'yougitai-secure-showcase',
'yougitai_error' => rawurlencode( $message ),
];
if ( $repository_id ) {
$args['repository_id'] = $repository_id;
}
if ( $snapshot_id ) {
$args['snapshot_id'] = $snapshot_id;
}
wp_safe_redirect( add_query_arg( $args, admin_url( 'admin.php' ) ) );
exit;
}
}

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%