Files
ubicloud/spec/routes/web/firewall_spec.rb
Jeremy Evans 488f2750ac Remove AccessPolicy
AccessPolicy was still referenced in a bunch of specs, where it had
no effect because the specs weren't testing what they thought they
were testing.  Replace AccessPolicy creation with equivalent
AccessControlEntry creation, and check that we can get to the
page we were expected to get to.  We should really go further and
check that if you remove an ACE allowing edit/destroy after
displaying the page (which shows the button), the button doesn't
work due to the access control violation.  However, that can be
added later.

Add association dependencies for access_control_entries and
subject_tags to Project.  I'm not sure these are ever used, since
we soft-delete projects instead of actually deleting them, so this
is just cargo culting because access_policies were listed.
2025-01-09 09:55:55 -08:00

340 lines
11 KiB
Ruby

# frozen_string_literal: true
require_relative "spec_helper"
RSpec.describe Clover, "firewall" do
let(:user) { create_account }
let(:project) { user.create_project_with_default_policy("project-1") }
let(:project_wo_permissions) { user.create_project_with_default_policy("project-2", default_policy: nil) }
let(:firewall) do
fw = Firewall.create_with_id(name: "dummy-fw", description: "dummy-fw", location: "hetzner-fsn1")
fw.associate_with_project(project)
fw
end
let(:fw_wo_permission) {
fw = Firewall.create_with_id(name: "dummy-fw-2", description: "dummy-fw-2", location: "hetzner-fsn1")
fw.associate_with_project(project_wo_permissions)
fw
}
describe "unauthenticated" do
it "can not list without login" do
visit "/firewall"
expect(page.title).to eq("Ubicloud - Login")
end
it "can not create without login" do
visit "/firewall/create"
expect(page.title).to eq("Ubicloud - Login")
end
end
describe "authenticated" do
before do
login(user.email)
end
describe "list" do
it "can list no firewalls" do
visit "#{project.path}/firewall"
expect(page.title).to eq("Ubicloud - Firewalls")
expect(page).to have_content "No firewalls"
click_link "New Firewall"
expect(page.title).to eq("Ubicloud - Create Firewall")
end
it "can not list firewalls when does not have permissions" do
firewall
fw_wo_permission
visit "#{project.path}/firewall"
expect(page.title).to eq("Ubicloud - Firewalls")
expect(page).to have_content firewall.name
expect(page).to have_no_content fw_wo_permission.name
end
end
describe "create" do
it "can create new firewall" do
project
visit "#{project.path}/firewall/create"
expect(page.title).to eq("Ubicloud - Create Firewall")
name = "dummy-fw"
fill_in "Name", with: name
fill_in "Description", with: name
click_button "Create"
expect(page.title).to eq("Ubicloud - #{name}")
expect(page).to have_flash_notice("'#{name}' is created")
expect(Firewall.count).to eq(1)
expect(Firewall.first.projects.first.id).to eq(project.id)
end
it "can create new firewall with private subnet" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1", location: "hetzner-fsn1").subject
visit "#{project.path}/firewall/create"
expect(page.title).to eq("Ubicloud - Create Firewall")
name = "dummy-fw-1"
fill_in "Name", with: name
fill_in "Description", with: name
select ps.name, from: "private_subnet_id"
click_button "Create"
expect(page.title).to eq("Ubicloud - #{name}")
expect(page).to have_flash_notice("'#{name}' is created")
fw = Firewall[name: name]
expect(fw.private_subnets.first.id).to eq(ps.id)
visit "#{project.path}#{ps.path}"
expect(page).to have_content name
visit "#{project.path}#{fw.path}"
expect(page).to have_content ps.name
end
it "can not create firewall with invalid name" do
project
visit "#{project.path}/firewall/create"
expect(page.title).to eq("Ubicloud - Create Firewall")
fill_in "Name", with: "invalid name"
click_button "Create"
expect(page.title).to eq("Ubicloud - Create Firewall")
expect(page).to have_content "Name must only contain"
expect((find "input[name=name]")["value"]).to eq("invalid name")
end
it "can not create firewall in a project when does not have permissions" do
project_wo_permissions
visit "#{project_wo_permissions.path}/firewall/create"
expect(page.title).to eq("Ubicloud - Forbidden")
expect(page.status_code).to eq(403)
expect(page).to have_content "Forbidden"
end
end
describe "show" do
it "can show firewall details" do
firewall
visit "#{project.path}/firewall"
expect(page.title).to eq("Ubicloud - Firewalls")
expect(page).to have_content firewall.name
click_link firewall.name, href: "#{project.path}#{firewall.path}"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_content firewall.name
end
it "raises forbidden when does not have permissions" do
visit "#{project_wo_permissions.path}#{fw_wo_permission.path}"
expect(page.title).to eq("Ubicloud - Forbidden")
expect(page.status_code).to eq(403)
expect(page).to have_content "Forbidden"
end
it "raises not found when firewall not exists" do
visit "#{project.path}/location/hetzner-fsn1/firewall/08s56d4kaj94xsmrnf5v5m3mav"
expect(page.title).to eq("Ubicloud - ResourceNotFound")
expect(page.status_code).to eq(404)
expect(page).to have_content "ResourceNotFound"
end
end
describe "subnets" do
it "can show" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1", location: "hetzner-fsn1").subject
firewall.associate_with_private_subnet(ps)
visit "#{project.path}#{firewall.path}"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_content ps.name
end
it "can attach subnet" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1", location: "hetzner-fsn1").subject
visit "#{project.path}#{firewall.path}"
select ps.name, from: "private_subnet_id"
click_button "Attach"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_flash_notice("Private subnet #{ps.name} is attached to the firewall")
expect(firewall.private_subnets_dataset.count).to eq(1)
visit "#{project.path}#{firewall.path}"
expect(page).to have_content ps.name
visit "#{project.path}#{ps.path}"
expect(page).to have_content firewall.name
end
it "can not attach subnet when it does not exist" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1", location: "hetzner-fsn1").subject
visit "#{project.path}#{firewall.path}"
select "dummy-ps-1", from: "private_subnet_id"
ps.destroy
click_button "Attach"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_flash_error("Private subnet not found")
expect(firewall.private_subnets_dataset.count).to eq(0)
end
it "can detach subnet" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1111", location: "hetzner-fsn1").subject
expect(page).to have_no_content ps.name
firewall.associate_with_private_subnet(ps)
visit "#{project.path}#{firewall.path}"
click_button "Detach"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_flash_notice("Private subnet #{ps.name} is detached from the firewall")
expect(firewall.private_subnets_dataset.count).to eq(0)
visit "#{project.path}#{ps.path}"
expect(page).to have_no_content firewall.name
end
it "can not detach subnet when it does not exist" do
ps = Prog::Vnet::SubnetNexus.assemble(project.id, name: "dummy-ps-1", location: "hetzner-fsn1").subject
visit "#{project.path}#{firewall.path}"
select "dummy-ps-1", from: "private_subnet_id"
click_button "Attach"
visit "#{project.path}#{firewall.path}"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(firewall.private_subnets_dataset.count).to eq(1)
ps.destroy
click_button "Detach"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_flash_error("Private subnet not found")
expect(firewall.private_subnets_dataset.count).to eq(0)
end
end
describe "rules" do
it "can add" do
visit "#{project.path}#{firewall.path}"
fill_in "cidr", with: "1.1.1.1/8"
fill_in "port_range", with: "80"
click_button "Create"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_flash_notice("Firewall rule is created")
expect(firewall.firewall_rules_dataset.count).to eq(1)
end
it "can not add rule when it is invalid" do
visit "#{project.path}#{firewall.path}"
fill_in "cidr", with: "invalid"
click_button "Create"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_content "Invalid CIDR"
fill_in "cidr", with: "1.1.1.1/32"
fill_in "port_range", with: "invalid"
click_button "Create"
expect(page.title).to eq("Ubicloud - #{firewall.name}")
expect(page).to have_content "Invalid port range"
expect(firewall.firewall_rules_dataset.count).to eq(0)
end
it "can delete rule" do
firewall.insert_firewall_rule("1.0.0.0/8", Sequel.pg_range(80..80))
visit "#{project.path}#{firewall.path}"
btn = find "#fwr-delete-#{firewall.firewall_rules.first.ubid} .delete-btn"
page.driver.delete btn["data-url"], {_csrf: btn["data-csrf"]}
expect(page.body).to eq({message: "Firewall rule deleted"}.to_json)
expect(firewall.firewall_rules_dataset.count).to eq(0)
visit "#{project.path}#{firewall.path}"
expect(page).to have_no_content "1.0.0.0/8"
end
it "accepts delete rule if it's already deleted" do
firewall.insert_firewall_rule("1.0.0.0/8", Sequel.pg_range(80..80))
visit "#{project.path}#{firewall.path}"
firewall.remove_firewall_rule(firewall.firewall_rules.first)
btn = find "#fwr-delete-#{firewall.firewall_rules.first.ubid} .delete-btn"
expect { page.driver.delete btn["data-url"], {_csrf: btn["data-csrf"]} }.not_to raise_error
expect(firewall.firewall_rules_dataset.count).to eq(0)
end
it "can show firewall rules which have port_range nil" do
firewall.insert_firewall_rule("1.0.0.0/8", nil)
visit "#{project.path}#{firewall.path}"
expect(page).to have_content "1.0.0.0/8"
expect(page).to have_content "0..65535"
expect(firewall.firewall_rules_dataset.count).to eq(1)
end
end
describe "delete" do
it "can delete firewall" do
visit "#{project.path}#{firewall.path}"
# We send delete request manually instead of just clicking to button because delete action triggered by JavaScript.
# UI tests run without a JavaScript enginer.
btn = find ".delete-btn"
page.driver.delete btn["data-url"], {_csrf: btn["data-csrf"]}
expect(page.status_code).to eq(204)
expect(page.body).to be_empty
expect(Firewall.count).to eq(0)
end
it "can not delete firewall when does not have permissions" do
# Give permission to view, so we can see the detail page
AccessControlEntry.create_with_id(project_id: project_wo_permissions.id, subject_id: user.id, action_id: ActionType::NAME_MAP["Firewall:view"])
visit "#{project_wo_permissions.path}#{fw_wo_permission.path}"
expect(page.title).to eq "Ubicloud - dummy-fw-2"
expect { find ".delete-btn" }.to raise_error Capybara::ElementNotFound
end
end
end
end