-
Notifications
You must be signed in to change notification settings - Fork 493
Validate uv package names against PEP 508 before uv pip show
#51016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
a6b2fde
34fd315
c716df6
242d733
dbefd32
304ca65
d6b4bb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,8 @@ import ( | |
| "fmt" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/github/gh-aw/pkg/fileutil" | ||
| ) | ||
|
|
||
| // TestRejectHyphenPrefixPackages tests the shared helper that guards against | ||
|
|
@@ -395,3 +397,23 @@ func TestValidatePipPackageName(t *testing.T) { | |
| }) | ||
| } | ||
| } | ||
|
|
||
| // TestValidateUvPackages_RejectsInvalidPackageName verifies that uv package names | ||
| // which do not conform to the PyPI naming rules are rejected before being passed | ||
| // as arguments to the uv CLI. | ||
| func TestValidateUvPackages_RejectsInvalidPackageName(t *testing.T) { | ||
| if _, err := fileutil.ResolveExecutablePath("uv"); err != nil { | ||
| t.Skip("uv not installed - skipping uv argument validation test") | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 242d733: package-name syntax validation (including the |
||
|
|
||
| compiler := NewCompiler() | ||
| err := compiler.validateUvPackages(&WorkflowData{ | ||
| CustomSteps: "uvx pkg;whoami", | ||
| }) | ||
| if err == nil { | ||
| t.Fatal("expected error for invalid uv package name but got none") | ||
| } | ||
| if !strings.Contains(err.Error(), "invalid pip package name") { | ||
| t.Errorf("expected error to mention invalid package name, got: %v", err) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -188,7 +188,18 @@ func (c *Compiler) validateUvPackages(workflowData *WorkflowData) error { | |
| pkgName = pkg[:eqIndex] | ||
| } | ||
|
|
||
| // Validate the package name against PyPI naming rules (PEP 508) before | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This rejects valid versioned 💡 Missing `@` version-specifier handling breaks legitimate uvx workflows
pkgName := pkg
if eqIndex := strings.Index(pkg, "=="); eqIndex > 0 {
pkgName = pkg[:eqIndex]
}
Fix: strip an pkgName := pkg
if eqIndex := strings.Index(pkg, "=="); eqIndex > 0 {
pkgName = pkg[:eqIndex]
} else if atIndex := strings.Index(pkg, "@"); atIndex > 0 {
pkgName = pkg[:atIndex]
}This is a real behavioral regression, not just a style nit — it will break existing CI workflows that pin uvx tool versions with
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 242d733: added |
||
| // passing it as a command argument to uv (argument injection guard). | ||
| if err := validatePipPackageName(pkgName); err != nil { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 242d733: added |
||
| pipValidationLog.Printf("Invalid uv package name %s: %v", pkgName, err) | ||
| errors = append(errors, fmt.Sprintf("uv package '%s' is invalid: %v", pkg, err)) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 242d733: invalid-name failures are now collected separately and returned immediately as a distinct
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invalid-name failures are merged into the same 💡 Aggregate error message is wrong for invalid-name failuresFurther down in this function, Suggested fix: track invalid-name errors in a separate slice/counter and surface a distinct, accurate error message for them (e.g. "invalid package name(s): ...") instead of folding them into the generic network/cache guidance.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 242d733: invalid-name failures are now tracked separately and returned as a distinct error before any network/cache validation, with a message about PEP 508 naming rules instead of the generic network/cache guidance. |
||
| continue | ||
| } | ||
|
|
||
| // Use uv pip show to check if package exists on PyPI | ||
| // #nosec G204 -- uvPath is resolved from the hardcoded executable name "uv" via | ||
| // fileutil.ResolveExecutablePath; pkgName is validated above by validatePipPackageName | ||
| // against the strict PyPI PEP 508 allowlist. | ||
| cmd := exec.Command(uvPath, "pip", "show", pkgName, "--no-cache") | ||
| _, err := cmd.CombinedOutput() | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This regression test silently
t.Skips in any CI environment withoutuvinstalled, meaning the argument-injection guard being added in this PR may never actually run in CI.💡 Security regression test can silently never execute
validateUvPackageshas two code paths: theuv-based path (where this PR adds the fix) and a pip-fallback path (validateUvPackagesWithPip) used whenuvis absent, which the PR description itself says treats invalid names as warnings, not errors. If the CI runner lacksuv, this test — the only regression coverage for the new guard — skips entirely and gives false confidence that the injection is blocked.Also note the PR author flagged this exact gap ("Note on the test guard... skips when uv is absent... Worth a second opinion on whether that fallback should also hard-fail") but shipped without resolving it.
Fix: don't gate the test on
uvbeing present. Either (a) callvalidatePipPackageNamedirectly to assert rejection independent of which downstream tool is available, or (b) make the pip-fallback path also hard-fail on invalid names so both paths are equally protected and testable withoutuv.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 242d733: package-name validation now runs before
uv/pipare resolved or invoked, so the test no longer skips whenuvis absent and reliably exercises the guard in CI.