main
rb 78 lines 3.26 KB
Raw
1 # frozen_string_literal: true
2
3 require "rails_helper"
4 require "tmpdir"
5 require "fileutils"
6
7 # End-to-end checks for the rendered read experience: a README renders (not
8 # raw) on the repo landing page, source files get syntax highlighting + line
9 # numbers, .md blobs render, the permalink pins to a commit SHA, and malicious
10 # HTML in a README is neutralised.
11 RSpec.describe "Blob view", type: :request do
12 around do |example|
13 Dir.mktmpdir("blob-view-spec") do |tmp|
14 @repo_dir = File.join(tmp, "demo.git")
15 build_repo(@repo_dir,
16 "README.md" => "# Demo Project\n\nHello <script>alert('xss')</script> world\n\n- [x] done\n- [ ] todo\n",
17 "main.rb" => "def greet\n puts 'hi'\nend\n")
18 @sha = `git --git-dir #{@repo_dir} rev-parse main`.strip
19 example.run
20 end
21 end
22
23 let(:user) { User.create!(smbcloud_id: 123_321, email: "blob-spec@example.com", username: "blobspec") }
24 let!(:repo) { user.repositories.create!(name: "demo", disk_path: @repo_dir, default_branch: "main") }
25
26 it "renders the README as HTML on the repo landing page" do
27 get "/blobspec/demo"
28 expect(response).to have_http_status(:success)
29 expect(response.body).to include('<div class="px-6 py-6 prose-readme"')
30 expect(response.body).to match(%r{<h1[^>]*>.*Demo Project}m)
31 end
32
33 it "neutralises malicious HTML in the README" do
34 get "/blobspec/demo"
35 # The payload is gone entirely; the only <script> tags left are the page
36 # layout's own (JSON-LD / importmap), never the README's.
37 expect(response.body).not_to include("alert('xss')")
38 rendered = response.body[/prose-readme.*?<\/div>/m]
39 expect(rendered).not_to include("<script")
40 end
41
42 it "shows syntax highlighting and per-line anchors for a source file" do
43 get "/blobspec/demo/blob/main/main.rb"
44 expect(response).to have_http_status(:success)
45 expect(response.body).to include('id="L1"').and include('id="L2"')
46 expect(response.body).to include('class="highlight"')
47 end
48
49 it "pins the copy-permalink base to the commit SHA, not the branch" do
50 get "/blobspec/demo/blob/main/main.rb"
51 expect(response.body).to include(
52 %(data-line-selection-permalink-base-value="/blobspec/demo/blob/#{@sha}/main.rb")
53 )
54 end
55
56 it "renders an .md blob as Markdown by default and as source with ?plain" do
57 get "/blobspec/demo/blob/main/README.md"
58 expect(response.body).to match(%r{<h1[^>]*>.*Demo Project}m)
59
60 get "/blobspec/demo/blob/main/README.md?plain=1"
61 expect(response.body).to include('id="L1"')
62 end
63
64 def build_repo(bare_path, files)
65 FileUtils.mkdir_p(bare_path)
66 system("git", "init", "--bare", bare_path, exception: true)
67 Dir.mktmpdir do |work|
68 system("git", "-C", work, "init", "-b", "main", exception: true)
69 system("git", "-C", work, "config", "user.email", "t@example.com", exception: true)
70 system("git", "-C", work, "config", "user.name", "Test", exception: true)
71 files.each { |name, content| File.write(File.join(work, name), content) }
72 system("git", "-C", work, "add", ".", exception: true)
73 system("git", "-C", work, "commit", "-m", "seed", exception: true)
74 system("git", "-C", work, "remote", "add", "origin", bare_path, exception: true)
75 system("git", "-C", work, "push", "origin", "main", exception: true)
76 end
77 end
78 end