From fd4e9eba8320659e827683f34a8cc02696d1f92c Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 10:44:09 -0400 Subject: [PATCH 01/26] Platform-specific defaults for Windows --- postman-api/parameters/os_family/Windows.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 postman-api/parameters/os_family/Windows.yaml diff --git a/postman-api/parameters/os_family/Windows.yaml b/postman-api/parameters/os_family/Windows.yaml new file mode 100644 index 0000000..998f9c0 --- /dev/null +++ b/postman-api/parameters/os_family/Windows.yaml @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +values: + config: + install_root: 'C:\Program Files\Postman' + wrapper_bin: 'C:\Program Files\Postman\postman.cmd' + pkg: + download_sig: '' + download_uri: 'https://dl.pstmn.io/download/latest/win64' + name: 'postman-api' + service: {} +... From 462567c14d84c54a72f8e23459c1ca217fbb9e0a Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 10:44:46 -0400 Subject: [PATCH 02/26] Download and execute installer/setup EXE Use an externalized powershell script (install_postman.ps1) to run the install: 1. Externalizing allows easier linting 2. Postman's use of Squirrel and expectation that installs will go to %localappdata%\Postman effectively necessitates use of a home-brewed installation script to work around the EXE's own limitations. --- postman-api/files/install_postman.ps1 | 91 +++++++++++++++++++++++++++ postman-api/package/win_install.sls | 26 ++++++++ 2 files changed, 117 insertions(+) create mode 100644 postman-api/files/install_postman.ps1 diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 new file mode 100644 index 0000000..a25cb3a --- /dev/null +++ b/postman-api/files/install_postman.ps1 @@ -0,0 +1,91 @@ +<# +.SYNOPSIS + Headless installation wrapper for the Squirrel-based Postman installer. +.DESCRIPTION + Installs Postman inside a headless Session 0 (SYSTEM) context. Because + the native Postman installer deadlocks trying to create interactive + desktop shortcuts, this script orchestrates a monitored extraction, + terminates the stuck processes, migrates binaries to a global target + root, and purges the temporary system profile staging directories. +.PARAMETER InstallRoot + The system-wide path where the Postman application binaries will be + permanently copied (e.g., 'C:\Program Files\Postman'). +.EXAMPLE + .\install_postman.ps1 -InstallRoot "C:\Program Files\Postman" +#> +param ( + [Parameter(Mandatory = $true)] + [string]$InstallRoot +) + +$SetupExe = 'C:\Windows\Temp\PostmanSetup.exe' +$StartArgs = @{ + ArgumentList = '--silent' + FilePath = $SetupExe +} +Start-Process @StartArgs + +$SourceDir = Join-Path $env:LOCALAPPDATA 'Postman' +$TimeoutSeconds = 90 +$Timer = [System.Diagnostics.Stopwatch]::StartNew() +$LastSize = -1 +$StableCount = 0 + +while ($StableCount -lt 3) { + if ($Timer.Elapsed.TotalSeconds -gt $TimeoutSeconds) { + break + } + Start-Sleep -Seconds 2 + if (Test-Path $SourceDir) { + $GciArgs = @{ + ErrorAction = 'SilentlyContinue' + File = $true + Path = $SourceDir + Recurse = $true + } + $Files = Get-ChildItem @GciArgs + $CurrentSize = ($Files | Measure-Object -Sum Length).Sum + if ($CurrentSize -eq $LastSize -and $CurrentSize -gt 0) { + $StableCount++ + } else { + $LastSize = $CurrentSize + $StableCount = 0 + } + } +} + +$KillList = @('PostmanSetup', 'Update', 'Postman') +foreach ($Name in $KillList) { + $KillArgs = @{ + ErrorAction = 'SilentlyContinue' + Force = $true + Name = $Name + } + Stop-Process @KillArgs +} + +if (Test-Path $SourceDir) { + if (!(Test-Path $InstallRoot)) { + $DirArgs = @{ + Force = $true + ItemType = 'Directory' + Path = $InstallRoot + } + New-Item @DirArgs + } + $CopyArgs = @{ + Destination = $InstallRoot + Force = $true + Path = Join-Path $SourceDir '*' + Recurse = $true + } + Copy-Item @CopyArgs + + $RemoveArgs = @{ + ErrorAction = 'SilentlyContinue' + Force = $true + Path = $SourceDir + Recurse = $true + } + Remove-Item @RemoveArgs +} diff --git a/postman-api/package/win_install.sls b/postman-api/package/win_install.sls index e69de29..9e7f4f9 100644 --- a/postman-api/package/win_install.sls +++ b/postman-api/package/win_install.sls @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} + +Download Postman Installer: + file.managed: + - makedirs: true + - name: 'C:\Windows\Temp\PostmanSetup.exe' + {%- if postman_api.pkg.download_sig %} + - source: '{{ postman_api.pkg.download_uri }}' + - source_hash: '{{ postman_api.pkg.download_sig }}' + {%- else %} + - skip_verify: true + - source: '{{ postman_api.pkg.download_uri }}' + {%- endif %} + +Execute Postman Installation: + cmd.script: + - args: '-InstallRoot "{{ postman_api.config.install_root }}"' + - require: + - file: Download Postman Installer + - shell: powershell + - source: salt://postman-api/files/install_postman.ps1 From b7d59f9feac0d71157d45629e8e37e4a5a0588c3 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 13:46:56 -0400 Subject: [PATCH 03/26] Try to ensure adequate idempotency: * Update `.../install_postman.ps1` script so that it will block when trying to install if there's already an installation and the installation is the same version as the to-be-installed version * Update `.../win_install.sls` state-file so that it uses a suitable requisite evaluation to determine if the to-be-installed version would be a reinstall of any present installed versions --- postman-api/files/install_postman.ps1 | 20 ++++++++++++++++++-- postman-api/package/win_install.sls | 24 +++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 index a25cb3a..392fa42 100644 --- a/postman-api/files/install_postman.ps1 +++ b/postman-api/files/install_postman.ps1 @@ -10,14 +10,30 @@ .PARAMETER InstallRoot The system-wide path where the Postman application binaries will be permanently copied (e.g., 'C:\Program Files\Postman'). +.PARAMETER TargetVersion + The specific version string expected for the deployment (e.g., '12.13.4'). .EXAMPLE - .\install_postman.ps1 -InstallRoot "C:\Program Files\Postman" + .\install_postman.ps1 -InstallRoot "C:\Program Files\Postman" ` + -TargetVersion "12.13.4" #> param ( [Parameter(Mandatory = $true)] - [string]$InstallRoot + [string]$InstallRoot, + + [Parameter(Mandatory = $true)] + [string]$TargetVersion ) +# Guard block ensuring version-based script idempotency +$ExePath = Join-Path $InstallRoot 'Postman.exe' +if (Test-Path $ExePath) { + $CurrentVersion = (Get-Item $ExePath).VersionInfo.ProductVersion + if ($CurrentVersion -match $TargetVersion) { + Write-Host "Postman version $CurrentVersion is up to date. Exiting." + exit 0 + } +} + $SetupExe = 'C:\Windows\Temp\PostmanSetup.exe' $StartArgs = @{ ArgumentList = '--silent' diff --git a/postman-api/package/win_install.sls b/postman-api/package/win_install.sls index 9e7f4f9..f51f15e 100644 --- a/postman-api/package/win_install.sls +++ b/postman-api/package/win_install.sls @@ -16,11 +16,33 @@ Download Postman Installer: - skip_verify: true - source: '{{ postman_api.pkg.download_uri }}' {%- endif %} + - unless: | + powershell -ExecutionPolicy Bypass -Command " + $PostmanExePath = '{{ postman_api.config.install_root }}\Postman.exe'; + if (Test-Path $PostmanExePath) { + $FileInfo = Get-Item $PostmanExePath; + $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion; + if ($InstalledProductVersion -match '{{ postman_api.pkg.version }}') { + exit 0 + } + }; exit 1" Execute Postman Installation: cmd.script: - - args: '-InstallRoot "{{ postman_api.config.install_root }}"' + - args: >- + -InstallRoot "{{ postman_api.config.install_root }}" + -TargetVersion "{{ postman_api.pkg.version }}" - require: - file: Download Postman Installer - shell: powershell - source: salt://postman-api/files/install_postman.ps1 + - unless: | + powershell -ExecutionPolicy Bypass -Command " + $PostmanExePath = '{{ postman_api.config.install_root }}\Postman.exe'; + if (Test-Path $PostmanExePath) { + $FileInfo = Get-Item $PostmanExePath; + $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion; + if ($InstalledProductVersion -match '{{ postman_api.pkg.version }}') { + exit 0 + } + }; exit 1" From 952b1b36aa42bf801fa98c4f66ae5dca35006a48 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 14:32:06 -0400 Subject: [PATCH 04/26] Make an overrideable version-parameter available Default values for `version` parameter: * Windows and Linux distros other than EL9: version: 'latest' * RHEL9 and derivative Linux distros: version: '10.24.26' --- postman-api/parameters/defaults.yaml | 1 + postman-api/parameters/os_family/RedHat.yaml.jinja | 5 +++++ postman-api/parameters/os_family/Windows.yaml | 1 + 3 files changed, 7 insertions(+) diff --git a/postman-api/parameters/defaults.yaml b/postman-api/parameters/defaults.yaml index 819b999..5d9f404 100644 --- a/postman-api/parameters/defaults.yaml +++ b/postman-api/parameters/defaults.yaml @@ -18,5 +18,6 @@ values: download_sig: '' download_uri: '' name: 'postman-api' + version: 'latest' service: {} ... diff --git a/postman-api/parameters/os_family/RedHat.yaml.jinja b/postman-api/parameters/os_family/RedHat.yaml.jinja index 04fa54a..46de1e9 100644 --- a/postman-api/parameters/os_family/RedHat.yaml.jinja +++ b/postman-api/parameters/os_family/RedHat.yaml.jinja @@ -12,6 +12,11 @@ values: selinux_fcontext: 'usr_t' ssl_min_version: 'tls1.2' update_mime_database: '/usr/bin/update-desktop-database' + {%- if salt['grains.get']('osmajorrelease') | int == 9 %} + version: '10.24.26' + {%- else %} + version: 'latest' + {%- endif %} whitelist_enabled: true wrapper_bin: '/usr/local/bin/postman' pkg: diff --git a/postman-api/parameters/os_family/Windows.yaml b/postman-api/parameters/os_family/Windows.yaml index 998f9c0..4310382 100644 --- a/postman-api/parameters/os_family/Windows.yaml +++ b/postman-api/parameters/os_family/Windows.yaml @@ -9,5 +9,6 @@ values: download_sig: '' download_uri: 'https://dl.pstmn.io/download/latest/win64' name: 'postman-api' + version: 'latest' service: {} ... From 7d5262acc6a1786e32a90bb89a3730f3c5d4dbce Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 15:12:03 -0400 Subject: [PATCH 05/26] Update to account for non-vendor download URIs --- postman-api/files/install_postman.ps1 | 40 ++++++++++++++---- postman-api/package/win_install.sls | 59 ++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 index 392fa42..841505e 100644 --- a/postman-api/files/install_postman.ps1 +++ b/postman-api/files/install_postman.ps1 @@ -7,16 +7,23 @@ desktop shortcuts, this script orchestrates a monitored extraction, terminates the stuck processes, migrates binaries to a global target root, and purges the temporary system profile staging directories. +.PARAMETER DownloadUri + The fully qualified download URI for the installer package. .PARAMETER InstallRoot The system-wide path where the Postman application binaries will be permanently copied (e.g., 'C:\Program Files\Postman'). .PARAMETER TargetVersion The specific version string expected for the deployment (e.g., '12.13.4'). .EXAMPLE - .\install_postman.ps1 -InstallRoot "C:\Program Files\Postman" ` - -TargetVersion "12.13.4" + .\install_postman.ps1 ` + -DownloadUri "https://dl.pstmn.io/download/latest/win64" ` + -InstallRoot "C:\Program Files\Postman" ` + -TargetVersion "latest" #> param ( + [Parameter(Mandatory = $true)] + [string]$DownloadUri, + [Parameter(Mandatory = $true)] [string]$InstallRoot, @@ -25,11 +32,30 @@ param ( ) # Guard block ensuring version-based script idempotency -$ExePath = Join-Path $InstallRoot 'Postman.exe' -if (Test-Path $ExePath) { - $CurrentVersion = (Get-Item $ExePath).VersionInfo.ProductVersion - if ($CurrentVersion -match $TargetVersion) { - Write-Host "Postman version $CurrentVersion is up to date. Exiting." +$PostmanExePath = Join-Path $InstallRoot 'Postman.exe' +if (Test-Path $PostmanExePath) { + $FileInfo = Get-Item $PostmanExePath + $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion + + $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*' + if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { + $BaseUrl = 'https://dl.pstmn.io/update/status' + $Query = '?currentVersion=12.0.0&platform=win64' + $StatusUrl = $BaseUrl + $Query + $RestArgs = @{ + ErrorAction = 'SilentlyContinue' + Uri = $StatusUrl + } + $UpdateStatus = Invoke-RestMethod @RestArgs + if ($UpdateStatus -and $UpdateStatus.version) { + $TargetVersion = $UpdateStatus.version + } + } + + $IsLatestMatched = $TargetVersion -eq 'latest' + $IsVersionMatch = $InstalledProductVersion -match $TargetVersion + if ($IsLatestMatched -or $IsVersionMatch) { + Write-Host "Postman version $InstalledProductVersion is up to date." exit 0 } } diff --git a/postman-api/package/win_install.sls b/postman-api/package/win_install.sls index f51f15e..7b841a9 100644 --- a/postman-api/package/win_install.sls +++ b/postman-api/package/win_install.sls @@ -18,18 +18,38 @@ Download Postman Installer: {%- endif %} - unless: | powershell -ExecutionPolicy Bypass -Command " - $PostmanExePath = '{{ postman_api.config.install_root }}\Postman.exe'; + $RootPath = '{{ postman_api.config.install_root }}'; + $PostmanExePath = Join-Path $RootPath 'Postman.exe'; if (Test-Path $PostmanExePath) { - $FileInfo = Get-Item $PostmanExePath; - $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion; - if ($InstalledProductVersion -match '{{ postman_api.pkg.version }}') { - exit 0 + $TargetVersion = '{{ postman_api.pkg.version }}'; + $DownloadUri = '{{ postman_api.pkg.download_uri }}'; + $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*'; + if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { + $BaseUrl = 'https://dl.pstmn.io/update/status'; + $Query = '?currentVersion=12.0.0&platform=win64'; + $StatusUrl = $BaseUrl + $Query; + $RestArgs = @{ + ErrorAction = 'SilentlyContinue' + Uri = $StatusUrl + }; + $UpdateStatus = Invoke-RestMethod @RestArgs; + if ($UpdateStatus -and $UpdateStatus.version) { + $TargetVersion = $UpdateStatus.version; + } } + if ($TargetVersion -eq 'latest') { exit 0 } + $FileInfo = Get-Item $PostmanExePath; + $InstalledProductVersion = + $FileInfo.VersionInfo.ProductVersion; + $IsMatch = $InstalledProductVersion -match + $TargetVersion; + if ($IsMatch) { exit 0 } }; exit 1" Execute Postman Installation: cmd.script: - args: >- + -DownloadUri "{{ postman_api.pkg.download_uri }}" -InstallRoot "{{ postman_api.config.install_root }}" -TargetVersion "{{ postman_api.pkg.version }}" - require: @@ -38,11 +58,30 @@ Execute Postman Installation: - source: salt://postman-api/files/install_postman.ps1 - unless: | powershell -ExecutionPolicy Bypass -Command " - $PostmanExePath = '{{ postman_api.config.install_root }}\Postman.exe'; + $RootPath = '{{ postman_api.config.install_root }}'; + $PostmanExePath = Join-Path $RootPath 'Postman.exe'; if (Test-Path $PostmanExePath) { - $FileInfo = Get-Item $PostmanExePath; - $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion; - if ($InstalledProductVersion -match '{{ postman_api.pkg.version }}') { - exit 0 + $TargetVersion = '{{ postman_api.pkg.version }}'; + $DownloadUri = '{{ postman_api.pkg.download_uri }}'; + $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*'; + if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { + $BaseUrl = 'https://dl.pstmn.io/update/status'; + $Query = '?currentVersion=12.0.0&platform=win64'; + $StatusUrl = $BaseUrl + $Query; + $RestArgs = @{ + ErrorAction = 'SilentlyContinue' + Uri = $StatusUrl + }; + $UpdateStatus = Invoke-RestMethod @RestArgs; + if ($UpdateStatus -and $UpdateStatus.version) { + $TargetVersion = $UpdateStatus.version; + } } + if ($TargetVersion -eq 'latest') { exit 0 } + $FileInfo = Get-Item $PostmanExePath; + $InstalledProductVersion = + $FileInfo.VersionInfo.ProductVersion; + $IsMatch = $InstalledProductVersion -match + $TargetVersion; + if ($IsMatch) { exit 0 } }; exit 1" From 1936e4af2d8fbeef4c62b8d213d6671a87d55baa Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 15:53:14 -0400 Subject: [PATCH 06/26] Externalize requisite-script's logic to the install-helper script --- postman-api/files/install_postman.ps1 | 13 +++- postman-api/package/win_install.sls | 86 ++++++++------------------- 2 files changed, 38 insertions(+), 61 deletions(-) diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 index 841505e..4f35db6 100644 --- a/postman-api/files/install_postman.ps1 +++ b/postman-api/files/install_postman.ps1 @@ -14,6 +14,9 @@ permanently copied (e.g., 'C:\Program Files\Postman'). .PARAMETER TargetVersion The specific version string expected for the deployment (e.g., '12.13.4'). +.PARAMETER CheckOnly + A switch flag to return the system validation status to the caller + without invoking downloading or extraction sequences. .EXAMPLE .\install_postman.ps1 ` -DownloadUri "https://dl.pstmn.io/download/latest/win64" ` @@ -28,7 +31,9 @@ param ( [string]$InstallRoot, [Parameter(Mandatory = $true)] - [string]$TargetVersion + [string]$TargetVersion, + + [switch]$CheckOnly ) # Guard block ensuring version-based script idempotency @@ -60,6 +65,12 @@ if (Test-Path $PostmanExePath) { } } +# If execution reaches here, the package is missing or outdated. +if ($CheckOnly) { + Write-Host "Postman requires installation or update." + exit 1 +} + $SetupExe = 'C:\Windows\Temp\PostmanSetup.exe' $StartArgs = @{ ArgumentList = '--silent' diff --git a/postman-api/package/win_install.sls b/postman-api/package/win_install.sls index 7b841a9..431f8ee 100644 --- a/postman-api/package/win_install.sls +++ b/postman-api/package/win_install.sls @@ -9,6 +9,8 @@ Download Postman Installer: file.managed: - makedirs: true - name: 'C:\Windows\Temp\PostmanSetup.exe' + - require: + - file: Stage Installation Script {%- if postman_api.pkg.download_sig %} - source: '{{ postman_api.pkg.download_uri }}' - source_hash: '{{ postman_api.pkg.download_sig }}' @@ -16,72 +18,36 @@ Download Postman Installer: - skip_verify: true - source: '{{ postman_api.pkg.download_uri }}' {%- endif %} - - unless: | - powershell -ExecutionPolicy Bypass -Command " - $RootPath = '{{ postman_api.config.install_root }}'; - $PostmanExePath = Join-Path $RootPath 'Postman.exe'; - if (Test-Path $PostmanExePath) { - $TargetVersion = '{{ postman_api.pkg.version }}'; - $DownloadUri = '{{ postman_api.pkg.download_uri }}'; - $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*'; - if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { - $BaseUrl = 'https://dl.pstmn.io/update/status'; - $Query = '?currentVersion=12.0.0&platform=win64'; - $StatusUrl = $BaseUrl + $Query; - $RestArgs = @{ - ErrorAction = 'SilentlyContinue' - Uri = $StatusUrl - }; - $UpdateStatus = Invoke-RestMethod @RestArgs; - if ($UpdateStatus -and $UpdateStatus.version) { - $TargetVersion = $UpdateStatus.version; - } - } - if ($TargetVersion -eq 'latest') { exit 0 } - $FileInfo = Get-Item $PostmanExePath; - $InstalledProductVersion = - $FileInfo.VersionInfo.ProductVersion; - $IsMatch = $InstalledProductVersion -match - $TargetVersion; - if ($IsMatch) { exit 0 } - }; exit 1" + - unless: >- + powershell -ExecutionPolicy Bypass -File + C:\Windows\Temp\install_postman.ps1 + -CheckOnly + -DownloadUri "{{ postman_api.pkg.download_uri }}" + -InstallRoot "{{ postman_api.config.install_root }}" + -TargetVersion "{{ postman_api.pkg.version }}" Execute Postman Installation: - cmd.script: - - args: >- + cmd.run: + - name: >- + powershell -ExecutionPolicy Bypass -File + C:\Windows\Temp\install_postman.ps1 -DownloadUri "{{ postman_api.pkg.download_uri }}" -InstallRoot "{{ postman_api.config.install_root }}" -TargetVersion "{{ postman_api.pkg.version }}" - require: - file: Download Postman Installer + - file: Stage Installation Script - shell: powershell + - unless: >- + powershell -ExecutionPolicy Bypass -File + C:\Windows\Temp\install_postman.ps1 + -CheckOnly + -DownloadUri "{{ postman_api.pkg.download_uri }}" + -InstallRoot "{{ postman_api.config.install_root }}" + -TargetVersion "{{ postman_api.pkg.version }}" + +Stage Installation Script: + file.managed: + - makedirs: true + - name: 'C:\Windows\Temp\install_postman.ps1' - source: salt://postman-api/files/install_postman.ps1 - - unless: | - powershell -ExecutionPolicy Bypass -Command " - $RootPath = '{{ postman_api.config.install_root }}'; - $PostmanExePath = Join-Path $RootPath 'Postman.exe'; - if (Test-Path $PostmanExePath) { - $TargetVersion = '{{ postman_api.pkg.version }}'; - $DownloadUri = '{{ postman_api.pkg.download_uri }}'; - $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*'; - if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { - $BaseUrl = 'https://dl.pstmn.io/update/status'; - $Query = '?currentVersion=12.0.0&platform=win64'; - $StatusUrl = $BaseUrl + $Query; - $RestArgs = @{ - ErrorAction = 'SilentlyContinue' - Uri = $StatusUrl - }; - $UpdateStatus = Invoke-RestMethod @RestArgs; - if ($UpdateStatus -and $UpdateStatus.version) { - $TargetVersion = $UpdateStatus.version; - } - } - if ($TargetVersion -eq 'latest') { exit 0 } - $FileInfo = Get-Item $PostmanExePath; - $InstalledProductVersion = - $FileInfo.VersionInfo.ProductVersion; - $IsMatch = $InstalledProductVersion -match - $TargetVersion; - if ($IsMatch) { exit 0 } - }; exit 1" From 8d69a596cdd974f8e3dd959acca3c0383116de83 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 16:24:09 -0400 Subject: [PATCH 07/26] Fix copy-paystah error --- tests/pillar/postman-api/main.sls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pillar/postman-api/main.sls b/tests/pillar/postman-api/main.sls index 68e700c..89f83a1 100644 --- a/tests/pillar/postman-api/main.sls +++ b/tests/pillar/postman-api/main.sls @@ -1,4 +1,4 @@ -nosql-booster: +postman-api: lookup: {%- if grains.os_family == "RedHat" %} pkg: From f55de390543bd7c6bb5be3bf0e0c492a52be6b72 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 16:59:28 -0400 Subject: [PATCH 08/26] Ensure no orphans after copy When re-running the formula to install a different version than is already installed, it leaves behind an `{{ install_root }}\app-X.Y.Z directory. Each such directory can be 0.5GiB or more. This update attempts to ensure no such orphans exist after a different version is installed in place of an existing version --- postman-api/files/install_postman.ps1 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 index 4f35db6..9230210 100644 --- a/postman-api/files/install_postman.ps1 +++ b/postman-api/files/install_postman.ps1 @@ -41,7 +41,7 @@ $PostmanExePath = Join-Path $InstallRoot 'Postman.exe' if (Test-Path $PostmanExePath) { $FileInfo = Get-Item $PostmanExePath $InstalledProductVersion = $FileInfo.VersionInfo.ProductVersion - + $IsVendorUrl = $DownloadUri -like '*dl.pstmn.io*' if ($TargetVersion -eq 'latest' -and $IsVendorUrl) { $BaseUrl = 'https://dl.pstmn.io/update/status' @@ -56,7 +56,7 @@ if (Test-Path $PostmanExePath) { $TargetVersion = $UpdateStatus.version } } - + $IsLatestMatched = $TargetVersion -eq 'latest' $IsVersionMatch = $InstalledProductVersion -match $TargetVersion if ($IsLatestMatched -or $IsVersionMatch) { @@ -118,7 +118,16 @@ foreach ($Name in $KillList) { } if (Test-Path $SourceDir) { - if (!(Test-Path $InstallRoot)) { + if (Test-Path $InstallRoot) { + # Purge existing installations completely to prevent directory bloat + $PurgeArgs = @{ + ErrorAction = 'SilentlyContinue' + Force = $true + Path = Join-Path $InstallRoot '*' + Recurse = $true + } + Remove-Item @PurgeArgs + } else { $DirArgs = @{ Force = $true ItemType = 'Directory' @@ -126,6 +135,7 @@ if (Test-Path $SourceDir) { } New-Item @DirArgs } + $CopyArgs = @{ Destination = $InstallRoot Force = $true From 440dc98443de3f940144d4e23dc2650438bdfe3d Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 17:06:49 -0400 Subject: [PATCH 09/26] With real contents, this is no longer needed --- tests/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/.gitkeep diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29..0000000 From 6c740ef0235f7f15e56d11c62f5738f5036c84d9 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Wed, 3 Jun 2026 17:09:29 -0400 Subject: [PATCH 10/26] Add PowerShell-linting to CI tests --- .github/workflows/test.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7c91ec4..2c4c18e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,3 +25,38 @@ jobs: salt-os-version: ${{ matrix.os_version }} salt-state: ${{ matrix.salt_state }} salt-pillar-root: ${{ matrix.salt_pillar_root }} + + lint_powershell: + name: PowerShell Linting + runs-on: windows-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Run PSScriptAnalyzer + shell: pwsh + run: | + $files = Get-ChildItem -Path ./ -Include *.ps1 -Recurse + Write-Host "--- Starting PowerShell Static Analysis ---" + + $anyErrors = $false + + foreach ($file in $files) { + $relativePath = $file.FullName.Replace($PWD.ProviderPath, ".") + $results = Invoke-ScriptAnalyzer -Path $file.FullName -Severity Warning + + if ($results) { + Write-Host "FAIL: $relativePath" -ForegroundColor Red + $results | Format-Table -AutoSize + $anyErrors = $true + } else { + Write-Host "PASS: $relativePath" -ForegroundColor Green + } + } + + if ($anyErrors) { + Write-Error "Static analysis failed. Please fix the errors above." + exit 1 + } else { + Write-Host "--- All files passed analysis! ---" + } From 0559cc59f205ae5be9d1d4dfe4790fab5d11013e Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 06:54:25 -0400 Subject: [PATCH 11/26] Make ready to run on STIGed hosts * Ensure proper security-setting on `install_root` * Suppress attempts at auto-updating (users can't do it, any way, given the installation-location and associated security-settings) * Add app-specific exclusion to Process Mitigation security controls --- postman-api/config/win_file.sls | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index e69de29..0582572 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} + +Configure Process Mitigation Exclusions: + cmd.run: + - name: >- + Set-ProcessMitigation + -Name Postman.exe + -Disable ChildProcess + - shell: powershell + - unless: >- + if ((Get-ProcessMitigation -Name Postman.exe).ChildProcess.Type + -eq 'None') { exit 0 } else { exit 1 } + +Harden Postman Directory Permissions: + file.directory: + - name: '{{ postman_api.config.install_root }}' + - win_inheritance: true + - win_owner: 'BUILTIN\Administrators' + - win_perms: + BUILTIN\Administrators: + perms: full_control + BUILTIN\Users: + perms: read_execute + +Suppress Automatic Updates Globally: + host.present: + - ip: '127.0.0.1' + - name: 'dl.pstmn.io' From d9ed89737205c8b872a1695e819360e9c86c6ecc Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 07:46:19 -0400 Subject: [PATCH 12/26] Tune process-mitigation exclusions --- postman-api/config/win_file.sls | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index 0582572..ccab5c1 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -10,11 +10,13 @@ Configure Process Mitigation Exclusions: - name: >- Set-ProcessMitigation -Name Postman.exe - -Disable ChildProcess + -Disable DisallowChildProcessCreation - shell: powershell - unless: >- - if ((Get-ProcessMitigation -Name Postman.exe).ChildProcess.Type - -eq 'None') { exit 0 } else { exit 1 } + $m = Get-ProcessMitigation -Name Postman.exe + -ErrorAction SilentlyContinue; + if ($m.ChildProcess.DisallowChildProcessCreation + -eq 'OFF') { exit 0 } else { exit 1 } Harden Postman Directory Permissions: file.directory: From a3ff047b31727f582b46b89042dba86ec140aff4 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 08:26:15 -0400 Subject: [PATCH 13/26] Moar enterprise-user 'readiness' tasks * Ensure all users have a "Postman" launcher-icon on their desktops * Ensure all users have a "Postman" launcher-icon in their start menues * Set up system-registry to ensure protocol deep-linking --- postman-api/config/win_file.sls | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index ccab5c1..a1d178f 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -5,6 +5,13 @@ {%- set tplroot = tpldir.split('/')[0] %} {%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} +Configure Postman Desktop Shortcut: + win_shortcut.present: + - force: true + - name: 'C:\Users\Public\Desktop\Postman.lnk' + - target: '{{ postman_api.config.install_root }}\Postman.exe' + - working_dir: '{{ postman_api.config.install_root }}' + Configure Process Mitigation Exclusions: cmd.run: - name: >- @@ -18,6 +25,34 @@ Configure Process Mitigation Exclusions: if ($m.ChildProcess.DisallowChildProcessCreation -eq 'OFF') { exit 0 } else { exit 1 } +Configure Protocol Deep Linking Base: + reg.present: + - name: 'HKLM\SOFTWARE\Classes\postman' + - vdata: 'URL:postman Protocol' + - vname: '(Default)' + - vtype: REG_SZ + +Configure Protocol Deep Linking Command: + reg.present: + - name: 'HKLM\SOFTWARE\Classes\postman\shell\open\command' + - vdata: '"{{ postman_api.config.install_root }}\Postman.exe" "%1"' + - vname: '(Default)' + - vtype: REG_SZ + +Configure Protocol Deep Linking Protocol Value: + reg.present: + - name: 'HKLM\SOFTWARE\Classes\postman' + - vdata: '' + - vname: 'URL Protocol' + - vtype: REG_SZ + +Configure Start Menu Shortcut: + win_shortcut.present: + - force: true + - name: 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Postman.lnk' + - target: '{{ postman_api.config.install_root }}\Postman.exe' + - working_dir: '{{ postman_api.config.install_root }}' + Harden Postman Directory Permissions: file.directory: - name: '{{ postman_api.config.install_root }}' From 397da900d0cb3490ec901cf109a89bb5c450aa69 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 09:20:18 -0400 Subject: [PATCH 14/26] fix resource-type delcaration --- postman-api/config/win_file.sls | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index a1d178f..e958e87 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -6,8 +6,7 @@ {%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} Configure Postman Desktop Shortcut: - win_shortcut.present: - - force: true + shortcut.present: - name: 'C:\Users\Public\Desktop\Postman.lnk' - target: '{{ postman_api.config.install_root }}\Postman.exe' - working_dir: '{{ postman_api.config.install_root }}' @@ -47,8 +46,7 @@ Configure Protocol Deep Linking Protocol Value: - vtype: REG_SZ Configure Start Menu Shortcut: - win_shortcut.present: - - force: true + shortcut.present: - name: 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Postman.lnk' - target: '{{ postman_api.config.install_root }}\Postman.exe' - working_dir: '{{ postman_api.config.install_root }}' From 9c8f4c970c5d03edf0ff5699a45dabf03e13eb7e Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 10:17:08 -0400 Subject: [PATCH 15/26] Gotta be more pedantic Fixes state verification failures for Windows shortcuts. explicitly declares 'icon_location' and 'icon_index' parameters within the native 'shortcut.present' resource definitions. This supplies the validation-query with explicit metadata to match against Windows COM API inspection returns, preventing false-positive state failures under Session 0 headless contexts (avoiding the need to resort to cmd.run kludgery) --- postman-api/config/win_file.sls | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index e958e87..386e3ee 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -7,6 +7,8 @@ Configure Postman Desktop Shortcut: shortcut.present: + - icon_index: 0 + - icon_location: '{{ postman_api.config.install_root }}\Postman.exe' - name: 'C:\Users\Public\Desktop\Postman.lnk' - target: '{{ postman_api.config.install_root }}\Postman.exe' - working_dir: '{{ postman_api.config.install_root }}' @@ -19,10 +21,12 @@ Configure Process Mitigation Exclusions: -Disable DisallowChildProcessCreation - shell: powershell - unless: >- - $m = Get-ProcessMitigation -Name Postman.exe - -ErrorAction SilentlyContinue; - if ($m.ChildProcess.DisallowChildProcessCreation - -eq 'OFF') { exit 0 } else { exit 1 } + $postmanProcessMitigation = Get-ProcessMitigation + -Name Postman.exe -ErrorAction SilentlyContinue; + $childProcessStatus = $postmanProcessMitigation. + ChildProcess.DisallowChildProcessCreation; + if ($childProcessStatus -eq 'OFF') { exit 0 } + else { exit 1 } Configure Protocol Deep Linking Base: reg.present: @@ -47,6 +51,8 @@ Configure Protocol Deep Linking Protocol Value: Configure Start Menu Shortcut: shortcut.present: + - icon_index: 0 + - icon_location: '{{ postman_api.config.install_root }}\Postman.exe' - name: 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Postman.lnk' - target: '{{ postman_api.config.install_root }}\Postman.exe' - working_dir: '{{ postman_api.config.install_root }}' From 572ed622b91092539acd9bcd9794f94b4631f00d Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 10:56:28 -0400 Subject: [PATCH 16/26] Ensure system PATH-env includes Postman --- postman-api/config/file.sls | 1 + postman-api/config/win_readiness.sls | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 postman-api/config/win_readiness.sls diff --git a/postman-api/config/file.sls b/postman-api/config/file.sls index 151a76f..b59a003 100644 --- a/postman-api/config/file.sls +++ b/postman-api/config/file.sls @@ -13,6 +13,7 @@ include: - postman-api.config.lin_file {%- elif grains.kernel == "Windows" %} - postman-api.config.win_file + - postman-api.config.win_readiness {%- endif %} Avoid being a null-router (config/file) - Postman API: diff --git a/postman-api/config/win_readiness.sls b/postman-api/config/win_readiness.sls new file mode 100644 index 0000000..5826533 --- /dev/null +++ b/postman-api/config/win_readiness.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} + +postman_api_environment_path: + environ.setenv: + - name: PATH + - update_with: path + - value: '{{ postman_api.config.install_root }}' + +postman_api_telemetry_opt_out: + environ.setenv: + - name: POSTMAN_DISABLE_TELEMETRY + - update_with: xappend + - value: '1' From 71fa8a11d5b5c27b615104f9b470437fb72ffd28 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 11:06:11 -0400 Subject: [PATCH 17/26] Remove unused directory-components The `service` and `subcomponent` directories are derived from execution of the https://github.com/saltstack-formulas/template-formula project's bin/convert-formula.sh script but aren't necessary for this formula --- postman-api/service/clean.sls | 11 -------- postman-api/service/init.sls | 5 ---- postman-api/service/running.sls | 17 ------------ postman-api/subcomponent/clean.sls | 5 ---- postman-api/subcomponent/config/clean.sls | 16 ----------- postman-api/subcomponent/config/file.sls | 27 ------------------- .../files/default/subcomponent-example.tmpl | 6 ----- .../default/subcomponent-example.tmpl.jinja | 6 ----- postman-api/subcomponent/config/init.sls | 5 ---- postman-api/subcomponent/init.sls | 5 ---- 10 files changed, 103 deletions(-) delete mode 100644 postman-api/service/clean.sls delete mode 100644 postman-api/service/init.sls delete mode 100644 postman-api/service/running.sls delete mode 100644 postman-api/subcomponent/clean.sls delete mode 100644 postman-api/subcomponent/config/clean.sls delete mode 100644 postman-api/subcomponent/config/file.sls delete mode 100644 postman-api/subcomponent/config/files/default/subcomponent-example.tmpl delete mode 100644 postman-api/subcomponent/config/files/default/subcomponent-example.tmpl.jinja delete mode 100644 postman-api/subcomponent/config/init.sls delete mode 100644 postman-api/subcomponent/init.sls diff --git a/postman-api/service/clean.sls b/postman-api/service/clean.sls deleted file mode 100644 index 02bed28..0000000 --- a/postman-api/service/clean.sls +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} - -postman-api-service-clean-service-dead: - service.dead: - - name: {{ postman_api.service.name }} - - enable: False diff --git a/postman-api/service/init.sls b/postman-api/service/init.sls deleted file mode 100644 index 6fe4d1a..0000000 --- a/postman-api/service/init.sls +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -include: - - .running diff --git a/postman-api/service/running.sls b/postman-api/service/running.sls deleted file mode 100644 index a631f61..0000000 --- a/postman-api/service/running.sls +++ /dev/null @@ -1,17 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- set sls_config_file = tplroot ~ '.config.file' %} -{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} - -include: - - {{ sls_config_file }} - -postman-api-service-running-service-running: - service.running: - - name: {{ postman_api.service.name }} - - enable: True - - watch: - - sls: {{ sls_config_file }} diff --git a/postman-api/subcomponent/clean.sls b/postman-api/subcomponent/clean.sls deleted file mode 100644 index 564769d..0000000 --- a/postman-api/subcomponent/clean.sls +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -include: - - .config.clean diff --git a/postman-api/subcomponent/config/clean.sls b/postman-api/subcomponent/config/clean.sls deleted file mode 100644 index cbda35b..0000000 --- a/postman-api/subcomponent/config/clean.sls +++ /dev/null @@ -1,16 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- set sls_service_clean = tplroot ~ '.service.clean' %} -{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} - -include: - - {{ sls_service_clean }} - -postman-api-subcomponent-config-clean-file-absent: - file.absent: - - name: {{ postman_api.subcomponent.config }} - - watch_in: - - sls: {{ sls_service_clean }} diff --git a/postman-api/subcomponent/config/file.sls b/postman-api/subcomponent/config/file.sls deleted file mode 100644 index 86be126..0000000 --- a/postman-api/subcomponent/config/file.sls +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -{#- Get the `tplroot` from `tpldir` #} -{%- set tplroot = tpldir.split('/')[0] %} -{%- set sls_config_file = tplroot ~ '.config.file' %} -{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} -{%- from tplroot ~ "/libtofs.jinja" import files_switch with context %} - -include: - - {{ sls_config_file }} - -postman-api-subcomponent-config-file-file-managed: - file.managed: - - name: {{ postman_api.subcomponent.config }} - - source: {{ files_switch(['subcomponent-example.tmpl'], - lookup='postman-api-subcomponent-config-file-file-managed', - use_subpath=True - ) - }} - - mode: 644 - - user: root - - group: {{ postman_api.rootgroup }} - - makedirs: True - - template: jinja - - require_in: - - sls: {{ sls_config_file }} diff --git a/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl b/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl deleted file mode 100644 index 522de00..0000000 --- a/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl +++ /dev/null @@ -1,6 +0,0 @@ -######################################################################## -# File managed by Salt at <{{ source }}>. -# Your changes will be overwritten. -######################################################################## - -This is a subcomponent example file from SaltStack template-formula. diff --git a/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl.jinja b/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl.jinja deleted file mode 100644 index cbfd51d..0000000 --- a/postman-api/subcomponent/config/files/default/subcomponent-example.tmpl.jinja +++ /dev/null @@ -1,6 +0,0 @@ -######################################################################## -# File managed by Salt at <{{ source }}>. -# Your changes will be overwritten. -######################################################################## - -This is another subcomponent example file from SaltStack template-formula. diff --git a/postman-api/subcomponent/config/init.sls b/postman-api/subcomponent/config/init.sls deleted file mode 100644 index 465ddfe..0000000 --- a/postman-api/subcomponent/config/init.sls +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -include: - - .file diff --git a/postman-api/subcomponent/init.sls b/postman-api/subcomponent/init.sls deleted file mode 100644 index 6003be1..0000000 --- a/postman-api/subcomponent/init.sls +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: ft=sls - -include: - - .config From 0ba0dccdc86d5689e1eeae53774d14bfbfd18407 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 11:08:29 -0400 Subject: [PATCH 18/26] Reverse win_install tasks While we're here, change state-IDs to use "capital-case" --- postman-api/config/win_clean.sls | 32 ++++++++++++++++++++++++++++ postman-api/config/win_readiness.sls | 12 +++++------ postman-api/package/win_clean.sls | 18 ++++++++++++++++ 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/postman-api/config/win_clean.sls b/postman-api/config/win_clean.sls index e69de29..2c12bd3 100644 --- a/postman-api/config/win_clean.sls +++ b/postman-api/config/win_clean.sls @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} +{%- set image_execution_options_reg = + 'HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\' + ~ 'Image File Execution Options\\Postman.exe' %} +{%- set start_menu_shortcut_path = + 'C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Postman.lnk' %} + +Remove Postman Desktop Shortcut: + file.absent: + - name: 'C:\Users\Public\Desktop\Postman.lnk' + +Remove Process Mitigation Exclusions: + reg.absent: + - name: '{{ image_execution_options_reg }}' + +Remove Protocol Deep Linking Registration: + reg.absent: + - name: 'HKLM\SOFTWARE\Classes\postman' + +Remove Start Menu Shortcut: + file.absent: + - name: '{{ start_menu_shortcut_path }}' + +Reverse Global Suppression of Automatic Updates: + host.absent: + - ip: '127.0.0.1' + - name: 'dl.pstmn.io' diff --git a/postman-api/config/win_readiness.sls b/postman-api/config/win_readiness.sls index 5826533..284dfcd 100644 --- a/postman-api/config/win_readiness.sls +++ b/postman-api/config/win_readiness.sls @@ -5,14 +5,12 @@ {%- set tplroot = tpldir.split('/')[0] %} {%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} -postman_api_environment_path: - environ.setenv: - - name: PATH - - update_with: path - - value: '{{ postman_api.config.install_root }}' +Configure Postman API into System PATH Entry: + win_path.exists: + - name: '{{ postman_api.config.install_root }}' -postman_api_telemetry_opt_out: +Opt Out of Postman API Telemetry: environ.setenv: - name: POSTMAN_DISABLE_TELEMETRY - - update_with: xappend + - permanent: HKLM - value: '1' diff --git a/postman-api/package/win_clean.sls b/postman-api/package/win_clean.sls index e69de29..c0c0e88 100644 --- a/postman-api/package/win_clean.sls +++ b/postman-api/package/win_clean.sls @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=sls + +{#- Get the `tplroot` from `tpldir` #} +{%- set tplroot = tpldir.split('/')[0] %} +{%- from tplroot ~ "/map.jinja" import mapdata as postman_api with context %} + +Remove Postman Installation Directory: + file.absent: + - name: '{{ postman_api.config.install_root }}' + +Remove Postman Staged Installer: + file.absent: + - name: 'C:\Windows\Temp\PostmanSetup.exe' + +Remove Postman Staged Script: + file.absent: + - name: 'C:\Windows\Temp\install_postman.ps1' From ec941cf2f6879cb7995a7706ff7ba8f7610a3d40 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 13:54:23 -0400 Subject: [PATCH 19/26] Ensure that GUI doesn't eat entire screen --- postman-api/config/win_file.sls | 2 ++ 1 file changed, 2 insertions(+) diff --git a/postman-api/config/win_file.sls b/postman-api/config/win_file.sls index 386e3ee..ff828d0 100644 --- a/postman-api/config/win_file.sls +++ b/postman-api/config/win_file.sls @@ -7,6 +7,7 @@ Configure Postman Desktop Shortcut: shortcut.present: + - arguments: '--window-size=1024,768 --force-device-scale-factor=0.85' - icon_index: 0 - icon_location: '{{ postman_api.config.install_root }}\Postman.exe' - name: 'C:\Users\Public\Desktop\Postman.lnk' @@ -51,6 +52,7 @@ Configure Protocol Deep Linking Protocol Value: Configure Start Menu Shortcut: shortcut.present: + - arguments: '--window-size=1024,768 --force-device-scale-factor=0.85' - icon_index: 0 - icon_location: '{{ postman_api.config.install_root }}\Postman.exe' - name: 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Postman.lnk' From a0376ff050c641af1dd07cd52fb5e3a35635526e Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 13:59:21 -0400 Subject: [PATCH 20/26] Add P3 standard CI tests for Windows targets --- .github/workflows/test.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2c4c18e..964cf48 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,6 +26,24 @@ jobs: salt-state: ${{ matrix.salt_state }} salt-pillar-root: ${{ matrix.salt_pillar_root }} + windows: + uses: plus3it/actions-workflows/.github/workflows/test-salt-windows.yml@ddd67e99878a285f728de398c1116151c2d7791a + strategy: + matrix: + os_version: + - windows-2019 + - windows-2022 + - windows-2025 + salt_state: + - postman-api + salt_pillar_root: + - ./tests/pillar/test-postman-api + with: + salt-os-version: ${{ matrix.os_version }} + salt-state: ${{ matrix.salt_state }} + salt-pillar-root: ${{ matrix.salt_pillar_root }} + + lint_powershell: name: PowerShell Linting runs-on: windows-latest From 712c05a8abe12ffc0dcb1b8919ae575de12e6c05 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:02:56 -0400 Subject: [PATCH 21/26] Address PSSScriptAnalyzer lints --- postman-api/files/install_postman.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postman-api/files/install_postman.ps1 b/postman-api/files/install_postman.ps1 index 9230210..832a356 100644 --- a/postman-api/files/install_postman.ps1 +++ b/postman-api/files/install_postman.ps1 @@ -60,14 +60,14 @@ if (Test-Path $PostmanExePath) { $IsLatestMatched = $TargetVersion -eq 'latest' $IsVersionMatch = $InstalledProductVersion -match $TargetVersion if ($IsLatestMatched -or $IsVersionMatch) { - Write-Host "Postman version $InstalledProductVersion is up to date." + Write-Output "Postman version $InstalledProductVersion is up to date." exit 0 } } # If execution reaches here, the package is missing or outdated. if ($CheckOnly) { - Write-Host "Postman requires installation or update." + Write-Output "Postman requires installation or update." exit 1 } From fa91cb7779033d2519c32b43d3c3cf183770790a Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:11:09 -0400 Subject: [PATCH 22/26] Updates changelog to describe updates included by PR --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2b139a..b0a9737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +### 0.1.1 + +**Released**: 2026.06.04 + +**Summary**: + +* Added Windows functionality + * Installs the Postman API binary (as downloaded from [vendor site](https://www.postman.com/downloads/)) + * Install-location defaults to `C:\Program Files\Postman` + * Install-location overrideable via Pillar's `install_root` parameter + * Installs latest installable version — v12.13.5 as of this document's writing (override via Pillar's `download_uri` parameter) + * Sets appropriate ownerships, permissions, etc. on content loaded into `install_root` + * Creates a desktop-launcher icon for all users + * Creates a launcher icon in the `Start` menus for all users + * Configures the launchers to constrain the initial-startup window to 85% of the display size +* Adds CI tests for Windows platforms (currently Windows Server 2019, 2022 and 2025) +* Updates pillar.example to explain Windows-specific parameters/inputs that may be specified via Pillar +* Update README with platform-notes + ### 0.1.0 **Released**: 2026.06.02 From 051a23f33ca71bfb376cbbeb7d275912d08c518a Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:22:04 -0400 Subject: [PATCH 23/26] Eliminate obsoleted parameters --- postman-api/parameters/os_family/RedHat.yaml.jinja | 5 ----- 1 file changed, 5 deletions(-) diff --git a/postman-api/parameters/os_family/RedHat.yaml.jinja b/postman-api/parameters/os_family/RedHat.yaml.jinja index 46de1e9..04fa54a 100644 --- a/postman-api/parameters/os_family/RedHat.yaml.jinja +++ b/postman-api/parameters/os_family/RedHat.yaml.jinja @@ -12,11 +12,6 @@ values: selinux_fcontext: 'usr_t' ssl_min_version: 'tls1.2' update_mime_database: '/usr/bin/update-desktop-database' - {%- if salt['grains.get']('osmajorrelease') | int == 9 %} - version: '10.24.26' - {%- else %} - version: 'latest' - {%- endif %} whitelist_enabled: true wrapper_bin: '/usr/local/bin/postman' pkg: From 4f33ce7bb27d2ae8be995218d9210e206e56c33b Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:25:59 -0400 Subject: [PATCH 24/26] Re-align pillar.examples to current parms' usage --- pillar.example | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pillar.example b/pillar.example index 0e1b85f..2be9d18 100644 --- a/pillar.example +++ b/pillar.example @@ -3,14 +3,15 @@ --- postman-api: config: - # Path where the system desktop entry file will be generated. + # Path where the system desktop entry file will be generated (Linux only). desktop_entry: '/usr/share/applications/postman.desktop' # Relative path to the application icon inside the installation directory. icon_source: '/app/resources/app/assets/icon.png' # The root directory tree where the application archive is extracted. - # Natively supports paths containing spaces (e.g., '/opt/Desktop Apps/Postman'). + # Natively supports Linux paths and Windows filesystem paths + # (e.g., 'C:\Program Files\Postman'). install_root: '/opt/Postman' # Controls Chromium's internal application isolation sandbox layer. @@ -35,6 +36,8 @@ postman-api: whitelist_enabled: true # The system path for the generated wrapper execution bash script. + # Supports Linux paths and Windows execution script pathways + # (e.g., 'C:\Program Files\Postman\postman.cmd'). wrapper_bin: '/usr/local/bin/postman' pkg: @@ -48,4 +51,8 @@ postman-api: # The internal name designation used for formula mapping identification. name: 'postman-api' + + # The target application version string expected for the deployment + # (e.g., '12.13.5' or 'latest'). Used primarily by Windows targets. + version: 'latest' ... From aeba16bd0080f7948bad63ba500066b1bd3d4d62 Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:30:27 -0400 Subject: [PATCH 25/26] Add Windows deployment-details to the "Notes" section --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 477a56a..6ce2881 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,10 @@ Executes _just_ the `config` state to uninstall the Postman API client-configura 1. Due to library compatibilities, the installable version of Postman on RHEL 9 (and derivatives) is constrained to < `11.x`. This formula defaults the RHEL 9 (and derivatives) installation to Postman version `10.24.26` 1. To support hardened enterprise baselines (such as the DISA STIG or CIS profiles), this formula defaults to disabling the Chromium application sandbox (`sandbox_enabled: false`) on Red Hat family distributions. These security profiles typically disable unprivileged user namespaces (`user.max_user_namespaces = 0`), which causes Electron-based applications to crash instantly on startup. For less restrictive environments where user namespaces are permitted, the sandbox can be safely re-enabled by setting `sandbox_enabled: true` via Pillar data. +### Windows + +1. **Headless Session 0 Execution:** The native Squirrel-based Postman installer package will deadlock or hang indefinitely when executed inside a headless `SYSTEM` context (Session 0) because it attempts to synchronously generate user-centric desktop interactive pathways. This formula handles this limitation by staging a purpose-built PowerShell management wrapper (`install_postman.ps1`) that orchestrates a monitored extraction, forces termination of the blocked installation threads, migrates application files to the designated global `install_root`, and purges staging profiles. +2. **Virtual Framebuffer Scaling Overrides:** To prevent the hardcoded Electron canvas landing layout from overflowing low-resolution framebuffers typical of remote automated pipelines or thin management consoles, system shortcuts are automatically configured with Chromium layout engine switches (`--window-size=1024,768` and `--force-device-scale-factor=0.85`) to guarantee complete interface visibility. [^1]: As of this README's writing, only Enterprise Linux and related distros (Red Hat and Oracle Enterprise, CentOS Stream, Rocky and Alma Linux). It has only been specifically tested with EL **_9_** variants. [^2]: As of this README's writing, this functionality has only been tested on Windows Server 2022 From 6a33a73dcc2b0481585817e654d231b9c932762f Mon Sep 17 00:00:00 2001 From: Thomas H Jones II Date: Thu, 4 Jun 2026 14:33:49 -0400 Subject: [PATCH 26/26] Match version to CHANGELOG's --- .bumpversion.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 871c1b1..9452bf3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.1.0 +current_version = 0.1.1 commit = True message = Bumps version to {new_version} tag = False