├── .devcontainer ├── Dockerfile ├── README.md └── devcontainer.json ├── .fixtures.yml ├── .gitattributes ├── .github ├── pull_request_template.md └── workflows │ ├── ci.yml │ ├── mend.yml │ ├── nightly.yml │ ├── release.yml │ └── release_prep.yml ├── .gitignore ├── .gitpod.Dockerfile ├── .gitpod.yml ├── .pdkignore ├── .puppet-lint.rc ├── .rspec ├── .rubocop.yml ├── .rubocop_todo.yml ├── .sync.yml ├── .vscode └── extensions.json ├── .yardopts ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── Gemfile ├── HISTORY.md ├── LICENSE ├── NOTICE ├── README.md ├── REFERENCE.md ├── Rakefile ├── data └── common.yaml ├── examples ├── compliance_example.pp ├── purge_example.pp ├── registry_examples.pp └── service_example.pp ├── hiera.yaml ├── lib ├── puppet │ ├── provider │ │ ├── registry_key │ │ │ └── registry.rb │ │ └── registry_value │ │ │ └── registry.rb │ └── type │ │ ├── registry_key.rb │ │ └── registry_value.rb └── puppet_x │ └── puppetlabs │ └── registry.rb ├── locales └── config.yaml ├── manifests ├── service.pp └── value.pp ├── metadata.json ├── pdk.yaml ├── provision.yaml └── spec ├── acceptance └── registry_management_spec.rb ├── classes └── mixed_default_settings_spec.rb ├── default_facts.yml ├── defines └── value_spec.rb ├── fixtures └── mixed_default_settings │ └── manifests │ └── init.pp ├── spec_helper.rb ├── spec_helper_acceptance.rb ├── spec_helper_acceptance_local.rb ├── spec_helper_local.rb ├── unit └── puppet │ ├── provider │ ├── registry_key_spec.rb │ └── registry_value_spec.rb │ └── type │ ├── registry_key_spec.rb │ └── registry_value_spec.rb └── watchr.rb /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM puppet/pdk:latest 2 | 3 | # [Optional] Uncomment this section to install additional packages. 4 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 5 | # && apt-get -y install --no-install-recommends 6 | 7 | -------------------------------------------------------------------------------- /.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | # devcontainer 2 | 3 | 4 | For format details, see https://aka.ms/devcontainer.json. 5 | 6 | For config options, see the README at: 7 | https://github.com/microsoft/vscode-dev-containers/tree/v0.140.1/containers/puppet 8 | 9 | ``` json 10 | { 11 | "name": "Puppet Development Kit (Community)", 12 | "dockerFile": "Dockerfile", 13 | 14 | // Set *default* container specific settings.json values on container create. 15 | "settings": { 16 | "terminal.integrated.profiles.linux": { 17 | "bash": { 18 | "path": "bash", 19 | } 20 | } 21 | }, 22 | 23 | // Add the IDs of extensions you want installed when the container is created. 24 | "extensions": [ 25 | "puppet.puppet-vscode", 26 | "rebornix.Ruby" 27 | ], 28 | 29 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 30 | "forwardPorts": [], 31 | 32 | // Use 'postCreateCommand' to run commands after the container is created. 33 | "postCreateCommand": "pdk --version", 34 | } 35 | ``` 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Puppet Development Kit (Community)", 3 | "dockerFile": "Dockerfile", 4 | 5 | "settings": { 6 | "terminal.integrated.profiles.linux": { 7 | "bash": { 8 | "path": "bash" 9 | } 10 | } 11 | }, 12 | 13 | "extensions": [ 14 | "puppet.puppet-vscode", 15 | "rebornix.Ruby" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.fixtures.yml: -------------------------------------------------------------------------------- 1 | fixtures: 2 | repositories: 3 | facts: 'https://github.com/puppetlabs/puppetlabs-facts.git' 4 | provision: 'https://github.com/puppetlabs/provision.git' 5 | puppet_agent: 6 | repo: 'https://github.com/puppetlabs/puppetlabs-puppet_agent.git' 7 | ref: v4.13.0 8 | symlinks: 9 | registry: "#{source_dir}" 10 | mixed_default_settings: "#{source_dir}/spec/fixtures/mixed_default_settings" 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rb eol=lf 2 | *.erb eol=lf 3 | *.pp eol=lf 4 | *.sh eol=lf 5 | *.epp eol=lf 6 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | Provide a detailed description of all the changes present in this pull request. 3 | 4 | ## Additional Context 5 | Add any additional context about the problem here. 6 | - [ ] Root cause and the steps to reproduce. (If applicable) 7 | - [ ] Thought process behind the implementation. 8 | 9 | ## Related Issues (if any) 10 | Mention any related issues or pull requests. 11 | 12 | ## Checklist 13 | - [ ] 🟢 Spec tests. 14 | - [ ] 🟢 Acceptance tests. 15 | - [ ] Manually verified. (For example `puppet apply`) -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: "ci" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "main" 7 | workflow_dispatch: 8 | 9 | jobs: 10 | Spec: 11 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 12 | secrets: "inherit" 13 | 14 | Acceptance: 15 | needs: Spec 16 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 17 | secrets: "inherit" 18 | -------------------------------------------------------------------------------- /.github/workflows/mend.yml: -------------------------------------------------------------------------------- 1 | name: "mend" 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - "main" 7 | schedule: 8 | - cron: "0 0 * * *" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | 13 | mend: 14 | uses: "puppetlabs/cat-github-actions/.github/workflows/mend_ruby.yml@main" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: "nightly" 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | Spec: 10 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_ci.yml@main" 11 | secrets: "inherit" 12 | 13 | Acceptance: 14 | needs: Spec 15 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_acceptance.yml@main" 16 | secrets: "inherit" 17 | 18 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: "Publish module" 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | release: 8 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release.yml@main" 9 | secrets: "inherit" 10 | -------------------------------------------------------------------------------- /.github/workflows/release_prep.yml: -------------------------------------------------------------------------------- 1 | name: "Release Prep" 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: "Module version to be released. Must be a valid semver string. (1.2.3)" 8 | required: true 9 | 10 | jobs: 11 | release_prep: 12 | uses: "puppetlabs/cat-github-actions/.github/workflows/module_release_prep.yml@main" 13 | with: 14 | version: "${{ github.event.inputs.version }}" 15 | secrets: "inherit" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /.vendor/ 23 | /convert_report.txt 24 | /update_report.txt 25 | .DS_Store 26 | .project 27 | .envrc 28 | /inventory.yaml 29 | /spec/fixtures/litmus_inventory.yaml 30 | .resource_types 31 | .modules 32 | .task_cache.json 33 | .plan_cache.json 34 | .rerun.json 35 | bolt-debug.log 36 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | RUN sudo wget https://apt.puppet.com/puppet-tools-release-bionic.deb && \ 3 | wget https://apt.puppetlabs.com/puppet6-release-bionic.deb && \ 4 | sudo dpkg -i puppet6-release-bionic.deb && \ 5 | sudo dpkg -i puppet-tools-release-bionic.deb && \ 6 | sudo apt-get update && \ 7 | sudo apt-get install -y pdk zsh puppet-agent && \ 8 | sudo apt-get clean && \ 9 | sudo rm -rf /var/lib/apt/lists/* 10 | RUN sudo usermod -s $(which zsh) gitpod && \ 11 | sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" && \ 12 | echo "plugins=(git gitignore github gem pip bundler python ruby docker docker-compose)" >> /home/gitpod/.zshrc && \ 13 | echo 'PATH="$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/puppetlabs/bin:/opt/puppetlabs/puppet/bin"' >> /home/gitpod/.zshrc && \ 14 | sudo /opt/puppetlabs/puppet/bin/gem install puppet-debugger hub -N && \ 15 | mkdir -p /home/gitpod/.config/puppet && \ 16 | /opt/puppetlabs/puppet/bin/ruby -r yaml -e "puts ({'disabled' => true}).to_yaml" > /home/gitpod/.config/puppet/analytics.yml 17 | RUN rm -f puppet6-release-bionic.deb puppet-tools-release-bionic.deb 18 | ENTRYPOINT /usr/bin/zsh 19 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | - init: pdk bundle install 6 | 7 | vscode: 8 | extensions: 9 | - puppet.puppet-vscode@1.0.0:oSzfTkDf6Cmc1jOjgW33VA== 10 | -------------------------------------------------------------------------------- /.pdkignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .*.sw[op] 3 | .metadata 4 | .yardoc 5 | .yardwarns 6 | *.iml 7 | /.bundle/ 8 | /.idea/ 9 | /.vagrant/ 10 | /coverage/ 11 | /bin/ 12 | /doc/ 13 | /Gemfile.local 14 | /Gemfile.lock 15 | /junit/ 16 | /log/ 17 | /pkg/ 18 | /spec/fixtures/manifests/ 19 | /spec/fixtures/modules/* 20 | /tmp/ 21 | /vendor/ 22 | /.vendor/ 23 | /convert_report.txt 24 | /update_report.txt 25 | .DS_Store 26 | .project 27 | .envrc 28 | /inventory.yaml 29 | /spec/fixtures/litmus_inventory.yaml 30 | .resource_types 31 | .modules 32 | .task_cache.json 33 | .plan_cache.json 34 | .rerun.json 35 | bolt-debug.log 36 | /.fixtures.yml 37 | /Gemfile 38 | /.gitattributes 39 | /.github/ 40 | /.gitignore 41 | /.pdkignore 42 | /.puppet-lint.rc 43 | /Rakefile 44 | /rakelib/ 45 | /.rspec 46 | /..yml 47 | /.yardopts 48 | /spec/ 49 | /.vscode/ 50 | /.sync.yml 51 | /.devcontainer/ 52 | -------------------------------------------------------------------------------- /.puppet-lint.rc: -------------------------------------------------------------------------------- 1 | --relative 2 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | require: 3 | - rubocop-performance 4 | - rubocop-rspec 5 | AllCops: 6 | NewCops: enable 7 | DisplayCopNames: true 8 | TargetRubyVersion: '2.6' 9 | Include: 10 | - "**/*.rb" 11 | Exclude: 12 | - bin/* 13 | - ".vendor/**/*" 14 | - "**/Gemfile" 15 | - "**/Rakefile" 16 | - pkg/**/* 17 | - spec/fixtures/**/* 18 | - vendor/**/* 19 | - "**/Puppetfile" 20 | - "**/Vagrantfile" 21 | - "**/Guardfile" 22 | inherit_from: ".rubocop_todo.yml" 23 | Layout/LineLength: 24 | Description: People have wide screens, use them. 25 | Max: 200 26 | RSpec/BeforeAfterAll: 27 | Description: Beware of using after(:all) as it may cause state to leak between tests. 28 | A necessary evil in acceptance testing. 29 | Exclude: 30 | - spec/acceptance/**/*.rb 31 | RSpec/HookArgument: 32 | Description: Prefer explicit :each argument, matching existing module's style 33 | EnforcedStyle: each 34 | RSpec/DescribeSymbol: 35 | Exclude: 36 | - spec/unit/facter/**/*.rb 37 | Style/BlockDelimiters: 38 | Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to 39 | be consistent then. 40 | EnforcedStyle: braces_for_chaining 41 | Style/ClassAndModuleChildren: 42 | Description: Compact style reduces the required amount of indentation. 43 | EnforcedStyle: compact 44 | Style/EmptyElse: 45 | Description: Enforce against empty else clauses, but allow `nil` for clarity. 46 | EnforcedStyle: empty 47 | Style/FormatString: 48 | Description: Following the main puppet project's style, prefer the % format format. 49 | EnforcedStyle: percent 50 | Style/FormatStringToken: 51 | Description: Following the main puppet project's style, prefer the simpler template 52 | tokens over annotated ones. 53 | EnforcedStyle: template 54 | Style/Lambda: 55 | Description: Prefer the keyword for easier discoverability. 56 | EnforcedStyle: literal 57 | Style/RegexpLiteral: 58 | Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 59 | EnforcedStyle: percent_r 60 | Style/TernaryParentheses: 61 | Description: Checks for use of parentheses around ternary conditions. Enforce parentheses 62 | on complex expressions for better readability, but seriously consider breaking 63 | it up. 64 | EnforcedStyle: require_parentheses_when_complex 65 | Style/TrailingCommaInArguments: 66 | Description: Prefer always trailing comma on multiline argument lists. This makes 67 | diffs, and re-ordering nicer. 68 | EnforcedStyleForMultiline: comma 69 | Style/TrailingCommaInArrayLiteral: 70 | Description: Prefer always trailing comma on multiline literals. This makes diffs, 71 | and re-ordering nicer. 72 | EnforcedStyleForMultiline: comma 73 | Style/SymbolArray: 74 | Description: Using percent style obscures symbolic intent of array's contents. 75 | EnforcedStyle: brackets 76 | RSpec/MessageSpies: 77 | EnforcedStyle: receive 78 | Style/Documentation: 79 | Exclude: 80 | - lib/puppet/parser/functions/**/* 81 | - spec/**/* 82 | Style/WordArray: 83 | EnforcedStyle: brackets 84 | Performance/AncestorsInclude: 85 | Enabled: true 86 | Performance/BigDecimalWithNumericArgument: 87 | Enabled: true 88 | Performance/BlockGivenWithExplicitBlock: 89 | Enabled: true 90 | Performance/CaseWhenSplat: 91 | Enabled: true 92 | Performance/ConstantRegexp: 93 | Enabled: true 94 | Performance/MethodObjectAsBlock: 95 | Enabled: true 96 | Performance/RedundantSortBlock: 97 | Enabled: true 98 | Performance/RedundantStringChars: 99 | Enabled: true 100 | Performance/ReverseFirst: 101 | Enabled: true 102 | Performance/SortReverse: 103 | Enabled: true 104 | Performance/Squeeze: 105 | Enabled: true 106 | Performance/StringInclude: 107 | Enabled: true 108 | Performance/Sum: 109 | Enabled: true 110 | Style/CollectionMethods: 111 | Enabled: true 112 | Style/MethodCalledOnDoEndBlock: 113 | Enabled: true 114 | Style/StringMethods: 115 | Enabled: true 116 | Bundler/GemFilename: 117 | Enabled: false 118 | Bundler/InsecureProtocolSource: 119 | Enabled: false 120 | Capybara/CurrentPathExpectation: 121 | Enabled: false 122 | Capybara/VisibilityMatcher: 123 | Enabled: false 124 | Gemspec/DuplicatedAssignment: 125 | Enabled: false 126 | Gemspec/OrderedDependencies: 127 | Enabled: false 128 | Gemspec/RequiredRubyVersion: 129 | Enabled: false 130 | Gemspec/RubyVersionGlobalsUsage: 131 | Enabled: false 132 | Layout/ArgumentAlignment: 133 | Enabled: false 134 | Layout/BeginEndAlignment: 135 | Enabled: false 136 | Layout/ClosingHeredocIndentation: 137 | Enabled: false 138 | Layout/EmptyComment: 139 | Enabled: false 140 | Layout/EmptyLineAfterGuardClause: 141 | Enabled: false 142 | Layout/EmptyLinesAroundArguments: 143 | Enabled: false 144 | Layout/EmptyLinesAroundAttributeAccessor: 145 | Enabled: false 146 | Layout/EndOfLine: 147 | Enabled: false 148 | Layout/FirstArgumentIndentation: 149 | Enabled: false 150 | Layout/HashAlignment: 151 | Enabled: false 152 | Layout/HeredocIndentation: 153 | Enabled: false 154 | Layout/LeadingEmptyLines: 155 | Enabled: false 156 | Layout/SpaceAroundMethodCallOperator: 157 | Enabled: false 158 | Layout/SpaceInsideArrayLiteralBrackets: 159 | Enabled: false 160 | Layout/SpaceInsideReferenceBrackets: 161 | Enabled: false 162 | Lint/BigDecimalNew: 163 | Enabled: false 164 | Lint/BooleanSymbol: 165 | Enabled: false 166 | Lint/ConstantDefinitionInBlock: 167 | Enabled: false 168 | Lint/DeprecatedOpenSSLConstant: 169 | Enabled: false 170 | Lint/DisjunctiveAssignmentInConstructor: 171 | Enabled: false 172 | Lint/DuplicateElsifCondition: 173 | Enabled: false 174 | Lint/DuplicateRequire: 175 | Enabled: false 176 | Lint/DuplicateRescueException: 177 | Enabled: false 178 | Lint/EmptyConditionalBody: 179 | Enabled: false 180 | Lint/EmptyFile: 181 | Enabled: false 182 | Lint/ErbNewArguments: 183 | Enabled: false 184 | Lint/FloatComparison: 185 | Enabled: false 186 | Lint/HashCompareByIdentity: 187 | Enabled: false 188 | Lint/IdentityComparison: 189 | Enabled: false 190 | Lint/InterpolationCheck: 191 | Enabled: false 192 | Lint/MissingCopEnableDirective: 193 | Enabled: false 194 | Lint/MixedRegexpCaptureTypes: 195 | Enabled: false 196 | Lint/NestedPercentLiteral: 197 | Enabled: false 198 | Lint/NonDeterministicRequireOrder: 199 | Enabled: false 200 | Lint/OrderedMagicComments: 201 | Enabled: false 202 | Lint/OutOfRangeRegexpRef: 203 | Enabled: false 204 | Lint/RaiseException: 205 | Enabled: false 206 | Lint/RedundantCopEnableDirective: 207 | Enabled: false 208 | Lint/RedundantRequireStatement: 209 | Enabled: false 210 | Lint/RedundantSafeNavigation: 211 | Enabled: false 212 | Lint/RedundantWithIndex: 213 | Enabled: false 214 | Lint/RedundantWithObject: 215 | Enabled: false 216 | Lint/RegexpAsCondition: 217 | Enabled: false 218 | Lint/ReturnInVoidContext: 219 | Enabled: false 220 | Lint/SafeNavigationConsistency: 221 | Enabled: false 222 | Lint/SafeNavigationWithEmpty: 223 | Enabled: false 224 | Lint/SelfAssignment: 225 | Enabled: false 226 | Lint/SendWithMixinArgument: 227 | Enabled: false 228 | Lint/ShadowedArgument: 229 | Enabled: false 230 | Lint/StructNewOverride: 231 | Enabled: false 232 | Lint/ToJSON: 233 | Enabled: false 234 | Lint/TopLevelReturnWithArgument: 235 | Enabled: false 236 | Lint/TrailingCommaInAttributeDeclaration: 237 | Enabled: false 238 | Lint/UnreachableLoop: 239 | Enabled: false 240 | Lint/UriEscapeUnescape: 241 | Enabled: false 242 | Lint/UriRegexp: 243 | Enabled: false 244 | Lint/UselessMethodDefinition: 245 | Enabled: false 246 | Lint/UselessTimes: 247 | Enabled: false 248 | Metrics/AbcSize: 249 | Enabled: false 250 | Metrics/BlockLength: 251 | Enabled: false 252 | Metrics/BlockNesting: 253 | Enabled: false 254 | Metrics/ClassLength: 255 | Enabled: false 256 | Metrics/CyclomaticComplexity: 257 | Enabled: false 258 | Metrics/MethodLength: 259 | Enabled: false 260 | Metrics/ModuleLength: 261 | Enabled: false 262 | Metrics/ParameterLists: 263 | Enabled: false 264 | Metrics/PerceivedComplexity: 265 | Enabled: false 266 | Migration/DepartmentName: 267 | Enabled: false 268 | Naming/AccessorMethodName: 269 | Enabled: false 270 | Naming/BlockParameterName: 271 | Enabled: false 272 | Naming/HeredocDelimiterCase: 273 | Enabled: false 274 | Naming/HeredocDelimiterNaming: 275 | Enabled: false 276 | Naming/MemoizedInstanceVariableName: 277 | Enabled: false 278 | Naming/MethodParameterName: 279 | Enabled: false 280 | Naming/RescuedExceptionsVariableName: 281 | Enabled: false 282 | Naming/VariableNumber: 283 | Enabled: false 284 | Performance/BindCall: 285 | Enabled: false 286 | Performance/DeletePrefix: 287 | Enabled: false 288 | Performance/DeleteSuffix: 289 | Enabled: false 290 | Performance/InefficientHashSearch: 291 | Enabled: false 292 | Performance/UnfreezeString: 293 | Enabled: false 294 | Performance/UriDefaultParser: 295 | Enabled: false 296 | RSpec/Be: 297 | Enabled: false 298 | RSpec/Capybara/FeatureMethods: 299 | Enabled: false 300 | RSpec/ContainExactly: 301 | Enabled: false 302 | RSpec/ContextMethod: 303 | Enabled: false 304 | RSpec/ContextWording: 305 | Enabled: false 306 | RSpec/DescribeClass: 307 | Enabled: false 308 | RSpec/EmptyHook: 309 | Enabled: false 310 | RSpec/EmptyLineAfterExample: 311 | Enabled: false 312 | RSpec/EmptyLineAfterExampleGroup: 313 | Enabled: false 314 | RSpec/EmptyLineAfterHook: 315 | Enabled: false 316 | RSpec/ExampleLength: 317 | Enabled: false 318 | RSpec/ExampleWithoutDescription: 319 | Enabled: false 320 | RSpec/ExpectChange: 321 | Enabled: false 322 | RSpec/ExpectInHook: 323 | Enabled: false 324 | RSpec/FactoryBot/AttributeDefinedStatically: 325 | Enabled: false 326 | RSpec/FactoryBot/CreateList: 327 | Enabled: false 328 | RSpec/FactoryBot/FactoryClassName: 329 | Enabled: false 330 | RSpec/HooksBeforeExamples: 331 | Enabled: false 332 | RSpec/ImplicitBlockExpectation: 333 | Enabled: false 334 | RSpec/ImplicitSubject: 335 | Enabled: false 336 | RSpec/LeakyConstantDeclaration: 337 | Enabled: false 338 | RSpec/LetBeforeExamples: 339 | Enabled: false 340 | RSpec/MatchArray: 341 | Enabled: false 342 | RSpec/MissingExampleGroupArgument: 343 | Enabled: false 344 | RSpec/MultipleExpectations: 345 | Enabled: false 346 | RSpec/MultipleMemoizedHelpers: 347 | Enabled: false 348 | RSpec/MultipleSubjects: 349 | Enabled: false 350 | RSpec/NestedGroups: 351 | Enabled: false 352 | RSpec/PredicateMatcher: 353 | Enabled: false 354 | RSpec/ReceiveCounts: 355 | Enabled: false 356 | RSpec/ReceiveNever: 357 | Enabled: false 358 | RSpec/RepeatedExampleGroupBody: 359 | Enabled: false 360 | RSpec/RepeatedExampleGroupDescription: 361 | Enabled: false 362 | RSpec/RepeatedIncludeExample: 363 | Enabled: false 364 | RSpec/ReturnFromStub: 365 | Enabled: false 366 | RSpec/SharedExamples: 367 | Enabled: false 368 | RSpec/StubbedMock: 369 | Enabled: false 370 | RSpec/UnspecifiedException: 371 | Enabled: false 372 | RSpec/VariableDefinition: 373 | Enabled: false 374 | RSpec/VoidExpect: 375 | Enabled: false 376 | RSpec/Yield: 377 | Enabled: false 378 | Security/Open: 379 | Enabled: false 380 | Style/AccessModifierDeclarations: 381 | Enabled: false 382 | Style/AccessorGrouping: 383 | Enabled: false 384 | Style/BisectedAttrAccessor: 385 | Enabled: false 386 | Style/CaseLikeIf: 387 | Enabled: false 388 | Style/ClassEqualityComparison: 389 | Enabled: false 390 | Style/ColonMethodDefinition: 391 | Enabled: false 392 | Style/CombinableLoops: 393 | Enabled: false 394 | Style/CommentedKeyword: 395 | Enabled: false 396 | Style/Dir: 397 | Enabled: false 398 | Style/DoubleCopDisableDirective: 399 | Enabled: false 400 | Style/EmptyBlockParameter: 401 | Enabled: false 402 | Style/EmptyLambdaParameter: 403 | Enabled: false 404 | Style/Encoding: 405 | Enabled: false 406 | Style/EvalWithLocation: 407 | Enabled: false 408 | Style/ExpandPathArguments: 409 | Enabled: false 410 | Style/ExplicitBlockArgument: 411 | Enabled: false 412 | Style/ExponentialNotation: 413 | Enabled: false 414 | Style/FloatDivision: 415 | Enabled: false 416 | Style/FrozenStringLiteralComment: 417 | Enabled: false 418 | Style/GlobalStdStream: 419 | Enabled: false 420 | Style/HashAsLastArrayItem: 421 | Enabled: false 422 | Style/HashLikeCase: 423 | Enabled: false 424 | Style/HashTransformKeys: 425 | Enabled: false 426 | Style/HashTransformValues: 427 | Enabled: false 428 | Style/IfUnlessModifier: 429 | Enabled: false 430 | Style/KeywordParametersOrder: 431 | Enabled: false 432 | Style/MinMax: 433 | Enabled: false 434 | Style/MixinUsage: 435 | Enabled: false 436 | Style/MultilineWhenThen: 437 | Enabled: false 438 | Style/NegatedUnless: 439 | Enabled: false 440 | Style/NumericPredicate: 441 | Enabled: false 442 | Style/OptionalBooleanParameter: 443 | Enabled: false 444 | Style/OrAssignment: 445 | Enabled: false 446 | Style/RandomWithOffset: 447 | Enabled: false 448 | Style/RedundantAssignment: 449 | Enabled: false 450 | Style/RedundantCondition: 451 | Enabled: false 452 | Style/RedundantConditional: 453 | Enabled: false 454 | Style/RedundantFetchBlock: 455 | Enabled: false 456 | Style/RedundantFileExtensionInRequire: 457 | Enabled: false 458 | Style/RedundantRegexpCharacterClass: 459 | Enabled: false 460 | Style/RedundantRegexpEscape: 461 | Enabled: false 462 | Style/RedundantSelfAssignment: 463 | Enabled: false 464 | Style/RedundantSort: 465 | Enabled: false 466 | Style/RescueStandardError: 467 | Enabled: false 468 | Style/SingleArgumentDig: 469 | Enabled: false 470 | Style/SlicingWithRange: 471 | Enabled: false 472 | Style/SoleNestedConditional: 473 | Enabled: false 474 | Style/StderrPuts: 475 | Enabled: false 476 | Style/StringConcatenation: 477 | Enabled: false 478 | Style/Strip: 479 | Enabled: false 480 | Style/SymbolProc: 481 | Enabled: false 482 | Style/TrailingBodyOnClass: 483 | Enabled: false 484 | Style/TrailingBodyOnMethodDefinition: 485 | Enabled: false 486 | Style/TrailingBodyOnModule: 487 | Enabled: false 488 | Style/TrailingCommaInHashLiteral: 489 | Enabled: false 490 | Style/TrailingMethodEndStatement: 491 | Enabled: false 492 | Style/UnpackFirst: 493 | Enabled: false 494 | Capybara/MatchStyle: 495 | Enabled: false 496 | Capybara/NegationMatcher: 497 | Enabled: false 498 | Capybara/SpecificActions: 499 | Enabled: false 500 | Capybara/SpecificFinders: 501 | Enabled: false 502 | Capybara/SpecificMatcher: 503 | Enabled: false 504 | Gemspec/DeprecatedAttributeAssignment: 505 | Enabled: false 506 | Gemspec/DevelopmentDependencies: 507 | Enabled: false 508 | Gemspec/RequireMFA: 509 | Enabled: false 510 | Layout/LineContinuationLeadingSpace: 511 | Enabled: false 512 | Layout/LineContinuationSpacing: 513 | Enabled: false 514 | Layout/LineEndStringConcatenationIndentation: 515 | Enabled: false 516 | Layout/SpaceBeforeBrackets: 517 | Enabled: false 518 | Lint/AmbiguousAssignment: 519 | Enabled: false 520 | Lint/AmbiguousOperatorPrecedence: 521 | Enabled: false 522 | Lint/AmbiguousRange: 523 | Enabled: false 524 | Lint/ConstantOverwrittenInRescue: 525 | Enabled: false 526 | Lint/DeprecatedConstants: 527 | Enabled: false 528 | Lint/DuplicateBranch: 529 | Enabled: false 530 | Lint/DuplicateMagicComment: 531 | Enabled: false 532 | Lint/DuplicateMatchPattern: 533 | Enabled: false 534 | Lint/DuplicateRegexpCharacterClassElement: 535 | Enabled: false 536 | Lint/EmptyBlock: 537 | Enabled: false 538 | Lint/EmptyClass: 539 | Enabled: false 540 | Lint/EmptyInPattern: 541 | Enabled: false 542 | Lint/IncompatibleIoSelectWithFiberScheduler: 543 | Enabled: false 544 | Lint/LambdaWithoutLiteralBlock: 545 | Enabled: false 546 | Lint/NoReturnInBeginEndBlocks: 547 | Enabled: false 548 | Lint/NonAtomicFileOperation: 549 | Enabled: false 550 | Lint/NumberedParameterAssignment: 551 | Enabled: false 552 | Lint/OrAssignmentToConstant: 553 | Enabled: false 554 | Lint/RedundantDirGlobSort: 555 | Enabled: false 556 | Lint/RefinementImportMethods: 557 | Enabled: false 558 | Lint/RequireRangeParentheses: 559 | Enabled: false 560 | Lint/RequireRelativeSelfPath: 561 | Enabled: false 562 | Lint/SymbolConversion: 563 | Enabled: false 564 | Lint/ToEnumArguments: 565 | Enabled: false 566 | Lint/TripleQuotes: 567 | Enabled: false 568 | Lint/UnexpectedBlockArity: 569 | Enabled: false 570 | Lint/UnmodifiedReduceAccumulator: 571 | Enabled: false 572 | Lint/UselessRescue: 573 | Enabled: false 574 | Lint/UselessRuby2Keywords: 575 | Enabled: false 576 | Metrics/CollectionLiteralLength: 577 | Enabled: false 578 | Naming/BlockForwarding: 579 | Enabled: false 580 | Performance/CollectionLiteralInLoop: 581 | Enabled: false 582 | Performance/ConcurrentMonotonicTime: 583 | Enabled: false 584 | Performance/MapCompact: 585 | Enabled: false 586 | Performance/RedundantEqualityComparisonBlock: 587 | Enabled: false 588 | Performance/RedundantSplitRegexpArgument: 589 | Enabled: false 590 | Performance/StringIdentifierArgument: 591 | Enabled: false 592 | RSpec/BeEq: 593 | Enabled: false 594 | RSpec/BeNil: 595 | Enabled: false 596 | RSpec/ChangeByZero: 597 | Enabled: false 598 | RSpec/ClassCheck: 599 | Enabled: false 600 | RSpec/DuplicatedMetadata: 601 | Enabled: false 602 | RSpec/ExcessiveDocstringSpacing: 603 | Enabled: false 604 | RSpec/FactoryBot/ConsistentParenthesesStyle: 605 | Enabled: false 606 | RSpec/FactoryBot/FactoryNameStyle: 607 | Enabled: false 608 | RSpec/FactoryBot/SyntaxMethods: 609 | Enabled: false 610 | RSpec/IdenticalEqualityAssertion: 611 | Enabled: false 612 | RSpec/NoExpectationExample: 613 | Enabled: false 614 | RSpec/PendingWithoutReason: 615 | Enabled: false 616 | RSpec/Rails/AvoidSetupHook: 617 | Enabled: false 618 | RSpec/Rails/HaveHttpStatus: 619 | Enabled: false 620 | RSpec/Rails/InferredSpecType: 621 | Enabled: false 622 | RSpec/Rails/MinitestAssertions: 623 | Enabled: false 624 | RSpec/Rails/TravelAround: 625 | Enabled: false 626 | RSpec/RedundantAround: 627 | Enabled: false 628 | RSpec/SkipBlockInsideExample: 629 | Enabled: false 630 | RSpec/SortMetadata: 631 | Enabled: false 632 | RSpec/SubjectDeclaration: 633 | Enabled: false 634 | RSpec/VerifiedDoubleReference: 635 | Enabled: false 636 | Security/CompoundHash: 637 | Enabled: false 638 | Security/IoMethods: 639 | Enabled: false 640 | Style/ArgumentsForwarding: 641 | Enabled: false 642 | Style/ArrayIntersect: 643 | Enabled: false 644 | Style/CollectionCompact: 645 | Enabled: false 646 | Style/ComparableClamp: 647 | Enabled: false 648 | Style/ConcatArrayLiterals: 649 | Enabled: false 650 | Style/DataInheritance: 651 | Enabled: false 652 | Style/DirEmpty: 653 | Enabled: false 654 | Style/DocumentDynamicEvalDefinition: 655 | Enabled: false 656 | Style/EmptyHeredoc: 657 | Enabled: false 658 | Style/EndlessMethod: 659 | Enabled: false 660 | Style/EnvHome: 661 | Enabled: false 662 | Style/FetchEnvVar: 663 | Enabled: false 664 | Style/FileEmpty: 665 | Enabled: false 666 | Style/FileRead: 667 | Enabled: false 668 | Style/FileWrite: 669 | Enabled: false 670 | Style/HashConversion: 671 | Enabled: false 672 | Style/HashExcept: 673 | Enabled: false 674 | Style/IfWithBooleanLiteralBranches: 675 | Enabled: false 676 | Style/InPatternThen: 677 | Enabled: false 678 | Style/MagicCommentFormat: 679 | Enabled: false 680 | Style/MapCompactWithConditionalBlock: 681 | Enabled: false 682 | Style/MapToHash: 683 | Enabled: false 684 | Style/MapToSet: 685 | Enabled: false 686 | Style/MinMaxComparison: 687 | Enabled: false 688 | Style/MultilineInPatternThen: 689 | Enabled: false 690 | Style/NegatedIfElseCondition: 691 | Enabled: false 692 | Style/NestedFileDirname: 693 | Enabled: false 694 | Style/NilLambda: 695 | Enabled: false 696 | Style/NumberedParameters: 697 | Enabled: false 698 | Style/NumberedParametersLimit: 699 | Enabled: false 700 | Style/ObjectThen: 701 | Enabled: false 702 | Style/OpenStructUse: 703 | Enabled: false 704 | Style/OperatorMethodCall: 705 | Enabled: false 706 | Style/QuotedSymbols: 707 | Enabled: false 708 | Style/RedundantArgument: 709 | Enabled: false 710 | Style/RedundantConstantBase: 711 | Enabled: false 712 | Style/RedundantDoubleSplatHashBraces: 713 | Enabled: false 714 | Style/RedundantEach: 715 | Enabled: false 716 | Style/RedundantHeredocDelimiterQuotes: 717 | Enabled: false 718 | Style/RedundantInitialize: 719 | Enabled: false 720 | Style/RedundantLineContinuation: 721 | Enabled: false 722 | Style/RedundantSelfAssignmentBranch: 723 | Enabled: false 724 | Style/RedundantStringEscape: 725 | Enabled: false 726 | Style/SelectByRegexp: 727 | Enabled: false 728 | Style/StringChars: 729 | Enabled: false 730 | Style/SwapValues: 731 | Enabled: false 732 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2023-11-28 06:40:08 UTC using RuboCop version 1.48.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 9 10 | # Configuration parameters: EnforcedStyle, IgnoreSharedExamples. 11 | # SupportedStyles: always, named_only 12 | RSpec/NamedSubject: 13 | Exclude: 14 | - 'spec/defines/value_spec.rb' 15 | -------------------------------------------------------------------------------- /.sync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ".gitlab-ci.yml": 3 | delete: true 4 | appveyor.yml: 5 | delete: true 6 | .rubocop.yml: 7 | include_todos: true 8 | 9 | 10 | spec/spec_helper.rb: 11 | mock_with: ":rspec" 12 | coverage_report: true 13 | .gitpod.Dockerfile: 14 | unmanaged: false 15 | .gitpod.yml: 16 | .github/workflows/auto_release.yml: 17 | unmanaged: false 18 | .github/workflows/ci.yml: 19 | unmanaged: false 20 | .github/workflows/nightly.yml: 21 | unmanaged: false 22 | .github/workflows/release.yml: 23 | unmanaged: false 24 | .travis.yml: 25 | delete: true 26 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "puppet.puppet-vscode", 4 | "Shopify.ruby-lsp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --markup markdown 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | All notable changes to this project will be documented in this file. 5 | 6 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org). 7 | 8 | ## [v5.0.3](https://github.com/puppetlabs/puppetlabs-registry/tree/v5.0.3) - 2025-02-04 9 | 10 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v5.0.2...v5.0.3) 11 | 12 | ### Fixed 13 | 14 | - (CAT-2212) Remove legacy facts [#312](https://github.com/puppetlabs/puppetlabs-registry/pull/312) ([amitkarsale](https://github.com/amitkarsale)) 15 | 16 | ## [v5.0.2](https://github.com/puppetlabs/puppetlabs-registry/tree/v5.0.2) - 2024-12-17 17 | 18 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v5.0.1...v5.0.2) 19 | 20 | ### Fixed 21 | 22 | - (CAT-2180) Upgrade rexml to address CVE-2024-49761 [#310](https://github.com/puppetlabs/puppetlabs-registry/pull/310) ([amitkarsale](https://github.com/amitkarsale)) 23 | 24 | ## [v5.0.1](https://github.com/puppetlabs/puppetlabs-registry/tree/v5.0.1) - 2023-06-20 25 | 26 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v5.0.0...v5.0.1) 27 | 28 | ### Fixed 29 | 30 | - (MODULES-11424) Fix requirement method [#287](https://github.com/puppetlabs/puppetlabs-registry/pull/287) ([Clebam](https://github.com/Clebam)) 31 | 32 | ## [v5.0.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v5.0.0) - 2023-04-05 33 | 34 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v4.1.2...v5.0.0) 35 | 36 | ### Changed 37 | 38 | - (CONT-796) Puppet 8 support / Drop Puppet 6 support [#278](https://github.com/puppetlabs/puppetlabs-registry/pull/278) ([LukasAud](https://github.com/LukasAud)) 39 | 40 | ## [v4.1.2](https://github.com/puppetlabs/puppetlabs-registry/tree/v4.1.2) - 2023-03-23 41 | 42 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v4.1.1...v4.1.2) 43 | 44 | ### Fixed 45 | 46 | - (CONT-362) Syntax update [#273](https://github.com/puppetlabs/puppetlabs-registry/pull/273) ([LukasAud](https://github.com/LukasAud)) 47 | 48 | ## [v4.1.1](https://github.com/puppetlabs/puppetlabs-registry/tree/v4.1.1) - 2022-10-03 49 | 50 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v4.1.0...v4.1.1) 51 | 52 | ### Fixed 53 | 54 | - (MAINT) Dropped support for Windows(7,8, 2008 Server and 2008 R2 Server) [#267](https://github.com/puppetlabs/puppetlabs-registry/pull/267) ([jordanbreen28](https://github.com/jordanbreen28)) 55 | 56 | ## [v4.1.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v4.1.0) - 2022-06-06 57 | 58 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v4.0.1...v4.1.0) 59 | 60 | ### Added 61 | 62 | - pdksync - (FM-8922) - Add Support for Windows 2022 [#259](https://github.com/puppetlabs/puppetlabs-registry/pull/259) ([david22swan](https://github.com/david22swan)) 63 | 64 | ## [v4.0.1](https://github.com/puppetlabs/puppetlabs-registry/tree/v4.0.1) - 2021-08-23 65 | 66 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v4.0.0...v4.0.1) 67 | 68 | ### Fixed 69 | 70 | - Add possibility to produce a detailed error message [#254](https://github.com/puppetlabs/puppetlabs-registry/pull/254) ([reidmv](https://github.com/reidmv)) 71 | 72 | ## [v4.0.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v4.0.0) - 2021-03-01 73 | 74 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v3.2.0...v4.0.0) 75 | 76 | ### Changed 77 | 78 | - pdksync - Remove Puppet 5 from testing and bump minimal version to 6.0.0 [#236](https://github.com/puppetlabs/puppetlabs-registry/pull/236) ([carabasdaniel](https://github.com/carabasdaniel)) 79 | 80 | ## [v3.2.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v3.2.0) - 2020-12-08 81 | 82 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v3.1.1...v3.2.0) 83 | 84 | ### Added 85 | 86 | - pdksync - (feat) Add support for Puppet 7 [#231](https://github.com/puppetlabs/puppetlabs-registry/pull/231) ([daianamezdrea](https://github.com/daianamezdrea)) 87 | 88 | ## [v3.1.1](https://github.com/puppetlabs/puppetlabs-registry/tree/v3.1.1) - 2020-08-12 89 | 90 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v3.1.0...v3.1.1) 91 | 92 | ### Added 93 | 94 | - pdksync - (IAC-973) - Update travis/appveyor to run on new default branch `main` [#217](https://github.com/puppetlabs/puppetlabs-registry/pull/217) ([david22swan](https://github.com/david22swan)) 95 | 96 | ### Fixed 97 | 98 | - (IAC-967) Puppet 7 compatibility fix: null termination for strings [#216](https://github.com/puppetlabs/puppetlabs-registry/pull/216) ([sanfrancrisko](https://github.com/sanfrancrisko)) 99 | 100 | ## [v3.1.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v3.1.0) - 2019-12-10 101 | 102 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/v3.0.0...v3.1.0) 103 | 104 | ### Added 105 | 106 | - (FM-8190) convert module to litmus [#190](https://github.com/puppetlabs/puppetlabs-registry/pull/190) ([DavidS](https://github.com/DavidS)) 107 | 108 | ## [v3.0.0](https://github.com/puppetlabs/puppetlabs-registry/tree/v3.0.0) - 2019-10-17 109 | 110 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/2.1.0...v3.0.0) 111 | 112 | ### Added 113 | 114 | - (FM-7693) Add Windows Server 2019 [#174](https://github.com/puppetlabs/puppetlabs-registry/pull/174) ([glennsarti](https://github.com/glennsarti)) 115 | 116 | ### Fixed 117 | 118 | - (MODULES-5625) Fail on empty strings in REG_MULTI_SZ [#173](https://github.com/puppetlabs/puppetlabs-registry/pull/173) ([glennsarti](https://github.com/glennsarti)) 119 | 120 | ## [2.1.0](https://github.com/puppetlabs/puppetlabs-registry/tree/2.1.0) - 2018-10-08 121 | 122 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/2.0.2...2.1.0) 123 | 124 | ## [2.0.2](https://github.com/puppetlabs/puppetlabs-registry/tree/2.0.2) - 2018-08-06 125 | 126 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/2.0.1...2.0.2) 127 | 128 | ### Added 129 | 130 | - (MODULES-4271) Add Server 2016 and Windows 10 to metadata [#160](https://github.com/puppetlabs/puppetlabs-registry/pull/160) ([glennsarti](https://github.com/glennsarti)) 131 | - (MODULES-6744) Add testmode switcher [#158](https://github.com/puppetlabs/puppetlabs-registry/pull/158) ([jpogran](https://github.com/jpogran)) 132 | 133 | ### Fixed 134 | 135 | - (MODULES-6818) Fix types to no longer use unsupported proc title patterns [#159](https://github.com/puppetlabs/puppetlabs-registry/pull/159) ([treydock](https://github.com/treydock)) 136 | 137 | ## [2.0.1](https://github.com/puppetlabs/puppetlabs-registry/tree/2.0.1) - 2018-01-26 138 | 139 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/2.0.0...2.0.1) 140 | 141 | ### Fixed 142 | 143 | - (MODULES-6528) Fix registry::value defined type [#153](https://github.com/puppetlabs/puppetlabs-registry/pull/153) ([Iristyle](https://github.com/Iristyle)) 144 | 145 | ## [2.0.0](https://github.com/puppetlabs/puppetlabs-registry/tree/2.0.0) - 2018-01-25 146 | 147 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.1.4...2.0.0) 148 | 149 | ### Added 150 | 151 | - (MODULES-2957) Add support for backslashes in registry value name [#146](https://github.com/puppetlabs/puppetlabs-registry/pull/146) ([glennsarti](https://github.com/glennsarti)) 152 | - (MODULES-5144) Prep for puppet 5 [#133](https://github.com/puppetlabs/puppetlabs-registry/pull/133) ([hunner](https://github.com/hunner)) 153 | 154 | ### Fixed 155 | 156 | - (MODULES-2957) Fix registry_value tests [#143](https://github.com/puppetlabs/puppetlabs-registry/pull/143) ([glennsarti](https://github.com/glennsarti)) 157 | 158 | ## [1.1.4](https://github.com/puppetlabs/puppetlabs-registry/tree/1.1.4) - 2017-03-06 159 | 160 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.1.3...1.1.4) 161 | 162 | ### Added 163 | 164 | - (MODULES-4263) add blacksmith rake tasks [#121](https://github.com/puppetlabs/puppetlabs-registry/pull/121) ([eputnam](https://github.com/eputnam)) 165 | - (FM-4917) Rake / Beaker / Rspec compatibility [#98](https://github.com/puppetlabs/puppetlabs-registry/pull/98) ([ferventcoder](https://github.com/ferventcoder)) 166 | 167 | ### Fixed 168 | 169 | - (MODULES-4331) quoted UNSET string [#123](https://github.com/puppetlabs/puppetlabs-registry/pull/123) ([binford2k](https://github.com/binford2k)) 170 | - (maint) Fix the style of the registry::value parameters [#102](https://github.com/puppetlabs/puppetlabs-registry/pull/102) ([natemccurdy](https://github.com/natemccurdy)) 171 | 172 | ## [1.1.3](https://github.com/puppetlabs/puppetlabs-registry/tree/1.1.3) - 2015-12-07 173 | 174 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.1.2...1.1.3) 175 | 176 | ## [1.1.2](https://github.com/puppetlabs/puppetlabs-registry/tree/1.1.2) - 2015-08-17 177 | 178 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.1.1...1.1.2) 179 | 180 | ### Fixed 181 | 182 | - (MODULES-2409) Endian-ness incorrect for DWORD and QWORD [#95](https://github.com/puppetlabs/puppetlabs-registry/pull/95) ([Iristyle](https://github.com/Iristyle)) 183 | 184 | ## [1.1.1](https://github.com/puppetlabs/puppetlabs-registry/tree/1.1.1) - 2015-08-12 185 | 186 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.1.0...1.1.1) 187 | 188 | ### Added 189 | 190 | - (maint) add AppVeyor support [#87](https://github.com/puppetlabs/puppetlabs-registry/pull/87) ([Iristyle](https://github.com/Iristyle)) 191 | 192 | ### Fixed 193 | 194 | - (MODULES-1921) Ruby registry writes corrupt string [#93](https://github.com/puppetlabs/puppetlabs-registry/pull/93) ([Iristyle](https://github.com/Iristyle)) 195 | - (maint) fix registry_value provider spec fail [#90](https://github.com/puppetlabs/puppetlabs-registry/pull/90) ([Iristyle](https://github.com/Iristyle)) 196 | - (MODULES-2207) Gem restrictions for Older puppet versions [#89](https://github.com/puppetlabs/puppetlabs-registry/pull/89) ([ferventcoder](https://github.com/ferventcoder)) 197 | - (maint) Multiple node acceptance fixes [#79](https://github.com/puppetlabs/puppetlabs-registry/pull/79) ([Iristyle](https://github.com/Iristyle)) 198 | 199 | ## [1.1.0](https://github.com/puppetlabs/puppetlabs-registry/tree/1.1.0) - 2015-03-26 200 | 201 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.0.3...1.1.0) 202 | 203 | ### Fixed 204 | 205 | - Fix issue with Rakefile where require beaker fails on windows or when not installed [#74](https://github.com/puppetlabs/puppetlabs-registry/pull/74) ([cyberious](https://github.com/cyberious)) 206 | - Modify the way we install stdlib due to github rpc hangups [#71](https://github.com/puppetlabs/puppetlabs-registry/pull/71) ([cyberious](https://github.com/cyberious)) 207 | - Fix tolerate mixed case test regex [#69](https://github.com/puppetlabs/puppetlabs-registry/pull/69) ([cyberious](https://github.com/cyberious)) 208 | 209 | ## [1.0.3](https://github.com/puppetlabs/puppetlabs-registry/tree/1.0.3) - 2014-08-28 210 | 211 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.0.2...1.0.3) 212 | 213 | ### Added 214 | 215 | - (MODULES-1176) FFI module - allow to work on x86 / x64 [#55](https://github.com/puppetlabs/puppetlabs-registry/pull/55) ([Iristyle](https://github.com/Iristyle)) 216 | 217 | ### Fixed 218 | 219 | - (MODULES-1292) Don't try to apply a regex to a binary string [#62](https://github.com/puppetlabs/puppetlabs-registry/pull/62) ([joshcooper](https://github.com/joshcooper)) 220 | - Fix registry testing, remove dependency of master to enable both foss an... [#59](https://github.com/puppetlabs/puppetlabs-registry/pull/59) ([cyberious](https://github.com/cyberious)) 221 | 222 | ## [1.0.2](https://github.com/puppetlabs/puppetlabs-registry/tree/1.0.2) - 2014-07-15 223 | 224 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.0.1...1.0.2) 225 | 226 | ## [1.0.1](https://github.com/puppetlabs/puppetlabs-registry/tree/1.0.1) - 2014-07-07 227 | 228 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/1.0.0...1.0.1) 229 | 230 | ### Added 231 | 232 | - Add padding for single character [#48](https://github.com/puppetlabs/puppetlabs-registry/pull/48) ([cyberious](https://github.com/cyberious)) 233 | - Add lint tasks [#45](https://github.com/puppetlabs/puppetlabs-registry/pull/45) ([cyberious](https://github.com/cyberious)) 234 | 235 | ## [1.0.0](https://github.com/puppetlabs/puppetlabs-registry/tree/1.0.0) - 2014-03-03 236 | 237 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/0.1.1...1.0.0) 238 | 239 | ### Added 240 | 241 | - Add a license file. [#33](https://github.com/puppetlabs/puppetlabs-registry/pull/33) ([apenney](https://github.com/apenney)) 242 | - Add travis support and update specs for rspec 2.14 [#26](https://github.com/puppetlabs/puppetlabs-registry/pull/26) ([hunner](https://github.com/hunner)) 243 | 244 | ### Fixed 245 | 246 | - Fix acceptance tests when running on 32-bit version of 2003 [#22](https://github.com/puppetlabs/puppetlabs-registry/pull/22) ([joshcooper](https://github.com/joshcooper)) 247 | - (Maint) Fix unhandled exception working around #4248 [#19](https://github.com/puppetlabs/puppetlabs-registry/pull/19) ([jeffmccune](https://github.com/jeffmccune)) 248 | 249 | ## [0.1.1](https://github.com/puppetlabs/puppetlabs-registry/tree/0.1.1) - 2012-05-22 250 | 251 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/0.1.0...0.1.1) 252 | 253 | ### Fixed 254 | 255 | - (#14572) Fix management of the default value [#17](https://github.com/puppetlabs/puppetlabs-registry/pull/17) ([jeffmccune](https://github.com/jeffmccune)) 256 | 257 | ## [0.1.0](https://github.com/puppetlabs/puppetlabs-registry/tree/0.1.0) - 2012-05-16 258 | 259 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/0.0.1...0.1.0) 260 | 261 | ### Added 262 | 263 | - (#14529) Add registry::value defined type [#16](https://github.com/puppetlabs/puppetlabs-registry/pull/16) ([jeffmccune](https://github.com/jeffmccune)) 264 | - Separate the implementation of the type and provider [#11](https://github.com/puppetlabs/puppetlabs-registry/pull/11) ([jeffmccune](https://github.com/jeffmccune)) 265 | 266 | ### Fixed 267 | 268 | - Fix autorequire case sensitivity [#14](https://github.com/puppetlabs/puppetlabs-registry/pull/14) ([jeffmccune](https://github.com/jeffmccune)) 269 | 270 | ## [0.0.1](https://github.com/puppetlabs/puppetlabs-registry/tree/0.0.1) - 2012-05-04 271 | 272 | [Full Changelog](https://github.com/puppetlabs/puppetlabs-registry/compare/065d43d960080df2280407eeb933913dc7bf9919...0.0.1) 273 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Setting ownership to the modules team 2 | * @puppetlabs/modules 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Puppet modules 2 | 3 | Check out our [Contributing to Supported Modules Blog Post](https://puppetlabs.github.io/iac/docs/contributing_to_a_module.html) to find all the information that you will need. 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source ENV['GEM_SOURCE'] || 'https://rubygems.org' 2 | 3 | def location_for(place_or_version, fake_version = nil) 4 | git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} 5 | file_url_regex = %r{\Afile:\/\/(?.*)} 6 | 7 | if place_or_version && (git_url = place_or_version.match(git_url_regex)) 8 | [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact 9 | elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) 10 | ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] 11 | else 12 | [place_or_version, { require: false }] 13 | end 14 | end 15 | 16 | group :development do 17 | gem "json", '= 2.1.0', require: false if Gem::Requirement.create(['>= 2.5.0', '< 2.7.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 18 | gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 19 | gem "json", '= 2.5.1', require: false if Gem::Requirement.create(['>= 3.0.0', '< 3.0.5']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 20 | gem "json", '= 2.6.1', require: false if Gem::Requirement.create(['>= 3.1.0', '< 3.1.3']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 21 | gem "json", '= 2.6.3', require: false if Gem::Requirement.create(['>= 3.2.0', '< 4.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 22 | gem "racc", '~> 1.4.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 3.0.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 23 | gem "deep_merge", '~> 1.2.2', require: false 24 | gem "voxpupuli-puppet-lint-plugins", '~> 5.0', require: false 25 | gem "facterdb", '~> 2.1', require: false 26 | gem "metadata-json-lint", '~> 4.0', require: false 27 | gem "rspec-puppet-facts", '~> 4.0', require: false 28 | gem "dependency_checker", '~> 1.0.0', require: false 29 | gem "parallel_tests", '= 3.12.1', require: false 30 | gem "pry", '~> 0.10', require: false 31 | gem "simplecov-console", '~> 0.9', require: false 32 | gem "puppet-debugger", '~> 1.0', require: false 33 | gem "rubocop", '~> 1.50.0', require: false 34 | gem "rubocop-performance", '= 1.16.0', require: false 35 | gem "rubocop-rspec", '= 2.19.0', require: false 36 | gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] 37 | gem "rexml", '>= 3.3.9', require: false 38 | end 39 | group :development, :release_prep do 40 | gem "puppet-strings", '~> 4.0', require: false 41 | gem "puppetlabs_spec_helper", '~> 7.0', require: false 42 | end 43 | group :system_tests do 44 | gem "puppet_litmus", '~> 1.0', require: false, platforms: [:ruby, :x64_mingw] 45 | gem "CFPropertyList", '< 3.0.7', require: false, platforms: [:mswin, :mingw, :x64_mingw] 46 | gem "serverspec", '~> 2.41', require: false 47 | end 48 | 49 | puppet_version = ENV['PUPPET_GEM_VERSION'] 50 | facter_version = ENV['FACTER_GEM_VERSION'] 51 | hiera_version = ENV['HIERA_GEM_VERSION'] 52 | 53 | gems = {} 54 | 55 | gems['puppet'] = location_for(puppet_version) 56 | 57 | # If facter or hiera versions have been specified via the environment 58 | # variables 59 | 60 | gems['facter'] = location_for(facter_version) if facter_version 61 | gems['hiera'] = location_for(hiera_version) if hiera_version 62 | 63 | gems.each do |gem_name, gem_params| 64 | gem gem_name, *gem_params 65 | end 66 | 67 | # Evaluate Gemfile.local and ~/.gemfile if they exist 68 | extra_gemfiles = [ 69 | "#{__FILE__}.local", 70 | File.join(Dir.home, '.gemfile'), 71 | ] 72 | 73 | extra_gemfiles.each do |gemfile| 74 | if File.file?(gemfile) && File.readable?(gemfile) 75 | eval(File.read(gemfile), binding) 76 | end 77 | end 78 | # vim: syntax=ruby 79 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | ## 2.1.0 2 | ### Added 3 | - Updated module for Puppet 6 ([MODULES-7832](https://tickets.puppetlabs.com/browse/MODULES-7832)) 4 | 5 | ### Changed 6 | - Update module for PDK ([MODULES-7404](https://tickets.puppetlabs.com/browse/MODULES-7404)) 7 | 8 | ## [2.0.2] - 2018-08-08 9 | ### Added 10 | - Add Windows Server 2016 and Windows 10 as supported Operating Systems ([MODULES-4271](https://tickets.puppetlabs.com/browse/MODULES-4271)) 11 | 12 | ### Changed 13 | - Convert tests to use testmode switcher ([MODULES-6744](https://tickets.puppetlabs.com/browse/MODULES-6744)) 14 | 15 | ### Fixed 16 | - Fix types to no longer use unsupported proc title patterns ([MODULES-6818](https://tickets.puppetlabs.com/browse/MODULES-6818)) 17 | - Fix acceptance tests in server-agent scenarios ([FM-6934](https://tickets.puppetlabs.com/browse/FM-6934)) 18 | - Use case insensitive search when purging ([MODULES-7534](https://tickets.puppetlabs.com/browse/MODULES-7534)) 19 | 20 | ### Removed 21 | 22 | ## [2.0.1] - 2018-01-25 23 | ### Fixed 24 | - Fix the restrictive typing introduced for the registry::value defined type to once again allow numeric values to be specified for DWORD, QWORD and arrays for REG_MULTI_SZ values ([MODULES-6528](https://tickets.puppetlabs.com/browse/MODULES-6528)) 25 | 26 | ## [2.0.0] - 2018-01-24 27 | ### Added 28 | - Add support for Puppet 5 ([MODULES-5144](https://tickets.puppetlabs.com/browse/MODULES-5144)) 29 | 30 | ### Changed 31 | - Convert beaker tests to beaker rspec tests ([MODULES-5976](https://tickets.puppetlabs.com/browse/MODULES-5976)) 32 | 33 | #### Fixed 34 | - Ensure registry values that include a `\` as part of the name are valid and usable ([MODULES-2957](https://tickets.puppetlabs.com/browse/MODULES-2957)) 35 | 36 | ### Removed 37 | - **BREAKING:** Dropped support for Puppet 3 38 | 39 | ## [1.1.4] - 2017-03-06 40 | ### Added 41 | - Ability to manage keys and values in `HKEY_USERS` (`hku`) ([MODULES-3865](https://tickets.puppetlabs.com/browse/MODULES-3865)) 42 | 43 | ### Removed 44 | - Remove Windows Server 2003 from supported Operating System list 45 | 46 | #### Fixed 47 | - Use double quotes so $key is interpolated ([FM-5236](https://tickets.puppetlabs.com/browse/FM-5236)) 48 | - Fix WOW64 Constant Definition ([MODULES-3195](https://tickets.puppetlabs.com/browse/MODULES-3195)) 49 | - Fix UNSET no longer available as a bareword ([MODULES-4331](https://tickets.puppetlabs.com/browse/MODULES-4331)) 50 | 51 | ## [1.1.3] - 2015-12-08 52 | ### Added 53 | - Support of newer PE versions. 54 | 55 | ## [1.1.2] - 2015-08-13 56 | ### Added 57 | - Added tests to catch scenario 58 | 59 | ### Changed 60 | - Changed byte conversion to use pack instead 61 | 62 | ### Fixed 63 | - Fix critical bug when writing dword and qword values. 64 | - Fix the way we write dword and qword values [MODULES-2409](https://tickets.puppet.com/browse/MODULES-2409) 65 | 66 | ## [1.1.1] - 2015-08-12 [YANKED] 67 | ### Added 68 | - Puppet Enterprise 2015.2.0 to metadata 69 | 70 | ### Changed 71 | - Gemfile updates 72 | - Updated the logic used to convert to byte arrays 73 | 74 | ### Fixed 75 | - Fixed Ruby registry writes corrupt string ([MODULES-1921](https://tickets.puppet.com/browse/MODULES-1921)) 76 | - Fixed testcases 77 | 78 | ## [1.1.0] - 2015-03-24 79 | ### Fixes 80 | - Additional tests for purge_values 81 | - Use wide character registry APIs 82 | - Test Ruby Registry methods uncalled 83 | - Introduce Ruby 2.1.5 failing tests 84 | 85 | 86 | ## [1.0.3] - 2014-08-25 87 | ### Added 88 | - Added support for native x64 ruby and puppet 3.7 89 | 90 | ### Fixed 91 | - Fixed issues with non-leading-zero binary values in registry keys. 92 | 93 | ## [1.0.2] - 2014-07-15 94 | ### Added 95 | - Added the ability to uninstall and upgrade the module via the `puppet module` command 96 | 97 | ## [1.0.1] - 2014-05-20 98 | ### Fixed 99 | - Add zero padding to binary single character inputs 100 | 101 | ## [1.0.0] - 2014-03-04 102 | ### Added 103 | - Add license file 104 | 105 | ### Changed 106 | - Documentation updates 107 | 108 | ## [0.1.2] - 2013-08-01 109 | ### Added 110 | - Add geppetto project file 111 | 112 | ### Changed 113 | - Updated README and manifest documentation 114 | - Refactored code into PuppetX namespace 115 | - Only manage redirected keys on 64 bit systems 116 | - Only use /sysnative filesystem when available 117 | - Use class accessor method instead of class instance variable 118 | 119 | ### Fixed 120 | - Fixed unhandled exception when loading windows code on *nix 121 | 122 | ## [0.1.1] - 2012-05-21 123 | ### Fixed 124 | - Improve error handling when writing values 125 | - Fix management of the default value 126 | 127 | ## [0.1.0] - 2012-05-16 128 | ### Added 129 | - Initial release 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Puppet Module - puppetlabs-registry 2 | 3 | Copyright 2012 - 2017 Puppet, Inc. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # registry 2 | 3 | #### Table of Contents 4 | 5 | 1. [Overview - What is the registry module?](#overview) 6 | 2. [Module Description - What registry does and why it is useful](#module-description) 7 | 3. [Setup - The basics of getting started with registry](#setup) 8 | * [Beginning with registry](#beginning-with-registry) 9 | 4. [Usage - Configuration options and additional functionality](#usage) 10 | 5. [Reference](#reference) 11 | 6. [Limitations](#limitations) 12 | 7. [License](#license) 13 | 8. [Development - Guide for contributing to registry](#development) 14 | 15 | ## Overview 16 | 17 | This module supplies the types and providers you'll need to manage the Registry on your Windows nodes. 18 | 19 | ## Module Description 20 | 21 | The Registry is a hierarchical database built into Microsoft Windows. It stores settings and other information for the operating system and a wide range of applications. This module lets Puppet manage individual Registry keys and values, and provides a simplified way to manage Windows services. 22 | 23 | ## Setup 24 | 25 | This module must be installed on your Puppet server. For a complete list of supported operating systems, please take a look at our [metadata.json](https://github.com/puppetlabs/puppetlabs-registry/blob/main/metadata.json#L13). 26 | 27 | ### Beginning with registry 28 | 29 | Use the `registry_key` type to manage a single registry key: 30 | 31 | ``` puppet 32 | registry_key { 'HKLM\System\CurrentControlSet\Services\Puppet': 33 | ensure => present, 34 | } 35 | ``` 36 | 37 | ## Usage 38 | 39 | The registry module works mainly through two types: `registry_key` and `registry_value`. These types combine to let you specify a Registry container and its intended contents. 40 | 41 | ### Manage a single Registry value 42 | 43 | ``` puppet 44 | registry_value { 'HKLM\System\CurrentControlSet\Services\Puppet\Description': 45 | ensure => present, 46 | type => string, 47 | data => "The Puppet Agent service periodically manages your configuration", 48 | } 49 | ``` 50 | 51 | ### Manage a single Registry value with a backslash in the value name 52 | 53 | ``` puppet 54 | registry_value { 'HKLM\System\CurrentControlSet\Services\Puppet\\\ValueWithA\Backslash': 55 | ensure => present, 56 | type => string, 57 | data => "The Puppet Agent service periodically manages your configuration", 58 | } 59 | ``` 60 | 61 | ### Manage a single Registry value with a different resource title 62 | 63 | ``` puppet 64 | registry_value { 'PuppetDescription': 65 | path => 'HKLM\System\CurrentControlSet\Services\Puppet\Description', 66 | ensure => present, 67 | type => string, 68 | data => "The Puppet Agent service periodically manages your configuration", 69 | } 70 | ``` 71 | 72 | ### Manage a Registry value and its parent key in one declaration 73 | 74 | ``` puppet 75 | class myapp { 76 | registry::value { 'puppetserver': 77 | key => 'HKLM\Software\Vendor\PuppetLabs', 78 | data => 'puppet.puppet.com', 79 | } 80 | } 81 | ``` 82 | 83 | Puppet looks up the key 'HKLM\Software\Vendor\PuppetLabs' and makes sure it contains a value named 'puppetserver' containing the string 'puppet.puppet.com'. 84 | 85 | ### Set the default value for a key 86 | 87 | ``` puppet 88 | registry::value { 'Setting0': 89 | key  => 'HKLM\System\CurrentControlSet\Services\Puppet', 90 | value => '(default)', 91 | data  => "Hello World!", 92 | } 93 | ``` 94 | 95 | You can still add values in a string (or array) beyond the default, but you can only set one default value per key. 96 | 97 | 98 | ### Purge existing values 99 | 100 | By default, if a key includes additional values besides the ones you specify through this module, Puppet leaves those extra values in place. To change that, use the `purge_values => true` parameter of the `registry_key` resource. **Enabling this feature deletes any values in the key that are not managed by Puppet.** 101 | 102 | The `registry::purge_example` class provides a quick and easy way to see a demonstration of how this works. This example class has two modes of operation determined by the Facter fact `PURGE_EXAMPLE_MODE`: 'setup' and 'purge'. 103 | 104 | To run the demonstration, make sure the `registry::purge_example` class is included in your node catalog, then set an environment variable in PowerShell. This sets up a Registry key that contains six values. 105 | 106 | ``` powershell 107 | PS C:\> $env:FACTER_PURGE_EXAMPLE_MODE = 'setup' 108 | PS C:\> puppet agent --test 109 | 110 | notice: /Stage[main]/Registry::Purge_example/Registry_key[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge]/ensure: created 111 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value3]/ensure: created 112 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value2]/ensure: created 113 | notice: /Stage[main]/Registry::Purge_example/Registry_key[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\SubKey]/ensure: created 114 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value5]/ensure: created 115 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value6]/ensure: created 116 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\SubKey\Value1]/ensure: created 117 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value1]/ensure: created 118 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\SubKey\Value2]/ensure: created 119 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value4]/ensure: created 120 | notice: Finished catalog run in 0.14 seconds 121 | ``` 122 | 123 | Switching the mode to 'purge' causes the class to only manage three of the six `registry_value` resources. The other three are purged because they are not specifically declared in the manifest. 124 | Notice how `Value4`, `Value5` and `Value6` are being removed. 125 | 126 | ``` powershell 127 | PS C:\> $env:FACTER_PURGE_EXAMPLE_MODE = 'purge' 128 | PS C:\> puppet agent --test 129 | 130 | notice: /Registry_value[hklm\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value4]/ensure: removed 131 | notice: /Registry_value[hklm\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value6]/ensure: removed 132 | notice: /Registry_value[hklm\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value5]/ensure: removed 133 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value3]/data: data changed 'key3' to 'should not be purged' 134 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value2]/data: data changed '2' to '0' 135 | notice: /Stage[main]/Registry::Purge_example/Registry_value[HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge\Value1]/data: data changed '1' to '0' 136 | notice: Finished catalog run in 0.16 seconds 137 | ``` 138 | 139 | ### Manage Windows services 140 | 141 | The `registry::service` define manages entries in the Microsoft service control framework by automatically manipulating values in the key `HKLM\System\CurrentControlSet\Services\$name\`. 142 | 143 | This is an alternative approach to using INSTSRV.EXE [1](http://support.microsoft.com/kb/137890). 144 | 145 | ``` puppet 146 | registry::service { puppet: 147 | ensure => present, 148 | display_name => "Puppet Agent", 149 | description => "Periodically fetches and applies configurations from a Puppet Server.", 150 | command => 'C:\PuppetLabs\Puppet\service\daemon.bat', 151 | } 152 | ``` 153 | 154 | ## Reference 155 | For information on the classes and types, see the [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-registry/blob/main/REFERENCE.md) 156 | 157 | ## Limitations 158 | 159 | * Keys within `HKEY_LOCAL_MACHINE` (`hklm`), `HKEY_CLASSES_ROOT` (`hkcr`) or `HKEY_USERS` (`hku`) are supported. Other predefined root keys (e.g., `HKEY_CURRENT_USER`) are not currently supported. 160 | * Puppet doesn't recursively delete Registry keys. 161 | 162 | Please report any issues through our [Module Issue Tracker](https://tickets.puppet.com/browse/MODULES). 163 | 164 | ## License 165 | 166 | This codebase is licensed under the Apache2.0 licensing, however due to the nature of the codebase the open source dependencies may also use a combination of [AGPL](https://opensource.org/license/agpl-v3/), [BSD-2](https://opensource.org/license/bsd-2-clause/), [BSD-3](https://opensource.org/license/bsd-3-clause/), [GPL2.0](https://opensource.org/license/gpl-2-0/), [LGPL](https://opensource.org/license/lgpl-3-0/), [MIT](https://opensource.org/license/mit/) and [MPL](https://opensource.org/license/mpl-2-0/) Licensing. 167 | 168 | ## Development 169 | 170 | Puppet Inc modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can't access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. 171 | 172 | We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. 173 | 174 | If you would like to contribute to this module, please follow the rules in the [CONTRIBUTING.md](https://github.com/puppetlabs/puppetlabs-registry/blob/main/CONTRIBUTING.md). For more information, see our [module contribution guide.](https://puppet.com/docs/puppet/latest/contributing.html) 175 | 176 | ### Contributors 177 | 178 | To see who's already involved, see the [list of contributors.](https://github.com/puppetlabs/puppetlabs-registry/graphs/contributors) 179 | -------------------------------------------------------------------------------- /REFERENCE.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | 4 | 5 | ## Table of Contents 6 | 7 | ### Defined types 8 | 9 | * [`registry::service`](#registry--service): Defined resource type that manages service entries 10 | * [`registry::value`](#registry--value): High level abstraction on top of registry_key and registry_value resources 11 | 12 | ### Resource types 13 | 14 | * [`registry_key`](#registry_key): Manages registry keys on Windows 15 | * [`registry_value`](#registry_value): Manages registry values on Windows systems. 16 | 17 | ## Defined types 18 | 19 | ### `registry::service` 20 | 21 | Manages the values in the key HKLM\System\CurrentControlSet\Services\$name\ 22 | 23 | * **Note** This defined resource type manages service entries in the Microsoft service 24 | control framework by managing the appropriate registry keys and values. 25 | 26 | This is an alternative approach to using INSTSRV.EXE [1]. 27 | 28 | [1] http://support.microsoft.com/kb/137890 29 | 30 | #### Examples 31 | 32 | ##### Sample Usage: 33 | 34 | ```puppet 35 | registry::service { puppet: 36 | ensure => present, 37 | display_name => 'Puppet Agent', 38 | description => 'Periodically fetches and applies 39 | configurations from a Puppet Server.', 40 | command => 'C:\PuppetLabs\Puppet\service\daemon.bat', 41 | } 42 | ``` 43 | 44 | #### Parameters 45 | 46 | The following parameters are available in the `registry::service` defined type: 47 | 48 | * [`ensure`](#-registry--service--ensure) 49 | * [`display_name`](#-registry--service--display_name) 50 | * [`description`](#-registry--service--description) 51 | * [`command`](#-registry--service--command) 52 | * [`start`](#-registry--service--start) 53 | 54 | ##### `ensure` 55 | 56 | Data type: `Enum['present', 'absent', 'UNSET']` 57 | 58 | Ensures the presence or absence of a registry key. Valid values: 'present', 'absent', 'UNSET'. 59 | 60 | Default value: `'UNSET'` 61 | 62 | ##### `display_name` 63 | 64 | Data type: `String[1]` 65 | 66 | The Display Name of the service. Defaults to the title of the resource. 67 | 68 | Default value: `'UNSET'` 69 | 70 | ##### `description` 71 | 72 | Data type: `String[1]` 73 | 74 | A description of the service. String value set to 'UNSET' by default. 75 | 76 | Default value: `'UNSET'` 77 | 78 | ##### `command` 79 | 80 | Data type: `String[1]` 81 | 82 | The command to execute. Set to 'UNSET' by default. 83 | 84 | Default value: `'UNSET'` 85 | 86 | ##### `start` 87 | 88 | Data type: `Enum['automatic', 'manual', 'disabled', 'UNSET']` 89 | 90 | The starting mode of the service. (Note, the native service 91 | resource can also be used to manage this setting.) 92 | Valid values: 'automatic', 'manual', 'disabled' 93 | 94 | Default value: `'UNSET'` 95 | 96 | ### `registry::value` 97 | 98 | Actions: 99 | - Manage the parent key if not already managed. 100 | - Manage the value 101 | 102 | Requires: 103 | - Registry Module 104 | - Stdlib Module 105 | 106 | * **Note** This defined resource type provides a higher level of abstraction on top of 107 | the registry_key and registry_value resources. Using this defined resource 108 | type, you do not need to explicitly manage the parent key for a particular 109 | value. Puppet will automatically manage the parent key for you. 110 | 111 | #### Examples 112 | 113 | ##### This example will automatically manage the key. It will also create a value named 'puppetserver' inside this key. 114 | 115 | ```puppet 116 | class myapp { 117 | registry::value { 'puppetserver': 118 | key => 'HKLM\Software\Vendor\PuppetLabs', 119 | data => 'puppet.puppetlabs.com', 120 | } 121 | } 122 | ``` 123 | 124 | #### Parameters 125 | 126 | The following parameters are available in the `registry::value` defined type: 127 | 128 | * [`key`](#-registry--value--key) 129 | * [`value`](#-registry--value--value) 130 | * [`type`](#-registry--value--type) 131 | * [`data`](#-registry--value--data) 132 | 133 | ##### `key` 134 | 135 | Data type: `Pattern[/^\w+/]` 136 | 137 | The path of key the value will placed inside. 138 | 139 | ##### `value` 140 | 141 | Data type: `Optional[String]` 142 | 143 | The name of the registry value to manage. This will be copied from 144 | the resource title if not specified. The special value of 145 | '(default)' may be used to manage the default value of the key. 146 | 147 | Default value: `undef` 148 | 149 | ##### `type` 150 | 151 | Data type: `Pattern[/^\w+/]` 152 | 153 | The type the registry value. Defaults to 'string'. See the output of 154 | `puppet describe registry_value` for a list of supported types in the 155 | "type" parameter. 156 | 157 | Default value: `'string'` 158 | 159 | ##### `data` 160 | 161 | Data type: 162 | 163 | ```puppet 164 | Optional[Variant[ 165 | String, 166 | Numeric, 167 | Array[String] 168 | ]] 169 | ``` 170 | 171 | The data to place inside the registry value. 172 | 173 | Default value: `undef` 174 | 175 | ## Resource types 176 | 177 | ### `registry_key` 178 | 179 | Manages registry keys on Windows 180 | 181 | #### Properties 182 | 183 | The following properties are available in the `registry_key` type. 184 | 185 | ##### `ensure` 186 | 187 | Valid values: `present`, `absent` 188 | 189 | The basic property that the resource should be in. 190 | 191 | Default value: `present` 192 | 193 | #### Parameters 194 | 195 | The following parameters are available in the `registry_key` type. 196 | 197 | * [`path`](#-registry_key--path) 198 | * [`provider`](#-registry_key--provider) 199 | * [`purge_values`](#-registry_key--purge_values) 200 | 201 | ##### `path` 202 | 203 | The path to the registry key to manage 204 | 205 | ##### `provider` 206 | 207 | The specific backend to use for this `registry_key` resource. You will seldom need to specify this --- Puppet will 208 | usually discover the appropriate provider for your platform. 209 | 210 | ##### `purge_values` 211 | 212 | Valid values: `true`, `false` 213 | 214 | Common boolean for munging and validation. 215 | 216 | Default value: `false` 217 | 218 | ### `registry_value` 219 | 220 | Manages registry values on Windows systems. 221 | 222 | #### Properties 223 | 224 | The following properties are available in the `registry_value` type. 225 | 226 | ##### `data` 227 | 228 | The data stored in the registry value. 229 | 230 | ##### `ensure` 231 | 232 | Valid values: `present`, `absent` 233 | 234 | The basic property that the resource should be in. 235 | 236 | Default value: `present` 237 | 238 | ##### `type` 239 | 240 | Valid values: `string`, `array`, `dword`, `qword`, `binary`, `expand` 241 | 242 | The Windows data type of the registry value. 243 | 244 | Default value: `string` 245 | 246 | #### Parameters 247 | 248 | The following parameters are available in the `registry_value` type. 249 | 250 | * [`path`](#-registry_value--path) 251 | * [`provider`](#-registry_value--provider) 252 | 253 | ##### `path` 254 | 255 | The path to the registry value to manage. 256 | 257 | ##### `provider` 258 | 259 | The specific backend to use for this `registry_value` resource. You will seldom need to specify this --- Puppet will 260 | usually discover the appropriate provider for your platform. 261 | 262 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler' 4 | require 'puppet_litmus/rake_tasks' if Gem.loaded_specs.key? 'puppet_litmus' 5 | require 'puppetlabs_spec_helper/rake_tasks' 6 | require 'puppet-syntax/tasks/puppet-syntax' 7 | require 'puppet-strings/tasks' if Gem.loaded_specs.key? 'puppet-strings' 8 | 9 | PuppetLint.configuration.send('disable_relative') 10 | -------------------------------------------------------------------------------- /data/common.yaml: -------------------------------------------------------------------------------- 1 | --- {} 2 | -------------------------------------------------------------------------------- /examples/compliance_example.pp: -------------------------------------------------------------------------------- 1 | # = Class: registry::compliance_example 2 | # 3 | # This class provides an example of how to use the audit metaparameter to 4 | # inspect registry_key and registry_value resources with the Compliance 5 | # feature of Puppet Enterprise. 6 | # 7 | # = Parameters 8 | # 9 | # = Actions 10 | # 11 | # = Requires 12 | # 13 | # = Sample Usage 14 | # 15 | # include registry::compliance_example 16 | # 17 | # (MARKUP: http://links.puppetlabs.com/puppet_manifest_documentation) 18 | class { 'registry': } 19 | 20 | $key_path = 'HKLM\Software\Vendor\Puppet Labs\Examples\Compliance' 21 | 22 | case $registry_compliance_example_mode { 23 | 'audit': { 24 | $mode = 'audit' 25 | } 26 | default: { 27 | $mode = 'setup' 28 | notify { 'compliance_example_mode_info': 29 | message => 'Switch to audit mode using 30 | \$env:FACTER_REGISTRY_COMPLIANCE_EXAMPLE_MODE = \'audit\'', 31 | before => Notify['compliance_example_mode'], 32 | } 33 | } 34 | } 35 | 36 | notify { 'compliance_example_mode': 37 | message => "Registry compliance example mode: ${mode}", 38 | } 39 | 40 | # Resource Defaults 41 | Registry_key { 42 | ensure => $mode ? { 43 | 'setup' => present, 44 | default => undef, 45 | }, 46 | purge_values => $mode ? { 47 | 'setup' => true, 48 | default => false, 49 | }, 50 | } 51 | Registry_value { 52 | ensure => $mode ? { 53 | 'setup' => present, 54 | default => undef, 55 | }, 56 | type => $mode ? { 57 | 'setup' => string, 58 | default => undef, 59 | }, 60 | data => $mode ? { 61 | 'setup' => 'Puppet Default Data', 62 | default => undef, 63 | }, 64 | audit => $mode ? { 65 | 'setup' => undef, 66 | default => all, 67 | }, 68 | } 69 | 70 | # Create the nested key structure we want to audit. The resource defaults 71 | # will determine the properties managed or audited. 72 | registry_key { $key_path: } 73 | registry_key { "${key_path}\\SubKeyA": } 74 | registry_key { "${key_path}\\SubKeyA\\SubKeyA1": } 75 | registry_key { "${key_path}\\SubKeyA\\SubKeyA2": } 76 | registry_key { "${key_path}\\SubKeyB": } 77 | registry_key { "${key_path}\\SubKeyB\\SubKeyB1": } 78 | registry_key { "${key_path}\\SubKeyB\\SubKeyB2": } 79 | registry_key { "${key_path}\\SubKeyC": } 80 | registry_key { "${key_path}\\SubKeyC\\SubKeyC1": } 81 | registry_key { "${key_path}\\SubKeyC\\SubKeyC2": } 82 | registry_value { "${key_path}\\Value1": } 83 | registry_value { "${key_path}\\Value2": } 84 | registry_value { "${key_path}\\Value3": } 85 | registry_value { "${key_path}\\SubKeyA\\ValueA1": } 86 | registry_value { "${key_path}\\SubKeyA\\ValueA2": } 87 | registry_value { "${key_path}\\SubKeyA\\ValueA3": } 88 | registry_value { "${key_path}\\SubKeyB\\ValueB1": } 89 | registry_value { "${key_path}\\SubKeyB\\ValueB2": } 90 | registry_value { "${key_path}\\SubKeyB\\ValueB3": } 91 | registry_value { "${key_path}\\SubKeyC\\ValueC1": } 92 | registry_value { "${key_path}\\SubKeyC\\ValueC2": } 93 | registry_value { "${key_path}\\SubKeyC\\ValueC3": } 94 | registry_value { "${key_path}\\SubKeyA\\SubKeyA1\\ValueA1X": } 95 | registry_value { "${key_path}\\SubKeyA\\SubKeyA1\\ValueA1Y": } 96 | registry_value { "${key_path}\\SubKeyA\\SubKeyA1\\ValueA1Z": } 97 | registry_value { "${key_path}\\SubKeyA\\SubKeyA2\\ValueA2X": } 98 | registry_value { "${key_path}\\SubKeyA\\SubKeyA2\\ValueA2Y": } 99 | registry_value { "${key_path}\\SubKeyA\\SubKeyA2\\ValueA2Z": } 100 | registry_value { "${key_path}\\SubKeyB\\SubKeyB1\\ValueB1X": } 101 | registry_value { "${key_path}\\SubKeyB\\SubKeyB1\\ValueB1Y": } 102 | registry_value { "${key_path}\\SubKeyB\\SubKeyB1\\ValueB1Z": } 103 | registry_value { "${key_path}\\SubKeyB\\SubKeyB2\\ValueB2X": } 104 | registry_value { "${key_path}\\SubKeyB\\SubKeyB2\\ValueB2Y": } 105 | registry_value { "${key_path}\\SubKeyB\\SubKeyB2\\ValueB2Z": } 106 | registry_value { "${key_path}\\SubKeyC\\SubKeyC1\\ValueC1X": } 107 | registry_value { "${key_path}\\SubKeyC\\SubKeyC1\\ValueC1Y": } 108 | registry_value { "${key_path}\\SubKeyC\\SubKeyC1\\ValueC1Z": } 109 | registry_value { "${key_path}\\SubKeyC\\SubKeyC2\\ValueC2X": } 110 | registry_value { "${key_path}\\SubKeyC\\SubKeyC2\\ValueC2Y": } 111 | registry_value { "${key_path}\\SubKeyC\\SubKeyC2\\ValueC2Z": } 112 | -------------------------------------------------------------------------------- /examples/purge_example.pp: -------------------------------------------------------------------------------- 1 | # = Class: registry::purge_example 2 | # 3 | # This class provides an example of how to purge registry values associated 4 | # with a specific key. 5 | # 6 | # This class has two modes of operation determined by the Facter fact 7 | # PURGE_EXAMPLE_MODE The value of this fact can be either 'setup' or 'purge' 8 | # 9 | # The easiest way to set this mode is to set an 10 | # environment variable in Power Shell: 11 | # 12 | # The setup mode creates a registry key and 6 values. 13 | # 14 | # `$env:FACTER_PURGE_EXAMPLE_MODE = "setup"` 15 | # `puppet agent --test` 16 | # 17 | # The purge mode manages the key with purge_values => true and manages only 3 18 | # of the 6 values. The other 3 values will be automatically purged. 19 | # 20 | # `$env:FACTER_PURGE_EXAMPLE_MODE = "purge"` 21 | # `puppet agent --test` 22 | # 23 | # = Parameters 24 | # 25 | # = Actions 26 | # 27 | # = Requires 28 | # 29 | # = Sample Usage 30 | # 31 | # include registry::purge_example 32 | # 33 | # (MARKUP: http://links.puppetlabs.com/puppet_manifest_documentation) 34 | class { 'registry': } 35 | 36 | $key_path = 'HKLM\Software\Vendor\Puppet Labs\Examples\KeyPurge' 37 | 38 | case $purge_example_mode { 39 | 'setup': { 40 | registry_key { $key_path: 41 | ensure => present, 42 | purge_values => false, 43 | } 44 | registry_key { "${key_path}\\SubKey": 45 | ensure => present, 46 | purge_values => false, 47 | } 48 | registry_value { "${key_path}\\SubKey\\Value1": 49 | ensure => present, 50 | type => dword, 51 | data => 1, 52 | } 53 | registry_value { "${key_path}\\SubKey\\Value2": 54 | ensure => present, 55 | type => dword, 56 | data => 1, 57 | } 58 | registry_value { "${key_path}\\Value1": 59 | ensure => present, 60 | type => dword, 61 | data => 1, 62 | } 63 | registry_value { "${key_path}\\Value2": 64 | ensure => present, 65 | type => dword, 66 | data => 2, 67 | } 68 | registry_value { "${key_path}\\Value3": 69 | ensure => present, 70 | type => string, 71 | data => 'key3', 72 | } 73 | registry_value { "${key_path}\\Value4": 74 | ensure => present, 75 | type => array, 76 | data => ['one', 'two', 'three'], 77 | } 78 | registry_value { "${key_path}\\Value5": 79 | ensure => present, 80 | type => expand, 81 | data => '%SystemRoot%\system32', 82 | } 83 | registry_value { "${key_path}\\Value6": 84 | ensure => present, 85 | type => binary, 86 | data => '01AB CDEF', 87 | } 88 | } 89 | 'purge': { 90 | registry_key { $key_path: 91 | ensure => present, 92 | purge_values => true, 93 | } 94 | registry_value { "${key_path}\\Value1": 95 | ensure => present, 96 | type => dword, 97 | data => 0, 98 | } 99 | registry_value { "${key_path}\\Value2": 100 | ensure => present, 101 | type => dword, 102 | data => 0, 103 | } 104 | registry_value { "${key_path}\\Value3": 105 | ensure => present, 106 | type => string, 107 | data => 'should not be purged', 108 | } 109 | } 110 | default: { 111 | notify { 'purge_example_notice': 112 | message => 'The purge_example_mode fact is not set. To try this 113 | example class first set \$env:FACTER_PURGE_EXAMPLE_MODE = \'setup\' then 114 | run puppet agent, then set \$env:FACTER_PURGE_EXAMPLE_MODE = \'purge\' 115 | and run puppet agent again to see the values purged.', 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /examples/registry_examples.pp: -------------------------------------------------------------------------------- 1 | # = Class: registry_example 2 | # 3 | # This is an example of how to manage registry keys and values. 4 | # 5 | # = Parameters 6 | # 7 | # = Actions 8 | # 9 | # = Requires 10 | # 11 | # = Sample Usage 12 | # 13 | # include registry_example 14 | # 15 | # (MARKUP: http://links.puppetlabs.com/puppet_manifest_documentation) 16 | class { 'registry': } 17 | 18 | registry_key { 'HKLM\Software\Vendor': 19 | ensure => present, 20 | } 21 | 22 | # This should trigger a duplicate resource with HKLM 23 | # registry_key { 'HKEY_LOCAL_MACHINE\Software\Vendor': 24 | # ensure => present, 25 | # } 26 | 27 | registry_key { 'HKLM\Software\Vendor\Bar': 28 | ensure => present, 29 | } 30 | 31 | registry_value { 'HKLM\Software\Vendor\Bar\valuedword2': 32 | ensure => present, 33 | type => dword, 34 | data => 0xFFFFFFFF, 35 | } 36 | 37 | registry_value { 'HKLM\Software\Vendor\Bar\valueqword1': 38 | ensure => present, 39 | type => qword, 40 | data => 100, 41 | } 42 | 43 | registry_value { 'HKLM\Software\Vendor\Bar\valuedstring1': 44 | ensure => present, 45 | type => string, 46 | data => 'this is a string', 47 | } 48 | 49 | registry_value { 'HKLM\Software\Vendor\Bar\valuedexpand1': 50 | ensure => present, 51 | type => expand, 52 | data => '%windir%\system32', 53 | } 54 | 55 | registry_value { 'HKLM\Software\Vendor\Bar\valuedbinary1': 56 | ensure => present, 57 | type => binary, 58 | data => 'DE AD BE EF', 59 | } 60 | 61 | registry_value { 'HKLM\Software\Vendor\Bar\valuedbinary2': 62 | ensure => present, 63 | type => binary, 64 | data => 'CAFEBEEF', 65 | } 66 | 67 | registry_value { 'HKLM\Software\Vendor\Bar\valuearray1': 68 | ensure => present, 69 | type => array, 70 | data => ['one', 'two', 'three'], 71 | } 72 | 73 | $some_string = 'somestring' 74 | registry_value { 'HKLM\Software\Vendor\Bar\valuearray2': 75 | ensure => present, 76 | type => array, 77 | data => [0, 'zero', '0', 123456, 'two', $some_string], 78 | } 79 | 80 | $some_array = ['array1', 'array2', 'array3'] 81 | registry_value { 'HKLM\Software\Vendor\Bar\valuearray3': 82 | ensure => present, 83 | type => array, 84 | data => $some_array, 85 | } 86 | 87 | include registry_example 88 | -------------------------------------------------------------------------------- /examples/service_example.pp: -------------------------------------------------------------------------------- 1 | # = Class: registry::service_example 2 | # 3 | # This is an example of how to use the registry::service defined resource 4 | # type included in this module. 5 | # 6 | # = Parameters 7 | # 8 | # = Actions 9 | # 10 | # = Requires 11 | # 12 | # = Sample Usage 13 | # 14 | # include registry::service_example 15 | # 16 | # 17 | # (MARKUP: http://links.puppetlabs.com/puppet_manifest_documentation) 18 | class { 'registry': } 19 | 20 | # Define a new service named "Puppet Test" that is disabled. 21 | registry::service { 'PuppetExample1': 22 | display_name => 'Puppet Example 1', 23 | description => 'This is a simple example managing the 24 | registry entries for a Windows Service', 25 | command => 'C:\PuppetExample1.bat', 26 | start => 'disabled', 27 | } 28 | registry::service { 'PuppetExample2': 29 | display_name => 'Puppet Example 2', 30 | description => 'This is a simple example 31 | managing the registry entries for a Windows Service', 32 | command => 'C:\PuppetExample2.bat', 33 | start => 'disabled', 34 | } 35 | -------------------------------------------------------------------------------- /hiera.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 5 3 | 4 | defaults: # Used for any hierarchy level that omits these keys. 5 | datadir: data # This path is relative to hiera.yaml's directory. 6 | data_hash: yaml_data # Use the built-in YAML backend. 7 | 8 | hierarchy: 9 | - name: "osfamily/major release" 10 | paths: 11 | # Used to distinguish between Debian and Ubuntu 12 | - "os/%{facts.os.name}/%{facts.os.release.major}.yaml" 13 | - "os/%{facts.os.family}/%{facts.os.release.major}.yaml" 14 | # Used for Solaris 15 | - "os/%{facts.os.family}/%{facts.kernelrelease}.yaml" 16 | - name: "osfamily" 17 | paths: 18 | - "os/%{facts.os.name}.yaml" 19 | - "os/%{facts.os.family}.yaml" 20 | - name: 'common' 21 | path: 'common.yaml' 22 | -------------------------------------------------------------------------------- /lib/puppet/provider/registry_key/registry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../../puppet_x/puppetlabs/registry' 4 | 5 | Puppet::Type.type(:registry_key).provide(:registry) do 6 | desc <<-DOC 7 | @summary Registry_key provider 8 | Manages individual Registry keys. 9 | DOC 10 | include Puppet::Util::Windows::Registry if Puppet.features.microsoft_windows? 11 | 12 | defaultfor 'os.name': :windows 13 | confine 'os.name': :windows 14 | 15 | def self.instances 16 | PuppetX::Puppetlabs::Registry.hkeys.keys.map do |hkey| 17 | new(provider: :registry, name: hkey.to_s) 18 | end 19 | end 20 | 21 | def hive 22 | PuppetX::Puppetlabs::Registry.hkeys[path.root] 23 | end 24 | 25 | def access 26 | path.access 27 | end 28 | 29 | def subkey 30 | path.subkey 31 | end 32 | 33 | def create 34 | Puppet.debug("Creating registry key #{self}") 35 | hive.create(subkey, Win32::Registry::KEY_ALL_ACCESS | access) { |_reg| true } 36 | end 37 | 38 | def exists? 39 | Puppet.debug("Checking existence of registry key #{self}") 40 | begin 41 | !!hive.open(subkey, Win32::Registry::KEY_READ | access) { |_reg| true } # rubocop:disable Style/DoubleNegation 42 | rescue StandardError 43 | false 44 | end 45 | end 46 | 47 | def destroy 48 | Puppet.debug("Destroying registry key #{self}") 49 | 50 | raise ArgumentError, "Cannot delete root key: #{path}" unless subkey 51 | 52 | delete_key(hive, subkey, access) 53 | end 54 | 55 | def values 56 | names = [] 57 | # Only try and get the values for this key if the key itself exists. 58 | if exists? 59 | hive.open(subkey, Win32::Registry::KEY_READ | access) do |reg| 60 | each_value(reg) { |name, _type, _data| names << name } 61 | end 62 | end 63 | names 64 | end 65 | 66 | private 67 | 68 | def path 69 | @path ||= PuppetX::Puppetlabs::Registry::RegistryKeyPath.new(resource.parameter(:path).value) 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/puppet/provider/registry_value/registry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet/type' 4 | require_relative '../../../puppet_x/puppetlabs/registry' 5 | 6 | Puppet::Type.type(:registry_value).provide(:registry) do 7 | desc <<-DOC 8 | @summary Registry_value provider 9 | Manages individual Registry values. 10 | DOC 11 | include Puppet::Util::Windows::Registry if Puppet.features.microsoft_windows? 12 | 13 | defaultfor 'os.name': :windows 14 | confine 'os.name': :windows 15 | 16 | def self.instances 17 | [] 18 | end 19 | 20 | def hive 21 | PuppetX::Puppetlabs::Registry.hkeys[path.root] 22 | end 23 | 24 | def access 25 | path.access 26 | end 27 | 28 | def subkey 29 | path.subkey 30 | end 31 | 32 | def exists? 33 | Puppet.debug("Checking the existence of registry value: #{self}") 34 | found = false 35 | begin 36 | hive.open(subkey, Win32::Registry::KEY_READ | access) do |reg| 37 | FFI::Pointer.from_string_to_wide_string(valuename) do |valuename_ptr| 38 | status = Puppet::Util::Windows::Registry.RegQueryValueExW(reg.hkey, valuename_ptr, 39 | FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL, 40 | FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL) 41 | 42 | found = status.zero? 43 | raise Win32::Registry::Error, status unless found 44 | end 45 | end 46 | rescue Win32::Registry::Error => e 47 | case e.code 48 | when 2 49 | # Code 2 is the error message for "The system cannot find the file specified." 50 | # http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx 51 | found = false 52 | else 53 | error = Puppet::Error.new("Unexpected exception from Win32 API. detail: (#{e.message}) ERROR CODE: #{e.code}. Puppet Error ID: D4B679E4-0E22-48D5-80EF-96AAEC0282B9") 54 | error.set_backtrace e.backtrace 55 | raise error 56 | end 57 | end 58 | found 59 | end 60 | 61 | def create 62 | Puppet.debug("Creating registry value: #{self}") 63 | write_value 64 | end 65 | 66 | def flush 67 | # REVISIT - This concept of flush seems different than package provider's 68 | # concept of flush. 69 | Puppet.debug("Flushing registry value: #{self}") 70 | return if resource[:ensure] == :absent 71 | 72 | write_value 73 | end 74 | 75 | def destroy 76 | Puppet.debug("Destroying registry value: #{self}") 77 | hive.open(subkey, Win32::Registry::KEY_ALL_ACCESS | access) { |reg| delete_value(reg, valuename) } 78 | end 79 | 80 | def type 81 | regvalue[:type] || :absent 82 | end 83 | 84 | def type=(value) 85 | regvalue[:type] = value 86 | end 87 | 88 | def data 89 | regvalue[:data] || :absent 90 | end 91 | 92 | def data=(value) 93 | regvalue[:data] = value 94 | end 95 | 96 | def regvalue 97 | unless @regvalue 98 | @regvalue = {} 99 | hive.open(subkey, Win32::Registry::KEY_READ | access) do |reg| 100 | FFI::Pointer.from_string_to_wide_string(valuename) do |valuename_ptr| 101 | if Puppet::Util::Windows::Registry.RegQueryValueExW(reg.hkey, valuename_ptr, 102 | FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL, 103 | FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL).zero? 104 | # Note - This actually calls read from Win32::Registry not Puppet::Util::Windows::Registry 105 | @regvalue[:type], @regvalue[:data] = from_native(reg.read(valuename)) 106 | end 107 | end 108 | end 109 | end 110 | @regvalue 111 | end 112 | 113 | # convert puppet type and data to native 114 | def to_native(ptype, pdata) 115 | # JJM Because the data property is set to :array_matching => :all we 116 | # should always get an array from Puppet. We need to convert this 117 | # array to something usable by the Win API. 118 | raise Puppet::Error, 'Data should be an Array (ErrorID 37D9BBAB-52E8-4A7C-9F2E-D7BF16A59050)' unless pdata.is_a?(Array) 119 | 120 | ndata = 121 | case ptype 122 | when :binary 123 | pdata.first.scan(%r{[a-f\d]{2}}i).map { |byte| [byte].pack('H2') }.join 124 | when :array 125 | # We already have an array, and the native API write method takes an 126 | # array, so send it thru. 127 | pdata 128 | else 129 | # Since we have an array, take the first element and send it to the 130 | # native API which is expecting a scalar. 131 | pdata.first 132 | end 133 | 134 | [PuppetX::Puppetlabs::Registry.name2type(ptype), ndata] 135 | end 136 | 137 | # convert from native type and data to puppet 138 | def from_native(ary) 139 | ntype, ndata = ary 140 | 141 | pdata = 142 | case PuppetX::Puppetlabs::Registry.type2name(ntype) 143 | when :binary 144 | ndata.bytes.map { |byte| '%02x' % byte }.join(' ') 145 | else 146 | ndata 147 | end 148 | 149 | # JJM Since the data property is set to :array_matching => all we should 150 | # always give an array to Puppet. This is why we have the ternary operator 151 | # I'm not calling .to_a because Ruby issues a warning about the default 152 | # implementation of to_a going away in the future. 153 | [PuppetX::Puppetlabs::Registry.type2name(ntype), pdata.is_a?(Array) ? pdata : [pdata]] 154 | end 155 | 156 | private 157 | 158 | def eval_error(err) 159 | case err 160 | when 2 161 | # Code 2 is the error message for "The system cannot find the file specified." 162 | # http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx 163 | Puppet::Error.new("Cannot write to the registry. The parent key does not exist. detail: (#{e.message}) Puppet Error ID: AC99C7C6-98D6-4E91-A75E-970F4064BF95") 164 | else 165 | Puppet::Error.new("Unexpected exception from Win32 API. detail: (#{e.message}). ERROR CODE: #{e.code}. Puppet Error ID: F46C6AE2-C711-48F9-86D6-5D50E1988E48") 166 | end 167 | end 168 | 169 | def write_value 170 | hive.open(subkey, Win32::Registry::KEY_ALL_ACCESS | access) do |reg| 171 | ary = to_native(resource[:type], resource[:data]) 172 | write(reg, valuename, ary[0], ary[1]) 173 | end 174 | rescue Win32::Registry::Error => e 175 | error = eval_error(e.code) 176 | error.set_backtrace e.backtrace 177 | raise error 178 | end 179 | 180 | def wide_string_to_bytes(data) 181 | bytes = Puppet::Util::Windows::String.wide_string(data).bytes.to_a 182 | # versions prior to 7 embedded a wide null in the string content to work 183 | # around ruby bugs, see PUP-3970 184 | if Puppet::PUPPETVERSION[0].to_i >= 7 185 | bytes << 0 << 0 186 | else 187 | bytes 188 | end 189 | end 190 | 191 | # This method must include wide null terminators in the returned 192 | # byte array for string-based registry values like REG_SZ. In 193 | # addition REG_MULTI_SZ must append another wide null character 194 | # to signify there are no more entries in the array. 195 | def data_to_bytes(type, data) 196 | bytes = [] 197 | 198 | case type 199 | when Win32::Registry::REG_SZ, Win32::Registry::REG_EXPAND_SZ 200 | bytes = wide_string_to_bytes(data) 201 | when Win32::Registry::REG_MULTI_SZ 202 | bytes = data.map { |s| wide_string_to_bytes(s) }.flat_map { |a| a } 203 | # requires an additional wide NULL terminator 204 | bytes << 0 << 0 205 | when Win32::Registry::REG_BINARY 206 | bytes = data.bytes.to_a 207 | when Win32::Registry::REG_DWORD 208 | # L is 32-bit unsigned native (little) endian order 209 | bytes = [data].pack('L').unpack('C*') 210 | when Win32::Registry::REG_QWORD 211 | # Q is 64-bit unsigned native (little) endian order 212 | bytes = [data].pack('Q').unpack('C*') 213 | else 214 | raise TypeError, "Unsupported type #{type}" 215 | end 216 | 217 | bytes 218 | end 219 | 220 | def write(reg, _name, type, data) 221 | FFI::Pointer.from_string_to_wide_string(valuename) do |name_ptr| 222 | bytes = data_to_bytes(type, data) 223 | FFI::MemoryPointer.new(:uchar, bytes.length) do |data_ptr| 224 | data_ptr.write_array_of_uchar(bytes) 225 | # From https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexw 226 | # "cbData must include the size of the terminating null character or characters" 227 | if RegSetValueExW(reg.hkey, name_ptr, 0, 228 | type, data_ptr, data_ptr.size) != 0 229 | raise Puppet::Util::Windows::Error, 'Failed to write registry value' 230 | end 231 | end 232 | end 233 | end 234 | 235 | if Puppet.features.microsoft_windows? 236 | require 'ffi' 237 | extend FFI::Library 238 | # https://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx 239 | # LONG WINAPI RegSetValueEx( 240 | # _In_ HKEY hKey, 241 | # _In_opt_ LPCTSTR lpValueName, 242 | # _Reserved_ DWORD Reserved, 243 | # _In_ DWORD dwType, 244 | # _In_ const BYTE *lpData, 245 | # _In_ DWORD cbData 246 | # ); 247 | ffi_lib :advapi32 248 | attach_function :RegSetValueExW, 249 | [:handle, :pointer, :dword, :dword, :pointer, :dword], :win32_long 250 | end 251 | 252 | def valuename 253 | path.valuename 254 | end 255 | 256 | def path 257 | @path ||= PuppetX::Puppetlabs::Registry::RegistryValuePath.new(resource.parameter(:path).value) 258 | end 259 | end 260 | -------------------------------------------------------------------------------- /lib/puppet/type/registry_key.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet/type' 4 | require_relative '../../puppet_x/puppetlabs/registry' 5 | 6 | # @summary 7 | # Manages registry keys on Windows systems 8 | # 9 | # @note 10 | # Keys within HKEY_LOCAL_MACHINE (hklm) or HKEY_CLASSES_ROOT (hkcr) are 11 | # supported.Other predefined root keys, e.g. HKEY_USERS, are not 12 | # currently supported. 13 | # 14 | # If Puppet creates a registry key, Windows will automatically create any 15 | # necessary parent registry keys that do not exist. 16 | # 17 | # Puppet will not recursively delete registry keys. 18 | # 19 | # **Autorequires:** Any parent registry key managed by Puppet will be 20 | # autorequired. 21 | Puppet::Type.newtype(:registry_key) do 22 | @doc = <<-KEYS 23 | Manages registry keys on Windows 24 | KEYS 25 | def self.title_patterns 26 | [[%r{^(.*?)\Z}m, [[:path]]]] 27 | end 28 | 29 | ensurable 30 | 31 | # @summary The path to the registry key to manage. 32 | # 33 | # @example For example 'HKLM\Software','HKEY_LOCAL_MACHINE\Software\Vendor'. If Puppet is running on a 64-bit 34 | # system, the 32-bit registry key can be explicitly managed using a 35 | # prefix. For example: '32:HKLM\Software'" 36 | newparam(:path, namevar: true) do 37 | @doc = <<-PATH 38 | The path to the registry key to manage 39 | PATH 40 | validate do |path| 41 | PuppetX::Puppetlabs::Registry::RegistryKeyPath.new(path).valid? 42 | end 43 | munge do |path| 44 | reg_path = PuppetX::Puppetlabs::Registry::RegistryKeyPath.new(path) 45 | # Windows is case insensitive and case preserving. We deal with this by 46 | # aliasing resources to their downcase values. This is inspired by the 47 | # munge block in the alias metaparameter. 48 | if @resource.catalog 49 | reg_path.aliases.each do |alt_name| 50 | @resource.catalog.alias(@resource, alt_name) 51 | end 52 | else 53 | Puppet.debug "Resource has no associated catalog. Aliases are not being set for #{@resource}" 54 | end 55 | reg_path.canonical 56 | end 57 | end 58 | 59 | # REVISIT - Make a common parameter for boolean munging and validation. This will be used 60 | # By both registry_key and registry_value types. 61 | # @summary Whether to delete any registry value associated with this key that is not being managed by puppet. 62 | newparam(:purge_values, boolean: true) do 63 | @doc = <<-BOOLEAN 64 | Common boolean for munging and validation. 65 | BOOLEAN 66 | newvalues(true, false) 67 | defaultto false 68 | 69 | validate do |value| 70 | case value 71 | when true, %r{^true$}i, %r{^false$}i, false, :undef, nil 72 | true 73 | else 74 | # We raise an ArgumentError and not a Puppet::Error so we get manifest 75 | # and line numbers in the error message displayed to the user. 76 | raise ArgumentError, "Validation Error: purge_values must be true or false, not #{value}" 77 | end 78 | end 79 | 80 | munge do |value| 81 | case value 82 | when true, %r{^true$}i 83 | true 84 | else 85 | false 86 | end 87 | end 88 | end 89 | 90 | # Autorequire the nearest ancestor registry_key found in the catalog. 91 | autorequire(:registry_key) do 92 | req = [] 93 | path = PuppetX::Puppetlabs::Registry::RegistryKeyPath.new(value(:path)) 94 | # It is important to match against the downcase value of the path because 95 | # other resources are expected to alias themselves to the downcase value so 96 | # that we respect the case insensitive and preserving nature of Windows. 97 | found = path.enum_for(:ascend).find { |p| catalog.resource(:registry_key, p.to_s.downcase) } 98 | req << found.to_s.downcase if found 99 | req 100 | end 101 | 102 | def eval_generate 103 | # This value will be given post-munge so we can assume it will be a ruby true or false object 104 | return [] unless value(:purge_values) 105 | 106 | # get the "should" names of registry values associated with this key 107 | should_values = catalog.relationship_graph.direct_dependents_of(self).select { |dep| dep.type == :registry_value }.map do |reg| 108 | PuppetX::Puppetlabs::Registry::RegistryValuePath.new(reg.parameter(:path).value).valuename.downcase 109 | end 110 | 111 | # get the "is" names of registry values associated with this key 112 | is_values = provider.values 113 | 114 | # create absent registry_value resources for the complement 115 | resources = [] 116 | is_values.each do |is_value| 117 | unless should_values.include?(is_value.downcase) 118 | resource_path = PuppetX::Puppetlabs::Registry::RegistryValuePath.combine_path_and_value(self[:path], is_value) 119 | resources << Puppet::Type.type(:registry_value).new(path: resource_path, ensure: :absent, catalog: catalog) 120 | end 121 | end 122 | resources 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /lib/puppet/type/registry_value.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet/type' 4 | require_relative '../../puppet_x/puppetlabs/registry' 5 | 6 | # @summary 7 | # Manages registry values on Windows systems. 8 | # 9 | # @note 10 | # The `registry_value` type can manage registry values. See the 11 | # `type` and `data` attributes for information about supported 12 | # registry types, e.g. REG_SZ, and how the data should be specified. 13 | # 14 | # **Autorequires:** Any parent registry key managed by Puppet will be 15 | # autorequired. 16 | Puppet::Type.newtype(:registry_value) do 17 | @doc = <<-VALUES 18 | Manages registry values on Windows systems. 19 | VALUES 20 | def self.title_patterns 21 | [[%r{^(.*?)\Z}m, [[:path]]]] 22 | end 23 | 24 | ensurable 25 | 26 | # @summary 27 | # The path to the registry value to manage. 28 | # 29 | # @example 30 | # For example: 31 | # 'HKLM\Software\Value1', 'HKEY_LOCAL_MACHINE\Software\Vendor\Value2'. 32 | # If Puppet is running on a 64-bit system, the 32-bit registry key can 33 | # be explicitly managed using a prefix. 34 | # @example 35 | # For example: 36 | # '32:HKLM\Software\Value3'. Use a double backslash between the value name 37 | # and path when managing a value with a backslash in the name." 38 | newparam(:path, namevar: true) do 39 | @doc = <<-PATH 40 | The path to the registry value to manage. 41 | PATH 42 | validate do |path| 43 | PuppetX::Puppetlabs::Registry::RegistryValuePath.new(path).valid? 44 | end 45 | munge do |path| 46 | reg_path = PuppetX::Puppetlabs::Registry::RegistryValuePath.new(path) 47 | # Windows is case insensitive and case preserving. We deal with this by 48 | # aliasing resources to their downcase values. This is inspired by the 49 | # munge block in the alias metaparameter. 50 | if @resource.catalog 51 | reg_path.aliases.each do |alt_name| 52 | @resource.catalog.alias(@resource, alt_name) 53 | end 54 | else 55 | Puppet.debug "Resource has no associated catalog. Aliases are not being set for #{@resource}" 56 | end 57 | reg_path.canonical 58 | end 59 | end 60 | 61 | # @summary 62 | # The Windows data type of the registry value. 63 | # 64 | # Puppet provides helpful names for these types as follows: 65 | # * string => REG_SZ 66 | # * array => REG_MULTI_SZ 67 | # * expand => REG_EXPAND_SZ 68 | # * dword => REG_DWORD 69 | # * qword => REG_QWORD 70 | # * binary => REG_BINARY 71 | # 72 | newproperty(:type) do 73 | @doc = <<-DATA 74 | The Windows data type of the registry value. 75 | DATA 76 | newvalues(:string, :array, :dword, :qword, :binary, :expand) 77 | defaultto :string 78 | end 79 | 80 | # @summary 81 | # The data stored in the registry value. 82 | # 83 | # Data should be specified 84 | # as a string value but may be specified as a Puppet array when the 85 | # type is set to `array`." 86 | # 87 | newproperty(:data, array_matching: :all) do 88 | @doc = <<-DATA 89 | The data stored in the registry value. 90 | DATA 91 | 92 | # We probably shouldn't set default values for this property at all. For 93 | # dword and qword specifically, the legacy default value will not pass 94 | # validation. As such, no default value will be set for those types. At 95 | # least for now, other types will still have the legacy empty-string 96 | # default value. 97 | defaultto { [:dword, :qword].include?(resource[:type]) ? nil : '' } 98 | 99 | validate do |value| 100 | case resource[:type] 101 | when :array 102 | raise('An array registry value can not contain empty values') if value.empty? 103 | when :dword 104 | munged = munge(value) 105 | raise("The data must be a valid DWORD: received '#{value}'") unless munged && (munged.abs >> 32) <= 0 106 | when :qword 107 | munged = munge(value) 108 | raise("The data must be a valid QWORD: received '#{value}'") unless munged && (munged.abs >> 64) <= 0 109 | when :binary 110 | munged = munge(value) 111 | raise("The data must be a hex encoded string of the form: '00 01 02 ...': received '#{value}'") unless munged =~ %r{^([a-f\d]{2} ?)+$}i || value.empty? 112 | else # :string, :expand, :array 113 | true 114 | end 115 | end 116 | 117 | munge do |value| 118 | case resource[:type] 119 | when :dword, :qword 120 | begin 121 | Integer(value) 122 | rescue StandardError 123 | nil 124 | end 125 | when :binary 126 | munged = if (value.respond_to?(:length) && value.length == 1) || (value.is_a?(Integer) && value <= 9) 127 | "0#{value}" 128 | else 129 | value 130 | end 131 | 132 | # First, strip out all spaces from the string in the manfest. Next, 133 | # put a space after each pair of hex digits. Strip off the rightmost 134 | # space if it's present. Finally, downcase the whole thing. The final 135 | # result should be: "CaFE BEEF" => "ca fe be ef" 136 | munged.gsub(%r{\s+}, '') 137 | .gsub(%r{([0-9a-f]{2})}i) { "#{Regexp.last_match(1)} " } 138 | .rstrip 139 | .downcase 140 | else # :string, :expand, :array 141 | value 142 | end 143 | end 144 | 145 | def property_matches?(current, desired) 146 | case resource[:type] 147 | when :binary 148 | return false unless current 149 | 150 | current.casecmp(desired).zero? 151 | else 152 | super(current, desired) 153 | end 154 | end 155 | 156 | def change_to_s(currentvalue, newvalue) 157 | currentvalue = currentvalue.join(',') if currentvalue.respond_to? :join 158 | newvalue = newvalue.join(',') if newvalue.respond_to? :join 159 | super(currentvalue, newvalue) 160 | end 161 | end 162 | 163 | validate do 164 | # To ensure consistent behavior, always require a value for the data 165 | # property. This validation can be removed if we remove the default value 166 | # for the data property, for all data types. 167 | raise ArgumentError, "No value supplied for required property 'data'" if property(:data).nil? 168 | end 169 | 170 | # Autorequire the nearest ancestor registry_key found in the catalog. 171 | autorequire(:registry_key) do 172 | req = [] 173 | # This is a value path and not a key path because it's based on the path of 174 | # the value resource. 175 | path = PuppetX::Puppetlabs::Registry::RegistryValuePath.new(value(:path)) 176 | # It is important to match against the downcase value of the path because 177 | # other resources are expected to alias themselves to the downcase value so 178 | # that we respect the case insensitive and preserving nature of Windows. 179 | found = path.enum_for(:ascend).find { |p| catalog.resource(:registry_key, p.to_s.downcase) } 180 | req << found.to_s.downcase if found 181 | req 182 | end 183 | end 184 | -------------------------------------------------------------------------------- /lib/puppet_x/puppetlabs/registry.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # @api private 4 | # rubocop:disable Style/ClassAndModuleChildren 5 | module PuppetX 6 | # @api private 7 | module Puppetlabs 8 | # @api private 9 | module Registry 10 | # rubocop:enable Style/ClassAndModuleChildren 11 | # For 64-bit OS, use 64-bit view. Ignored on 32-bit OS 12 | KEY_WOW64_64KEY = 0x100 13 | # For 64-bit OS, use 32-bit view. Ignored on 32-bit OS 14 | KEY_WOW64_32KEY = 0x200 unless defined? KEY_WOW64_32KEY 15 | 16 | def self.hkeys 17 | { 18 | hkcr: Win32::Registry::HKEY_CLASSES_ROOT, 19 | hklm: Win32::Registry::HKEY_LOCAL_MACHINE, 20 | hku: Win32::Registry::HKEY_USERS 21 | } 22 | end 23 | 24 | def self.hive 25 | hkeys[root] 26 | end 27 | 28 | def self.type2name_map 29 | { 30 | Win32::Registry::REG_NONE => :none, 31 | Win32::Registry::REG_SZ => :string, 32 | Win32::Registry::REG_EXPAND_SZ => :expand, 33 | Win32::Registry::REG_BINARY => :binary, 34 | Win32::Registry::REG_DWORD => :dword, 35 | Win32::Registry::REG_QWORD => :qword, 36 | Win32::Registry::REG_MULTI_SZ => :array 37 | } 38 | end 39 | 40 | def self.type2name(type) 41 | type2name_map[type] 42 | end 43 | 44 | def self.name2type(name) 45 | name2type = {} 46 | type2name_map.each_pair { |k, v| name2type[v] = k } 47 | name2type[name] 48 | end 49 | 50 | # This is the base class for Path manipulation. This class is meant to be 51 | # abstract, RegistryKeyPath and RegistryValuePath will customize and override 52 | # this class. 53 | class RegistryPathBase < String 54 | attr_reader :path 55 | 56 | def initialize(path) 57 | @filter_path_memo = nil 58 | @path ||= path 59 | super(path) 60 | end 61 | 62 | # The path is valid if we're able to parse it without exceptions. 63 | def valid? 64 | (filter_path && true) 65 | rescue StandardError 66 | false 67 | end 68 | 69 | def canonical 70 | filter_path[:canonical] 71 | end 72 | 73 | # This method is meant to help setup aliases so autorequire can sort itself 74 | # out in a case insensitive but preserving manner. It returns an array of 75 | # resource identifiers. 76 | def aliases 77 | [canonical.downcase] 78 | end 79 | 80 | def access 81 | filter_path[:access] 82 | end 83 | 84 | def root 85 | filter_path[:root] 86 | end 87 | 88 | def subkey 89 | filter_path[:trailing_path] 90 | end 91 | 92 | def ascend 93 | p = canonical 94 | while idx = p.rindex('\\') # rubocop:disable Lint/AssignmentInCondition 95 | p = p[0, idx] 96 | yield p 97 | end 98 | end 99 | 100 | private 101 | 102 | def filter_bits(prefix, res) 103 | case prefix 104 | when '32:' 105 | res[:access] = PuppetX::Puppetlabs::Registry::KEY_WOW64_32KEY 106 | res[:prefix] = '32:' 107 | else 108 | res[:access] = PuppetX::Puppetlabs::Registry::KEY_WOW64_64KEY 109 | res[:prefix] = '' 110 | end 111 | res 112 | end 113 | 114 | def filter_canonical(res) 115 | return "#{res[:prefix]}#{res[:root]}" if res[:trailing_path].empty? 116 | 117 | # Leading backslash is not part of the subkey name 118 | "#{res[:prefix]}#{res[:root]}\\#{res[:trailing_path]}" 119 | end 120 | 121 | def filter_hkey(path) 122 | case path 123 | when %r{hkey_local_machine}, %r{hklm} 124 | :hklm 125 | when %r{hkey_classes_root}, %r{hkcr} 126 | :hkcr 127 | when %r{hkey_users}, %r{hku} 128 | :hku 129 | when %r{hkey_current_user}, %r{hkcu}, %r{hkey_current_config}, %r{hkcc}, %r{hkey_performance_data}, 130 | %r{hkey_performance_text}, %r{hkey_performance_nlstext}, %r{hkey_dyn_data} 131 | raise ArgumentError, "Unsupported predefined key: #{path}" 132 | else 133 | raise ArgumentError, "Invalid registry key: #{path}" 134 | end 135 | end 136 | 137 | def filter_path 138 | return @filter_path_memo if @filter_path_memo 139 | 140 | result = {} 141 | 142 | path = @path 143 | # Strip off any trailing slash. 144 | path = path.gsub(%r{\\*$}, '') 145 | 146 | captures = %r{^(32:)?([h|H][^\\]*)((?:\\[^\\]{1,255})*)$}.match(path) 147 | raise ArgumentError, "Invalid registry key: #{path}" unless captures 148 | 149 | filter_bits(captures[1], result) 150 | 151 | # canonical root key symbol 152 | result[:root] = filter_hkey(captures[2].to_s.downcase) 153 | result[:trailing_path] = captures[3] 154 | result[:trailing_path].gsub!(%r{^\\}, '') 155 | result[:canonical] = filter_canonical(result) 156 | 157 | @filter_path_memo = result 158 | end 159 | # rubocop:enable Metrics/MethodLength 160 | end 161 | 162 | class RegistryKeyPath < RegistryPathBase 163 | end 164 | 165 | # @summary Windows registry value path 166 | class RegistryValuePath < RegistryPathBase 167 | attr_reader :valuename 168 | 169 | # Combines a registry key path and valuename into a resource title for 170 | # registry_value resource. 171 | # 172 | # To maintain backwards compatibility, only use the double backslash 173 | # delimiter if the valuename actually contains a backslash 174 | def self.combine_path_and_value(keypath, valuename) 175 | if valuename.include?('\\') 176 | "#{keypath}\\\\#{valuename}" 177 | else 178 | "#{keypath}\\#{valuename}" 179 | end 180 | end 181 | 182 | # Extract the valuename from the path and then munge the actual path 183 | def initialize(path) 184 | raise ArgumentError, "Invalid registry key: #{path}" unless path.include?('\\') 185 | 186 | # valuename appears after the the first double backslash 187 | path, @valuename = path.split('\\\\', 2) 188 | # no \\ but there is at least a single \ to split on 189 | path, _, @valuename = path.rpartition('\\') if @valuename.nil? 190 | @is_default = @valuename.empty? 191 | 192 | super(path) 193 | end 194 | 195 | def canonical 196 | # Because we extracted the valuename in the initializer we 197 | # need to add it back in when canonical is called. 198 | if valuename.include?('\\') 199 | "#{filter_path[:canonical]}\\\\#{valuename}" 200 | else 201 | "#{filter_path[:canonical]}\\#{valuename}" 202 | end 203 | end 204 | 205 | def default? 206 | @is_default 207 | end 208 | 209 | def filter_path 210 | result = super 211 | 212 | # It's possible to pass in a path of 'hklm' which can still be parsed, but is not valid registry key. Only the default value 'hklm\' 213 | # and named values 'hklm\something' are allowed 214 | raise ArgumentError, "Invalid registry key: #{path}" if result[:trailing_path].empty? && valuename.empty? && !default? 215 | 216 | result 217 | end 218 | end 219 | end 220 | end 221 | end 222 | -------------------------------------------------------------------------------- /locales/config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # This is the project-specific configuration file for setting up 3 | # fast_gettext for your project. 4 | gettext: 5 | # This is used for the name of the .pot and .po files; they will be 6 | # called .pot? 7 | project_name: puppetlabs-registry 8 | # This is used in comments in the .pot and .po files to indicate what 9 | # project the files belong to and should bea little more desctiptive than 10 | # 11 | package_name: puppetlabs-registry 12 | # The locale that the default messages in the .pot file are in 13 | default_locale: en 14 | # The email used for sending bug reports. 15 | bugs_address: docs@puppet.com 16 | # The holder of the copyright. 17 | copyright_holder: Puppet, Inc. 18 | # This determines which comments in code should be eligible for translation. 19 | # Any comments that start with this string will be externalized. (Leave 20 | # empty to include all.) 21 | comments_tag: TRANSLATOR 22 | # Patterns for +Dir.glob+ used to find all files that might contain 23 | # translatable content, relative to the project root directory 24 | source_files: 25 | - './lib/**/*.rb' 26 | 27 | -------------------------------------------------------------------------------- /manifests/service.pp: -------------------------------------------------------------------------------- 1 | # @summary Defined resource type that manages service entries 2 | # @note 3 | # This defined resource type manages service entries in the Microsoft service 4 | # control framework by managing the appropriate registry keys and values. 5 | # 6 | # This is an alternative approach to using INSTSRV.EXE [1]. 7 | # 8 | # [1] http://support.microsoft.com/kb/137890 9 | # 10 | # @param ensure 11 | # Ensures the presence or absence of a registry key. Valid values: 'present', 'absent', 'UNSET'. 12 | # 13 | # @param display_name 14 | # The Display Name of the service. Defaults to the title of the resource. 15 | # 16 | # @param description 17 | # A description of the service. String value set to 'UNSET' by default. 18 | # 19 | # @param command 20 | # The command to execute. Set to 'UNSET' by default. 21 | # 22 | # @param start 23 | # The starting mode of the service. (Note, the native service 24 | # resource can also be used to manage this setting.) 25 | # Valid values: 'automatic', 'manual', 'disabled' 26 | # 27 | # 28 | # Manages the values in the key HKLM\System\CurrentControlSet\Services\$name\ 29 | # 30 | # @example Sample Usage: 31 | # registry::service { puppet: 32 | # ensure => present, 33 | # display_name => 'Puppet Agent', 34 | # description => 'Periodically fetches and applies 35 | # configurations from a Puppet Server.', 36 | # command => 'C:\PuppetLabs\Puppet\service\daemon.bat', 37 | # } 38 | # 39 | define registry::service ( 40 | Enum['present', 'absent', 'UNSET'] $ensure = 'UNSET', 41 | String[1] $display_name = 'UNSET', 42 | String[1] $description = 'UNSET', 43 | String[1] $command = 'UNSET', 44 | Enum['automatic', 'manual', 'disabled', 'UNSET'] $start = 'UNSET' 45 | ) { 46 | $ensure_real = $ensure ? { 47 | 'UNSET' => present, 48 | 'present' => present, 49 | 'absent' => absent, 50 | } 51 | 52 | $display_name_real = $display_name ? { 53 | 'UNSET' => $name, 54 | default => $display_name, 55 | } 56 | 57 | $description_real = $description ? { 58 | 'UNSET' => $display_name_real, 59 | default => $description, 60 | } 61 | 62 | # FIXME Better validation of the command parameter. 63 | # (Fully qualified path? Though, it will be a REG_EXPAND_SZ.) 64 | $command_real = $command ? { 65 | default => $command, 66 | } 67 | 68 | # Map descriptive names to flags. 69 | $start_real = $start ? { 70 | 'automatic' => 2, 71 | 'manual' => 3, 72 | 'disabled' => 4, 73 | } 74 | 75 | # Variable to hold the base key path. 76 | $service_key = "HKLM\\System\\CurrentControlSet\\Services\\${name}" 77 | 78 | # Manage the key 79 | if $ensure_real == present { 80 | registry_key { $service_key: 81 | ensure => present, 82 | } 83 | } else { 84 | registry_key { $service_key: 85 | ensure => absent, 86 | # REVISIT: purge_values => true, 87 | } 88 | } 89 | 90 | # Manage the values 91 | if $ensure_real == present { 92 | registry_value { "${service_key}\\Description": 93 | ensure => present, 94 | type => string, 95 | data => $description_real, 96 | } 97 | registry_value { "${service_key}\\DisplayName": 98 | ensure => present, 99 | type => string, 100 | data => $display_name_real, 101 | } 102 | registry_value { "${service_key}\\ErrorControl": 103 | ensure => present, 104 | type => dword, 105 | data => 0x00000001, 106 | } 107 | registry_value { "${service_key}\\ImagePath": 108 | ensure => present, 109 | type => expand, 110 | data => $command_real, 111 | } 112 | registry_value { "${service_key}\\ObjectName": 113 | ensure => present, 114 | type => string, 115 | data => 'LocalSystem', 116 | } 117 | registry_value { "${service_key}\\Start": 118 | ensure => present, 119 | type => dword, 120 | data => $start_real, 121 | } 122 | registry_value { "${service_key}\\Type": 123 | ensure => present, 124 | type => dword, 125 | data => 0x00000010, # (16) 126 | } 127 | } 128 | } 129 | # EOF 130 | -------------------------------------------------------------------------------- /manifests/value.pp: -------------------------------------------------------------------------------- 1 | # @summary High level abstraction on top of registry_key and registry_value resources 2 | # 3 | # @note 4 | # This defined resource type provides a higher level of abstraction on top of 5 | # the registry_key and registry_value resources. Using this defined resource 6 | # type, you do not need to explicitly manage the parent key for a particular 7 | # value. Puppet will automatically manage the parent key for you. 8 | # 9 | # @param key 10 | # The path of key the value will placed inside. 11 | # @param value 12 | # The name of the registry value to manage. This will be copied from 13 | # the resource title if not specified. The special value of 14 | # '(default)' may be used to manage the default value of the key. 15 | # @param type 16 | # The type the registry value. Defaults to 'string'. See the output of 17 | # `puppet describe registry_value` for a list of supported types in the 18 | # "type" parameter. 19 | # @param data 20 | # The data to place inside the registry value. 21 | # 22 | # Actions: 23 | # - Manage the parent key if not already managed. 24 | # - Manage the value 25 | # 26 | # Requires: 27 | # - Registry Module 28 | # - Stdlib Module 29 | # 30 | # 31 | # @example This example will automatically manage the key. It will also create a value named 'puppetserver' inside this key. 32 | # class myapp { 33 | # registry::value { 'puppetserver': 34 | # key => 'HKLM\Software\Vendor\PuppetLabs', 35 | # data => 'puppet.puppetlabs.com', 36 | # } 37 | # } 38 | # 39 | define registry::value ( 40 | Pattern[/^\w+/] $key, 41 | Optional[String] $value = undef, 42 | Pattern[/^\w+/] $type = 'string', 43 | Optional[Variant[ 44 | String, 45 | Numeric, 46 | Array[String] 47 | ]] $data = undef, 48 | ) { 49 | # ensure windows os 50 | if $facts['os']['name'] != 'windows' { 51 | fail("Unsupported OS ${facts['os']['name']}") 52 | } 53 | 54 | $value_real = $value ? { 55 | undef => $name, 56 | '(default)' => '', 57 | default => $value, 58 | } 59 | 60 | # Resource defaults. 61 | Registry_key { ensure => present } 62 | Registry_value { ensure => present } 63 | 64 | if !defined(Registry_key[$key]) { 65 | registry_key { $key: } 66 | } 67 | 68 | # If value_real is an empty string then the default value of the key will be 69 | # managed. Use a double backslash so value names with a backslash are supported 70 | registry_value { "${key}\\\\${value_real}": 71 | type => $type, 72 | data => $data, 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "puppetlabs-registry", 3 | "version": "5.0.3", 4 | "author": "puppetlabs", 5 | "summary": "This module provides a native type and provider to manage keys and values in the Windows Registry", 6 | "license": "Apache-2.0", 7 | "source": "git://github.com/puppetlabs/puppetlabs-registry.git", 8 | "project_page": "https://github.com/puppetlabs/puppetlabs-registry", 9 | "issues_url": "https://github.com/puppetlabs/puppetlabs-registry/issues", 10 | "dependencies": [ 11 | 12 | ], 13 | "operatingsystem_support": [ 14 | { 15 | "operatingsystem": "Windows", 16 | "operatingsystemrelease": [ 17 | "10", 18 | "2012", 19 | "2012 R2", 20 | "2016", 21 | "2019", 22 | "2022" 23 | ] 24 | } 25 | ], 26 | "requirements": [ 27 | { 28 | "name": "puppet", 29 | "version_requirement": ">= 7.0.0 < 9.0.0" 30 | } 31 | ], 32 | "description": "This module provides a native type and provider to manage keys and values in the Windows Registry", 33 | "pdk-version": "3.2.0", 34 | "template-url": "https://github.com/puppetlabs/pdk-templates.git#main", 35 | "template-ref": "tags/3.2.0.4-0-g5d17ec1" 36 | } 37 | -------------------------------------------------------------------------------- /pdk.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: [] 3 | -------------------------------------------------------------------------------- /provision.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | default: 3 | provisioner: abs 4 | images: 5 | - win-2016-x86_64 6 | release_checks: 7 | provisioner: abs 8 | images: 9 | - win-2008-x86_64 10 | - win-2008r2-x86_64 11 | - win-2012-x86_64 12 | - win-2012r2-x86_64 13 | - win-2016-core-x86_64 14 | - win-2019-core-x86_64 15 | - win-7-x86_64 16 | - win-81-x86_64 17 | - win-10-pro-x86_64 18 | vagrant: 19 | provisioner: vagrant 20 | images: 21 | - gusztavvargadr/windows-server 22 | release_checks_7: 23 | provisioner: abs 24 | images: 25 | - win-2012r2-x86_64 26 | - win-2016-core-x86_64 27 | - win-2019-core-x86_64 28 | - win-10-pro-x86_64 29 | -------------------------------------------------------------------------------- /spec/acceptance/registry_management_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper_acceptance' 4 | 5 | describe 'Registry Management' do 6 | before(:all) do 7 | # use this unique keyname and keypath for all tests 8 | @keyname = "PuppetLabsTest_#{random_string(8)}" 9 | end 10 | 11 | let(:arch_prefix) { (host_inventory['facter']['architecture'] == 'x64') ? '32:' : '' } 12 | let(:keypath) { "HKLM\\Software\\Vendor\\#{@keyname}" } # rubocop:disable RSpec/InstanceVariable 13 | 14 | let(:create) do 15 | <<-CREATE 16 | # use a different case here, to exercise the case-conversion codepaths 17 | registry_key { 'HKLM\\Software\\VENDOR': ensure => present } 18 | 19 | registry_key { '#{keypath}': ensure => 'present' } 20 | registry_key { '#{keypath}\\SubKey1': ensure => present } 21 | 22 | registry_key { '#{keypath}\\SubKeyToPurge': ensure => present } 23 | 24 | registry_value { '#{keypath}\\SubKeyToPurge\\Value1': data => 'Test Data1' } 25 | # use a different case here, to exercise the case-conversion codepaths 26 | registry_value { '#{keypath}\\SUBKEYTOPURGE\\Value2': data => 'Test Data2' } 27 | registry_value { '#{keypath}\\SubKeyToPurge\\Value3': data => 'Test Data3' } 28 | 29 | registry_value { '#{keypath}\\SubKey1\\\\': 30 | data => "Some Data", 31 | } 32 | 33 | registry_value { '#{keypath}\\SubKey1\\ValueArray': 34 | type => array, 35 | data => [ "content", "array element" ], 36 | } 37 | 38 | registry_value { '#{keypath}\\SubKey1\\ValueExpand': 39 | type => expand, 40 | data => "%SystemRoot% - a REG_EXPAND_SZ value", 41 | } 42 | 43 | registry_value { '#{keypath}\\SubKey1\\ValueDword': 44 | type => dword, 45 | data => 42, 46 | } 47 | 48 | registry_value { '#{keypath}\\SubKey1\\ValueQword': 49 | type => qword, 50 | data => 99, 51 | } 52 | 53 | registry_value { '#{keypath}\\SubKey1\\ValueBinary': 54 | type => binary, 55 | data => "DE AD BE EF CA FE" 56 | } 57 | 58 | # 32bit and registry::value testing 59 | registry::value { 'some_value': 60 | key => '32:HKLM\\Software\\VENDOR\\PuppetLabs_32bits', 61 | data => "32bit string", 62 | } 63 | CREATE 64 | end 65 | 66 | let(:update) do 67 | <<-UPDATE 68 | registry_key { '#{keypath}\\SubKeyToPurge': 69 | ensure => present, 70 | purge_values => true, 71 | } 72 | 73 | registry_value { '#{keypath}\\SubKey1\\\\': 74 | data => "Some Updated Data", 75 | } 76 | 77 | registry_value { '#{keypath}\\SubKey1\\ValueArray': 78 | type => array, 79 | data => [ "content", "array element", "additional element" ], 80 | } 81 | 82 | registry_value { '#{keypath}\\SubKey1\\ValueExpand': 83 | type => expand, 84 | data => "%SystemRoot% - an updated REG_EXPAND_SZ value", 85 | } 86 | 87 | registry_value { '#{keypath}\\SubKey1\\ValueDword': 88 | type => dword, 89 | data => 17, 90 | } 91 | 92 | registry_value { '#{keypath}\\SubKey1\\ValueQword': 93 | type => qword, 94 | data => 53, 95 | } 96 | 97 | registry_value { '#{keypath}\\SubKey1\\ValueBinary': 98 | type => binary, 99 | data => "AB CD EF 16 32" 100 | } 101 | 102 | # 32bit and registry::value testing 103 | registry::value { 'some_value': 104 | key => '32:HKLM\\Software\\VENDOR\\PuppetLabs_32bits', 105 | data => "updated 32bit string", 106 | } 107 | UPDATE 108 | end 109 | 110 | let(:delete) do 111 | <<-DELETE 112 | Registry_key { ensure => absent } 113 | 114 | # These have relationships because autorequire break things when 115 | # ensure is absent. REVISIT: Make this not a requirement. 116 | # REVISIT: This appears to work with explicit relationships but not with -> 117 | # notation. 118 | registry_key { '#{keypath}\\SubKey1': } 119 | registry_key { '#{keypath}\\SubKeyToPurge': } 120 | registry_key { '#{keypath}': 121 | require => Registry_key['#{keypath}\\SubKeyToPurge', '#{keypath}\\SubKey1'], 122 | } 123 | 124 | registry_value { [ 125 | '#{keypath}\\SubKey1\\\\', 126 | '#{keypath}\\SubKey1\\ValueArray', 127 | '#{keypath}\\SubKey1\\ValueExpand', 128 | '#{keypath}\\SubKey1\\ValueDword', 129 | '#{keypath}\\SubKey1\\ValueQword', 130 | '#{keypath}\\SubKey1\\ValueBinary', 131 | ]: 132 | ensure => absent 133 | } 134 | 135 | # 32bit and registry::value testing 136 | # registry::value { 'some_value': 137 | # key => '32:HKLM\\Software\\VENDOR\\PuppetLabs_32bits', 138 | # ensure => absent, 139 | # } 140 | registry_value { '32:HKLM\\Software\\VENDOR\\PuppetLabs_32bits\\\\some_value': 141 | ensure => absent, 142 | } 143 | DELETE 144 | end 145 | 146 | it 'creates registry entries' do 147 | expect(idempotent_apply(create)) 148 | end 149 | 150 | it 'update registry entries' do 151 | expect(idempotent_apply(update)) 152 | end 153 | 154 | it 'deletes registry entries' do 155 | expect(idempotent_apply(delete)) 156 | end 157 | end 158 | -------------------------------------------------------------------------------- /spec/classes/mixed_default_settings_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | # The manifest used for testing, is located in spec/fixtures/mixed_default_settings/manifests/init.pp 6 | 7 | # This test is to ensure that the way of setting default values (trailing slash) compiles correctly 8 | # when there is a similar looking path in the manifest. It mixes default and non-default value_names in the same manifest 9 | # 10 | # This manifest attempts to manage two registry values 11 | # 12 | # + HKLM 13 | # + Software 14 | # - foo <-- This is a value called 'foo' in the 'HKLM\Sofware' key. 15 | # | This is the 'hklm\Software\foo' resource 16 | # | 17 | # + foo 18 | # + (default value) <-- This is the default value for a key called 'HKLM\Software\foo'. 19 | # This is the 'hklm\Software\foo\\' resource 20 | # 21 | 22 | describe 'mixed_default_settings' do 23 | it { is_expected.to compile } 24 | 25 | it { is_expected.to contain_registry_value('hklm\Software\foo\\') } 26 | it { is_expected.to contain_registry_value('hklm\Software\foo') } 27 | end 28 | -------------------------------------------------------------------------------- /spec/default_facts.yml: -------------------------------------------------------------------------------- 1 | # Use default_module_facts.yml for module specific facts. 2 | # 3 | # Facts specified here will override the values provided by rspec-puppet-facts. 4 | --- 5 | networking: 6 | ip: "172.16.254.254" 7 | ip6: "FE80:0000:0000:0000:AAAA:AAAA:AAAA" 8 | mac: "AA:AA:AA:AA:AA:AA" 9 | is_pe: false 10 | -------------------------------------------------------------------------------- /spec/defines/value_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'puppet/type/registry_key' 5 | require 'puppet/type/registry_value' 6 | 7 | RSpec.describe 'registry::value', type: :define do 8 | let(:title) { 'value_name' } 9 | 10 | on_supported_os.each do |os, facts| 11 | context "when #{os}" do 12 | let(:facts) do 13 | facts 14 | end 15 | 16 | context 'with an empty key' do 17 | let(:params) { { key: '' } } 18 | 19 | it { is_expected.to compile.and_raise_error(%r{parameter 'key'}) } 20 | end 21 | 22 | context 'with a key specified' do 23 | let(:params) { { key: 'HKLM\Software\Vendor' } } 24 | 25 | it { is_expected.to compile } 26 | 27 | it { 28 | expect(subject).to contain_registry_key('HKLM\Software\Vendor') 29 | .with_ensure('present') 30 | } 31 | 32 | it { 33 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 34 | .with(ensure: 'present', type: 'string', data: nil) 35 | } 36 | 37 | context 'with an empty type' do 38 | let(:params) { super().merge(type: '') } 39 | 40 | it { is_expected.to compile.and_raise_error(%r{parameter 'type'}) } 41 | end 42 | 43 | context 'with untyped string data' do 44 | let(:params) { super().merge(data: 'some string data') } 45 | 46 | it { is_expected.to compile } 47 | 48 | it { 49 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 50 | .with(ensure: 'present', type: 'string', data: 'some string data') 51 | } 52 | end 53 | 54 | arr1 = ['dword', 'qword'] 55 | arr1.each do |type| 56 | context "with #{type} numeric data" do 57 | let(:params) { super().merge(type: type, data: 42) } 58 | 59 | it { is_expected.to compile } 60 | 61 | it { 62 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 63 | .with(ensure: 'present', type: type, data: 42) 64 | } 65 | end 66 | end 67 | 68 | context 'with binary data' do 69 | let(:params) { super().merge(type: 'binary', data: '1') } 70 | 71 | it { is_expected.to compile } 72 | 73 | it { 74 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 75 | .with(ensure: 'present', type: 'binary', data: '1') 76 | } 77 | end 78 | 79 | arr2 = ['string', 'expand'] 80 | arr2.each do |type| 81 | context "with string data typed as '#{type}'" do 82 | let(:params) { super().merge(type: type, data: 'some typed string data') } 83 | 84 | it { is_expected.to compile } 85 | 86 | it { 87 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 88 | .with(ensure: 'present', type: type, data: 'some typed string data') 89 | } 90 | end 91 | end 92 | 93 | context 'with array data' do 94 | let(:params) { super().merge(type: 'array', data: ['JakeTheSnake', 'AndreTheGiant']) } 95 | 96 | it { is_expected.to compile } 97 | 98 | it { 99 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\value_name') 100 | .with(ensure: 'present', type: 'array', data: ['JakeTheSnake', 'AndreTheGiant']) 101 | } 102 | end 103 | 104 | context 'with an empty value name' do 105 | let(:params) { super().merge(value: '(default)') } 106 | 107 | it { is_expected.to compile } 108 | 109 | it { 110 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\') 111 | .with_ensure('present') 112 | } 113 | end 114 | 115 | context 'with a value name override' do 116 | let(:params) { super().merge(value: 'other_name') } 117 | 118 | it { is_expected.to compile } 119 | 120 | it { 121 | expect(subject).to contain_registry_value('HKLM\Software\Vendor\\\\other_name') 122 | .with_ensure('present') 123 | } 124 | end 125 | end 126 | end 127 | end 128 | 129 | context 'when a non-windows platform' do 130 | let(:params) do 131 | { 132 | key: 'foo' 133 | } 134 | end 135 | let(:facts) do 136 | { 137 | os: { name: 'bar' } 138 | } 139 | end 140 | 141 | it { is_expected.to compile.and_raise_error(%r{Unsupported OS bar}) } 142 | end 143 | end 144 | -------------------------------------------------------------------------------- /spec/fixtures/mixed_default_settings/manifests/init.pp: -------------------------------------------------------------------------------- 1 | # mixed_default_settings 2 | class mixed_default_settings { 3 | registry_value { 'hklm\Software\foo\\': 4 | ensure => present, 5 | type => string, 6 | data => 'default', 7 | } 8 | 9 | registry_value { 'hklm\Software\foo': 10 | ensure => present, 11 | type => string, 12 | data => 'nondefault', 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |c| 4 | c.mock_with :rspec 5 | end 6 | 7 | require 'puppetlabs_spec_helper/module_spec_helper' 8 | require 'rspec-puppet-facts' 9 | 10 | require 'spec_helper_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_local.rb')) 11 | 12 | include RspecPuppetFacts 13 | 14 | default_facts = { 15 | puppetversion: Puppet.version, 16 | facterversion: Facter.version, 17 | } 18 | 19 | default_fact_files = [ 20 | File.expand_path(File.join(File.dirname(__FILE__), 'default_facts.yml')), 21 | File.expand_path(File.join(File.dirname(__FILE__), 'default_module_facts.yml')), 22 | ] 23 | 24 | default_fact_files.each do |f| 25 | next unless File.exist?(f) && File.readable?(f) && File.size?(f) 26 | 27 | begin 28 | require 'deep_merge' 29 | default_facts.deep_merge!(YAML.safe_load(File.read(f), permitted_classes: [], permitted_symbols: [], aliases: true)) 30 | rescue StandardError => e 31 | RSpec.configuration.reporter.message "WARNING: Unable to load #{f}: #{e}" 32 | end 33 | end 34 | 35 | # read default_facts and merge them over what is provided by facterdb 36 | default_facts.each do |fact, value| 37 | add_custom_fact fact, value, merge_facts: true 38 | end 39 | 40 | RSpec.configure do |c| 41 | c.default_facts = default_facts 42 | c.before :each do 43 | # set to strictest setting for testing 44 | # by default Puppet runs at warning level 45 | Puppet.settings[:strict] = :warning 46 | Puppet.settings[:strict_variables] = true 47 | end 48 | c.filter_run_excluding(bolt: true) unless ENV['GEM_BOLT'] 49 | c.after(:suite) do 50 | RSpec::Puppet::Coverage.report!(0) 51 | end 52 | 53 | # Filter backtrace noise 54 | backtrace_exclusion_patterns = [ 55 | %r{spec_helper}, 56 | %r{gems}, 57 | ] 58 | 59 | if c.respond_to?(:backtrace_exclusion_patterns) 60 | c.backtrace_exclusion_patterns = backtrace_exclusion_patterns 61 | elsif c.respond_to?(:backtrace_clean_patterns) 62 | c.backtrace_clean_patterns = backtrace_exclusion_patterns 63 | end 64 | end 65 | 66 | # Ensures that a module is defined 67 | # @param module_name Name of the module 68 | def ensure_module_defined(module_name) 69 | module_name.split('::').reduce(Object) do |last_module, next_module| 70 | last_module.const_set(next_module, Module.new) unless last_module.const_defined?(next_module, false) 71 | last_module.const_get(next_module, false) 72 | end 73 | end 74 | 75 | # 'spec_overrides' from sync.yml will appear below this line 76 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'puppet_litmus' 4 | require 'spec_helper_acceptance_local' if File.file?(File.join(File.dirname(__FILE__), 'spec_helper_acceptance_local.rb')) 5 | 6 | PuppetLitmus.configure! 7 | -------------------------------------------------------------------------------- /spec/spec_helper_acceptance_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | def random_string(length) 4 | chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a 5 | str = '' 6 | 1.upto(length) { |_i| str += chars[rand(chars.size - 1)] } 7 | str 8 | end 9 | 10 | def is_x64? 11 | host_inventory['facter']['os']['architecture'] == 'x64' 12 | end 13 | -------------------------------------------------------------------------------- /spec/spec_helper_local.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # We need this because the RAL uses 'should' as a method. This 4 | # allows us the same behaviour but with a different method name. 5 | class Object 6 | alias must should 7 | end 8 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/registry_key_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'puppet/type/registry_key' 5 | 6 | describe Puppet::Type.type(:registry_key).provider(:registry) do 7 | let(:catalog) { Puppet::Resource::Catalog.new } 8 | let(:type) { Puppet::Type.type(:registry_key) } 9 | let(:instance) { instance_double(Win32::Registry) } 10 | 11 | puppet_key = 'SOFTWARE\\Puppet Labs' 12 | subkey_name = 'PuppetRegProviderTest' 13 | 14 | before(:each) do 15 | skip('Not on Windows platform') unless Puppet.features.microsoft_windows? 16 | # problematic Ruby codepath triggers a conversion of UTF-16LE to 17 | # a local codepage which can totally break when that codepage has no 18 | # conversion from the given UTF-16LE characters to local codepage 19 | # a prime example is that IBM437 has no conversion from a Unicode en-dash 20 | 21 | expect(instance).not_to receive(:export_string) 22 | 23 | expect(instance).not_to receive(:delete_value) 24 | expect(instance).not_to receive(:delete_key) 25 | end 26 | 27 | describe '#destroy' do 28 | it 'can destroy a randomly created key' do 29 | guid = SecureRandom.uuid 30 | reg_key = type.new(path: "hklm\\#{puppet_key}\\#{subkey_name}\\#{guid}", provider: described_class.name) 31 | already_exists = reg_key.provider.exists? 32 | expect(already_exists).to be(false) 33 | 34 | # something has gone terribly wrong here, pull the ripcord 35 | break if already_exists 36 | 37 | reg_key.provider.create 38 | reg_key.provider.exists?.should be true 39 | 40 | # test FFI code 41 | reg_key.provider.destroy 42 | reg_key.provider.exists?.should be false 43 | end 44 | end 45 | 46 | describe '#purge_values' do 47 | let(:guid) { SecureRandom.uuid } 48 | let(:reg_path) { "#{puppet_key}\\#{subkey_name}\\Unicode-#{guid}" } 49 | 50 | def bytes_to_utf8(bytes) 51 | bytes.pack('c*').force_encoding(Encoding::UTF_8) 52 | end 53 | 54 | before(:each) do 55 | skip('Not on Windows platform') unless Puppet.features.microsoft_windows? 56 | end 57 | 58 | after(:each) do 59 | reg_key = type.new(path: "hklm\\#{reg_path}", provider: described_class.name) 60 | reg_key.provider.destroy 61 | 62 | reg_key.provider.exists?.should be_falsey 63 | end 64 | 65 | context 'with ANSI strings on all Ruby platforms' do 66 | before(:each) do 67 | Win32::Registry::HKEY_LOCAL_MACHINE.create(reg_path, 68 | Win32::Registry::KEY_ALL_ACCESS | 69 | PuppetX::Puppetlabs::Registry::KEY_WOW64_64KEY) do |reg_key| 70 | reg_key.write('hi', Win32::Registry::REG_SZ, 'yes') 71 | end 72 | end 73 | 74 | it 'does not raise an error' do 75 | reg_key = type.new(catalog: catalog, 76 | ensure: :absent, 77 | name: "hklm\\#{reg_path}", 78 | purge_values: true, 79 | provider: described_class.name) 80 | 81 | catalog.add_resource(reg_key) 82 | 83 | expect { reg_key.eval_generate }.not_to raise_error 84 | end 85 | end 86 | 87 | context 'with unicode' do 88 | before(:each) do 89 | skip('Not on Windows platform with Ruby version 2.x') unless Puppet.features.microsoft_windows? && RUBY_VERSION =~ %r{^2\.} 90 | # create temp registry key with Unicode values 91 | Win32::Registry::HKEY_LOCAL_MACHINE.create(reg_path, 92 | Win32::Registry::KEY_ALL_ACCESS | 93 | PuppetX::Puppetlabs::Registry::KEY_WOW64_64KEY) do |reg_key| 94 | endash = bytes_to_utf8([0xE2, 0x80, 0x93]) 95 | tm = bytes_to_utf8([0xE2, 0x84, 0xA2]) 96 | 97 | reg_key.write(endash, Win32::Registry::REG_SZ, tm) 98 | end 99 | end 100 | 101 | it 'does not use Rubys each_value, which unnecessarily string encodes' do 102 | # endash and tm undergo LOCALE conversion during Rubys each_value 103 | # which will generally lead to a conversion exception 104 | reg_key = type.new(catalog: catalog, 105 | ensure: :absent, 106 | name: "hklm\\#{reg_path}", 107 | purge_values: true, 108 | provider: described_class.name) 109 | 110 | catalog.add_resource(reg_key) 111 | 112 | # this will trigger 113 | expect { reg_key.eval_generate }.not_to raise_error 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /spec/unit/puppet/provider/registry_value_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'puppet/type/registry_value' 5 | 6 | describe Puppet::Type.type(:registry_value).provider(:registry) do 7 | let(:catalog) { Puppet::Resource::Catalog.new } 8 | let(:type) { Puppet::Type.type(:registry_value) } 9 | let(:instance) { instance_double(Win32::Registry) } 10 | 11 | puppet_key = 'SOFTWARE\\Puppet Labs' 12 | subkey_name = 'PuppetRegProviderTest' 13 | 14 | before(:all) do # rubocop:disable RSpec/BeforeAfterAll 15 | if Puppet.features.microsoft_windows? 16 | Win32::Registry::HKEY_LOCAL_MACHINE.create("#{puppet_key}\\#{subkey_name}", 17 | Win32::Registry::KEY_ALL_ACCESS | 18 | PuppetX::Puppetlabs::Registry::KEY_WOW64_64KEY) 19 | end 20 | end 21 | 22 | before(:each) do 23 | skip('Not on Windows platform') unless Puppet.features.microsoft_windows? 24 | # problematic Ruby codepath triggers a conversion of UTF-16LE to 25 | # a local codepage which can totally break when that codepage has no 26 | # conversion from the given UTF-16LE characters to local codepage 27 | # a prime example is that IBM437 has no conversion from a Unicode en-dash 28 | 29 | expect(instance).not_to receive(:export_string) 30 | 31 | expect(instance).not_to receive(:delete_value) 32 | expect(instance).not_to receive(:delete_key) 33 | 34 | if RUBY_VERSION >= '2.1' 35 | # also, expect that we're not using Rubys each_key / each_value which exhibit bad behavior 36 | expect(instance).not_to receive(:each_key) 37 | expect(instance).not_to receive(:each_value) 38 | 39 | # this covers []= write_s write_i and write_bin 40 | expect(instance).not_to receive(:write) 41 | end 42 | end 43 | 44 | after(:all) do # rubocop:disable RSpec/BeforeAfterAll 45 | if Puppet.features.microsoft_windows? 46 | # Ruby 2.1.5 has bugs with deleting registry keys due to using ANSI 47 | # character APIs, but passing wide strings to them (facepalm) 48 | # https://github.com/ruby/ruby/blob/v2_1_5/ext/win32/lib/win32/registry.rb#L323-L329 49 | # therefore, use our own code instead of hklm.delete_value 50 | 51 | # NOTE: registry_value tests unfortunately depend on registry_key type 52 | # otherwise, there would be a bit of Win32 API code here 53 | reg_key = Puppet::Type.type(:registry_key).new(path: "hklm\\#{puppet_key}\\#{subkey_name}", 54 | provider: :registry) 55 | reg_key.provider.destroy 56 | end 57 | end 58 | 59 | describe '#exists?' do 60 | it 'returns true for a well known hive' do 61 | reg_value = type.new(title: 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareType', provider: described_class.name) 62 | expect(reg_value.provider.exists?).to be(true) 63 | end 64 | 65 | it 'returns true for a well known hive with mixed case name' do 66 | reg_value = type.new(title: 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareType'.upcase, provider: described_class.name) 67 | expect(reg_value.provider.exists?).to be(true) 68 | end 69 | 70 | it 'returns true for a well known hive with double backslash' do 71 | reg_value = type.new(title: 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\\\\SoftwareType', provider: described_class.name) 72 | expect(reg_value.provider.exists?).to be(true) 73 | end 74 | 75 | it 'returns true for a well known hive with mixed case name with double backslash' do 76 | reg_value = type.new(title: 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\\\\SoftwareType'.upcase, provider: described_class.name) 77 | expect(reg_value.provider.exists?).to be(true) 78 | end 79 | 80 | it 'returns false for a bogus hive/path' do 81 | reg_value = type.new(path: 'hklm\foobar5000', catalog: catalog, provider: described_class.name) 82 | expect(reg_value.provider.exists?).to be(false) 83 | end 84 | end 85 | 86 | describe '#regvalue' do 87 | it 'returns a valid string for a well known key' do 88 | reg_value = type.new(path: 'hklm\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot', provider: described_class.name) 89 | expect(reg_value.provider.data).to equal([ENV.fetch('SystemRoot', nil)]) 90 | expect(reg_value.provider.type).to equal(:string) 91 | end 92 | 93 | it 'returns a string of lowercased hex encoded bytes' do 94 | reg = described_class.new 95 | _type, data = reg.from_native([3, "\u07AD"]) 96 | expect(data).to equal(['de ad']) 97 | end 98 | 99 | it 'left pads binary strings' do 100 | reg = described_class.new 101 | _type, data = reg.from_native([3, "\x1"]) 102 | expect(data).to equal(['01']) 103 | end 104 | end 105 | 106 | describe '#destroy' do 107 | let(:default_path) { _path = "hklm\\#{puppet_key}\\#{subkey_name}\\" } 108 | let(:valuename) { SecureRandom.uuid } 109 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\#{valuename}" } 110 | 111 | def create_and_destroy(path, reg_type, data) 112 | reg_value = type.new(path: path, 113 | type: reg_type, 114 | data: data, 115 | provider: described_class.name) 116 | already_exists = reg_value.provider.exists? 117 | expect(already_exists).to be(false) 118 | # something has gone terribly wrong here, pull the ripcord 119 | raise if already_exists 120 | 121 | reg_value.provider.create 122 | expect(reg_value.provider.exists?).to be(true) 123 | expect(reg_value.provider.data).to eq([data].flatten) 124 | 125 | reg_value.provider.destroy 126 | expect(reg_value.provider.exists?).to be(false) 127 | end 128 | 129 | context 'with a valuename containing a middle double backslash' do 130 | let(:valuename) { SecureRandom.uuid.insert(5, '\\\\') } 131 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\\\#{valuename}" } 132 | 133 | it 'can destroy a randomly created REG_SZ value' do 134 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 135 | end 136 | end 137 | 138 | context 'with a valuename containing a leading double backslash' do 139 | let(:valuename) { "\\\\#{SecureRandom.uuid}" } 140 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\\\#{valuename}" } 141 | 142 | it 'can destroy a randomly created REG_SZ value' do 143 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 144 | end 145 | end 146 | 147 | context 'with a valuename containing a trailing double backslash' do 148 | let(:valuename) { "#{SecureRandom.uuid}\\\\" } 149 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\\\#{valuename}" } 150 | 151 | it 'can destroy a randomly created REG_SZ value' do 152 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 153 | end 154 | end 155 | 156 | context 'with a valuename of a backslash' do 157 | let(:valuename) { '\\' } 158 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\\\#{valuename}" } 159 | 160 | it 'can destroy a randomly created REG_SZ value' do 161 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 162 | end 163 | end 164 | 165 | context 'with a valuename containing a backslash' do 166 | let(:valuename) { SecureRandom.uuid.insert(5, '\\') } 167 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\\\#{valuename}" } 168 | 169 | it 'can destroy a randomly created REG_SZ value' do 170 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 171 | end 172 | 173 | it 'can destroy a randomly created REG_EXPAND_SZ value' do 174 | expect(create_and_destroy(path, :expand, "#{SecureRandom.uuid} system root is %SystemRoot%")).to be(true) 175 | end 176 | 177 | it 'can destroy a randomly created REG_BINARY value' do 178 | expect(create_and_destroy(path, :binary, '01 01 10 10')).to be(true) 179 | end 180 | 181 | it 'can destroy a randomly created REG_DWORD value' do 182 | expect(create_and_destroy(path, :dword, rand((2**32) - 1))).to be(true) 183 | end 184 | 185 | it 'can destroy a randomly created REG_QWORD value' do 186 | expect(create_and_destroy(path, :qword, rand((2**64) - 1))).to be(true) 187 | end 188 | 189 | it 'can destroy a randomly created REG_MULTI_SZ value' do 190 | expect(create_and_destroy(path, :array, [SecureRandom.uuid, SecureRandom.uuid])).to be(true) 191 | end 192 | end 193 | 194 | it 'can destroy a randomly created default REG_SZ value' do 195 | expect(create_and_destroy(default_path, :string, SecureRandom.uuid)).to be(true) 196 | end 197 | 198 | it 'can destroy a randomly created REG_SZ value' do 199 | expect(create_and_destroy(path, :string, SecureRandom.uuid)).to be(true) 200 | end 201 | 202 | it 'can destroy a randomly created REG_EXPAND_SZ value' do 203 | expect(create_and_destroy(path, :expand, "#{SecureRandom.uuid} system root is %SystemRoot%")).to be(true) 204 | end 205 | 206 | it 'can destroy a randomly created REG_BINARY value' do 207 | expect(create_and_destroy(path, :binary, '01 01 10 10')).to be(true) 208 | end 209 | 210 | it 'can destroy a randomly created REG_DWORD value' do 211 | expect(create_and_destroy(path, :dword, rand((2**32) - 1))).to be(true) 212 | end 213 | 214 | it 'can destroy a randomly created REG_QWORD value' do 215 | expect(create_and_destroy(path, :qword, rand((2**64) - 1))).to be(true) 216 | end 217 | 218 | it 'can destroy a randomly created REG_MULTI_SZ value' do 219 | expect(create_and_destroy(path, :array, [SecureRandom.uuid, SecureRandom.uuid])).to be(true) 220 | end 221 | end 222 | 223 | context 'when writing numeric values' do 224 | let(:path) { "hklm\\#{puppet_key}\\#{subkey_name}\\#{SecureRandom.uuid}" } 225 | 226 | after(:each) do 227 | reg_value = type.new(path: path, provider: described_class.name) 228 | 229 | reg_value.provider.destroy 230 | end 231 | 232 | def write_and_read_value(path, reg_type, value) 233 | reg_value = type.new(path: path, 234 | type: reg_type, 235 | data: value, 236 | provider: described_class.name) 237 | 238 | reg_value.provider.create 239 | expect(reg_value.provider).to be_exists 240 | expect(reg_value.provider.type).to eq(reg_type) 241 | 242 | written = reg_value.provider.data.first 243 | expect(written).to eq(value) 244 | end 245 | 246 | # values chosen at 1 bit past previous byte boundary 247 | [0xFF + 1, 0xFFFF + 1, 0xFFFFFF + 1, 0xFFFFFFFF].each do |value| 248 | it 'properly round-trips written values by converting endianness properly - 1' do 249 | expect(idempotent_apply(write_and_read_value(path, :dword, value))).to be(true) 250 | end 251 | end 252 | 253 | [0xFFFFFFFFFF + 1, 0xFFFFFFFFFFFF + 1, 0xFFFFFFFFFFFFFF + 1, 0xFFFFFFFFFFFFFFFF].each do |value| 254 | it 'properly round-trips written values by converting endianness properly - 2' do 255 | expect(write_and_read_value(path, :qword, value)).to be(true) 256 | end 257 | end 258 | end 259 | 260 | context 'when reading non-ASCII values' do 261 | ENDASH_UTF_8 = [0xE2, 0x80, 0x93].freeze 262 | ENDASH_UTF_16 = [0x2013].freeze 263 | TM_UTF_8 = [0xE2, 0x84, 0xA2].freeze 264 | TM_UTF_16 = [0x2122].freeze 265 | 266 | let(:guid) { SecureRandom.uuid } 267 | 268 | after(:each) do 269 | # Ruby 2.1.5 has bugs with deleting registry keys due to using ANSI 270 | # character APIs, but passing wide strings to them (facepalm) 271 | # https://github.com/ruby/ruby/blob/v2_1_5/ext/win32/lib/win32/registry.rb#L323-L329 272 | # therefore, use our own code instead of hklm.delete_value 273 | 274 | reg_value = type.new(path: "hklm\\#{puppet_key}\\#{subkey_name}\\#{guid}", 275 | provider: described_class.name) 276 | 277 | reg_value.provider.destroy 278 | reg_value.provider.exists?.should be_falsey 279 | end 280 | 281 | # proof that there is no conversion to local encodings like IBM437 282 | it 'will return a UTF-8 string from a REG_SZ registry value (written as UTF-16LE)' do 283 | skip('Not on Windows platform with Ruby version greater than or equal to 2.1') unless Puppet.features.microsoft_windows? && RUBY_VERSION >= '2.1' 284 | 285 | # create a UTF-16LE byte array representing "–™" 286 | utf_16_bytes = ENDASH_UTF_16 + TM_UTF_16 287 | utf_16_str = utf_16_bytes.pack('s*').force_encoding(Encoding::UTF_16LE) 288 | 289 | # and it's UTF-8 equivalent bytes 290 | utf_8_bytes = ENDASH_UTF_8 + TM_UTF_8 291 | utf_8_str = utf_8_bytes.pack('c*').force_encoding(Encoding::UTF_8) 292 | 293 | reg_value = type.new(path: "hklm\\#{puppet_key}\\#{subkey_name}\\#{guid}", 294 | type: :string, 295 | data: utf_16_str, 296 | provider: described_class.name) 297 | 298 | already_exists = reg_value.provider.exists? 299 | already_exists.should be_falsey 300 | 301 | reg_value.provider.create 302 | expect(reg_value.provider.exists?).to be(true) 303 | 304 | expect(reg_value.provider.data.length).to eq(1) 305 | expect(reg_value.provider.type).to eq(:string) 306 | 307 | # The UTF-16LE string written should come back as the equivalent UTF-8 308 | written = reg_value.provider.data.first 309 | expect(written).to eq(utf_8_str) 310 | expect(written.encoding).to eq(Encoding::UTF_8) 311 | end 312 | end 313 | end 314 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/registry_key_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'puppet/resource' 5 | require 'puppet/resource/catalog' 6 | require 'puppet/type/registry_key' 7 | 8 | describe Puppet::Type.type(:registry_key) do 9 | let(:catalog) { Puppet::Resource::Catalog.new } 10 | 11 | # This is overridden here so we get a consistent association with the key 12 | # and a catalog using memoized let methods. 13 | let(:key) { Puppet::Type.type(:registry_key).new(name: 'HKLM\Software', catalog: catalog) } 14 | let(:provider) { Puppet::Provider.new(key) } 15 | 16 | before(:each) do 17 | key.provider = provider 18 | end 19 | 20 | [:ensure].each do |property| 21 | it "has a #{property} property" do 22 | expect(described_class.attrclass(property).ancestors).to be_include(Puppet::Property) 23 | end 24 | 25 | it "has documentation for its #{property} property" do 26 | expect(described_class.attrclass(property).doc).to be_instance_of(String) 27 | end 28 | end 29 | 30 | describe 'path parameter' do 31 | it 'has a path parameter' do 32 | expect(Puppet::Type.type(:registry_key).attrtype(:path).must == :param) 33 | end 34 | 35 | # rubocop:disable RSpec/RepeatedExample,RSpec/RepeatedDescription 36 | ['hklm', 'hklm\\software', 'hklm\\software\\vendor'].each do |path| 37 | it "accepts #{path}" do 38 | expect(key[:path] = path) 39 | end 40 | end 41 | 42 | ['hku', 'hku\\.DEFAULT', 'hku\\.DEFAULT\\software', 'hku\\.DEFAULT\\software\\vendor'].each do |path| 43 | it "accepts #{path}" do 44 | expect(key[:path] = path) 45 | end 46 | end 47 | # rubocop:enable RSpec/RepeatedExample,RSpec/RepeatedDescription 48 | 49 | ['HKEY_DYN_DATA', 'HKEY_PERFORMANCE_DATA'].each do |path| 50 | it "rejects #{path} as unsupported case insensitively" do 51 | expect { key[:path] = path }.to raise_error(Puppet::Error, %r{Unsupported}) 52 | end 53 | end 54 | 55 | ['hklm\\', 'hklm\\foo\\', 'unknown', 'unknown\\subkey', '\\:hkey'].each do |path| 56 | it "rejects #{path} as invalid" do 57 | path = "hklm\\#{'a' * 256}" 58 | expect { key[:path] = path }.to raise_error(Puppet::Error, %r{Invalid registry key}) 59 | end 60 | end 61 | 62 | ['HKLM', 'HKEY_LOCAL_MACHINE', 'hklm'].each do |root| 63 | it "canonicalizes the root key #{root}" do 64 | expect(key[:path] = root) 65 | expect(key[:path].must == 'hklm') 66 | end 67 | end 68 | 69 | it 'should be case-preserving' 70 | it 'should be case-insensitive' 71 | it 'should autorequire ancestor keys' 72 | it 'supports 32-bit keys' do 73 | expect(key[:path] = '32:hklm\software') 74 | end 75 | end 76 | 77 | describe '#eval_generate' do 78 | context 'without purging' do 79 | it 'returns an empty array' do 80 | expect(key.eval_generate.must(be_empty)) 81 | end 82 | end 83 | 84 | context 'when purging' do 85 | let(:catalog) { Puppet::Resource::Catalog.new } 86 | 87 | # This is overridden here so we get a consistent association with the key 88 | # and a catalog using memoized let methods. 89 | let(:key) { Puppet::Type.type(:registry_key).new(name: 'HKLM\Software', catalog: catalog) } 90 | 91 | before :each do 92 | key[:purge_values] = true 93 | catalog.add_resource(key) 94 | catalog.add_resource(Puppet::Type.type(:registry_value).new(path: "#{key[:path]}\\val1", catalog: catalog)) 95 | catalog.add_resource(Puppet::Type.type(:registry_value).new(path: "#{key[:path]}\\vAl2", catalog: catalog)) 96 | catalog.add_resource(Puppet::Type.type(:registry_value).new(path: "#{key[:path]}\\\\val\\3", catalog: catalog)) 97 | end 98 | 99 | it "returns an empty array if the key doesn't have any values" do 100 | expect(key.provider).to receive(:values).and_return([]) 101 | key.eval_generate.must be_empty 102 | end 103 | 104 | # rubocop:disable Lint/Void 105 | it 'purges existing values that are not being managed (without backslash)' do 106 | expect(key.provider).to receive(:values).and_return(['val1', 'val\3', 'val99']) 107 | resources = key.eval_generate 108 | resources.count.must == 1 109 | res = resources.first 110 | 111 | res[:ensure].must == :absent 112 | res[:path].must == "#{key[:path]}\\val99" 113 | end 114 | 115 | it 'purges existing values that are not being managed (with backslash)' do 116 | expect(key.provider).to receive(:values).and_return(['val1', 'val\3', 'val\99']) 117 | 118 | resources = key.eval_generate 119 | resources.count.must == 1 120 | res = resources.first 121 | 122 | res[:ensure].must == :absent 123 | res[:path].must == "#{key[:path]}\\\\val\\99" 124 | end 125 | 126 | it 'purges existing values that are not being managed and case insensitive)' do 127 | expect(key.provider).to receive(:values).and_return(['VAL1', 'VaL\3', 'Val99']) 128 | resources = key.eval_generate 129 | resources.count.must == 1 130 | res = resources.first 131 | 132 | res[:ensure].must == :absent 133 | res[:path].must == "#{key[:path]}\\Val99" 134 | end 135 | # rubocop:enable Lint/Void 136 | 137 | it 'returns an empty array if all existing values are being managed' do 138 | expect(key.provider).to receive(:values).and_return(['val1', 'val2', 'val\3']) 139 | key.eval_generate.must be_empty 140 | end 141 | end 142 | end 143 | 144 | describe 'resource aliases' do 145 | let :the_catalog do 146 | Puppet::Resource::Catalog.new 147 | end 148 | 149 | let(:the_resource_name) { 'HKLM\Software\Vendor\PuppetLabs' } 150 | 151 | let :the_resource do 152 | # JJM Holy cow this is an intertangled mess. ;) 153 | resource = Puppet::Type.type(:registry_key).new(name: the_resource_name, catalog: the_catalog) 154 | the_catalog.add_resource resource 155 | resource 156 | end 157 | 158 | it 'initializes the catalog instance variable' do 159 | expect(the_resource.catalog.must(be the_catalog)) 160 | end 161 | 162 | it 'allows case insensitive lookup using the downcase path' do 163 | expect(the_resource.must(be the_catalog.resource(:registry_key, the_resource_name.downcase))) 164 | end 165 | 166 | it 'preserves the case of the user specified path' do 167 | expect(the_resource.must(be the_catalog.resource(:registry_key, the_resource_name))) 168 | end 169 | 170 | it 'returns the same resource regardless of the alias used' do 171 | expect(the_resource.must(be the_catalog.resource(:registry_key, the_resource_name))) 172 | expect(the_resource.must(be the_catalog.resource(:registry_key, the_resource_name.downcase))) 173 | end 174 | end 175 | end 176 | -------------------------------------------------------------------------------- /spec/unit/puppet/type/registry_value_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | require 'puppet/type/registry_value' 5 | 6 | describe Puppet::Type.type(:registry_value) do 7 | let(:catalog) { Puppet::Resource::Catalog.new } 8 | 9 | [:ensure, :type, :data].each do |property| 10 | it "has a #{property} property" do 11 | expect(described_class.attrclass(property).ancestors.should(be_include(Puppet::Property))) 12 | end 13 | 14 | it "has documentation for its #{property} property" do 15 | expect(described_class.attrclass(property).doc.should(be_instance_of(String))) 16 | end 17 | end 18 | 19 | describe 'path parameter' do 20 | it 'has a path parameter' do 21 | expect(Puppet::Type.type(:registry_value).attrtype(:path).should == :param) 22 | end 23 | 24 | # rubocop:disable RSpec/RepeatedExample 25 | ['hklm\\propname', 'hklm\\software\\propname'].each do |path| 26 | it "accepts #{path}" do 27 | expect(described_class.new(path: path, catalog: catalog)) 28 | end 29 | end 30 | 31 | ['hklm\\', 'hklm\\software\\', 'hklm\\software\\vendor\\'].each do |path| 32 | it "accepts the unnamed (default) value: #{path}" do 33 | expect(described_class.new(path: path, catalog: catalog)) 34 | end 35 | end 36 | # rubocop:enable RSpec/RepeatedExample 37 | 38 | it 'strips trailling slashes from unnamed values' do 39 | value = described_class.new(path: 'hklm\\software\\\\', catalog: catalog) 40 | 41 | expect(value[:path]).to eq('hklm\\software\\') 42 | end 43 | 44 | ['HKEY_DYN_DATA\\', 'HKEY_PERFORMANCE_DATA\\name'].each do |path| 45 | it "rejects #{path} as unsupported" do 46 | expect { described_class.new(path: path, catalog: catalog) }.to raise_error(Puppet::Error, %r{Unsupported}) 47 | end 48 | end 49 | 50 | ['hklm', 'hkcr', 'unknown\\name', 'unknown\\subkey\\name'].each do |path| 51 | it "rejects #{path} as invalid" do 52 | expect { described_class.new(path: path, catalog: catalog) }.to raise_error(Puppet::Error, %r{Invalid registry key}) 53 | end 54 | end 55 | 56 | ['HKLM\\name', 'HKEY_LOCAL_MACHINE\\name', 'hklm\\name'].each do |root| 57 | it "canonicalizes root key #{root}" do 58 | value = described_class.new(path: root, catalog: catalog) 59 | expect(value[:path].should == 'hklm\name') 60 | end 61 | end 62 | 63 | ['HKLM\\Software\\\\nam\\e', 'HKEY_LOCAL_MACHINE\\Software\\\\nam\\e', 'hklm\\Software\\\\nam\\e'].each do |root| 64 | it "uses a double backslash when canonicalizing value names with a backslash #{root}" do 65 | value = described_class.new(path: root, catalog: catalog) 66 | expect(value[:path].should == 'hklm\Software\\\\nam\e') 67 | end 68 | end 69 | 70 | { 71 | 'HKLM\\Software\\\\Middle\\\\Slashes' => 'hklm\\Software\\\\Middle\\\\Slashes', 72 | 'HKLM\\Software\\\\\\\\LeadingSlashes' => 'hklm\\Software\\\\\\\\LeadingSlashes', 73 | 'HKLM\\Software\\\\TrailingSlashes\\' => 'hklm\\Software\\\\TrailingSlashes\\', 74 | 'HKLM\\Software\\\\\\' => 'hklm\\Software\\\\\\' # A value name of backslash 75 | }.each do |testcase, expected_value| 76 | it "uses a double backslash as a delimeter between path and value for title #{testcase}" do 77 | value = described_class.new(path: testcase, catalog: catalog) 78 | expect(value[:path].should == expected_value) 79 | end 80 | end 81 | 82 | it 'should validate the length of the value name' 83 | it 'should validate the length of the value data' 84 | it 'should be case-preserving' 85 | it 'should be case-insensitive' 86 | it 'supports 32-bit values' do 87 | expect(_value = described_class.new(path: '32:hklm\software\foo', catalog: catalog)) 88 | end 89 | end 90 | 91 | describe '#autorequire' do 92 | let(:instance) { described_class.new(title: subject_title, catalog: catalog) } 93 | 94 | [ 95 | { 96 | context: 'with a non-default value_name', 97 | reg_value_title: 'hklm\software\foo\bar', 98 | expected_reg_key_title: 'hklm\Software\foo' 99 | }, 100 | { 101 | context: 'with a mixed case path and value_name', 102 | reg_value_title: 'hkLm\soFtwarE\fOo\Bar', 103 | expected_reg_key_title: 'hklm\Software\foo' 104 | }, 105 | { 106 | context: 'with a default value_name', 107 | reg_value_title: 'hklm\software\foo\bar\\', 108 | expected_reg_key_title: 'hklm\Software\foo\bar' 109 | }, 110 | { 111 | context: 'with a value whose parent key is not managed but does have an ancestor key in the catalog', 112 | reg_value_title: 'hklm\software\foo\bar\baz\alice', 113 | expected_reg_key_title: 'hklm\Software\foo\bar' 114 | }, 115 | ].each do |testcase| 116 | context testcase[:context] do 117 | let(:instance) { described_class.new(title: testcase[:reg_value_title], catalog: catalog) } 118 | 119 | it 'does not autorequire ancestor keys if none exist' do 120 | expect(instance.autorequire).to eq([]) 121 | end 122 | 123 | it 'onlies autorequire the nearest ancestor registry_key resource' do 124 | catalog.add_resource(Puppet::Type.type(:registry_key).new(path: 'hklm\Software', catalog: catalog)) 125 | catalog.add_resource(Puppet::Type.type(:registry_key).new(path: 'hklm\Software\foo', catalog: catalog)) 126 | catalog.add_resource(Puppet::Type.type(:registry_key).new(path: 'hklm\Software\foo\bar', catalog: catalog)) 127 | 128 | autorequire_array = instance.autorequire 129 | expect(autorequire_array.count).to eq(1) 130 | expect(autorequire_array[0].to_s).to eq("Registry_key[#{testcase[:expected_reg_key_title]}] => Registry_value[#{testcase[:reg_value_title]}]") 131 | end 132 | end 133 | end 134 | end 135 | 136 | describe 'type property' do 137 | let(:value) { described_class.new(path: 'hklm\software\foo', catalog: catalog) } 138 | 139 | [:string, :array, :dword, :qword, :binary, :expand].each do |type| 140 | it "supports a #{type} type" do 141 | value[:type] = type 142 | expect(value[:type].should == type) 143 | end 144 | end 145 | 146 | it 'rejects other types' do 147 | expect { value[:type] = 'REG_SZ' }.to raise_error(Puppet::Error) 148 | end 149 | end 150 | 151 | describe 'data property' do 152 | let(:value) { described_class.new(path: 'hklm\software\foo', catalog: catalog) } 153 | 154 | context 'with string data' do 155 | ['', 'foobar'].each do |data| 156 | it "accepts '#{data}'" do 157 | value[:type] = :string 158 | expect(value[:data] = data) 159 | end 160 | end 161 | end 162 | 163 | context 'with integer data' do 164 | [:dword, :qword].each do |type| 165 | context "when #{type}" do 166 | arr1 = [0, 0xFFFFFFFF, -1, 42] 167 | arr1.each do |data| 168 | it "accepts #{data}" do 169 | value[:type] = type 170 | expect(value[:data] = data) 171 | end 172 | end 173 | arr2 = ['foobar', ':true'] 174 | arr2.each do |data| 175 | it "rejects #{data}" do 176 | value[:type] = type 177 | expect { value[:data] = data }.to raise_error(Puppet::Error) 178 | end 179 | end 180 | end 181 | end 182 | 183 | context 'when 64-bit integers' do 184 | let(:data) { 0xFFFFFFFFFFFFFFFF } 185 | 186 | it 'accepts qwords' do 187 | value[:type] = :qword 188 | expect(value[:data] = data) 189 | end 190 | 191 | it 'rejects dwords' do 192 | value[:type] = :dword 193 | expect { value[:data] = data }.to raise_error(Puppet::Error) 194 | end 195 | end 196 | end 197 | 198 | context 'when binary data' do 199 | # rubocop:disable RSpec/RepeatedExample 200 | ['', 'CA FE BE EF', 'DEADBEEF'].each do |data| 201 | it "accepts '#{data}'" do 202 | value[:type] = :binary 203 | expect(value[:data] = data) 204 | end 205 | end 206 | [9, '1', 'A'].each do |data| 207 | it "accepts '#{data}' and have a leading zero" do 208 | value[:type] = :binary 209 | expect(value[:data] = data) 210 | end 211 | end 212 | # rubocop:enable RSpec/RepeatedExample 213 | 214 | ["\040\040", 'foobar', true].each do |data| 215 | it "rejects '#{data}'" do 216 | value[:type] = :binary 217 | expect { value[:data] = data }.to raise_error(Puppet::Error) 218 | end 219 | end 220 | end 221 | 222 | context 'when array data' do 223 | it 'supports array data' do 224 | value[:type] = :array 225 | expect(value[:data] = ['foo', 'bar', 'baz']) 226 | end 227 | 228 | it 'supports an empty array' do 229 | value[:type] = :array 230 | expect(value[:data] = []) 231 | end 232 | 233 | [[''], nil, ['', 'foo', 'bar'], ['foo', '', 'bar'], ['foo', 'bar', '']].each do |data| 234 | it "rejects '#{data}'" do 235 | value[:type] = :array 236 | expect { value[:data] = data }.to raise_error(Puppet::Error) 237 | end 238 | end 239 | end 240 | end 241 | end 242 | -------------------------------------------------------------------------------- /spec/watchr.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV['AUTOTEST'] = 'true' 4 | ENV['WATCHR'] = '1' 5 | 6 | system 'clear' 7 | 8 | def growl(message) 9 | growlnotify = `which growlnotify`.chomp 10 | title = 'Watchr Test Results' 11 | image = case message 12 | when %r{(\d+)\s+?(failure|error)}i 13 | (Regexp.last_match(1).to_i == 0) ? '~/.watchr_images/passed.png' : '~/.watchr_images/failed.png' 14 | else 15 | '~/.watchr_images/unknown.png' 16 | end 17 | options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'" 18 | system %(#{growlnotify} #{options} &) 19 | end 20 | 21 | def run(cmd) 22 | puts(cmd) 23 | `#{cmd}` 24 | end 25 | 26 | def run_spec_test(file) 27 | if File.exist? file 28 | result = run "rspec --format d --color #{file}" 29 | growl result.split("\n").last 30 | puts result 31 | else 32 | puts "FIXME: No test #{file} [#{Time.now}]" 33 | end 34 | end 35 | 36 | def filter_rspec(data) 37 | data.split("\n").grep(%r{^(\d+)\s+exampl\w+.*?(\d+).*?failur\w+.*?(\d+).*?pending}).join("\n") 38 | end 39 | 40 | def run_all_tests 41 | system('clear') 42 | files = Dir.glob('spec/**/*_spec.rb').join(' ') 43 | result = run "rspec --format d --color #{files}" 44 | growl_results = filter_rspec result 45 | growl growl_results 46 | puts result 47 | puts "GROWL: #{growl_results}" 48 | end 49 | 50 | # Ctrl-\ 51 | Signal.trap 'QUIT' do 52 | puts " --- Running all tests ---\n\n" 53 | run_all_tests 54 | end 55 | 56 | @interrupted = false 57 | 58 | # Ctrl-C 59 | Signal.trap 'INT' do 60 | if @interrupted 61 | @wants_to_quit = true 62 | abort("\n") 63 | else 64 | puts 'Interrupt a second time to quit' 65 | @interrupted = true 66 | Kernel.sleep 1.5 67 | # raise Interrupt, nil # let the run loop catch it 68 | run_suite 69 | end 70 | end 71 | 72 | def file2spec(file) 73 | _result = file.sub('lib/puppet/', 'spec/unit/puppet/').gsub(%r{\.rb$}, '_spec.rb') 74 | _result = file.sub('lib/facter/', 'spec/unit/facter/').gsub(%r{\.rb$}, '_spec.rb') 75 | end 76 | 77 | watch('spec/.*_spec\.rb') do |_md| 78 | # run_spec_test(md[0]) 79 | run_all_tests 80 | end 81 | watch('lib/.*\.rb') do |_md| 82 | # run_spec_test(file2spec(md[0])) 83 | run_all_tests 84 | end 85 | --------------------------------------------------------------------------------