Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

368 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const puppeteer = require('puppeteer');
const AuthHelper = require('./auth_helper');
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
// Color codes for terminal output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m'
};
function log(message, type = 'info') {
const timestamp = new Date().toISOString();
const prefix = {
info: `${colors.blue}`,
success: `${colors.green}✓`,
error: `${colors.red}ERROR:`,
warn: `${colors.yellow}⚠`
}[type] || '';
console.log(`${prefix}[${timestamp}] ${message}${colors.reset}`);
}
(async () => {
let browser;
let authHelper;
try {
// Test configuration
const TEST_API_KEY_1 = 'test-api-key-12345';
const TEST_API_KEY_2 = 'changed-api-key-67890';
const BASE_URL = 'http://localhost:5000';
log(`${colors.bright}=== Starting API Key Settings Test ===${colors.reset}`, 'info');
// Launch browser
browser = await puppeteer.launch(getPuppeteerLaunchOptions());
log('Browser launched', 'success');
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });
// Log browser console errors
page.on('console', msg => {
if (msg.type() === 'error') {
log(`Browser console: ${msg.text()}`, 'error');
}
});
// Initialize auth helper
authHelper = new AuthHelper(page);
// Create test user with timestamp
const timestamp = Date.now();
const testUsername = `api_test_${timestamp}`;
const testPassword = 'testpass123';
log(`Creating user: ${testUsername}`, 'info');
// Register and login
await authHelper.register(testUsername, testPassword);
const isAuthenticated = await authHelper.isLoggedIn();
if (!isAuthenticated) {
throw new Error('Failed to authenticate after registration');
}
log('User authenticated successfully', 'success');
// Navigate to settings page
log('Navigating to settings page...', 'info');
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
// Check if we got redirected to login
const currentUrl = page.url();
if (currentUrl.includes('/auth/login')) {
log('Redirected to login page, attempting to login again...', 'warn');
// Try to login again
await authHelper.login(testUsername, testPassword);
// Navigate to settings again
await page.goto(`${BASE_URL}/settings`, { waitUntil: 'domcontentloaded' });
}
// Wait for settings to load - try multiple selectors
try {
await page.waitForSelector('.settings-container, #settings-content, .settings-page, main', { timeout: 5000 });
} catch {
log('Settings container not found, continuing anyway...', 'warn');
}
// Take screenshot of initial settings page
await page.screenshot({
path: `/tmp/api_key_test_settings_initial_${timestamp}.png`,
fullPage: true
});
log('Screenshot saved: Initial settings page', 'info');
// Debug: Check page title and URL
const pageTitle = await page.title();
const pageUrl = page.url();
log(`Current page - Title: ${pageTitle}, URL: ${pageUrl}`, 'info');
// Find and click on LLM settings section
log('Looking for LLM settings section...', 'info');
// Click on LLM section in the sidebar if needed - use simpler selectors
const llmSectionSelectors = ['a[href="#llm"]', '.nav-link:contains("LLM")', 'button:contains("LLM")'];
let clicked = false;
for (const selector of llmSectionSelectors) {
try {
if (await page.$(selector)) {
await page.click(selector);
await new Promise(resolve => setTimeout(resolve, 500));
log(`Clicked LLM section with selector: ${selector}`, 'success');
clicked = true;
break;
}
} catch {
// Try next selector
}
}
// Look for OpenAI Endpoint subsection
const openaiEndpointSelectors = ['a[href="#llm-openai-endpoint"]', '.nav-link:contains("OpenAI Endpoint")', 'button:contains("OpenAI Endpoint")'];
for (const selector of openaiEndpointSelectors) {
try {
if (await page.$(selector)) {
await page.click(selector);
await new Promise(resolve => setTimeout(resolve, 500));
log(`Clicked OpenAI Endpoint section with selector: ${selector}`, 'success');
break;
}
} catch {
// Try next selector
}
}
// Find the API key input field
log('Looking for OpenAI Endpoint API key field...', 'info');
// Try multiple selectors for the API key field
const apiKeySelectors = [
'input[name="llm.openai_endpoint.api_key"]',
'input[id="llm.openai_endpoint.api_key"]',
'input[data-setting="llm.openai_endpoint.api_key"]',
'input[type="password"][name*="openai_endpoint"]',
'input[type="text"][name*="openai_endpoint.api_key"]'
];
let apiKeyInput = null;
for (const selector of apiKeySelectors) {
apiKeyInput = await page.$(selector);
if (apiKeyInput) {
log(`Found API key input with selector: ${selector}`, 'success');
break;
}
}
if (!apiKeyInput) {
// Try to find it by label
const labels = await page.$$('label');
for (const label of labels) {
const text = await label.evaluate(el => el.textContent);
if (text.toLowerCase().includes('openai endpoint') && text.toLowerCase().includes('api key')) {
const forAttr = await label.evaluate(el => el.getAttribute('for'));
if (forAttr) {
apiKeyInput = await page.$(`#${forAttr}`);
if (apiKeyInput) {
log(`Found API key input via label: ${forAttr}`, 'success');
break;
}
}
}
}
}
if (!apiKeyInput) {
throw new Error('Could not find OpenAI Endpoint API key input field');
}
// Clear and set first API key
log(`Setting API key to: ${TEST_API_KEY_1}`, 'info');
await apiKeyInput.click({ clickCount: 3 });
await apiKeyInput.type(TEST_API_KEY_1);
// Find and click save button
log('Looking for save button...', 'info');
const saveButtonSelectors = [
'button[type="submit"]',
'button.btn-primary',
'.save-btn',
'button.save-settings',
'#save-settings-btn'
];
let saveButton = null;
for (const selector of saveButtonSelectors) {
try {
saveButton = await page.waitForSelector(selector, { timeout: 2000 });
if (saveButton) {
log(`Found save button with selector: ${selector}`, 'success');
break;
}
} catch {
// Continue to next selector
}
}
if (saveButton) {
await saveButton.click();
log('Clicked save button', 'success');
// Wait for save confirmation
await new Promise(resolve => setTimeout(resolve, 2000));
// Take screenshot after first save
await page.screenshot({
path: `/tmp/api_key_test_after_first_save_${timestamp}.png`,
fullPage: true
});
log('Screenshot saved: After first API key save', 'info');
}
// Refresh page to verify persistence
log('Refreshing page to verify API key persistence...', 'info');
await page.reload({ waitUntil: 'domcontentloaded' });
await new Promise(resolve => setTimeout(resolve, 1000));
// Navigate back to OpenAI Endpoint settings
for (const selector of llmSectionSelectors) {
try {
if (await page.$(selector)) {
await page.click(selector);
await new Promise(resolve => setTimeout(resolve, 500));
break;
}
} catch {
// Try next selector
}
}
for (const selector of openaiEndpointSelectors) {
try {
if (await page.$(selector)) {
await page.click(selector);
await new Promise(resolve => setTimeout(resolve, 500));
break;
}
} catch {
// Try next selector
}
}
// Find API key input again
apiKeyInput = null;
for (const selector of apiKeySelectors) {
apiKeyInput = await page.$(selector);
if (apiKeyInput) break;
}
if (apiKeyInput) {
// Get current value
const currentValue = await apiKeyInput.evaluate(el => el.value);
log(`Current API key value after refresh: ${currentValue ? '***' + currentValue.slice(-5) : 'empty'}`, 'info');
if (currentValue && currentValue.includes(TEST_API_KEY_1.slice(-5))) {
log('API key persisted correctly after refresh!', 'success');
} else {
log('API key did not persist after refresh', 'error');
}
// Now change to second API key
log(`Changing API key to: ${TEST_API_KEY_2}`, 'info');
await apiKeyInput.click({ clickCount: 3 });
await apiKeyInput.type(TEST_API_KEY_2);
// Save again
if (saveButton) {
await saveButton.click();
log('Clicked save button for second API key', 'success');
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
// Make an API call to verify the setting was saved
log('Verifying API key via API call...', 'info');
const apiResponse = await page.evaluate(async () => {
try {
const response = await fetch('/api/settings', {
credentials: 'same-origin'
});
const data = await response.json();
// Look for the API key setting
const apiKeySetting = data.settings?.find(s =>
s.key === 'llm.openai_endpoint.api_key' ||
s.setting_key === 'llm.openai_endpoint.api_key'
);
return {
success: response.ok,
apiKeyFound: !!apiKeySetting,
apiKeyValue: apiKeySetting?.value,
allSettings: data.settings?.map(s => s.key || s.setting_key)
};
} catch (error) {
return { success: false, error: error.message };
}
});
if (apiResponse.success) {
log(`API call successful. API key found: ${apiResponse.apiKeyFound}`, 'info');
if (apiResponse.apiKeyValue) {
log(`API key value from API: ***${apiResponse.apiKeyValue.slice(-5)}`, 'info');
}
if (apiResponse.allSettings) {
log(`Total settings found: ${apiResponse.allSettings.length}`, 'info');
const llmSettings = apiResponse.allSettings.filter(s => s && s.startsWith('llm.'));
log(`LLM settings found: ${llmSettings.length}`, 'info');
}
} else {
log(`API call failed: ${apiResponse.error}`, 'error');
}
// Take final screenshot
await page.screenshot({
path: `/tmp/api_key_test_final_${timestamp}.png`,
fullPage: true
});
log('Screenshot saved: Final state', 'info');
// Try to trigger a research to see if the API key is being used
log('Testing if API key is accessible for research...', 'info');
await page.goto(`${BASE_URL}/`, { waitUntil: 'domcontentloaded' });
// Get final status
const finalUrl = page.url();
log(`Final page URL: ${finalUrl}`, 'info');
log('API Key Settings test completed', 'success');
} catch (error) {
log(`Test failed: ${error.message}`, 'error');
console.error(error);
// Take error screenshot
if (browser) {
const page = (await browser.pages())[0];
if (page) {
await page.screenshot({
path: `/tmp/api_key_test_error_${Date.now()}.png`,
fullPage: true
});
log('Error screenshot saved', 'info');
}
}
process.exit(1);
} finally {
if (browser) {
await browser.close();
log('Browser closed', 'success');
}
}
})();