-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat: Add experimental wails3 setup wizard
#4906
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
base: v3-alpha
Are you sure you want to change the base?
Conversation
- Add 'splash' step as the initial wizard page - Scrolling montage background with Wails app screenshots - Centered logo with red glow effect - Apple-style welcome text - Footer with theme toggle, sponsor link, and Get Started button - Simplified button styling (rounded-lg, no glow) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TemplateFooter with theme toggle + sponsor on left, nav on right - Redesign WelcomePage with logo on left, title/subtitle on right - Add numbered setup steps (1, 2, 3) and links bar - Footer styling now matches splash page design 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add logo (80px) top left with header/subheader next to it - Footer grounded to bottom with theme toggle, sponsor, and nav buttons - Remove WelcomePage (splash now goes directly to dependencies) - Match splash page footer dimensions with template footer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move dependency checking from splash transition to dependencies page - Show inline spinner above deps list while checking - Show green success message above deps when all installed - Disable Next button while checking - Trigger check automatically via useEffect on page mount 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add imageBuilt field to DependencyStatus struct to track whether the wails-cross Docker image exists. This allows the OOBE flow to properly detect when Docker is installed but the cross-compilation image hasn't been built yet, and prompt users to set up cross-platform builds. Also moves the Docker build progress indicator to the center of the footer for better visual placement. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add Docker logo asset and updated frontend build output files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive test coverage for the applyGlobalDefaults function
that applies global defaults from ~/.config/wails/defaults.yaml to
init options when creating new projects.
Tests cover:
- Template default application
- Company default application
- Copyright generation with year/company placeholders
- Product identifier generation from prefix
- Description template with {name} placeholder
- Version default application
- Verification that non-default values are not overridden
- Combined defaults application
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move URLs from Message field to HelpURL field on Windows and Darwin so the frontend can render them as clickable links. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…encies On Windows, when software is installed, the PATH environment variable is updated in the registry but running processes still have the old PATH. This adds a refreshPath() function that reads the current PATH from both system and user registry keys before checking for npm and docker. This allows "Check Again" to work without restarting setup. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Show the cross-platform build question regardless of Docker install status. Previously, the page was only shown when Docker was installed but the wails-cross image wasn't built. Now it's shown when: 1. Docker is not installed (user might want to install it), OR 2. Docker is installed but wails-cross image is not built 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace all Docker logo SVGs with official path that includes container boxes - Add "Some platforms may require a reboot" note on Docker install page - Affects: Install Docker, Start Docker, Building image, Docker ready pages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Combine Company and Bundle ID fields into one page called "Projects" in the sidebar. Remove template selection from setup wizard as it's not needed during initial setup. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…page - Fix CheckingPage centering by using justify-start with pt-[30%] padding - Replace h-full with flex-1 for proper flex container sizing - Redesign CompletePage with compact terminal-style command display - Add framework logos (JavaScript, TypeScript, React, Vue, Svelte, etc.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove terminal-style command display from complete page - Remove "Read the documentation" link - Change "Start Building" button to link to first-app quickstart guide - Remove unused CopyableCommand component and handleClose function 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…asses) - Add new wizard step after TypeScript selection for binding style choice - Add UseInterfaces field to GlobalDefaults and pass through to templates - Update Taskfile template to conditionally add -i flag for interfaces - Improve button positioning to match SplashPage layout - Remove "This sets the default template" text from template page - Fix overflow issues when resizing window 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ebar - Move Docker build progress indicator to sidebar (above bottom icons) - Fix light mode text colors in ProjectsPage settings rows - Add light mode CSS variants for settings-group and settings-row - Improve button positioning consistency across pages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update language selection cards with light mode text colors - Update framework/template cards with light mode backgrounds and borders - Use text-gray-900 dark:text-white pattern for proper contrast - Add bg-gray-100 dark:bg-white/5 for unselected card backgrounds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use Docker Engine API for accurate download progress with byte counts - Add SSE streaming for smooth real-time UI updates (replaces polling) - Show toast notification when Docker completes in background mode - Fix progress calculation to use bytes instead of layer count - Fix framework selection border clipping with padding - Pull pre-built image from ghcr.io/wailsapp/wails-cross instead of building locally
- Add lipgloss-based styling (term/styles.go) with Wails brand colors - Update init output to show Framework, Language, Bindings from config - Display '(default)' suffix for values from global config - Add Framework/Language fields to defaults for cleaner config - New minimal banner style: 'Wails v3.x.x › Command'
- Add SigningDefaults to GlobalDefaults for macOS/Windows/Linux signing config - Add signing status section to doctor command with platform detection - Add --json flag to doctor command for machine-readable output - Add /api/signing and /api/signing/status endpoints to setup wizard - Add SigningStep component with platform tabs and status indicators - Wire signing step into wizard flow after projects step The signing step shows detected signing identities from: - macOS: keychain codesigning identities, notarization config - Windows: certificate file/store/cloud, SignTool availability - Linux: GPG keys from keyring or config
- Add Configure button for each platform that opens a form - Add configuration forms for macOS (identity, team ID, notarization profile) - Add configuration forms for Windows (certificate path, thumbprint, timestamp) - Add configuration forms for Linux (GPG key ID, key path) - Use inline SVGs for platform icons (same as CrossPlatformPage) - Forms save to defaults.yaml via /api/signing endpoint - Include helpful command hints for finding signing identities
- Detect host OS and show platform-appropriate guidance - On Mac: show 'security find-identity' and 'xcrun notarytool' commands - On Linux/Windows: show rcodesign info and P12 certificate path field - Add App Store Connect API fields for cross-platform notarization - Link to Apple docs for API key creation - Disable keychain profile field on non-Mac (not applicable)
… detection - Add user-facing documentation at docs/getting-started/setup.mdx - Remove internal design storyboard (docs/setup-wizard-storyboard.md) - Wire up main `wails3 setup` command in CLI - Add experimental warning with link to feedback issue #4904 - Add "Report Bug" button in wizard sidebar with clipboard template - Fix npm detection on Linux to check PATH, not just package manager - Use term.Warning and term.Hyperlink for styled terminal output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add tip about setup wizard in Dependencies section - Add "Next Steps" section recommending `wails3 setup` - Keep manual installation as fallback option - Link to setup guide and feedback issue Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add setup step to quickstart code blocks on home page - Add setup to TL;DR section in quick-start/installation - Add new step 4 "Run Setup Wizard" with experimental warning - Link to feedback issue #4904 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Morphs "desktop" to "server" in the hero tagline - 4 transition types: fade, blur, scale, slide - Random transition selection - Random interval 3-5 seconds - Fixed width to prevent layout shift - Slow 0.8s transitions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add MorphText component for animated title text morphing - Title morphs between "Desktop" and "Server" with fade/blur/scale effects - Add humorous footnote to "No browsers*" tagline - Add Vite alias for component imports in MDX - Clean up UNRELEASED_CHANGELOG to only show setup wizard changes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
WalkthroughAdds an interactive v3 setup wizard (backend + frontend) with Docker image inspection and SSE progress, cross-platform code-signing detection/config endpoints, doctor JSON output, new defaults/template options (including UseInterfaces), TypeScript bindings flag, expanded docs, and homepage UI updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User (CLI / Frontend)
participant Frontend as Setup Frontend
participant Backend as Setup Backend
participant Docker as Docker Daemon
participant Defaults as Global Defaults
participant Doctor as Doctor Service
User->>Frontend: open wizard / interact
Frontend->>Backend: GET /api/docker/status/stream (SSE)
Backend->>Docker: inspect image / trigger pull
Docker-->>Backend: layer progress events
Backend->>Frontend: SSE events (DockerStatus with pullProgress, bytes)
Frontend->>Backend: GET /api/signing/status & GET /api/signing
Backend->>Defaults: read signing defaults
Frontend->>Backend: POST /api/signing (save)
Frontend->>Backend: request doctor status (json flag)
Backend->>Doctor: doctor.Run(jsonOutput bool)
Backend-->>Frontend: aggregated status (JSON or rendered)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying wails with
|
| Latest commit: |
bc76ca9
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://aba999e8.wails.pages.dev |
| Branch Preview URL: | https://v3-feature-setup.wails.pages.dev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
v3/internal/setupwizard/frontend/src/api.ts (1)
5-8: Missing error handling for failed HTTP responses.The
getStatefunction (and most other fetch calls in this file) doesn't checkresponse.okbefore callingresponse.json(). If the server returns a 4xx/5xx error, this will either throw an unhelpful JSON parse error or silently return error response body as data.Suggested fix pattern for all fetch calls
export async function getState(): Promise<WizardState> { const response = await fetch(`${API_BASE}/state`); + if (!response.ok) { + throw new Error(`Failed to get state: ${response.status} ${response.statusText}`); + } return response.json(); }Apply this pattern to all fetch-based functions in this file.
v3/internal/setupwizard/wizard.go (1)
1263-1304: Security concern: handleInstallDependency executes arbitrary commands.This endpoint executes any command passed in the request body (line 1288). While it appears to be intended for installing dependencies, there's no validation of the command. A malicious actor with access to the local wizard server could execute arbitrary commands.
Consider:
- Validating commands against an allowlist of known install commands
- Adding a warning in documentation that the wizard should only be run locally
- Restricting the server to localhost only (which appears to be done at line 269)
Since this binds to
127.0.0.1only, the risk is limited to local attacks, but it's worth documenting this security consideration.v3/internal/setupwizard/wizard_darwin.go (1)
101-134: Add a clarifying comment to Darwin's npm dependency configuration to match Linux's rationale.npm is marked
Required: trueon Darwin (line 104) and Windows, butRequired: falseon Linux with a comment explaining "Optional - not strictly required for Go-only projects." For consistency and clarity, add a similar comment to the Darwin configuration explaining why npm is required on this platform, or conversely, document the platform-specific rationale if the requirements differ.
🤖 Fix all issues with AI agents
In `@docs/astro.config.mjs`:
- Around line 15-20: The vite.resolve.alias entry for '@components' uses a
relative string ("/src/components") which can fail; update the alias value to an
absolute filesystem path (for example build it with path.resolve or new
URL('./src/components', import.meta.url).pathname) so Vite can resolve it
reliably; ensure to import 'path' if you use path.resolve or use the URL
approach without extra imports, and as an alternative consider moving the alias
to tsconfig.json/jsconfig.json for editor/tooling alignment.
In `@docs/src/content/docs/index.mdx`:
- Line 9: The tagline line contains a trailing asterisk "No browsers.*" with no
footnote; update the tagline string to use a proper footnote marker (e.g.,
replace the trailing "*" with "[^no-browsers]") and add a matching footnote
entry near the end of the document (e.g., "[^no-browsers]: Uses the system's
built-in WebView rather than bundling a browser engine") so readers see the
clarification; ensure the marker text matches exactly and that the new footnote
is valid MDX/Markdown syntax in index.mdx.
In `@TODO.md`:
- Around line 333-345: Update the three fenced code blocks in TODO.md that show
directory trees to include a language identifier to satisfy markdownlint MD040:
change the opening fences for the block containing the "artifacts/" tree (the
block that starts with "artifacts/"), the block containing "dist/", and the
final block containing "v3/" so they read ```text instead of ```; ensure only
the opening backticks are modified and the content remains unchanged.
In `@v3/build/docker/Dockerfile.darwin-cross`:
- Around line 12-18: The Alpine image must include a glibc-compat package so the
glibc-linked Zig binary (downloaded using ARG ZIG_VERSION and invoked via
zig/zig cc in the wrapper scripts) can run; update the RUN that installs
packages (the line that currently installs curl xz nodejs npm) to also install
either gcompat or libc6-compat (e.g., add gcompat) so zig binaries execute
successfully at runtime and wrapper scripts calling zig cc will not fail.
- Around line 28-47: This Dockerfile uses heredoc-style COPY (COPY <<'ZIGWRAP')
which requires BuildKit; add the BuildKit frontend syntax directive as the very
first line in the Dockerfile (before any comments or instructions) by inserting
"# syntax=docker/dockerfile:1.6" at the top so the COPY <<'ZIGWRAP' blocks (and
other heredocs) like the one that creates /usr/local/bin/zcc-darwin-arm64 work
correctly with BuildKit.
In `@v3/internal/commands/init_test.go`:
- Around line 343-364: The test "empty global defaults do not change options"
has a misleading name because the code under test normalizes the copyright field
(transforming input "\u00a9 now, My Company" to "© "+currentYear+", My
Company"); update the test to either (A) rename the case to reflect that
copyright is normalized (e.g., "empty global defaults normalize copyright to
current year") OR (B) if the intended behavior is to preserve the original
string, change wantOptions.ProductCopyright to match the original input value
"\u00a9 now, My Company" so the expectation matches the intended behavior;
adjust the test case name or wantOptions.ProductCopyright in the test struct
accordingly (refer to the test case name string and the flags.Init struct fields
TemplateName/ProductCompany/ProductCopyright/ProductIdentifier/ProductDescription/ProductVersion/ProjectName).
In `@v3/internal/commands/init.go`:
- Around line 128-131: In applyGlobalDefaults, don't unconditionally overwrite
options.UseInterfaces; instead mirror the other fields' pattern by only
assigning options.UseInterfaces = globalDefaults.Project.UseInterfaces and
setting options.UseInterfacesFromDefaults = true when the current
options.UseInterfaces still equals its default/sentinel value (i.e., only when
the user hasn't explicitly set the flag). Update the guard around UseInterfaces
to check the same default condition used elsewhere in applyGlobalDefaults and
then set UseInterfacesFromDefaults inside that conditional, referencing
options.UseInterfaces, options.UseInterfacesFromDefaults, and
globalDefaults.Project.UseInterfaces.
In `@v3/internal/doctor/signing.go`:
- Around line 40-48: CheckSigning currently discards the error from
defaults.Load(); modify it to capture the error (e.g., globalDefaults, err :=
defaults.Load()) and if err != nil emit a clear warning that the defaults file
couldn’t be loaded (include err details) before continuing to build the
SigningStatus. Keep using the existing fall-back behavior (call
checkDarwinSigning, checkWindowsSigning, checkLinuxSigning with globalDefaults)
but ensure the logged warning surfaces parsing/permission failures so users know
their config wasn’t applied.
In `@v3/internal/setupwizard/docker/Dockerfile.cross`:
- Around line 15-20: The Dockerfile.cross currently downloads the glibc-built
Zig tarball (using ZIG_VERSION) which fails on Alpine/musl; replace the manual
curl+tar install with the Alpine-packaged zig from the community repo (install
via apk add zig and ensure the community repo is enabled or pin the package
version), or if you must keep the upstream tarball, install the gcompat
compatibility shim via apk add gcompat before extracting to provide the missing
ld-linux-x86-64.so.2; update the RUN that references ZIG_VERSION and the symlink
step (ln -s ... /usr/local/bin/zig) accordingly so wrappers using zig cc work on
musl.
- Around line 29-47: The Dockerfile uses heredoc-style COPY directives (e.g.,
the COPY <<'ZIGWRAP' block that creates the zcc-darwin-arm64 wrapper) which
require BuildKit; add the BuildKit syntax directive as the very first line of
the Dockerfile (e.g., # syntax=docker/dockerfile:1) so heredocs parse correctly
and hadolint DL1000 is avoided; ensure this directive appears before any
FROM/COPY instructions and commit the change to the Dockerfile.cross containing
the zcc-darwin-arm64 wrapper blocks.
In `@v3/internal/setupwizard/frontend/src/components/SigningStep.tsx`:
- Around line 52-64: The save handler handleSave currently only logs errors to
the console and leaves users uninformed; update handleSave to surface save
failures to the UI by using the existing notification or error state approach
(e.g., call the app's toast/alert function or set an error state that the
component renders) when saveSigning(config) throws, while keeping the existing
setSaving(false) in finally; ensure you still call loadData() and
setConfiguring(false) only on success and reference the same symbols
(handleSave, saveSigning, loadData, setConfiguring, setSaving, config) so the UI
displays a clear error message when saving fails.
- Around line 45-50: The catch block in loadData currently only logs the error
to console; update it to call setError(error) (or setError(e)) so the component
tracks the failure, keep setLoading(false) in finally, and ensure the
SigningStep component renders a visible error state when the error state is set
(e.g., show a user-facing message or retry button), referencing the loadData
function, the setLoading and setError state setters, and the error state
variable so the UI reflects failures instead of silently failing.
In `@v3/internal/setupwizard/wizard_windows.go`:
- Around line 15-48: The refreshPath function currently reads PATH values from
the registry and writes them directly, which can leave unexpanded environment
variables; update refreshPath so that after retrieving systemPath and userPath
from registry.GetStringValue you call registry.ExpandString on each (handling
and logging any ExpandString error) and then split the expanded result into path
entries, trimming and deduplicating as before; ensure both places that read
"Path" (the system and user blocks) use registry.ExpandString before
strings.Split and still close the registry keys.
In `@v3/internal/setupwizard/wizard.go`:
- Around line 773-778: In the block that calls decoder.Decode(&event) replace
the fragile string comparison err.Error() == "EOF" with a proper EOF check using
errors.Is(err, io.EOF); update the surrounding logic to break only on io.EOF and
handle other errors accordingly, and add the necessary imports (errors and io)
or reference them if already present so the code uses errors.Is(err, io.EOF)
instead of comparing the error string.
- Around line 1168-1184: The temporary SDK file (tmpFile/tmpPath) is left on
disk because it is closed but never removed; change the flow so the temp file is
deleted after the local Docker build has finished copying it: either (A) make
startDockerBuildLocal accept the path and perform the copy synchronously (or
return only once its internal copy is complete) and then call os.Remove(tmpPath)
after w.startDockerBuildLocal(tmpPath) returns, or (B) have
startDockerBuildLocal signal completion (e.g. return an error or channel) and
delete tmpPath in the caller once the signal is received; reference
tmpFile/tmpPath in the handler and the startDockerBuildLocal function to locate
and implement the cleanup.
In `@v3/internal/term/styles.go`:
- Around line 76-89: The RenderTable function currently indexes row[0] and
row[1] without checking row length which can panic for short rows; update
RenderTable to guard each row (in the loops that compute maxKeyLen and build
output) by checking len(row) >= 2 and either skip rows that are too short or
treat missing cells as empty strings (e.g., treat key/val as "" when len < 1 or
< 2 respectively); ensure you still call padRight and MutedStyle.Render only
with a safe key string and write a sensible line to the strings.Builder for rows
with missing values.
In `@v3/internal/term/term.go`:
- Around line 14-22: The Header function currently uses fmt.Println which
bypasses pterm's output suppression; update Header to use pterm.Println instead
of fmt.Println so headers respect pterm.DisableOutput (keep the same brandStyle
and mutedStyle rendering and string concatenation), and add or adjust the
imports to include the pterm package; refer to the Header function and its
brandStyle/mutedStyle variables when making the change.
🧹 Nitpick comments (18)
v3/internal/defaults/defaults.go (1)
21-77:omitemptywon’t omit non-pointer signing structs.Struct fields are never “empty” for
omitempty, sosigning(anddarwin/windows/linux) will serialize as{}even when unset. If you intend truly optional signing defaults, consider pointers (or a custom marshal).♻️ Suggested refactor (requires nil checks at call sites)
type GlobalDefaults struct { // Author information Author AuthorDefaults `json:"author" yaml:"author"` // Default project settings Project ProjectDefaults `json:"project" yaml:"project"` // Code signing configuration (optional) - Signing SigningDefaults `json:"signing,omitempty" yaml:"signing,omitempty"` + Signing *SigningDefaults `json:"signing,omitempty" yaml:"signing,omitempty"` } // SigningDefaults contains code signing configuration for all platforms type SigningDefaults struct { - Darwin DarwinSigningDefaults `json:"darwin,omitempty" yaml:"darwin,omitempty"` - Windows WindowsSigningDefaults `json:"windows,omitempty" yaml:"windows,omitempty"` - Linux LinuxSigningDefaults `json:"linux,omitempty" yaml:"linux,omitempty"` + Darwin *DarwinSigningDefaults `json:"darwin,omitempty" yaml:"darwin,omitempty"` + Windows *WindowsSigningDefaults `json:"windows,omitempty" yaml:"windows,omitempty"` + Linux *LinuxSigningDefaults `json:"linux,omitempty" yaml:"linux,omitempty"` }v3/internal/commands/init_test.go (1)
372-390: Consider usingreflect.DeepEqualorcmp.Difffor more maintainable struct comparison.Individual field assertions work but can become hard to maintain as
flags.Initgrows. Usingreflect.DeepEqualorgithub.com/google/go-cmp/cmpwould automatically catch new fields.Also, based on the AI summary,
UseInterfaceswas added toflags.Initbut isn't tested here. Consider adding test coverage for this field.Example using cmp.Diff
+import "github.com/google/go-cmp/cmp" + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { options := tt.options applyGlobalDefaults(&options, tt.globalDefaults) - - if options.TemplateName != tt.wantOptions.TemplateName { - t.Errorf("TemplateName = %q, want %q", options.TemplateName, tt.wantOptions.TemplateName) - } - // ... other field checks + if diff := cmp.Diff(tt.wantOptions, options); diff != "" { + t.Errorf("applyGlobalDefaults() mismatch (-want +got):\n%s", diff) + } }) }v3/internal/setupwizard/frontend/src/api.ts (2)
38-44: Consider adding exponential backoff for SSE reconnection.The current implementation retries with a fixed 1-second delay on error. If the server is temporarily unavailable, this could result in rapid reconnection attempts. Consider implementing exponential backoff or a maximum retry limit.
Example with exponential backoff
export function subscribeDockerStatus(onUpdate: (status: DockerStatus) => void): () => void { let eventSource: EventSource | null = null; let closed = false; + let retryDelay = 1000; + const maxRetryDelay = 30000; const connect = () => { if (closed) return; + retryDelay = 1000; // Reset on new connection attempt eventSource = new EventSource(`${API_BASE}/docker/status/stream`); eventSource.onmessage = (event) => { // ... }; eventSource.onerror = () => { eventSource?.close(); if (!closed) { - setTimeout(connect, 1000); + setTimeout(connect, retryDelay); + retryDelay = Math.min(retryDelay * 2, maxRetryDelay); } }; };
162-165:reportBuguses GET for an action that may have side effects.Using GET for
reportBugis semantically incorrect if this endpoint creates an issue or performs any server-side mutation. GET requests should be idempotent and safe. Consider using POST if this triggers any action.v3/internal/setupwizard/frontend/src/components/SigningStep.tsx (2)
279-288: Timestamp server default is duplicated between frontend and backend.The default value
'http://timestamp.digicert.com'is hardcoded here and also inv3/internal/doctor/signing.go(line 96). Consider either:
- Having the backend always return the default in the config response, or
- Defining a shared constant
This prevents inconsistency if one is updated without the other.
453-475: Tab accessibility could be improved witharia-controls.The tabs have
role="tab"andaria-selected, but are missingaria-controlsto link to the correspondingtabpanel. The tabpanel (line 510) also lacks anid.Suggested improvement
<PlatformTab platform="darwin" label="macOS" isActive={selectedPlatform === 'darwin'} hasConfig={status?.darwin.hasIdentity} onClick={() => { setSelectedPlatform('darwin'); setConfiguring(false); }} + ariaControls="signing-tabpanel" /> // ... other tabs <motion.div key="status" // ... role="tabpanel" + id="signing-tabpanel" + aria-labelledby={`tab-${selectedPlatform}`} >v3/internal/doctor/signing.go (2)
128-153: Identity filtering may be too restrictive.The function only captures identities containing
"Developer ID"(line 142). This excludes other valid signing identities like "Apple Distribution" or "3rd Party Mac Developer Application" that users might want to use for App Store distribution.Consider making this configurable or capturing all valid codesigning identities:
for _, line := range lines { - if strings.Contains(line, "\"") && strings.Contains(line, "Developer ID") { + if strings.Contains(line, "\"") && !strings.Contains(line, "CSSMERR") { start := strings.Index(line, "\"") end := strings.LastIndex(line, "\"") if start != -1 && end > start { identity := line[start+1 : end] identities = append(identities, identity) } } }Or filter by valid prefixes:
Developer ID,Apple Distribution,3rd Party Mac Developer.
155-178: GPG output parsing is fragile and may break with different GPG versions.The function parses
gpg --list-secret-keysoutput by looking for lines containing "sec" and then splitting on "/". This format can vary between GPG versions. Consider using--with-colonsfor machine-readable output.More robust parsing approach
func getDefaultGPGKey() string { - cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long") + cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long", "--with-colons") output, err := cmd.Output() if err != nil { return "" } lines := strings.Split(string(output), "\n") for _, line := range lines { - if strings.Contains(line, "sec") { - parts := strings.Fields(line) - for _, part := range parts { - if strings.Contains(part, "/") { - keyParts := strings.Split(part, "/") - if len(keyParts) > 1 { - return keyParts[1] - } - } - } + // With --with-colons, secret key lines start with "sec:" + // Format: sec:validity:keysize:algo:keyid:created:expires:... + if strings.HasPrefix(line, "sec:") { + fields := strings.Split(line, ":") + if len(fields) > 4 { + return fields[4] // Key ID is the 5th field + } } } return "" }docs/src/content/docs/getting-started/setup.mdx (1)
42-42: Consider clarifying the config path for Windows users.The config path
~/.config/wails/config.yamlis Linux/macOS-specific. On Windows, the path would typically be different (e.g.,%APPDATA%\wails\config.yamlor similar). Consider noting the platform-specific paths or using a more generic description like "saved to your user configuration directory."v3/internal/setupwizard/pull_parser_test.go (2)
8-29: LGTM!Good table-driven test for
parseSizecovering:
- Various units (B, KB, MB, GB)
- Decimal values (1.5MB)
- Raw numbers without units
Consider adding edge cases for invalid inputs or empty strings if the parser should handle those gracefully.
138-171: Testing internal state (parser.layerSizes) couples test to implementation.Line 164 accesses
parser.layerSizesdirectly, which is an internal field. This makes the test brittle to refactoring. Consider testing observable behavior (progress values, stages) rather than internal state, or accept this as an intentional implementation test.v3/internal/setupwizard/wizard_darwin.go (1)
29-65: Consider extracting shared Go version check logic.The
checkGo()function is duplicated acrosswizard_darwin.go,wizard_linux.go, andwizard_windows.gowith minor differences (Linux includesInstallCommand). Consider extracting the common logic to reduce duplication.Also, silently ignoring
strconv.Atoierrors on lines 54-55 could mask malformed version strings. If parsing fails,majorandminordefault to 0, which would incorrectly trigger the "needs_update" condition.Suggested improvement for error handling
versionParts := strings.Split(versionStr, ".") if len(versionParts) >= 2 { - major, _ := strconv.Atoi(versionParts[0]) - minor, _ := strconv.Atoi(versionParts[1]) + major, err1 := strconv.Atoi(versionParts[0]) + minor, err2 := strconv.Atoi(versionParts[1]) + if err1 != nil || err2 != nil { + dep.Message = "Unable to parse Go version" + return dep + } if major < 1 || (major == 1 && minor < 25) {docs/src/components/MorphText.astro (2)
4-9: Fixed width may cause layout issues with different word lengths.The
width: 4.5emmay not accommodate all words in thewordsarray equally. "Desktop" and "Server" have different character counts which could cause text overflow or excessive whitespace.Consider using min-width or measuring the longest word
.morph-word-title { display: inline-block; position: relative; - width: 4.5em; + min-width: 4.5em; text-align: left; }
136-142: Redundant event listener registration.The
init()function is registered for bothDOMContentLoaded(line 137) andload(line 142) events, and also called directly ifdocument.readyStateis not "loading" (line 139). While theinitializedflag prevents duplicate execution, theloadevent listener on line 142 will always fire after the other checks have already runinit().This is harmless but adds unnecessary event listener overhead.
Simplified initialization
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } - - window.addEventListener('load', init); })();v3/internal/setupwizard/wizard_linux.go (1)
62-99: Duplicate checkGo() implementation.This function is nearly identical to the Darwin version. The only difference is the addition of
InstallCommandon line 74. Consider extracting shared logic to a common file (e.g.,wizard_common.gowithout build tags) to reduce maintenance burden. Based on learnings, platform-specific behavior should be controlled via build tags, but shared helpers can live in common files.v3/internal/doctor/doctor.go (1)
164-166: Integer division may lose precision for memory reporting.The calculation
memory.TotalPhysicalBytes/1024/1024/1024performs integer division which could show "15GB" for systems with 15.5GB. Consider using floating-point for more accurate reporting.Optional: More precise memory reporting
memory, _ := ghw.Memory() if memory != nil { - report.System.Memory = strconv.Itoa(int(memory.TotalPhysicalBytes/1024/1024/1024)) + "GB" + memGB := float64(memory.TotalPhysicalBytes) / (1024 * 1024 * 1024) + report.System.Memory = fmt.Sprintf("%.1f GB", memGB) } else if runtime.GOOS == "darwin" {v3/internal/setupwizard/wizard.go (2)
1509-1534: macOS signing identity detection is limited to "Developer ID" certificates.The
getMacOSSigningIdentitiesfunction only captures identities containing "Developer ID" (line 1523). This excludes other valid signing identities like "Apple Development" or "Apple Distribution" certificates that developers might use.Consider broader certificate matching
for _, line := range lines { - if strings.Contains(line, "\"") && strings.Contains(line, "Developer ID") { + if strings.Contains(line, "\"") && (strings.Contains(line, "Developer ID") || strings.Contains(line, "Apple Development") || strings.Contains(line, "Apple Distribution")) { start := strings.Index(line, "\"")
1536-1559: GPG key parsing is fragile.The
getDefaultGPGKeyfunction parsesgpg --list-secret-keysoutput by looking for lines containing "sec" and splitting on "/". This assumes a specific output format that may vary across GPG versions.Consider using
--with-colonsfor machine-parseable output:More robust GPG key detection
func getDefaultGPGKey() string { - cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long") + cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long", "--with-colons") output, err := cmd.Output() if err != nil { return "" } lines := strings.Split(string(output), "\n") for _, line := range lines { - if strings.Contains(line, "sec") { - parts := strings.Fields(line) - for _, part := range parts { - if strings.Contains(part, "/") { - keyParts := strings.Split(part, "/") - if len(keyParts) > 1 { - return keyParts[1] - } - } - } + if strings.HasPrefix(line, "sec:") { + fields := strings.Split(line, ":") + if len(fields) > 4 { + return fields[4] // Key ID is in field 5 (0-indexed: 4) + } } }
- Use fileURLToPath for Vite alias in astro.config.mjs - Add gcompat to Alpine Dockerfiles for Zig glibc compatibility - Add conditional check for UseInterfaces in applyGlobalDefaults - Expand REG_EXPAND_SZ registry values in Windows PATH refresh - Route Header/Section output through pterm to honor DisableOutput Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addressed CodeRabbit Review FeedbackFixed all major issues in commit a2e93de:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@v3/build/docker/Dockerfile.darwin-cross`:
- Around line 15-24: The Dockerfile downloads Zig and the macOS SDK without
verifying integrity; add SHA256 checksum checks after each download and fail the
build on mismatch. For the Zig step (ARG ZIG_VERSION and the RUN that fetches
zig-linux-x86_64-${ZIG_VERSION}.tar.xz and creates /usr/local/bin/zig) introduce
a corresponding expected checksum variable (e.g., ZIG_SHA256) and verify the
streamed or saved tar.xz with sha256sum (or openssl dgst -sha256) before
extracting and linking, exiting non‑zero if it doesn't match. Do the same for
the macOS SDK step (ARG MACOS_SDK_VERSION and the RUN that downloads
MacOSX${MACOS_SDK_VERSION}.sdk.tar.xz and moves /opt/macos-sdk) using a
MACOS_SDK_SHA256 variable and checksum verification prior to tar
extraction/move. Ensure the checksum values match the provided hashes and that
failures stop the build.
In `@v3/internal/setupwizard/docker/Dockerfile.cross`:
- Around line 17-25: Download Zig to a temporary file instead of piping to tar
and validate its SHA256 against a build ARG (e.g., ZIG_SHA256) before extracting
to /opt and symlinking the zig binary; update the Dockerfile CROSS steps that
reference ZIG_VERSION to use curl -o /tmp/zig.tar.xz then verify with sha256sum
(or shasum -a 256) and exit nonzero on mismatch, then extract and ln -s.
Separately, confirm that the macOS SDK release referenced by MACOS_SDK_VERSION
exists and is publicly accessible in the wailsapp/macosx-sdks repo before
attempting the curl for MacOSX${MACOS_SDK_VERSION}.sdk.tar.xz (or add a
pre-check step/ARG to skip or fail early), and keep the existing retry logic for
the SDK download.
In `@v3/internal/setupwizard/wizard_windows.go`:
- Around line 106-116: The version parsing silently ignores strconv.Atoi errors
causing invalid "needs_update" for versions like "go1.25beta1"; update the logic
in the block that splits versionStr into versionParts to check and handle errors
from strconv.Atoi for both major and minor (the variables currently assigned
with `_`), e.g., if atoi returns an error either try a numeric-only extraction
(regex) or treat the parse as indeterminate and do not set
dep.Status="needs_update"; also log or attach the parse error to dep.Message so
malformed/unexpected version strings don't incorrectly mark an install as
needing update.
- Around line 93-94: Update the Go version check and user message in the setup
wizard so it requires Go 1.21 instead of 1.25: locate the version-check
conditional that reads if major < 1 || (major == 1 && minor < 25) and change it
to if major < 1 || (major == 1 && minor < 21); also update the user-facing
dep.Message from "Go 1.25+ is required" to "Go 1.21+ is required" (keep
dep.HelpURL as-is). Apply the same edits wherever this logic appears
(wizard_windows.go, wizard_linux.go, wizard_darwin.go) so the checks and
messages are consistent.
♻️ Duplicate comments (2)
v3/build/docker/Dockerfile.darwin-cross (1)
29-46: Add Dockerfile frontend syntax directive for heredoc support.Heredoc
COPY <<'ZIGWRAP'requires the BuildKit frontend; without# syntax=..., legacy builders (and linters) will fail to parse the file.🔧 Suggested fix
+# syntax=docker/dockerfile:1.6 # Cross-compile Wails v3 apps to macOS from Linuxv3/internal/setupwizard/docker/Dockerfile.cross (1)
1-1: Add Dockerfile syntax directive to ensure heredoc parsing.Line 1:
COPY <<'ZIGWRAP'heredocs later in this file require the Dockerfile frontend syntax directive; without it, non‑BuildKit builders and hadolint can fail parsing (DL1000).✅ Proposed fix
+# syntax=docker/dockerfile:1 FROM golang:1.25-alpine
🧹 Nitpick comments (3)
v3/internal/setupwizard/wizard_windows.go (1)
22-33: Consider usingdeferfor registry key cleanup.If a panic occurs between
OpenKeyandClose, the key handle would leak. Usingdeferensures cleanup regardless of control flow.♻️ Suggested improvement
if key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Session Manager\Environment`, registry.QUERY_VALUE); err == nil { + defer key.Close() if systemPath, valType, err := key.GetStringValue("Path"); err == nil { // Expand environment variables if the value is REG_EXPAND_SZ if valType == registry.EXPAND_SZ { if expanded, err := registry.ExpandString(systemPath); err == nil { systemPath = expanded } } paths = append(paths, strings.Split(systemPath, ";")...) } - key.Close() }Apply the same pattern to the user PATH block (lines 36-47).
v3/internal/setupwizard/docker/Dockerfile.cross (2)
170-172: Prefernpm ciwhen a lockfile exists.Line 170-172:
npm installcan drift across runs. Considernpm ciwhenpackage-lock.jsonis present for repeatable container builds.♻️ Suggested tweak
-if [ -d "frontend" ] && [ -f "frontend/package.json" ] && [ ! -d "frontend/dist" ]; then - (cd frontend && npm install --silent && npm run build --silent) +if [ -d "frontend" ] && [ -f "frontend/package.json" ] && [ ! -d "frontend/dist" ]; then + if [ -f "frontend/package-lock.json" ]; then + (cd frontend && npm ci --silent && npm run build --silent) + else + (cd frontend && npm install --silent && npm run build --silent) + fi fi
175-186: Quote paths to avoid word-splitting.Line 175-186: unquoted
$(pwd)/$APPcan break if the repo path or app name contains spaces.🛠️ Safe quoting
-APP=${APP_NAME:-$(basename $(pwd))} +APP=${APP_NAME:-$(basename "$PWD")} @@ -go build -ldflags="$LDFLAGS" -o bin/${APP}-${GOOS}-${GOARCH}${EXT} . -echo "Built: bin/${APP}-${GOOS}-${GOARCH}${EXT}" +go build -ldflags="$LDFLAGS" -o "bin/${APP}-${GOOS}-${GOARCH}${EXT}" . +echo "Built: bin/${APP}-${GOOS}-${GOARCH}${EXT}"
- Add BuildKit syntax directive to Dockerfiles for heredoc support - Log warning when defaults.Load() fails in signing check - Use errors.Is(err, io.EOF) instead of string comparison - Clean up temp SDK file after Docker build copies it - Guard against short/empty rows in RenderTable to prevent panics Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace "Use local file" upload with "Build your own" docs link - Remove handleDockerBuildWithSDK endpoint and startDockerBuildLocal - Remove embedded Dockerfile.cross files (now documented inline) - Add comprehensive "Build Your Own Image" documentation section - Clean up unused imports (bufio, strconv) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/wizard.go`:
- Around line 700-719: startDockerPull currently only resets PullStatus,
PullProgress and PullMessage, leaving prior error/metrics (e.g., PullError,
PullCompleted, PullBytes, PullStartedAt) which causes stale UI state; update
startDockerPull (while holding w.dockerMu) to explicitly clear prior error and
metric fields such as w.dockerStatus.PullError = "" (or nil),
w.dockerStatus.PullCompleted = false, w.dockerStatus.PullBytes = 0 and
optionally set w.dockerStatus.PullStartedAt = time.Now() before unlocking; keep
the existing flow that calls w.pullViaDockerAPI() and falls back to
w.pullViaDockerCLI().
- Around line 493-515: The shutdown channel is closed unconditionally in
Wizard.handleClose which can panic if /api/close is called multiple times; add a
guard (e.g., a sync.Once field on Wizard, or an atomic bool) and use it to
ensure close(w.shutdown) is only called once inside the goroutine that waits on
w.buildWg; update Wizard struct to include the guard (e.g., shutdownOnce
sync.Once) and replace the direct close(w.shutdown) call with
shutdownOnce.Do(func(){ close(w.shutdown) }) while keeping the existing docker
status check (w.dockerMu and dockerStatus.PullStatus) and build wait
(w.buildWg.Wait()) logic.
♻️ Duplicate comments (1)
v3/internal/setupwizard/wizard.go (1)
721-889: Treat non-EOF decode errors as failures (avoid false “complete”).
If decoding fails for reasons other than EOF, the loop breaks and the code later marks the pull as complete. This can report success on a broken stream and skip CLI fallback.🐛 Proposed fix
for { var event dockerPullEvent if err := decoder.Decode(&event); err != nil { if errors.Is(err, io.EOF) { break } - break + w.dockerMu.Lock() + w.dockerStatus.PullStatus = "error" + w.dockerStatus.PullError = fmt.Sprintf("Docker API stream decode failed: %v", err) + w.dockerStatus.PullMessage = "Failed" + w.dockerBuildLogs = logs.String() + w.dockerMu.Unlock() + return fmt.Errorf("docker API stream decode failed: %w", err) }
🧹 Nitpick comments (4)
docs/src/content/docs/guides/build/cross-platform.mdx (3)
370-370: Quote command substitution to handle paths with spaces.The
$(pwd)should be quoted to prevent word splitting if the working directory path contains spaces.Suggested fix
-APP=${APP_NAME:-$(basename $(pwd))} +APP=${APP_NAME:-$(basename "$(pwd)")}
412-418: Consider noting that the SDK version in the example should match your actual SDK.The example uses a hardcoded
MacOSX14.5.sdkpath. Users copying this snippet with a different SDK version might miss updating both the filename and themvcommand. A brief note could prevent confusion.Suggested clarification
```dockerfile # Replace the curl/tar SDK download section with: +# Note: Update the version numbers below to match your SDK (e.g., 14.5, 15.0) COPY MacOSX14.5.sdk.tar.xz /tmp/sdk.tar.xz RUN tar -xJf /tmp/sdk.tar.xz -C /opt \ && mv /opt/MacOSX14.5.sdk /opt/macos-sdk \ && rm /tmp/sdk.tar.xz</details> --- `196-199`: **Consider updating to newer stable versions.** The Dockerfile references `golang:1.24-alpine` and `ZIG_VERSION=0.14.0`. While both versions are valid and released, newer stable versions are available: Go 1.25.5 and Zig 0.15.2. Updating to the latest stable versions would provide access to recent bug fixes, performance improvements, and security updates. </blockquote></details> <details> <summary>v3/internal/setupwizard/wizard.go (1)</summary><blockquote> `592-597`: **Consider removing wildcard CORS for the SSE endpoint.** Unless cross-origin access is required, dropping or restricting `Access-Control-Allow-Origin: *` reduces exposure of local status data. <details> <summary>♻️ Suggested tweak</summary> ```diff - rw.Header().Set("Access-Control-Allow-Origin", "*")
- Add docker-options intermediate step with two choices: - "Download official image" (red outline) → SDK license → download - "Build your own image" (gray outline) → opens docs in new tab - Update SDK license page to match other pages (back button at bottom) - Add Wails favicon to wizard - Fix shutdown channel panic on repeated /api/close (sync.Once guard) - Fix Go version parsing for beta/rc versions like go1.25beta1 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Clear PullError, BytesTotal, BytesDone, LayerCount, LayersDone, and dockerBuildLogs when starting a new Docker pull to prevent stale UI state. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/wizard_windows.go`:
- Around line 238-250: The platform-specific check in wizard_windows.go uses the
hardcoded image name "wails-cross" instead of the shared constant
crossImageName; update the Docker image inspection call that invokes
execCommand("docker", "image", "inspect", "wails-cross") to use the shared
crossImageName constant so the image lookup matches the pulled registry name,
leaving the rest of the dep status logic (dep.Installed, dep.ImageBuilt,
dep.Message) unchanged.
In `@v3/internal/setupwizard/wizard.go`:
- Around line 775-783: The loop decoding dockerPullEvent treats any non-EOF
decode error as success by breaking; update the loop in wizard.go so that when
decoder.Decode(&event) returns a non-nil error that is not io.EOF you return
that error (or otherwise mark the pull as failed) instead of just breaking.
Locate the for loop that uses decoder and dockerPullEvent and change the error
branch to propagate an error (or set a failure state) so the caller of the pull
routine (the surrounding function that currently marks the pull complete) can
detect and handle the failure rather than reporting success.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use shared crossImageName constant in platform-specific wizard files - Return error on non-EOF decode failures to trigger CLI fallback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add public/ to .gitignore (dist/ already contains copied files) - Remove unused showcase images (only montage.png is used) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
v3/internal/setupwizard/wizard.go (1)
1091-1131: Arbitrary command execution in handleInstallDependency.The endpoint executes arbitrary commands from the request body. While this is a local-only wizard, consider validating the command against an allowlist or at least documenting the security implications.
Consider adding command validation
func (w *Wizard) handleInstallDependency(rw http.ResponseWriter, r *http.Request) { + // Security note: This wizard runs locally and executes user-provided commands. + // In a production scenario, commands should be validated against an allowlist. if r.Method != http.MethodPost { http.Error(rw, "Method not allowed", http.StatusMethodNotAllowed) return } + + // Optionally validate against known install commands + allowedPrefixes := []string{"apt", "dnf", "brew", "pacman", "winget", "choco"} + // ... validation logic
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/frontend/.gitignore`:
- Line 1: Remove the stale `public/` entry from the frontend `.gitignore` and
either leave the file empty (if `dist/` is to be committed) or replace `public/`
with `dist/` so that the Vite build output and Go embed reference (`dist/`) are
ignored consistently; update the `.gitignore` entry accordingly to match the
project convention used in v2.
In `@v3/internal/setupwizard/wizard_linux.go`:
- Around line 62-99: The Linux checkGo function parses versionStr and splits
into versionParts then converts parts to integers, but unlike the Windows
implementation it fails on pre-release strings like "go1.25beta1"; update
checkGo to normalize versionStr the same way as Windows by stripping non-numeric
suffixes from the minor (and patch) component before Atoi (or use a regex to
capture major/minor digits), so versionParts -> major/minor parsing in checkGo
correctly handles beta/rc builds and sets dep.Status/dep.Message consistently.
In `@v3/internal/setupwizard/wizard.go`:
- Around line 1249-1257: checkSigningStatus currently discards the error from
LoadGlobalDefaults(), causing misleading results; update checkSigningStatus to
handle the error from LoadGlobalDefaults() instead of ignoring it: call
LoadGlobalDefaults() and if it returns an error either return a signed error
result (change signature to return (signingStatusResponse, error)) or
log/propagate the error before calling checkDarwinSigningStatus,
checkWindowsSigningStatus, and checkLinuxSigningStatus so they don't run with a
zero-valued globalDefaults; reference checkSigningStatus, LoadGlobalDefaults,
signingStatusResponse, checkDarwinSigningStatus, checkWindowsSigningStatus, and
checkLinuxSigningStatus when making the change.
🧹 Nitpick comments (3)
v3/internal/setupwizard/wizard_windows.go (1)
192-195: Silentstrconv.Atoierror in npm version parsing.The error from
strconv.Atoiis ignored. While this is unlikely to cause issues in practice (npm versions are typically numeric), it's inconsistent with the more robust error handling incheckGo.Consider handling parse errors consistently
parts := strings.Split(version, ".") if len(parts) > 0 { - major, _ := strconv.Atoi(parts[0]) + major, err := strconv.Atoi(parts[0]) + if err != nil { + // Couldn't parse version; assume it's acceptable + dep.Installed = true + dep.Status = "installed" + return dep + } if major < 7 {v3/internal/setupwizard/wizard.go (2)
329-332: Consider adding error handling for PDF write.The
rw.Write(appleLicensePDF)error is ignored. While unlikely to fail, this is inconsistent with good practice.Handle write error
mux.HandleFunc("/assets/apple-sdk-license.pdf", func(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/pdf") - rw.Write(appleLicensePDF) + if _, err := rw.Write(appleLicensePDF); err != nil { + // Client disconnected; nothing to do + return + } })
985-996: Remove the unusedformatBytesfunction.The
formatBytesfunction is defined but never called in the codebase. OnlyformatBytesMBis actively used.
- Fix .gitignore: track public/ (source), ignore dist/ (build output) - Apply beta/rc Go version parsing fix to Linux and Darwin - Surface LoadGlobalDefaults error in signing status response Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/wizard.go`:
- Around line 985-996: The function formatBytes is dead code (never referenced;
only formatBytesMB is used) — remove the unused function formatBytes to
eliminate dead code, or if you intend to keep it for future use, add a clear
comment above formatBytes explaining why it's retained (e.g., "kept for
potential future use; do not remove") and add a TODO with an issue/PR reference;
update any imports if necessary after removal.
🧹 Nitpick comments (4)
v3/internal/setupwizard/wizard.go (4)
329-332: Consider handling the write error for the PDF asset.The error returned by
rw.Write()is silently discarded. While this is common for HTTP handlers, logging the error could help diagnose issues when clients disconnect mid-transfer.♻️ Suggested improvement
mux.HandleFunc("/assets/apple-sdk-license.pdf", func(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/pdf") - rw.Write(appleLicensePDF) + if _, err := rw.Write(appleLicensePDF); err != nil { + // Client likely disconnected; no action needed + return + } })
1371-1394: Consider using machine-readable GPG output format.Parsing human-readable GPG output (looking for "sec" and splitting by "/") can be fragile across different GPG versions and locales. The
--with-colonsflag provides a stable, machine-parseable format.♻️ More robust alternative
func getDefaultGPGKey() string { - cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long") + cmd := exec.Command("gpg", "--list-secret-keys", "--keyid-format", "long", "--with-colons") output, err := cmd.Output() if err != nil { return "" } lines := strings.Split(string(output), "\n") for _, line := range lines { - if strings.Contains(line, "sec") { - parts := strings.Fields(line) - for _, part := range parts { - if strings.Contains(part, "/") { - keyParts := strings.Split(part, "/") - if len(keyParts) > 1 { - return keyParts[1] - } - } - } + // Colon-separated format: sec:u:4096:1:KEYID:... + if strings.HasPrefix(line, "sec:") { + fields := strings.Split(line, ":") + if len(fields) >= 5 { + return fields[4] // Key ID is in field 5 (0-indexed: 4) + } } } return "" }
1357-1366: Only "Developer ID" certificates are detected.The current filter only captures "Developer ID" certificates. Users with "Apple Development" or "Mac Developer" certificates (for local testing) won't see them listed. This may be intentional for production-focused tooling, but worth noting.
545-546: Hardcoded GitHub issue URL.The URL
https://github.com/wailsapp/wails/issues/4904#issue-comment-boxpoints to a specific issue. If this issue is closed or the project moves, the link will break. Consider making this configurable or pointing to a more stable endpoint.
Only formatBytesMB is used in the codebase. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/wizard.go`:
- Around line 593-598: In handleDockerStatusStream, remove the wildcard CORS
header or restrict it to same-origin: stop unconditionally setting
rw.Header().Set("Access-Control-Allow-Origin", "*") and instead only set
Access-Control-Allow-Origin when the request Origin matches the wizard's own
origin (e.g., build expected origin from r.Host or compare
r.Header.Get("Origin") against allowed origin), or simply omit the header
entirely since the UI is served same-origin; this prevents cross-origin reads of
Docker/system status.
- Around line 786-794: The handler in startDockerPull currently treats
event.Error as terminal but returns nil, preventing the CLI fallback; after
setting w.dockerStatus.PullStatus/ PullError/ PullMessage and w.dockerBuildLogs
(and unlocking w.dockerMu), return a non-nil error (e.g., wrap event.Error with
fmt.Errorf or errors.New) so startDockerPull propagates failure and triggers the
CLI fallback; ensure you reference event.Error, startDockerPull, and
w.dockerStatus.PullError when making this change.
- Remove unnecessary Access-Control-Allow-Origin: * from SSE endpoint (UI is served same-origin, no CORS needed) - Return error when Docker API reports event.Error to trigger CLI fallback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Go embed directive requires frontend/dist/* to exist at build time. Reverting .gitignore change - dist/ must be tracked for CI to pass. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@v3/internal/setupwizard/wizard.go`:
- Around line 728-753: In pullViaDockerAPI, before constructing the v1.44 URL
and issuing API calls, add an explicit Docker version check by calling the
Docker /version endpoint over the same socketPath (or via the http.Client) to
retrieve ApiVersion/Version, parse and ensure it meets the minimum required API
version (v1.44) or Docker release (>= 25.0); if the version is too old, return a
clear error indicating the minimum required Docker/API version (and avoid
silently falling back to CLI), otherwise proceed to use the existing logic that
builds url from crossImageName and tag.
🧹 Nitpick comments (1)
v3/internal/setupwizard/wizard.go (1)
329-332: Consider handling the Write error for completeness.The
rw.Write(appleLicensePDF)return value is ignored. While unlikely to fail for embedded content, handling the error is good practice.♻️ Optional fix
mux.HandleFunc("/assets/apple-sdk-license.pdf", func(rw http.ResponseWriter, r *http.Request) { rw.Header().Set("Content-Type", "application/pdf") - rw.Write(appleLicensePDF) + if _, err := rw.Write(appleLicensePDF); err != nil { + // Log or handle if needed; typically benign for static assets + return + } })
Add comment explaining that pullViaDockerAPI uses API v1.44 (Docker 25.0+) and that older versions gracefully fall back to CLI-based pulling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>




Summary
Adds an experimental interactive setup wizard (
wails3 setup) that guides users through:The wizard runs in the browser and saves configuration to
~/.config/wails/config.yaml.Also includes:
wails3 setup signingandwails3 setup entitlementssub-commands--jsonflag forwails3 doctor(machine-readable output)wails3 doctorScreenshots
The wizard provides a step-by-step browser UI for configuration.
Test plan
wails3 setupon Linux - verify dependency detection and Docker setupwails3 setupon macOS - verify Xcode tools and signing detectionwails3 setupon Windows - verify WebView2 and signing detectionwails3 doctor --jsonoutputs valid JSONwails3 initNotes
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.