Skip to main content
This setup is a package manager client deployment. MDM pushes the Package Firewall configuration to developer machines. Mobile device management (MDM) deployment lets an IT administrator configure many developer machines at once. You generate a self-contained script, push it through your MDM tool, and it configures each machine’s package manager clients to route installations through Package Firewall. Developers do nothing, and the scripts preserve existing package manager client configuration. The scripts cover the following ecosystems. They are idempotent, so they are safe to re-run on every MDM check-in, and they have no runtime dependencies beyond the shell. The Package Firewall MDM scripts also cover protection against malicious VS Code extensions from the Microsoft Marketplace. See VS Code extensions to learn more.
The scripts are available in the Endor Labs MDM scripts repository under the package-firewall/ directory.

Before you begin

Create an API key dedicated to the Package Firewall so that the deployment scripts can authenticate to it. You can create it through one of the following methods:
  • Using the Endor Labs user interface, with the Package Firewall User role. See API keys to learn more.
  • Using endorctl, with the SYSTEM_ROLE_PACKAGE_FIREWALL role. Make sure to install and configure endorctl before you create the key.
To create the key using endorctl, run the following command and replace:
  • <namespace> with your namespace.
  • <API key name> with the name of the API key for the Package Firewall use case.
  • <YYYY-MM-DDTHH:MM:SSZ> with the API key expiration in ISO 8601 UTC format, for example 2026-12-31T23:59:59Z.

Generate the MDM scripts

Clone the generator repository and run it with your namespace and Package Firewall credentials. Select your platform for the matching commands.
The generated scripts default to https://factory.endorlabs.com. If you use Endor Labs with an EU tenant, set ENDOR_FQDN=https://factory.eu.endorlabs.com when you run the generator. The browser generator has a region picker for the same setting.
You can also generate the scripts in the browser using the MDM script generator. The generator fetches the real source files from the Endor Labs MDM scripts repository (https://github.com/endorlabs/mdm-scripts). The GitHub repository is the authoritative source for the scripts.
  1. Clone the generator repository: Clone the repository and change into the bash generator directory.
  2. Generate the scripts: Pass your credentials as environment variables. This keeps them out of your shell history.
    Alternatively, store the variables in a .env file, add .env to .gitignore, and source it.
The generator writes endor-js.sh, endor-python.sh, endor-go.sh, endor-maven.sh, endor-nuget.sh, endor-vscode.sh, endor-all.sh, and endor-remove.sh to out/<namespace>/. Re-running generate.sh overwrites the same directory.On macOS, endor-vscode.sh and endor-all.sh leave VS Code unchanged unless you add ENDOR_VSCODE_MACOS_DAEMON=1 to the generator command. Read Enable VS Code on macOS before you set it.
The generated scripts contain your API key and secret in plain text, because the scripts need them to write credentials on each device. MDM deployment then copies that one credential to every enrolled machine. Scope the key to the Package Firewall role only, keep the scripts and the out/ directory out of source control, restrict who can view the MDM policy, and rotate the key on a schedule by redeploying the script.

Upload the scripts to your MDM tool

Each generated script is self-contained with no runtime dependencies, so you upload it directly to your MDM tool. On macOS and Linux the scripts use the .sh extension. On Windows, they use .ps1.
Run the scripts as root. The script detects the logged-in console user and writes configuration files to the correct home directory.
  1. Add the script: Go to Library > Custom Scripts > Add Script.
  2. Provide the script: Paste the script content or upload the file.
  3. Set the run context: Set Run as to Root.
  4. Set the frequency: Set Execution Frequency to Run once per device, or to every check-in for ongoing enforcement.
  5. Assign the script: Assign the script to the relevant device blueprint.
  1. Add the script: Go to Settings > Scripts > New and paste the script content.
  2. Create a policy: Go to Policies > New Policy > Scripts and add your script.
  3. Set the frequency: Set the Execution Frequency as appropriate.
  4. Scope the policy: Scope the policy to the target devices.
Upload the script file and run it as root. The script detects the logged-in console user and writes configuration files to the correct home directory.

How credentials are stored

The scripts write your credentials to a single source on each device and reference them from the package manager client configuration files. The storage mechanism depends on your platform.
The scripts write all credentials to ~/.config/endor/env.sh and set the file permissions to 600.
Each shell profile (.zshrc, .bash_profile, and .bashrc) gets a one-line block that sources this file. The configuration files reference these variables instead of embedding credentials, except pip.conf, uv.toml, and the go env file, which cannot expand variables and get a literal index URL baked in at install time.To rotate credentials, redeploy the MDM script to update env.sh on the target machines. You do not need to change any configuration files.

User attribution

The generated scripts label each machine’s Package Firewall traffic with the developer who owns it. The firewall logs then attribute activity to a person and machine rather than to a shared API key. By default the label is <console-user>@<machine>, built at install time from the logged-in console user and the machine name. The scripts encode the label into the Basic-auth username they write for every package manager client they configure. They store the encoded username as ENDOR_ATTR_USER in the credential store, which is env.sh on macOS and Linux and HKCU:\Environment on Windows. See User attribution to choose a different label, learn how the encoding works, or attribute traffic from the other deployment models.

What the scripts do

Each install script writes the credential store and an Endor-managed block to the package manager client configuration files. The file locations depend on your platform.
The endor-js.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following files.The endor-go.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following file.The endor-python.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following files.The endor-maven.sh script writes ~/.config/endor/env.sh and an Endor-managed block to the following file.The endor-nuget.sh script writes ~/.config/endor/env.sh and Endor-managed blocks to the following file.

Configure each package manager client

The scripts apply a few package manager client-specific behaviors that are the same on every platform unless a bullet says otherwise.
  • JavaScript: The scripts write _auth (base64) instead of _authToken, which bun requires. Yarn classic reads authentication from .npmrc, so the .npmrc write covers it. The scripts do not write the project-level bunfig.toml.
  • Go: The scripts resolve the go env file path with go env GOENV, then write GOPROXY to it. If go is not installed, they fall back to the OS default path (~/Library/Application Support/go/env on macOS, ~/.config/go/env on Linux, or %APPDATA%\go\env on Windows). Credentials are literal because go env files cannot expand environment variables. The GOPROXY value ends in ,direct, so Go downloads a module directly from its source when the firewall does not serve it. The go env file applies to every go command regardless of shell, and it has lower precedence than the GOPROXY process variable, so project-level overrides still work.
  • Python (pip): The scripts write the pip settings in a [global] section. If the file already has a [global] section, they merge the Endor keys into it, because pip rejects duplicate [global] sections. The scripts disable any conflicting keys, such as an existing index-url, with an #endor-bak# prefix and restore them when the remove script runs.
  • Python (uv): uv ignores pip.conf, so the scripts write the user-level uv.toml with the firewall index URL. The scripts bake the URL in literally because uv cannot expand environment variables in its config, so it carries the attributed username.
  • Python (Poetry): Poetry reads credentials from the POETRY_HTTP_BASIC_ENDOR_FIREWALL_* environment variables, so you do not need a separate write step. Add the source to your pyproject.toml: Poetry reads the registry URL from pyproject.toml and the credentials from environment variables. Add the Package Firewall as a source in each project. The source includes the URL only, never the credentials.
  • Maven: The scripts write a user-level settings.xml (~/.m2/settings.xml, or %USERPROFILE%\.m2\settings.xml on Windows) with a <mirror> of * that points at the firewall, plus a matching <server>. Credentials are not baked into the file. The <server> references ${env.ENDOR_ATTR_USER} and ${env.ENDOR_API_SECRET}, which Maven resolves at runtime from the environment variables the credential store already sets. Gradle uses this too when it reads ~/.m2/settings.xml.
  • .NET (NuGet): The macOS and Linux scripts merge the Endor source into the existing <packageSources> section of ~/.nuget/NuGet/NuGet.Config. The block starts with <clear />, so the firewall replaces nuget.org and every other source listed before it. If the file lists a private feed, such as Artifactory or Azure Artifacts, the script warns and exits with code 1. Re-add that feed in a repository-level nuget.config, or use the JFrog Artifactory integration instead. Credentials are not baked into the file. The <packageSourceCredentials> entry references %ENDOR_ATTR_USER% and %ENDOR_API_SECRET%, which NuGet resolves at runtime from the environment variables that env.sh sets. IDEs launched outside a shell, for example from the macOS Dock, do not inherit env.sh, so their restores fail with a 401 error rather than bypassing the firewall.
    A repository-level nuget.config overrides the user-level file for that repository. A repository that commits <clear /> followed by nuget.org bypasses the firewall. For full enforcement, commit endor-firewall as the only public source in each repository. The key must be exactly endor-firewall so that the user-level credentials apply. A repository nuget.config that only adds a source keeps that source active next to the firewall.

Preserve existing configuration

The scripts use a sentinel block pattern. Each script writes only a clearly delimited section to a configuration file and leaves everything else untouched, so existing settings survive every deployment. The following example shows an .npmrc file that already contains administrator settings. The script adds only the Endor-managed block between the BEGIN and END markers.
The following table describes how the scripts handle each configuration scenario.

Remove the configuration

To offboard a machine, deploy the remove script. It strips the Endor block from every managed file and removes the credentials the install scripts added.
Deploy endor-remove.sh. It removes the Endor block from each configuration file and removes the credentials from ~/.config/endor/env.sh. For the macOS VS Code daemon, it also restores Microsoft’s original app when available and removes the signing identity. See Remove the daemon for the fallback when no original is available.

Security notes

The scripts store credentials on each device. Review the following before you deploy.

Generate your MDM script in the browser

Select your platform, ecosystem, MDM tool, and region, then enter your namespace and API key. The region sets the Package Firewall URL, and you can edit the URL directly. The generator builds the script entirely in your browser. It never sends your credentials to Endor Labs or GitHub, and only bakes them into the script you download. For Bash scripts that include VS Code, select Enable VS Code firewall on macOS to opt in to the daemon. It is off by default and has no effect on Linux. See Enable VS Code on macOS to review signing changes and user prompts before deploying.
The generated script contains your API key and secret in plain text, because the install script needs them to write credentials on each device. MDM deployment then copies that one credential to every enrolled machine. Scope the key to the Package Firewall role only, and keep generated scripts out of source control. Restrict who can view the MDM policy, and rotate the key on a schedule by redeploying the script.