Skip to content

feat(obs-integration): add OBS integration plugin - #210

Open
neyfua wants to merge 21 commits into
noctalia-dev:mainfrom
neyfua:obs-integration
Open

feat(obs-integration): add OBS integration plugin#210
neyfua wants to merge 21 commits into
noctalia-dev:mainfrom
neyfua:obs-integration

Conversation

@neyfua

@neyfua neyfua commented Aug 2, 2026

Copy link
Copy Markdown

Plugin

  • Id: neyfua/obs-integration
  • New plugin
  • Update to an existing plugin (version bumped in plugin.toml)

What it does

Manage openSUSE Build Service (OBS) projects and packages directly from the Noctalia bar, without leaving the shell for common tasks.

  • Bar widget — OBS icon toggles the plugin panel; status colors reflect OSC/account state.
  • My Projects — lists every project you own and projects where you maintain packages (verified against OBS roles, so scmsync git-pool false positives are excluded). Search and A-Z/Z-A sort included.
  • Browse packages — opens a project to its packages, showing which are checked out locally.
  • Checkout / remove — one-click osc co for new packages; remove a package locally (with a confirm step), auto-cleaning the project dir when the last package goes.
  • Edit — osc meta for project/package metadata, $EDITOR for _service and .spec, osc vc for .changes, plus a full file listing with per-file remove.
  • Rebuild — trigger osc rebuild for a specific architecture or all.
  • Add/Remove & Commit — run osc ar and osc ci from the checkout with the terminal visible for progress or commit-message editing.
  • Sticky navigation — the panel reopens where you left off (project or package level).
    It's a GUI convenience layer over the osc CLI: no OBS-side changes, credentials live in your normal ~/.config/osc/oscrc.

External dependencies

The plugin shells out to the osc command (listed in dependencies in plugin.toml) for every operation: project/package listing and metadata, checkout, osc vc changelog editing, osc ar add/remove, osc ci commit, and osc rebuild. Authentication is read from the user's existing ~/.config/osc/oscrc; the plugin keeps no separate credentials.

It also spawns $EDITOR (or nano as a fallback) to open _service and .spec files, and uses standard find/ls/rm for local file operations inside the checkout directory.

Testing

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Noctalia version tested against: v5.0.0-beta.7
  • Plugin API level: 9

Screenshots / Videos

image image image image image

Checklist

  • The directory name matches the part of id after the / in plugin.toml exactly.
  • It ships plugin.toml, README.md, thumbnail.webp, and translations/en.json.
  • README.md follows the
    README template, documents
    every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable.
  • I created thumbnail.webp with the thumbnail generator.
  • version follows semver and is bumped in this PR; plugin_api is the oldest API level this plugin requires.
  • Every non-English translation in this PR uses a locale supported by Noctalia core, and I can read, write, and
    understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
  • I did not edit catalog.toml; CI generates it.
  • This PR touches exactly one plugin directory.

Code review attestation

Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:

  • The code is readable and not obfuscated, minified, or generated.
  • It does not download and execute remote code.
  • Every network call, filesystem write, and spawned process is something the description above accounts for.
  • I have the right to publish this code under the license declared in plugin.toml.

@ItsLemmy

ItsLemmy commented Aug 2, 2026

Copy link
Copy Markdown
Contributor
  1. blocking - obs-integration/panel.luau:746

    The rebuild architecture selector never takes effect; every rebuild is
    issued for all architectures.

    ui.select delivers its onChange index to Luau as a string, not a number
    (noctalia-shell src/ui/ui_tree_reconciler.cpp:1522 formats the index into
    a string, and ScriptRuntime::enqueueCallStrings pushes it with
    lua_pushlstring). obs-integration/panel.luau:737 stores that string
    verbatim into rebuildArchIndex, and obs-integration/panel.luau:746 then
    does rebuildOptions[rebuildArchIndex]. A Lua table lookup with the string
    key "1" is not the same key as the number 1, so the lookup always yields
    nil, and rebuildPackage (obs-integration/panel.luau:120) drops the -a flag
    for every selection.

    The same string value is fed back as selectedIndex at
    obs-integration/panel.luau:733. numProp uses std::get_if
    (src/ui/ui_tree_reconciler.cpp:45), so the prop is silently ignored on
    later renders while the widget keeps showing the architecture the user
    picked. The UI therefore reports a targeted rebuild while osc rebuild runs
    against every architecture, which is a real OBS-side side effect.

    Other plugins in this repo already handle the convention, for example
    hypr-screen-mirror/panel.luau:48 uses tonumber(selected) and
    gslapper/panel.luau:912 offsets a 0-based index. Converting with tonumber
    and indexing rebuildOptions[index + 1] fixes it.

  2. non-blocking - obs-integration/panel.luau:41

    validName does not implement the guarantee its own comment at
    obs-integration/panel.luau:39 states ("reject anything that could escape
    the checkout dir ... dots-as-prefix"). The pattern ^[%w:.+%-_]+$ accepts
    "." and "..", so validName("..") returns true.

    Project names reach this guard from OBS server output (osc search at
    obs-integration/panel.luau:442 and the osc api XML parse at
    obs-integration/panel.luau:488) and from the on-disk cache
    (obs-integration/panel.luau:355). A project value of ".." would make
    removePackageLocal (obs-integration/panel.luau:197) build
    <checkout_dir>/../ and rm -rf outside the checkout tree. Exploitation
    requires attacker-influenced OBS data or a tampered cache file, so this is
    not a practical attack, but the guard in front of rm -rf should reject
    names consisting only of dots.

  3. non-blocking - obs-integration/panel.luau:49

    resolveCheckoutDir falls back to "~/OBS" only when checkout_dir is nil. An
    empty string is truthy in Lua, so setting the setting to "" yields an empty
    base path, and removePackageLocal (obs-integration/panel.luau:202) then
    computes projectDir = "/" and runs rm -rf against a filesystem
    root path. Treating an empty or whitespace-only setting as unset would
    close this.

@ItsLemmy
ItsLemmy marked this pull request as draft August 2, 2026 01:46
@neyfua
neyfua marked this pull request as ready for review August 2, 2026 11:45
@neyfua
neyfua marked this pull request as draft August 2, 2026 13:56
@neyfua
neyfua marked this pull request as ready for review August 2, 2026 19:09
@neyfua

neyfua commented Aug 2, 2026

Copy link
Copy Markdown
Author

@ItsLemmy I think it's ready for another review if u have some free time :D

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