Allow Python script-only packages - #49070
Conversation
**Related issue:** Resolves #48393 Adds `.py` as an accepted script-only software package on the server — mirroring `.sh`, assigned the new `py_packages` source and installable on macOS and Linux hosts. # Checklist for submitter - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually
**Related issue:** Resolves #48394 Adds `.py` to the custom-package upload form and software details page, accepted and detected as a script-only package (advanced options follow `.sh`/`.ps1`), shown with the Python icon and per-platform file-type tooltips, and mapped to the `py_packages` source that renders as "Script-only package (macOS & Linux)". # Checklist for submitter - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually ## Manual QA - [x] Verified live in the browser against a dev server
There was a problem hiding this comment.
Pull request overview
Adds first-class support for uploading Python (.py) script-only software packages, treating them like existing .sh/.ps1 script packages: the uploaded file contents become install_script, the installer is stored under a new py_packages source, and installs are allowed on Linux and macOS (via the existing unix-like exception).
Changes:
- Backend: recognize
.pyas a script package, map it topy_packages, store asplatform=linux, and allow installs on unix-like hosts. - Frontend: accept
.pyuploads, display correct platform/tooltips, and render a Python file icon where appropriate. - Tests: add/extend unit, integration, and GitOps tests to cover
.pyupload/validation/install behavior and UI rendering.
Reviewed changes
Copilot reviewed 26 out of 27 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| server/service/testdata/software-installers/script.py | Adds a .py script fixture for installer testdata. |
| server/service/integration_enterprise_test.go | Adds integration coverage for .py upload validation and persistence behavior. |
| server/fleet/software_installer.go | Adds py_packages source mapping, linux platform mapping, and .py script package detection. |
| server/fleet/software_installer_test.go | Extends unit tests for .py platform/source/script-package helpers. |
| ee/server/service/software_installers.go | Extends install platform exception to .py, adds .py to validation/error strings, script metadata mapping, and script:// validation messaging. |
| ee/server/service/software_installers_test.go | Adds unit tests for python script validation/metadata and unix-like install allowance. |
| cmd/fleetctl/integrationtest/gitops/software_test.go | Updates expected unsupported-file-type errors to include .py. |
| cmd/fleetctl/fleetctl/generate_gitops_test.go | Extends GitOps generation tests to include .py script packages. |
| frontend/utilities/software_uninstall_scripts.ts | Treats .py like other script-only packages for default uninstall-script behavior. |
| frontend/utilities/software_install_scripts.ts | Treats .py like other script-only packages for default install-script behavior. |
| frontend/utilities/file/fileUtils.tsx | Adds .py → “macOS & Linux” platform display mapping. |
| frontend/utilities/file/fileUtils.tests.tsx | Adds .py coverage to file utils tests. |
| frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsPage.tsx | Threads source through to installer details widget. |
| frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareInstallerCard/InstallerDetailsWidget/InstallerDetailsWidget.tsx | Renders a Python file icon for py_packages. |
| frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareInstallerCard/InstallerDetailsWidget/InstallerDetailsWidget.tests.tsx | Adds tests for Python vs generic package icon selection. |
| frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/LibraryItemAccordion/LibraryItemAccordion.tsx | Threads source into the shared installer widget for icon selection. |
| frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/helpers.tests.ts | Adds a test ensuring py_packages titles are treated as script packages. |
| frontend/pages/SoftwarePage/components/forms/PackageForm/PackageForm.tsx | Accepts .py uploads, displays .py icon, and updates per-platform supported-type tooltips. |
| frontend/pages/SoftwarePage/components/cards/SoftwareDetailsSummary/SoftwareDetailsSummary.tsx | Updates comment to reflect broader “no version/host data” sources. |
| frontend/pages/hosts/details/DeviceUserPage/helpers.ts | Uses SCRIPT_PACKAGE_SOURCES for script-only detection (now including .py). |
| frontend/pages/hosts/details/DeviceUserPage/helpers.tests.ts | Adds test coverage for .py script setup-step detection. |
| frontend/pages/DashboardPage/cards/ActivityFeed/GlobalActivityItem/GlobalActivityItem.tests.tsx | Adds activity feed test coverage for .py script package statuses. |
| frontend/interfaces/software.ts | Adds py_packages conversions and includes .py in SCRIPT_PACKAGE_SOURCES. |
| frontend/interfaces/setup.ts | Updates comments/examples to include .py script packages. |
| frontend/interfaces/package_type.ts | Adds "py" to script-only package types. |
| frontend/components/ActivityDetails/InstallDetails/SoftwareScriptDetailsModal/SoftwareScriptDetailsModal.tsx | Updates comment/examples to include py_packages. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis change adds Python ( Possibly related issues
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #49070 +/- ##
==========================================
- Coverage 68.17% 68.16% -0.01%
==========================================
Files 3849 3856 +7
Lines 243469 244189 +720
Branches 12973 13165 +192
==========================================
+ Hits 165989 166457 +468
- Misses 62481 62689 +208
- Partials 14999 15043 +44
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
**Related issue:** Resolves #49369 Self-service install of a `.py` script-only package was rejected on macOS hosts (`Package (.py) can be installed only on linux hosts.`) because `SelfServiceInstallSoftwareTitle` only allowed `.sh` in the unix-like (linux + darwin) exception. Now allows `.py` too, matching the admin install path (`installSoftwareTitleUsingInstaller`). # Checklist for submitter - [x] Changes file: N/A — unreleased fix on the `#41470` feature branch; the feature PR (#49070) carries the changes file. - [x] Input data is properly validated (platform-gate fix only; no new input handling, SQL, or shell interpolation). ## Testing - [x] Added/updated automated tests — `TestSelfServiceInstallPyScriptOnUnixLike` (linux + darwin); confirmed it fails without the fix and passes with it. - [x] QA'd all new/changed functionality manually — live on a macOS host: self-service `.py` install went from HTTP 400 → 202 → `installed` (script executed), with no regression to `.sh`/Linux/Windows behavior.
**Related issue:** Resolves #49370 `fleetctl gitops` rejected a local `path:`-referenced `.py` software package client-side with `unsupported extension ".py"`, even though a `url:`-referenced `.py` worked end-to-end. The package-path `switch` and the two `HydrateToPackageLevel` gates (team-level advanced options + icon) only recognized `.sh`/`.ps1`. They now use `fleet.IsScriptPackage`, so `.py` is accepted — and future script types won't drift out of sync. # Checklist for submitter - [x] Changes file: N/A — unreleased fix on the `#41470` feature branch; the feature PR (#49070) carries the changes file. - [x] Input data is properly validated (extension-gating fix only; no new input handling, SQL, or shell interpolation). ## Testing - [x] Added/updated automated tests — `TestScriptOnlyPackagesPathPy` (path `.py` with team-level self-service, uninstall/post-install scripts, pre-install query, and icon); confirmed it fails without the fix and passes with it. Also updated a sibling test's error-string assertion. - [x] QA'd all new/changed functionality manually — live before/after with the real `fleetctl` binary: unfixed → `unsupported extension ".py"`; fixed → `gitops dry run succeeded`, and a real apply persisted the package with `source: py_packages`.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/spec/gitops.go (1)
286-302: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse
isScriptvariable.Since
isScriptis already evaluated at the beginning of the function, you can reuse it here instead of callingfleet.IsScriptPackage(ext)again.♻️ Proposed refactor
// Icon should be allowed at the team level yaml for script packages which must be specified as a path if spec.Icon.Path != "" { - if !fleet.IsScriptPackage(ext) { + if !isScript { return packageLevel, fmt.Errorf("the software package defined in %s must not have icons, scripts, queries, URL, or hash specified at the team level", *spec.Path) } }🤖 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 `@pkg/spec/gitops.go` around lines 286 - 302, Reuse the existing isScript variable in the icon validation condition instead of calling fleet.IsScriptPackage(ext) again. Keep the surrounding spec.Icon.Path validation and behavior unchanged.
🤖 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.
Nitpick comments:
In `@pkg/spec/gitops.go`:
- Around line 286-302: Reuse the existing isScript variable in the icon
validation condition instead of calling fleet.IsScriptPackage(ext) again. Keep
the surrounding spec.Icon.Path validation and behavior unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b660cea7-b66a-4d14-b6f7-6cfca35d5147
📒 Files selected for processing (5)
ee/server/service/software_installers.goee/server/service/software_installers_test.gopkg/spec/gitops.gopkg/spec/gitops_test.gopkg/spec/testdata/software/script-only.py
🚧 Files skipped from review as they are similar to previous changes (2)
- ee/server/service/software_installers_test.go
- ee/server/service/software_installers.go
**Related issue:** Resolves #49371 Typing `py` (or `python`) in the command palette didn't surface **Add custom package**, even though `.py` is now an accepted custom-package upload type. The `add-custom-package` entry's `keywords` list enumerated every other extension (`pkg`, `ipa`, `msi`, `exe`, `ps1`, `deb`, `rpm`, `tar.gz`, `sh`) but omitted `py`. Added `py` and `python`. # Checklist for submitter - [x] Changes file: N/A — unreleased fix on the `#41470` feature branch; the feature PR (#49070) carries the changes file. ## Testing - [x] Added/updated automated tests — new `helpers.tests.ts` case asserting the `add-custom-package` entry surfaces on `py`/`python`; confirmed it fails without the fix and passes with it. - [x] QA'd all new/changed functionality manually — live in the browser: with a team selected, searching `py` in the command palette now lists **Add custom package**. <img width="1914" height="518" alt="Screenshot 2026-07-15 at 20 35 23" src="https://github.com/user-attachments/assets/bd764e9a-0389-4f29-a77f-5f77b5090677" />
There was a problem hiding this comment.
🧹 Nitpick comments (1)
frontend/components/CommandPalette/helpers.tests.ts (1)
330-341: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winExercise the actual palette search path.
This test verifies keyword registration, but it never searches for
pyorpython; it would pass even if keyword matching were broken. Invoke the real best-match/filtering logic with both queries and assert thatadd-custom-packageis returned.🤖 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 `@frontend/components/CommandPalette/helpers.tests.ts` around lines 330 - 341, Update the test for “surfaces Add custom package when searching py / python” to exercise the actual palette best-match/filtering path instead of only inspecting keywords. Run the search with both “py” and “python” queries and assert each result includes the “add-custom-package” item, while preserving the existing team context.
🤖 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.
Nitpick comments:
In `@frontend/components/CommandPalette/helpers.tests.ts`:
- Around line 330-341: Update the test for “surfaces Add custom package when
searching py / python” to exercise the actual palette best-match/filtering path
instead of only inspecting keywords. Run the search with both “py” and “python”
queries and assert each result includes the “add-custom-package” item, while
preserving the existing team context.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 174c1abd-2521-40df-a560-5c6c957ef36d
📒 Files selected for processing (2)
frontend/components/CommandPalette/groups/commands.tsfrontend/components/CommandPalette/helpers.tests.ts
Related issue: Resolves #41470
Adds support for uploading Python (
.py) script-only software packages — accepted as script-only (the file contents become the install script; advanced options and automatic install follow.sh/.ps1), assigned the newpy_packagessource, and installable on macOS and Linux hosts across the UI, REST API, and GitOps.Feature branch combining the backend (#48942) and frontend (#48946) sub-PRs.
Checklist for submitter
changes/,orbit/changes/oree/fleetd-chrome/changes.SELECT *is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.Testing
Summary by CodeRabbit
.py) script-only software packages across UI uploads, API/self-service installs, and GitOps parsing..py(and consistent handling of related script fields/options).