Skip to content

Add user configurable fleetd base URL#48136

Closed
William-TecNQ wants to merge 11 commits into
fleetdm:mainfrom
William-TecNQ:williamb-add-dynamic-fleetd-manifest-url
Closed

Add user configurable fleetd base URL#48136
William-TecNQ wants to merge 11 commits into
fleetdm:mainfrom
William-TecNQ:williamb-add-dynamic-fleetd-manifest-url

Conversation

@William-TecNQ

@William-TecNQ William-TecNQ commented Jun 23, 2026

Copy link
Copy Markdown

Related issue: Resolves #48060

Checklist for submitter

If some of the following don't apply, delete the relevant line.

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features
    • Added a “Fleet Agent base URL” option under Advanced Options in Fleet settings to override where hosts download fleetd from.
  • User Experience
    • Includes URL validation, dedicated error messaging, and help text with a guide link for self-hosted automatic enrollment.
  • Behavioral Updates
    • The configured base URL is now used to generate fleetd metadata/manifest URLs for installer-related MDM flows, based on the latest app configuration returned to clients.

Copilot AI review requested due to automatic review settings June 23, 2026 22:26
@William-TecNQ William-TecNQ requested review from a team as code owners June 23, 2026 22:26

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.33333% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.23%. Comparing base (264036b) to head (545e4fe).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
server/service/microsoft_mdm.go 40.00% 2 Missing and 1 partial ⚠️
server/worker/apple_mdm.go 66.66% 1 Missing and 2 partials ⚠️
.../admin/OrgSettingsPage/cards/Advanced/Advanced.tsx 60.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #48136      +/-   ##
==========================================
- Coverage   67.32%   67.23%   -0.10%     
==========================================
  Files        3657     3657              
  Lines      231233   231319      +86     
  Branches    12062    12211     +149     
==========================================
- Hits       155676   155521     -155     
- Misses      61590    61864     +274     
+ Partials    13967    13934      -33     
Flag Coverage Δ
backend 68.83% <72.72%> (-0.12%) ⬇️
frontend 58.41% <75.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 703cc2b8-a449-40c3-999d-163ea93b8a32

📥 Commits

Reviewing files that changed from the base of the PR and between 6c3edb8 and 545e4fe.

📒 Files selected for processing (5)
  • cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigEmpty.yml
  • cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml
  • server/datastore/mysql/schema.sql
  • server/worker/apple_mdm.go
  • tools/cloner-check/generated_files/appconfig.txt
✅ Files skipped from review due to trivial changes (2)
  • cmd/fleetctl/fleetctl/testdata/macosSetupExpectedAppConfigSet.yml
  • tools/cloner-check/generated_files/appconfig.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/worker/apple_mdm.go

Walkthrough

A new fleetd_base_url configuration field is introduced end-to-end. On the backend, an AgentSettings struct with FleetdBaseURL is added to AppConfig and exposed via the app config API response. The pkg/fleetdbase package's GetMetadata and GetPKGManifestURL functions are updated to accept a configBaseURL string, with getBaseURL falling back through the config value, an environment variable, and a hardcoded default. The Apple MDM worker and Microsoft MDM enrollment command paths are updated to load AppConfig and pass AgentSettings.FleetdBaseURL to these functions. In the frontend, the Advanced org settings form gains a fleetdBaseURL field with validation, initial state population from appConfig.agent_settings?.fleetd_base_url, and a save payload mapping; a corresponding InputField is rendered in ServerAuthenticationSection. All affected fleetdbase unit tests and MDM/VPP integration tests are updated to match the new function signatures.

Possibly related PRs

  • fleetdm/fleet#47736: Both PRs modify server/service/microsoft_mdm.go's enqueueInstallFleetdCommand flow for fleetd installation (one changes how commands are enqueued to preserve Add/Exec order, the other threads agent_settings.fleetd_base_url into fleetdbase.GetMetadata).
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'Add user configurable fleetd base URL' clearly summarizes the main change: enabling users to configure a custom base URL for fleetd package retrieval.
Description check ✅ Passed The pull request description covers the essential checklist items with clear confirmations: changes file added, input validation verified, automated tests added/updated, and manual QA completed.
Linked Issues check ✅ Passed The PR fully satisfies issue #48060 requirements: adds configurable fleetd base URL in Advanced Options, validates input data, implements backend support for custom base URL resolution, includes proper tests and manual QA verification.
Out of Scope Changes check ✅ Passed All changes are directly aligned with adding user-configurable fleetd base URL: frontend UI, configuration structures, validation logic, backend resolution, tests, and test data updates. No out-of-scope modifications detected.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/fleetdbase/fleetd_base_test.go (1)

13-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add precedence and trailing-slash coverage for the new base URL contract.

Current tests validate env-only and config-only cases, but not the critical configURL + env precedence or trailing-slash behavior.

Suggested test additions
 func TestGetBaseURL(t *testing.T) {
+	t.Run("configURL takes precedence over env variable", func(t *testing.T) {
+		dev_mode.SetOverride("FLEET_DEV_DOWNLOAD_FLEETDM_URL", "https://download-testing.fleetdm.com", t)
+		require.Equal(t, "https://download.test.com", getBaseURL("https://download.test.com"))
+	})
+
 	t.Run("with env variable", func(t *testing.T) {
 		dev_mode.SetOverride("FLEET_DEV_DOWNLOAD_FLEETDM_URL", "https://download-testing.fleetdm.com", t)
 		require.Equal(t, "https://download-testing.fleetdm.com", getBaseURL(""))
 	})
@@
 func TestGetPKGManifestURL(t *testing.T) {
+	t.Run("configURL with trailing slash", func(t *testing.T) {
+		require.Equal(t, "https://download.test.com/stable/fleetd-base-manifest.plist", GetPKGManifestURL("https://download.test.com/"))
+	})
+
 	t.Run("with env variable", func(t *testing.T) {
 		dev_mode.SetOverride("FLEET_DEV_DOWNLOAD_FLEETDM_URL", "https://download-test.fleetdm.com", t)
 		require.Equal(t, "https://download-test.fleetdm.com/stable/fleetd-base-manifest.plist", GetPKGManifestURL(""))
 	})

Also applies to: 88-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/fleetdbase/fleetd_base_test.go` around lines 13 - 25, The TestGetBaseURL
test function lacks coverage for two critical scenarios: precedence when both
configURL and the FLEET_DEV_DOWNLOAD_FLEETDM_URL environment variable are set,
and handling of trailing slashes in URLs. Add a test case using t.Run that sets
both the FLEET_DEV_DOWNLOAD_FLEETDM_URL environment variable via
dev_mode.SetOverride and passes a non-empty configURL parameter to getBaseURL to
verify which value takes precedence. Additionally, add separate test cases to
verify that the getBaseURL function correctly handles trailing slashes in
configURL values, testing both cases where configURL has a trailing slash and
where it does not.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/fleetdbase/fleetd_base.go`:
- Around line 22-35: The getBaseURL function returns the configBaseURL as-is
without normalizing it, which causes malformed URLs with double slashes when
admins provide a trailing slash (e.g., https://mirror.local/fleetd/ becomes
https://mirror.local/fleetd//stable/meta.json). In the getBaseURL function,
before returning configBaseURL on line 23 or any other returned URL value, trim
any trailing slashes to ensure URLs are properly normalized. This normalization
should also be applied to other URL construction locations referenced at lines
60-62 to maintain consistency across all path appending operations.

---

Nitpick comments:
In `@pkg/fleetdbase/fleetd_base_test.go`:
- Around line 13-25: The TestGetBaseURL test function lacks coverage for two
critical scenarios: precedence when both configURL and the
FLEET_DEV_DOWNLOAD_FLEETDM_URL environment variable are set, and handling of
trailing slashes in URLs. Add a test case using t.Run that sets both the
FLEET_DEV_DOWNLOAD_FLEETDM_URL environment variable via dev_mode.SetOverride and
passes a non-empty configURL parameter to getBaseURL to verify which value takes
precedence. Additionally, add separate test cases to verify that the getBaseURL
function correctly handles trailing slashes in configURL values, testing both
cases where configURL has a trailing slash and where it does not.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2c0833df-0f39-4921-b47e-b0f403fc4d58

📥 Commits

Reviewing files that changed from the base of the PR and between 264036b and 265335d.

⛔ Files ignored due to path filters (1)
  • articles/self-host-fleetd-for-automatic-enrollment.md is excluded by !**/*.md
📒 Files selected for processing (16)
  • changes/48060-self-host-fleetd-base-url
  • frontend/__mocks__/configMock.ts
  • frontend/interfaces/config.ts
  • frontend/pages/admin/OrgSettingsPage/cards/Advanced/Advanced.tsx
  • frontend/pages/admin/OrgSettingsPage/cards/Advanced/components/ServerAuthenticationSection/ServerAuthenticationSection.tsx
  • pkg/fleetdbase/fleetd_base.go
  • pkg/fleetdbase/fleetd_base_test.go
  • server/fleet/app.go
  • server/service/appconfig.go
  • server/service/integration_apple_vpp_config_test.go
  • server/service/integration_mdm_dep_test.go
  • server/service/integration_mdm_lifecycle_test.go
  • server/service/integration_mdm_test.go
  • server/service/integration_vpp_install_test.go
  • server/service/microsoft_mdm.go
  • server/worker/apple_mdm.go

Comment on lines +22 to 35
func getBaseURL(configBaseURL string) string {
if configBaseURL != "" {
return configBaseURL
}
devURL := dev_mode.Env("FLEET_DEV_DOWNLOAD_FLEETDM_URL")
if devURL != "" {
return devURL
}
return "https://download.fleetdm.com"
}

func GetMetadata() (*Metadata, error) {
baseURL := getBaseURL()
func GetMetadata(configBaseURL string) (*Metadata, error) {
baseURL := getBaseURL(configBaseURL)
rawURL := fmt.Sprintf("%s/stable/meta.json", baseURL)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Normalize base URL before appending /stable/... paths.

Returning configBaseURL as-is on Line 23 can produce malformed URLs like https://mirror.local/fleetd//stable/meta.json and ...//stable/fleetd-base-manifest.plist when admins enter a trailing slash.

Suggested fix
 import (
 	"encoding/json"
 	"fmt"
 	"net/http"
 	"net/url"
+	"strings"

 	"github.com/fleetdm/fleet/v4/server/dev_mode"
 )

 func getBaseURL(configBaseURL string) string {
 	if configBaseURL != "" {
-		return configBaseURL
+		return strings.TrimRight(configBaseURL, "/")
 	}
 	devURL := dev_mode.Env("FLEET_DEV_DOWNLOAD_FLEETDM_URL")
 	if devURL != "" {
-		return devURL
+		return strings.TrimRight(devURL, "/")
 	}
 	return "https://download.fleetdm.com"
 }

Also applies to: 60-62

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/fleetdbase/fleetd_base.go` around lines 22 - 35, The getBaseURL function
returns the configBaseURL as-is without normalizing it, which causes malformed
URLs with double slashes when admins provide a trailing slash (e.g.,
https://mirror.local/fleetd/ becomes
https://mirror.local/fleetd//stable/meta.json). In the getBaseURL function,
before returning configBaseURL on line 23 or any other returned URL value, trim
any trailing slashes to ensure URLs are properly normalized. This normalization
should also be applied to other URL construction locations referenced at lines
60-62 to maintain consistency across all path appending operations.

Copilot AI left a comment

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.

Pull request overview

Adds a user-configurable fleetd base URL (via org advanced settings) and threads it through Apple (manifest URL) and Windows (meta.json fetch) MDM enrollment flows so environments with restricted outbound access can self-host the fleetd artifacts.

Changes:

  • Introduces agent_settings.fleetd_base_url in app config and returns it from /fleet/config.
  • Uses the configured base URL when generating the macOS manifest URL and when fetching Windows fleetd-base metadata.
  • Updates integration/unit tests and adds a new guide article + changelog entry.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
server/worker/apple_mdm.go Uses app config fleetd_base_url when generating the macOS fleetd manifest URL for MDM install.
server/service/microsoft_mdm.go Uses app config fleetd_base_url when fetching fleetd-base metadata for Windows MDM install.
server/service/integration_vpp_install_test.go Updates integration tests to validate manifest URL generation against configured base URL.
server/service/integration_mdm_test.go Updates shared helper to assert manifest URL using configured base URL; updates call sites.
server/service/integration_mdm_lifecycle_test.go Updates assertions to match configured fleetd base URL behavior.
server/service/integration_mdm_dep_test.go Updates DEP-related assertions to match configured fleetd base URL behavior.
server/service/integration_apple_vpp_config_test.go Updates assertions for fleetd install command to use configured base URL.
server/service/appconfig.go Includes AgentSettings in the config response payload.
server/fleet/app.go Adds AgentSettings and fleetd_base_url to the app config model.
pkg/fleetdbase/fleetd_base.go Makes fleetd-base URL helpers accept a configured base URL.
pkg/fleetdbase/fleetd_base_test.go Updates unit tests for new fleetdbase function signatures and config override behavior.
frontend/pages/admin/OrgSettingsPage/cards/Advanced/components/ServerAuthenticationSection/ServerAuthenticationSection.tsx Adds “Fleet Agent base URL” UI field with tooltip/help link.
frontend/pages/admin/OrgSettingsPage/cards/Advanced/Advanced.tsx Adds form state, validation, and payload wiring for agent_settings.fleetd_base_url.
frontend/interfaces/config.ts Extends IConfig with agent_settings.fleetd_base_url.
frontend/mocks/configMock.ts Updates config mock to include agent_settings.
changes/48060-self-host-fleetd-base-url Adds changelog entry for the new setting.
articles/self-host-fleetd-for-automatic-enrollment.md Adds a guide describing self-hosting the fleetd artifacts and configuring the base URL.
Comments suppressed due to low confidence (1)

pkg/fleetdbase/fleetd_base.go:38

  • rawURL := fmt.Sprintf("%s/stable/meta.json", baseURL) will produce a double slash when fleetd_base_url ends with / (e.g. https://example.com/https://example.com//stable/...), which can break self-hosted setups depending on the web server/proxy. Building the URL via url.JoinPath avoids that class of errors and correctly handles base URLs that include a subdirectory.
	baseURL := getBaseURL(configBaseURL)
	rawURL := fmt.Sprintf("%s/stable/meta.json", baseURL)

	parsedURL, err := url.Parse(rawURL)
	if err != nil {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/fleetdbase/fleetd_base.go Outdated
@@ -1,4 +1,4 @@
// pacakge fleetdbase contains functions to interact with downloads.fleetdm.com
// package fleetdbase contains functions to interact with downloads.fleetdm.com
Comment on lines +60 to 63
func GetPKGManifestURL(configBaseURL string) string {
baseURL := getBaseURL(configBaseURL)
return fmt.Sprintf("%s/stable/fleetd-base-manifest.plist", baseURL)
}
Comment on lines +33 to 37
func GetMetadata(configBaseURL string) (*Metadata, error) {
baseURL := getBaseURL(configBaseURL)
rawURL := fmt.Sprintf("%s/stable/meta.json", baseURL)

parsedURL, err := url.Parse(rawURL)
fleetdBaseURL := appCfg.AgentSettings.FleetdBaseURL
fleetdMetadata, err := fleetdbase.GetMetadata(fleetdBaseURL)
if err != nil {
svc.logger.WarnContext(ctx, "unable to get fleetd-base metadata")
Comment on lines 229 to 231
ConditionalAccess: appConfig.ConditionalAccess,
AgentSettings: appConfig.AgentSettings,
},
Comment thread server/worker/apple_mdm.go Outdated
Comment on lines +565 to +570
func (a *AppleMDM) installFleetd(ctx context.Context, hostUUID string) (string, error) {
manifestURL := fleetdbase.GetPKGManifestURL()
cfg, err := a.Datastore.AppConfig(ctx)
if err != nil {
return "", ctxerr.Wrap(ctx, err, "retrieving app config")
}
manifestURL := fleetdbase.GetPKGManifestURL(cfg.AgentSettings.FleetdBaseURL)
Comment on lines +18 to +19
* [fleetd-base.pkg](https://download.fleetdm.com/stable/fleetd-base.pkg) - Used for MacOS enrollments
* [fleetd-base-manifest.plist](https://download.fleetdm.com/stable/fleetd-base-manifest.plist) - Used for MacOS enrollments
Comment on lines +5 to +6
This can be configured to ensure that host enrollments are successful in environments with strict network access

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/worker/apple_mdm.go`:
- Around line 174-175: In the `runPostDEPEnrollment` function, `appCfg` is only
loaded when `args.TeamID == nil`, leaving it nil for team-based DEP enrollment.
When `!manualAgentInstall` is true, this causes `installFleetd` to receive a nil
`appCfg` and panic when dereferencing `cfg.AgentSettings.FleetdBaseURL`. Before
the call to `installFleetd(ctx, args.HostUUID, appCfg)` in the
`!manualAgentInstall` block, add logic to load `appCfg` for the team-based case
using the existing `getAppConfig` function (which handles lazy caching),
ensuring `appCfg` is never nil when passed to `installFleetd`.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d428cae-7bbc-42f7-aebe-ce89cb2317d1

📥 Commits

Reviewing files that changed from the base of the PR and between 265335d and 6c3edb8.

⛔ Files ignored due to path filters (1)
  • articles/self-host-fleetd-for-automatic-enrollment.md is excluded by !**/*.md
📒 Files selected for processing (2)
  • pkg/fleetdbase/fleetd_base.go
  • server/worker/apple_mdm.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/fleetdbase/fleetd_base.go

Comment thread server/worker/apple_mdm.go
@mike-j-thomas mike-j-thomas requested review from noahtalerman and removed request for mike-j-thomas June 26, 2026 10:20
@noahtalerman noahtalerman marked this pull request as draft June 29, 2026 15:30
@noahtalerman noahtalerman removed their request for review June 29, 2026 15:30
@noahtalerman

Copy link
Copy Markdown
Member

Thanks @William-TecNQ!

Up to @melpike as Product Designer per the community PR process: https://fleetdm.com/handbook/engineering#review-a-community-pull-request

@melpike

melpike commented Jul 2, 2026

Copy link
Copy Markdown
Member

Hey @William-TecNQ, are you allow listing Apple but not Fleet?

Best practice is to let devices talk to Apple’s services and fleetdm.com.

Apple services are required for ADE enrollment, while updates.fleetdm.com are required for Fleet’s agent to update.

One option is to use the dev flag FLEET_DEV_DOWNLOAD_FLEETDM_URL. This is undocumented—we use it for testing but don’t use it in production. Use at your own risk.

We'll close this PR for now and leave the feature request open.

@melpike melpike closed this Jul 2, 2026
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.

Self host fleetd base URL

4 participants