diff --git a/src/api/app/controllers/public_controller.rb b/src/api/app/controllers/public_controller.rb
index 1ecafc2a457..2468a6aaff7 100644
--- a/src/api/app/controllers/public_controller.rb
+++ b/src/api/app/controllers/public_controller.rb
@@ -145,7 +145,11 @@ def show_request
# GET /public/binary_packages/:project/:package
def binary_packages
check_package_access(params[:project], params[:package], use_source: false)
- @pkg = Package.find_by_project_and_name(params[:project], params[:package])
+ # Packages of scmsync projects don't exist in the database. follow_project_scmsync_links
+ # builds a read-only instance from the backend package meta so we can still resolve the
+ # project, its repositories and the package name/title/description below.
+ @pkg = Package.get_by_project_and_name(params[:project], params[:package],
+ use_source: false, follow_project_scmsync_links: true)
begin
binaries = Xmlhash.parse(Backend::Api::Search.published_binaries_for_package(params[:project], params[:package]))
diff --git a/src/api/spec/controllers/public_controller_spec.rb b/src/api/spec/controllers/public_controller_spec.rb
index dcda24c8b68..fcfb998ad1d 100644
--- a/src/api/spec/controllers/public_controller_spec.rb
+++ b/src/api/spec/controllers/public_controller_spec.rb
@@ -189,4 +189,49 @@
it { expect(revisions.count).to eq(1) }
end
end
+
+ # NOTE: defined last on purpose. VCR names cassettes for anonymous `it { ... }`
+ # examples after their scoped id, so inserting an example group earlier in this
+ # file would renumber the recorded cassettes of the groups that follow it.
+ describe 'GET #binary_packages for a package of an scmsync project' do
+ let(:scmsync_project) do
+ create(:project, name: 'scmsync_public_controller_project', scmsync: 'https://github.com/example/scmsync-project.git')
+ end
+ let(:package_meta) do
+ <<~XML
+
+ eza title
+ eza description
+
+ XML
+ end
+
+ before do
+ allow(Backend::Api::Search).to receive(:published_binaries_for_package).and_return('')
+ end
+
+ context 'when the package exists on the backend' do
+ before do
+ # scmsync packages don't exist in the database, they are served from the backend
+ allow(Backend::Api::Sources::Package).to receive(:meta).and_return(package_meta)
+
+ get :binary_packages, params: { project: scmsync_project.name, package: 'eza' }
+ end
+
+ it { expect(response).to have_http_status(:success) }
+ it { expect(assigns(:pkg)).to be_a(Package) }
+ it { expect(assigns(:pkg).name).to eq('eza') }
+ it { expect(assigns(:pkg).project).to eq(scmsync_project) }
+ end
+
+ context 'when the package does not exist on the backend' do
+ before do
+ allow(Backend::Api::Sources::Package).to receive(:meta).and_raise(Backend::NotFoundError)
+
+ get :binary_packages, params: { project: scmsync_project.name, package: 'does_not_exist' }
+ end
+
+ it { expect(response).to have_http_status(:not_found) }
+ end
+ end
end