nonnative 3.43.0 → 3.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aaedf40a9f9c58092a97588471ef0b2812c4da4c6302076fe28bb8f52bfe2b30
4
- data.tar.gz: 91e5779b4b95b4e2cf9f5b8546a38c9af2ff3bb3ac3aeb4fe23903b92a768f59
3
+ metadata.gz: 86c81434b301e56014082243bce30a3ebed651adb66bdea4b8d725b040982518
4
+ data.tar.gz: 57c657c17907418c17392cb2a687e551d5f8830b72ce3cd4d2200eed2b4fb734
5
5
  SHA512:
6
- metadata.gz: 27eeb19115b61ef97b159ff28deb3429507e8262cc4bf42f005841d30d30de829f9511a9c91ec482e0a5f5a850ccad278cddebe9bda3e1b6f882f977920ecf2c
7
- data.tar.gz: 4f57f4f9ed41cfc84e26b4d65b336f589b70d306ff7f041925d74028277976e468bf9c61dbb6519a2856a0da434ba8fb1e283ff3118e22335e47bf3bc21f8ca9
6
+ metadata.gz: f84551f9e069342560b321958654ebc2bf6f594e72ffc3aea9a3b5d085d3fb71e66c49c5536b76d1f1b8a289328cb9d0e9a9191b4d1a17c26c0c48c388ed785d
7
+ data.tar.gz: 6f955ecf1da3a0f0d374890ccca21a5414845bceab0b626e00c6d103219d80c66fc61d5d8f12c15a00acc847eaab0ba06fe8152529983409111e84e8727a36be
data/README.md CHANGED
@@ -225,7 +225,6 @@ Supported `kind` values (all Ed25519, generation only):
225
225
 
226
226
  - `jwt`: EdDSA JWT with the key id in the `kid` header. `private_key` is a PKCS#8 PEM file.
227
227
  - `paseto`: PASETO v4.public with the key id in a `{"kid":"..."}` footer. `private_key` is a PKCS#8 PEM file. Requires system **libsodium** (via `rbnacl`); it loads lazily, so `require 'nonnative'` works without libsodium until you generate a PASETO token.
228
- - `ssh`: go-service style `base64(claims).base64(signature)` with a raw Ed25519 signature over `v1` claims. `private_key` is an **OpenSSH-format** key. `issuer` and `sub` are ignored (the subject is the key id).
229
228
 
230
229
  The audience is endpoint-scoped; build it with the helpers:
231
230
 
@@ -241,8 +240,6 @@ By default the time claims are pinned to the current time (`iat`/`nbf` at now, `
241
240
  token.generate(aud: 'GET /v1/things', sub: 'user-1', not_before: Time.now + 3600)
242
241
  ```
243
242
 
244
- `ssh` tokens have no `nbf` claim, so passing `not_before` for the `ssh` kind raises `ArgumentError`.
245
-
246
243
  ### 🔁 Lifecycle strategies (Cucumber integration)
247
244
 
248
245
  Nonnative ships Cucumber hooks (when loaded) that support these tags/strategies:
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nonnative
4
- # Builds signed tokens (JWT, PASETO, or SSH) for authenticating against services under test.
4
+ # Builds signed JWT or PASETO tokens for authenticating against services under test.
5
5
  #
6
6
  # The consumer passes in the signing parameters they parsed from their own configuration; this class
7
7
  # is not coupled to any particular service's configuration format. The generated token string is
@@ -20,7 +20,7 @@ module Nonnative
20
20
  # @see Nonnative::Header.auth_bearer
21
21
  class Token
22
22
  # Supported token kinds mapped to their implementation.
23
- KINDS = { 'jwt' => Nonnative::JwtToken, 'paseto' => Nonnative::PasetoToken, 'ssh' => Nonnative::SshToken }.freeze
23
+ KINDS = { 'jwt' => Nonnative::JwtToken, 'paseto' => Nonnative::PasetoToken }.freeze
24
24
 
25
25
  class << self
26
26
  # Builds the audience string for an HTTP endpoint.
@@ -41,10 +41,10 @@ module Nonnative
41
41
  end
42
42
  end
43
43
 
44
- # @param kind [String] token kind, one of `"jwt"`, `"paseto"`, or `"ssh"`
45
- # @param issuer [String] the `iss` claim (unused by the `ssh` kind)
46
- # @param key [String] the key id (JWT `kid` header, PASETO `kid` footer, or SSH `kid` claim)
47
- # @param private_key [String] path to the Ed25519 private key file (PKCS#8 PEM for `jwt`/`paseto`, OpenSSH format for `ssh`)
44
+ # @param kind [String] token kind, one of `"jwt"` or `"paseto"`
45
+ # @param issuer [String] the `iss` claim
46
+ # @param key [String] the key id (JWT `kid` header or PASETO `kid` footer)
47
+ # @param private_key [String] path to a PKCS#8 Ed25519 private key PEM file
48
48
  # @param expiration [Integer] token lifetime in seconds (drives `exp`)
49
49
  # @raise [ArgumentError] if the kind is not supported
50
50
  def initialize(kind:, issuer:, key:, private_key:, expiration:)
@@ -57,13 +57,12 @@ module Nonnative
57
57
  # The optional time claims default to the current time (and the constructor `expiration`), so
58
58
  # omitting them reproduces the token's normal claims. Supply them to mint tokens with specific
59
59
  # time claims for negative auth tests, such as a not-yet-valid (future `not_before`) or
60
- # clock-skewed token. Times are absolute; the `ssh` kind has no `nbf` claim and rejects
61
- # `not_before`.
60
+ # clock-skewed token. Times are absolute.
62
61
  #
63
62
  # @param aud [String] the `aud` claim
64
63
  # @param sub [String] the `sub` claim
65
64
  # @param issued_at [Time, nil] overrides the `iat` claim (default: now)
66
- # @param not_before [Time, nil] overrides the `nbf` claim (default: `issued_at`); unsupported by `ssh`
65
+ # @param not_before [Time, nil] overrides the `nbf` claim (default: `issued_at`)
67
66
  # @param expires_at [Time, nil] overrides the `exp` claim (default: `issued_at` plus `expiration`)
68
67
  # @return [String] the signed token
69
68
  def generate(aud:, sub:, issued_at: nil, not_before: nil, expires_at: nil)
@@ -4,5 +4,5 @@ module Nonnative
4
4
  # The current gem version.
5
5
  #
6
6
  # @return [String]
7
- VERSION = '3.43.0'
7
+ VERSION = '3.44.0'
8
8
  end
data/lib/nonnative.rb CHANGED
@@ -68,10 +68,9 @@ require 'rspec/wait'
68
68
  require 'puma'
69
69
  require 'puma/server'
70
70
 
71
- # jwt-eddsa (with the ed25519 gem) and ssh_data are pure Ruby and need no system library, so they load
72
- # here. PASETO's rbnacl needs system libsodium, so Nonnative::PasetoToken requires it lazily instead.
71
+ # jwt-eddsa (with the ed25519 gem) is pure Ruby and needs no system library, so it loads here.
72
+ # PASETO's rbnacl needs system libsodium, so Nonnative::PasetoToken requires it lazily instead.
73
73
  require 'jwt/eddsa'
74
- require 'ssh_data'
75
74
 
76
75
  require 'nonnative/version'
77
76
  require 'nonnative/error'
@@ -126,7 +125,6 @@ require 'nonnative/header'
126
125
  require 'nonnative/ed25519_key'
127
126
  require 'nonnative/jwt_token'
128
127
  require 'nonnative/paseto_token'
129
- require 'nonnative/ssh_token'
130
128
  require 'nonnative/token'
131
129
 
132
130
  # The main namespace for the gem.
@@ -218,10 +216,10 @@ module Nonnative
218
216
  # The signing parameters are passed in directly; this is not coupled to any service's
219
217
  # configuration format. The generated token string is ready for {Nonnative::Header.auth_bearer}.
220
218
  #
221
- # @param kind [String] token kind, one of `"jwt"`, `"paseto"`, or `"ssh"`
222
- # @param issuer [String] the `iss` claim (unused by the `ssh` kind)
223
- # @param key [String] the key id (JWT `kid` header, PASETO `kid` footer, or SSH `kid` claim)
224
- # @param private_key [String] path to the Ed25519 private key file (PKCS#8 PEM for `jwt`/`paseto`, OpenSSH format for `ssh`)
219
+ # @param kind [String] token kind, one of `"jwt"` or `"paseto"`
220
+ # @param issuer [String] the `iss` claim
221
+ # @param key [String] the key id (JWT `kid` header or PASETO `kid` footer)
222
+ # @param private_key [String] path to a PKCS#8 Ed25519 private key PEM file
225
223
  # @param expiration [Integer] token lifetime in seconds (drives `exp`)
226
224
  # @return [Nonnative::Token]
227
225
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nonnative
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.43.0
4
+ version: 3.44.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Falkowski
@@ -363,26 +363,6 @@ dependencies:
363
363
  - - "<"
364
364
  - !ruby/object:Gem::Version
365
365
  version: '5'
366
- - !ruby/object:Gem::Dependency
367
- name: ssh_data
368
- requirement: !ruby/object:Gem::Requirement
369
- requirements:
370
- - - ">="
371
- - !ruby/object:Gem::Version
372
- version: '1'
373
- - - "<"
374
- - !ruby/object:Gem::Version
375
- version: '3'
376
- type: :runtime
377
- prerelease: false
378
- version_requirements: !ruby/object:Gem::Requirement
379
- requirements:
380
- - - ">="
381
- - !ruby/object:Gem::Version
382
- version: '1'
383
- - - "<"
384
- - !ruby/object:Gem::Version
385
- version: '3'
386
366
  description: Starts OS processes, in-process Ruby servers, and proxy-only services
387
367
  with TCP readiness checks and fault-injection proxies.
388
368
  email:
@@ -441,7 +421,6 @@ files:
441
421
  - lib/nonnative/slicer_socket_pair.rb
442
422
  - lib/nonnative/socket_pair.rb
443
423
  - lib/nonnative/socket_pair_factory.rb
444
- - lib/nonnative/ssh_token.rb
445
424
  - lib/nonnative/start_error.rb
446
425
  - lib/nonnative/startup.rb
447
426
  - lib/nonnative/stop_error.rb
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nonnative
4
- # Generates go-service style SSH tokens for authenticating against services under test.
5
- #
6
- # Despite the name this is not an SSH protocol signature: the key is loaded from an OpenSSH-format
7
- # Ed25519 private key and used as a raw Ed25519 key, matching go-service's SSH token scheme. The token
8
- # is `<base64(claims)>.<base64(signature)>`, where the signature is a raw Ed25519 signature over the
9
- # claims JSON. Claims are ver/kid/sub/aud/iat/exp, with `sub == kid == key` and `iat`/`exp` in Unix
10
- # nanoseconds. `issuer` and `sub` are accepted for a uniform interface with the other kinds but unused:
11
- # SSH tokens have no issuer, and the subject is always the key id.
12
- #
13
- # @example
14
- # ssh = Nonnative::SshToken.new(key: 'key-1', private_key: 'config/id_ed25519', expiration: 3600)
15
- # ssh.generate(aud: 'GET /v1/things', sub: 'user-1')
16
- #
17
- # @see https://github.com/github/ssh_data ssh_data
18
- class SshToken
19
- # The go-service SSH token format version.
20
- TOKEN_VERSION = 'v1'
21
-
22
- # @param key [String] the key id; also used as the subject
23
- # @param private_key [String] path to an OpenSSH-format Ed25519 private key file
24
- # @param expiration [Integer] token lifetime in seconds (drives `exp`)
25
- def initialize(key:, private_key:, expiration:, **)
26
- @key = key
27
- @private_key = private_key
28
- @expiration = expiration
29
- end
30
-
31
- # Generates a signed SSH token.
32
- #
33
- # SSH tokens carry only `iat`/`exp` (in Unix nanoseconds); there is no `nbf` claim, so
34
- # `not_before` is rejected.
35
- #
36
- # @param aud [String] the `aud` claim (for example `"GET /v1/things"` or a gRPC full method)
37
- # @param issued_at [Time, nil] overrides the `iat` claim (default: now)
38
- # @param expires_at [Time, nil] overrides the `exp` claim (default: `issued_at` plus `expiration`)
39
- # @raise [ArgumentError] if `not_before` is given (SSH tokens have no `nbf` claim)
40
- # @return [String] the token, `"<base64(claims)>.<base64(signature)>"`
41
- def generate(aud:, issued_at: nil, expires_at: nil, not_before: nil, **)
42
- raise ArgumentError, "ssh tokens do not support 'not_before' (no nbf claim)" unless not_before.nil?
43
-
44
- iat = nanoseconds(issued_at || Time.now)
45
- claims = {
46
- ver: TOKEN_VERSION,
47
- kid: @key,
48
- sub: @key,
49
- aud: aud,
50
- iat: iat,
51
- exp: expires_at ? nanoseconds(expires_at) : iat + (@expiration * 1_000_000_000)
52
- }.to_json
53
-
54
- signature = Ed25519::SigningKey.new(seed).sign(claims)
55
-
56
- "#{Base64.strict_encode64(claims)}.#{Base64.strict_encode64(signature)}"
57
- end
58
-
59
- private
60
-
61
- def nanoseconds(time)
62
- (time.to_i * 1_000_000_000) + time.nsec
63
- end
64
-
65
- def seed
66
- SSHData::PrivateKey.parse_openssh(File.read(@private_key)).first.sk[0, 32]
67
- end
68
- end
69
- end