spec/cgi_auth_spec.cr @ trunk
spec
scale = 0.75 fontscale = 1.500 box wid 1.380 ht 0.340 with .nw at (0.035, -0.035) fill 0xCBD5E1 color 0xCBD5E1 box wid 1.380 ht 0.340 with .nw at (0.000, 0.000) fill 0x7C83E6 color 0x7C83E6 box wid 0.300 ht 0.065 rad 0.018 at (0.370, -0.022) fill 0xffffff color 0xffffff line from (0.140, 0.000) to (0.140, -0.340) color white line from (1.240, 0.000) to (1.240, -0.340) color white text "require 'spec'" color white at (0.690, -0.170)→ /pikchrshow
crystal source
require "spec"
json block
{
"kind": "require",
"name": "spec",
"doc": null,
"children": []
}
private def gpcr_bin : String
File.join(Dir.current, "bin", "gpcr")
end
private def run_cgi(caps : String, path : String, method : String = "GET") : String
buf = IO::Memory.new
env = {
"PATH" => "/usr/bin:/bin",
"GATEWAY_INTERFACE" => "CGI/1.1",
"REQUEST_METHOD" => method,
"PATH_INFO" => path,
"QUERY_STRING" => "",
"SCRIPT_NAME" => "/ext/gpcr",
"FOSSIL_REPOSITORY" => "/nonexistent/gpcr_auth_test.fossil",
"FOSSIL_CAPABILITIES" => caps,
}
stdin = IO::Memory.new
Process.run(gpcr_bin, env: env, clear_env: true, input: stdin, output: buf,
error: Process::Redirect::Close)
buf.to_s
end
private def is_403?(response : String) : Bool
response.includes?("Status: 403")
end
describe "GPCR CGI capability matrix" do
bin = gpcr_bin
unless File.exists?(bin)
pending "gpcr binary not present — skipping capability matrix tests"
next
end
describe "no capabilities (FOSSIL_CAPABILITIES='')" do
it "GET / (explorer) → 403 Forbidden" do
is_403?(run_cgi("", "/")).should be_true
end
it "GET /gallery → 403 Forbidden" do
is_403?(run_cgi("", "/gallery")).should be_true
end
it "GET /src/gpcr/cli.cr (file route) → 403 Forbidden" do
is_403?(run_cgi("", "/src/gpcr/cli.cr")).should be_true
end
it "GET /edit → 403 Forbidden" do
is_403?(run_cgi("", "/edit")).should be_true
end
it "GET /edit.js (fetch-swap asset) → 403 Forbidden" do
is_403?(run_cgi("", "/edit.js")).should be_true
end
it "POST /edit → 403 Forbidden" do
is_403?(run_cgi("", "/edit", "POST")).should be_true
end
it "POST /edit refused → no Location header (zero-state-mutation proof)" do
run_cgi("", "/edit", "POST").should_not contain("Location:")
end
end
describe "read capabilities (FOSSIL_CAPABILITIES='o')" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("o", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("o", "/gallery")).should be_false
end
it "GET /src/gpcr/cli.cr (file route) → allowed (not 403)" do
is_403?(run_cgi("o", "/src/gpcr/cli.cr")).should be_false
end
it "GET /edit → 403 Forbidden (i capability required)" do
is_403?(run_cgi("o", "/edit")).should be_true
end
it "GET /edit.js (fetch-swap asset) → allowed (not 403) — read-only static asset" do
is_403?(run_cgi("o", "/edit.js")).should be_false
end
it "POST /edit → 403 Forbidden (i capability required)" do
is_403?(run_cgi("o", "/edit", "POST")).should be_true
end
end
describe "edit capabilities (FOSSIL_CAPABILITIES='ohi')" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("ohi", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("ohi", "/gallery")).should be_false
end
it "GET /edit → allowed (not 403)" do
is_403?(run_cgi("ohi", "/edit")).should be_false
end
it "POST /edit → allowed (not 403)" do
is_403?(run_cgi("ohi", "/edit", "POST")).should be_false
end
end
describe "setup capability (FOSSIL_CAPABILITIES='s') — superset, all routes allowed" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("s", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("s", "/gallery")).should be_false
end
it "GET /src/gpcr/cli.cr (file route) → allowed (not 403)" do
is_403?(run_cgi("s", "/src/gpcr/cli.cr")).should be_false
end
it "GET /edit → allowed (not 403) (setup implies all caps)" do
is_403?(run_cgi("s", "/edit")).should be_false
end
it "POST /edit → allowed (not 403)" do
is_403?(run_cgi("s", "/edit", "POST")).should be_false
end
end
describe "admin capability (FOSSIL_CAPABILITIES='a') — superset, all routes allowed" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("a", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("a", "/gallery")).should be_false
end
it "GET /src/gpcr/cli.cr (file route) → allowed (not 403)" do
is_403?(run_cgi("a", "/src/gpcr/cli.cr")).should be_false
end
it "GET /edit → allowed (not 403) (admin implies all caps)" do
is_403?(run_cgi("a", "/edit")).should be_false
end
it "POST /edit → allowed (not 403)" do
is_403?(run_cgi("a", "/edit", "POST")).should be_false
end
end
describe "developer capability (FOSSIL_CAPABILITIES='v') — read+edit allowed" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("v", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("v", "/gallery")).should be_false
end
it "GET /src/gpcr/cli.cr (file route) → allowed (not 403)" do
is_403?(run_cgi("v", "/src/gpcr/cli.cr")).should be_false
end
it "GET /edit → allowed (not 403) (v expands to include i)" do
is_403?(run_cgi("v", "/edit")).should be_false
end
it "POST /edit → allowed (not 403)" do
is_403?(run_cgi("v", "/edit", "POST")).should be_false
end
end
describe "reader capability (FOSSIL_CAPABILITIES='u') — read-only" do
it "GET / (explorer) → allowed (not 403)" do
is_403?(run_cgi("u", "/")).should be_false
end
it "GET /gallery → allowed (not 403)" do
is_403?(run_cgi("u", "/gallery")).should be_false
end
it "GET /src/gpcr/cli.cr (file route) → allowed (not 403)" do
is_403?(run_cgi("u", "/src/gpcr/cli.cr")).should be_false
end
it "GET /edit → 403 Forbidden (u expands to read caps only, no i)" do
is_403?(run_cgi("u", "/edit")).should be_true
end
it "POST /edit → 403 Forbidden (u expands to read caps only, no i)" do
is_403?(run_cgi("u", "/edit", "POST")).should be_true
end
end
describe "trailing slash normalization (ticket 8428fb1664)" do
it "GET /edit/ with no caps → 403 (same as /edit)" do
is_403?(run_cgi("", "/edit/")).should be_true
end
it "GET /edit/ with edit caps → allowed (same as /edit)" do
is_403?(run_cgi("ohi", "/edit/")).should be_false
end
it "POST /edit/ with edit caps → allowed (same as /edit)" do
is_403?(run_cgi("ohi", "/edit/", "POST")).should be_false
end
it "GET /gallery/ with no caps → 403 (same as /gallery)" do
is_403?(run_cgi("", "/gallery/")).should be_true
end
it "GET /gallery/ with read caps → allowed (same as /gallery)" do
is_403?(run_cgi("o", "/gallery/")).should be_false
end
end
end