Skip to content

Software Packaging with WinRepo-NG

Summary

This guide explains how to configure WinRepo-NG on a Salt master to deploy custom Windows software using Salt’s native pkg.* states.

Installer binaries are hosted externally (for example in Artifactory), while package metadata is managed in a Git repository. This separates binary distribution from configuration logic and allows software deployment to be version-controlled, repeatable, and environment-aware.


High-level Process

  1. Upload installer binaries to Artifactory or an HTTP-accessible repository.

  2. Configure the Salt master to use WinRepo-NG.

  3. Store WinRepo package definition files (*.sls) in Git.

  4. Regenerate the WinRepo metadata database.

  5. Use pkg.* states to install or remove software.

Flow diagram

WinRepo Flow Diagram

Architecture Overview

WinRepo-NG separates responsibilities:

  • Binary distribution: HTTP repository (Artifactory)

  • Package metadata: Git repository

  • Deployment logic: Salt states

  • Execution: Salt minions

This separation allows:

  • Centralised version control

  • Controlled promotion across environments

  • Clear auditability of software changes


Detailed setup

Binary file distribution (Artifactory)

There must be a centralised location where Salt minions fetch installer binaries.
In production this will typically be something like Artifactory. In a lab environment, an NGINX web server is used to simulate the same HTTP directory structure as Artifactory.

Configure Salt master

Create winrepo.conf file

Create a new configuration file on the Salt master:/etc/salt/master.d/winrepo.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
winrepo_dir_ng: /srv/salt/win/repo-ng

# Winrepo-ng settings
winrepo_provider: pygit2
winrepo_branch: main

# Turn off the legacy HTTP winrepo
winrepo_remotes: []

# Point NG at your SSH repo of package definitions
winrepo_remotes_ng:
  - git@github.com:<USERNAME>/<REPO NAME>.git  # (1)

# SSH key for winrepo-ng
winrepo_pubkey: <PATH TO PUBLIC KEY>
winrepo_privkey: <PATH TO PRIVATE KEY>

# Cache file 
winrepo_cachefile: 'winrepo.p'
  1. Replace <USERNAME> and <REPO NAME> with your actual GitHub account and repository.
    Example: git@github.com:mattwarren/salt-winrepo.git

Restart Salt master to load the config:

systemctl restart salt-master

Create the winrepo required directories

winrepo_dir_ng is a local cache directory on the Salt master where WinRepo-NG clones and renders package metadata. It is only a local cache location and does not need to mirror the Git repository structure.

mkdir -p /srv/salt/win/repo-ng

Create software package definition files (WinRepo)

Each software component needs a WinRepo definition file. Place these files in your git repo. WinRepo-NG recursively scans the configured git repository for windows/*.sls files. The top-level directory name (for example repo-ng/) is arbitrary and does not need to match winrepo_dir_ng

Sample git repository directory structure:

repo-ng/
└── windows/
    ├── 7zip.sls
    └── Firefox.sls

Here is an example /repo-ng/windows/7zip.sls package:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
7zip:
  {% set base = 'https://<URL to Fileserver/Artifactory dir>' %}  # (1)

  '25.01.00.0':  # (2)
    installer: '{{ base }}/25.01/7z2501-x64.msi'
    full_name: '7-Zip 25.01 (x64 edition)'  # (3)
    reboot: False
    msiexec: True
    install_flags: '/quiet /norestart'
    uninstall_flags: '/quiet /norestart'
  1. Replace this with your internal fileserver or Artifactory base URL.
  2. Must match the exact MSI product version, not just the marketing version.
  3. Must exactly match the application name shown in Add/Remove Programs (Appwiz.cpl), or Salt will fail the install check.

Note that the directory structure used in the installer: URL must resolve to a direct HTTP link to the file. You can test it by building the path manually and then using curl or wget to retrieve it from a test minion machine.

Rebuild the WinRepo metadata

After creating or modifying WinRepo definitions, run the following on the master to refresh from git and then regenerate the repo.

salt-run winrepo.update_git_repos  # (1)
salt-run winrepo.genrepo           # (2)
  1. Pull latest package definitions from Git.
  2. Regenerate the WinRepo metadata database.

You must also force a refresh on any existing minions that you want to target with any new software definitions:

salt 'existing-minion-id' pkg.refresh_db

Verify the new package definitions are available to minions

Run the following command on a test minion to verify the new packages are available

salt <minion> pkg.list_available

If the package does not appear, ensure:

  • winrepo.update_git_repos completed successfully

  • winrepo.genrepo ran without errors

  • The minion has refreshed its package database


Deploying Software in States

In your deployment state use the pkg abstraction layer module to install or remove software:

# Ensure 7zip is present at the specific version
install_7zip:
  pkg.installed:
    - name: 7zip
    - version: '25.01.00.0'

Notes:

  • Remove the version: line if you want Salt to install the latest defined version.
  • You can also install directly from the command line using:
salt 'win-test' pkg.install 7zip

This allows software deployment to remain abstracted from installer mechanics.

See also