Skip to content

Windows RDP support (macOS production-ready) - #1

Merged
Meanski merged 4 commits into
mainfrom
feat/windows-rdp
Jun 21, 2026
Merged

Windows RDP support (macOS production-ready)#1
Meanski merged 4 commits into
mainfrom
feat/windows-rdp

Conversation

@Meanski

@Meanski Meanski commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Adds RDP as a first-class connection type, rendering a live Windows desktop in-app via a bundled FreeRDP sidecar. macOS is production-ready (self-contained, signed/notarized in CI); Windows/Linux sidecars are a tracked fast-follow.

What's included

  • RDP connection type — add-connection form (port 3389, user/pass), sidebar "Remote Desktop" section, Monitor icons across tab bar / list / type picker
  • FreeRDP sidecar (native/rdp-spike/sidecar.c) — connects to the host and streams composed RGBA frames over stdout (length-prefixed NXF1 blobs); ipc/rdp.ts parses them into a <canvas> (RdpView). Output-only for now.
  • Robust framing — parser resyncs past stray stdout instead of tearing down; sidecar pins WLog to stderr at ERROR level so logging can't corrupt the binary frame channel
  • Dashboard shows all connection types — SSH/untyped keep live CPU/RAM; other types render as metric-less launch cards

Production packaging (macOS)

  • build-freerdp-static.sh builds a minimal static FreeRDP (no X11/ffmpeg/H264/audio/redirection channels) → sidecar links only system libs (zero Homebrew refs, ~7 MB)
  • extraResources bundles it into the app; afterPack guard (scripts/verify-sidecar.js) fails the build if it ever relinks non-redistributable libs
  • release.yml builds + caches the static sidecar on the macOS runner
  • RDP UI gated to macOS (the only platform shipping a sidecar today)

Verified

  • 310 tests pass, both TS projects typecheck, npm run pack bundles a self-contained, runnable sidecar
  • Rendered a real Windows Server desktop against a live host

Remaining (fast-follow)

  • Windows sidecar (FreeRDP via vcpkg/MSVC) + Linux sidecar, then enable their extraResources + un-gate the UI
  • Input injection (mouse/keyboard) — currently view-only

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Added macOS Remote Desktop (RDP) support with read-only viewing.
    • RDP is available in the connection manager (default port 3389) with username/password inputs and RDP-specific connection behavior.
    • RDP sessions now appear in the sidebar, dashboard, and open dedicated Remote Desktop tabs.
  • Bug Fixes
    • Improved RDP session cleanup to prevent per-window session leaks.
  • Chores
    • Enhanced macOS app packaging to bundle and validate the native RDP sidecar.

Meanski and others added 2 commits June 21, 2026 12:34
Introduces RDP as a first-class connection type, rendering a live Windows
desktop in-app. A FreeRDP 3 sidecar process (native/rdp-spike/sidecar.c)
connects to the host and streams composed RGBA frames over stdout as
length-prefixed NXF1 blobs; the main process (ipc/rdp.ts) parses them and
forwards each frame to a <canvas> in RdpView. Output-only for now (input
injection is the next milestone).

- New 'rdp' ConnectionType: add-connection form (port 3389, user/pass),
  sidebar "Remote Desktop" section, tab/list/type icons (Monitor glyph)
- openTab routes rdp -> RDP view (and folds in redis routing too)
- Frame parser resyncs past stray stdout instead of tearing down; sidecar
  pins WLog to stderr at ERROR level so logging can't corrupt the binary
  frame channel (root cause of the original desync)
- Dashboard now lists all connection types: SSH/untyped keep live CPU/RAM,
  other types render as metric-less launch cards
- diag-frames.mjs: dev tool to inspect the sidecar frame stream

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dev sidecar dynamically linked Homebrew FreeRDP (ffmpeg, X11, openssl,
…) — not redistributable. Build a minimal, statically-linked FreeRDP and
bundle the sidecar into the signed macOS app so it runs on a clean machine.

- build-freerdp-static.sh: minimal static FreeRDP (no X11/ffmpeg/H264/audio/
  redirection channels), collapsing the dep tree to system libs + OpenSSL
- Makefile `rdp-sidecar-static`: links the static libs into a self-contained
  binary (verified: zero /opt/homebrew refs, ~7MB)
- electron-builder: bundle via mac extraResources; afterPack guard
  (scripts/verify-sidecar.js) fails the build if the sidecar ever links
  non-redistributable libraries
- release.yml: build + cache the static sidecar on the macOS runner
- sidecarPath() is platform-aware (.exe on Windows)
- sidecar.c: WLog threshold raised to ERROR (drops benign WARN console noise)
- Gate the RDP connection type + "Open Remote Desktop" to macOS, the only
  platform shipping a sidecar today (graceful no-op elsewhere)

Remaining for full cross-platform: Windows and Linux sidecar builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 439bcaad-e98e-49d8-b0df-e237e476b982

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds end-to-end read-only RDP streaming: a C sidecar process (sidecar.c) uses FreeRDP GDI callbacks to emit NXF1-framed RGBA frames over stdout; a static build pipeline compiles and bundles it; Electron IPC handlers spawn, stream-parse, and forward frames; and React components display them on a canvas with full UI wiring across the connection manager, dashboard, sidebar, and tab bar.

Changes

RDP Streaming Feature

Layer / File(s) Summary
Native FreeRDP sidecar and spike C implementation
native/rdp-spike/Makefile, native/rdp-spike/sidecar.c, native/rdp-spike/spike.c, native/rdp-spike/diag-frames.mjs, native/rdp-spike/README.md, native/rdp-spike/HANDOFF.md
sidecar.c registers a FreeRDP EndPaint callback, swizzles BGRA→RGBA pixels into a reusable scratch buffer, and writes NXF1-framed binary frames to stdout while routing all FreeRDP logs to stderr. spike.c is a single-frame PPM proof-of-concept. The Makefile builds both via pkg-config and adds an rdp-sidecar-static target linking against arch-scoped static FreeRDP, OpenSSL, Jansson, and macOS frameworks. diag-frames.mjs walks a captured binary file to verify frame framing and detect desync.
Static build script, CI pipeline, and packaging verification
native/rdp-spike/build-freerdp-static.sh, .github/workflows/release.yml, electron-builder.yml, scripts/verify-sidecar.js, .gitignore
build-freerdp-static.sh shallow-clones FreeRDP and runs CMake/Ninja with minimal features into a per-arch prefix. The release workflow adds a macOS cache-restore step keyed on the script hash and runs the build. electron-builder.yml adds an afterPack hook and extraResources entry to bundle the sidecar. verify-sidecar.js runs otool -L on the bundled sidecar and fails the build if any Homebrew/local dylib paths are found.
Electron main-process IPC bridge
src/main/ipc/rdp.ts, src/main/index.ts
rdp.ts defines RdpSession records, resolves the sidecar binary path for dev/packaged builds, implements NXF1 stream resync and drainFrames, spawns the sidecar subprocess, and registers rdp:connect/rdp:disconnect IPC handlers plus disposeRdpSessionsForSender. index.ts imports, registers, and wires per-sender cleanup on window destroy.
Preload context bridge and type declarations
src/preload/index.ts, src/preload/index.d.ts
Exposes api.rdp via contextBridge with connect, disconnect, onFrame, and onClose methods; the type declaration extends window.api with typed callback signatures.
App store types and RDP tab management
src/renderer/src/store/index.ts
Adds 'rdp' to ConnectionType and TabView unions, extends the state interface with openRdpTab, updates openTab to route RDP sessions to the 'rdp' view with 'connected' status and RDP · ... label prefixes, and implements openRdpTab with tab deduplication.
RdpView canvas component and MainContent routing
src/renderer/src/components/RDP/RdpView.tsx, src/renderer/src/components/MainContent.tsx
RdpView fetches credentials, connects to the sidecar, subscribes to onFrame/onClose IPC events, and paints RGBA pixel buffers onto a canvas (resizing when dimensions change); unmount disposes the session. MainContent adds a tab.view === 'rdp' branch wrapped in TabErrorBoundary.
Connection manager, dashboard, sidebar, and tab bar UI wiring
src/renderer/src/components/ConnectionManager/AddConnectionModal.tsx, src/renderer/src/components/ConnectionManager/ConnectionManager.tsx, src/renderer/src/components/Dashboard/Dashboard.tsx, src/renderer/src/components/Dashboard/ServerViews.tsx, src/renderer/src/components/ServerContextMenu.tsx, src/renderer/src/components/Sidebar/Sidebar.tsx, src/renderer/src/components/TabBar/TabBar.tsx, src/renderer/src/lib/colors.ts
AddConnectionModal adds an RDP type option (macOS-only, port 3389, username validation, credential fields, no Test Connection button). ConnectionManager adds color/label/icon mappings for rdp. Dashboard generalizes from SSH-only to dashboardSessions and wires onOpenRdp context menu. ServerViews adds isMetricCapable and StatusBox for non-metric types plus an rdp icon branch. ServerContextMenu adds onOpenRdp prop and menu item. Sidebar adds rdpSessions, a "Remote Desktop" draggable section, and macOS-gated onOpenRdp. TabBar and colors.ts add rdp icon and color.

Sequence Diagram

sequenceDiagram
  participant User as User
  participant RdpView as RdpView (renderer)
  participant MainIPC as rdp.ts (main process)
  participant Sidecar as rdp-sidecar (C process)
  participant FreeRDP as FreeRDP GDI

  User->>RdpView: Open RDP tab
  RdpView->>MainIPC: ipcRenderer.invoke("rdp:connect", config)
  MainIPC->>Sidecar: spawn rdp-sidecar host port user pass
  Sidecar->>FreeRDP: freerdp_connect()
  FreeRDP-->>Sidecar: EndPaint callback (primary_buffer)
  Sidecar->>Sidecar: BGRA to RGBA swizzle + write NXF1 frame to stdout
  Sidecar-->>MainIPC: stdout NXF1 binary frames
  MainIPC->>MainIPC: drainFrames() parse and copy pixel buffer
  MainIPC->>RdpView: webContents.send("rdp:frame", id, w, h, pixels)
  RdpView->>RdpView: canvas.putImageData(ImageData)
  User->>RdpView: Close tab
  RdpView->>MainIPC: ipcRenderer.invoke("rdp:disconnect", id)
  MainIPC->>Sidecar: process.kill()
  MainIPC->>RdpView: webContents.send("rdp:closed", id, null)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐰 A sidecar of pixels hops over the wire,
NXF1 frames stacked higher and higher,
FreeRDP whispers its secrets to C,
Stdout streams BGRA — oh, glorious spree!
The canvas awakes with a cyan-bright hue,
Remote desktops rendered, read-only and new. 🖥️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Windows RDP support (macOS production-ready)' accurately describes the main change: introducing RDP support with current macOS availability, which aligns with the substantial feature addition across 30+ files including RDP UI, sidecar, and native build infrastructure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/windows-rdp

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Cross-machine handoff (next session is on Windows): documents what's done
(macOS production-ready), the architecture + key files, and the step-by-step
Windows sidecar plan — including the critical _setmode(stdout, _O_BINARY)
gotcha, extraResources/guard/UI-gate changes, and lessons learned.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 21, 2026

Copy link
Copy Markdown

Deploying noxed with  Cloudflare Pages  Cloudflare Pages

Latest commit: 38bc201
Status: ✅  Deploy successful!
Preview URL: https://1a94c666.noxed.pages.dev
Branch Preview URL: https://feat-windows-rdp.noxed.pages.dev

View logs

@Meanski

Meanski commented Jun 21, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/renderer/src/store/index.ts (1)

246-259: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

openTab can activate the wrong view for RDP sessions.

At Line 246, dedupe only checks sessionId, not the derived view. If a session already has a non-RDP tab, opening an RDP session can incorrectly focus that tab instead of creating/reusing an RDP tab.

Suggested fix
   openTab: (session) =>
     set((s) => {
-      const existing = s.tabs.find((t) => t.sessionId === session.id && t.status !== 'error' && !t.paneOf)
-      if (existing) return { activeTabId: existing.id, focusedPaneId: null }
       const isK8s = session.type === 'kubernetes'
       const isSftp = session.type === 'sftp'
       const isDb = session.type === 'database'
       const isRdp = session.type === 'rdp'
       const isRedis = session.type === 'redis'
       const view: TabView = isK8s ? 'k8s' : isSftp ? 'sftp' : isDb ? 'database' : isRdp ? 'rdp' : isRedis ? 'redis' : 'terminal'
+      const existing = s.tabs.find(
+        (t) => t.sessionId === session.id && t.view === view && t.status !== 'error' && !t.paneOf,
+      )
+      if (existing) return { activeTabId: existing.id, focusedPaneId: null }
       const tab: Tab = {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/store/index.ts` around lines 246 - 259, The deduplication
check in the `openTab` function only compares sessionId but not the derived view
type, which can cause the wrong tab view to be activated. Move the calculation
of the view type (the ternary expression that determines whether it should be
'k8s', 'sftp', 'database', 'rdp', 'redis', or 'terminal') before the existing
tab lookup, then update the find condition to also check that t.view equals the
calculated view value, ensuring the correct tab type is found or created for
each session.
🧹 Nitpick comments (1)
src/renderer/src/components/MainContent.tsx (1)

235-243: ⚡ Quick win

Consider pausing RDP rendering when tab is inactive.

This file intentionally keeps tabs mounted; for RdpView that can mean background frame decoding/painting while hidden (display: none). Passing an isActive prop and short-circuiting paint when inactive would reduce idle CPU.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/src/components/MainContent.tsx` around lines 235 - 243, The
RdpView component continues rendering and decoding frames even when its tab is
inactive (hidden with display: none), consuming unnecessary CPU resources. Add
an isActive prop to RdpView that indicates whether the tab is currently the
active tab, passing the active status based on the current tab context. Then
modify the RdpView component to short-circuit or pause frame decoding and
painting operations when isActive is false to reduce idle CPU usage on
background tabs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release.yml:
- Around line 40-43: The actions/cache step in the Cache static FreeRDP task on
line 42 uses a mutable version tag `@v4` which poses a security risk in a release
pipeline handling sensitive secrets. Replace the mutable tag `@v4` with a full
commit SHA to ensure an immutable, predictable version of the action is always
used. Look up the latest commit SHA for actions/cache and update the uses field
to reference it directly instead of the version tag.

In `@native/rdp-spike/build-freerdp-static.sh`:
- Around line 22-24: The conditional check that tests for the existence of
"$SRC/.git" only performs a git clone during the initial run. On subsequent
script executions, if the repository already exists but FREERDP_TAG has changed,
the clone step is skipped entirely, causing the script to use stale source code.
To fix this, add logic after the conditional block that fetches the latest
changes and checks out the specified FREERDP_TAG branch, ensuring the requested
tag is honored on both initial clones and subsequent runs when the repository
already exists.

In `@native/rdp-spike/diag-frames.mjs`:
- Around line 39-51: The offset advancement using off += 16 + dataLen does not
validate whether the buffer contains enough remaining bytes, allowing truncated
or corrupt frames to cause the offset to overshoot EOF undetected. Before
advancing the offset in the main loop (at the line with off += 16 + dataLen),
add a validation check to ensure that off + 16 + dataLen does not exceed
buf.length. If the check fails, log an error or warning indicating truncation
was detected and exit the loop early, preventing false success reports on the
final validation that checks if off equals buf.length.

In `@native/rdp-spike/sidecar.c`:
- Around line 191-199: The password is being passed as a command-line argument
(argv[4]) which exposes credentials to local process listing tools and crash
diagnostics. Remove the parsing of argv[4] into the 'pass' variable and update
the usage message to not include [password] as a command-line parameter.
Instead, implement secure password input by reading the password from stdin
using a function that doesn't echo the input to the terminal, or alternatively
read it from an environment variable. Make sure the argument count validation in
the condition (argc >= 6 for width/height) is adjusted accordingly to account
for the removal of the password argument.
- Around line 79-113: The emit_frame function calculates dataLen as rowBytes
multiplied by h without checking for integer overflow or validating against the
64 MiB frame size limit. Add bounds validation after calculating dataLen to
ensure it does not exceed the maximum allowed frame size and does not overflow
when cast to UINT32 for the header write operation. Check for overflow in the
rowBytes * h multiplication by verifying the result fits within size_t bounds,
then validate the final dataLen against a reasonable upper bound (64 MiB) before
proceeding with the realloc call and header construction at the end of
emit_frame.
- Around line 214-220: The freerdp_settings_set_bool call that sets
FreeRDP_IgnoreCertificate to TRUE disables server certificate validation,
creating a security vulnerability to man-in-the-middle attacks. Remove or change
this line to not disable certificate validation by default. Instead, either set
FreeRDP_IgnoreCertificate to FALSE to enable certificate validation, or make
this setting configurable through an external parameter so certificate
validation is enabled by default and can only be explicitly disabled by the user
if absolutely necessary.

In `@src/main/ipc/rdp.ts`:
- Around line 116-124: The code currently only validates that dataLen is within
MAX_FRAME_BYTES but does not validate the width and height values or check
consistency between the data length and the frame dimensions. After reading
width, height, and dataLen from the buffer, add additional validation checks to
ensure width and height are non-zero and reasonable (not exceeding maximum
display dimensions), and verify that dataLen equals width * height * 4. If any
validation fails, treat it as a false positive header match by calling
resyncToMagic and continuing to the next iteration, similar to the existing
MAX_FRAME_BYTES check.
- Around line 159-163: Remove the password from the arguments array passed to
the spawn call (which currently includes host, port, username, password, width,
and height). Instead, write the password to the stdin stream of the spawned
process after it is created. Access the stdin pipe via the proc object's stdin
property and write the password there to keep credentials out of process
arguments where they could be exposed via local process inspection.

In `@src/renderer/src/components/ConnectionManager/AddConnectionModal.tsx`:
- Around line 930-961: The RDP password fields shown when type === 'rdp' may not
be saved because the form's authType field could still be set to 'key' from a
previous connection type selection. When the connection type is switched to
'rdp', ensure that authType is automatically updated to 'password' at the same
time. Check the onChange handler for the type field (where 'rdp' is being
selected) and ensure it also updates authType to 'password' so that the save
logic includes the RDP password in the payload.

In `@src/renderer/src/components/ConnectionManager/ConnectionManager.tsx`:
- Around line 70-74: The filter menu in the ConnectionManager component is
missing options for the newly added redis and rdp connection types. Locate the
filter menu implementation (likely a list or array that defines available filter
options for connection types) and add redis and rdp as selectable filter options
alongside the existing types like ssh, sftp, database, and kubernetes. Ensure
the filter menu uses the same type identifiers (redis, rdp) that are defined in
the color and typeLabel mappings so filtering works correctly.

In `@src/renderer/src/components/Dashboard/Dashboard.tsx`:
- Around line 406-408: The onOpenRdp callback on line 406 is being exposed for
all sessions on macOS without verifying the session type, allowing non-RDP
entries to trigger RDP tab opening with mismatched data. Modify the condition
that assigns onOpenRdp to additionally check that the ctxMenu.session is
specifically an RDP session type before allowing the openRdpTab function to be
assigned, ensuring the callback is only available when both the platform is
darwin AND the session is an RDP connection.

In `@src/renderer/src/components/RDP/RdpView.tsx`:
- Around line 57-82: The RDP session can leak if unmount occurs while the
window.api.rdp.connect() call is still pending, because rdpId is assigned after
the cleanup function runs. To fix this, store a reference to the connect promise
returned by window.api.rdp.connect() in the async IIFE, and in the cleanup
function (the return statement), ensure that if the connect promise is still
pending when disposal occurs, you properly disconnect the session once it
resolves. This prevents the race condition where rdpId gets assigned after
cleanup has already checked for it. Track the connecting state and handle the
resolution of the connect promise in the cleanup handler to guarantee
disconnection regardless of timing.

In `@src/renderer/src/components/Sidebar/Sidebar.tsx`:
- Around line 248-260: The RDP section in the DraggableSection component is
rendered without verifying platform support, which conflicts with the macOS-only
RDP rollout. Add a platform check to the conditional rendering logic alongside
the existing rdpSessions.length > 0 check so that the RDP section only appears
on supported platforms. Additionally, ensure that the onOpen handler is only
passed when the platform supports RDP affordances to prevent surfacing invalid
actions for incompatible session types.

---

Outside diff comments:
In `@src/renderer/src/store/index.ts`:
- Around line 246-259: The deduplication check in the `openTab` function only
compares sessionId but not the derived view type, which can cause the wrong tab
view to be activated. Move the calculation of the view type (the ternary
expression that determines whether it should be 'k8s', 'sftp', 'database',
'rdp', 'redis', or 'terminal') before the existing tab lookup, then update the
find condition to also check that t.view equals the calculated view value,
ensuring the correct tab type is found or created for each session.

---

Nitpick comments:
In `@src/renderer/src/components/MainContent.tsx`:
- Around line 235-243: The RdpView component continues rendering and decoding
frames even when its tab is inactive (hidden with display: none), consuming
unnecessary CPU resources. Add an isActive prop to RdpView that indicates
whether the tab is currently the active tab, passing the active status based on
the current tab context. Then modify the RdpView component to short-circuit or
pause frame decoding and painting operations when isActive is false to reduce
idle CPU usage on background tabs.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d4b8538-43e5-40d9-8033-7df0e2e4a887

📥 Commits

Reviewing files that changed from the base of the PR and between 7199180 and bcffa69.

📒 Files selected for processing (26)
  • .github/workflows/release.yml
  • .gitignore
  • electron-builder.yml
  • native/rdp-spike/HANDOFF.md
  • native/rdp-spike/Makefile
  • native/rdp-spike/README.md
  • native/rdp-spike/build-freerdp-static.sh
  • native/rdp-spike/diag-frames.mjs
  • native/rdp-spike/sidecar.c
  • native/rdp-spike/spike.c
  • scripts/verify-sidecar.js
  • src/main/index.ts
  • src/main/ipc/rdp.ts
  • src/preload/index.d.ts
  • src/preload/index.ts
  • src/renderer/src/components/ConnectionManager/AddConnectionModal.tsx
  • src/renderer/src/components/ConnectionManager/ConnectionManager.tsx
  • src/renderer/src/components/Dashboard/Dashboard.tsx
  • src/renderer/src/components/Dashboard/ServerViews.tsx
  • src/renderer/src/components/MainContent.tsx
  • src/renderer/src/components/RDP/RdpView.tsx
  • src/renderer/src/components/ServerContextMenu.tsx
  • src/renderer/src/components/Sidebar/Sidebar.tsx
  • src/renderer/src/components/TabBar/TabBar.tsx
  • src/renderer/src/lib/colors.ts
  • src/renderer/src/store/index.ts

Comment on lines +40 to +43
- name: Cache static FreeRDP
if: runner.os == 'macOS'
uses: actions/cache@v4
with:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd .github/workflows && head -50 release.yml | cat -n

Repository: Meanski/noxed

Length of output: 1796


🏁 Script executed:

cat -n .github/workflows/release.yml | tail -n +40

Repository: Meanski/noxed

Length of output: 6518


Pin actions/cache to a full commit SHA.

Line 42 uses a mutable tag (@v4) in a release pipeline that handles signing/notarization secrets. Pin to an immutable commit SHA.

Suggested fix
      - name: Cache static FreeRDP
        if: runner.os == 'macOS'
-        uses: actions/cache@v4
+        uses: actions/cache@<FULL_LENGTH_COMMIT_SHA>
🧰 Tools
🪛 zizmor (1.25.2)

[error] 42-42: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 42-42: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 40 - 43, The actions/cache step
in the Cache static FreeRDP task on line 42 uses a mutable version tag `@v4` which
poses a security risk in a release pipeline handling sensitive secrets. Replace
the mutable tag `@v4` with a full commit SHA to ensure an immutable, predictable
version of the action is always used. Look up the latest commit SHA for
actions/cache and update the uses field to reference it directly instead of the
version tag.

Source: Linters/SAST tools

Comment thread native/rdp-spike/build-freerdp-static.sh
Comment thread native/rdp-spike/diag-frames.mjs
Comment thread native/rdp-spike/sidecar.c
Comment thread native/rdp-spike/sidecar.c Outdated
Comment thread src/renderer/src/components/ConnectionManager/ConnectionManager.tsx
Comment thread src/renderer/src/components/Dashboard/Dashboard.tsx Outdated
Comment thread src/renderer/src/components/RDP/RdpView.tsx
Comment thread src/renderer/src/components/Sidebar/Sidebar.tsx Outdated
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 10 file(s) based on 13 unresolved review comments.

Files modified:

  • native/rdp-spike/build-freerdp-static.sh
  • native/rdp-spike/diag-frames.mjs
  • native/rdp-spike/sidecar.c
  • package-lock.json
  • src/main/ipc/rdp.ts
  • src/renderer/src/components/ConnectionManager/AddConnectionModal.tsx
  • src/renderer/src/components/ConnectionManager/ConnectionManager.tsx
  • src/renderer/src/components/Dashboard/Dashboard.tsx
  • src/renderer/src/components/RDP/RdpView.tsx
  • src/renderer/src/components/Sidebar/Sidebar.tsx

Commit: 38bc2016e299a31923d9afbcb4d3c231dca34827

The changes have been pushed to the feat/windows-rdp branch.

Time taken: 4m 35s


⚠️ 1 file(s) could not be committed — the agent does not have permission to push to .github/workflows/. Please apply these changes manually:

.github/workflows/release.yml — 1 change:

Lines 39–45
       # arch. Cached so FreeRDP isn't recompiled on every release.
       - name: Cache static FreeRDP
         if: runner.os == 'macOS'
-        uses: actions/cache@v4
+        uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684
         with:
           path: |
             native/rdp-spike/.freerdp-src

Fixed 10 file(s) based on 13 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@Meanski

Meanski commented Jun 21, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Meanski
Meanski merged commit 5263399 into main Jun 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant