#21 - Replace Lens with Freelens in the coder-xfce-vnc variant #23

Merged
GuillaumeHemmen merged 1 commit from 21-replace-lens-with-freelens into master 2026-09-11 09:23:00 +00:00
Member

What

Replace Lens (k8slens, proprietary) with Freelens in the coder-xfce-vnc variant. Freelens is the MIT-licensed community fork of OpenLens. It's installed from Freelens's official APT repo and set up the same way Lens was: a wrapper that adds the flags needed in the pod, plus a desktop-entry override.

Changes

  • Dockerfile: the Lens block is replaced by a Freelens block.
    • The signing key's fingerprint 50B1 BA0A AF45 14AE 56F9 9AC4 8B2A 569C D2EE ECC1 is checked before the key is trusted, the same check the Claude Desktop block does.
    • test -x "$(readlink -f /usr/bin/freelens)" checks that the update-alternatives entry point exists.
    • The override freelens.desktop is generated with sed from the packaged entry: Exec points to /usr/local/bin/freelens (upstream's own flags are kept), Categories=Development;. Both changes are checked with grep.
    • COPY now ships the Freelens wrapper, and the comments that mentioned Lens elsewhere are updated.
  • scripts/lens-desktop-wrapper.shscripts/freelens-wrapper.sh: same wrapper (ELECTRON_DISABLE_SANDBOX=1 + --disable-dev-shm-usage), now pointing at /usr/bin/freelens.
  • scripts/coder-init-desktop.sh: I removed the code that cleaned up stale user-local Lens menu entries. It only ran when the Lens wrapper existed, so with Lens gone it could never run again. Its note on why entries are renamed to .bak now sits on the Claude Desktop cleanup code.
  • README.md: Lens → Freelens in the app list, the Electron section (the heading anchor changed, and every link to it is updated), the coder-init-desktop docs, and Version Information. A ~/.config/Freelens/ row is added to the persisted-state table.

One design point worth reviewing: where the repo is defined

The Freelens repo is not set up like the Azul/Mozilla/Claude repos (/usr/share/keyrings/* + a .list file). The freelens deb installs its own /etc/apt/keyrings/freelens.asc and /etc/apt/sources.list.d/freelens.sources as conffiles. If the repo were defined anywhere else, apt would see the same source twice with two different Signed-By paths. That fails every later apt-get update, including the Claude Desktop step right after it and any sudo apt update in a workspace. I checked this in a pod:

E: Conflicting values set for option Signed-By regarding source https://github.com/freelensapp/freelens/releases/latest/download/ ./: /usr/share/keyrings/freelens-archive-keyring.asc != /etc/apt/keyrings/freelens.asc
E: The list of sources could not be read.

So the block writes the key and a deb822 source file at exactly those paths. The source file is byte-identical to the one the package ships. --force-confdef --force-confold means that if the key bundled in the deb ever differs from the fingerprint-checked one, the build keeps ours instead of stopping at a conffile prompt.

The repo is served from GitHub's releases/latest download URL, so every build installs the current Freelens release (currently 1.10.3) with no manual version bump. That's the same always-latest approach as Toolbox and Nimbalyst. APT still checks the signed Release file.

Verification

I pulled the RUN step out of the Dockerfile with a script and ran it in an ubuntu:24.04 pod on the cluster:

Check Result
Key fingerprint check pass
apt-get install freelens pass, 1.10.3
/usr/bin/freelens alternative /opt/Freelens/freelens
All 3 conffiles: dpkg md5 vs on-disk match (no .dpkg-dist / .dpkg-old files)
Override Exec / Categories checks pass
apt-get update after install clean, no W:/E: lines
Negative control: second definition with a different Signed-By fails as shown above

shellcheck passes on freelens-wrapper.sh and coder-init-desktop.sh. The branch push also starts the docker-dev Kaniko build.

Not verified: actually running Freelens inside the VNC session, which needs a real desktop. It's an Electron app with the same two failure modes the wrapper already handles for Lens and Claude Desktop, so I expect it to work, but that's inference. Worth a smoke test once the image is built.

Notes

  • Existing workspaces: Freelens keeps its state in ~/.config/Freelens/, not Lens's ~/.config/Lens/, so clusters added in Lens won't show up automatically. ~/.kube/config is read as usual. The old ~/.config/Lens/ directory stays on the PVC untouched.
  • The Freelens signing key expires 2028-01-16. If upstream extends it, the fingerprint stays the same and the next build picks it up, since the key is downloaded fresh each time. If upstream switches to a new key, the fingerprint check fails the build loudly, and the pin needs a deliberate update.
  • During install, the package's postinst prints unshare: unshare failed: Operation not permitted and then sets chrome-sandbox setuid. That's harmless here: ELECTRON_DISABLE_SANDBOX=1 still applies, as with Claude Desktop.

Closes #21

🤖 Generated with Claude Code

https://claude.ai/code/session_01XPajGyTH2js52mY5WSJoNA

## What Replace **Lens** (k8slens, proprietary) with **[Freelens](https://github.com/freelensapp/freelens)** in the `coder-xfce-vnc` variant. Freelens is the MIT-licensed community fork of OpenLens. It's installed from Freelens's official APT repo and set up the same way Lens was: a wrapper that adds the flags needed in the pod, plus a desktop-entry override. ## Changes - **`Dockerfile`**: the Lens block is replaced by a Freelens block. - The signing key's fingerprint `50B1 BA0A AF45 14AE 56F9 9AC4 8B2A 569C D2EE ECC1` is checked before the key is trusted, the same check the Claude Desktop block does. - `test -x "$(readlink -f /usr/bin/freelens)"` checks that the `update-alternatives` entry point exists. - The override `freelens.desktop` is generated with `sed` from the packaged entry: `Exec` points to `/usr/local/bin/freelens` (upstream's own flags are kept), `Categories=Development;`. Both changes are checked with `grep`. - `COPY` now ships the Freelens wrapper, and the comments that mentioned Lens elsewhere are updated. - **`scripts/lens-desktop-wrapper.sh` → `scripts/freelens-wrapper.sh`**: same wrapper (`ELECTRON_DISABLE_SANDBOX=1` + `--disable-dev-shm-usage`), now pointing at `/usr/bin/freelens`. - **`scripts/coder-init-desktop.sh`**: I removed the code that cleaned up stale user-local Lens menu entries. It only ran when the Lens wrapper existed, so with Lens gone it could never run again. Its note on why entries are renamed to `.bak` now sits on the Claude Desktop cleanup code. - **`README.md`**: Lens → Freelens in the app list, the Electron section (the heading anchor changed, and every link to it is updated), the `coder-init-desktop` docs, and Version Information. A `~/.config/Freelens/` row is added to the persisted-state table. ## One design point worth reviewing: where the repo is defined The Freelens repo is **not** set up like the Azul/Mozilla/Claude repos (`/usr/share/keyrings/*` + a `.list` file). **The freelens deb installs its own `/etc/apt/keyrings/freelens.asc` and `/etc/apt/sources.list.d/freelens.sources` as conffiles.** If the repo were defined anywhere else, apt would see the same source twice with two different `Signed-By` paths. That fails every later `apt-get update`, including the Claude Desktop step right after it and any `sudo apt update` in a workspace. I checked this in a pod: ``` E: Conflicting values set for option Signed-By regarding source https://github.com/freelensapp/freelens/releases/latest/download/ ./: /usr/share/keyrings/freelens-archive-keyring.asc != /etc/apt/keyrings/freelens.asc E: The list of sources could not be read. ``` So the block writes the key and a deb822 source file at exactly those paths. The source file is byte-identical to the one the package ships. `--force-confdef --force-confold` means that if the key bundled in the deb ever differs from the fingerprint-checked one, the build keeps ours instead of stopping at a conffile prompt. The repo is served from GitHub's `releases/latest` download URL, so every build installs the current Freelens release (currently **1.10.3**) with no manual version bump. That's the same always-latest approach as Toolbox and Nimbalyst. APT still checks the signed `Release` file. ## Verification I pulled the `RUN` step out of the Dockerfile with a script and ran it in an `ubuntu:24.04` pod on the cluster: | Check | Result | |---|---| | Key fingerprint check | pass | | `apt-get install freelens` | pass, `1.10.3` | | `/usr/bin/freelens` alternative | → `/opt/Freelens/freelens` | | All 3 conffiles: dpkg md5 vs on-disk | match (no `.dpkg-dist` / `.dpkg-old` files) | | Override `Exec` / `Categories` checks | pass | | `apt-get update` after install | clean, no `W:`/`E:` lines | | Negative control: second definition with a different `Signed-By` | fails as shown above | `shellcheck` passes on `freelens-wrapper.sh` and `coder-init-desktop.sh`. The branch push also starts the `docker-dev` Kaniko build. **Not verified:** actually running Freelens inside the VNC session, which needs a real desktop. It's an Electron app with the same two failure modes the wrapper already handles for Lens and Claude Desktop, so I expect it to work, but that's inference. Worth a smoke test once the image is built. ## Notes - **Existing workspaces:** Freelens keeps its state in `~/.config/Freelens/`, not Lens's `~/.config/Lens/`, so clusters added in Lens won't show up automatically. `~/.kube/config` is read as usual. The old `~/.config/Lens/` directory stays on the PVC untouched. - The Freelens signing key expires **2028-01-16**. If upstream extends it, the fingerprint stays the same and the next build picks it up, since the key is downloaded fresh each time. If upstream switches to a new key, the fingerprint check fails the build loudly, and the pin needs a deliberate update. - During install, the package's postinst prints `unshare: unshare failed: Operation not permitted` and then sets `chrome-sandbox` setuid. That's harmless here: `ELECTRON_DISABLE_SANDBOX=1` still applies, as with Claude Desktop. Closes #21 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01XPajGyTH2js52mY5WSJoNA
#21 - Replace Lens with Freelens in the coder-xfce-vnc variant
Some checks failed
/ docker-dev-ci (push) Successful in 7m16s
/ docker-dev-coder (push) Successful in 8m5s
/ docker-dev-coder-xfce-vnc (push) Failing after 11m12s
b3b3b95e2a
Swap proprietary Lens (k8slens) for Freelens, the MIT-licensed community
fork of OpenLens, installed from the official Freelens APT repo with the
signing-key fingerprint asserted before the key is trusted.

The key and deb822 source are written at the exact paths the freelens deb
ships as conffiles, so apt never sees two definitions of the source with
conflicting Signed-By values (which would break every later apt-get
update). Launches go through a new /usr/local/bin/freelens wrapper and a
sed-derived desktop-entry override, same as Lens before.

The Lens stale-entry healer in coder-init-desktop.sh is removed: it was
guarded on the Lens wrapper, which no longer exists. README updated.

Closes #21

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPajGyTH2js52mY5WSJoNA
GuillaumeHemmen approved these changes 2026-09-10 07:09:40 +00:00
Dismissed
claude-bot force-pushed 21-replace-lens-with-freelens from b3b3b95e2a
Some checks failed
/ docker-dev-ci (push) Successful in 7m16s
/ docker-dev-coder (push) Successful in 8m5s
/ docker-dev-coder-xfce-vnc (push) Failing after 11m12s
to af5014544f
Some checks failed
/ docker-dev-ci (push) Successful in 6m51s
/ docker-dev-coder (push) Successful in 7m36s
/ docker-dev-coder-xfce-vnc (push) Failing after 11m31s
2026-09-10 08:13:22 +00:00
Compare
claude-bot dismissed GuillaumeHemmen's review 2026-09-10 08:13:22 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

GuillaumeHemmen force-pushed 21-replace-lens-with-freelens from af5014544f
Some checks failed
/ docker-dev-ci (push) Successful in 6m51s
/ docker-dev-coder (push) Successful in 7m36s
/ docker-dev-coder-xfce-vnc (push) Failing after 11m31s
to d6cf824b06
Some checks are pending
/ docker-dev-coder (push) Successful in 7m29s
/ docker-dev-ci (push) Successful in 26m14s
/ docker-dev-coder-xfce-vnc (push) Has started running
2026-09-11 06:25:07 +00:00
Compare
GuillaumeHemmen force-pushed 21-replace-lens-with-freelens from d6cf824b06
Some checks are pending
/ docker-dev-coder (push) Successful in 7m29s
/ docker-dev-ci (push) Successful in 26m14s
/ docker-dev-coder-xfce-vnc (push) Has started running
to e163c2a591
Some checks are pending
/ docker-dev-ci (push) Has started running
/ docker-dev-coder (push) Has started running
/ docker-dev-coder-xfce-vnc (push) Has started running
2026-09-11 07:55:21 +00:00
Compare
GuillaumeHemmen force-pushed 21-replace-lens-with-freelens from e163c2a591
Some checks are pending
/ docker-dev-ci (push) Has started running
/ docker-dev-coder (push) Has started running
/ docker-dev-coder-xfce-vnc (push) Has started running
to a6f3310f7c
All checks were successful
/ docker-dev-ci (push) Successful in 3m50s
/ docker-dev-coder (push) Successful in 4m9s
/ docker-dev-coder-xfce-vnc (push) Successful in 9m36s
2026-09-11 08:49:53 +00:00
Compare
GuillaumeHemmen deleted branch 21-replace-lens-with-freelens 2026-09-11 09:23:00 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
actions/sindri!23
No description provided.