Repository: rgl/packer-provisioner-windows-update Branch: master Commit: 632974b08f3c Files: 27 Total size: 108.9 KB Directory structure: gitextract_5np1h6zz/ ├── .devcontainer/ │ ├── Dockerfile │ ├── devcontainer.json │ ├── inputrc │ ├── login.sh │ └── setup.sh ├── .gitattributes ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .goreleaser.yml ├── .vscode/ │ └── settings.json ├── LICENSE.txt ├── Makefile ├── README.md ├── ci-release.sh ├── go.mod ├── go.sum ├── main.go ├── renovate.json5 ├── renovate.sh ├── test.pkr.hcl ├── test.sh └── update/ ├── elevated-template.ps1 ├── elevated.go ├── provisioner.go ├── provisioner.hcl2spec.go ├── update_ui.go └── windows-update.ps1 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .devcontainer/Dockerfile ================================================ # syntax=docker.io/docker/dockerfile:1.23 # see https://github.com/devcontainers/images/blob/main/src/base-debian/manifest.json FROM mcr.microsoft.com/devcontainers/base:2.1.7-trixie RUN <<'EOF' #!/usr/bin/bash set -euxo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update apt-get -y install --no-install-recommends \ bash-completion \ curl \ git \ openssh-client \ pylint \ python3-argcomplete \ python3-openssl \ python3-pip \ python3-venv \ python3-yaml \ qemu-system-x86 \ qemu-utils \ sudo \ unzip \ wget apt-get clean rm -rf /var/lib/apt/lists/* activate-global-python-argcomplete python3 -m venv --system-site-packages /opt/venv EOF ENV PATH="/opt/venv/bin:$PATH" # disable the packer telemetry. ENV CHECKPOINT_DISABLE=1 RUN <<'EOF' #!/usr/bin/bash set -euxo pipefail # ensure /etc/profile is called at the top of the file, when running in a # login shell. sed -i '0,/esac/s/esac/&\n\nsource \/etc\/profile/' /home/vscode/.bashrc EOF COPY .devcontainer/inputrc /etc/inputrc COPY .devcontainer/login.sh /etc/profile.d/login.sh ================================================ FILE: .devcontainer/devcontainer.json ================================================ { "name": "Packer", "dockerFile": "Dockerfile", "context": "..", "runArgs": [ "--group-add=108", // 108 is the id of the kvm group. "-v=${localEnv:HOME}/.ssh/id_rsa:/home/vscode/.ssh/id_rsa:ro", "-v=${localEnv:HOME}/.ssh/id_rsa.pub:/home/vscode/.ssh/id_rsa.pub:ro", "-v=${localEnv:HOME}/.vagrant.d:/home/vscode/.vagrant.d:ro", "-v=/usr/share/ovmf:/usr/share/ovmf:ro", "--device=/dev/kvm" ], "postCreateCommand": "bash .devcontainer/setup.sh", "features": { "ghcr.io/devcontainers/features/go:1": { "version": "1.26.1" }, "ghcr.io/devcontainers-extra/features/packer-asdf:2": { "version": "1.15.1" } }, "customizations": { "vscode": { "extensions": [ "hashicorp.hcl", "streetsidesoftware.code-spell-checker" ] } } } ================================================ FILE: .devcontainer/inputrc ================================================ set input-meta on set output-meta on set show-all-if-ambiguous on set completion-ignore-case on "\e[A": history-search-backward "\e[B": history-search-forward "\eOD": backward-word "\eOC": forward-word ================================================ FILE: .devcontainer/login.sh ================================================ export EDITOR=code export PAGER=less alias l='ls -lF --color' alias ll='l -a' alias h='history 25' alias j='jobs -l' ================================================ FILE: .devcontainer/setup.sh ================================================ #!/bin/bash set -euxo pipefail pushd /home/vscode sudo chown vscode:vscode .ssh && sudo chmod 700 .ssh popd ================================================ FILE: .gitattributes ================================================ /update/*.ps1 -text ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: [push, pull_request] jobs: build: name: Build runs-on: windows-2022 steps: - name: Configure git run: git config --global core.autocrlf false - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: actions/setup-go@v6 with: go-version: '1.26.1' - name: Set up msys2 uses: msys2/setup-msys2@v2 with: install: make tar zip unzip path-type: inherit - name: Import GPG key id: import_gpg uses: crazy-max/ghaction-import-gpg@v7 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PASSPHRASE }} - name: Build env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} run: msys2 ./ci-release.sh - name: Archive uses: actions/upload-artifact@v7 with: name: artifacts path: | dist/ !dist/*/* ================================================ FILE: .gitignore ================================================ dist/ packer-plugin-windows-update packer-plugin-windows-update.exe tmp* .idea/ output-*/ *.log ================================================ FILE: .goreleaser.yml ================================================ version: 2 builds: - env: - CGO_ENABLED=0 goos: - linux - darwin - windows goarch: - amd64 - arm64 flags: - -v - -trimpath ldflags: - -s - -w - -X main.version={{ .Version }} - -X main.commit={{ .Commit }} - -X main.date={{ .CommitDate }} mod_timestamp: '{{ .CommitTimestamp }}' binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' changelog: sort: asc filters: exclude: - '^docs:' - '^test:' snapshot: version_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}' release: draft: true prerelease: auto archives: - formats: - zip name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' checksum: name_template: '{{ .ProjectName }}_v{{ .Version }}_SHA256SUMS' algorithm: sha256 signs: - artifacts: checksum args: - --batch - --local-user - "{{ .Env.GPG_FINGERPRINT }}" - --output - ${signature} - --detach-sign - ${artifact} ================================================ FILE: .vscode/settings.json ================================================ { "cSpell.words": [ "devcontainers" ] } ================================================ FILE: LICENSE.txt ================================================ Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: Makefile ================================================ GOPATH := $(shell go env GOPATH | tr '\\' '/') GOEXE := $(shell go env GOEXE) GOHOSTOS := $(shell go env GOHOSTOS) GOHOSTARCH := $(shell go env GOHOSTARCH) GOHOSTARCHVERSION := $(shell go env "GO$(shell go env GOHOSTARCH | tr '[:lower:]' '[:upper:]')") GORELEASER := $(GOPATH)/bin/goreleaser SOURCE_FILES := *.go update/* update/provisioner.hcl2spec.go PLUGIN_PATH := dist/packer-plugin-windows-update_$(GOHOSTOS)_$(GOHOSTARCH)_$(GOHOSTARCHVERSION)/packer-plugin-windows-update_*_$(GOHOSTOS)_$(GOHOSTARCH)$(GOEXE) # see https://github.com/goreleaser/goreleaser # renovate: datasource=github-releases depName=goreleaser/goreleaser extractVersion=^v?(?2\..+) GORELEASER_VERSION := 2.15.2 all: clean build init: go mod download $(GORELEASER): go install github.com/goreleaser/goreleaser/v2@v$(GORELEASER_VERSION) build: init $(GORELEASER) $(SOURCE_FILES) API_VERSION="$(shell go run . describe 2>/dev/null | jq -r .api_version)" \ $(GORELEASER) build --skip=validate --clean --single-target release-snapshot: init $(GORELEASER) $(SOURCE_FILES) API_VERSION="$(shell go run . describe 2>/dev/null | jq -r .api_version)" \ $(GORELEASER) release --snapshot --skip=publish --clean release: init $(GORELEASER) $(SOURCE_FILES) API_VERSION="$(shell go run . describe 2>/dev/null | jq -r .api_version)" \ $(GORELEASER) release --clean # see https://www.packer.io/guides/hcl/component-object-spec/ update/provisioner.hcl2spec.go: update/provisioner.go go install github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc@$(shell go list -m -f '{{.Version}}' github.com/hashicorp/packer-plugin-sdk) go generate ./... clean: rm -rf update/provisioner.hcl2spec.go dist tmp* output-test *.log test: build ./test.sh .PHONY: all init build release release-snapshot install uninstall clean test ================================================ FILE: README.md ================================================ # Packer Windows Update Provisioner [![Build status](https://github.com/rgl/packer-plugin-windows-update/workflows/Build/badge.svg)](https://github.com/rgl/packer-plugin-windows-update/actions?query=workflow%3ABuild) This is a Packer plugin for installing Windows updates (akin to [rgl/vagrant-windows-update](https://github.com/rgl/vagrant-windows-update)). **NB** This was only tested with Packer 1.15.1 and the images at [rgl/windows-vagrant](https://github.com/rgl/windows-vagrant), so YMMV. # Usage Configure your packer template to require a [release version of the plugin](https://github.com/rgl/packer-plugin-windows-update/releases), e.g.: ```hcl packer { required_plugins { windows-update = { version = "0.18.1" source = "github.com/rgl/windows-update" } } } ``` Initialize your packer template (it will install the plugin): ```bash packer init your-template.pkr.hcl ``` Use this provisioner plugin from your packer template file, e.g. like in [rgl/windows-vagrant](https://github.com/rgl/windows-vagrant): ```hcl build { provisioner "windows-update" { filters = [ # exclude KB5007651: # Update for Windows Security platform - KB5007651 (Version 10.0.29510.1001) # NB it can only be applied while the user is logged in. "exclude:$_.Title -like '*KB5007651*'", "include:$true", ] } } ``` Note, the plugin automatically restarts the machine after Windows Updates are applied and repeats until all updates are installed. The reboots occur similar to the windows-restart provisioner built into packer where packer is aware that a shutdown is in progress. ## Search Criteria, Filters and Update Limit You can select which Windows Updates are installed by defining the search criteria, a set of filters, and how many updates are installed at a time. Normally you would use one of the following settings: | Name | `search_criteria` | `filters` | |---------------|---------------------------------------------|-----------------| | Important | `AutoSelectOnWebSites=1 and IsInstalled=0` | `$true` | | Recommended | `BrowseOnly=0 and IsInstalled=0` | `$true` | | All | `IsInstalled=0` | `$true` | | Optional Only | `AutoSelectOnWebSites=0 and IsInstalled=0` | `$_.BrowseOnly` | **NB** `Recommended` is the default setting. But you can customize them, e.g.: ```hcl build { provisioner "windows-update" { search_criteria = "IsInstalled=0" filters = [ "exclude:$_.Title -like '*Preview*'", "include:$true", ] update_limit = 25 } } ``` **NB** For more information about the search criteria see the [IUpdateSearcher::Search method](https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search) documentation and the [xWindowsUpdateAgent DSC resource source](https://github.com/dsccommunity/xWindowsUpdate/tree/master/source/DSCResources/MSFT_xWindowsUpdateAgent). **NB** If the `update_limit` attribute is not declared, it defaults to `1000`. The general filter syntax is: ACTION:EXPRESSION `ACTION` is a string that can have one of the following values: | action | description | | --------- | ------------------------------------------------------------ | | `include` | includes the update when the expression evaluates to `$true` | | `exclude` | excludes the update when the expression evaluates to `$true` | **NB** If no `ACTION` evaluates to `$true` the update will **NOT** be installed. `EXPRESSION` is a PowerShell expression. When it returns `$true`, the `ACTION` is executed and no further filters are evaluated. Inside an expression, the Windows Update [IUpdate interface](https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdate) can be referenced by the `$_` variable. # Development Install the dependencies: * [Docker](https://docs.docker.com/engine/install/). * [Visual Studio Code](https://code.visualstudio.com). * [Dev Container plugin](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers). * [`windows-2022-amd64` vagrant box](https://github.com/rgl/windows-vagrant). Open this directory with the Dev Container plugin. Open `bash` inside the Visual Studio Code Terminal. Build: ```bash make ``` Test with QEMU: ```bash make test ``` ================================================ FILE: ci-release.sh ================================================ #!/bin/bash set -euxo pipefail # ensure provisioner.hcl2spec.go is updated by re-generate it. if there are # differences, abort the build. rm -f update/provisioner.hcl2spec.go make update/provisioner.hcl2spec.go git diff --exit-code update/provisioner.hcl2spec.go \ || (echo 'ERROR: You must re-generate update/provisioner.hcl2spec.go and commit the changes.' && exit 1) # point the msys2 user gpg home to the one managed by the crazy-max/ghaction-import-gpg github action. ln -s /c/Users/runneradmin/.gnupg ~/.gnupg # do the release. if [[ $GITHUB_REF == refs/tags/v* ]]; then make release else make release-snapshot fi ================================================ FILE: go.mod ================================================ module github.com/rgl/packer-plugin-windows-update go 1.26.1 require ( github.com/hashicorp/hcl/v2 v2.24.0 github.com/hashicorp/packer-plugin-sdk v0.6.7 github.com/zclconf/go-cty v1.18.0 ) require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aws/aws-sdk-go-v2 v1.41.5 // indirect github.com/aws/aws-sdk-go-v2/config v1.32.14 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.19.14 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 // indirect github.com/aws/smithy-go v1.24.3 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/fatih/color v1.19.0 // indirect github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/consul/api v1.33.7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter/v2 v2.2.3 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.4 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/go-version v1.9.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/hashicorp/serf v0.10.2 // indirect github.com/hashicorp/vault/api v1.23.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/klauspost/compress v1.18.5 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/iochan v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/ugorji/go/codec v1.3.1 // indirect github.com/ulikunitz/xz v0.5.15 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect golang.org/x/mod v0.34.0 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/sys v0.42.0 // indirect golang.org/x/text v0.35.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.43.0 // indirect google.golang.org/protobuf v1.36.11 // indirect ) replace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/packer-plugin-sdk/issues/187 ================================================ FILE: go.sum ================================================ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI= github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo= github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5 h1:z2ayoK3pOvf8ODj/vPR0FgAS5ONruBq0F94SRoW/BIU= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.5/go.mod h1:mpZB5HAl4ZIISod9qCi12xZ170TbHX9CCJV5y7nb7QU= github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM= github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= github.com/aws/smithy-go v1.24.3 h1:XgOAaUgx+HhVBoP4v8n6HCQoTRDhoMghKqw4LNHsDNg= github.com/aws/smithy-go v1.24.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/consul/api v1.33.7 h1:apLZVzX7O7BLgHyh4pvczcsBzPmYSVXGKZQbOaA1ae0= github.com/hashicorp/consul/api v1.33.7/go.mod h1:SjR3cjwCUSLLDfVw5dFg76rnnKjOySxr8W8lC5s01C8= github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0= github.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter/v2 v2.2.3 h1:6CVzhT0KJQHqd9b0pK3xSP0CM/Cv+bVhk+jcaRJ2pGk= github.com/hashicorp/go-getter/v2 v2.2.3/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack/v2 v2.1.2 h1:4Ee8FTp834e+ewB71RDrQ0VKpyFdrKOjvYtnQ/ltVj0= github.com/hashicorp/go-msgpack/v2 v2.1.2/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= github.com/hashicorp/memberlist v0.5.2 h1:rJoNPWZ0juJBgqn48gjy59K5H4rNgvUoM1kUD7bXiuI= github.com/hashicorp/memberlist v0.5.2/go.mod h1:Ri9p/tRShbjYnpNf4FFPXG7wxEGY4Nrcn6E7jrVa//4= github.com/hashicorp/packer-plugin-sdk v0.6.7 h1:R6xO8j5GUT1AC+1CmDvXCjjiCDndWbIA1O7jJ3MeTVs= github.com/hashicorp/packer-plugin-sdk v0.6.7/go.mod h1:J+hZE+SdN0MPCZLmoRPSrqg4YuP/mXTuuVqiAYbDVfw= github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= github.com/hashicorp/vault/api v1.23.0 h1:gXgluBsSECfRWTSW9niY2jwg2e9mMJc4WoHNv4g3h6A= github.com/hashicorp/vault/api v1.23.0/go.mod h1:zransKiB9ftp+kgY8ydjnvCU7Wk8i9L0DYWpXeMj9ko= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nywilken/go-cty v1.13.3 h1:03U99oXf3j3g9xgqAE3YGpixCjM8Mg09KZ0Ji9LzX0o= github.com/nywilken/go-cty v1.13.3/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA= golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ= golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= ================================================ FILE: main.go ================================================ package main import ( "log" "github.com/hashicorp/packer-plugin-sdk/plugin" v "github.com/hashicorp/packer-plugin-sdk/version" "github.com/rgl/packer-plugin-windows-update/update" ) var ( version = "0.0.0" commit = "unknown" date = "unknown" ) func main() { log.Printf("Starting packer-plugin-windows-update (version %s; commit %s; date %s)", version, commit, date) pps := plugin.NewSet() pps.RegisterProvisioner(plugin.DEFAULT_NAME, new(update.Provisioner)) pps.SetVersion(v.InitializePluginVersion(version, "")) err := pps.Run() if err != nil { log.Fatalf("Failed to start: %v", err) } } ================================================ FILE: renovate.json5 ================================================ // see https://docs.renovatebot.com/templates/ // see https://docs.renovatebot.com/modules/manager/ // see https://docs.renovatebot.com/modules/manager/regex/ // see https://docs.renovatebot.com/configuration-options/ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "regexManagers": [ // default datasources. { "fileMatch": [ "\\.yml$", "\\.sh$", "Makefile", ], "matchStrings": [ "# renovate: datasource=(?[^:]+?) depName=(?.+?)( versioning=(?.+?))?( extractVersion=(?.+?))?( registryUrl=(?.+?))?\\s.+?(:=|:|=)\\s*[\"']?(?.+?)[\"']?\\s" ], "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}semver-coerced{{/if}}", "extractVersionTemplate": "{{#if extractVersion}}{{{extractVersion}}}{{else}}^v?(?.+)${{/if}}" }, // nuget:powershellgallery datasource. { "fileMatch": [ "\\.yml$", "\\.sh$", "Makefile", ], "matchStrings": [ "# renovate: datasource=(?nuget):powershellgallery depName=(?.+?)( versioning=(?.+?))?( extractVersion=(?.+?))?( registryUrl=(?.+?))?\\s.+?(:=|:|=)\\s*[\"']?(?.+?)[\"']?\\s" ], "registryUrlTemplate": "{{#if registryUrl}}{{{registryUrl}}}{{else}}https://www.powershellgallery.com/api/v2{{/if}}", "versioningTemplate": "{{#if versioning}}{{{versioning}}}{{else}}nuget{{/if}}", "extractVersionTemplate": "{{#if extractVersion}}{{{extractVersion}}}{{else}}^v?(?.+)${{/if}}" } ] } ================================================ FILE: renovate.sh ================================================ #!/bin/bash set -euo pipefail # this executes renovate against the local repository. # NB this uses a temporary gitea instance because running renovate against a # local directory not (yet?) supported. # see https://github.com/renovatebot/renovate/issues/3609 export RENOVATE_USERNAME='renovate' export RENOVATE_NAME='Renovate Bot' export RENOVATE_PASSWORD='password' gitea_container_name="$(basename "$(dirname "$(realpath "${BASH_SOURCE[0]}")")")-renovate-gitea" # see https://hub.docker.com/r/gitea/gitea/tags # renovate: datasource=docker depName=gitea/gitea gitea_version='1.25.5' # see https://hub.docker.com/r/renovate/renovate/tags # see https://github.com/renovatebot/renovate/releases # renovate: datasource=docker depName=renovate/renovate renovate_version='43.104.1' # clean. echo 'Deleting existing Gitea...' docker rm --force "$gitea_container_name" >/dev/null 2>&1 echo 'Deleting existing temporary files...' rm -f tmp/renovate-* install -d tmp # start gitea in background. # see https://docs.gitea.io/en-us/config-cheat-sheet/ # see https://github.com/go-gitea/gitea/releases # see https://github.com/go-gitea/gitea/blob/v1.25.5/docker/root/etc/s6/gitea/setup echo 'Starting Gitea...' docker run \ --detach \ --name "$gitea_container_name" \ -v /etc/timezone:/etc/timezone:ro \ -v /etc/localtime:/etc/localtime:ro \ -e SECRET_KEY=opensesame \ -p 3000 \ "gitea/gitea:$gitea_version" \ >/dev/null gitea_addr="$(docker port "$gitea_container_name" 3000 | head -1)" gitea_url="http://$gitea_addr" export RENOVATE_ENDPOINT="$gitea_url" export GIT_PUSH_REPOSITORY="http://$RENOVATE_USERNAME:$RENOVATE_PASSWORD@$gitea_addr/$RENOVATE_USERNAME/test.git" # wait for gitea to be ready. echo "Waiting for Gitea to be ready at $gitea_url..." GITEA_URL="$gitea_url" bash -euc 'while [ -z "$(wget -qO- "$GITEA_URL/api/v1/version" | jq -r ".version | select(.!=null)")" ]; do sleep 5; done' # create user in gitea. echo "Creating Gitea $RENOVATE_USERNAME user..." docker exec --user git "$gitea_container_name" gitea admin user create \ --admin \ --email "$RENOVATE_USERNAME@example.com" \ --username "$RENOVATE_USERNAME" \ --password "$RENOVATE_PASSWORD" curl \ --silent \ --show-error \ --fail-with-body \ -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ -X 'PATCH' \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d "{\"full_name\":\"$RENOVATE_NAME\"}" \ "$gitea_url/api/v1/user/settings" \ | jq \ > /dev/null # create the user personal access token. # see https://docs.gitea.io/en-us/api-usage/ # see https://docs.gitea.io/en-us/oauth2-provider/#scopes # see https://try.gitea.io/api/swagger#/user/userCreateToken echo "Creating Gitea $RENOVATE_USERNAME user personal access token..." curl \ --silent \ --show-error \ --fail-with-body \ -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ -X POST \ -H "Content-Type: application/json" \ -d '{"name": "renovate", "scopes": ["read:user", "write:issue", "write:repository"]}' \ "$gitea_url/api/v1/users/$RENOVATE_USERNAME/tokens" \ | jq -r .sha1 \ >tmp/renovate-gitea-token.txt # try the token. echo "Trying the Gitea $RENOVATE_USERNAME user personal access token..." RENOVATE_TOKEN="$(cat tmp/renovate-gitea-token.txt)" export RENOVATE_TOKEN curl \ --silent \ --show-error \ --fail-with-body \ -H "Authorization: token $RENOVATE_TOKEN" \ -H 'Accept: application/json' \ "$gitea_url/api/v1/version" \ | jq \ > /dev/null # create remote repository in gitea. echo "Creating Gitea $RENOVATE_USERNAME test repository..." curl \ --silent \ --show-error \ --fail-with-body \ -u "$RENOVATE_USERNAME:$RENOVATE_PASSWORD" \ -X POST \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"name": "test"}' \ "$gitea_url/api/v1/user/repos" \ | jq \ > /dev/null # push the code to local gitea repository. # NB running renovate locally is not yet supported. # see https://github.com/renovatebot/renovate/issues/3609 echo "Pushing local repository to Gitea $RENOVATE_USERNAME test repository..." git push --force "$GIT_PUSH_REPOSITORY" # see https://docs.renovatebot.com/modules/platform/gitea/ # see https://docs.renovatebot.com/self-hosted-configuration/#dryrun # see https://github.com/renovatebot/renovate/blob/main/docs/usage/examples/self-hosting.md # see https://github.com/renovatebot/renovate/tree/main/lib/modules/datasource # see https://github.com/renovatebot/renovate/tree/main/lib/modules/versioning RENOVATE_TOKEN="$(cat tmp/renovate-gitea-token.txt)" export RENOVATE_TOKEN # NB these can also be passed as raw positional arguments to docker run. export RENOVATE_REPOSITORIES="$RENOVATE_USERNAME/test" # see https://docs.github.com/en/rest/rate-limit#get-rate-limit-status-for-the-authenticated-user # see https://github.com/settings/tokens # NB this is only used for authentication. the token should not have any scope enabled. #export GITHUB_COM_TOKEN='TODO-YOUR-TOKEN' # let renovate create all the required pull requests. # see https://docs.renovatebot.com/configuration-options/#prhourlylimit # see https://docs.renovatebot.com/configuration-options/#prconcurrentlimit export RENOVATE_PR_HOURLY_LIMIT='0' export RENOVATE_PR_CONCURRENT_LIMIT='0' echo 'Running renovate...' # NB to capture the traffic using mitmproxy, start mitmweb in a different # shell, then enable the following if (i.e. true). docker_extra_args=() if false; then docker_extra_args+=( --env http_proxy=http://127.0.0.1:8080 --env https_proxy=http://127.0.0.1:8080 --env no_proxy= --env SSL_CERT_FILE=/usr/local/shared/ca-certificates/mitmproxy-ca.crt --volume "$HOME/.mitmproxy/mitmproxy-ca-cert.pem:/usr/local/shared/ca-certificates/mitmproxy-ca.crt:ro" ) fi # NB use --dry-run=lookup for not modifying the repository (e.g. for not # creating pull requests). docker run \ --rm \ --tty \ --interactive \ --net host \ --env GITHUB_COM_TOKEN \ --env RENOVATE_ENDPOINT \ --env RENOVATE_TOKEN \ --env RENOVATE_REPOSITORIES \ --env RENOVATE_PR_HOURLY_LIMIT \ --env RENOVATE_PR_CONCURRENT_LIMIT \ --env LOG_LEVEL=debug \ --env LOG_FORMAT=json \ "${docker_extra_args[@]}" \ "renovate/renovate:$renovate_version" \ --platform=gitea \ --git-url=endpoint \ >tmp/renovate-log.txt grep -E '^{' \ tmp/renovate-log.txt \ >tmp/renovate-log.json echo 'Getting results...' # extract the errors. jq 'select(.err)' tmp/renovate-log.json >tmp/renovate-errors.json # extract the result from the renovate log. jq 'select(.msg == "packageFiles with updates") | .config' tmp/renovate-log.json >tmp/renovate-result.json # extract all the dependencies. jq 'to_entries[].value[] | {packageFile,dep:.deps[]}' tmp/renovate-result.json >tmp/renovate-dependencies.json # extract the dependencies that have updates. jq 'select((.dep.updates | length) > 0)' tmp/renovate-dependencies.json >tmp/renovate-dependencies-updates.json # helpers. function show-title { echo echo '#' echo "# $1" echo '#' echo } # show errors. if [ "$(jq --slurp length tmp/renovate-errors.json)" -ne '0' ]; then show-title errors jq . tmp/renovate-errors.json fi # show dependencies. function show-dependencies { show-title "$1" ( printf 'packageFile\tdatasource\tdepName\tcurrentValue\tnewVersions\tskipReason\twarnings\n' jq \ -r \ '[ .packageFile, .dep.datasource, .dep.depName, .dep.currentValue, (.dep | select(.updates) | .updates | map(.newVersion) | join(" | ")), .dep.skipReason, (.dep | select(.warnings) | .warnings | map(.message) | join(" | ")) ] | @tsv' \ "$2" \ | sort ) | column -t -s "$(printf \\t)" } show-dependencies 'Dependencies' tmp/renovate-dependencies.json show-dependencies 'Dependencies Updates' tmp/renovate-dependencies-updates.json # show the gitea project. show-title "See PRs at $gitea_url/$RENOVATE_USERNAME/test/pulls (you can login as $RENOVATE_USERNAME:$RENOVATE_PASSWORD)" ================================================ FILE: test.pkr.hcl ================================================ packer { required_plugins { # see https://github.com/hashicorp/packer-plugin-qemu qemu = { version = "1.1.4" source = "github.com/hashicorp/qemu" } # see https://github.com/rgl/packer-plugin-windows-update windows-update = { version = ">= 0.0.0" source = "github.com/rgl/windows-update" } } } variable "disk_size" { type = string default = "61440" } variable "disk_image" { type = string } source "qemu" "test" { headless = true accelerator = "kvm" machine_type = "q35" cpus = 2 memory = 4096 qemuargs = [ strcontains(var.disk_image, "uefi") ? ["-bios", "/usr/share/ovmf/OVMF.fd"] : null, ["-cpu", "host"], ] disk_interface = "virtio-scsi" disk_cache = "unsafe" disk_discard = "unmap" disk_image = true use_backing_file = true disk_size = var.disk_size iso_url = var.disk_image iso_checksum = "none" net_device = "virtio-net" shutdown_command = "shutdown /s /t 0 /f /d p:4:1 /c \"Packer Shutdown\"" communicator = "winrm" winrm_username = "vagrant" winrm_password = "vagrant" winrm_timeout = "4h" } build { sources = [ "source.qemu.test", ] provisioner "windows-update" { } provisioner "powershell" { use_pwsh = true inline = [ <<-EOF $p = 'c:/packer.delete.me.to.end.test.wait.txt' Set-Content $p 'delete this file to end the packer test wait' Write-Host "ATTENTION To end this test wait, login into the machine and delete the $p file. Or just press Ctrl+C." while (Test-Path $p) { Start-Sleep -Seconds 5 } EOF ] } } ================================================ FILE: test.sh ================================================ #!/usr/bin/bash set -euo pipefail GOHOSTOS="$(go env GOHOSTOS)" GOHOSTARCH="$(go env GOHOSTARCH)" PLUGIN_PATH="$( jq -r \ --arg goos "$GOHOSTOS" \ --arg goarch "$GOHOSTARCH" \ '.[] | select(.goos == $goos and .goarch == $goarch and .extra.ID == "packer-plugin-windows-update") | .path' \ dist/artifacts.json)" PLUGIN_BASE_NAME="$(basename "$PLUGIN_PATH")" PLUGIN_TEST_PATH="dist/test/plugins/github.com/rgl/windows-update/$PLUGIN_BASE_NAME" # see https://developer.hashicorp.com/packer/docs/plugins/creation/plugin-load-spec rm -rf output-test test.log dist/test install -d dist/test/plugins/github.com/rgl/windows-update install "$PLUGIN_PATH" "$PLUGIN_TEST_PATH" (cd "$(dirname "$PLUGIN_TEST_PATH")" && \ sha256sum "$PLUGIN_BASE_NAME" >"${PLUGIN_BASE_NAME}_SHA256SUM") export CHECKPOINT_DISABLE=1 export PACKER_LOG=1 export PACKER_LOG_PATH=test.log export PACKER_CONFIG_DIR="$PWD/dist/test" export PACKER_PLUGIN_PATH="$PWD/dist/test/plugins" #export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-11-24h2-amd64/0.0.0/libvirt/box_0.img #export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2022-amd64/0.0.0/libvirt/box_0.img #export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2025-amd64/0.0.0/libvirt/box_0.img #export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-11-24h2-uefi-amd64/0.0.0/libvirt/box_0.img export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2022-uefi-amd64/0.0.0/libvirt/box_0.img #export PKR_VAR_disk_image=~/.vagrant.d/boxes/windows-2025-uefi-amd64/0.0.0/libvirt/box_0.img packer init -only=qemu.test test.pkr.hcl packer build -only=qemu.test -on-error=abort test.pkr.hcl ================================================ FILE: update/elevated-template.ps1 ================================================ Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' trap { Write-Output "ERROR: $_" Write-Output (($_.ScriptStackTrace -split '\r?\n') -replace '^(.*)$','ERROR: $1') Write-Output (($_.Exception.ToString() -split '\r?\n') -replace '^(.*)$','ERROR EXCEPTION: $1') Exit 1 } $name = "{{.TaskName}}" $log = "$env:SystemRoot\Temp\$name.out" $s = New-Object -ComObject "Schedule.Service" $s.Connect() $t = $s.NewTask($null) $t.XmlText = @' {{.TaskDescription}} HighestAvailable IgnoreNew false false true false false false false true true false false false PT24H 4 cmd /c {{.Command}} >%SYSTEMROOT%\Temp\{{.TaskName}}.out 2>&1 '@ $username = "{{.Username}}" $password = "{{.Password}}" if (!$password) { $password = $null } $f = $s.GetFolder("\") $f.RegisterTaskDefinition($name, $t, 6, $username, $password, 1, $null) | Out-Null $t = $f.GetTask("\$name") $t.Run($null) | Out-Null $timeout = 10 $sec = 0 while ((!($t.state -eq 4)) -and ($sec -lt $timeout)) { Start-Sleep -Seconds 1 $sec++ } # Windows PowerShell 2 on Windows 7 does not have Get-CimInstance. # PowerShell 6 does not have Get-WmiObject. if (!(Get-Command Get-CimInstance -ErrorAction:SilentlyContinue)) { function Get-CimInstance { [CmdletBinding()] param( [Parameter(Mandatory = $True, Position = 0)] [string] $ClassName ) Get-WmiObject -Class $ClassName } } $reportProgressInterval = New-TimeSpan -Minutes 1 $startDate = Get-Date $line = 0 do { Start-Sleep -Seconds 5 if (Test-Path $log) { Get-Content $log | Select-Object -skip $line | ForEach-Object { ++$line Write-Output $_ } } $currentDate = Get-Date if ($currentDate.Subtract($startDate) -ge $reportProgressInterval) { $startDate = $currentDate $cpuUsage = (Get-CimInstance CIM_Processor | Measure-Object -Property LoadPercentage -Average).Average / 100 $os = Get-CimInstance Win32_OperatingSystem $memoryUsage = 1 - $os.FreePhysicalMemory / $os.TotalVisibleMemorySize Write-Output ("Waiting for operation to complete (system performance: {0:P0} cpu; {1:P0} memory)..." -f $cpuUsage,$memoryUsage) } } while (!($t.state -eq 3)) $result = $t.LastTaskResult if (Test-Path $log) { Remove-Item $log -Force -ErrorAction SilentlyContinue | Out-Null } # delete scheduled task $f.DeleteTask("\$name", 0) [System.Runtime.Interopservices.Marshal]::ReleaseComObject($s) | Out-Null exit $result ================================================ FILE: update/elevated.go ================================================ // NB this code was based on https://github.com/hashicorp/packer/blob/370b67497e90785b71be1b6fcc6430de487d644e/provisioner/powershell/elevated.go package update import ( _ "embed" // this is needed for using the go:embed directive "text/template" ) type elevatedOptions struct { Username string Password string TaskName string TaskDescription string Command string } //go:embed elevated-template.ps1 var elevatedTemplatePs1 string var elevatedTemplate = template.Must( template.New("Elevated").Parse( elevatedTemplatePs1)) ================================================ FILE: update/provisioner.go ================================================ //go:generate packer-sdc mapstructure-to-hcl2 -type Config // NB this code was based on https://github.com/hashicorp/packer/blob/81522dced0b25084a824e79efda02483b12dc7cd/provisioner/windows-restart/provisioner.go package update import ( "bytes" "context" _ "embed" // this is needed for using the go:embed directive "encoding/base64" "errors" "fmt" "strings" "time" "unicode/utf16" "github.com/hashicorp/hcl/v2/hcldec" "github.com/hashicorp/packer-plugin-sdk/common" "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/retry" "github.com/hashicorp/packer-plugin-sdk/template/config" "github.com/hashicorp/packer-plugin-sdk/template/interpolate" "github.com/hashicorp/packer-plugin-sdk/uuid" ) const ( elevatedPath = "C:/Windows/Temp/packer-windows-update-elevated.ps1" elevatedCommand = "PowerShell -ExecutionPolicy Bypass -OutputFormat Text -File C:/Windows/Temp/packer-windows-update-elevated.ps1" windowsUpdatePath = "C:/Windows/Temp/packer-windows-update.ps1" pendingRebootElevatedPath = "C:/Windows/Temp/packer-windows-update-pending-reboot-elevated.ps1" pendingRebootElevatedCommand = "PowerShell -ExecutionPolicy Bypass -OutputFormat Text -File C:/Windows/Temp/packer-windows-update-pending-reboot-elevated.ps1" restartCommand = "shutdown.exe -f -r -t 0 -c \"packer restart\"" testRestartCommand = "shutdown.exe -f -r -t 60 -c \"packer restart test\"" abortTestRestartCommand = "shutdown.exe -a" retryableDelay = 5 * time.Second uploadTimeout = 5 * time.Minute ) //go:embed windows-update.ps1 var windowsUpdatePs1 []byte type Config struct { common.PackerConfig `mapstructure:",squash"` // The timeout for waiting for the machine to restart RestartTimeout time.Duration `mapstructure:"restart_timeout"` // Instructs the communicator to run the remote script as a // Windows scheduled task, effectively elevating the remote // user by impersonating a logged-in user. Username string `mapstructure:"username"` Password string `mapstructure:"password"` // The updates search criteria. // See the IUpdateSearcher::Search method at https://docs.microsoft.com/en-us/windows/desktop/api/wuapi/nf-wuapi-iupdatesearcher-search. SearchCriteria string `mapstructure:"search_criteria"` // Filters the installed Windows updates. If no filter is // matched the update is NOT installed. Filters []string `mapstructure:"filters"` // Adds a limit to how many updates are installed at a time UpdateLimit int `mapstructure:"update_limit"` // Max times the provisioner will try install the updates // in case of failure. UpdateMaxRetries int `mapstructure:"update_max_retries"` ctx interpolate.Context } type Provisioner struct { config Config } func (b *Provisioner) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } func (p *Provisioner) Prepare(raws ...interface{}) error { err := config.Decode(&p.config, &config.DecodeOpts{ Interpolate: true, InterpolateContext: &p.config.ctx, InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "execute_command", }, }, }, raws...) if err != nil { return err } if p.config.RestartTimeout == 0 { p.config.RestartTimeout = 4 * time.Hour } if p.config.Username == "" { p.config.Username = "SYSTEM" } var errs error if p.config.Username == "" { errs = packer.MultiErrorAppend(errs, errors.New("Must supply an 'username'")) } if p.config.UpdateLimit == 0 { p.config.UpdateLimit = 1000 } if p.config.UpdateMaxRetries == 0 { p.config.UpdateMaxRetries = 5 } return errs } func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.Communicator, _ map[string]interface{}) error { ui.Say("Uploading the Windows update elevated script...") var buffer bytes.Buffer err := elevatedTemplate.Execute(&buffer, elevatedOptions{ Username: p.config.Username, Password: p.config.Password, TaskDescription: "Packer Windows update elevated task", TaskName: fmt.Sprintf("packer-windows-update-%s", uuid.TimeOrderedUUID()), Command: p.windowsUpdateCommand(), }) if err != nil { fmt.Printf("Error creating elevated template: %s", err) return err } err = retry.Config{StartTimeout: uploadTimeout}.Run(ctx, func(context.Context) error { if err := comm.Upload( elevatedPath, bytes.NewReader(buffer.Bytes()), nil); err != nil { return fmt.Errorf("Error uploading the Windows update elevated script: %s", err) } return nil }) if err != nil { return err } ui.Say("Uploading the Windows update check for reboot required elevated script...") buffer.Reset() err = elevatedTemplate.Execute(&buffer, elevatedOptions{ Username: p.config.Username, Password: p.config.Password, TaskDescription: "Packer Windows update pending reboot elevated task", TaskName: fmt.Sprintf("packer-windows-update-pending-reboot-%s", uuid.TimeOrderedUUID()), Command: p.windowsUpdateCheckForRebootRequiredCommand(), }) if err != nil { fmt.Printf("Error creating elevated template: %s", err) return err } err = retry.Config{StartTimeout: uploadTimeout}.Run(ctx, func(context.Context) error { if err := comm.Upload( pendingRebootElevatedPath, bytes.NewReader(buffer.Bytes()), nil); err != nil { return fmt.Errorf("Error uploading the Windows update check for reboot required elevated script: %s", err) } return nil }) if err != nil { return err } ui.Say("Uploading the Windows update script...") err = comm.Upload( windowsUpdatePath, bytes.NewReader(windowsUpdatePs1), nil) if err != nil { return err } for { restartPending, err := p.update(ctx, ui, comm) if err != nil { return err } if !restartPending { return nil } err = p.restart(ctx, ui, comm) if err != nil { return err } } } func (p *Provisioner) update(ctx context.Context, ui packer.Ui, comm packer.Communicator) (bool, error) { ui.Say("Running Windows update...") var restartPending bool err := retry.Config{ RetryDelay: func() time.Duration { return retryableDelay }, Tries: p.config.UpdateMaxRetries, }.Run(ctx, func(ctx context.Context) error { ui := NewUpdateUi(ui) cmd := &packer.RemoteCmd{Command: elevatedCommand} err := cmd.RunWithUi(ctx, comm, ui) if err != nil { return err } var exitStatus = cmd.ExitStatus() if !ui.finished { return fmt.Errorf("Windows update script did not finish") } switch exitStatus { case 0: return nil case 101: restartPending = true return nil case 2147942501: //windows 2012 restartPending = true return nil default: return fmt.Errorf("Windows update script exited with non-zero exit status: %d", exitStatus) } }) return restartPending, err } func (p *Provisioner) restart(ctx context.Context, ui packer.Ui, comm packer.Communicator) error { restartPending := true for restartPending { ui.Say("Restarting the machine...") err := p.retryable(ctx, func(ctx context.Context) error { cmd := &packer.RemoteCmd{Command: restartCommand} err := cmd.RunWithUi(ctx, comm, ui) if err != nil { return err } exitStatus := cmd.ExitStatus() if exitStatus != 0 { return fmt.Errorf("Failed to restart the machine with exit status: %d", exitStatus) } return err }) if err != nil { return err } ui.Say("Waiting for machine to become available...") err = p.retryable(ctx, func(ctx context.Context) error { // wait for the machine to reboot. cmd := &packer.RemoteCmd{Command: testRestartCommand} err := cmd.RunWithUi(ctx, comm, ui) if err != nil { return err } exitStatus := cmd.ExitStatus() if exitStatus != 0 { return fmt.Errorf("Machine not yet available (exit status %d)", exitStatus) } cmd = &packer.RemoteCmd{Command: abortTestRestartCommand} err = cmd.RunWithUi(ctx, comm, ui) return err }) if err != nil { return err } ui.Say("Checking for pending restart...") err = p.retryable(ctx, func(ctx context.Context) error { ui := NewUpdateUi(ui) cmd := &packer.RemoteCmd{Command: pendingRebootElevatedCommand} err = cmd.RunWithUi(ctx, comm, ui) if err != nil { return err } if !ui.finished { return fmt.Errorf("Windows update script did not finish") } exitStatus := cmd.ExitStatus() switch exitStatus { case 0: restartPending = false case 101: restartPending = true case 2147942501: //windows 2012 restartPending = true default: return fmt.Errorf("Machine not yet available (exit status %d)", exitStatus) } return err }) if err != nil { return err } if restartPending { ui.Say("Restart is still pending...") } else { ui.Say("Restart complete") } } return nil } // retryable will retry the given function over and over until a // non-error is returned, RestartTimeout expires, or ctx is // cancelled. func (p *Provisioner) retryable(ctx context.Context, f func(ctx context.Context) error) error { return retry.Config{ RetryDelay: func() time.Duration { return retryableDelay }, StartTimeout: p.config.RestartTimeout, }.Run(ctx, f) } func (p *Provisioner) windowsUpdateCommand() string { return fmt.Sprintf( "PowerShell -ExecutionPolicy Bypass -OutputFormat Text -EncodedCommand %s", base64.StdEncoding.EncodeToString( encodeUtf16Le(fmt.Sprintf( "%s%s%s -UpdateLimit %d", windowsUpdatePath, searchCriteriaArgument(p.config.SearchCriteria), filtersArgument(p.config.Filters), p.config.UpdateLimit)))) } func (p *Provisioner) windowsUpdateCheckForRebootRequiredCommand() string { return fmt.Sprintf( "PowerShell -ExecutionPolicy Bypass -OutputFormat Text -EncodedCommand %s", base64.StdEncoding.EncodeToString( encodeUtf16Le(fmt.Sprintf( "%s -OnlyCheckForRebootRequired", windowsUpdatePath)))) } func encodeUtf16Le(s string) []byte { d := utf16.Encode([]rune(s)) b := make([]byte, len(d)*2) for i, r := range d { b[i*2] = byte(r) b[i*2+1] = byte(r >> 8) } return b } func searchCriteriaArgument(searchCriteria string) string { if searchCriteria == "" { return "" } var buffer bytes.Buffer buffer.WriteString(" -SearchCriteria ") buffer.WriteString(escapePowerShellString(searchCriteria)) return buffer.String() } func filtersArgument(filters []string) string { if filters == nil { return "" } var buffer bytes.Buffer buffer.WriteString(" -Filters ") for i, filter := range filters { if i > 0 { buffer.WriteString(",") } buffer.WriteString(escapePowerShellString(filter)) } return buffer.String() } func escapePowerShellString(value string) string { return fmt.Sprintf( "'%s'", // escape single quotes with another single quote. strings.ReplaceAll(value, "'", "''")) } ================================================ FILE: update/provisioner.hcl2spec.go ================================================ // Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. package update import ( "github.com/hashicorp/hcl/v2/hcldec" "github.com/zclconf/go-cty/cty" ) // FlatConfig is an auto-generated flat version of Config. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatConfig struct { PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` RestartTimeout *string `mapstructure:"restart_timeout" cty:"restart_timeout" hcl:"restart_timeout"` Username *string `mapstructure:"username" cty:"username" hcl:"username"` Password *string `mapstructure:"password" cty:"password" hcl:"password"` SearchCriteria *string `mapstructure:"search_criteria" cty:"search_criteria" hcl:"search_criteria"` Filters []string `mapstructure:"filters" cty:"filters" hcl:"filters"` UpdateLimit *int `mapstructure:"update_limit" cty:"update_limit" hcl:"update_limit"` UpdateMaxRetries *int `mapstructure:"update_max_retries" cty:"update_max_retries" hcl:"update_max_retries"` } // FlatMapstructure returns a new FlatConfig. // FlatConfig is an auto-generated flat version of Config. // Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { return new(FlatConfig) } // HCL2Spec returns the hcl spec of a Config. // This spec is used by HCL to read the fields of Config. // The decoded values from this spec will then be applied to a FlatConfig. func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, "restart_timeout": &hcldec.AttrSpec{Name: "restart_timeout", Type: cty.String, Required: false}, "username": &hcldec.AttrSpec{Name: "username", Type: cty.String, Required: false}, "password": &hcldec.AttrSpec{Name: "password", Type: cty.String, Required: false}, "search_criteria": &hcldec.AttrSpec{Name: "search_criteria", Type: cty.String, Required: false}, "filters": &hcldec.AttrSpec{Name: "filters", Type: cty.List(cty.String), Required: false}, "update_limit": &hcldec.AttrSpec{Name: "update_limit", Type: cty.Number, Required: false}, "update_max_retries": &hcldec.AttrSpec{Name: "update_max_retries", Type: cty.Number, Required: false}, } return s } ================================================ FILE: update/update_ui.go ================================================ package update import ( "io" "strings" "github.com/hashicorp/packer-plugin-sdk/packer" ) type UpdateUi struct { ui packer.Ui finished bool } func NewUpdateUi(ui packer.Ui) *UpdateUi { return &UpdateUi{ ui: ui, finished: false, } } func (u *UpdateUi) Askf(s string, args ...any) (string, error) { return u.ui.Askf(s, args...) } func (u *UpdateUi) Ask(s string) (string, error) { return u.ui.Ask(s) } func (u *UpdateUi) Sayf(s string, args ...any) { u.ui.Sayf(s, args...) } func (u *UpdateUi) Say(s string) { if strings.HasPrefix(s, "Exiting with code ") { u.finished = true return } u.ui.Say(s) } func (u *UpdateUi) Message(s string) { u.Say(s) } func (u *UpdateUi) Errorf(s string, args ...any) { u.ui.Errorf(s, args...) } func (u *UpdateUi) Error(s string) { u.ui.Error(s) } func (u *UpdateUi) Machine(t string, args ...string) { u.ui.Machine(t, args...) } func (u *UpdateUi) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) (body io.ReadCloser) { return u.ui.TrackProgress(src, currentSize, totalSize, stream) } ================================================ FILE: update/windows-update.ps1 ================================================ # see Using the Windows Update Agent API | Searching, Downloading, and Installing Updates # at https://learn.microsoft.com/en-us/windows/win32/wua_sdk/searching--downloading--and-installing-updates # see ISystemInformation interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-isysteminformation # see IUpdateSession interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatesession # see IUpdateSearcher interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatesearcher # see IUpdateSearcher::Search method # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesearcher-search # see IUpdateDownloader interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatedownloader # see IUpdateCollection interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdatecollection # see IUpdate interface # at https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nn-wuapi-iupdate # see xWindowsUpdateAgent DSC resource # at https://github.com/dsccommunity/xWindowsUpdate/tree/master/source/DSCResources/MSFT_xWindowsUpdateAgent # NB you can install common sets of updates with one of these settings: # | Name | SearchCriteria | Filters | # |---------------|-------------------------------------------|---------------| # | Important | AutoSelectOnWebSites=1 and IsInstalled=0 | $true | # | Recommended | BrowseOnly=0 and IsInstalled=0 | $true | # | All | IsInstalled=0 | $true | # | Optional Only | AutoSelectOnWebSites=0 and IsInstalled=0 | $_.BrowseOnly | param( [string]$SearchCriteria = 'BrowseOnly=0 and IsInstalled=0', [string[]]$Filters = @('include:$true'), [int]$UpdateLimit = 1000, [switch]$OnlyCheckForRebootRequired = $false ) $mock = $false function ExitWithCode($exitCode) { $host.SetShouldExit($exitCode) Write-Output "Exiting with code $exitCode" Exit } Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' trap { Write-Output "ERROR: $_" Write-Output (($_.ScriptStackTrace -split '\r?\n') -replace '^(.*)$','ERROR: $1') Write-Output (($_.Exception.ToString() -split '\r?\n') -replace '^(.*)$','ERROR EXCEPTION: $1') ExitWithCode 1 } if ($mock) { $mockWindowsUpdatePath = 'C:\Windows\Temp\windows-update-count-mock.txt' if (!(Test-Path $mockWindowsUpdatePath)) { Set-Content $mockWindowsUpdatePath 10 } $count = [int]::Parse((Get-Content $mockWindowsUpdatePath).Trim()) if ($count) { Write-Output "Synthetic reboot countdown counter is at $count" Set-Content $mockWindowsUpdatePath (--$count) ExitWithCode 101 } Write-Output 'No Windows updates found' ExitWithCode 0 } Add-Type @' using System; using System.Runtime.InteropServices; public static class Windows { [DllImport("kernel32", SetLastError=true)] public static extern UInt64 GetTickCount64(); public static TimeSpan GetUptime() { return TimeSpan.FromMilliseconds(GetTickCount64()); } } '@ function Wait-Condition { param( [scriptblock]$Condition, [int]$DebounceSeconds=15 ) process { $begin = [Windows]::GetUptime() do { Start-Sleep -Seconds 1 try { $result = &$Condition } catch { $result = $false } if (-not $result) { $begin = [Windows]::GetUptime() continue } } while ((([Windows]::GetUptime()) - $begin).TotalSeconds -lt $DebounceSeconds) } } $operationResultCodes = @{ 0 = "NotStarted"; 1 = "InProgress"; 2 = "Succeeded"; 3 = "SucceededWithErrors"; 4 = "Failed"; 5 = "Aborted" } function LookupOperationResultCode($code) { if ($operationResultCodes.ContainsKey($code)) { return $operationResultCodes[$code] } return "Unknown Code $code" } function ExitWhenRebootRequired($rebootRequired = $false) { # check for pending Windows Updates. if (!$rebootRequired) { $systemInformation = New-Object -ComObject 'Microsoft.Update.SystemInfo' $rebootRequired = $systemInformation.RebootRequired } # check for pending Windows Features. if (!$rebootRequired) { $pendingPackagesKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending' $pendingPackagesCount = (Get-ChildItem -ErrorAction SilentlyContinue $pendingPackagesKey | Measure-Object).Count $rebootRequired = $pendingPackagesCount -gt 0 } if ($rebootRequired) { Write-Output 'Waiting for the Windows Modules Installer to exit...' Wait-Condition {(Get-Process -ErrorAction SilentlyContinue TiWorker | Measure-Object).Count -eq 0} ExitWithCode 101 } } # try to repair the windows update settings to work in non-preview mode. # see https://github.com/rgl/packer-plugin-windows-update/issues/144 # see https://learn.microsoft.com/en-sg/answers/questions/1791668/powershell-command-outputting-system-comobject-on function Repair-WindowsUpdate { $settingsPath = 'C:\ProgramData\Microsoft\Windows\OneSettings\UusSettings.json' if (!(Test-Path $settingsPath)) { throw 'the windows update api is in an invalid state. see https://github.com/rgl/packer-plugin-windows-update/issues/144.' } $version = (New-Object -ComObject Microsoft.Update.AgentInfo).GetInfo('ProductVersionString') $settings = Get-Content -Raw $settingsPath | ConvertFrom-Json if ($settings.settings.EXCLUSIONS -notcontains $version) { $settings.settings.EXCLUSIONS += $version Write-Output 'Repairing the windows update settings to work in non-preview mode...' Copy-Item $settingsPath "$settingsPath.backup.json" -Force [System.IO.File]::WriteAllText( $settingsPath, ($settings | ConvertTo-Json -Compress -Depth 100), (New-Object System.Text.UTF8Encoding $false)) } Write-Output 'Restarting the machine to retry a new windows update round...' ExitWithCode 101 } ExitWhenRebootRequired if ($OnlyCheckForRebootRequired) { Write-Output "$env:COMPUTERNAME restarted." ExitWithCode 0 } $updateFilters = $Filters | ForEach-Object { $action, $expression = $_ -split ':',2 New-Object PSObject -Property @{ Action = $action Expression = [ScriptBlock]::Create($expression) } } function Test-IncludeUpdate($filters, $update) { foreach ($filter in $filters) { if (Where-Object -InputObject $update $filter.Expression) { return $filter.Action -eq 'include' } } return $false } $windowsOsVersion = [System.Environment]::OSVersion.Version Write-Output 'Searching for Windows updates...' $updatesToDownloadSize = 0 $updatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl' $updatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl' while ($true) { try { $updateSession = New-Object -ComObject 'Microsoft.Update.Session' $updateSession.ClientApplicationID = 'packer-windows-update' $updateSearcher = $updateSession.CreateUpdateSearcher() $searchResult = $updateSearcher.Search($SearchCriteria) if ($searchResult.ResultCode -eq 2) { break } $searchStatus = LookupOperationResultCode($searchResult.ResultCode) } catch { $searchStatus = $_.ToString() } Write-Output "Search for Windows updates failed with '$searchStatus'. Retrying..." Start-Sleep -Seconds 5 } $rebootRequired = $false for ($i = 0; $i -lt $searchResult.Updates.Count; ++$i) { $update = $searchResult.Updates.Item($i) # when the windows update api returns an invalid update object, repair # windows update and signal a reboot to try again. # see https://github.com/rgl/packer-plugin-windows-update/issues/144 # see The June 2024 preview update might impact applications using Windows Update APIs # https://learn.microsoft.com/en-us/windows/release-health/status-windows-11-23h2#3351msgdesc $expectedProperties = @( 'Title' 'MaxDownloadSize' 'LastDeploymentChangeTime' 'InstallationBehavior' 'AcceptEula' ) $properties = $update ` | Get-Member $expectedProperties ` | Select-Object -ExpandProperty Name if (!$properties -or (Compare-Object $expectedProperties $properties)) { Repair-WindowsUpdate } $updateTitle = $update.Title $updateMaxDownloadSize = $update.MaxDownloadSize $updateDate = $update.LastDeploymentChangeTime.ToString('yyyy-MM-dd') $updateSize = ($updateMaxDownloadSize/1024/1024).ToString('0.##') $updateSummary = "Windows update ($updateDate; $updateSize MB): $updateTitle" if (!(Test-IncludeUpdate $updateFilters $update)) { Write-Output "Skipped (filter) $updateSummary" continue } if ($update.InstallationBehavior.CanRequestUserInput) { Write-Output "Warning The update '$updateTitle' has the CanRequestUserInput flag set (if the install hangs, you might need to exclude it with the filter 'exclude:`$_.InstallationBehavior.CanRequestUserInput' or 'exclude:`$_.Title -like '*$updateTitle*'')" } if (($updatesToInstall | Select-Object -ExpandProperty Title) -contains $updateTitle) { Write-Output "Warning, Skipping queueing the duplicated titled update '$updateTitle'." continue } Write-Output "Found $updateSummary" $update.AcceptEula() | Out-Null $updatesToDownloadSize += $updateMaxDownloadSize $updatesToDownload.Add($update) | Out-Null $updatesToInstall.Add($update) | Out-Null if ($updatesToInstall.Count -ge $UpdateLimit) { $rebootRequired = $true break } } if ($updatesToDownload.Count) { $updateSize = ($updatesToDownloadSize/1024/1024).ToString('0.##') Write-Output "Downloading Windows updates ($($updatesToDownload.Count) updates; $updateSize MB)..." $updateDownloader = $updateSession.CreateUpdateDownloader() # see https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoa#remarks if (($windowsOsVersion.Major -eq 6 -and $windowsOsVersion.Minor -gt 1) -or ($windowsOsVersion.Major -gt 6)) { $updateDownloader.Priority = 4 # 1 (dpLow), 2 (dpNormal), 3 (dpHigh), 4 (dpExtraHigh). } else { # For versions lower then 6.2 highest prioirty is 3 $updateDownloader.Priority = 3 # 1 (dpLow), 2 (dpNormal), 3 (dpHigh). } $updateDownloader.Updates = $updatesToDownload while ($true) { $downloadResult = $updateDownloader.Download() if ($downloadResult.ResultCode -eq 2) { break } if ($downloadResult.ResultCode -eq 3) { Write-Output "Download Windows updates succeeded with errors. Will retry after the next reboot." $rebootRequired = $true break } $downloadStatus = LookupOperationResultCode($downloadResult.ResultCode) Write-Output "Download Windows updates failed with $downloadStatus. Retrying..." Start-Sleep -Seconds 5 } } if ($updatesToInstall.Count) { Write-Output 'Installing Windows updates...' $updateInstaller = $updateSession.CreateUpdateInstaller() $updateInstaller.Updates = $updatesToInstall $installRebootRequired = $false try { $installResult = $updateInstaller.Install() Write-Output "Windows update installation completed. Checking for more updates after a reboot..." $installRebootRequired = $installResult.RebootRequired -or $true } catch { Write-Warning "Windows update installation failed with error:" Write-Warning $_.Exception.ToString() # Windows update install failed for some reason # restart the machine and try again $rebootRequired = $true } ExitWhenRebootRequired ($installRebootRequired -or $rebootRequired) } else { ExitWhenRebootRequired $rebootRequired Write-Output 'No Windows updates found' } ExitWithCode 0