mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-03 09:56:57 +02:00
* fix: support Windows Opera and Opera GX cookie imports Fixes #2957 * fix: repair Windows cookie decryption and make Opera import failures actionable - strip the SHA-256(host_key) prefix Chromium adds to v10 values (DB meta v24+) on Windows - keep receipts and name `$B handoff` recovery for App-Bound rows in browsers without native extraction - explain missing browsers, missing profiles and ambiguous profile selection with next steps - add windowsNative/resolveBrowserInfo, the operagx alias and sorted failure reasons in CLI output - cover the Node server runtime with a real-DPAPI Windows test * docs: document Windows Opera cookie import and guard browser lists against drift * chore: file cookie-import follow-ups from the Opera fix wave review * test: keep Opera receipt tests independent of the shared key cache * test: declare generated gstack/llms.txt as a command-reference input for PR selection * chore: release v1.91.4.0 * test: reconstruct the historical cookie-workflow approval after the Opera BROWSER.md additions * test: run the real-DPAPI Windows check with the runner's environment PowerShell launched with a stripped environment took ~18-21s on the Windows runner (measured on a throwaway diagnostics run), past dpapiDecrypt's 10s deadline; with the full environment it returns in ~0.3s. Only APPDATA is redirected to the fixture's Opera root. --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
43 lines
3.1 KiB
TypeScript
43 lines
3.1 KiB
TypeScript
import { readFileSync } from 'node:fs';
|
|
import { createHash } from 'node:crypto';
|
|
import { resolve } from 'node:path';
|
|
import type { EvalTestEntry } from './eval-store';
|
|
import { buildCookieWorkflowJudgeInput } from './cookie-workflow-judge-input';
|
|
import { COOKIE_MANUAL_REVIEW_FILE } from './cookie-workflow-manual-review';
|
|
|
|
// Later documentation added to the judged BROWSER.md section after the approval
|
|
// was recorded (v1.91.4.0 Windows Opera wave). Reversing it reconstructs the
|
|
// exact historical prompt bytes, including the section's line range.
|
|
const LATER_BROWSER_BLOCK = /\*\*Windows: Opera and Opera GX\.\*\*[\s\S]*?appear in CLI output\.\n\n/;
|
|
const LATER_BROWSER_EDITS: Array<[string, string]> = [
|
|
['The picker recognizes Chrome, Chromium, Brave, Edge, Windows-only Opera and Opera GX, and macOS-only Comet, Arc, and Dia.', 'The picker recognizes Chrome, Chromium, Brave, Edge, and macOS-only Comet, Arc, and Dia.'],
|
|
[' Opera and Opera GX are Windows-only and read from `%APPDATA%\\Opera Software\\Opera Stable` or `Opera GX Stable`, in `Default` or `Profile N` directories; legacy root-level layouts, Opera side profiles and portable or relocated installs are not detected. Opera has no native extraction, so its App-Bound cookies (if any) need manual sign-in.', ''],
|
|
];
|
|
|
|
export function approvedCookieWorkflowSource(source: string): string {
|
|
let removedLines = 0;
|
|
let historical = source
|
|
.replace('sha256sum < "$tmpfile" | awk \'{print $(1)}\'', 'sha256sum "$tmpfile" | awk \'{print $1}\'')
|
|
.replace('shasum -a 256 < "$tmpfile" | awk \'{print $(1)}\'', 'shasum -a 256 "$tmpfile" | awk \'{print $1}\'')
|
|
.replace(LATER_BROWSER_BLOCK, block => { removedLines = block.split('\n').length - 1; return ''; });
|
|
for (const [later, earlier] of LATER_BROWSER_EDITS) historical = historical.replace(later, earlier);
|
|
return historical.replace(/(--- BEGIN FILE "BROWSER\.md" \(lines \d+-)(\d+)(; section\) ---)/, (_, head, end, tail) => `${head}${Number(end) - removedLines}${tail}`);
|
|
}
|
|
|
|
export function manualReviewFixture(root = resolve(import.meta.dir, '../..')): EvalTestEntry {
|
|
const approval = JSON.parse(readFileSync(resolve(root, COOKIE_MANUAL_REVIEW_FILE), 'utf8'));
|
|
const prompt = approvedCookieWorkflowSource(buildCookieWorkflowJudgeInput(root).prompt);
|
|
if (createHash('sha256').update(prompt).digest('hex') !== approval.prompt_sha256
|
|
|| Buffer.byteLength(prompt) !== approval.prompt_bytes) {
|
|
throw new Error('Historical cookie approval fixture no longer reconstructs the exact approved prompt');
|
|
}
|
|
return {
|
|
name: 'setup-browser-cookies/SKILL.md workflow', suite: 'Cookie setup workflow quality', tier: 'llm-judge',
|
|
passed: false, execution: 'executed', exit_reason: 'provider_refusal', attempt: 1, duration_ms: 1, cost_usd: 0,
|
|
model: approval.model, prompt,
|
|
error: 'Synthetic provider refusal fixture, not live model evidence',
|
|
manual_review: { approval, refusal: { stop_reason: 'refusal', response_id: 'msg_synthetic_fixture',
|
|
request_id: 'req_synthetic_fixture', model: approval.model, input_tokens: 1, output_tokens: 0, text_blocks: 0 } },
|
|
};
|
|
}
|