-
Notifications
You must be signed in to change notification settings - Fork 110
Add in-app issue reporting funnel and canonical repo URLs #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
791134f
de0b6b0
4182339
4fe264c
fbeff80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| blank_issues_enabled: false | ||
|
|
||
| contact_links: | ||
| - name: Questions & Answers | ||
| url: https://github.com/nesszer/Win-CodexBar/discussions | ||
| about: Ask usage questions, share tips, and discuss Win-CodexBar with other users. | ||
| - name: Configuration docs | ||
| url: https://github.com/nesszer/Win-CodexBar/blob/main/docs/CONFIGURATION.md | ||
| about: Configuration questions are best answered by the docs first. | ||
| - name: Cookies and browser docs | ||
| url: https://github.com/nesszer/Win-CodexBar/blob/main/docs/COOKIES.md | ||
| about: Browser cookie import questions are covered in the cookies docs. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| # Security policy | ||
|
|
||
| ## Supported versions | ||
|
|
||
| Only the latest release of Win-CodexBar is supported. Security fixes are made | ||
| against the current release line; older releases and the historical upstream | ||
| macOS project are not patched. | ||
|
|
||
| ## Reporting a vulnerability | ||
|
|
||
| Please use GitHub's private vulnerability reporting: open the | ||
| [Security tab](https://github.com/nesszer/Win-CodexBar/security) and click | ||
| "Report a vulnerability". | ||
|
|
||
| Do **not** open a public GitHub issue for a vulnerability. Public issues and | ||
| the bug report template are for non-security problems only. | ||
|
|
||
| Win-CodexBar handles provider cookies, OAuth tokens, and API keys locally, so | ||
| reports touching that surface — credential extraction, storage, redaction, or | ||
| leakage — are taken seriously. Please keep report details private and do not | ||
| paste secrets, cookies, or tokens into any report. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,24 @@ | ||||||
| # Support | ||||||
|
|
||||||
| ## Bug reports | ||||||
|
|
||||||
| Use the [bug report template](https://github.com/nesszer/Win-CodexBar/issues/new?template=bug_report.yml). | ||||||
| If you have safe diagnostics from the CLI, attach them: | ||||||
| `codexbar diagnose` exports provider diagnostics as JSON with no cookies or | ||||||
| tokens. | ||||||
|
|
||||||
| ## Questions and discussions | ||||||
|
|
||||||
| Ask in [Discussions](https://github.com/nesszer/Win-CodexBar/discussions). | ||||||
|
|
||||||
| ## Docs | ||||||
|
|
||||||
| Configuration, CLI, cookies, providers, and privacy docs live in | ||||||
| [`docs/`](docs): ARCHITECTURE, BUILDING, CLI, CODE_SIGNING, CONFIGURATION, | ||||||
| COOKIES, PRIVACY, PROVIDERS, WINDOWS_PROOF, WSL, and the ADRs under | ||||||
| [`docs/adr/`](docs/adr). | ||||||
|
|
||||||
| Feature requests use the | ||||||
| [feature request template](https://github.com/nesszer/Win-CodexBar/issues/new?template=feature_request.yml). | ||||||
| Security vulnerabilities go through the | ||||||
| [Security tab](SECURITY.md), not public issues. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Point the “Security tab” link to the Security tab. Line 24 links to local Proposed fix-Security vulnerabilities go through the [Security tab](SECURITY.md), not public issues.
+Security vulnerabilities go through the [Security tab](https://github.com/nesszer/Win-CodexBar/security), not public issues.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,53 @@ | ||
| // `get_safe_diagnostics` (the only Tauri command this module exposed) was | ||
| // removed as orphaned dead code — the frontend wrappers that invoked it were | ||
| // deleted, leaving zero invokers. Its `SafeDiagnostics` payload + the | ||
| // `safe_diagnostics_from` builder + the secret-redaction test existed solely | ||
| // to support that command and were removed with it. | ||
| //! `get_safe_diagnostics` — a copy-friendly, secret-free diagnostics string | ||
| //! for bug reports. Contains only: app version/build, OS, update channel, | ||
| //! the log file's config-relative path, and the redacted log tail. The log | ||
| //! path is trimmed to its segments below the user profile so no username is | ||
| //! embedded, and the tail is redacted for both secrets and email addresses. | ||
| //! Never includes provider names, plans, account info, cookies, or tokens. | ||
|
|
||
| use super::*; | ||
|
|
||
| /// Last segments of `path` below the user profile (never the profile itself). | ||
| fn config_relative_path(path: &std::path::Path) -> String { | ||
| let segments: Vec<std::ffi::OsString> = | ||
| path.iter().map(std::borrow::ToOwned::to_owned).collect(); | ||
| let tail: Vec<String> = segments | ||
| .iter() | ||
| .rev() | ||
| .take(3) | ||
| .rev() | ||
| .map(|s| s.to_string_lossy().to_string()) | ||
| .collect(); | ||
| if tail.len() == 3 { | ||
| tail.join("/") | ||
| } else { | ||
| "unresolvable".to_string() | ||
| } | ||
| } | ||
|
|
||
| #[tauri::command] | ||
| pub fn get_safe_diagnostics() -> String { | ||
| let settings = Settings::load(); | ||
| let log_dir = codexbar::logging::log_file_path() | ||
| .map(|p| config_relative_path(&p)) | ||
| .unwrap_or_else(|| "unresolvable".to_string()); | ||
|
Comment on lines
+31
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Redact profile-derived paths in copied diagnostics. The diagnostics response includes the log directory and log-tail lines verbatim. On Windows these can contain 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| let log_tail = | ||
| codexbar::logging::read_log_tail().unwrap_or_else(|| "log file unavailable".to_string()); | ||
|
|
||
| format!( | ||
| "CodexBar diagnostics\n\ | ||
| -------------------\n\ | ||
| version: {} (build {})\n\ | ||
| os: {}\n\ | ||
| channel: {}\n\ | ||
| log file: {}\n\ | ||
| --- last log lines (redacted) ---\n\ | ||
| {}", | ||
| env!("CARGO_PKG_VERSION"), | ||
| option_env!("BUILD_NUMBER").unwrap_or("dev"), | ||
| std::env::consts::OS, | ||
| update_channel_label(settings.update_channel), | ||
| log_dir, | ||
| log_tail, | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import { fireEvent, render, screen, waitFor } from "@testing-library/react"; | ||
| import { beforeEach, describe, expect, it, vi } from "vitest"; | ||
|
|
||
| const tauriMocks = vi.hoisted(() => ({ | ||
| getSafeDiagnostics: vi.fn(), | ||
| registerGlobalShortcut: vi.fn().mockResolvedValue(undefined), | ||
| unregisterGlobalShortcut: vi.fn().mockResolvedValue(undefined), | ||
| })); | ||
|
|
||
| vi.mock("../../../lib/tauri", () => tauriMocks); | ||
| vi.mock("../../../hooks/useLocale", () => ({ | ||
| useLocale: () => ({ t: (key: string) => key }), | ||
| })); | ||
|
|
||
| import AdvancedTab from "./AdvancedTab"; | ||
| import type { SettingsSnapshot } from "../../../types/bridge"; | ||
|
|
||
| const settings: SettingsSnapshot = { | ||
| enabledProviders: [], | ||
| refreshIntervalSecs: 300, | ||
| adaptiveRefresh: false, | ||
| refreshAllProvidersOnMenuOpen: false, | ||
| lowPowerMode: false, | ||
| startAtLogin: false, | ||
| startMinimized: false, | ||
| showNotifications: true, | ||
| soundEnabled: true, | ||
| notificationSoundTheme: "windows", | ||
| highUsageThreshold: 70, | ||
| criticalUsageThreshold: 90, | ||
| predictivePaceWarningEnabled: false, | ||
| trayIconMode: "single", | ||
| switcherShowsIcons: true, | ||
| menuBarShowsHighestUsage: true, | ||
| menuBarShowsPercent: true, | ||
| showAsUsed: false, | ||
| showAllTokenAccountsInMenu: true, | ||
| enableAnimations: true, | ||
| resetTimeRelative: true, | ||
| showResetWhenExhausted: false, | ||
| menuBarDisplayMode: "compact", | ||
| notificationSoundPaths: { | ||
| predictiveWarning: null, | ||
| highUsage: null, | ||
| criticalUsage: null, | ||
| exhausted: null, | ||
| statusIssue: null, | ||
| sessionDepleted: null, | ||
| sessionRestored: null, | ||
| }, | ||
| hidePersonalInfo: false, | ||
| autoDownloadUpdates: false, | ||
| installUpdatesOnQuit: false, | ||
| globalShortcut: "", | ||
| codexCustomSessionsDirs: [], | ||
| updateChannel: "stable", | ||
| uiLanguage: "english", | ||
| theme: "dark", | ||
| windowScalePercent: 125, | ||
| trayScalePercent: 100, | ||
| powertoysStatusPipeEnabled: false, | ||
| claudeAvoidKeychainPrompts: true, | ||
| codexSparkUsageVisible: true, | ||
| disableKeychainAccess: false, | ||
| providerMetrics: {}, | ||
| floatBarEnabled: false, | ||
| floatBarOpacity: 0.9, | ||
| floatBarScale: 100, | ||
| floatBarOrientation: "horizontal", | ||
| floatBarStyle: "floating", | ||
| floatBarClickThrough: false, | ||
| floatBarProviderIds: [], | ||
| floatBarDarkText: false, | ||
| floatBarShowResetInline: false, | ||
| floatBarShowCost: false, | ||
| claudeDailyRoutinesUsageVisible: true, | ||
| claudeAllowReadingClaudeCodeCredentials: false, | ||
| alibabaTokenPlanRegion: "cn", | ||
| weeklyProgressWorkDays: null, | ||
| costSummaryDisplayStyle: "compact", | ||
| providerAccentColors: {}, | ||
| }; | ||
|
|
||
| describe("AdvancedTab", () => { | ||
| beforeEach(() => { | ||
| vi.clearAllMocks(); | ||
| tauriMocks.getSafeDiagnostics.mockResolvedValue("diagnostics text"); | ||
| }); | ||
|
|
||
| it("copies safe diagnostics to the clipboard", async () => { | ||
| const writeText = vi.fn().mockResolvedValue(undefined); | ||
| Object.assign(navigator, { clipboard: { writeText } }); | ||
|
|
||
| render(<AdvancedTab settings={settings} set={vi.fn()} saving={false} />); | ||
|
|
||
| screen.getByRole("heading", { name: "DiagnosticsSectionHeading" }); | ||
| fireEvent.click( | ||
| screen.getByRole("button", { name: "DiagnosticsCopyButton" }), | ||
| ); | ||
|
|
||
| await waitFor(() => { | ||
| expect(tauriMocks.getSafeDiagnostics).toHaveBeenCalled(); | ||
| }); | ||
| await waitFor(() => { | ||
| expect(writeText).toHaveBeenCalledWith("diagnostics text"); | ||
| }); | ||
| await waitFor(() => { | ||
| expect(screen.getAllByText("DiagnosticsCopied").length).toBeGreaterThan(0); | ||
| }); | ||
| }); | ||
|
|
||
| it("shows an error when copying diagnostics fails", async () => { | ||
| tauriMocks.getSafeDiagnostics.mockRejectedValue(new Error("invoke failed")); | ||
| render(<AdvancedTab settings={settings} set={vi.fn()} saving={false} />); | ||
|
|
||
| screen.getByRole("heading", { name: "DiagnosticsSectionHeading" }); | ||
| fireEvent.click( | ||
| screen.getByRole("button", { name: "DiagnosticsCopyButton" }), | ||
| ); | ||
| await waitFor(() => { | ||
| expect( | ||
| screen.getAllByText(/DiagnosticsCopyFailed/).length, | ||
| ).toBeGreaterThan(0); | ||
| }); | ||
| }); | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.