codex-desktop-linux

LOW
maintainer facet 1 votes scanned 2026-11-01 00:21:48.120785
View on AUR
Why flagged

The package downloads a prebuilt .deb from a non-whitelisted host, but it is checksum-verified, pinned to a specific version, and used as a source payload that is patched and validated; the host, while not standard, is plausibly official for the project.

Triggered rules

Low AI review downgraded a static finding llm_review

The static rules flagged this MEDIUM, but an AI model (qwen/qwen3-235b-a22b-2507) reviewed the full PKGBUILD and judged it LOW (confidence 95%): The package downloads a prebuilt .deb from a non-whitelisted host, but it is checksum-verified, pinned to a specific version, and used as a source payload that is patched and validated; the host, while not standard, is plausibly official for the project.

1 higher static finding superseded - not the current verdict (shown for transparency)
Medium source=() URL on a non-standard host source_untrusted_domain

One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).

  • PKGBUILD:93 "$_debfile::https://persistent.oaistatic.com/codex-app-prod/linux/deb/pool/main/c/chatgpt/$_debfile"

PKGBUILD

1 offending line(s) highlighted
1# Maintainer: distsystem <dev@dist.systems>
2
3# Codex Desktop for Linux, distsystem soft-fork.
4#
5# Patches OpenAI's official Linux package into the fork's distribution, pinned
6# to the version nix/upstream-linux-packages.json carries so a build always
7# targets the payload the patches were validated against. Sourced from main
8# (rolling): the distsystem fork stays rebased on upstream/main, and main is
9# force-pushed only after CI validates the cross-combination, so main is always
10# last-known-good, with no separate tag needed.
11#
12# This is a standalone PKGBUILD for the no-updater pacman/AUR install path;
13# updates come from pacman. packaging/linux/PKGBUILD.template is a different
14# path: the updater-rebuild shell rendered by build-pacman.sh, bundled into the
15# update-builder and referenced by updater/src/builder.rs.
16
17pkgname=codex-desktop-linux
18# Copied from nix/upstream-linux-packages.json; prepare() asserts they agree.
19_appver=26.1023.51421
20pkgver=26.1023.51421
21pkgrel=1
22pkgdesc="Codex Desktop for Linux, distsystem soft-fork (official Linux package pinned, no auto-updater)"
23arch=('x86_64')
24url="https://github.com/distsystem/codex-desktop-linux"
25license=('MIT')
26# Runtime libraries the official ChatGPT ELF links against, matching
27# packaging/linux/PKGBUILD.template minus the updater's polkit.
28depends=(
29 'curl'
30 'nodejs'
31 'xdg-utils'
32 'alsa-lib'
33 'at-spi2-core'
34 'atk'
35 'cairo'
36 'dbus'
37 'expat'
38 'gdk-pixbuf2'
39 'glib2'
40 'graphite'
41 'gtk3'
42 'libcups'
43 'libdrm'
44 'libglvnd'
45 'libnotify'
46 'libusb'
47 'libx11'
48 'libxcb'
49 'libxcomposite'
50 'libxdamage'
51 'libxext'
52 'libxfixes'
53 'libxkbcommon'
54 'libxrandr'
55 'mesa'
56 'nspr'
57 'nss'
58 'openssl'
59 'pango'
60 'systemd-libs'
61 'tpm2-tss'
62 'xz'
63)
64makedepends=(
65 'git' # clone the distsystem fork (rolling main)
66 'dpkg' # dpkg-deb: read and unpack the official Linux package
67 'python' # candidate promotion helpers
68 'nodejs' # asar patch, electron-rebuild, feature stage hooks, validate-patch-report
69 'npm' # native module install (better-sqlite3, node-pty)
70 'rust' # cargo: Computer Use + read-aloud-mcp backends
71 'curl' # Electron / managed Node downloads
72 'unzip' # Electron runtime extraction
73)
74optdepends=(
75 'nodejs>=22.22.0: override the bundled managed Node.js runtime'
76 'npm: Codex CLI install/update flows'
77 'zenity: GTK dialog fallback when the Codex CLI is missing'
78 'kdialog: KDE dialog fallback when the Codex CLI is missing'
79 'ydotool: synthetic keyboard/pointer input for Computer Use on Wayland'
80 'xdg-desktop-portal-wlr: screenshot/remote-desktop portal backend (niri/sway/wlroots)'
81 'xdg-desktop-portal-gnome: screenshot/remote-desktop portal backend (GNOME/Mutter)'
82 'alsa-utils: audio playback for Read Aloud'
83 'speech-dispatcher: system TTS bridge for Read Aloud'
84 'espeak-ng: offline TTS fallback for Read Aloud'
85)
86provides=('codex-desktop')
87conflicts=('codex-desktop')
88options=('!debug' '!strip')
89install="$pkgname.install"
90_debfile="chatgpt_${_appver}_amd64.deb"
91source=(
92 "$pkgname::git+https://github.com/distsystem/codex-desktop-linux.git#branch=main"
93 "$_debfile::https://persistent.oaistatic.com/codex-app-prod/linux/deb/pool/main/c/chatgpt/$_debfile"
94)
95sha256sums=('SKIP'
96 '4484dc2b54fc0978beb23b8d8d717494e4e0b4fbeab0a876739105e50b44de5a')
97# install.sh runs dpkg-deb on the payload itself; let it own the extraction.
98noextract=("$_debfile")
99
100# Installed app identity stays "codex-desktop": matches the Electron WM_CLASS,
101# the ~/.config/codex-desktop settings dir, and provides/conflicts.
102_appname=codex-desktop
103
104pkgver() {
105 cd "$srcdir/$pkgname"
106 printf '%s.r%s.g%s' "$_appver" "$(git rev-list --count HEAD)" "$(git rev-parse --short=8 HEAD)"
107}
108
109prepare() {
110 cd "$srcdir/$pkgname"
111
112 # makepkg evaluates source=() before the git source is cloned, so the
113 # version and checksum cannot be read from the tree at that point. They are
114 # copied above and asserted against their source of truth here, so drift
115 # fails the build instead of quietly packaging a different payload.
116 local pinned_version pinned_sha
117 pinned_version="$(node -p 'require("./nix/upstream-linux-packages.json").version')"
118 pinned_sha="$(node -p 'require("./nix/upstream-linux-packages.json").amd64.sha256')"
119 if [ "$pinned_version" != "$_appver" ] || [ "$pinned_sha" != "${sha256sums[1]}" ]; then
120 echo "error: PKGBUILD pins $_appver/${sha256sums[1]}, nix/upstream-linux-packages.json pins $pinned_version/$pinned_sha" >&2
121 return 1
122 fi
123
124 # The in-app Computer Use UI is opened via the env flag in build().
125 # record-and-replay pulls in chronicle-skysight through its feature.json.
126 cat > linux-features/features.json <<'JSON'
127{
128 "enabled": [
129 "copilot-reasoning-effort",
130 "read-aloud",
131 "read-aloud-mcp",
132 "remote-control-ui",
133 "remote-mobile-control",
134 "cli-model-visibility",
135 "computer-use-linux",
136 "tray-usage",
137 "frameless-titlebar",
138 "directory-only-working-tree-watch",
139 "node-repl-reaper",
140 "mcp-helper-reaper",
141 "preferred-editor-file-links",
142 "pet-overlay",
143 "persistent-status-panel",
144 "authored-message-visibility",
145 "project-task-sort",
146 "project-group-last-updated-sort",
147 "model-picker-default-presets",
148 "record-and-replay",
149 "agent-workspace",
150 "automation-extensions",
151 "filesystem-root-follow-ups"
152 ],
153 "settings": {
154 "model-picker-default-presets": {
155 "presets": [
156 {"model": "gpt-6-luna", "effort": "medium"},
157 {"model": "gpt-6-astra", "effort": "medium", "default": true},
158 {"model": "gpt-6.1-sol", "effort": "high"}
159 ]
160 }
161 }
162}
163JSON
164}
165
166build() {
167 cd "$srcdir/$pkgname"
168 # Let the upstream toolchain own its compile flags; makepkg defaults can
169 # break the prebuilt-runtime ABI.
170 unset CFLAGS CXXFLAGS LDFLAGS
171
172 export PACKAGE_WITH_UPDATER=0 # updates come from pacman
173 export CODEX_LINUX_ENABLE_COMPUTER_USE_UI=1 # expose the in-app Computer Use UI
174 # Have install.sh write the patch report so check() can validate it.
175 export CODEX_PATCH_REPORT_JSON="$srcdir/patch-report.json"
176
177 # Feature stage hooks copy prebuilt release binaries into the app tree.
178 # The Makefile target owns which crate each enabled feature needs, so it
179 # reads the features.json prepare() wrote rather than repeating that map.
180 make build-native-feature-helpers
181
182 # Pass the payload positionally: without a path install.sh resolves the
183 # package through signed APT metadata and picks up whatever version is
184 # current, defeating the pin. Patches app.asar, rebuilds native modules,
185 # builds the Rust backends, runs feature stage hooks. --fresh is
186 # non-interactive.
187 ./install.sh --fresh "$srcdir/$_debfile"
188}
189
190check() {
191 # Patch gate: every makepkg (CI + AUR users) validates that the
192 # required-upstream patches actually applied against the pinned official
193 # Linux package. Fails if a required patch was skipped or failed.
194 cd "$srcdir/$pkgname"
195 node scripts/ci/validate-patch-report.js "$srcdir/patch-report.json" --profile upstream-build
196}
197
198package() {
199 cd "$srcdir/$pkgname"
200 export PACKAGE_WITH_UPDATER=0
201
202 # Variables the staging helpers expect; stage straight into $pkgdir. The
203 # updater-off path skips polkit/systemd/update-builder.
204 export REPO_DIR="$PWD"
205 export APP_DIR="$PWD/codex-app"
206 export PACKAGE_NAME="$_appname"
207 export PACKAGE_DISPLAY_NAME="Codex Desktop"
208 export PACKAGE_COMMENT="Run Codex Desktop on Linux"
209 export ICON_SOURCE="$PWD/assets/codex.png"
210 export DESKTOP_TEMPLATE="$PWD/packaging/linux/codex-desktop.desktop"
211 export PACKAGED_RUNTIME_SOURCE="$PWD/packaging/linux/codex-packaged-runtime.sh"
212
213 . "$PWD/scripts/lib/package-common.sh"
214
215 ensure_app_layout
216 assert_official_payload_architecture amd64
217 stage_common_package_files "$pkgdir"
218 write_launcher_stub "$pkgdir"
219
220 install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
221}
222

Changes since previous scan

--- PKGBUILD @ 2026-10-29 00:13
+++ PKGBUILD @ 2026-11-01 00:21
@@ -1,44 +1,49 @@
# Maintainer: distsystem <dev@dist.systems>
-# Codex Desktop for Linux — distsystem soft-fork.
+# Codex Desktop for Linux, distsystem soft-fork.
#
-# Converts OpenAI's macOS Codex payload into a Linux Electron tree. Pinned to a
-# patch-validated version (the appcast-versioned arm64 zip; _appver is kept in
-# sync with flake.nix's codexVersion). Sourced from main (rolling): the
-# distsystem fork stays rebased on upstream/main, and main is force-pushed only
-# after CI validates the cross-combination, so main is always last-known-good
-# — no separate tag needed.
+# Patches OpenAI's official Linux package into the fork's distribution, pinned
+# to the version nix/upstream-linux-packages.json carries so a build always
+# targets the payload the patches were validated against. Sourced from main
+# (rolling): the distsystem fork stays rebased on upstream/main, and main is
+# force-pushed only after CI validates the cross-combination, so main is always
+# last-known-good, with no separate tag needed.
#
-# This is NOT the PKGBUILD.template path: that template is the updater-rebuild
-# shell (rendered by build-pacman.sh, bundled into the update-builder and
-# referenced by updater/src/builder.rs). This file is a standalone PKGBUILD
-# for the no-updater pacman/AUR install path; updates come from pacman.
+# This is a standalone PKGBUILD for the no-updater pacman/AUR install path;
+# updates come from pacman. packaging/linux/PKGBUILD.template is a different
+# path: the updater-rebuild shell rendered by build-pacman.sh, bundled into the
+# update-builder and referenced by updater/src/builder.rs.
pkgname=codex-desktop-linux
-# _appver / pkgver must match repo-root CODEX_VERSION (the single source of
-# truth that flake.nix and scripts/dev.sh also read). makepkg needs _appver
-# at source=() eval time, before the git source is cloned, so the file
-# cannot be read here — prepare() asserts equality and fails the build if
-# this PKGBUILD drifts away from CODEX_VERSION.
-_appver=26.707.31428
-pkgver=26.707.31428
+# Copied from nix/upstream-linux-packages.json; prepare() asserts they agree.
+_appver=26.1023.51421
+pkgver=26.1023.51421
pkgrel=1
-pkgdesc="Codex Desktop for Linux — distsystem soft-fork (versioned-zip pinned, no auto-updater)"
+pkgdesc="Codex Desktop for Linux, distsystem soft-fork (official Linux package pinned, no auto-updater)"
arch=('x86_64')
url="https://github.com/distsystem/codex-desktop-linux"
license=('MIT')
+# Runtime libraries the official ChatGPT ELF links against, matching
+# packaging/linux/PKGBUILD.template minus the updater's polkit.
depends=(
- 'python'
- # Electron runtime libraries
+ 'curl'
+ 'nodejs'
+ 'xdg-utils'
'alsa-lib'
'at-spi2-core'
'atk'
'cairo'
'dbus'
+ 'expat'
+ 'gdk-pixbuf2'
'glib2'
+ 'graphite'
'gtk3'
'libcups'
'libdrm'
+ 'libglvnd'
+ 'libnotify'
+ 'libusb'
'libx11'
'libxcb'
'libxcomposite'
@@ -50,11 +55,16 @@
'mesa'
'nspr'
'nss'
+ 'openssl'
'pango'
+ 'systemd-libs'
+ 'tpm2-tss'
+ 'xz'
)
makedepends=(
'git' # clone the distsystem fork (rolling main)
- '7zip' # extract the macOS app payload
+ 'dpkg' # dpkg-deb: read and unpack the official Linux package
+ 'python' # candidate promotion helpers
'nodejs' # asar patch, electron-rebuild, feature stage hooks, validate-patch-report
'npm' # native module install (better-sqlite3, node-pty)
'rust' # cargo: Computer Use + read-aloud-mcp backends
@@ -77,14 +87,15 @@
conflicts=('codex-desktop')
options=('!debug' '!strip')
install="$pkgname.install"
+_debfile="chatgpt_${_appver}_amd64.deb"
source=(
"$pkgname::git+https://github.com/distsystem/codex-desktop-linux.git#branch=main"
- "Codex-$_appver.zip::https://persistent.oaistatic.com/codex-app-prod/ChatGPT-darwin-arm64-$_appver.zip"
+ "$_debfile::https://persistent.oaistatic.com/codex-app-prod/linux/deb/pool/main/c/chatgpt/$_debfile"
)
sha256sums=('SKIP'
- 'ffdc351a507105d55d7464e3340302c758b8a54b926711c4b15bf373ccb47d64')
-# install.sh runs 7z on the payload itself; let it own the extraction.
-noextract=("Codex-$_appver.zip")
+ '4484dc2b54fc0978beb23b8d8d717494e4e0b4fbeab0a876739105e50b44de5a')
+# install.sh runs dpkg-deb on the payload itself; let it own the extraction.
+noextract=("$_debfile")
# Installed app identity stays "codex-desktop": matches the Electron WM_CLASS,
# the ~/.config/codex-desktop settings dir, and provides/conflicts.
@@ -98,18 +109,57 @@
prepare() {
cd "$srcdir/$pkgname"
- local sot
- sot=$(<CODEX_VERSION)
- sot=${sot%$'\n'}
- if [ "$sot" != "$_appver" ]; then
- echo "error: PKGBUILD _appver=$_appver but repo CODEX_VERSION=$sot - update both" >&2
+ # makepkg evaluates source=() before the git source is cloned, so the
+ # version and checksum cannot be read from the tree at that point. They are
+ # copied above and asserted against their source of truth here, so drift
+ # fails the build instead of quietly packaging a different payload.
+ local pinned_version pinned_sha
+ pinned_version="$(node -p 'require("./nix/upstream-linux-packages.json").version')"
+ pinned_sha="$(node -p 'require("./nix/upstream-linux-packages.json").amd64.sha256')"
+ if [ "$pinned_version" != "$_appver" ] || [ "$pinned_sha" != "${sha256sums[1]}" ]; then
+ echo "error: PKGBUILD pins $_appver/${sha256sums[1]}, nix/upstream-linux-packages.json pins $pinned_version/$pinned_sha" >&2
return 1
fi
- # Enable every Linux feature; the in-app Computer Use UI is opened via the
- # env flag in build().
+ # The in-app Computer Use UI is opened via the env flag in build().
+ # record-and-replay pulls in chronicle-skysight through its feature.json.
cat > linux-features/features.json <<'JSON'
-{"enabled":["open-target-discovery","zed-opener","copilot-reasoning-effort","read-aloud","read-aloud-mcp","conversation-mode","remote-control-ui","remote-mobile-control","cli-model-visibility"]}
+{
+ "enabled": [
+ "copilot-reasoning-effort",
+ "read-aloud",
+ "read-aloud-mcp",
+ "remote-control-ui",
+ "remote-mobile-control",
+ "cli-model-visibility",
+ "computer-use-linux",
+ "tray-usage",
+ "frameless-titlebar",
+ "directory-only-working-tree-watch",
+ "node-repl-reaper",
+ "mcp-helper-reaper",
+ "preferred-editor-file-links",
+ "pet-overlay",
+ "persistent-status-panel",
+ "authored-message-visibility",
+ "project-task-sort",
+ "project-group-last-updated-sort",
+ "model-picker-default-presets",
+ "record-and-replay",
+ "agent-workspace",
+ "automation-extensions",
+ "filesystem-root-follow-ups"
+ ],
+ "settings": {
+ "model-picker-default-presets": {
+ "presets": [
+ {"model": "gpt-6-luna", "effort": "medium"},
+ {"model": "gpt-6-astra", "effort": "medium", "default": true},
+ {"model": "gpt-6.1-sol", "effort": "high"}
+ ]
+ }
+ }
+}
JSON
}
@@ -124,19 +174,23 @@
# Have install.sh write the patch report so check() can validate it.
export CODEX_PATCH_REPORT_JSON="$srcdir/patch-report.json"
- # Pin the payload via positional arg — install-helpers.sh resets the env
- # var to empty, so $PROVIDED_DMG_PATH does nothing. Without this the
- # script falls back to downloading the rolling Codex.dmg, defeating the
- # whole versioned-zip pin.
- # Patches app.asar, rebuilds native modules, builds the Rust backends,
- # runs feature stage hooks. --fresh is non-interactive.
- ./install.sh --fresh "$srcdir/Codex-$_appver.zip"
+ # Feature stage hooks copy prebuilt release binaries into the app tree.
+ # The Makefile target owns which crate each enabled feature needs, so it
+ # reads the features.json prepare() wrote rather than repeating that map.
+ make build-native-feature-helpers
+
+ # Pass the payload positionally: without a path install.sh resolves the
+ # package through signed APT metadata and picks up whatever version is
+ # current, defeating the pin. Patches app.asar, rebuilds native modules,
+ # builds the Rust backends, runs feature stage hooks. --fresh is
+ # non-interactive.
+ ./install.sh --fresh "$srcdir/$_debfile"
}
check() {
# Patch gate: every makepkg (CI + AUR users) validates that the
- # required-upstream patches actually applied against the pinned versioned
- # zip. Fails if a required patch was skipped or failed.
+ # required-upstream patches actually applied against the pinned official
+ # Linux package. Fails if a required patch was skipped or failed.
cd "$srcdir/$pkgname"
node scripts/ci/validate-patch-report.js "$srcdir/patch-report.json" --profile upstream-build
}
@@ -159,6 +213,7 @@
. "$PWD/scripts/lib/package-common.sh"
ensure_app_layout
+ assert_official_payload_architecture amd64
stage_common_package_files "$pkgdir"
write_launcher_stub "$pkgdir"

Scan history

Scanned at (UTC)SeverityRules
2026-11-01 00:21:48 Low 2
2026-10-31 00:07:41 Low 2
2026-10-30 05:55:14 Medium 1
2026-10-30 00:29:30 Low 2
2026-10-29 13:52:19 Medium 1
2026-10-29 00:13:55 Medium 2
2026-10-28 00:06:54 Medium 2
2026-10-27 00:23:28 Medium 2
2026-10-26 00:12:40 Medium 2
2026-10-25 00:20:48 Medium 2
2026-10-24 00:14:55 Medium 2
2026-10-23 00:02:19 Medium 2
2026-10-22 00:13:10 Medium 2
2026-10-21 00:12:50 Medium 2
2026-10-20 00:10:31 Medium 2
2026-10-19 00:03:55 Medium 2
2026-10-18 00:06:55 Medium 2
2026-10-17 00:21:55 Medium 2
2026-10-16 00:12:47 Medium 2
2026-10-15 00:28:05 Medium 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion