main
rb 75 lines 2.89 KB
Raw
1 # frozen_string_literal: true
2
3 require "rails_helper"
4 require "tmpdir"
5 require "fileutils"
6 require "base64"
7
8 # The /raw endpoint is what install scripts, badges, and CI hit, so it must
9 # return the exact bytes with a sensible content-type and the nosniff guard
10 # that stops the browser from running user content as active content on the
11 # app origin.
12 RSpec.describe "Raw blob", type: :request do
13 around do |example|
14 Dir.mktmpdir("raw-blob-spec") do |tmp|
15 @repo_dir = File.join(tmp, "demo.git")
16 build_repo(@repo_dir,
17 "hello.txt" => "plain bytes\n",
18 "page.html" => "<h1>hi</h1>\n",
19 "logo.png" => png_bytes)
20 example.run
21 end
22 end
23
24 let(:user) { User.create!(smbcloud_id: 987_654, email: "raw-spec@example.com", username: "rawspec") }
25 let!(:repo) { user.repositories.create!(name: "demo", disk_path: @repo_dir, default_branch: "main") }
26
27 it "returns exact bytes with text/plain and nosniff for a text file" do
28 get "/rawspec/demo/raw/main/hello.txt"
29 expect(response).to have_http_status(:success)
30 expect(response.body).to eq("plain bytes\n")
31 expect(response.media_type).to match(%r{text/plain})
32 expect(response.headers["X-Content-Type-Options"]).to eq("nosniff")
33 end
34
35 it "serves HTML files as text/plain so they cannot run as active content" do
36 get "/rawspec/demo/raw/main/page.html"
37 expect(response).to have_http_status(:success)
38 expect(response.media_type).to match(%r{text/plain})
39 expect(response.headers["X-Content-Type-Options"]).to eq("nosniff")
40 end
41
42 it "serves images with their real content-type" do
43 get "/rawspec/demo/raw/main/logo.png"
44 expect(response).to have_http_status(:success)
45 expect(response.media_type).to eq("image/png")
46 expect(response.headers["X-Content-Type-Options"]).to eq("nosniff")
47 end
48
49 it "returns 404 for a missing file" do
50 get "/rawspec/demo/raw/main/does-not-exist.txt"
51 expect(response).to have_http_status(:not_found)
52 end
53
54 def build_repo(bare_path, files)
55 FileUtils.mkdir_p(bare_path)
56 system("git", "init", "--bare", bare_path, exception: true)
57 Dir.mktmpdir do |work|
58 system("git", "-C", work, "init", "-b", "main", exception: true)
59 system("git", "-C", work, "config", "user.email", "t@example.com", exception: true)
60 system("git", "-C", work, "config", "user.name", "Test", exception: true)
61 files.each { |name, content| File.binwrite(File.join(work, name), content) }
62 system("git", "-C", work, "add", ".", exception: true)
63 system("git", "-C", work, "commit", "-m", "seed", exception: true)
64 system("git", "-C", work, "remote", "add", "origin", bare_path, exception: true)
65 system("git", "-C", work, "push", "origin", "main", exception: true)
66 end
67 end
68
69 # Smallest valid 1x1 PNG.
70 def png_bytes
71 Base64.decode64(
72 "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
73 )
74 end
75 end