Skip to content

feat(ci): publish stable releases to the AUR as cap-bin - #3160

Open
Wraient wants to merge 11 commits into
CapSoftware:mainfrom
Wraient:feat/aur-publish
Open

Wraient wants to merge 11 commits into
CapSoftware:mainfrom
Wraient:feat/aur-publish

Conversation

@Wraient

@Wraient Wraient commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Since 0.6.0, every release has shipped an Arch package (cap-bin-*.pkg.tar.zst), but only as a direct download. Arch users install it with pacman -U and never get updates through yay or paru. This PR adds a workflow that publishes each stable release to the AUR as cap-bin.

How it works

  • publish-aur.yml runs when a cap-v{x.y.z} release is published, skipping prereleases. It can also be dispatched manually with a tag.
  • It reads the release's linux-deb link from DOWNLOADS_JSON, the same data /download/versions uses, and downloads the DEB.
  • It runs scripts/build-linux-arch-package.sh with that URL, in the pinned Arch container desktop-release.yml already uses, with --network none.
  • Given a URL, the builder also writes the PKGBUILD it built from and its .SRCINFO, with the source pointed at the CDN asset. The AUR package therefore uses the official package's recipe, dependencies and package-format marker, and later changes to the builder carry over.
  • The workflow checks that the DEB contains the tagged version and uploads both files as an artifact. It then pushes them to ssh://aur@aur.archlinux.org/cap-bin.git, with the AUR host key pinned. It skips the push if the AUR already has a newer version or identical files. If the upstream version matches the AUR's but the recipe changed, it carries the AUR pkgrel forward by one, so the fix reaches installed users as an upgrade instead of a same-version file swap.

Builder changes (without a URL, the output is the same as before):

  • The DEB's source filename now includes the version (Cap_0.6.1_x86_64.deb). AUR helpers reuse build directories, and makepkg uses an existing file of the same name, so a fixed Cap.deb would fail the checksum on every upgrade.
  • Adds the # Maintainer: line the AUR guidelines ask for. Cap Software <hello at cap dot so> is a placeholder; change it to whatever you prefer.

Setup needed from maintainers

  1. Create an AUR account for Cap and add a dedicated SSH public key to it.
  2. Add the private key as the AUR_SSH_PRIVATE_KEY repository secret. Until it exists, the workflow builds and uploads the files, then ends with a warning instead of pushing.
  3. After merging, run publish-aur from main with tag: cap-v0.6.1 (or the latest release) to create the package. A release event runs the workflow from the tagged commit, so tags that predate this PR need this manual run.

The AUR guidelines warn that automated updates don't replace a maintainer's attention. Because this PKGBUILD comes from the same builder as the official package, dependency changes only need to be made once. The account should still watch the package's comments and out-of-date flags.

Verification

Check Result
Builder without a URL (the release CI path), real 0.6.1 DEB, compared with the published cap-bin-0.6.1-1 .PKGINFO identical apart from build date and packager. Every payload file is identical: paths, modes, sizes, sha256.
Builder with a URL, in the pinned container with --network none makepkg uses the versioned DEB already in place, the checksum passes, and the package is the same
Fresh AUR-style build from only the generated PKGBUILD and .SRCINFO Downloads from the CDN asset URL, the checksum passes, and the package is the same. .SRCINFO matches makepkg --printsrcinfo.
namcap PKGBUILD Clean
actionlint 1.7.12 with shellcheck 0.11.0 Clean
Workflow run: blocks run locally against cap-v0.6.1 (resolve, download, build) Pass. Rejects v0.6.1, cap-v0.6, a nightly tag, cap-v0.5.9 (no linux-deb link) and a tag with no release.
Push logic against a local bare repo standing in for the AUR First publish works, a re-run does nothing, it skips when the AUR is newer, and it updates when the AUR is older
Merge with #2934 Merges cleanly in either order. The combined builder writes epoch = 1, the version check compares only pkgver, and the downgrade check includes the epoch.

Not tested: the real SSH push to aur.archlinux.org, which needs an AUR account. The pinned ed25519 host key matches the fingerprint published on aur.archlinux.org and the one in archlinux/infrastructure's docs/ssh-known_hosts.txt. The release trigger also assumes the GitHub release is published by a maintainer or the Discord bot, not by a workflow's GITHUB_TOKEN, because releases published with that token don't start other workflows. Nothing in this repo publishes them that way. If the next release doesn't start publish-aur, a manual dispatch with its tag does the same job.

namcap on the package also reports hicolor-icon-theme as a missing dependency. The current builder already has that gap, so this PR leaves it; it can be added to depends in a follow-up.

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with a non-blocking improvement needed for republishing corrected recipes.

Findings

  1. P2 Recipe fixes miss installed users ▶
Fix with agent prompt
### Issue 1
.github/workflows/publish-aur.yml:135-138
Re-running `publish-aur` after changing the recipe can push different files with the same package version. The builder always writes `pkgrel=1`, and this step allows equal versions whenever the files differ. For example, correcting `depends` and dispatching the same release tag updates the AUR recipe, but installed users see no newer version to upgrade to.

Increment `pkgrel` for same-release package changes, or reject changed recipes with an unchanged package version.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds stable-release publication to the AUR as cap-bin.

  • Stable Cap releases now reach Arch users through the AUR.

Acknowledged by Wraient: the maintainer address is an intentional placeholder; the existing hicolor-icon-theme gap is deferred; older tags require manual dispatch; releases published through GITHUB_TOKEN may require manual dispatch.

Reviews (1) · Last reviewed commit: "feat(ci): publish stable releases to the..." · Reviewed by Greptile

Add a publish-aur workflow that runs when a stable cap-v release is
published (or on manual dispatch with a tag). It downloads the release's
linux-deb asset from DOWNLOADS_JSON, builds it with the existing Arch
package builder in the pinned offline Arch container, and pushes the
resulting PKGBUILD and .SRCINFO to ssh://aur@aur.archlinux.org/cap-bin.git
using the AUR_SSH_PRIVATE_KEY secret. Without the secret it only builds and
uploads the files as an artifact.

The builder takes an optional download URL. With one, it sources the
versioned DEB from that URL and also writes the PKGBUILD and .SRCINFO, so
the AUR package is built from the same recipe as the release's own pacman
package. The DEB file name is now versioned, because AUR helpers reuse
build directories and would otherwise find a stale Cap.deb.
@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

@Wraient is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-25T00:16:38.714773Z
We couldn’t complete this review. Comment @codex review to try again.
045d6c5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment on lines +135 to +138
cp "$PACKAGE/PKGBUILD" "$PACKAGE/.SRCINFO" "$AUR/"
cd "$AUR"
git add PKGBUILD .SRCINFO
if git diff --cached --quiet; then

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.

P2 Recipe fixes miss installed users

Re-running publish-aur after changing the recipe can push different files with the same package version. The builder always writes pkgrel=1, and this step allows equal versions whenever the files differ. For example, correcting depends and dispatching the same release tag updates the AUR recipe, but installed users see no newer version to upgrade to.

Increment pkgrel for same-release package changes, or reject changed recipes with an unchanged package version.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/publish-aur.yml
Line: 135-138

Comment:
**Recipe fixes miss installed users**

Re-running `publish-aur` after changing the recipe can push different files with the same package version. The builder always writes `pkgrel=1`, and this step allows equal versions whenever the files differ. For example, correcting `depends` and dispatching the same release tag updates the AUR recipe, but installed users see no newer version to upgrade to.

Increment `pkgrel` for same-release package changes, or reject changed recipes with an unchanged package version.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in ffc34f8. When the AUR already carries the same upstream version and the generated PKGBUILD differs, the push step now carries the AUR pkgrel forward by one in both the PKGBUILD and .SRCINFO before pushing, so a recipe-only change reaches installed users as an upgrade. Verified against a local bare repo standing in for the AUR: changed recipe at the same version publishes as 0.6.1-2, an identical re-run does nothing, a newer version still publishes at pkgrel 1, and an older version is still skipped.

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks! Can you get Greptile to 5/5? Then we'll take a look.

Re-running publish-aur for an already published version with a corrected
recipe pushed the new files under the same pkgver-pkgrel, so installed
users never saw an upgrade. When the upstream version matches the AUR's
and the PKGBUILD differs, carry the AUR pkgrel forward by one in both
the PKGBUILD and .SRCINFO before pushing.

@superagent-security superagent-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Superagent found 1 security concern(s).

Comment thread .github/workflows/publish-aur.yml Outdated
! cmp -s "$AUR/PKGBUILD" "$PACKAGE/PKGBUILD"; then
# Same upstream version but a changed recipe: installed users
# only upgrade on a higher pkgrel, so carry the AUR's forward.
NEW_PKGREL=$(( $(pkgrel_of "$AUR/.SRCINFO") + 1 ))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: AUR-controlled .SRCINFO pkgrel is evaluated as bash arithmetic in the secret-bearing publish job

AUR-controlled .SRCINFO pkgrel is fed into bash $(( )) while AUR_SSH_PRIVATE_KEY is in scope.

Validate pkgrel as a plain integer before arithmetic and never evaluate remote .SRCINFO values in the shell.

AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.

<file name=".github/workflows/publish-aur.yml">
<violation number="1" location=".github/workflows/publish-aur.yml:144">
<priority>P1</priority>
<title>AUR-controlled .SRCINFO pkgrel is evaluated as bash arithmetic in the secret-bearing publish job</title>
<evidence>Added line 144 runs `NEW_PKGREL=$(( $(pkgrel_of "$AUR/.SRCINFO") + 1 ))`. `pkgrel_of` (lines 130-132) prints the `pkgrel` field from the AUR repository cloned at line 123, with no numeric validation. Bash re-evaluates array subscripts and command substitutions inside arithmetic operands, so a malicious `pkgrel` such as an array-subscript expression containing a command substitution (payload redacted) executes that command before `NEW_PKGREL` is computed. The same step holds `AUR_SSH_PRIVATE_KEY` in its environment (line 107) and has network access for the AUR clone. The existing `cap-bin` AUR package is maintained by a third-party AUR account, so the cloned `.SRCINFO` is not Cap-controlled; even after Cap obtains the package, co-maintainers or a compromised AUR repo can supply the value. The injected command can read/exfiltrate the key and rewrite `$PACKAGE/PKGBUILD` and `$PACKAGE/.SRCINFO` before the `cp` and `git push` at lines 150-158 publish them. This is distinct from the PR discussion's pkgrel-upgrade correctness note: the security issue is the evaluation of remote metadata in shell arithmetic.</evidence>
<recommendation>Read `pkgrel` into a variable and validate it against a strict integer pattern before any arithmetic, failing closed on non-numeric AUR metadata. Do not interpolate values from the cloned `.SRCINFO` into `$(( ))`; parse them as data only. Confirm the `cap-bin` AUR package is actually controlled by Cap before enabling `AUR_SSH_PRIVATE_KEY`, and consider verifying the expected AUR owner/maintainer before using the repository contents.</recommendation>
</violation>
</file>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, this one checks out. I verified it locally: a crafted pkgrel using an array-subscript command substitution executed under the old $(( $(pkgrel_of ...) + 1 )), while the fixed code rejects it.

Fixed in 1955c49: the AUR pkgrel is now read into a variable and validated against ^[0-9]+$ before any arithmetic, failing closed with an error on non-numeric AUR metadata. The valid path is unchanged (e.g. 7 still carries forward to 8).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fix acknowledged. Reading pkgrel into a variable, validating against ^[0-9]+$, and failing closed before arithmetic directly addresses the shell evaluation risk. Local verification of the exploit and the targeted fix are appreciated.

The AUR clone is not Cap-controlled, and bash re-evaluates command
substitutions inside $(( )), so a crafted pkgrel in the cloned
.SRCINFO could execute commands with AUR_SSH_PRIVATE_KEY in scope.
Read it into a variable, reject anything but digits, and fail closed.

This branch has not been deployed

No deployments
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.

2 participants