ArtifactFileField.pre_save spuriously rejects uploads named 'artifact*' when MEDIA_ROOT is empty
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 598
- Forks
- 168
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 86
Description
Summary
ArtifactFileField.pre_save uses a fragile prefix check to decide whether an incoming file is already inside artifact storage:
https://github.com/pulp/pulpcore/blob/main/pulpcore/app/models/fields.py#L69-L73
is_in_artifact_storage = file.name.startswith(os.path.join(settings.MEDIA_ROOT, "artifact"))
When settings.MEDIA_ROOT is "" — which is the case for object-storage backends (azure, s3, etc.) — this collapses to:
file.name.startswith("artifact")
file.name for a fresh upload is the client-provided filename. Any uploaded file whose name begins with the substring artifact (e.g. artifact-foo-1.0-1.noarch.rpm) therefore matches, already_in_place is False, and pre_save raises:
ValueError: The file referenced by the Artifact is already present in Artifact storage.
Files must be stored outside this location prior to Artifact creation.
which surfaces to the client as a 500 Internal Server Error on POST /pulp/<domain>/api/v3/artifacts/.
Impact
Any user uploading an artifact whose filename starts with artifact to a deployment with an empty MEDIA_ROOT (object storage) gets a spurious 500. The bug is filename-dependent and backend-dependent, so it is easy to miss.
How it was discovered
A pulp_rpm functional test (test_domains.py::test_artifact_from_file) built an RPM named artifact-<hex>-1.0-1.noarch.rpm and uploaded it via the artifacts endpoint. It failed only on the azure job (empty MEDIA_ROOT); the sibling test using a content- prefix passed.
Suggested fix
The prefix check is meant to detect files that are already physically in artifact storage. It should not rely on a bare startswith against a possibly-empty settings.MEDIA_ROOT, and it arguably should consider the current domain's actual storage location rather than the global setting. Options:
- Normalize/join paths and compare path components instead of doing a raw string prefix match.
- Guard against an empty
MEDIA_ROOTso the check does not degenerate tostartswith("artifact").
Environment
- Reproducible with any object-storage backend where
MEDIA_ROOTis empty (azure/s3), including per-domainFileSystemstorage where the globalsettings.MEDIA_ROOTis still empty.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in pulpcore/app/models/fields.py at the ArtifactFileField.pre_save prefix check, then review pulp_rpm's test_domains.py::test_artifact_from_file and its artifact-prefixed filename. Reproduce the failure with an empty MEDIA_ROOT and verify that the test succeeds for object-storage configurations without rejecting a fresh upload.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100