diff --git a/.rubocop.yml b/.rubocop.yml index b3a8dee..07b68b8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,138 +1,540 @@ --- require: +- rubocop-performance - rubocop-rspec -- rubocop-i18n AllCops: DisplayCopNames: true TargetRubyVersion: '2.4' Include: - - "./**/*.rb" + - "**/*.rb" Exclude: - bin/* - ".vendor/**/*" - "**/Gemfile" - "**/Rakefile" - pkg/**/* - spec/fixtures/**/* - vendor/**/* - "**/Puppetfile" - "**/Vagrantfile" - "**/Guardfile" -Metrics/LineLength: +Layout/LineLength: Description: People have wide screens, use them. Max: 200 -GetText: - Enabled: false -GetText/DecorateString: - Description: We don't want to decorate test output. - Exclude: - - spec/**/* - Enabled: false RSpec/BeforeAfterAll: Description: Beware of using after(:all) as it may cause state to leak between tests. A necessary evil in acceptance testing. Exclude: - spec/acceptance/**/*.rb RSpec/HookArgument: Description: Prefer explicit :each argument, matching existing module's style EnforcedStyle: each Style/BlockDelimiters: Description: Prefer braces for chaining. Mostly an aesthetical choice. Better to be consistent then. EnforcedStyle: braces_for_chaining -Style/BracesAroundHashParameters: - Description: Braces are required by Ruby 2.7. Cop removed from RuboCop v0.80.0. - See https://github.com/rubocop-hq/rubocop/pull/7643 - Enabled: false Style/ClassAndModuleChildren: Description: Compact style reduces the required amount of indentation. EnforcedStyle: compact Style/EmptyElse: Description: Enforce against empty else clauses, but allow `nil` for clarity. EnforcedStyle: empty Style/FormatString: Description: Following the main puppet project's style, prefer the % format format. EnforcedStyle: percent Style/FormatStringToken: Description: Following the main puppet project's style, prefer the simpler template tokens over annotated ones. EnforcedStyle: template Style/Lambda: Description: Prefer the keyword for easier discoverability. EnforcedStyle: literal Style/RegexpLiteral: Description: Community preference. See https://github.com/voxpupuli/modulesync_config/issues/168 EnforcedStyle: percent_r Style/TernaryParentheses: Description: Checks for use of parentheses around ternary conditions. Enforce parentheses on complex expressions for better readability, but seriously consider breaking it up. EnforcedStyle: require_parentheses_when_complex Style/TrailingCommaInArguments: Description: Prefer always trailing comma on multiline argument lists. This makes diffs, and re-ordering nicer. EnforcedStyleForMultiline: comma -Style/TrailingCommaInLiteral: +Style/TrailingCommaInArrayLiteral: Description: Prefer always trailing comma on multiline literals. This makes diffs, and re-ordering nicer. EnforcedStyleForMultiline: comma Style/SymbolArray: Description: Using percent style obscures symbolic intent of array's contents. EnforcedStyle: brackets -inherit_from: ".rubocop_todo.yml" RSpec/MessageSpies: EnforcedStyle: receive Style/Documentation: Exclude: - lib/puppet/parser/functions/**/* - spec/**/* Style/WordArray: EnforcedStyle: brackets +Performance/AncestorsInclude: + Enabled: true +Performance/BigDecimalWithNumericArgument: + Enabled: true +Performance/BlockGivenWithExplicitBlock: + Enabled: true +Performance/Caller: + Enabled: true +Performance/CaseWhenSplat: + Enabled: true +Performance/Casecmp: + Enabled: true +Performance/CollectionLiteralInLoop: + Exclude: + - spec/**/* + Enabled: true +Performance/CompareWithBlock: + Enabled: true +Performance/ConstantRegexp: + Enabled: true +Performance/Count: + Enabled: true +Performance/Detect: + Enabled: true +Performance/DoubleStartEndWith: + Enabled: true +Performance/EndWith: + Enabled: true +Performance/FixedSize: + Enabled: true +Performance/FlatMap: + Enabled: true +Performance/MethodObjectAsBlock: + Enabled: true +Performance/RangeInclude: + Enabled: true +Performance/RedundantBlockCall: + Enabled: true +Performance/RedundantMatch: + Enabled: true +Performance/RedundantMerge: + Enabled: true +Performance/RedundantSortBlock: + Enabled: true +Performance/RedundantStringChars: + Enabled: true +Performance/RegexpMatch: + Enabled: true +Performance/ReverseEach: + Enabled: true +Performance/ReverseFirst: + Enabled: true +Performance/Size: + Enabled: true +Performance/SortReverse: + Enabled: true +Performance/Squeeze: + Enabled: true +Performance/StartWith: + Enabled: true +Performance/StringInclude: + Enabled: true +Performance/StringReplacement: + Enabled: true +Performance/Sum: + Enabled: true +Performance/TimesMap: + Enabled: true Style/CollectionMethods: Enabled: true Style/MethodCalledOnDoEndBlock: Enabled: true Style/StringMethods: Enabled: true -GetText/DecorateFunctionMessage: +Bundler/InsecureProtocolSource: + Enabled: false +Gemspec/DuplicatedAssignment: Enabled: false -GetText/DecorateStringFormattingUsingInterpolation: +Gemspec/OrderedDependencies: Enabled: false -GetText/DecorateStringFormattingUsingPercent: +Gemspec/RequiredRubyVersion: + Enabled: false +Gemspec/RubyVersionGlobalsUsage: + Enabled: false +Layout/ArgumentAlignment: + Enabled: false +Layout/BeginEndAlignment: + Enabled: false +Layout/ClosingHeredocIndentation: + Enabled: false +Layout/EmptyComment: + Enabled: false +Layout/EmptyLineAfterGuardClause: + Enabled: false +Layout/EmptyLinesAroundArguments: + Enabled: false +Layout/EmptyLinesAroundAttributeAccessor: Enabled: false Layout/EndOfLine: Enabled: false -Layout/IndentHeredoc: +Layout/FirstArgumentIndentation: + Enabled: false +Layout/HashAlignment: + Enabled: false +Layout/HeredocIndentation: + Enabled: false +Layout/LeadingEmptyLines: + Enabled: false +Layout/SpaceAroundMethodCallOperator: + Enabled: false +Layout/SpaceInsideArrayLiteralBrackets: + Enabled: false +Layout/SpaceInsideReferenceBrackets: + Enabled: false +Lint/BigDecimalNew: + Enabled: false +Lint/BooleanSymbol: + Enabled: false +Lint/ConstantDefinitionInBlock: + Enabled: false +Lint/DeprecatedOpenSSLConstant: + Enabled: false +Lint/DisjunctiveAssignmentInConstructor: + Enabled: false +Lint/DuplicateBranch: + Enabled: false +Lint/DuplicateElsifCondition: + Enabled: false +Lint/DuplicateRegexpCharacterClassElement: + Enabled: false +Lint/DuplicateRequire: + Enabled: false +Lint/DuplicateRescueException: + Enabled: false +Lint/EmptyBlock: + Enabled: false +Lint/EmptyClass: + Enabled: false +Lint/EmptyConditionalBody: + Enabled: false +Lint/EmptyFile: + Enabled: false +Lint/ErbNewArguments: + Enabled: false +Lint/FloatComparison: + Enabled: false +Lint/HashCompareByIdentity: + Enabled: false +Lint/IdentityComparison: + Enabled: false +Lint/InterpolationCheck: + Enabled: false +Lint/MissingCopEnableDirective: + Enabled: false +Lint/MixedRegexpCaptureTypes: + Enabled: false +Lint/NestedPercentLiteral: + Enabled: false +Lint/NoReturnInBeginEndBlocks: + Enabled: false +Lint/NonDeterministicRequireOrder: + Enabled: false +Lint/OrderedMagicComments: + Enabled: false +Lint/OutOfRangeRegexpRef: + Enabled: false +Lint/RaiseException: + Enabled: false +Lint/RedundantCopEnableDirective: + Enabled: false +Lint/RedundantRequireStatement: + Enabled: false +Lint/RedundantSafeNavigation: + Enabled: false +Lint/RedundantWithIndex: + Enabled: false +Lint/RedundantWithObject: + Enabled: false +Lint/RegexpAsCondition: + Enabled: false +Lint/ReturnInVoidContext: + Enabled: false +Lint/SafeNavigationConsistency: + Enabled: false +Lint/SafeNavigationWithEmpty: + Enabled: false +Lint/SelfAssignment: + Enabled: false +Lint/SendWithMixinArgument: + Enabled: false +Lint/ShadowedArgument: + Enabled: false +Lint/StructNewOverride: + Enabled: false +Lint/ToEnumArguments: + Enabled: false +Lint/ToJSON: + Enabled: false +Lint/TopLevelReturnWithArgument: + Enabled: false +Lint/TrailingCommaInAttributeDeclaration: + Enabled: false +Lint/UnexpectedBlockArity: + Enabled: false +Lint/UnmodifiedReduceAccumulator: + Enabled: false +Lint/UnreachableLoop: + Enabled: false +Lint/UriEscapeUnescape: + Enabled: false +Lint/UriRegexp: + Enabled: false +Lint/UselessMethodDefinition: + Enabled: false +Lint/UselessTimes: Enabled: false Metrics/AbcSize: Enabled: false Metrics/BlockLength: Enabled: false +Metrics/BlockNesting: + Enabled: false Metrics/ClassLength: Enabled: false Metrics/CyclomaticComplexity: Enabled: false Metrics/MethodLength: Enabled: false Metrics/ModuleLength: Enabled: false Metrics/ParameterLists: Enabled: false Metrics/PerceivedComplexity: Enabled: false +Migration/DepartmentName: + Enabled: false +Naming/AccessorMethodName: + Enabled: false +Naming/BlockParameterName: + Enabled: false +Naming/HeredocDelimiterCase: + Enabled: false +Naming/HeredocDelimiterNaming: + Enabled: false +Naming/MemoizedInstanceVariableName: + Enabled: false +Naming/MethodParameterName: + Enabled: false +Naming/RescuedExceptionsVariableName: + Enabled: false +RSpec/Be: + Enabled: false +RSpec/Capybara/CurrentPathExpectation: + Enabled: false +RSpec/Capybara/FeatureMethods: + Enabled: false +RSpec/Capybara/VisibilityMatcher: + Enabled: false +RSpec/ContextMethod: + Enabled: false +RSpec/ContextWording: + Enabled: false RSpec/DescribeClass: Enabled: false +RSpec/EmptyHook: + Enabled: false +RSpec/EmptyLineAfterExample: + Enabled: false +RSpec/EmptyLineAfterExampleGroup: + Enabled: false +RSpec/EmptyLineAfterHook: + Enabled: false RSpec/ExampleLength: Enabled: false -RSpec/MessageExpectation: +RSpec/ExampleWithoutDescription: + Enabled: false +RSpec/ExpectChange: + Enabled: false +RSpec/ExpectInHook: + Enabled: false +RSpec/FactoryBot/AttributeDefinedStatically: + Enabled: false +RSpec/FactoryBot/CreateList: + Enabled: false +RSpec/FactoryBot/FactoryClassName: + Enabled: false +RSpec/HooksBeforeExamples: + Enabled: false +RSpec/ImplicitBlockExpectation: + Enabled: false +RSpec/ImplicitSubject: + Enabled: false +RSpec/LeakyConstantDeclaration: + Enabled: false +RSpec/LetBeforeExamples: + Enabled: false +RSpec/MissingExampleGroupArgument: Enabled: false RSpec/MultipleExpectations: Enabled: false +RSpec/MultipleMemoizedHelpers: + Enabled: false +RSpec/MultipleSubjects: + Enabled: false RSpec/NestedGroups: Enabled: false +RSpec/PredicateMatcher: + Enabled: false +RSpec/ReceiveCounts: + Enabled: false +RSpec/ReceiveNever: + Enabled: false +RSpec/RepeatedExampleGroupBody: + Enabled: false +RSpec/RepeatedExampleGroupDescription: + Enabled: false +RSpec/RepeatedIncludeExample: + Enabled: false +RSpec/ReturnFromStub: + Enabled: false +RSpec/SharedExamples: + Enabled: false +RSpec/StubbedMock: + Enabled: false +RSpec/UnspecifiedException: + Enabled: false +RSpec/VariableDefinition: + Enabled: false +RSpec/VoidExpect: + Enabled: false +RSpec/Yield: + Enabled: false +Security/Open: + Enabled: false +Style/AccessModifierDeclarations: + Enabled: false +Style/AccessorGrouping: + Enabled: false +Style/ArgumentsForwarding: + Enabled: false Style/AsciiComments: Enabled: false +Style/BisectedAttrAccessor: + Enabled: false +Style/CaseLikeIf: + Enabled: false +Style/ClassEqualityComparison: + Enabled: false +Style/CollectionCompact: + Enabled: false +Style/ColonMethodDefinition: + Enabled: false +Style/CombinableLoops: + Enabled: false +Style/CommentedKeyword: + Enabled: false +Style/Dir: + Enabled: false +Style/DocumentDynamicEvalDefinition: + Enabled: false +Style/DoubleCopDisableDirective: + Enabled: false +Style/EmptyBlockParameter: + Enabled: false +Style/EmptyLambdaParameter: + Enabled: false +Style/Encoding: + Enabled: false +Style/EvalWithLocation: + Enabled: false +Style/ExpandPathArguments: + Enabled: false +Style/ExplicitBlockArgument: + Enabled: false +Style/ExponentialNotation: + Enabled: false +Style/FloatDivision: + Enabled: false +Style/GlobalStdStream: + Enabled: false +Style/HashAsLastArrayItem: + Enabled: false +Style/HashLikeCase: + Enabled: false +Style/HashTransformKeys: + Enabled: false +Style/HashTransformValues: + Enabled: false Style/IfUnlessModifier: Enabled: false +Style/KeywordParametersOrder: + Enabled: false +Style/MinMax: + Enabled: false +Style/MixinUsage: + Enabled: false +Style/MultilineWhenThen: + Enabled: false +Style/NegatedIfElseCondition: + Enabled: false +Style/NegatedUnless: + Enabled: false +Style/NilLambda: + Enabled: false +Style/NumericPredicate: + Enabled: false +Style/OptionalBooleanParameter: + Enabled: false +Style/OrAssignment: + Enabled: false +Style/RandomWithOffset: + Enabled: false +Style/RedundantArgument: + Enabled: false +Style/RedundantAssignment: + Enabled: false +Style/RedundantCondition: + Enabled: false +Style/RedundantConditional: + Enabled: false +Style/RedundantFetchBlock: + Enabled: false +Style/RedundantFileExtensionInRequire: + Enabled: false +Style/RedundantRegexpCharacterClass: + Enabled: false +Style/RedundantRegexpEscape: + Enabled: false +Style/RedundantSelfAssignment: + Enabled: false +Style/RedundantSort: + Enabled: false +Style/RescueStandardError: + Enabled: false +Style/SingleArgumentDig: + Enabled: false +Style/SlicingWithRange: + Enabled: false +Style/SoleNestedConditional: + Enabled: false +Style/StderrPuts: + Enabled: false +Style/StringConcatenation: + Enabled: false +Style/Strip: + Enabled: false +Style/SwapValues: + Enabled: false Style/SymbolProc: Enabled: false +Style/TrailingBodyOnClass: + Enabled: false +Style/TrailingBodyOnMethodDefinition: + Enabled: false +Style/TrailingBodyOnModule: + Enabled: false +Style/TrailingCommaInHashLiteral: + Enabled: false +Style/TrailingMethodEndStatement: + Enabled: false +Style/UnpackFirst: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 6aa2579..0000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,2 +0,0 @@ -Lint/ScriptPermission: - Enabled: false diff --git a/.sync.yml b/.sync.yml index d76a125..899996c 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,77 +1,62 @@ --- ".gitlab-ci.yml": delete: true -".rubocop.yml": - default_configs: - inherit_from: ".rubocop_todo.yml" ".travis.yml": - global_env: + global_env: - HONEYCOMB_WRITEKEY="7f3c63a70eecc61d635917de46bea4e6",HONEYCOMB_DATASET="litmus tests" deploy_to_forge: enabled: false simplecov: true branches: - release use_litmus: true litmus: provision_list: - ---travis_el - travis_deb - travis_el7 - travis_el8 complex: - collection: puppet_collection: - puppet6 provision_list: - travis_ub_6 - collection: puppet_collection: - puppet5 provision_list: - travis_ub_5 notifications: slack: secure: A6h/CuKh9x1tYbifGg04I1Dr6Z6E7xCJjMWAj4XVvdXvooAcgQ+A8pZMCFcl9c7URkIj36XS8uzTTzq5Z+ZYiwyLVMJxkSYaRwl2PPxTb/XA3r2f8bxm++XMoMYecUJhy0WkVmEjNarpzHnSi3OWQq6Eup+dEpntJaHFlZptsM0= appveyor.yml: environment: HONEYCOMB_WRITEKEY: 7f3c63a70eecc61d635917de46bea4e6 HONEYCOMB_DATASET: litmus tests simplecov: true use_litmus: true matrix_extras: - RUBY_VERSION: 25-x64 ACCEPTANCE: 'yes' TARGET_HOST: localhost - RUBY_VERSION: 25-x64 ACCEPTANCE: 'yes' TARGET_HOST: localhost APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 Gemfile: - required: - ":system_tests": - - gem: puppet-module-posix-system-r#{minor_version} - platforms: ruby - - gem: puppet-module-win-system-r#{minor_version} - platforms: - - mswin - - mingw - - x64_mingw optional: ":development": - gem: ruby-pwsh - gem: github_changelog_generator - git: https://github.com/skywinder/github-changelog-generator - ref: 20ee04ba1234e9e83eb2ffb5056e23d641c7a018 - condition: Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.2.2') spec/spec_helper.rb: mock_with: ":rspec" coverage_report: true .gitpod.Dockerfile: unmanaged: false .gitpod.yml: unmanaged: false .github/workflows/nightly.yml: unmanaged: false .github/workflows/pr_test.yml: unmanaged: false diff --git a/.travis.yml b/.travis.yml index 7e49612..b434e36 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,137 +1,129 @@ --- os: linux dist: xenial language: ruby cache: bundler before_install: - bundle -v - rm -f Gemfile.lock - "# Update system gems if requested. This is useful to temporarily workaround troubles in the test runner" - "# See https://github.com/puppetlabs/pdk-templates/commit/705154d5c437796b821691b707156e1b056d244f for an example of how this was used" - "# Ignore exit code of SIGPIPE'd yes to not fail with shell's pipefail set" - '[ -z "$RUBYGEMS_VERSION" ] || (yes || true) | gem update --system $RUBYGEMS_VERSION' - gem --version - bundle -v script: - 'SIMPLECOV=yes bundle exec rake $CHECK' bundler_args: --without system_tests rvm: - 2.5.7 env: global: - HONEYCOMB_WRITEKEY="7f3c63a70eecc61d635917de46bea4e6",HONEYCOMB_DATASET="litmus tests" stages: - static - spec - acceptance jobs: fast_finish: true include: - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_ub_6]'" - "bundle exec rake 'litmus:install_agent[puppet6]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_ub_6_puppet6 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_ub_5]'" - "bundle exec rake 'litmus:install_agent[puppet5]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_ub_5_puppet5 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_deb]'" - "bundle exec rake 'litmus:install_agent[puppet5]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_deb_puppet5 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_el7]'" - "bundle exec rake 'litmus:install_agent[puppet5]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_el7_puppet5 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_el8]'" - "bundle exec rake 'litmus:install_agent[puppet5]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_el8_puppet5 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_deb]'" - "bundle exec rake 'litmus:install_agent[puppet6]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_deb_puppet6 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_el7]'" - "bundle exec rake 'litmus:install_agent[puppet6]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_el7_puppet6 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - - + - bundler_args: --with system_tests before_script: - "bundle exec rake 'litmus:provision_list[travis_el8]'" - "bundle exec rake 'litmus:install_agent[puppet6]'" - "bundle exec rake litmus:install_module" - bundler_args: env: PLATFORMS=travis_el8_puppet6 rvm: 2.5.7 script: ["travis_wait 45 bundle exec rake litmus:acceptance:parallel"] services: docker stage: acceptance - env: CHECK="check:symlinks check:git_ignore check:dot_underscore check:test_file rubocop syntax lint metadata_lint" stage: static - env: PUPPET_GEM_VERSION="~> 5.0" CHECK=parallel_spec rvm: 2.4.5 stage: spec - env: PUPPET_GEM_VERSION="~> 6.0" CHECK=parallel_spec rvm: 2.5.7 stage: spec branches: only: - main - /^v\d/ - release notifications: email: false slack: secure: A6h/CuKh9x1tYbifGg04I1Dr6Z6E7xCJjMWAj4XVvdXvooAcgQ+A8pZMCFcl9c7URkIj36XS8uzTTzq5Z+ZYiwyLVMJxkSYaRwl2PPxTb/XA3r2f8bxm++XMoMYecUJhy0WkVmEjNarpzHnSi3OWQq6Eup+dEpntJaHFlZptsM0= diff --git a/Gemfile b/Gemfile index efe8a05..122328d 100644 --- a/Gemfile +++ b/Gemfile @@ -1,79 +1,74 @@ source ENV['GEM_SOURCE'] || 'https://rubygems.org' def location_for(place_or_version, fake_version = nil) git_url_regex = %r{\A(?(https?|git)[:@][^#]*)(#(?.*))?} file_url_regex = %r{\Afile:\/\/(?.*)} if place_or_version && (git_url = place_or_version.match(git_url_regex)) [fake_version, { git: git_url[:url], branch: git_url[:branch], require: false }].compact elsif place_or_version && (file_url = place_or_version.match(file_url_regex)) ['>= 0', { path: File.expand_path(file_url[:path]), require: false }] else [place_or_version, { require: false }] end end ruby_version_segments = Gem::Version.new(RUBY_VERSION.dup).segments minor_version = ruby_version_segments[0..1].join('.') group :development do - gem "fast_gettext", '1.1.0', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') - gem "fast_gettext", require: false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') - gem "json_pure", '<= 2.0.1', require: false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') - gem "json", '= 1.8.1', require: false if Gem::Version.new(RUBY_VERSION.dup) == Gem::Version.new('2.1.9') gem "json", '= 2.0.4', require: false if Gem::Requirement.create('~> 2.4.2').satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) 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)) gem "json", '= 2.3.0', require: false if Gem::Requirement.create(['>= 2.7.0', '< 2.8.0']).satisfied_by?(Gem::Version.new(RUBY_VERSION.dup)) - gem "rb-readline", '= 0.5.5', require: false, platforms: [:mswin, :mingw, :x64_mingw] - gem "puppet-module-posix-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] - gem "puppet-module-posix-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:ruby] - gem "puppet-module-win-default-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] - gem "puppet-module-win-dev-r#{minor_version}", '~> 0.4', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-posix-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] + gem "puppet-module-posix-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] + gem "puppet-module-win-default-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-win-dev-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] gem "ruby-pwsh", require: false - gem "github_changelog_generator", require: false, git: 'https://github.com/skywinder/github-changelog-generator', ref: '20ee04ba1234e9e83eb2ffb5056e23d641c7a018' if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.2.2') + gem "github_changelog_generator", require: false end group :system_tests do - gem "puppet-module-posix-system-r#{minor_version}", require: false, platforms: [:ruby] - gem "puppet-module-win-system-r#{minor_version}", require: false, platforms: [:mswin, :mingw, :x64_mingw] + gem "puppet-module-posix-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:ruby] + gem "puppet-module-win-system-r#{minor_version}", '~> 1.0', require: false, platforms: [:mswin, :mingw, :x64_mingw] end puppet_version = ENV['PUPPET_GEM_VERSION'] facter_version = ENV['FACTER_GEM_VERSION'] hiera_version = ENV['HIERA_GEM_VERSION'] gems = {} gems['puppet'] = location_for(puppet_version) # If facter or hiera versions have been specified via the environment # variables gems['facter'] = location_for(facter_version) if facter_version gems['hiera'] = location_for(hiera_version) if hiera_version if Gem.win_platform? && puppet_version =~ %r{^(file:///|git://)} # If we're using a Puppet gem on Windows which handles its own win32-xxx gem # dependencies (>= 3.5.0), set the maximum versions (see PUP-6445). gems['win32-dir'] = ['<= 0.4.9', require: false] gems['win32-eventlog'] = ['<= 0.6.5', require: false] gems['win32-process'] = ['<= 0.7.5', require: false] gems['win32-security'] = ['<= 0.2.5', require: false] gems['win32-service'] = ['0.8.8', require: false] end gems.each do |gem_name, gem_params| gem gem_name, *gem_params end # Evaluate Gemfile.local and ~/.gemfile if they exist extra_gemfiles = [ "#{__FILE__}.local", File.join(Dir.home, '.gemfile'), ] extra_gemfiles.each do |gemfile| if File.file?(gemfile) && File.readable?(gemfile) eval(File.read(gemfile), binding) end end # vim: syntax=ruby diff --git a/lib/puppet/provider/java_ks/keytool.rb b/lib/puppet/provider/java_ks/keytool.rb index e335beb..abf45ff 100644 --- a/lib/puppet/provider/java_ks/keytool.rb +++ b/lib/puppet/provider/java_ks/keytool.rb @@ -1,375 +1,375 @@ # frozen_string_literal: true require 'openssl' require 'timeout' require 'puppet/util/filetype' Puppet::Type.type(:java_ks).provide(:keytool) do desc 'Uses a combination of openssl and keytool to manage Java keystores' def command_keytool 'keytool' end # Keytool can only import a keystore if the format is pkcs12. Generating and # importing a keystore is used to add private_key and certificate pairs. def to_pkcs12(path) case private_key_type when :rsa pkey = OpenSSL::PKey::RSA.new File.read(private_key), password when :dsa pkey = OpenSSL::PKey::DSA.new File.read(private_key), password when :ec pkey = OpenSSL::PKey::EC.new File.read(private_key), password end if chain x509_cert = OpenSSL::X509::Certificate.new File.read certificate chain_certs = get_chain(chain) else chain_certs = get_chain(certificate) x509_cert = chain_certs.shift end pkcs12 = OpenSSL::PKCS12.create(password, @resource[:name], pkey, x509_cert, chain_certs) File.open(path, 'wb') { |f| f.print pkcs12.to_der } end # Keytool can only import a jceks keystore if the format is der. Generating and # importing a keystore is used to add private_key and certificate pairs. def to_der(path) x509_cert = OpenSSL::X509::Certificate.new File.read certificate File.open(path, 'wb') { |f| f.print x509_cert.to_der } end def get_chain(path) chain_certs = File.read(path, encoding: 'ISO-8859-1').scan(%r{-----BEGIN [^\n]*CERTIFICATE.*?-----END [^\n]*CERTIFICATE-----}m) if chain_certs.any? chain_certs.map { |cert| OpenSSL::X509::Certificate.new cert } else chain_certs << ((OpenSSL::X509::Certificate.new File.binread path)) end end def password if @resource[:password_file].nil? @resource[:password] else file = File.open(@resource[:password_file], 'r') pword = file.read file.close pword.chomp end end def password_file pword = password source_pword = sourcepassword tmpfile = Tempfile.new("#{@resource[:name]}.") contents = if File.exist?(@resource[:target]) && !File.zero?(@resource[:target]) if !source_pword.nil? "#{pword}\n#{source_pword}" else "#{pword}\n#{pword}" end elsif !source_pword.nil? "#{pword}\n#{pword}\n#{source_pword}" else "#{pword}\n#{pword}\n#{pword}" end tmpfile.write(contents) tmpfile.flush tmpfile end # Where we actually to the import of the file created using to_pkcs12. def import_ks tmppk12 = Tempfile.new("#{@resource[:name]}.") to_pkcs12(tmppk12.path) cmd = [ command_keytool, '-importkeystore', '-srcstoretype', 'PKCS12', '-destkeystore', @resource[:target], '-srckeystore', tmppk12.path, '-alias', @resource[:name] ] cmd << '-trustcacerts' if @resource[:trustcacerts] == :true cmd += ['-destkeypass', @resource[:destkeypass]] unless @resource[:destkeypass].nil? pwfile = password_file run_command(cmd, @resource[:target], pwfile) tmppk12.close! pwfile.close! if pwfile.is_a? Tempfile end def import_pkcs12 cmd = [ command_keytool, '-importkeystore', '-srcstoretype', 'PKCS12', '-destkeystore', @resource[:target], '-srckeystore', certificate ] if @resource[:source_alias] cmd.concat([ '-srcalias', @resource[:source_alias], '-destalias', @resource[:name] ]) end if @resource[:destkeypass] cmd.concat([ '-destkeypass', @resource[:destkeypass] ]) end pwfile = password_file run_command(cmd, @resource[:target], pwfile) pwfile.close! if pwfile.is_a? Tempfile end def import_jceks tmpder = Tempfile.new("#{@resource[:name]}.") to_der(tmpder.path) cmd = [ command_keytool, '-importcert', '-noprompt', '-alias', @resource[:name], '-file', tmpder.path, '-keystore', @resource[:target], '-storetype', storetype ] cmd << '-trustcacerts' if @resource[:trustcacerts] == :true cmd += ['-destkeypass', @resource[:destkeypass]] unless @resource[:destkeypass].nil? pwfile = password_file run_command(cmd, @resource[:target], pwfile) pwfile.close! if pwfile.is_a? Tempfile end def exists? cmd = [ command_keytool, '-list', '-keystore', @resource[:target], '-alias', @resource[:name] ] cmd += ['-storetype', storetype] if storetype == :jceks begin tmpfile = password_file run_command(cmd, false, tmpfile) tmpfile.close! - return true + true rescue => e if e.message.match?(%r{password was incorrect}i) # we have the wrong password for the keystore. so delete it if :password_fail_reset if @resource[:password_fail_reset] == :true File.delete(@resource[:target]) end end - return false + false end end # Extracts the fingerprints of a given output def extract_fingerprint(output) output.scan(%r{Certificate fingerprints:\n\s+(?:MD5: .*\n\s+)?SHA1: (.*)}).flatten.join('/') end # Reading the fingerprint of the certificate on disk. def latest # The certificate file may not exist during a puppet noop run as it's managed by puppet. # Return value must be different to provider.current to signify a possible trigger event. if Puppet[:noop] && !File.exist?(certificate) 'latest' elsif storetype == :pkcs12 cmd = [ command_keytool, '-v', '-list', '-keystore', certificate, '-storetype', 'PKCS12', '-storepass', sourcepassword ] output = run_command(cmd) latest = extract_fingerprint(output) latest else cmd = [ command_keytool, '-v', '-printcert', '-file', certificate ] output = run_command(cmd) if chain cmd = [ command_keytool, '-v', '-printcert', '-file', chain ] output += run_command(cmd) end latest = extract_fingerprint(output) latest end end # Reading the fingerprint of the certificate currently in the keystore. def current # The keystore file may not exist during a puppet noop run as it's managed by puppet. if Puppet[:noop] && !File.exist?(@resource[:target]) 'current' else cmd = [ command_keytool, '-list', '-v', '-keystore', @resource[:target], '-alias', @resource[:name] ] cmd += ['-storetype', storetype] if storetype == :jceks tmpfile = password_file output = run_command(cmd, false, tmpfile) tmpfile.close! current = extract_fingerprint(output) current end end # Determine if we need to do an import of a private_key and certificate pair # or just add a signed certificate, then do it. def create if !certificate.nil? && !private_key.nil? import_ks elsif certificate.nil? && !private_key.nil? raise Puppet::Error, 'Keytool is not capable of importing a private key without an accompanying certificate.' elsif storetype == :jceks import_jceks elsif storetype == :pkcs12 import_pkcs12 else cmd = [ command_keytool, '-importcert', '-noprompt', '-alias', @resource[:name], '-file', certificate, '-keystore', @resource[:target] ] cmd << '-trustcacerts' if @resource[:trustcacerts] == :true tmpfile = password_file run_command(cmd, @resource[:target], tmpfile) tmpfile.close! end end def destroy cmd = [ command_keytool, '-delete', '-alias', @resource[:name], '-keystore', @resource[:target] ] cmd += ['-storetype', storetype] if storetype == :jceks tmpfile = password_file run_command(cmd, false, tmpfile) tmpfile.close! end # Being safe since I have seen some additions overwrite and some just throw errors. def update destroy create end def certificate @resource[:certificate] end def private_key @resource[:private_key] end def private_key_type @resource[:private_key_type] end def chain @resource[:chain] end def sourcepassword @resource[:source_password] end def storetype @resource[:storetype] end def run_command(cmd, target = false, stdinfile = false, env = {}) env[:PATH] = @resource[:path].join(File::PATH_SEPARATOR) if resource[:path] # The Puppet::Util::Execution.execute method is deprecated in Puppet 3.x # but we need this to work on 2.7.x too. exec_method = if Puppet::Util::Execution.respond_to?(:execute) Puppet::Util::Execution.method(:execute) else Puppet::Util.method(:execute) end withenv = if Puppet::Util::Execution.respond_to?(:withenv) Puppet::Util::Execution.method(:withenv) else Puppet::Util.method(:withenv) end # the java keytool will not correctly deal with an empty target keystore # file. If we encounter an empty keystore target file, preserve the mode, # owner and group, temporarily raise the umask, and delete the empty file. if target && (File.exist?(target) && File.zero?(target)) stat = File.stat(target) umask = File.umask(0o077) File.delete(target) end # There's a problem in IBM java keytool wherein stdin cannot be used # (trivially) to pass in the keystore passwords. The below hack makes the # provider work on SLES with minimal effort at the cost of letting the # passphrase to the keystore show up in the process list as an argument. # From a best practice standpoint the keystore should be protected by file # permissions and not just the passphrase so "making it work on SLES" # trumps. if Facter.value('osfamily') == 'Suse' && @resource[:password] cmd_to_run = cmd.is_a?(String) ? cmd.split(%r{\s}).first : cmd.first if cmd_to_run == command_keytool cmd << '-srcstorepass' << @resource[:password] cmd << '-deststorepass' << @resource[:password] end end # Now run the command options = { failonfail: true, combine: true } output = nil begin Timeout.timeout(@resource[:keytool_timeout], Timeout::Error) do output = if stdinfile withenv.call(env) do exec_method.call(cmd, options.merge(stdinfile: stdinfile.path)) end else withenv.call(env) do exec_method.call(cmd, options) end end end rescue Timeout::Error raise Puppet::Error, "Timed out waiting for '#{@resource[:name]}' to run keytool" end # for previously empty files, restore the umask, mode, owner and group. # The funky double-take check is because on Suse defined? doesn't seem # to behave quite the same as on Debian, RedHat if target and (defined? stat and stat) # rubocop:disable Style/AndOr : Changing 'and' to '&&' causes test failures. File.umask(umask) # Need to change group ownership before mode to prevent making the file # accessible to the wrong group. File.chown(stat.uid, stat.gid, target) File.chmod(stat.mode, target) end output end end diff --git a/metadata.json b/metadata.json index 88fa3dc..94a2b7a 100644 --- a/metadata.json +++ b/metadata.json @@ -1,109 +1,109 @@ { "name": "puppetlabs-java_ks", "version": "3.4.0", "author": "puppetlabs", "summary": "Manage arbitrary Java keystore files", "license": "Apache-2.0", "source": "https://github.com/puppetlabs/puppetlabs-java_ks", "project_page": "https://github.com/puppetlabs/puppetlabs-java_ks", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", "dependencies": [ ], "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "5", "6", "7", "8" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "5", "6", "7", "8" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "6", "7" ] }, { "operatingsystem": "SLES", "operatingsystemrelease": [ "11 SP1", "12", "15" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "8", "9", "10" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "14.04", "16.04", "18.04", "20.04" ] }, { "operatingsystem": "Solaris", "operatingsystemrelease": [ "10", "11" ] }, { "operatingsystem": "AIX", "operatingsystemrelease": [ "7.1" ] }, { "operatingsystem": "Windows", "operatingsystemrelease": [ "2008 R2", "2012", "2012 R2", "2016", "2019", "7", "8.1", "10" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 5.5.10 < 8.0.0" } ], "description": "Uses a combination of keytool and Ruby openssl library to manage entries in a Java keystore.", "template-url": "https://github.com/puppetlabs/pdk-templates#main", - "template-ref": "heads/main-0-g24afa8d", + "template-ref": "heads/main-0-g4543421", "pdk-version": "1.18.1" } diff --git a/spec/unit/puppet/provider/java_ks/keytool_spec.rb b/spec/unit/puppet/provider/java_ks/keytool_spec.rb old mode 100644 new mode 100755 index 642a4df..a466095 --- a/spec/unit/puppet/provider/java_ks/keytool_spec.rb +++ b/spec/unit/puppet/provider/java_ks/keytool_spec.rb @@ -1,223 +1,222 @@ -#!/usr/bin/env rspec # frozen_string_literal: true require 'spec_helper' describe Puppet::Type.type(:java_ks).provider(:keytool) do let(:temp_dir) do if Puppet.features.microsoft_windows? ENV['TEMP'] else '/tmp/' end end let(:global_params) do { title: "app.example.com:#{temp_dir}application.jks", name: 'app.example.com', target: "#{temp_dir}application.jks", password: 'puppet', certificate: "#{temp_dir}app.example.com.pem", private_key: "#{temp_dir}private/app.example.com.pem", storetype: 'jceks', provider: described_class.name, } end let(:params) do global_params end let(:resource) do Puppet::Type.type(:java_ks).new(params) end let(:provider) do resource.provider end before(:each) do allow(provider).to receive(:command).with(:keytool).and_return('mykeytool') allow(provider).to receive(:command).with(:openssl).and_return('myopenssl') allow(provider).to receive(:command_keytool).and_return('mykeytool') allow(provider).to receive(:command_openssl).and_return('myopenssl') tempfile = class_double('tempfile', class: Tempfile, write: true, flush: true, close!: true, path: "#{temp_dir}testing.stuff") allow(Tempfile).to receive(:new).and_return(tempfile) end describe 'when updating a certificate' do it 'calls destroy and create' do expect(provider).to receive(:destroy) expect(provider).to receive(:create) provider.update end end describe 'when running keystore commands', if: !Puppet.features.microsoft_windows? do it 'calls the passed command' do cmd = '/bin/echo testing 1 2 3' exec_class = if Puppet::Util::Execution.respond_to?(:execute) Puppet::Util::Execution else Puppet::Util end expect(exec_class).to receive(:execute).with( cmd, failonfail: true, combine: true, ) provider.run_command(cmd) end context 'short timeout' do let(:params) do global_params.merge(keytool_timeout: 0.1) end it 'errors if timeout occurs' do cmd = 'sleep 1' expect { provider.run_command(cmd) }.to raise_error Puppet::Error, "Timed out waiting for 'app.example.com' to run keytool" end end it 'normally times out after 120 seconds' do cmd = '/bin/echo testing 1 2 3' expect(Timeout).to receive(:timeout).with(120, Timeout::Error).and_raise(Timeout::Error) expect { provider.run_command(cmd) }.to raise_error Puppet::Error, "Timed out waiting for 'app.example.com' to run keytool" end end describe 'when importing a private key and certifcate' do describe '#to_pkcs12' do it 'converts a certificate to a pkcs12 file' do sleep 0.1 # due to https://github.com/mitchellh/vagrant/issues/5056 testing_key = OpenSSL::PKey::RSA.new 1024 testing_ca = OpenSSL::X509::Certificate.new testing_ca.serial = 1 testing_ca.public_key = testing_key.public_key testing_subj = '/CN=Test CA/ST=Denial/L=Springfield/O=Dis/CN=www.example.com' testing_ca.subject = OpenSSL::X509::Name.parse testing_subj testing_ca.issuer = testing_ca.subject testing_ca.not_before = Time.now testing_ca.not_after = testing_ca.not_before + 360 testing_ca.sign(testing_key, OpenSSL::Digest::SHA256.new) allow(provider).to receive(:password).and_return(resource[:password]) allow(File).to receive(:read).with(resource[:private_key]).and_return('private key') allow(File).to receive(:read).with(resource[:certificate], hash_including(encoding: 'ISO-8859-1')).and_return(testing_ca.to_pem) expect(OpenSSL::PKey::RSA).to receive(:new).with('private key', 'puppet').and_return('priv_obj') expect(OpenSSL::X509::Certificate).to receive(:new).with(testing_ca.to_pem.chomp).and_return('cert_obj') pkcs_double = BogusPkcs.new expect(pkcs_double).to receive(:to_der) expect(OpenSSL::PKCS12).to receive(:create).with(resource[:password], resource[:name], 'priv_obj', 'cert_obj', []).and_return(pkcs_double) provider.to_pkcs12("#{temp_dir}testing.stuff") end end describe '#import_ks' do it 'executes openssl and keytool with specific options' do expect(provider).to receive(:to_pkcs12).with("#{temp_dir}testing.stuff") expect(provider).to receive(:run_command).with(['mykeytool', '-importkeystore', '-srcstoretype', 'PKCS12', '-destkeystore', resource[:target], '-srckeystore', "#{temp_dir}testing.stuff", '-alias', resource[:name]], any_args) provider.import_ks end it 'uses destkeypass when provided' do dkp = resource.dup dkp[:destkeypass] = 'keypass' expect(provider).to receive(:to_pkcs12).with("#{temp_dir}testing.stuff") expect(provider).to receive(:run_command).with(['mykeytool', '-importkeystore', '-srcstoretype', 'PKCS12', '-destkeystore', dkp[:target], '-srckeystore', "#{temp_dir}testing.stuff", '-alias', dkp[:name], '-destkeypass', dkp[:destkeypass]], any_args) provider.import_ks end end end describe 'when importing a pkcs12 file' do let(:params) do { title: "app.example.com:#{temp_dir}testing.jks", name: 'app.example.com', target: "#{temp_dir}application.jks", password: 'puppet', certificate: "#{temp_dir}testing.p12", storetype: 'pkcs12', source_password: 'password', provider: described_class.name, } end let(:resource) do Puppet::Type.type(:java_ks).new(params) end let(:provider) do resource.provider end describe '#import_pkcs12' do it 'supports pkcs12 source' do pkcs12 = resource.dup pkcs12[:storetype] = 'pkcs12' expect(provider).to receive(:run_command).with(['mykeytool', '-importkeystore', '-srcstoretype', 'PKCS12', '-destkeystore', pkcs12[:target], '-srckeystore', "#{temp_dir}testing.p12"], any_args) provider.import_pkcs12 end end end describe 'when creating entries in a keystore' do let(:params) do { title: "app.example.com:#{temp_dir}application.jks", name: 'app.example.com', target: "#{temp_dir}application.jks", password: 'puppet', certificate: "#{temp_dir}app.example.com.pem", private_key: "#{temp_dir}private/app.example.com.pem", provider: described_class.name, } end let(:resource) do Puppet::Type.type(:java_ks).new(params) end let(:provider) do resource.provider end it 'calls import_ks if private_key and certificate are provided' do expect(provider).to receive(:import_ks) provider.create end it 'calls keytool with specific options if only certificate is provided' do no_pk = resource.dup no_pk.delete(:private_key) expect(provider).to receive(:run_command).with(['mykeytool', '-importcert', '-noprompt', '-alias', no_pk[:name], '-file', no_pk[:certificate], '-keystore', no_pk[:target]], any_args) expect(no_pk.provider).to receive(:import_ks).never no_pk.provider.create end end describe 'when removing entries from keytool' do it 'executes keytool with a specific set of options' do expect(provider).to receive(:run_command).with(['mykeytool', '-delete', '-alias', resource[:name], '-keystore', resource[:target], '-storetype', resource[:storetype]], any_args) provider.destroy end end end class BogusPkcs end diff --git a/spec/unit/puppet/type/java_ks_spec.rb b/spec/unit/puppet/type/java_ks_spec.rb index 7b0d222..192a002 100644 --- a/spec/unit/puppet/type/java_ks_spec.rb +++ b/spec/unit/puppet/type/java_ks_spec.rb @@ -1,245 +1,244 @@ # frozen_string_literal: true -! # /usr/bin/env rspec require 'spec_helper' describe Puppet::Type.type(:java_ks) do let(:temp_dir) do if Puppet.features.microsoft_windows? ENV['TEMP'] else '/tmp/' end end let(:provider_var) { class_double('provider', class: described_class.defaultprovider, clear: nil) } let(:app_example_com) do { title: "app.example.com:#{temp_dir}application.jks", name: 'app.example.com', target: "#{temp_dir}application.jks", password: 'puppet', destkeypass: 'keypass', certificate: "#{temp_dir}app.example.com.pem", private_key: "#{temp_dir}private/app.example.com.pem", private_key_type: 'rsa', storetype: 'jceks', provider: :keytool, } end let(:jks_resource) do app_example_com end before(:each) do allow(described_class.defaultprovider).to receive(:new).and_return(provider_var) end it 'defaults to being present' do expect(described_class.new(app_example_com)[:ensure]).to eq(:present) end describe 'when validating attributes' do [:name, :target, :private_key, :private_key_type, :certificate, :password, :password_file, :trustcacerts, :destkeypass, :password_fail_reset, :source_password].each do |param| - it "should have a #{param} parameter" do + it "has a #{param} parameter" do expect(described_class.attrtype(param)).to eq(:param) end end [:ensure].each do |prop| - it "should have a #{prop} property" do + it "has a #{prop} property" do expect(described_class.attrtype(prop)).to eq(:property) end end end describe 'when validating attribute values' do [:present, :absent, :latest].each do |value| - it "should support #{value} as a value to ensure" do + it "supports #{value} as a value to ensure" do described_class.new(jks_resource.merge(ensure: value)) end end it 'first half of title should map to name parameter' do jks = jks_resource.dup jks.delete(:name) expect(described_class.new(jks)[:name]).to eq(jks_resource[:name]) end it 'second half of title should map to target parameter when no target is supplied' do jks = jks_resource.dup jks.delete(:target) expect(described_class.new(jks)[:target]).to eq(jks_resource[:target]) end it 'second half of title should not map to target parameter when target is supplied #not to equal' do jks = jks_resource.dup jks[:target] = "#{temp_dir}some_other_app.jks" expect(described_class.new(jks)[:target]).not_to eq(jks_resource[:target]) end it 'second half of title should not map to target parameter when target is supplied #to equal' do jks = jks_resource.dup jks[:target] = "#{temp_dir}some_other_app.jks" expect(described_class.new(jks)[:target]).to eq("#{temp_dir}some_other_app.jks") end it 'title components should map to namevar parameters #name' do jks = jks_resource.dup jks.delete(:name) jks.delete(:target) expect(described_class.new(jks)[:name]).to eq(jks_resource[:name]) end it 'title components should map to namevar parameters #target' do jks = jks_resource.dup jks.delete(:name) jks.delete(:target) expect(described_class.new(jks)[:target]).to eq(jks_resource[:target]) end it 'downcases :name values' do jks = jks_resource.dup jks[:name] = 'APP.EXAMPLE.COM' expect(described_class.new(jks)[:name]).to eq(jks_resource[:name]) end it 'has :false value to :trustcacerts when parameter not provided' do expect(described_class.new(jks_resource)[:trustcacerts]).to eq(:false) end it 'has :rsa as the default value for :private_key_type' do expect(described_class.new(jks_resource)[:private_key_type]).to eq(:rsa) end it 'fails if :private_key_type is neither :rsa nor :ec nor :dsa' do jks = jks_resource.dup jks[:private_key_type] = 'nosuchkeytype' expect { described_class.new(jks) }.to raise_error(Puppet::Error) end it 'fails if both :password and :password_file are provided' do jks = jks_resource.dup jks[:password_file] = '/path/to/password_file' expect { described_class.new(jks) }.to raise_error(Puppet::Error, %r{You must pass either}) end it 'fails if neither :password or :password_file is provided' do jks = jks_resource.dup jks.delete(:password) expect { described_class.new(jks) }.to raise_error(Puppet::Error, %r{You must pass one of}) end it 'fails if :password is fewer than 6 characters' do jks = jks_resource.dup jks[:password] = 'aoeui' expect { described_class.new(jks) }.to raise_error(Puppet::Error, %r{6 characters}) end it 'fails if :destkeypass is fewer than 6 characters' do jks = jks_resource.dup jks[:destkeypass] = 'aoeui' expect { described_class.new(jks) }.to raise_error(Puppet::Error, %r{length 6}) end it 'has :false value to :password_fail_reset when parameter not provided' do expect(described_class.new(jks_resource)[:password_fail_reset]).to eq(:false) end it 'fails if :source_password is not provided for pkcs12 :storetype' do jks = jks_resource.dup jks[:storetype] = 'pkcs12' expect { described_class.new(jks) }.to raise_error(Puppet::Error, %r{You must provide 'source_password' when using a 'pkcs12' storetype}) end end describe 'when ensure is set to latest' do it 'insync? should return false if sha1 fingerprints do not match and state is :present' do jks = jks_resource.dup jks[:ensure] = :latest allow(provider_var).to receive(:latest).and_return('9B:8B:23:4C:6A:9A:08:F6:4E:B6:01:23:EA:5A:E7:8F:6A') allow(provider_var).to receive(:current).and_return('21:46:45:65:57:50:FE:2D:DA:7C:C8:57:D2:33:3A:B0:A6') expect(described_class.new(jks).property(:ensure)).not_to be_insync(:present) end it 'insync? should return false if state is :absent' do jks = jks_resource.dup jks[:ensure] = :latest expect(described_class.new(jks).property(:ensure)).not_to be_insync(:absent) end it 'insync? should return true if sha1 fingerprints match and state is :present' do jks = jks_resource.dup jks[:ensure] = :latest allow(provider_var).to receive(:latest).and_return('66:9B:8B:23:4C:6A:9A:08:F6:4E:B6:01:23:EA:5A') allow(provider_var).to receive(:current).and_return('66:9B:8B:23:4C:6A:9A:08:F6:4E:B6:01:23:EA:5A') expect(described_class.new(jks).property(:ensure)).to be_insync(:present) end end describe 'when file resources are in the catalog' do let(:file_provider) { class_double('provider', class: Puppet::Type.type(:file).defaultprovider, clear: nil) } before(:each) do allow(Puppet::Type.type(:file).defaultprovider).to receive(:new).and_return(file_provider) end [:private_key, :certificate].each do |file| - it "should autorequire for #{file} #file" do + it "autorequires for #{file} #file" do test_jks = described_class.new(jks_resource) test_file = Puppet::Type.type(:file).new(title: jks_resource[file]) Puppet::Resource::Catalog.new :testing do |conf| [test_jks, test_file].each { |resource| conf.add_resource resource } end rel = test_jks.autorequire[0] expect(rel.source.ref).to eq(test_file.ref) end - it "should autorequire for #{file} #jks" do + it "autorequires for #{file} #jks" do test_jks = described_class.new(jks_resource) test_file = Puppet::Type.type(:file).new(title: jks_resource[file]) Puppet::Resource::Catalog.new :testing do |conf| [test_jks, test_file].each { |resource| conf.add_resource resource } end rel = test_jks.autorequire[0] expect(rel.target.ref).to eq(test_jks.ref) end end it 'autorequires for the :target directory #file' do test_jks = described_class.new(jks_resource) test_file = Puppet::Type.type(:file).new(title: ::File.dirname(jks_resource[:target])) Puppet::Resource::Catalog.new :testing do |conf| [test_jks, test_file].each { |resource| conf.add_resource resource } end rel = test_jks.autorequire[0] expect(rel.source.ref).to eq(test_file.ref) end it 'autorequires for the :target directory #jks' do test_jks = described_class.new(jks_resource) test_file = Puppet::Type.type(:file).new(title: ::File.dirname(jks_resource[:target])) Puppet::Resource::Catalog.new :testing do |conf| [test_jks, test_file].each { |resource| conf.add_resource resource } end rel = test_jks.autorequire[0] expect(rel.target.ref).to eq(test_jks.ref) end end end