Files
ubicloud/spec/routes/web/clover_web_spec.rb
Jeremy Evans 8cada58820 Add audit logging to all route actions
Audit logging is designed to be simple to use.  You call the audit_log
method with the object affected and the action taken on it:

```ruby
audit_log(vm, "create")
```

If additional objects are affected by the same action, then you can
include them in the third argument:

```ruby
audit_log(ps, "connect", subnet)
```

This implements an audit logging check similar to the recently
added authorization check.  All successful non-GET requests to the
application are checked for audit logging, and will fail in
non-frozen tests if an audit logging method is not called.

Currently, only create/destroy actions are logged.  Audit logging
in other cases is ignored.  However, this approach was necessary
to check that no cases that should result in audit logging were
missed. It also allows for easily flipping the switch to audit log
all route actions.
2025-05-13 06:38:49 +09:00

115 lines
3.4 KiB
Ruby

# frozen_string_literal: true
require_relative "spec_helper"
RSpec.describe Clover do
it "handles CSRF token errors" do
visit "/login"
find(".rodauth input[name=_csrf]", visible: false).set("")
click_button "Sign in"
expect(page.status_code).to eq(400)
expect(page).to have_flash_error("An invalid security token submitted with this request, please try again")
end
it "does not redirect to requested path if path is too long" do
create_account
visit("/a" * 2048)
expect(page.status_code).to eq(200)
expect(page).to have_current_path("/login", ignore_query: true)
fill_in "Email Address", with: TEST_USER_EMAIL
fill_in "Password", with: TEST_USER_PASSWORD
click_button "Sign in"
expect(page.title).to end_with("Dashboard")
end
if ENV["CLOVER_FREEZE"] != "1"
it "raises error if no_authorization_needed called when not needed or already authorized" do
create_account.create_project_with_default_policy("project-1")
login
visit "/test-no-authorization-needed/once"
expect(page.status_code).to eq(200)
re = /called no_authorization_needed when authorization already not needed: /
expect { visit "/test-no-authorization-needed/twice" }.to raise_error(RuntimeError, re)
expect { visit "/test-no-authorization-needed/after-authorization" }.to raise_error(RuntimeError, re)
expect { visit "/test-no-authorization-needed/runtime-error" }.to raise_error(RuntimeError, /no authorization check for /)
end
it "raises error for non-GET request without audit logging" do
expect { post "/webhook/test-no-audit-logging/test" }.to raise_error(RuntimeError, /no audit logging for /)
end
end
it "raises error for unsupported audit log action" do
expect { post "/webhook/test-no-audit-logging/bad" }.to raise_error(RuntimeError, "unsupported audit_log action: bad_action")
end
it "handles expected errors" do
expect(Clog).to receive(:emit).with("route exception").and_call_original
visit "/webhook/test-error"
expect(page.title).to eq("Ubicloud - UnexceptedError")
end
it "raises unexpected errors in test environment" do
expect(Clog).not_to receive(:emit)
expect { visit "/webhook/test-error?message=treat+as+unexpected+error" }.to raise_error(RuntimeError, "treat as unexpected error")
end
it "raises validation error if a required parameter is not present" do
create_account
login
visit("/test-missing-request-params")
# Validation error without referrer redirects to /, which redirects to default project dashboard
expect(page.title).to eq("Ubicloud - Default Dashboard")
end
it "does not have broken links" do
create_account
login
visited = {"" => true}
failures = []
queue = Queue.new
queue.push([nil, "/"])
pop = lambda do
queue.pop(true)
rescue ThreadError
end
while (tuple = pop.call)
from, path = tuple
next if visited[path]
visited[path] = true
visit path
if page.status_code == 404
failures << [from, path]
end
if page.response_headers["content-type"].include?("text/html")
links = page.all("a").map do |a|
a["href"].sub(/#.*\z/, "")
end
links.reject! do |path|
path.empty? || path.start_with?(%r{https://|mailto:})
end
links.each do |path|
queue.push [page.current_path, path]
end
end
end
expect(failures).to be_empty
end
end