kubeclient 4.1.2 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kubeclient might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '036441648e04f1ead9f4c15517c8f8ae31ecf521a77e08601fcfc4d298bbaa28'
4
- data.tar.gz: 6ee8cd72c57fb7a10334d7ceebd7f51a7f38e1eced12a40b12d50c7180e56945
3
+ metadata.gz: 2bc02012cb0c78fc1ec3335e836c2749973e432022083fb3b95bed3d702332a5
4
+ data.tar.gz: 7b5d68aa1c1200d387a086a09f3a8ca628e892c84c590ef76180b37f60f8ca88
5
5
  SHA512:
6
- metadata.gz: 97f3c94d05d1cc79d889c1f851a52b82162a8093ada781444f1e10209d7a3896081fdf423807598c3bae95ce107234005a149b08bf71cf7f3248398631a3dad7
7
- data.tar.gz: 9924a65f531452cccd20c1fe03457acfb9ec779af055513e2dc3532849dd089613011ed3bea005f2e1a5d80243b168940620dca0a21c8842f2be4e4112ebac7f
6
+ metadata.gz: a5c2c2d281b9ed728faf12b8a7937283225b509d6eb4ca4dc7c6245024e1677799ced3adc1a14bf111dab9092b9061af41b0b7924d54dbef5a9f72ff90d554e9
7
+ data.tar.gz: 7c55c0f9c3595045ecb98b1c35d682d8aa8bb3907c3a208c33a32980890e702fca58faa927d0c82b59a69e27e5508cf1efce119ea76846c4f7b5c4bd4ee85944
@@ -25,3 +25,5 @@ Security/MarshalLoad:
25
25
  Style/MethodCallWithArgsParentheses:
26
26
  IgnoredMethods:
27
27
  - require_relative
28
+ Style/RegexpLiteral:
29
+ Enabled: false
@@ -4,14 +4,22 @@ Notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
5
5
  Kubeclient release versioning follows [SemVer](https://semver.org/).
6
6
 
7
- ## 4.1.2 — 2018-12-26
7
+ ## 4.2.0 — 2018-12-20
8
8
 
9
- ### Fixed
10
- - For resources that contain dashes in name, there will be an attempt to resolve the method name based on singular name prefix or by replacing the dash in names with underscores (#382).
9
+ ### Added
10
+ - Support `user: exec: ...` credential plugins like in Go client (#363, #375).
11
+
12
+ ### Security
13
+ - Really made `Kubeclient::Config.new(data, nil)` prevent external file lookups. (#372)
14
+ README documented this since 3.1.1 (#334) but alas that was a lie — absolute paths always worked.
15
+ Now this also prevents credential plugin execution.
16
+
17
+ Even in this mode, using config from untrusted sources is not recommended.
11
18
 
12
19
  ## 4.1.1 — 2018-12-17
13
20
 
14
21
  ### Fixed
22
+
15
23
  - Fixed method names for non-suffix plurals such as y -> ies (#377).
16
24
 
17
25
  ## 4.1.0 — 2018-11-28 — REGRESSION
data/README.md CHANGED
@@ -268,6 +268,11 @@ If you've been using `kubectl` and have a `.kube/config` file (possibly referenc
268
268
  config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
269
269
  ```
270
270
 
271
+ This will lookup external files; relative paths will be resolved relative to the file's directory, if config refers to them with relative path.
272
+ This includes external [`exec:` credential plugins][exec] to be executed.
273
+
274
+ [exec]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
275
+
271
276
  You can also construct `Config` directly from nested data. For example if you have JSON or YAML config data in a variable:
272
277
 
273
278
  ```ruby
@@ -277,7 +282,7 @@ config = Kubeclient::Config.new(JSON.parse(json_text), nil)
277
282
  ```
278
283
 
279
284
  The 2nd argument is a base directory for finding external files, if config refers to them with relative path.
280
- Setting it to `nil` disables file lookups. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
285
+ Setting it to `nil` disables file lookups, and `exec:` execution - such configs will raise an exception. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
281
286
 
282
287
  To create a client based on a Config object:
283
288
 
@@ -297,7 +302,9 @@ Kubeclient::Client.new(
297
302
 
298
303
  #### Security: Don't use config from untrusted sources
299
304
 
300
- Kubeclient was never reviewed for behaving safely with malicious / malformed config.
305
+ `Config.read` is catastrophically unsafe it will execute arbitrary command lines specified by the config!
306
+
307
+ `Config.new(data, nil)` is better but Kubeclient was never reviewed for behaving safely with malicious / malformed config.
301
308
  It might crash / misbehave in unexpected ways...
302
309
 
303
310
  #### namespace
@@ -604,9 +611,9 @@ Checking the type of a resource can be done using:
604
611
 
605
612
  update_* delete_* and patch_* now return a RecursiveOpenStruct like the get_* methods
606
613
 
607
- The gem raises Kubeclient::HttpError or subclasses now. Catching KubeException still works but is deprecated.
614
+ The `Kubeclient::Client` class raises `Kubeclient::HttpError` or subclasses now. Catching `KubeException` still works but is deprecated.
608
615
 
609
- `Kubeclient::Config#context` raises KeyError instead of RuntimeError for non-existent context name.
616
+ `Kubeclient::Config#context` raises `KeyError` instead of `RuntimeError` for non-existent context name.
610
617
 
611
618
  <a name="past_version_1.2.0">
612
619
 
@@ -55,7 +55,9 @@ bundle exec rake test rubocop
55
55
 
56
56
  Create and push the tag:
57
57
  ```bash
58
- gem tag --destination https://github.com/abonas/kubeclient
58
+ gem tag --no-push
59
+ git push --tags --dry-run https://github.com/abonas/kubeclient # Check for unexpected tags
60
+ git push --tags https://github.com/abonas/kubeclient
59
61
  ```
60
62
 
61
63
  Release onto rubygems.org:
@@ -5,6 +5,7 @@ require 'kubeclient/common'
5
5
  require 'kubeclient/config'
6
6
  require 'kubeclient/entity_list'
7
7
  require 'kubeclient/google_application_default_credentials'
8
+ require 'kubeclient/exec_credentials'
8
9
  require 'kubeclient/http_error'
9
10
  require 'kubeclient/missing_kind_compatibility'
10
11
  require 'kubeclient/resource'
@@ -163,7 +163,8 @@ module Kubeclient
163
163
  method_names = [prefix_underscores + singular_suffix, # "network_policy"
164
164
  prefix_underscores + plural_suffix] # "network_policies"
165
165
  else
166
- method_names = resolve_unconventional_method_names(name, kind, singular_name)
166
+ # Something weird, can't infer underscores for plural so just give them up
167
+ method_names = [singular_name, name]
167
168
  end
168
169
  end
169
170
  end
@@ -175,17 +176,6 @@ module Kubeclient
175
176
  )
176
177
  end
177
178
 
178
- def self.resolve_unconventional_method_names(name, kind, singular_name)
179
- underscored_name = name.tr('-', '_')
180
- singular_underscores = ClientMixin.underscore_entity(kind)
181
- if underscored_name.start_with?(singular_underscores)
182
- [singular_underscores, underscored_name]
183
- else
184
- # fallback to lowercase, no separators for both names
185
- [singular_name, underscored_name.tr('_', '')]
186
- end
187
- end
188
-
189
179
  def handle_uri(uri, path)
190
180
  raise ArgumentError, 'Missing uri' unless uri
191
181
  @api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri))
@@ -18,12 +18,17 @@ module Kubeclient
18
18
  end
19
19
  end
20
20
 
21
- def initialize(kcfg, kcfg_path)
22
- @kcfg = kcfg
21
+ # data (Hash) - Parsed kubeconfig data.
22
+ # kcfg_path (string) - Base directory for resolving relative references to external files.
23
+ # If set to nil, all external lookups & commands are disabled (even for absolute paths).
24
+ # See also the more convenient Config.read
25
+ def initialize(data, kcfg_path)
26
+ @kcfg = data
23
27
  @kcfg_path = kcfg_path
24
28
  raise 'Unknown kubeconfig version' if @kcfg['apiVersion'] != 'v1'
25
29
  end
26
30
 
31
+ # Builds Config instance by parsing given file, with lookups relative to file's directory.
27
32
  def self.read(filename)
28
33
  parsed = YAML.safe_load(File.read(filename), [Date, Time])
29
34
  Config.new(parsed, File.dirname(filename))
@@ -65,10 +70,35 @@ module Kubeclient
65
70
 
66
71
  private
67
72
 
73
+ def allow_external_lookups?
74
+ @kcfg_path != nil
75
+ end
76
+
68
77
  def ext_file_path(path)
78
+ unless allow_external_lookups?
79
+ raise "Kubeclient::Config: external lookups disabled, can't load '#{path}'"
80
+ end
69
81
  Pathname(path).absolute? ? path : File.join(@kcfg_path, path)
70
82
  end
71
83
 
84
+ def ext_command_path(path)
85
+ unless allow_external_lookups?
86
+ raise "Kubeclient::Config: external lookups disabled, can't execute '#{path}'"
87
+ end
88
+ # Like go client https://github.com/kubernetes/kubernetes/pull/59495#discussion_r171138995,
89
+ # distinguish 3 cases:
90
+ # - absolute (e.g. /path/to/foo)
91
+ # - $PATH-based (e.g. curl)
92
+ # - relative to config file's dir (e.g. ./foo)
93
+ if Pathname(path).absolute?
94
+ path
95
+ elsif File.basename(path) == path
96
+ path
97
+ else
98
+ File.join(@kcfg_path, path)
99
+ end
100
+ end
101
+
72
102
  def fetch_context(context_name)
73
103
  context = @kcfg['contexts'].detect do |x|
74
104
  break x['context'] if x['name'] == context_name
@@ -119,6 +149,10 @@ module Kubeclient
119
149
  options = {}
120
150
  if user.key?('token')
121
151
  options[:bearer_token] = user['token']
152
+ elsif user.key?('exec')
153
+ exec_opts = user['exec'].dup
154
+ exec_opts['command'] = ext_command_path(exec_opts['command']) if exec_opts['command']
155
+ options[:bearer_token] = Kubeclient::ExecCredentials.token(exec_opts)
122
156
  else
123
157
  %w[username password].each do |attr|
124
158
  options[attr.to_sym] = user[attr] if user.key?(attr)
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kubeclient
4
+ # An exec-based client auth provide
5
+ # https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration
6
+ # Inspired by https://github.com/kubernetes/client-go/blob/master/plugin/pkg/client/auth/exec/exec.go
7
+ class ExecCredentials
8
+ class << self
9
+ def token(opts)
10
+ require 'open3'
11
+ require 'json'
12
+
13
+ raise ArgumentError, 'exec options are required' if opts.nil?
14
+
15
+ cmd = opts['command']
16
+ args = opts['args']
17
+ env = map_env(opts['env'])
18
+
19
+ # Validate exec options
20
+ validate_opts(opts)
21
+
22
+ out, err, st = Open3.capture3(env, cmd, *args)
23
+
24
+ raise "exec command failed: #{err}" unless st.success?
25
+
26
+ creds = JSON.parse(out)
27
+ validate_credentials(opts, creds)
28
+ creds['status']['token']
29
+ end
30
+
31
+ private
32
+
33
+ def validate_opts(opts)
34
+ raise KeyError, 'exec command is required' unless opts['command']
35
+ end
36
+
37
+ def validate_credentials(opts, creds)
38
+ # out should have ExecCredential structure
39
+ raise 'invalid credentials' if creds.nil?
40
+
41
+ # Verify apiVersion?
42
+ api_version = opts['apiVersion']
43
+ if api_version && api_version != creds['apiVersion']
44
+ raise "exec plugin is configured to use API version #{api_version}, " \
45
+ "plugin returned version #{creds['apiVersion']}"
46
+ end
47
+
48
+ raise 'exec plugin didn\'t return a status field' if creds['status'].nil?
49
+ raise 'exec plugin didn\'t return a token' if creds['status']['token'].nil?
50
+ end
51
+
52
+ # Transform name/value pairs to hash
53
+ def map_env(env)
54
+ return {} unless env
55
+
56
+ Hash[env.map { |e| [e['name'], e['value']] }]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,4 +1,4 @@
1
1
  # Kubernetes REST-API Client
2
2
  module Kubeclient
3
- VERSION = '4.1.2'.freeze
3
+ VERSION = '4.2.0'.freeze
4
4
  end
@@ -0,0 +1,62 @@
1
+ apiVersion: v1
2
+ clusters:
3
+ - cluster:
4
+ server: https://localhost:8443
5
+ insecure-skip-tls-verify: true
6
+ name: localhost:8443
7
+ contexts:
8
+ - context:
9
+ cluster: localhost:8443
10
+ namespace: default
11
+ user: system:admin:exec-search-path
12
+ name: localhost/system:admin:exec-search-path
13
+ - context:
14
+ cluster: localhost:8443
15
+ namespace: default
16
+ user: system:admin:exec-relative-path
17
+ name: localhost/system:admin:exec-relative-path
18
+ - context:
19
+ cluster: localhost:8443
20
+ namespace: default
21
+ user: system:admin:exec-absolute-path
22
+ name: localhost/system:admin:exec-absolute-path
23
+ kind: Config
24
+ preferences: {}
25
+ users:
26
+ - name: system:admin:exec-search-path
27
+ user:
28
+ exec:
29
+ # Command to execute. Required.
30
+ command: "example-exec-plugin"
31
+
32
+ # API version to use when decoding the ExecCredentials resource. Required.
33
+ #
34
+ # The API version returned by the plugin MUST match the version listed here.
35
+ #
36
+ # To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1alpha1),
37
+ # set an environment variable or pass an argument to the tool that indicates which version the exec plugin expects.
38
+ apiVersion: "client.authentication.k8s.io/v1beta1"
39
+
40
+ # Environment variables to set when executing the plugin. Optional.
41
+ env:
42
+ - name: "FOO"
43
+ value: "bar"
44
+
45
+ # Arguments to pass when executing the plugin. Optional.
46
+ args:
47
+ - "arg1"
48
+ - "arg2"
49
+
50
+ - name: system:admin:exec-relative-path
51
+ user:
52
+ exec:
53
+ # Command to execute. Required.
54
+ command: "dir/example-exec-plugin"
55
+ apiVersion: "client.authentication.k8s.io/v1beta1"
56
+
57
+ - name: system:admin:exec-absolute-path
58
+ user:
59
+ exec:
60
+ # Command to execute. Required.
61
+ command: "/abs/path/example-exec-plugin"
62
+ apiVersion: "client.authentication.k8s.io/v1beta1"
@@ -81,11 +81,6 @@ class CommonTest < MiniTest::Test
81
81
  LatinDatum latindata latin_datum latin_data
82
82
  Noseparator noseparators noseparator noseparators
83
83
  lowercase lowercases lowercase lowercases
84
- TestWithDash test-with-dashes test_with_dash test_with_dashes
85
- TestUnderscore test_underscores test_underscore test_underscores
86
- TestMismatch other-odd-name testmismatch otheroddname
87
- MixedDashMinus mixed-dash_minuses mixed_dash_minus mixed_dash_minuses
88
- SameUptoWordboundary sameup-toword-boundarys sameuptowordboundary sameuptowordboundarys
89
84
  ].each_slice(4) do |kind, plural, expected_single, expected_plural|
90
85
  method_names = Kubeclient::ClientMixin.parse_definition(kind, plural).method_names
91
86
  assert_equal(method_names[0], expected_single)
@@ -1,5 +1,6 @@
1
1
  require_relative 'test_helper'
2
2
  require 'yaml'
3
+ require 'open3'
3
4
 
4
5
  # Testing Kubernetes client configuration
5
6
  class KubeclientConfigTest < MiniTest::Test
@@ -28,18 +29,18 @@ class KubeclientConfigTest < MiniTest::Test
28
29
  # kcfg_path = nil should prevent file access
29
30
  config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
30
31
  assert_raises(StandardError) do
31
- config.context.ssl_options
32
+ config.context
32
33
  end
33
34
  end
34
35
 
35
36
  def test_external_nopath_absolute
36
37
  yaml = File.read(config_file('external.kubeconfig'))
37
38
  # kcfg_path = nil should prevent file access, even if absolute path specified
38
- ca_absolute_path = File.absolute_path(config_file('external.kubeconfig').path)
39
- yaml = yaml.gsub('external-ca.pem', ca_absolute_path)
39
+ ca_absolute_path = File.absolute_path(config_file('external-'))
40
+ yaml = yaml.gsub('external-', ca_absolute_path)
40
41
  config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
41
42
  assert_raises(StandardError) do
42
- config.context.ssl_options
43
+ config.context
43
44
  end
44
45
  end
45
46
 
@@ -73,6 +74,55 @@ class KubeclientConfigTest < MiniTest::Test
73
74
  Kubeclient::Config.read(config_file('timestamps.kubeconfig'))
74
75
  end
75
76
 
77
+ def test_user_exec
78
+ token = '0123456789ABCDEF0123456789ABCDEF'
79
+ creds = {
80
+ 'apiVersion': 'client.authentication.k8s.io/v1beta1',
81
+ 'status': {
82
+ 'token': token
83
+ }
84
+ }
85
+
86
+ config = Kubeclient::Config.read(config_file('execauth.kubeconfig'))
87
+ assert_equal(['localhost/system:admin:exec-search-path',
88
+ 'localhost/system:admin:exec-relative-path',
89
+ 'localhost/system:admin:exec-absolute-path'],
90
+ config.contexts)
91
+
92
+ # A bare command name in config means search PATH, so it's executed as bare command.
93
+ stub_exec(%r{^example-exec-plugin$}, creds) do
94
+ context = config.context('localhost/system:admin:exec-search-path')
95
+ check_context(context, ssl: false)
96
+ assert_equal(token, context.auth_options[:bearer_token])
97
+ end
98
+
99
+ # A relative path is taken relative to the dir of the kubeconfig.
100
+ stub_exec(%r{.*config/dir/example-exec-plugin$}, creds) do
101
+ context = config.context('localhost/system:admin:exec-relative-path')
102
+ check_context(context, ssl: false)
103
+ assert_equal(token, context.auth_options[:bearer_token])
104
+ end
105
+
106
+ # An absolute path is taken as-is.
107
+ stub_exec(%r{^/abs/path/example-exec-plugin$}, creds) do
108
+ context = config.context('localhost/system:admin:exec-absolute-path')
109
+ check_context(context, ssl: false)
110
+ assert_equal(token, context.auth_options[:bearer_token])
111
+ end
112
+ end
113
+
114
+ def test_user_exec_nopath
115
+ yaml = File.read(config_file('execauth.kubeconfig'))
116
+ config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
117
+ config.contexts.each do |context_name|
118
+ Open3.stub(:capture3, proc { flunk 'should not execute command' }) do
119
+ assert_raises(StandardError) do
120
+ config.context(context_name)
121
+ end
122
+ end
123
+ end
124
+ end
125
+
76
126
  private
77
127
 
78
128
  def check_context(context, ssl: true)
@@ -102,6 +152,20 @@ class KubeclientConfigTest < MiniTest::Test
102
152
  end
103
153
 
104
154
  def config_file(name)
105
- File.new(File.join(File.dirname(__FILE__), 'config', name))
155
+ File.join(File.dirname(__FILE__), 'config', name)
156
+ end
157
+
158
+ def stub_exec(command_regexp, creds)
159
+ st = Minitest::Mock.new
160
+ st.expect(:success?, true)
161
+
162
+ capture3_stub = lambda do |_env, command, *_args|
163
+ assert_match command_regexp, command
164
+ [JSON.dump(creds), nil, st]
165
+ end
166
+
167
+ Open3.stub(:capture3, capture3_stub) do
168
+ yield
169
+ end
106
170
  end
107
171
  end
@@ -0,0 +1,125 @@
1
+ require_relative 'test_helper'
2
+ require 'open3'
3
+
4
+ # Unit tests for the ExecCredentials token provider
5
+ class ExecCredentialsTest < MiniTest::Test
6
+ def test_exec_opts_missing
7
+ expected_msg =
8
+ 'exec options are required'
9
+ exception = assert_raises(ArgumentError) do
10
+ Kubeclient::ExecCredentials.token(nil)
11
+ end
12
+ assert_equal(expected_msg, exception.message)
13
+ end
14
+
15
+ def test_exec_command_missing
16
+ expected_msg =
17
+ 'exec command is required'
18
+ exception = assert_raises(KeyError) do
19
+ Kubeclient::ExecCredentials.token({})
20
+ end
21
+ assert_equal(expected_msg, exception.message)
22
+ end
23
+
24
+ def test_exec_command_failure
25
+ err = 'Error'
26
+ expected_msg =
27
+ "exec command failed: #{err}"
28
+
29
+ st = Minitest::Mock.new
30
+ st.expect(:success?, false)
31
+
32
+ opts = { 'command' => 'dummy' }
33
+
34
+ Open3.stub(:capture3, [nil, err, st]) do
35
+ exception = assert_raises(RuntimeError) do
36
+ Kubeclient::ExecCredentials.token(opts)
37
+ end
38
+ assert_equal(expected_msg, exception.message)
39
+ end
40
+ end
41
+
42
+ def test_token
43
+ opts = { 'command' => 'dummy' }
44
+
45
+ creds = JSON.dump(
46
+ 'apiVersion': 'client.authentication.k8s.io/v1alpha1',
47
+ 'status': {
48
+ 'token': '0123456789ABCDEF0123456789ABCDEF'
49
+ }
50
+ )
51
+
52
+ st = Minitest::Mock.new
53
+ st.expect(:success?, true)
54
+
55
+ Open3.stub(:capture3, [creds, nil, st]) do
56
+ assert_equal('0123456789ABCDEF0123456789ABCDEF', Kubeclient::ExecCredentials.token(opts))
57
+ end
58
+ end
59
+
60
+ def test_status_missing
61
+ opts = { 'command' => 'dummy' }
62
+
63
+ creds = JSON.dump('apiVersion': 'client.authentication.k8s.io/v1alpha1')
64
+
65
+ st = Minitest::Mock.new
66
+ st.expect(:success?, true)
67
+
68
+ expected_msg = 'exec plugin didn\'t return a status field'
69
+
70
+ Open3.stub(:capture3, [creds, nil, st]) do
71
+ exception = assert_raises(RuntimeError) do
72
+ Kubeclient::ExecCredentials.token(opts)
73
+ end
74
+ assert_equal(expected_msg, exception.message)
75
+ end
76
+ end
77
+
78
+ def test_token_missing
79
+ opts = { 'command' => 'dummy' }
80
+
81
+ creds = JSON.dump(
82
+ 'apiVersion': 'client.authentication.k8s.io/v1alpha1',
83
+ 'status': {}
84
+ )
85
+
86
+ st = Minitest::Mock.new
87
+ st.expect(:success?, true)
88
+
89
+ expected_msg = 'exec plugin didn\'t return a token'
90
+
91
+ Open3.stub(:capture3, [creds, nil, st]) do
92
+ exception = assert_raises(RuntimeError) do
93
+ Kubeclient::ExecCredentials.token(opts)
94
+ end
95
+ assert_equal(expected_msg, exception.message)
96
+ end
97
+ end
98
+
99
+ def test_api_version_mismatch
100
+ api_version = 'client.authentication.k8s.io/v1alpha1'
101
+ expected_version = 'client.authentication.k8s.io/v1beta1'
102
+
103
+ opts = {
104
+ 'command' => 'dummy',
105
+ 'apiVersion' => expected_version
106
+ }
107
+
108
+ creds = JSON.dump(
109
+ 'apiVersion': api_version
110
+ )
111
+
112
+ st = Minitest::Mock.new
113
+ st.expect(:success?, true)
114
+
115
+ expected_msg = "exec plugin is configured to use API version #{expected_version}," \
116
+ " plugin returned version #{api_version}"
117
+
118
+ Open3.stub(:capture3, [creds, nil, st]) do
119
+ exception = assert_raises(RuntimeError) do
120
+ Kubeclient::ExecCredentials.token(opts)
121
+ end
122
+ assert_equal(expected_msg, exception.message)
123
+ end
124
+ end
125
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubeclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alissa Bonas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-26 00:00:00.000000000 Z
11
+ date: 2018-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -191,6 +191,7 @@ files:
191
191
  - lib/kubeclient/common.rb
192
192
  - lib/kubeclient/config.rb
193
193
  - lib/kubeclient/entity_list.rb
194
+ - lib/kubeclient/exec_credentials.rb
194
195
  - lib/kubeclient/google_application_default_credentials.rb
195
196
  - lib/kubeclient/http_error.rb
196
197
  - lib/kubeclient/missing_kind_compatibility.rb
@@ -200,6 +201,7 @@ files:
200
201
  - lib/kubeclient/watch_stream.rb
201
202
  - test/cassettes/kubernetes_guestbook.yml
202
203
  - test/config/allinone.kubeconfig
204
+ - test/config/execauth.kubeconfig
203
205
  - test/config/external-ca.pem
204
206
  - test/config/external-cert.pem
205
207
  - test/config/external-key.rsa
@@ -268,6 +270,7 @@ files:
268
270
  - test/test_component_status.rb
269
271
  - test/test_config.rb
270
272
  - test/test_endpoint.rb
273
+ - test/test_exec_credentials.rb
271
274
  - test/test_google_application_default_credentials.rb
272
275
  - test/test_guestbook_go.rb
273
276
  - test/test_helper.rb
@@ -318,6 +321,7 @@ summary: A client for Kubernetes REST api
318
321
  test_files:
319
322
  - test/cassettes/kubernetes_guestbook.yml
320
323
  - test/config/allinone.kubeconfig
324
+ - test/config/execauth.kubeconfig
321
325
  - test/config/external-ca.pem
322
326
  - test/config/external-cert.pem
323
327
  - test/config/external-key.rsa
@@ -386,6 +390,7 @@ test_files:
386
390
  - test/test_component_status.rb
387
391
  - test/test_config.rb
388
392
  - test/test_endpoint.rb
393
+ - test/test_exec_credentials.rb
389
394
  - test/test_google_application_default_credentials.rb
390
395
  - test/test_guestbook_go.rb
391
396
  - test/test_helper.rb