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
2 changes: 2 additions & 0 deletions .ameba.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Naming/AccessorMethodName:
Enabled: false
Lint/SpecFilename:
Enabled: false
Lint/UselessAssign:
Enabled: false

Documentation/DocumentationAdmonition:
Enabled: false
61 changes: 60 additions & 1 deletion spec/controllers/drivers_spec.cr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "../helper"

module PlaceOS::Api
describe Drivers do
describe Drivers, tags: "drivers" do
describe "index", tags: "search" do
Spec.test_base_index(klass: Model::Driver, controller_klass: Drivers)

Expand Down Expand Up @@ -74,6 +74,65 @@ module PlaceOS::Api
end
end

describe "readme" do
it "returns the readme content for a driver" do
# Create a repository pointing to the real PlaceOS/drivers repo
repository = Model::Generator.repository(type: Model::Repository::Type::Driver)
repository.uri = "https://github.com/PlaceOS/drivers"
repository.save!

# Create a driver with a real file path that has a readme
driver = Model::Driver.new(
name: "Auto Release",
role: Model::Driver::Role::Logic,
commit: "HEAD",
module_name: "AutoRelease",
file_name: "drivers/place/auto_release.cr",
)
driver.repository = repository
driver.save!

id = driver.id.as(String)
path = File.join(Drivers.base_route, id, "readme")

result = client.get(
path: path,
headers: Spec::Authentication.headers,
)

result.success?.should be_true
result.body.should contain("Auto Release")
end

it "returns 404 when readme does not exist" do
# Create a repository pointing to the real PlaceOS/drivers repo
repository = Model::Generator.repository(type: Model::Repository::Type::Driver)
repository.uri = "https://github.com/PlaceOS/drivers"
repository.save!

# Create a driver with a file path that does NOT have a readme
driver = Model::Driver.new(
name: "No Readme Driver",
role: Model::Driver::Role::Logic,
commit: "HEAD",
module_name: "NoReadme",
file_name: "drivers/place/nonexistent_driver.cr",
)
driver.repository = repository
driver.save!

id = driver.id.as(String)
path = File.join(Drivers.base_route, id, "readme")

result = client.get(
path: path,
headers: Spec::Authentication.headers,
)

result.status_code.should eq 404
end
end

describe "scopes" do
before_each do
HttpMocks.core_compiled
Expand Down
1 change: 0 additions & 1 deletion src/placeos-rest-api/controllers/alerts.cr
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ module PlaceOS::Api
})
end

p! query
query.sort(NAME_SORT_ASC)
paginate_results(elastic, query)
end
Expand Down
6 changes: 3 additions & 3 deletions src/placeos-rest-api/controllers/drivers.cr
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ module PlaceOS::Api
driver_file_name = current_driver.file_name
readme_path = driver_file_name.chomp(".cr") + "_readme.md"

# Create GitRepository instance
repository_path = File.join(Repositories.repository_dir, repository.folder_name)
git_repo = GitRepository.new(repository_path)
# Create GitRepository instance using the repository's remote URI
password = repository.decrypt_password if repository.password.presence
git_repo = GitRepository.new(repository.uri, repository.username, password)

# Check if the readme file exists using the driver's commit
files = git_repo.file_list(ref: current_driver.commit, path: readme_path)
Expand Down
3 changes: 2 additions & 1 deletion src/placeos-rest-api/utilities/current-user.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module PlaceOS::Api
# Parses, and validates JWT if present.
# Throws Error::MissingBearer and JWT::Error.

# ameba:disable Metrics/CyclomaticComplexity
def authorize! : ::PlaceOS::Model::UserJWT
if token = @user_token
return token
Expand Down Expand Up @@ -42,7 +43,7 @@ module PlaceOS::Api
begin
# peek the token to determine type
token_info = Utils::MSTokenExchange.peek_token_info(token)
if token_info.is_ms_token?
if token_info.ms_token?
user = Utils::MSTokenExchange.obtain_place_user(token, token_info)
raise "MS token could not be exchanged" unless user
@current_user = user
Expand Down
38 changes: 17 additions & 21 deletions src/placeos-rest-api/utilities/ms-token-exchange.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module PlaceOS::Api
version : TokenVersion,
kid : String? do
# Basic heuristic to detect Microsoft Entra / Azure AD issuers
def is_ms_token? : Bool
def ms_token? : Bool
iss_val = iss_host
return false unless iss_val
iss_val = iss_val.downcase
Expand Down Expand Up @@ -119,14 +119,14 @@ module PlaceOS::Api

# if not existing or refresh failed, get a token using this token and on behalf of
# https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-on-behalf-of-flow#example
form = URI::Params.build do |form|
form.add "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"
form.add "client_id", oauth.client_id
form.add "client_secret", oauth.client_secret
form.add "assertion", token
form.add "scope", oauth.scope
form.add "requested_token_use", "on_behalf_of"
form.add "resource", "https://graph.microsoft.com/"
form = URI::Params.build do |builder|
builder.add "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"
builder.add "client_id", oauth.client_id
builder.add "client_secret", oauth.client_secret
builder.add "assertion", token
builder.add "scope", oauth.scope
builder.add "requested_token_use", "on_behalf_of"
builder.add "resource", "https://graph.microsoft.com/"
end

uri = token_info.token_endpoint
Expand Down Expand Up @@ -163,23 +163,19 @@ module PlaceOS::Api
# ---------- Audience Parsing ----------

def extract_aud_host(aud_raw : String) : String
begin
uri = URI.parse(aud_raw)
uri.host || aud_raw
rescue
aud_raw
end
uri = URI.parse(aud_raw)
uri.host || aud_raw
rescue
aud_raw
end

# ---------- Issuer Parsing ----------

def extract_issuer_host(iss_raw : String) : String?
begin
uri = URI.parse(iss_raw)
uri.host
rescue
nil
end
uri = URI.parse(iss_raw)
uri.host
rescue
nil
end

# ---------- Validation (JWKS) ----------
Expand Down
Loading