Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions spec/controllers/drivers_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,41 @@ module PlaceOS::Api
end
end

describe "access control", tags: "access-control" do
it "GET /drivers returns 403 for non-admin / non-support callers" do
_, headers = Spec::Authentication.authentication(sys_admin: false, support: false)
result = client.get(Drivers.base_route, headers: headers)
result.status_code.should eq 403
end

it "GET /drivers/:id/readme returns 403 for non-admin / non-support callers" do
repository = Model::Generator.repository(type: Model::Repository::Type::Driver)
repository.uri = "https://github.com/PlaceOS/drivers"
repository.save!

driver = Model::Driver.new(
name: "Restricted Readme",
role: Model::Driver::Role::Logic,
commit: "HEAD",
module_name: "AutoRelease",
file_name: "drivers/place/auto_release.cr",
)
driver.repository = repository
driver.save!

_, headers = Spec::Authentication.authentication(sys_admin: false, support: false)
path = File.join(Drivers.base_route, driver.id.as(String), "readme")
result = client.get(path, headers: headers)
result.status_code.should eq 403
end

it "GET /drivers is allowed for support-only callers" do
_, headers = Spec::Authentication.authentication(sys_admin: false, support: true)
result = client.get(Drivers.base_route, headers: headers)
result.success?.should be_true
end
end

describe "scopes" do
before_each do
HttpMocks.core_compiled
Expand Down
28 changes: 28 additions & 0 deletions spec/controllers/zones_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,34 @@ module PlaceOS::Api
end
end

describe "GET /zones/:id/triggers access control" do
it "returns 403 for non-admin / non-support callers" do
zone = Model::Generator.zone.save!
_, headers = Spec::Authentication.authentication(sys_admin: false, support: false)

result = client.get(
path: "#{Zones.base_route}#{zone.id}/triggers",
headers: headers,
)
result.status_code.should eq 403

zone.destroy
end

it "is allowed for support-only callers" do
zone = Model::Generator.zone.save!
_, headers = Spec::Authentication.authentication(sys_admin: false, support: true)

result = client.get(
path: "#{Zones.base_route}#{zone.id}/triggers",
headers: headers,
)
result.success?.should be_true

zone.destroy
end
end

describe "scopes" do
Spec.test_controller_scope(Zones)
Spec.test_update_write_scope(Zones)
Expand Down
6 changes: 6 additions & 0 deletions src/placeos-rest-api/controllers/drivers.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ module PlaceOS::Api

before_action :check_admin, except: [:index, :show, :readme]

# Restrict driver listing and readme access to admin/support. These
# endpoints expose internal infrastructure detail (driver inventory, driver
# README files that may include configuration notes or credential examples)
# that should not be available to standard authenticated users.
before_action :check_support, only: [:index, :readme]

###############################################################################################

@[AC::Route::Filter(:before_action, except: [:index, :create])]
Expand Down
6 changes: 4 additions & 2 deletions src/placeos-rest-api/controllers/zones.cr
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
# Scopes
###############################################################################################

before_action :can_read, only: [:index, :show]
before_action :can_read, only: [:index, :show, :trigger_instances]
before_action :can_write, only: [:create, :update, :destroy, :remove]

before_action :check_support, only: [:zone_execute]
# Restrict zone trigger listing to admin/support — `:trigger_instances`
# (GET /zones/:id/triggers) exposes internal automation/driver state.
before_action :check_support, only: [:zone_execute, :trigger_instances]

# Response helpers
###############################################################################################
Expand Down Expand Up @@ -234,7 +236,7 @@
"tags" => filter_tags,
})
elsif group_zone_ids.nil?
raise Error::Forbidden.new unless (parent_id && !parent_id.empty?) || user_support?

Check notice on line 239 in src/placeos-rest-api/controllers/zones.cr

View workflow job for this annotation

GitHub Actions / Ameba

Style/NegatedConditionsInUnless

Avoid negated conditions in unless blocks
Raw output
> raise Error::Forbidden.new unless (parent_id && !parent_id.empty?) || user_support?
  ^
query.search_field "name"
end

Expand Down
Loading