summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/snippets/components/show.vue13
-rw-r--r--app/assets/javascripts/snippets/mixins/snippets.js1
-rw-r--r--app/graphql/queries/snippet/snippet.query.graphql1
-rw-r--r--app/graphql/queries/snippet/snippet_blob_content.query.graphql1
-rw-r--r--app/graphql/resolvers/snippets/blobs_resolver.rb24
-rw-r--r--app/graphql/types/snippets/blob_connection_type.rb16
-rw-r--r--app/graphql/types/snippets/blob_type.rb2
-rw-r--r--app/models/snippet.rb10
8 files changed, 52 insertions, 16 deletions
diff --git a/app/assets/javascripts/snippets/components/show.vue b/app/assets/javascripts/snippets/components/show.vue
index 35d88d5ec8e..ee8b00c1f5d 100644
--- a/app/assets/javascripts/snippets/components/show.vue
+++ b/app/assets/javascripts/snippets/components/show.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import eventHub from '~/blob/components/eventhub';
import {
SNIPPET_MARK_VIEW_APP_START,
@@ -23,6 +23,7 @@ export default {
EmbedDropdown,
SnippetHeader,
SnippetTitle,
+ GlAlert,
GlLoadingIcon,
SnippetBlob,
CloneDropdownButton,
@@ -35,6 +36,9 @@ export default {
canBeCloned() {
return Boolean(this.snippet.sshUrlToRepo || this.snippet.httpUrlToRepo);
},
+ hasUnretrievableBlobs() {
+ return this.snippet.hasUnretrievableBlobs;
+ },
},
beforeCreate() {
performanceMarkAndMeasure({ mark: SNIPPET_MARK_VIEW_APP_START });
@@ -66,6 +70,13 @@ export default {
data-qa-selector="clone_button"
/>
</div>
+ <gl-alert v-if="hasUnretrievableBlobs" variant="danger" class="gl-mb-3" :dismissible="false">
+ {{
+ __(
+ 'WARNING: This snippet contains hidden files which might be used to mask malicious behavior. Exercise caution if cloning and executing code from this snippet.',
+ )
+ }}
+ </gl-alert>
<snippet-blob
v-for="blob in blobs"
:key="blob.path"
diff --git a/app/assets/javascripts/snippets/mixins/snippets.js b/app/assets/javascripts/snippets/mixins/snippets.js
index b72befef56b..0b3cca4e53a 100644
--- a/app/assets/javascripts/snippets/mixins/snippets.js
+++ b/app/assets/javascripts/snippets/mixins/snippets.js
@@ -17,6 +17,7 @@ export const getSnippetMixin = {
// Set `snippet.blobs` since some child components are coupled to this.
if (!isEmpty(res)) {
+ res.hasUnretrievableBlobs = res.blobs?.hasUnretrievableBlobs || false;
// It's possible for us to not get any blobs in a response.
// In this case, we should default to current blobs.
res.blobs = res.blobs ? res.blobs.nodes : blobsDefault;
diff --git a/app/graphql/queries/snippet/snippet.query.graphql b/app/graphql/queries/snippet/snippet.query.graphql
index 24b268ec853..5c0c7ebaa1b 100644
--- a/app/graphql/queries/snippet/snippet.query.graphql
+++ b/app/graphql/queries/snippet/snippet.query.graphql
@@ -15,6 +15,7 @@ query GetSnippetQuery($ids: [SnippetID!]) {
sshUrlToRepo
blobs {
__typename
+ hasUnretrievableBlobs
nodes {
__typename
binary
diff --git a/app/graphql/queries/snippet/snippet_blob_content.query.graphql b/app/graphql/queries/snippet/snippet_blob_content.query.graphql
index 005f42ff726..4459a5e4316 100644
--- a/app/graphql/queries/snippet/snippet_blob_content.query.graphql
+++ b/app/graphql/queries/snippet/snippet_blob_content.query.graphql
@@ -12,6 +12,7 @@ query SnippetBlobContent($ids: [ID!], $rich: Boolean!, $paths: [String!]) {
richData @include(if: $rich)
plainData @skip(if: $rich)
}
+ hasUnretrievableBlobs
}
}
}
diff --git a/app/graphql/resolvers/snippets/blobs_resolver.rb b/app/graphql/resolvers/snippets/blobs_resolver.rb
index cbbc65d7263..29716ce1394 100644
--- a/app/graphql/resolvers/snippets/blobs_resolver.rb
+++ b/app/graphql/resolvers/snippets/blobs_resolver.rb
@@ -19,18 +19,18 @@ module Resolvers
def resolve(paths: [])
return [snippet.blob] if snippet.empty_repo?
- if paths.empty?
- snippet.blobs
- else
- snippet.repository.blobs_at(transformed_blob_paths(paths))
- end
- end
-
- private
-
- def transformed_blob_paths(paths)
- ref = snippet.default_branch
- paths.map { |path| [ref, path] }
+ paths = snippet.all_files if paths.empty?
+ blobs = snippet.blobs(paths)
+
+ # TODO: Some blobs, e.g. those with non-utf8 filenames, are returned as nil from the
+ # repository. We need to provide a flag to notify the user of this until we come up with a
+ # way to retrieve and display these blobs. We will be exploring a more holistic solution for
+ # this general problem of making all blobs retrievable as part
+ # of https://gitlab.com/gitlab-org/gitlab/-/issues/323082, at which point this attribute may
+ # be removed.
+ context[:unretrievable_blobs?] = blobs.size < paths.size
+
+ blobs
end
end
end
diff --git a/app/graphql/types/snippets/blob_connection_type.rb b/app/graphql/types/snippets/blob_connection_type.rb
new file mode 100644
index 00000000000..15d26af7374
--- /dev/null
+++ b/app/graphql/types/snippets/blob_connection_type.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ module Snippets
+ # rubocop: disable Graphql/AuthorizeTypes
+ class BlobConnectionType < GraphQL::Types::Relay::BaseConnection
+ field :has_unretrievable_blobs, GraphQL::Types::Boolean, null: false,
+ description: 'Indicates if the snippet has unretrievable blobs.',
+ resolver_method: :unretrievable_blobs?
+
+ def unretrievable_blobs?
+ !!context[:unretrievable_blobs?]
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/snippets/blob_type.rb b/app/graphql/types/snippets/blob_type.rb
index 2b9b76a6194..80702c71f63 100644
--- a/app/graphql/types/snippets/blob_type.rb
+++ b/app/graphql/types/snippets/blob_type.rb
@@ -8,6 +8,8 @@ module Types
description 'Represents the snippet blob'
present_using SnippetBlobPresenter
+ connection_type_class(Types::Snippets::BlobConnectionType)
+
field :rich_data, GraphQL::Types::String,
description: 'Blob highlighted data.',
null: true
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 6a8123b3c08..b04fca64c87 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -237,15 +237,19 @@ class Snippet < ApplicationRecord
end
end
+ def all_files
+ list_files(default_branch)
+ end
+
def blob
@blob ||= Blob.decorate(SnippetBlob.new(self), self)
end
- def blobs
+ def blobs(paths = [])
return [] unless repository_exists?
- files = list_files(default_branch)
- items = files.map { |file| [default_branch, file] }
+ paths = all_files if paths.empty?
+ items = paths.map { |path| [default_branch, path] }
repository.blobs_at(items).compact
end