Skip to content

Fix provisioning BBB servers#3014

Merged
samuelwei merged 12 commits intoTHM-Health:developfrom
pizkaz:fix/provisioning-bbb-servers
Apr 8, 2026
Merged

Fix provisioning BBB servers#3014
samuelwei merged 12 commits intoTHM-Health:developfrom
pizkaz:fix/provisioning-bbb-servers

Conversation

@pizkaz
Copy link
Copy Markdown
Contributor

@pizkaz pizkaz commented Apr 3, 2026

Fixes #3011

Type

  • Bugfix
  • Feature
  • Documentation
  • Refactoring (e.g. Style updates, Test implementation, etc.)
  • Other (please describe):

Checklist

  • Code updated to current develop branch head
  • Passes CI checks
  • Is a part of an issue
  • Tests added for the bugfix or newly implemented feature, describe below why if not
  • Changelog is updated
  • Documentation of code and features exists

Changes

  • It is now ensured that the API URLs of provisioned servers end with a slash
  • Fields documented as optional / having default values really are optional now

Summary by CodeRabbit

  • Bug Fixes

    • Provisioning now tolerates missing top-level sections and supports partial payloads; server endpoints are normalized with a trailing slash.
  • Documentation

    • Updated provisioning docs to state top-level sections, subsections and fields are optional and clarified permissions handling.
  • Tests

    • Added partial provisioning fixture and unit test; updated assertions to reflect normalized base URL and adjusted provisioning expectations.
  • Chores

    • Added changelog entry for these changes.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Make provisioning JSON sections optional with null-safe guards; ensure BBB server endpoints are normalized to end with /; initialize role permissions arrays before syncing; broaden error handling to catch \Throwable; add a partial provisioning fixture and tests; update provisioning docs and CHANGELOG.

Changes

Cohort / File(s) Summary
Provision Command
app/Console/Commands/ProvisionCommand.php
Make top-level provisioning sections optional (null-safe ?-> checks and ?? defaults), conditionally skip wipe/create loops when sections are missing, and change catch (Exception) to catch (\Throwable) (removed use Exception).
Provisioning Logic
app/Services/ProvisioningService.php
Normalize server base_url using Str::finish(..., '/') to ensure trailing slash; initialize $permissions = [] before populating and syncing role permissions.
Unit Tests
tests/Backend/Unit/ProvisioningServiceTest.php, tests/Backend/Unit/Console/ProvisionCommandTest.php
Expect Server::$base_url to include a trailing /; add test_provisioning_partial() exercising the new partial fixture and adjusted seed expectations.
Fixtures
tests/Backend/Fixtures/provisioning_data-partial.json
Add partial provisioning fixture with minimal servers.add, empty server_pools.add and room_types, roles.add with permissions, and partial settings.
Docs
docs/docs/administration/08-advanced/07-provisioning.md
Document that top-level sections and fields are optional, add item fields are optional, roles.permissions missing entries revoke permissions, and settings subsections/fields are optional.
Changelog
CHANGELOG.md
Add Unreleased → Changed entry describing trailing / normalization for BBB endpoints and updated partial provisioning format; add link references for #3011 and #3014.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive Title is vague and lacks specificity about the main changes; 'Fix provisioning BBB servers' does not clearly convey what the fix entails or reference the dual objectives (URL normalization and optional fields). Consider a more specific title like 'Normalize BBB server URLs and make provisioning fields optional' to better reflect both key changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed Description covers the main objectives and includes checked checklist items, but provides minimal detail on implementation approach and lacks specific explanation of how optional fields are now supported.
Linked Issues check ✅ Passed Changes fully address issue #3011 by normalizing BBB API URLs with trailing slashes and making provisioning fields optional, matching the documented objectives.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue #3011; no out-of-scope modifications detected beyond URL normalization and optional field support.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/Console/Commands/ProvisionCommand.php`:
- Around line 87-93: The role provisioning path fails for empty permission
groups because $permissions is only created inside the nested grant loop; update
the role-handling logic in ProvisioningService (around lines 210-223) to
initialize $permissions = [] before iterating grants, then populate it if grants
exist (e.g., foreach ($role->permissions as $namespace => $grants) { foreach
((array)$grants as $g) { $permissions[] = ... } }), and ensure you cast empty
grant containers to arrays so a role with permissions: {} or {"rooms": []}
results in an empty $permissions array and still calls the role creation
routine.
- Around line 64-110: The code calls count() and get_object_vars() on untrusted
$data properties (e.g. $data->servers->add, $data->server_pools->add,
$data?->room_types->add, $data->roles->add, $data->users->add and
$data->settings) which can throw TypeError for non-countable/non-object values;
before each count() or foreach, check and normalize the value (use
is_countable() or is_array() and cast to array (or skip) for *.add lists, and
ensure $data->settings is an object before calling get_object_vars()—convert or
initialize it to an object or array as needed—and make the null-safe access
consistent (remove the stray ? in $data?->room_types->add); then proceed to call
provision methods like $this->provision->server->create, serverPool->create,
roomType->create, role->create, user->create and settings->set only with
validated/cast data.

In `@CHANGELOG.md`:
- Line 16: The changelog entry "Fix provisioning BBB servers ([`#3011`])"
references an undefined link label; update that line to use the actual, declared
changelog reference or a full issue/PR URL so the link resolves (e.g., replace
"([`#3011`])" with the existing reference label used in the file or the canonical
issue/PR link), ensuring the label you use matches one declared in the reference
list at the bottom of the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 85f9ed5a-41c6-4302-bd49-72338fb080f0

📥 Commits

Reviewing files that changed from the base of the PR and between 9e989eb and 05f6800.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • app/Console/Commands/ProvisionCommand.php
  • app/Services/ProvisioningService.php
  • docs/docs/administration/08-advanced/07-provisioning.md

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 3, 2026

Codecov Report

❌ Patch coverage is 97.50000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 96.71%. Comparing base (2ec467d) to head (399dcd2).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
app/Console/Commands/ProvisionCommand.php 97.36% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop    #3014      +/-   ##
=============================================
+ Coverage      96.70%   96.71%   +0.01%     
- Complexity      1905     1911       +6     
=============================================
  Files            445      445              
  Lines          12885    12892       +7     
  Branches        2077     2077              
=============================================
+ Hits           12460    12469       +9     
+ Misses           425      423       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@pizkaz pizkaz force-pushed the fix/provisioning-bbb-servers branch 3 times, most recently from fd896a6 to 02f4d5f Compare April 3, 2026 16:57
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
app/Console/Commands/ProvisionCommand.php (2)

62-68: Minor: $data->servers->add ?? [] is evaluated twice.

The add array is evaluated once for count() and again for foreach. This is negligible for performance but could be consolidated for clarity.

♻️ Optional: assign once and reuse
             if (isset($data->servers)) {
-                $n = count($data->servers->add ?? []);
-                info("Provisioning $n servers");
-                foreach ($data->servers->add ?? [] as $item) {
+                $add = $data->servers->add ?? [];
+                info('Provisioning ' . count($add) . ' servers');
+                foreach ($add as $item) {
                     $this->provision->server->create($item);
                 }
             }

This pattern could be applied to all similar blocks (server_pools, room_types, roles, users).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Console/Commands/ProvisionCommand.php` around lines 62 - 68, The code
evaluates $data->servers->add twice; assign the add array to a local variable
(e.g., $serversToAdd = $data->servers->add ?? []) then use count($serversToAdd)
and foreach ($serversToAdd as $item) to avoid duplicate evaluation and improve
clarity; apply the same refactor pattern to the other similar blocks
(server_pools, room_types, roles, users) and keep calls to
$this->provision->server->create($item) unchanged.

44-57: Wipe conditions are correct but could be more readable.

The nested ternary isset($data->X) ? $data->X->wipe ?? false : false works correctly but is verbose. A simpler pattern using logical AND short-circuits identically:

♻️ Optional simplification
-            if (isset($data->room_types) ? $data->room_types->wipe ?? false : false) {
+            if (isset($data->room_types) && ($data->room_types->wipe ?? false)) {
                 $this->provision->roomType->destroy();
             }
-            if (isset($data->server_pools) ? $data->server_pools->wipe ?? false : false) {
+            if (isset($data->server_pools) && ($data->server_pools->wipe ?? false)) {
                 $this->provision->serverPool->destroy();
             }
-            if (isset($data->servers) ? $data->servers->wipe ?? false : false) {
+            if (isset($data->servers) && ($data->servers->wipe ?? false)) {
                 $this->provision->server->destroy();
             }
-            if (isset($data->roles) ? $data->roles->wipe ?? false : false) {
+            if (isset($data->roles) && ($data->roles->wipe ?? false)) {
                 $this->provision->role->destroy();
             }
-            if (isset($data->users) ? $data->users->wipe ?? false : false) {
+            if (isset($data->users) && ($data->users->wipe ?? false)) {
                 $this->provision->user->destroy();
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Console/Commands/ProvisionCommand.php` around lines 44 - 57, The repeated
nested ternary checks for wipe flags are correct but verbose; replace each
pattern like isset($data->room_types) ? $data->room_types->wipe ?? false : false
with a short-circuit expression using logical AND and null coalescing (e.g.,
isset($data->room_types) && ($data->room_types->wipe ?? false)) for the
roomType, serverPool, server, role, and user wipe checks that call
$this->provision->roomType->destroy(), $this->provision->serverPool->destroy(),
$this->provision->server->destroy(), $this->provision->role->destroy(), and
$this->provision->user->destroy() respectively so the semantics remain identical
but the code is more readable.
tests/Backend/Unit/ProvisioningServiceTest.php (1)

152-162: Consider adding a test case for endpoints already ending with a slash.

While Str::finish() correctly handles this (it won't double the slash), an explicit test would document the expected behavior and guard against regressions if the implementation changes.

🧪 Optional additional test
/**
 * Test server creation with endpoint already having trailing slash
 */
public function test_server_create_endpoint_with_trailing_slash()
{
    $this->testServer->endpoint = 'https://bbb.testdoma.in/';
    $this->svc->server->create($this->testServer);
    $server = Server::firstWhere('name', $this->testServer->name);
    $this->assertNotNull($server);
    $this->assertEquals('https://bbb.testdoma.in/', $server->base_url);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Backend/Unit/ProvisioningServiceTest.php` around lines 152 - 162, Add a
new unit test that verifies create() preserves a trailing slash on endpoints so
it doesn't double or strip it: extend the tests near test_server_create by
adding a test (e.g., test_server_create_endpoint_with_trailing_slash) that sets
$this->testServer->endpoint to a URL that already ends with '/' before calling
$this->svc->server->create($this->testServer), then fetch the record with
Server::firstWhere('name', $this->testServer->name) and assert the saved
base_url equals the original URL with the trailing slash; this will document and
protect the behavior handled by Str::finish() in the create() implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/Console/Commands/ProvisionCommand.php`:
- Around line 62-68: The code evaluates $data->servers->add twice; assign the
add array to a local variable (e.g., $serversToAdd = $data->servers->add ?? [])
then use count($serversToAdd) and foreach ($serversToAdd as $item) to avoid
duplicate evaluation and improve clarity; apply the same refactor pattern to the
other similar blocks (server_pools, room_types, roles, users) and keep calls to
$this->provision->server->create($item) unchanged.
- Around line 44-57: The repeated nested ternary checks for wipe flags are
correct but verbose; replace each pattern like isset($data->room_types) ?
$data->room_types->wipe ?? false : false with a short-circuit expression using
logical AND and null coalescing (e.g., isset($data->room_types) &&
($data->room_types->wipe ?? false)) for the roomType, serverPool, server, role,
and user wipe checks that call $this->provision->roomType->destroy(),
$this->provision->serverPool->destroy(), $this->provision->server->destroy(),
$this->provision->role->destroy(), and $this->provision->user->destroy()
respectively so the semantics remain identical but the code is more readable.

In `@tests/Backend/Unit/ProvisioningServiceTest.php`:
- Around line 152-162: Add a new unit test that verifies create() preserves a
trailing slash on endpoints so it doesn't double or strip it: extend the tests
near test_server_create by adding a test (e.g.,
test_server_create_endpoint_with_trailing_slash) that sets
$this->testServer->endpoint to a URL that already ends with '/' before calling
$this->svc->server->create($this->testServer), then fetch the record with
Server::firstWhere('name', $this->testServer->name) and assert the saved
base_url equals the original URL with the trailing slash; this will document and
protect the behavior handled by Str::finish() in the create() implementation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fc5201b6-92d9-4c48-8763-b34feb02afb4

📥 Commits

Reviewing files that changed from the base of the PR and between 05f6800 and 02f4d5f.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • app/Console/Commands/ProvisionCommand.php
  • app/Services/ProvisioningService.php
  • docs/docs/administration/08-advanced/07-provisioning.md
  • tests/Backend/Unit/ProvisioningServiceTest.php
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/docs/administration/08-advanced/07-provisioning.md

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/Backend/Unit/Console/ProvisionCommandTest.php`:
- Around line 39-55: The fixture provisioning_data-partial.json doesn't include
the data the test_provisioning_partial expects; update the fixture so the
ProvisionCommand (which only reads the fixture's "add" arrays) will create the
expected records: add a server_pools.add entry with name "default"; add a
room_types object containing an add array with four room type objects (include
one with name "Meeting") following the structure used in provisioning_data.json;
and set settings.recording.recording_retention_period to the string "365" to
match the fixture format.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 402b7088-7066-4bd1-8154-7bbfb44ccb38

📥 Commits

Reviewing files that changed from the base of the PR and between 02f4d5f and 7ea787f.

📒 Files selected for processing (3)
  • app/Console/Commands/ProvisionCommand.php
  • tests/Backend/Fixtures/provisioning_data-partial.json
  • tests/Backend/Unit/Console/ProvisionCommandTest.php
✅ Files skipped from review due to trivial changes (1)
  • tests/Backend/Fixtures/provisioning_data-partial.json

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/Console/Commands/ProvisionCommand.php`:
- Around line 44-57: Move the payload file reading and json_decode call into the
existing try block inside the ProvisionCommand handler, replace json_decode with
json_decode(..., flags: JSON_THROW_ON_ERROR) so invalid JSON throws, and
explicitly check the return of file_get_contents() before decoding (throw an
exception if it returns false or empty). Ensure the catch block handles the
thrown exceptions so the command fails instead of silently proceeding; update
references where $data is used (the null-safe checks around $data?->room_types
etc. and the transaction block that calls $this->provision->roomType->destroy(),
serverPool->destroy(), server->destroy(), role->destroy(), user->destroy()) to
rely on a validated $data object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a0184dd0-4bf3-40b6-beff-b039df5d8877

📥 Commits

Reviewing files that changed from the base of the PR and between 7ea787f and 2f1b6c0.

📒 Files selected for processing (1)
  • app/Console/Commands/ProvisionCommand.php

Comment on lines +44 to 57
if ($data?->room_types?->wipe ?? false) {
$this->provision->roomType->destroy();
}
if ($data->server_pools->wipe) {
if ($data?->server_pools?->wipe ?? false) {
$this->provision->serverPool->destroy();
}
if ($data->servers->wipe) {
if ($data?->servers?->wipe ?? false) {
$this->provision->server->destroy();
}
if ($data->roles->wipe) {
if ($data?->roles?->wipe ?? false) {
$this->provision->role->destroy();
}
if ($data->users->wipe) {
if ($data?->users?->wipe ?? false) {
$this->provision->user->destroy();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the ProvisionCommand.php file to see the full context
find . -type f -name "ProvisionCommand.php" | head -5

Repository: THM-Health/PILOS

Length of output: 103


🏁 Script executed:

# Get the file size and read it
wc -l app/Console/Commands/ProvisionCommand.php

Repository: THM-Health/PILOS

Length of output: 105


🏁 Script executed:

# Read the entire ProvisionCommand.php to understand the payload handling
cat -n app/Console/Commands/ProvisionCommand.php

Repository: THM-Health/PILOS

Length of output: 4795


Move payload decoding into the try block and enforce a valid JSON object root.

Lines 38-40 currently decode outside the try-catch, so json_decode() and file_get_contents() errors are unhandled. If the JSON file is invalid or missing, both return falsy values that silently pass through all the null-safe and isset guards (lines 44-110), causing the command to succeed with an empty transaction. Add explicit validation by moving the decode into the try block, using JSON_THROW_ON_ERROR to catch invalid JSON, and checking file_get_contents() explicitly.

Suggested approach
-        $data = json_decode(file_get_contents($this->argument('path')));
-
-        try {
+        try {
+            $json = file_get_contents($this->argument('path'));
+            if ($json === false) {
+                throw new \RuntimeException("Could not read provisioning file '{$this->argument('path')}'");
+            }
+
+            $data = json_decode($json, false, 512, JSON_THROW_ON_ERROR);
+            if (! is_object($data)) {
+                throw new \UnexpectedValueException('Provisioning data must be a JSON object.');
+            }
+
             DB::beginTransaction();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/Console/Commands/ProvisionCommand.php` around lines 44 - 57, Move the
payload file reading and json_decode call into the existing try block inside the
ProvisionCommand handler, replace json_decode with json_decode(..., flags:
JSON_THROW_ON_ERROR) so invalid JSON throws, and explicitly check the return of
file_get_contents() before decoding (throw an exception if it returns false or
empty). Ensure the catch block handles the thrown exceptions so the command
fails instead of silently proceeding; update references where $data is used (the
null-safe checks around $data?->room_types etc. and the transaction block that
calls $this->provision->roomType->destroy(), serverPool->destroy(),
server->destroy(), role->destroy(), user->destroy()) to rely on a validated
$data object.

@samuelwei samuelwei force-pushed the fix/provisioning-bbb-servers branch from 2f1b6c0 to 5c65908 Compare April 8, 2026 14:57
@samuelwei samuelwei merged commit 42f6c6f into THM-Health:develop Apr 8, 2026
16 of 17 checks passed
@pizkaz pizkaz deleted the fix/provisioning-bbb-servers branch April 9, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

API URLs of BBB Servers added with the provisioning command miss a '/' at the end

2 participants