1
<?php if ( ! defined( 'ABSPATH' ) ) exit; ?>
2
<?php
3
$yougitai_status_labels = [
4
'draft' => __( 'Draft', 'yougitai-secure-showcase' ),
5
'published' => __( 'Published', 'yougitai-secure-showcase' ),
6
'pending' => __( 'Pending', 'yougitai-secure-showcase' ),
7
'needs_review' => __( 'Needs review', 'yougitai-secure-showcase' ),
8
'ready' => __( 'Ready', 'yougitai-secure-showcase' ),
9
'approved' => __( 'Approved', 'yougitai-secure-showcase' ),
10
'public' => __( 'Public', 'yougitai-secure-showcase' ),
11
'redacted' => __( 'Redacted', 'yougitai-secure-showcase' ),
12
'hidden' => __( 'Hidden', 'yougitai-secure-showcase' ),
13
'open' => __( 'Open', 'yougitai-secure-showcase' ),
14
'resolved' => __( 'Resolved', 'yougitai-secure-showcase' ),
15
'accepted' => __( 'Risk accepted', 'yougitai-secure-showcase' ),
16
'ignored' => __( 'Ignored', 'yougitai-secure-showcase' ),
17
];
18
$yougitai_profile_labels = [
19
'portfolio' => __( 'Portfolio', 'yougitai-secure-showcase' ),
20
'balanced' => __( 'Balanced', 'yougitai-secure-showcase' ),
21
'investor' => __( 'Investor', 'yougitai-secure-showcase' ),
22
'maximum' => __( 'Maximum IP protection', 'yougitai-secure-showcase' ),
23
];
24
$yougitai_severity_labels = [
25
'low' => __( 'Low', 'yougitai-secure-showcase' ),
26
'medium' => __( 'Medium', 'yougitai-secure-showcase' ),
27
'high' => __( 'High', 'yougitai-secure-showcase' ),
28
'critical' => __( 'Critical', 'yougitai-secure-showcase' ),
29
];
30
$yougitai_source_labels = [
31
'scanner' => __( 'Scanner', 'yougitai-secure-showcase' ),
32
'ai' => __( 'AI', 'yougitai-secure-showcase' ),
33
'manual' => __( 'Manual', 'yougitai-secure-showcase' ),
34
'global' => __( 'Global', 'yougitai-secure-showcase' ),
35
];
36
$yougitai_recommendation_labels = [
37
'review' => __( 'Review', 'yougitai-secure-showcase' ),
38
'redact' => __( 'Redact', 'yougitai-secure-showcase' ),
39
'hide' => __( 'Hide', 'yougitai-secure-showcase' ),
40
];
41
$yougitai_latest_snapshot = ! empty( $snapshots ) ? $snapshots[0] : null;
42
$yougitai_active_snapshot = null;
43
foreach ( $snapshots as $yougitai_snapshot_item ) {
44
if ( (int) $repository['active_snapshot_id'] === (int) $yougitai_snapshot_item['id'] ) {
45
$yougitai_active_snapshot = $yougitai_snapshot_item;
46
break;
47
}
48
}
49
$yougitai_active_rules = array_values( array_filter( $rules, static fn( $rule ) => ! empty( $rule['enabled'] ) ) );
50
$yougitai_pending_proposals = array_values( array_filter( $rules, static fn( $rule ) => empty( $rule['enabled'] ) && (string) ( $rule['source'] ?? '' ) === 'connected_ai' ) );
51
$yougitai_latest_rule_time = 0;
52
foreach ( $yougitai_active_rules as $yougitai_rule_item ) {
53
$yougitai_latest_rule_time = max( $yougitai_latest_rule_time, strtotime( (string) ( $yougitai_rule_item['updated_at'] ?? $yougitai_rule_item['created_at'] ?? '' ) ) ?: 0 );
54
}
55
$yougitai_latest_snapshot_time = $yougitai_latest_snapshot ? ( strtotime( (string) $yougitai_latest_snapshot['created_at'] ) ?: 0 ) : 0;
56
$yougitai_protection_needs_apply = $yougitai_latest_snapshot && $yougitai_active_rules && $yougitai_latest_rule_time > $yougitai_latest_snapshot_time;
57
$yougitai_files_by_path = [];
58
$yougitai_protected_file_count = 0;
59
foreach ( $files as $yougitai_file_item ) {
60
$yougitai_files_by_path[ (string) $yougitai_file_item['path'] ] = $yougitai_file_item;
61
if ( in_array( (string) $yougitai_file_item['visibility'], [ 'redacted', 'hidden' ], true ) ) $yougitai_protected_file_count++;
62
}
63
$yougitai_finding_groups = [];
64
$yougitai_open_finding_count = 0;
65
$yougitai_critical_open_count = 0;
66
foreach ( $findings as $yougitai_finding_item ) {
67
$yougitai_path = (string) $yougitai_finding_item['file_path'];
68
if ( ! isset( $yougitai_finding_groups[ $yougitai_path ] ) ) {
69
$yougitai_finding_groups[ $yougitai_path ] = [ 'items' => [], 'open_ids' => [], 'max_risk' => 0, 'severity' => 'low' ];
70
}
71
$yougitai_finding_groups[ $yougitai_path ]['items'][] = $yougitai_finding_item;
72
$yougitai_finding_groups[ $yougitai_path ]['max_risk'] = max( $yougitai_finding_groups[ $yougitai_path ]['max_risk'], (int) $yougitai_finding_item['risk_score'] );
73
if ( $yougitai_finding_item['status'] === 'open' ) {
74
$yougitai_finding_groups[ $yougitai_path ]['open_ids'][] = (int) $yougitai_finding_item['id'];
75
$yougitai_open_finding_count++;
76
if ( $yougitai_finding_item['severity'] === 'critical' ) $yougitai_critical_open_count++;
77
}
78
$yougitai_rank = [ 'low' => 1, 'medium' => 2, 'high' => 3, 'critical' => 4 ];
79
if ( ( $yougitai_rank[ $yougitai_finding_item['severity'] ] ?? 0 ) > ( $yougitai_rank[ $yougitai_finding_groups[ $yougitai_path ]['severity'] ] ?? 0 ) ) {
80
$yougitai_finding_groups[ $yougitai_path ]['severity'] = $yougitai_finding_item['severity'];
81
}
82
}
83
$yougitai_ai_labels = [
84
'openai' => 'OpenAI / ChatGPT',
85
'anthropic' => 'Anthropic / Claude',
86
'gemini' => 'Google / Gemini',
87
'direct' => 'ChatGPT (DIRECT)',
88
];
89
?>
90
<div class="wrap yougitai-admin">
91
<p><a href="<?php echo esc_url( admin_url( 'admin.php?page=yougitai-secure-showcase' ) ); ?>">← <?php esc_html_e( 'Repositories', 'yougitai-secure-showcase' ); ?></a></p>
92
<div class="yougitai-page-title">
93
<div>
94
<h1><?php echo esc_html( $repository['title'] ); ?></h1>
95
<code><?php echo esc_html( $repository['owner'] . '/' . $repository['repo'] ); ?></code>
96
</div>
97
<span class="yougitai-status yougitai-status-<?php echo esc_attr( $repository['status'] ); ?>"><?php echo esc_html( $repository['status'] === 'published' ? __( 'Published', 'yougitai-secure-showcase' ) : __( 'Draft', 'yougitai-secure-showcase' ) ); ?></span>
98
</div>
99
100
<?php if ( $message ) : ?><div class="notice notice-success"><p><?php echo esc_html( urldecode( $message ) ); ?></p></div><?php endif; ?>
101
<?php if ( $error ) : ?><div class="notice notice-error"><p><?php echo esc_html( urldecode( $error ) ); ?></p></div><?php endif; ?>
102
103
<section class="yougitai-card yougitai-guided-workflow" aria-labelledby="yougitai-next-steps-title">
104
<div class="yougitai-card-header">
105
<div>
106
<h2 id="yougitai-next-steps-title"><?php esc_html_e( 'What do I do next?', 'yougitai-secure-showcase' ); ?></h2>
107
<p class="yougitai-muted"><?php esc_html_e( 'Follow these steps in order. You only need GitHub again when the repository itself has changed.', 'yougitai-secure-showcase' ); ?></p>
108
</div>
109
</div>
110
<div class="yougitai-stepper">
111
<div class="yougitai-step <?php echo $yougitai_latest_snapshot ? 'is-done' : 'is-current'; ?>">
112
<span class="yougitai-step-number">1</span>
113
<div><strong><?php esc_html_e( 'Bring in the repository once', 'yougitai-secure-showcase' ); ?></strong><p><?php echo $yougitai_latest_snapshot ? esc_html( sprintf( __( 'Done — snapshot #%d is available.', 'yougitai-secure-showcase' ), (int) $yougitai_latest_snapshot['id'] ) ) : esc_html__( 'Import the repository from GitHub to create the first safe draft.', 'yougitai-secure-showcase' ); ?></p></div>
114
</div>
115
<div class="yougitai-step <?php echo $yougitai_pending_proposals ? 'is-current' : ( $yougitai_active_rules ? 'is-done' : '' ); ?>">
116
<span class="yougitai-step-number">2</span>
117
<div><strong><?php esc_html_e( 'Review protection suggestions', 'yougitai-secure-showcase' ); ?></strong><p><?php printf( esc_html__( '%1$d active rules · %2$d suggestions still waiting for your decision.', 'yougitai-secure-showcase' ), count( $yougitai_active_rules ), count( $yougitai_pending_proposals ) ); ?></p><a class="button" href="#yougitai-rules"><?php esc_html_e( 'Review suggestions', 'yougitai-secure-showcase' ); ?></a></div>
118
</div>
119
<div class="yougitai-step <?php echo $yougitai_protection_needs_apply ? 'is-current' : ( $yougitai_latest_snapshot && $yougitai_active_rules ? 'is-done' : '' ); ?>">
120
<span class="yougitai-step-number">3</span>
121
<div>
122
<strong><?php esc_html_e( 'Apply approved protection', 'yougitai-secure-showcase' ); ?></strong>
123
<p><?php esc_html_e( 'This uses the existing safe draft and creates a new protected review draft. GitHub is not contacted and nothing is published.', 'yougitai-secure-showcase' ); ?></p>
124
<?php if ( $yougitai_latest_snapshot && $yougitai_active_rules && empty( $repository['show_original'] ) ) : ?>
125
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-inline-form">
126
<input type="hidden" name="action" value="yougitai_ss_apply_protection_rules">
127
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
128
<input type="hidden" name="base_snapshot_id" value="<?php echo esc_attr( $yougitai_latest_snapshot['id'] ); ?>">
129
<?php wp_nonce_field( 'yougitai_ss_apply_protection_rules_' . $repository['id'] ); ?>
130
<?php submit_button( __( 'Apply protection now', 'yougitai-secure-showcase' ), $yougitai_protection_needs_apply ? 'primary' : 'secondary', 'submit', false ); ?>
131
</form>
132
<?php elseif ( ! $yougitai_latest_snapshot ) : ?>
133
<small><?php esc_html_e( 'Create the first draft in step 1 before applying protection.', 'yougitai-secure-showcase' ); ?></small>
134
<?php elseif ( ! $yougitai_active_rules ) : ?>
135
<small><?php esc_html_e( 'Approve at least one protection rule first.', 'yougitai-secure-showcase' ); ?></small>
136
<?php endif; ?>
137
</div>
138
</div>
139
<div class="yougitai-step <?php echo $yougitai_latest_snapshot ? 'is-current' : ''; ?>">
140
<span class="yougitai-step-number">4</span>
141
<div><strong><?php esc_html_e( 'Check the result and publish only when ready', 'yougitai-secure-showcase' ); ?></strong><p><?php esc_html_e( 'Open the newest review draft, inspect the visible code and redactions, then explicitly publish it. Your current live showcase stays unchanged until then.', 'yougitai-secure-showcase' ); ?></p><?php if ( $yougitai_latest_snapshot ) : ?><a class="button button-primary" href="<?php echo esc_url( add_query_arg( [ 'page'=>'yougitai-secure-showcase', 'repository_id'=>(int) $repository['id'], 'snapshot_id'=>(int) $yougitai_latest_snapshot['id'] ], admin_url( 'admin.php' ) ) . '#yougitai-snapshots' ); ?>"><?php esc_html_e( 'Open newest review draft', 'yougitai-secure-showcase' ); ?></a><?php endif; ?></div>
142
</div>
143
</div>
144
<div class="yougitai-info-box"><strong><?php esc_html_e( 'When do I use GitHub sync?', 'yougitai-secure-showcase' ); ?></strong><p><?php esc_html_e( 'Only when the source repository has changed and you want to bring those new GitHub changes into YougitAI. Approving or applying protection does not require another GitHub import.', 'yougitai-secure-showcase' ); ?></p></div>
145
</section>
146
147
<nav class="yougitai-section-nav" aria-label="<?php echo esc_attr__( 'Repository sections', 'yougitai-secure-showcase' ); ?>">
148
<a href="#yougitai-overview"><?php esc_html_e( 'Overview', 'yougitai-secure-showcase' ); ?></a>
149
<a href="#yougitai-snapshots"><?php esc_html_e( 'Snapshots', 'yougitai-secure-showcase' ); ?></a>
150
<a href="#yougitai-protection"><?php esc_html_e( 'Code & redaction', 'yougitai-secure-showcase' ); ?></a>
151
<a href="#yougitai-rules"><?php esc_html_e( 'Protection rules', 'yougitai-secure-showcase' ); ?></a>
152
<a href="#yougitai-sync"><?php esc_html_e( 'GitHub sync', 'yougitai-secure-showcase' ); ?></a>
153
<a href="#yougitai-audit"><?php esc_html_e( 'Audit history', 'yougitai-secure-showcase' ); ?></a>
154
</nav>
155
156
<section class="yougitai-workflow-status" id="yougitai-overview">
157
<div class="yougitai-workflow-item is-live">
158
<span><?php esc_html_e( 'Live showcase', 'yougitai-secure-showcase' ); ?></span>
159
<strong><?php echo $yougitai_active_snapshot ? '#' . esc_html( $yougitai_active_snapshot['id'] ) : esc_html__( 'Not published yet', 'yougitai-secure-showcase' ); ?></strong>
160
<small><?php esc_html_e( 'This is what visitors currently see.', 'yougitai-secure-showcase' ); ?></small>
161
</div>
162
<div class="yougitai-workflow-item">
163
<span><?php esc_html_e( 'Latest review draft', 'yougitai-secure-showcase' ); ?></span>
164
<strong><?php echo $yougitai_latest_snapshot ? '#' . esc_html( $yougitai_latest_snapshot['id'] ) : esc_html__( 'No snapshot yet', 'yougitai-secure-showcase' ); ?></strong>
165
<small><?php esc_html_e( 'This is your newest working draft. Protection can be applied again without contacting GitHub.', 'yougitai-secure-showcase' ); ?></small>
166
</div>
167
<div class="yougitai-workflow-item">
168
<span><?php esc_html_e( 'Active protection rules', 'yougitai-secure-showcase' ); ?></span>
169
<strong><?php echo esc_html( number_format_i18n( count( array_filter( $rules, static fn( $rule ) => ! empty( $rule['enabled'] ) ) ) ) ); ?></strong>
170
<small><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Rules are retained but bypassed while Original source mode is active.', 'yougitai-secure-showcase' ) : esc_html__( 'Approved rules are re-applied to every new draft.', 'yougitai-secure-showcase' ); ?></small>
171
</div>
172
<div class="yougitai-workflow-item <?php echo ! empty( $repository['show_original'] ) ? 'is-original' : ''; ?>">
173
<span><?php esc_html_e( 'Display mode', 'yougitai-secure-showcase' ); ?></span>
174
<strong><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Original source', 'yougitai-secure-showcase' ) : esc_html__( 'Secure showcase', 'yougitai-secure-showcase' ); ?></strong>
175
<small><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'New snapshots contain unredacted text source.', 'yougitai-secure-showcase' ) : esc_html__( 'New snapshots are processed through protection and review.', 'yougitai-secure-showcase' ); ?></small>
176
</div>
177
</section>
178
179
<section class="yougitai-card yougitai-publication-card">
180
<div class="yougitai-card-header"><div><h2><?php esc_html_e( 'Publication & access', 'yougitai-secure-showcase' ); ?></h2><p class="yougitai-muted"><?php esc_html_e( 'Control whether the verified showcase is public, password-protected, private, or taken offline as a draft. Changing this does not delete snapshots.', 'yougitai-secure-showcase' ); ?></p></div></div>
181
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-publication-form">
182
<input type="hidden" name="action" value="yougitai_ss_set_publication_state">
183
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
184
<?php wp_nonce_field( 'yougitai_ss_set_publication_state_' . $repository['id'] ); ?>
185
<label><span><?php esc_html_e( 'Publication state', 'yougitai-secure-showcase' ); ?></span><select name="publication_status"><option value="published" <?php selected( $repository['status'], 'published' ); ?>><?php esc_html_e( 'Published', 'yougitai-secure-showcase' ); ?></option><option value="draft" <?php selected( $repository['status'], 'draft' ); ?>><?php esc_html_e( 'Draft / offline', 'yougitai-secure-showcase' ); ?></option></select></label>
186
<label><span><?php esc_html_e( 'Visitor access', 'yougitai-secure-showcase' ); ?></span><select name="access_mode"><option value="public" <?php selected( $repository['access_mode'] ?? 'public', 'public' ); ?>><?php esc_html_e( 'Public', 'yougitai-secure-showcase' ); ?></option><option value="password" <?php selected( $repository['access_mode'] ?? 'public', 'password' ); ?>><?php esc_html_e( 'Password protected', 'yougitai-secure-showcase' ); ?></option><option value="private" <?php selected( $repository['access_mode'] ?? 'public', 'private' ); ?>><?php esc_html_e( 'Private (admins only)', 'yougitai-secure-showcase' ); ?></option></select></label>
187
<label><span><?php esc_html_e( 'Password', 'yougitai-secure-showcase' ); ?></span><input type="password" name="access_password" autocomplete="new-password" placeholder="<?php echo esc_attr__( 'Leave blank to keep the current password', 'yougitai-secure-showcase' ); ?>"></label>
188
<div class="yougitai-actions"><?php submit_button( __( 'Save publication settings', 'yougitai-secure-showcase' ), 'primary', 'submit', false ); ?></div>
189
</form>
190
<p class="description"><?php esc_html_e( 'Draft/offline removes the showcase from public access immediately but keeps the verified snapshot so you can publish it again later.', 'yougitai-secure-showcase' ); ?></p>
191
</section>
192
193
<section class="yougitai-card yougitai-display-mode-card <?php echo ! empty( $repository['show_original'] ) ? 'is-original' : 'is-secure'; ?>">
194
<div class="yougitai-card-header"><div><h2><?php esc_html_e( 'What should visitors see?', 'yougitai-secure-showcase' ); ?></h2><p class="yougitai-muted"><?php esc_html_e( 'Choose whether new snapshots are protected or intentionally mirror the repository source without redaction.', 'yougitai-secure-showcase' ); ?></p></div></div>
195
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-display-mode-form">
196
<input type="hidden" name="action" value="yougitai_ss_set_display_mode">
197
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
198
<?php wp_nonce_field( 'yougitai_ss_set_display_mode_' . $repository['id'] ); ?>
199
<label class="yougitai-mode-option">
200
<input type="radio" name="display_mode" value="secure" <?php checked( empty( $repository['show_original'] ) ); ?>>
201
<span><strong><?php esc_html_e( 'Secure showcase (recommended)', 'yougitai-secure-showcase' ); ?></strong><small><?php esc_html_e( 'Secret scanner, manual rules and optional AI protection are applied. Syncs remain drafts until you publish them.', 'yougitai-secure-showcase' ); ?></small></span>
202
</label>
203
<label class="yougitai-mode-option yougitai-mode-original">
204
<input type="radio" name="display_mode" value="original" <?php checked( ! empty( $repository['show_original'] ) ); ?>>
205
<span><strong><?php esc_html_e( 'Show original source', 'yougitai-secure-showcase' ); ?></strong><small><?php esc_html_e( 'For repositories that may be shown completely. New snapshots bypass redaction rules, secret scanning and AI protection.', 'yougitai-secure-showcase' ); ?></small></span>
206
</label>
207
<div class="yougitai-original-confirm">
208
<label><input type="checkbox" name="confirm_original" value="1"> <span><?php esc_html_e( 'I understand that enabling Original source mode can make the complete text source of this repository public after I publish a new snapshot.', 'yougitai-secure-showcase' ); ?></span></label>
209
</div>
210
<div class="yougitai-actions">
211
<?php submit_button( __( 'Save display mode', 'yougitai-secure-showcase' ), 'primary', 'submit', false ); ?>
212
</div>
213
</form>
214
<p class="description"><?php esc_html_e( 'Changing this setting never changes the currently published snapshot. Import a new snapshot and publish it explicitly before visitors see the new mode.', 'yougitai-secure-showcase' ); ?></p>
215
</section>
216
217
<section class="yougitai-card yougitai-quick-protection" id="yougitai-protection">
218
<div class="yougitai-card-header"><div><h2><?php esc_html_e( 'Code & redaction', 'yougitai-secure-showcase' ); ?></h2><p class="yougitai-muted"><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Original source mode is active. Existing rules are kept but are not applied to new snapshots until secure mode is enabled again.', 'yougitai-secure-showcase' ) : esc_html__( 'Manual protection is always available. AI is optional.', 'yougitai-secure-showcase' ); ?></p></div></div>
219
<div class="yougitai-quick-steps">
220
<div class="yougitai-quick-step"><strong><?php esc_html_e( '1. Existing safe draft', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'Your imported draft is the working copy for protection decisions.', 'yougitai-secure-showcase' ); ?></span></div>
221
<div class="yougitai-quick-step"><strong><?php esc_html_e( '2. Select a file', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'Open a snapshot, choose a file, then hide the entire file or select code lines to redact.', 'yougitai-secure-showcase' ); ?></span></div>
222
<div class="yougitai-quick-step"><strong><?php esc_html_e( '3. Apply, review & publish', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'Apply approved rules to the existing draft, inspect the result, then publish explicitly.', 'yougitai-secure-showcase' ); ?></span></div>
223
</div>
224
<div class="yougitai-actions">
225
<?php if ( $yougitai_latest_snapshot ) : ?><a class="button button-primary" href="<?php echo esc_url( add_query_arg( [ 'page'=>'yougitai-secure-showcase', 'repository_id'=>(int) $repository['id'], 'snapshot_id'=>(int) $yougitai_latest_snapshot['id'] ], admin_url( 'admin.php' ) ) . '#yougitai-protection' ); ?>"><?php esc_html_e( 'Open latest draft for redaction', 'yougitai-secure-showcase' ); ?></a><?php endif; ?>
226
<a class="button" href="#yougitai-rules"><?php esc_html_e( 'Manage protection rules', 'yougitai-secure-showcase' ); ?></a>
227
</div>
228
</section>
229
230
<div class="yougitai-dashboard-grid">
231
<section class="yougitai-card" id="yougitai-import">
232
<h2><?php esc_html_e( 'Update source from GitHub', 'yougitai-secure-showcase' ); ?></h2>
233
<p><?php esc_html_e( 'Use this only when the repository on GitHub has changed. You do not need this after approving protection suggestions.', 'yougitai-secure-showcase' ); ?></p>
234
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
235
<input type="hidden" name="action" value="yougitai_ss_import_snapshot">
236
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
237
<?php wp_nonce_field( 'yougitai_ss_import_snapshot_' . $repository['id'] ); ?>
238
<?php submit_button( __( 'Fetch current GitHub version', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?>
239
</form>
240
</section>
241
<section class="yougitai-card">
242
<h2><?php esc_html_e( 'Protection', 'yougitai-secure-showcase' ); ?></h2>
243
<p><strong><?php esc_html_e( 'Profile:', 'yougitai-secure-showcase' ); ?></strong> <?php echo esc_html( $yougitai_profile_labels[ $repository['protection_profile'] ] ?? $repository['protection_profile'] ); ?></p>
244
<?php if ( ! empty( $repository['show_original'] ) ) : ?>
245
<div class="yougitai-warning"><strong><?php esc_html_e( 'Original source mode is active.', 'yougitai-secure-showcase' ); ?></strong><p><?php esc_html_e( 'New snapshots are intentionally imported without redaction. Protection rules remain stored but are bypassed.', 'yougitai-secure-showcase' ); ?></p></div>
246
<?php else : ?>
247
<p><?php esc_html_e( 'Built-in secret scanning always runs. External AI runs only when explicitly enabled in settings.', 'yougitai-secure-showcase' ); ?></p>
248
<?php endif; ?>
249
</section>
250
<section class="yougitai-card" id="yougitai-sync">
251
<h2><?php esc_html_e( 'GitHub sync', 'yougitai-secure-showcase' ); ?></h2>
252
<p><strong><?php esc_html_e( 'Mode:', 'yougitai-secure-showcase' ); ?></strong> <?php $sync_labels = [ 'manual' => __( 'Manual', 'yougitai-secure-showcase' ), 'webhook' => __( 'Webhook', 'yougitai-secure-showcase' ), 'hourly' => __( 'Hourly', 'yougitai-secure-showcase' ), 'daily' => __( 'Daily', 'yougitai-secure-showcase' ) ]; echo esc_html( $sync_labels[ $repository['sync_mode'] ] ?? __( 'Manual', 'yougitai-secure-showcase' ) ); ?></p>
253
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-inline-form">
254
<input type="hidden" name="action" value="yougitai_ss_queue_sync">
255
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
256
<?php wp_nonce_field( 'yougitai_ss_queue_sync_' . $repository['id'] ); ?>
257
<?php submit_button( __( 'Queue secure sync', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?>
258
</form>
259
<hr>
260
<p><strong><?php esc_html_e( 'Webhook URL', 'yougitai-secure-showcase' ); ?></strong><br><code class="yougitai-break"><?php echo esc_html( $webhook_url ); ?></code></p>
261
<?php if ( $webhook_secret_once ) : ?>
262
<div class="notice notice-warning inline"><p><strong><?php esc_html_e( 'Copy this webhook secret now. It will not be shown again:', 'yougitai-secure-showcase' ); ?></strong><br><code class="yougitai-break"><?php echo esc_html( $webhook_secret_once ); ?></code></p></div>
263
<?php endif; ?>
264
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-inline-form">
265
<input type="hidden" name="action" value="yougitai_ss_rotate_webhook">
266
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
267
<?php wp_nonce_field( 'yougitai_ss_rotate_webhook_' . $repository['id'] ); ?>
268
<?php submit_button( $repository['webhook_secret'] ? __( 'Rotate webhook secret', 'yougitai-secure-showcase' ) : __( 'Generate webhook secret', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?>
269
</form>
270
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-rule-form">
271
<input type="hidden" name="action" value="yougitai_ss_set_sync_mode">
272
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
273
<?php wp_nonce_field( 'yougitai_ss_set_sync_mode_' . $repository['id'] ); ?>
274
<label><span><?php esc_html_e( 'Sync mode', 'yougitai-secure-showcase' ); ?></span><select name="sync_mode"><option value="manual" <?php selected( $repository['sync_mode'], 'manual' ); ?>><?php esc_html_e( 'Manual', 'yougitai-secure-showcase' ); ?></option><option value="webhook" <?php selected( $repository['sync_mode'], 'webhook' ); ?>><?php esc_html_e( 'Webhook', 'yougitai-secure-showcase' ); ?></option><option value="hourly" <?php selected( $repository['sync_mode'], 'hourly' ); ?>><?php esc_html_e( 'Hourly', 'yougitai-secure-showcase' ); ?></option><option value="daily" <?php selected( $repository['sync_mode'], 'daily' ); ?>><?php esc_html_e( 'Daily', 'yougitai-secure-showcase' ); ?></option></select></label>
275
<div><?php submit_button( __( 'Save sync mode', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?></div>
276
</form>
277
<div class="yougitai-safety-note">
278
<strong><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Sync safety: the live snapshot still never changes automatically.', 'yougitai-secure-showcase' ) : esc_html__( 'Safe sync: existing redactions stay protected.', 'yougitai-secure-showcase' ); ?></strong>
279
<p><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Every sync creates a new draft containing the unredacted text source because Original source mode is active. Your currently published showcase remains unchanged until you explicitly publish that draft.', 'yougitai-secure-showcase' ) : esc_html__( 'Every sync creates a new draft and reapplies all active protection rules. Your currently published showcase stays unchanged until you review and publish a new snapshot. If a fingerprinted line or symbol can no longer be matched safely, YougitAI hides the file fail-closed instead of exposing new source code.', 'yougitai-secure-showcase' ); ?></p>
280
</div>
281
</section>
282
</div>
283
284
<section class="yougitai-card" id="yougitai-snapshots">
285
<h2><?php esc_html_e( 'Snapshots', 'yougitai-secure-showcase' ); ?></h2>
286
<?php if ( ! $snapshots ) : ?><div class="yougitai-empty-state"><strong><?php esc_html_e( 'No snapshots yet.', 'yougitai-secure-showcase' ); ?></strong><p><?php esc_html_e( 'Import the first secure draft before selecting files or creating visual redactions.', 'yougitai-secure-showcase' ); ?></p><a class="button button-primary" href="#yougitai-import"><?php esc_html_e( 'Go to import', 'yougitai-secure-showcase' ); ?></a></div><?php endif; ?>
287
<?php if ( $snapshots ) : ?>
288
<table class="widefat striped">
289
<thead><tr><th><?php esc_html_e( 'Snapshot', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Commit', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Files', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Findings', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Review', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Status', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Actions', 'yougitai-secure-showcase' ); ?></th></tr></thead>
290
<tbody>
291
<?php foreach ( $snapshots as $snapshot ) : ?>
292
<tr>
293
<td><a href="<?php echo esc_url( add_query_arg( [ 'page'=>'yougitai-secure-showcase', 'repository_id'=>(int) $repository['id'], 'snapshot_id'=>(int) $snapshot['id'] ], admin_url( 'admin.php' ) ) ); ?>">#<?php echo esc_html( $snapshot['id'] ); ?></a></td>
294
<td><code><?php echo esc_html( substr( (string) $snapshot['source_sha'], 0, 10 ) ); ?></code></td>
295
<td><?php echo esc_html( number_format_i18n( (int) $snapshot['file_count'] ) ); ?></td>
296
<td><?php echo esc_html( number_format_i18n( (int) $snapshot['finding_count'] ) ); ?><?php if ( (int) $snapshot['critical_count'] > 0 ) : ?> <strong class="yougitai-critical">(<?php echo esc_html( $snapshot['critical_count'] ); ?> <?php esc_html_e( 'critical', 'yougitai-secure-showcase' ); ?>)</strong><?php endif; ?></td>
297
<td><?php echo esc_html( $yougitai_status_labels[ $snapshot['review_status'] ] ?? $snapshot['review_status'] ); ?></td>
298
<td><?php echo esc_html( $yougitai_status_labels[ $snapshot['status'] ] ?? $snapshot['status'] ); ?><?php if ( (int) $repository['active_snapshot_id'] === (int) $snapshot['id'] ) : ?> <strong>· <?php esc_html_e( 'Active', 'yougitai-secure-showcase' ); ?></strong><?php endif; ?></td>
299
<td>
300
<?php if ( $snapshot['status'] === 'published' && ! empty( $snapshot['verification_hash'] ) && (int) $repository['active_snapshot_id'] !== (int) $snapshot['id'] ) : ?>
301
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
302
<input type="hidden" name="action" value="yougitai_ss_restore_snapshot">
303
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
304
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $snapshot['id'] ); ?>">
305
<?php wp_nonce_field( 'yougitai_ss_restore_snapshot_' . $snapshot['id'] ); ?>
306
<button class="button button-small" type="submit"><?php esc_html_e( 'Restore verified snapshot', 'yougitai-secure-showcase' ); ?></button>
307
</form>
308
<?php else : ?>—<?php endif; ?>
309
</td>
310
</tr>
311
<?php endforeach; ?>
312
</tbody>
313
</table>
314
<?php endif; ?>
315
</section>
316
317
<?php if ( $selected_snapshot ) : ?>
318
<section class="yougitai-review-hero">
319
<div>
320
<p class="yougitai-eyebrow"><?php echo esc_html( sprintf( __( 'Snapshot #%d', 'yougitai-secure-showcase' ), (int) $selected_snapshot['id'] ) ); ?></p>
321
<h2><?php esc_html_e( 'Review & protect this draft', 'yougitai-secure-showcase' ); ?></h2>
322
<p><?php esc_html_e( 'This page shows only the sanitized draft stored by YougitAI. Scanner removals are already applied. Nothing here changes the currently live showcase until you explicitly publish.', 'yougitai-secure-showcase' ); ?></p>
323
</div>
324
<div class="yougitai-actions">
325
<?php if ( ! in_array( $selected_snapshot['review_status'], [ 'approved', 'ready' ], true ) ) : ?>
326
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
327
<input type="hidden" name="action" value="yougitai_ss_approve_snapshot">
328
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
329
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
330
<?php wp_nonce_field( 'yougitai_ss_approve_snapshot_' . $selected_snapshot['id'] ); ?>
331
<?php submit_button( __( 'Mark review complete', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?>
332
</form>
333
<?php endif; ?>
334
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
335
<input type="hidden" name="action" value="yougitai_ss_publish_snapshot">
336
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
337
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
338
<?php wp_nonce_field( 'yougitai_ss_publish_snapshot_' . $selected_snapshot['id'] ); ?>
339
<?php submit_button( __( 'Verify & publish', 'yougitai-secure-showcase' ), 'primary', 'submit', false ); ?>
340
</form>
341
</div>
342
</section>
343
344
<section class="yougitai-review-summary" aria-label="<?php echo esc_attr__( 'Protection summary', 'yougitai-secure-showcase' ); ?>">
345
<div class="yougitai-summary-stat is-protected"><strong><?php echo esc_html( number_format_i18n( $yougitai_protected_file_count ) ); ?></strong><span><?php esc_html_e( 'files already redacted or hidden', 'yougitai-secure-showcase' ); ?></span></div>
346
<div class="yougitai-summary-stat <?php echo $yougitai_open_finding_count ? 'has-warning' : 'is-ok'; ?>"><strong><?php echo esc_html( number_format_i18n( $yougitai_open_finding_count ) ); ?></strong><span><?php esc_html_e( 'open review notes', 'yougitai-secure-showcase' ); ?></span></div>
347
<div class="yougitai-summary-stat <?php echo $yougitai_critical_open_count ? 'has-danger' : 'is-ok'; ?>"><strong><?php echo esc_html( number_format_i18n( $yougitai_critical_open_count ) ); ?></strong><span><?php esc_html_e( 'open critical notes', 'yougitai-secure-showcase' ); ?></span></div>
348
<div class="yougitai-summary-stat"><strong><?php echo esc_html( number_format_i18n( count( $files ) ) ); ?></strong><span><?php esc_html_e( 'files in this draft', 'yougitai-secure-showcase' ); ?></span></div>
349
</section>
350
351
<section class="yougitai-card yougitai-ai-review-card">
352
<div class="yougitai-card-header">
353
<div>
354
<h3><?php esc_html_e( 'AI protection', 'yougitai-secure-showcase' ); ?></h3>
355
<?php if ( $ai_provider === 'direct' ) : ?>
356
<p class="yougitai-muted"><?php esc_html_e( 'ChatGPT (DIRECT) is selected. The review is controlled from an authorized ChatGPT conversation, so WordPress does not need an AI API key.', 'yougitai-secure-showcase' ); ?></p>
357
<?php elseif ( $ai_configured ) : ?>
358
<p class="yougitai-muted"><?php echo esc_html( sprintf( __( '%s is configured. You can create a fresh draft with AI-assisted protection using the current repository profile.', 'yougitai-secure-showcase' ), $yougitai_ai_labels[ $ai_provider ] ?? $ai_provider ) ); ?></p>
359
<?php else : ?>
360
<p class="yougitai-muted"><?php esc_html_e( 'AI is optional and is not currently configured. The deterministic scanner and all manual protection tools still work without AI.', 'yougitai-secure-showcase' ); ?></p>
361
<?php endif; ?>
362
</div>
363
<div class="yougitai-actions">
364
<?php if ( $ai_provider === 'direct' ) : ?>
365
<a class="button button-primary" href="<?php echo esc_url( admin_url( 'admin.php?page=yougitai-secure-showcase-settings' ) ); ?>"><?php esc_html_e( 'Open ChatGPT DIRECT setup', 'yougitai-secure-showcase' ); ?></a>
366
<?php elseif ( $ai_configured && empty( $repository['show_original'] ) ) : ?>
367
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
368
<input type="hidden" name="action" value="yougitai_ss_ai_protect_snapshot">
369
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
370
<?php wp_nonce_field( 'yougitai_ss_ai_protect_snapshot_' . $repository['id'] ); ?>
371
<button class="button button-primary" type="submit"><?php esc_html_e( 'Protect with AI', 'yougitai-secure-showcase' ); ?></button>
372
</form>
373
<?php else : ?>
374
<a class="button button-secondary" href="<?php echo esc_url( admin_url( 'admin.php?page=yougitai-secure-showcase-settings' ) ); ?>"><?php esc_html_e( 'Configure AI', 'yougitai-secure-showcase' ); ?></a>
375
<?php endif; ?>
376
</div>
377
</div>
378
<p class="yougitai-safety-inline"><?php esc_html_e( '“Protect with AI” creates a new draft. It never rewrites or publishes the current live showcase automatically.', 'yougitai-secure-showcase' ); ?></p>
379
</section>
380
381
<section class="yougitai-card" id="yougitai-findings">
382
<div class="yougitai-card-header">
383
<div><h3><?php esc_html_e( 'Security review', 'yougitai-secure-showcase' ); ?></h3><p class="yougitai-muted"><?php esc_html_e( 'Findings are grouped by file. A scanner finding marked “already protected” means the suspicious value has already been removed from this draft.', 'yougitai-secure-showcase' ); ?></p></div>
384
</div>
385
<div class="yougitai-review-help">
386
<div><strong><?php esc_html_e( 'Mark reviewed', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'You checked the result and the current protection is correct.', 'yougitai-secure-showcase' ); ?></span></div>
387
<div><strong><?php esc_html_e( 'Accept risk', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'You knowingly accept the remaining risk. This does not restore removed source.', 'yougitai-secure-showcase' ); ?></span></div>
388
<div><strong><?php esc_html_e( 'Ignore as false positive', 'yougitai-secure-showcase' ); ?></strong><span><?php esc_html_e( 'The note is not relevant. This also does not undo an automatic redaction in the current draft.', 'yougitai-secure-showcase' ); ?></span></div>
389
</div>
390
<?php if ( ! $yougitai_finding_groups ) : ?>
391
<div class="yougitai-empty-state"><strong><?php esc_html_e( 'No security findings', 'yougitai-secure-showcase' ); ?></strong><p><?php esc_html_e( 'No scanner or AI review notes were detected for this snapshot.', 'yougitai-secure-showcase' ); ?></p></div>
392
<?php else : ?>
393
<form id="yougitai-bulk-findings" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-bulk-toolbar">
394
<input type="hidden" name="action" value="yougitai_ss_bulk_findings">
395
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
396
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
397
<?php wp_nonce_field( 'yougitai_ss_bulk_findings_' . $selected_snapshot['id'] ); ?>
398
<label><input type="checkbox" data-yougitai-select-all="finding-group"> <span><?php esc_html_e( 'Select all open groups', 'yougitai-secure-showcase' ); ?></span></label>
399
<select name="finding_status">
400
<option value="resolved"><?php esc_html_e( 'Mark selected as reviewed', 'yougitai-secure-showcase' ); ?></option>
401
<option value="accepted"><?php esc_html_e( 'Accept risk for selected', 'yougitai-secure-showcase' ); ?></option>
402
<option value="ignored"><?php esc_html_e( 'Ignore selected as false positives', 'yougitai-secure-showcase' ); ?></option>
403
</select>
404
<button class="button button-secondary" type="submit"><?php esc_html_e( 'Apply to selected', 'yougitai-secure-showcase' ); ?></button>
405
</form>
406
<?php foreach ( $yougitai_finding_groups as $yougitai_path => $yougitai_group ) : ?>
407
<?php
408
$yougitai_related_file = $yougitai_files_by_path[ $yougitai_path ] ?? null;
409
$yougitai_already_protected = $yougitai_related_file && in_array( (string) $yougitai_related_file['visibility'], [ 'redacted', 'hidden' ], true );
410
$yougitai_unique_titles = array_values( array_unique( array_map( static fn( $item ) => (string) $item['title'], $yougitai_group['items'] ) ) );
411
$yougitai_open_csv = implode( ',', $yougitai_group['open_ids'] );
412
?>
413
<article class="yougitai-finding-group yougitai-severity-<?php echo esc_attr( $yougitai_group['severity'] ); ?>">
414
<div class="yougitai-finding-group-select">
415
<?php if ( $yougitai_open_csv !== '' ) : ?><input type="checkbox" form="yougitai-bulk-findings" name="finding_groups[]" value="<?php echo esc_attr( $yougitai_open_csv ); ?>" data-yougitai-select-item="finding-group" aria-label="<?php echo esc_attr__( 'Select this finding group', 'yougitai-secure-showcase' ); ?>"><?php endif; ?>
416
</div>
417
<div class="yougitai-finding-main">
418
<div class="yougitai-finding-title-row">
419
<strong><?php echo esc_html( $yougitai_path ); ?></strong>
420
<?php if ( $yougitai_already_protected ) : ?><span class="yougitai-badge is-success"><?php esc_html_e( 'Already protected in this draft', 'yougitai-secure-showcase' ); ?></span><?php endif; ?>
421
</div>
422
<p><?php echo esc_html( sprintf( _n( '%d review note in this file', '%d review notes in this file', count( $yougitai_group['items'] ), 'yougitai-secure-showcase' ), count( $yougitai_group['items'] ) ) ); ?> · <?php echo esc_html( sprintf( __( 'highest risk %d/100', 'yougitai-secure-showcase' ), $yougitai_group['max_risk'] ) ); ?></p>
423
<ul class="yougitai-finding-reasons">
424
<?php foreach ( $yougitai_unique_titles as $yougitai_title ) : ?><li><?php echo esc_html( $yougitai_title ); ?></li><?php endforeach; ?>
425
</ul>
426
</div>
427
<?php if ( $yougitai_open_csv !== '' ) : ?>
428
<div class="yougitai-actions yougitai-group-actions">
429
<?php foreach ( [ 'resolved' => __( 'Mark reviewed', 'yougitai-secure-showcase' ), 'accepted' => __( 'Accept risk', 'yougitai-secure-showcase' ), 'ignored' => __( 'Ignore', 'yougitai-secure-showcase' ) ] as $yougitai_group_status => $yougitai_group_label ) : ?>
430
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
431
<input type="hidden" name="action" value="yougitai_ss_bulk_findings"><input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>"><input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>"><input type="hidden" name="finding_groups[]" value="<?php echo esc_attr( $yougitai_open_csv ); ?>"><input type="hidden" name="finding_status" value="<?php echo esc_attr( $yougitai_group_status ); ?>">
432
<?php wp_nonce_field( 'yougitai_ss_bulk_findings_' . $selected_snapshot['id'] ); ?>
433
<button class="button button-small" type="submit"><?php echo esc_html( $yougitai_group_label ); ?></button>
434
</form>
435
<?php endforeach; ?>
436
</div>
437
<?php endif; ?>
438
</article>
439
<?php endforeach; ?>
440
<?php endif; ?>
441
</section>
442
443
<section class="yougitai-card" id="yougitai-files">
444
<div class="yougitai-card-header"><div><h3><?php esc_html_e( 'Files & manual redaction', 'yougitai-secure-showcase' ); ?></h3><p class="yougitai-muted"><?php esc_html_e( 'Select one file to open the visual editor, or select several files and hide them together on the next import.', 'yougitai-secure-showcase' ); ?></p></div></div>
445
<form id="yougitai-bulk-files" method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-bulk-toolbar">
446
<input type="hidden" name="action" value="yougitai_ss_bulk_files"><input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>"><input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
447
<?php wp_nonce_field( 'yougitai_ss_bulk_files_' . $selected_snapshot['id'] ); ?>
448
<label><input type="checkbox" data-yougitai-select-all="file"> <span><?php esc_html_e( 'Select all files', 'yougitai-secure-showcase' ); ?></span></label>
449
<button class="button button-secondary yougitai-danger-soft" type="submit"><?php esc_html_e( 'Hide selected files on next import', 'yougitai-secure-showcase' ); ?></button>
450
</form>
451
<div class="yougitai-file-list yougitai-file-list-checkable">
452
<?php foreach ( $files as $file ) : ?>
453
<?php $yougitai_risk_text = (int) $file['risk_score'] === 0 ? __( 'No risk detected', 'yougitai-secure-showcase' ) : sprintf( __( 'Risk %d/100', 'yougitai-secure-showcase' ), (int) $file['risk_score'] ); ?>
454
<div class="<?php echo $selected_file && (int) $selected_file['id'] === (int) $file['id'] ? 'is-current' : ''; ?>">
455
<input type="checkbox" form="yougitai-bulk-files" name="file_ids[]" value="<?php echo esc_attr( $file['id'] ); ?>" data-yougitai-select-item="file" aria-label="<?php echo esc_attr__( 'Select file', 'yougitai-secure-showcase' ); ?>">
456
<a href="<?php echo esc_url( add_query_arg( [ 'page'=>'yougitai-secure-showcase', 'repository_id'=>(int) $repository['id'], 'snapshot_id'=>(int) $selected_snapshot['id'], 'file_id'=>(int) $file['id'] ], admin_url( 'admin.php' ) ) . '#yougitai-redaction-editor' ); ?>"><code><?php echo esc_html( $file['path'] ); ?></code></a>
457
<span class="yougitai-status yougitai-status-<?php echo esc_attr( $file['visibility'] ); ?>"><?php echo esc_html( $yougitai_status_labels[ $file['visibility'] ] ?? $file['visibility'] ); ?> · <?php echo esc_html( $yougitai_risk_text ); ?></span>
458
</div>
459
<?php endforeach; ?>
460
</div>
461
</section>
462
463
<?php if ( $selected_file ) : ?>
464
<section class="yougitai-card" id="yougitai-redaction-editor">
465
<div class="yougitai-card-header"><div><h3><?php esc_html_e( 'Visual redaction editor', 'yougitai-secure-showcase' ); ?></h3><p><code><?php echo esc_html( $selected_file['path'] ); ?></code></p></div><form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"><input type="hidden" name="action" value="yougitai_ss_add_rule"><input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>"><input type="hidden" name="rule_type" value="path"><input type="hidden" name="file_path" value=""><input type="hidden" name="target" value="<?php echo esc_attr( $selected_file['path'] ); ?>"><input type="hidden" name="rule_action" value="hide"><input type="hidden" name="replacement" value="[PROTECTED]"><?php wp_nonce_field( 'yougitai_ss_add_rule_' . $repository['id'] ); ?><button class="button button-secondary yougitai-danger-soft" type="submit"><?php esc_html_e( 'Hide entire file on next import', 'yougitai-secure-showcase' ); ?></button></form></div>
466
<?php if ( $selected_file['visibility'] === 'hidden' || $selected_file['content'] === '' ) : ?>
467
<p><?php esc_html_e( 'This file is hidden and has no persisted source content to display.', 'yougitai-secure-showcase' ); ?></p>
468
<?php else : ?>
469
<div class="yougitai-code-editor" aria-label="<?php echo esc_attr__( 'Protected code preview', 'yougitai-secure-showcase' ); ?>">
470
<?php foreach ( preg_split( '/\R/', (string) $selected_file['content'] ) as $yougitai_line_number => $yougitai_line ) : ?>
471
<div class="yougitai-code-line" data-line="<?php echo esc_attr( $yougitai_line_number + 1 ); ?>"><span><?php echo esc_html( $yougitai_line_number + 1 ); ?></span><code><?php echo esc_html( $yougitai_line ); ?></code></div>
472
<?php endforeach; ?>
473
</div>
474
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-rule-form">
475
<input type="hidden" name="action" value="yougitai_ss_add_line_rule">
476
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
477
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
478
<input type="hidden" name="file_id" value="<?php echo esc_attr( $selected_file['id'] ); ?>">
479
<?php wp_nonce_field( 'yougitai_ss_add_line_rule_' . $selected_file['id'] ); ?>
480
<label><span><?php esc_html_e( 'Start line', 'yougitai-secure-showcase' ); ?></span><input type="number" min="1" name="line_start" required></label>
481
<label><span><?php esc_html_e( 'End line', 'yougitai-secure-showcase' ); ?></span><input type="number" min="1" name="line_end" required></label>
482
<label><span><?php esc_html_e( 'Replacement', 'yougitai-secure-showcase' ); ?></span><input type="text" name="replacement" value="[PROTECTED]"></label>
483
<div><?php submit_button( __( 'Protect selected line range', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?></div>
484
</form>
485
<p class="description"><?php esc_html_e( 'The selected range is fingerprinted. If those lines change upstream, the next import hides the entire file fail-closed and creates a critical review finding.', 'yougitai-secure-showcase' ); ?></p>
486
<hr>
487
<h4><?php esc_html_e( 'Protect class or function', 'yougitai-secure-showcase' ); ?></h4>
488
<p><?php esc_html_e( 'Symbol rules follow a named class, function, or method across line-number changes. If the symbol is ambiguous, missing, or its signature changes unexpectedly, the file is hidden fail-closed.', 'yougitai-secure-showcase' ); ?></p>
489
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-rule-form">
490
<input type="hidden" name="action" value="yougitai_ss_add_symbol_rule">
491
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
492
<input type="hidden" name="snapshot_id" value="<?php echo esc_attr( $selected_snapshot['id'] ); ?>">
493
<input type="hidden" name="file_id" value="<?php echo esc_attr( $selected_file['id'] ); ?>">
494
<?php wp_nonce_field( 'yougitai_ss_add_symbol_rule_' . $selected_file['id'] ); ?>
495
<label><span><?php esc_html_e( 'Symbol name', 'yougitai-secure-showcase' ); ?></span><input type="text" name="symbol" required placeholder="RecommendationEngine"></label>
496
<label><span><?php esc_html_e( 'Replacement', 'yougitai-secure-showcase' ); ?></span><input type="text" name="replacement" value="[PROTECTED SYMBOL]"></label>
497
<div><?php submit_button( __( 'Protect symbol', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?></div>
498
</form>
499
<?php endif; ?>
500
</section>
501
<?php endif; ?>
502
<?php endif; ?>
503
504
<section class="yougitai-card" id="yougitai-rules">
505
<h2><?php esc_html_e( 'Protection rules', 'yougitai-secure-showcase' ); ?></h2>
506
<p><?php echo ! empty( $repository['show_original'] ) ? esc_html__( 'Protection rules are retained but currently bypassed because Original source mode is active. Switch back to Secure showcase mode before applying protection.', 'yougitai-secure-showcase' ) : esc_html__( 'Approved rules can be applied directly to the existing safe draft. Path rules can hide complete files; string and regular-expression rules redact matching content.', 'yougitai-secure-showcase' ); ?></p>
507
<?php if ( $rules ) : ?>
508
<?php $pending_ai_rules = array_values( array_filter( $rules, static fn( array $rule ): bool => $rule['source'] === 'connected_ai' && ! (int) $rule['enabled'] ) ); ?>
509
<?php if ( $pending_ai_rules ) : ?>
510
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-bulk-rule-form" data-yougitai-bulk-rule-form>
511
<input type="hidden" name="action" value="yougitai_ss_bulk_approve_rules">
512
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
513
<?php wp_nonce_field( 'yougitai_ss_bulk_approve_rules_' . $repository['id'] ); ?>
514
<div class="yougitai-rule-filters" data-yougitai-rule-filters>
515
<label><span><?php esc_html_e( 'Decision', 'yougitai-secure-showcase' ); ?></span>
516
<select data-yougitai-rule-filter="decision">
517
<option value=""><?php esc_html_e( 'All decisions', 'yougitai-secure-showcase' ); ?></option>
518
<option value="hide">HIDE</option><option value="redact">REDACT</option><option value="abstract">ABSTRACT</option><option value="show">SHOW</option>
519
</select>
520
</label>
521
<label><span><?php esc_html_e( 'Source', 'yougitai-secure-showcase' ); ?></span>
522
<select data-yougitai-rule-filter="source">
523
<option value=""><?php esc_html_e( 'All sources', 'yougitai-secure-showcase' ); ?></option>
524
<option value="scanner"><?php esc_html_e( 'Scanner', 'yougitai-secure-showcase' ); ?></option>
525
<option value="ai"><?php esc_html_e( 'AI', 'yougitai-secure-showcase' ); ?></option>
526
<option value="manual"><?php esc_html_e( 'Manual', 'yougitai-secure-showcase' ); ?></option>
527
</select>
528
</label>
529
<button class="button" type="button" data-yougitai-rule-filter-reset><?php esc_html_e( 'Reset filters', 'yougitai-secure-showcase' ); ?></button>
530
<span class="description" data-yougitai-rule-filter-count></span>
531
</div>
532
<div class="yougitai-bulk-toolbar">
533
<label><input type="checkbox" data-yougitai-select-all="rule-proposal"> <span><?php esc_html_e( 'Select all visible', 'yougitai-secure-showcase' ); ?></span></label>
534
<button class="button button-primary" type="submit" data-yougitai-confirm="<?php echo esc_attr__( 'Approve the selected protection proposals? After approval, use “Apply protection now” to create a new review draft.', 'yougitai-secure-showcase' ); ?>"><?php esc_html_e( 'Approve selected', 'yougitai-secure-showcase' ); ?></button>
535
<button class="button" type="button" data-yougitai-approve-all-rules data-confirm="<?php echo esc_attr__( 'Approve all visible protection proposals? After approval, use “Apply protection now” to create a new review draft.', 'yougitai-secure-showcase' ); ?>"><?php esc_html_e( 'Approve all visible', 'yougitai-secure-showcase' ); ?></button>
536
</div>
537
<table class="widefat striped"><thead><tr><th class="check-column"><span class="screen-reader-text"><?php esc_html_e( 'Select', 'yougitai-secure-showcase' ); ?></span></th><th><?php esc_html_e( 'Type', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'File', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Target', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Action', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Source', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Status', 'yougitai-secure-showcase' ); ?></th></tr></thead><tbody>
538
<?php foreach ( $rules as $rule ) : ?>
539
<?php
540
$yougitai_decision = $rule['action'] === 'hide' ? 'hide' : ( $rule['action'] === 'redact' ? 'redact' : '' );
541
if ( ! empty( $rule['notes'] ) && preg_match( '/\bdecision=(show|abstract|redact|hide)\b/i', (string) $rule['notes'], $yougitai_decision_match ) ) {
542
$yougitai_decision = strtolower( $yougitai_decision_match[1] );
543
}
544
$yougitai_source = in_array( $rule['source'], [ 'connected_ai', 'ai' ], true ) ? 'ai' : ( $rule['source'] === 'scanner' ? 'scanner' : 'manual' );
545
?>
546
<tr data-yougitai-rule-row data-rule-decision="<?php echo esc_attr( $yougitai_decision ); ?>" data-rule-source="<?php echo esc_attr( $yougitai_source ); ?>">
547
<th class="check-column"><?php if ( $rule['source'] === 'connected_ai' && ! (int) $rule['enabled'] ) : ?><input type="checkbox" name="rule_ids[]" value="<?php echo esc_attr( $rule['id'] ); ?>" data-yougitai-select-item="rule-proposal"><?php endif; ?></th>
548
<td><?php echo esc_html( [ 'path'=>__( 'Path pattern', 'yougitai-secure-showcase' ), 'string'=>__( 'Exact string', 'yougitai-secure-showcase' ), 'regex'=>__( 'Regular expression', 'yougitai-secure-showcase' ), 'line_range'=>__( 'Line range', 'yougitai-secure-showcase' ), 'symbol'=>__( 'Symbol', 'yougitai-secure-showcase' ) ][ $rule['rule_type'] ] ?? $rule['rule_type'] ); ?></td>
549
<td><code><?php echo esc_html( $rule['file_path'] ?: '—' ); ?></code></td>
550
<td><code><?php echo esc_html( $rule['target'] ); ?></code></td>
551
<td><?php echo esc_html( [ 'hide'=>__( 'Hide file', 'yougitai-secure-showcase' ), 'redact'=>__( 'Redact match', 'yougitai-secure-showcase' ) ][ $rule['action'] ] ?? $rule['action'] ); ?></td>
552
<td><?php echo esc_html( $rule['source'] === 'connected_ai' ? __( 'Connected AI proposal', 'yougitai-secure-showcase' ) : __( 'Manual', 'yougitai-secure-showcase' ) ); ?></td>
553
<td><?php if ( $rule['source'] === 'connected_ai' && ! empty( $rule['notes'] ) ) : ?><span class="description"><?php echo esc_html( $rule['notes'] ); ?></span><br><?php endif; ?><?php if ( $rule['source'] === 'connected_ai' && ! (int) $rule['enabled'] ) : ?><button class="button button-small" type="submit" name="single_rule_id" value="<?php echo esc_attr( $rule['id'] ); ?>" formnovalidate><?php esc_html_e( 'Approve proposal', 'yougitai-secure-showcase' ); ?></button><?php else : ?><?php echo esc_html( (int) $rule['enabled'] ? __( 'Active', 'yougitai-secure-showcase' ) : __( 'Disabled', 'yougitai-secure-showcase' ) ); ?><?php endif; ?></td>
554
</tr>
555
<?php endforeach; ?>
556
</tbody></table>
557
</form>
558
<?php else : ?>
559
<table class="widefat striped"><thead><tr><th><?php esc_html_e( 'Type', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'File', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Target', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Action', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Source', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Status', 'yougitai-secure-showcase' ); ?></th></tr></thead><tbody>
560
<?php foreach ( $rules as $rule ) : ?><tr><td><?php echo esc_html( [ 'path'=>__( 'Path pattern', 'yougitai-secure-showcase' ), 'string'=>__( 'Exact string', 'yougitai-secure-showcase' ), 'regex'=>__( 'Regular expression', 'yougitai-secure-showcase' ), 'line_range'=>__( 'Line range', 'yougitai-secure-showcase' ), 'symbol'=>__( 'Symbol', 'yougitai-secure-showcase' ) ][ $rule['rule_type'] ] ?? $rule['rule_type'] ); ?></td><td><code><?php echo esc_html( $rule['file_path'] ?: '—' ); ?></code></td><td><code><?php echo esc_html( $rule['target'] ); ?></code></td><td><?php echo esc_html( [ 'hide'=>__( 'Hide file', 'yougitai-secure-showcase' ), 'redact'=>__( 'Redact match', 'yougitai-secure-showcase' ) ][ $rule['action'] ] ?? $rule['action'] ); ?></td><td><?php echo esc_html( $rule['source'] === 'connected_ai' ? __( 'Connected AI proposal', 'yougitai-secure-showcase' ) : __( 'Manual', 'yougitai-secure-showcase' ) ); ?></td><td><?php echo esc_html( (int) $rule['enabled'] ? __( 'Active', 'yougitai-secure-showcase' ) : __( 'Disabled', 'yougitai-secure-showcase' ) ); ?></td></tr><?php endforeach; ?>
561
</tbody></table>
562
<?php endif; ?>
563
<?php endif; ?>
564
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="yougitai-rule-form">
565
<input type="hidden" name="action" value="yougitai_ss_add_rule">
566
<input type="hidden" name="repository_id" value="<?php echo esc_attr( $repository['id'] ); ?>">
567
<?php wp_nonce_field( 'yougitai_ss_add_rule_' . $repository['id'] ); ?>
568
<label><span><?php esc_html_e( 'Rule type', 'yougitai-secure-showcase' ); ?></span><select name="rule_type"><option value="path"><?php esc_html_e( 'Path pattern', 'yougitai-secure-showcase' ); ?></option><option value="string"><?php esc_html_e( 'Exact string', 'yougitai-secure-showcase' ); ?></option><option value="regex"><?php esc_html_e( 'Regular expression', 'yougitai-secure-showcase' ); ?></option></select></label>
569
<label><span><?php esc_html_e( 'File path (optional)', 'yougitai-secure-showcase' ); ?></span><input type="text" name="file_path" placeholder="src/service.php"></label>
570
<label><span><?php esc_html_e( 'Target', 'yougitai-secure-showcase' ); ?></span><input type="text" name="target" required placeholder="src/private/*"></label>
571
<label><span><?php esc_html_e( 'Action', 'yougitai-secure-showcase' ); ?></span><select name="rule_action"><option value="hide"><?php esc_html_e( 'Hide file', 'yougitai-secure-showcase' ); ?></option><option value="redact"><?php esc_html_e( 'Redact match', 'yougitai-secure-showcase' ); ?></option></select></label>
572
<label><span><?php esc_html_e( 'Replacement', 'yougitai-secure-showcase' ); ?></span><input type="text" name="replacement" value="[PROTECTED]"></label>
573
<div><?php submit_button( __( 'Add protection rule', 'yougitai-secure-showcase' ), 'secondary', 'submit', false ); ?></div>
574
</form>
575
</section>
576
<section class="yougitai-card" id="yougitai-audit">
577
<h2><?php esc_html_e( 'Audit history', 'yougitai-secure-showcase' ); ?></h2>
578
<p><?php esc_html_e( 'Security-relevant repository actions are recorded here for review and troubleshooting.', 'yougitai-secure-showcase' ); ?></p>
579
<?php if ( empty( $audit_events ) ) : ?>
580
<p><?php esc_html_e( 'No audit events yet.', 'yougitai-secure-showcase' ); ?></p>
581
<?php else : ?>
582
<table class="widefat striped">
583
<thead><tr><th><?php esc_html_e( 'Time', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Event', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Snapshot', 'yougitai-secure-showcase' ); ?></th><th><?php esc_html_e( 'Message', 'yougitai-secure-showcase' ); ?></th></tr></thead>
584
<tbody>
585
<?php foreach ( $audit_events as $event ) : ?>
586
<tr>
587
<td><?php echo esc_html( mysql2date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $event['created_at'] ) ); ?></td>
588
<td><code><?php echo esc_html( $event['event_type'] ); ?></code></td>
589
<td><?php echo $event['snapshot_id'] ? '#' . esc_html( $event['snapshot_id'] ) : '—'; ?></td>
590
<td><?php echo esc_html( $event['message'] ); ?></td>
591
</tr>
592
<?php endforeach; ?>
593
</tbody>
594
</table>
595
<?php endif; ?>
596
</section>
597
598
</div>
599