knoxcall 0.0.1 → 1.0.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -0
  3. data/README.md +439 -2
  4. data/exe/knoxcall +8 -0
  5. data/lib/knoxcall/bootstrap.rb +70 -0
  6. data/lib/knoxcall/bound_route.rb +47 -0
  7. data/lib/knoxcall/cli/ai.rb +79 -0
  8. data/lib/knoxcall/cli/ai_control.rb +275 -0
  9. data/lib/knoxcall/cli/common.rb +96 -0
  10. data/lib/knoxcall/cli/init.rb +94 -0
  11. data/lib/knoxcall/cli/login.rb +306 -0
  12. data/lib/knoxcall/cli/logout.rb +41 -0
  13. data/lib/knoxcall/cli/whoami.rb +29 -0
  14. data/lib/knoxcall/cli.rb +377 -0
  15. data/lib/knoxcall/client.rb +1025 -0
  16. data/lib/knoxcall/credentials_file.rb +442 -0
  17. data/lib/knoxcall/dpop.rb +79 -0
  18. data/lib/knoxcall/egress_observations.rb +372 -0
  19. data/lib/knoxcall/errors.rb +304 -0
  20. data/lib/knoxcall/intercept_patch.rb +181 -0
  21. data/lib/knoxcall/intercept_pipeline.rb +455 -0
  22. data/lib/knoxcall/intercept_resolver.rb +140 -0
  23. data/lib/knoxcall/intercept_store.rb +203 -0
  24. data/lib/knoxcall/login.rb +144 -0
  25. data/lib/knoxcall/resources/account.rb +12 -0
  26. data/lib/knoxcall/resources/agents.rb +25 -0
  27. data/lib/knoxcall/resources/ai_gateway.rb +417 -0
  28. data/lib/knoxcall/resources/api_keys.rb +35 -0
  29. data/lib/knoxcall/resources/audit_logs.rb +45 -0
  30. data/lib/knoxcall/resources/clients.rb +39 -0
  31. data/lib/knoxcall/resources/crypto.rb +122 -0
  32. data/lib/knoxcall/resources/dynamic_db.rb +68 -0
  33. data/lib/knoxcall/resources/environments.rb +16 -0
  34. data/lib/knoxcall/resources/logs.rb +51 -0
  35. data/lib/knoxcall/resources/oauth_clients.rb +34 -0
  36. data/lib/knoxcall/resources/opportunities.rb +61 -0
  37. data/lib/knoxcall/resources/pki.rb +41 -0
  38. data/lib/knoxcall/resources/roles.rb +27 -0
  39. data/lib/knoxcall/resources/routes.rb +53 -0
  40. data/lib/knoxcall/resources/secrets.rb +98 -0
  41. data/lib/knoxcall/resources/unwraps_envelope.rb +90 -0
  42. data/lib/knoxcall/resources/vaults.rb +77 -0
  43. data/lib/knoxcall/resources/webhooks.rb +48 -0
  44. data/lib/knoxcall/resources/workflows.rb +86 -0
  45. data/lib/knoxcall/resources/wrap.rb +352 -0
  46. data/lib/knoxcall/route_refusal.rb +67 -0
  47. data/lib/knoxcall/signup.rb +122 -0
  48. data/lib/knoxcall/token_exchange.rb +169 -0
  49. data/lib/knoxcall/ulid.rb +19 -0
  50. data/lib/knoxcall/warnings.rb +63 -0
  51. data/lib/knoxcall/workload_provider.rb +192 -0
  52. data/lib/knoxcall/wrap_faraday_adapter.rb +119 -0
  53. data/lib/knoxcall/wrap_faraday_middleware.rb +67 -0
  54. data/lib/knoxcall/wrap_transport.rb +139 -0
  55. data/lib/knoxcall.rb +45 -1
  56. metadata +70 -9
@@ -0,0 +1,119 @@
1
+ require "faraday"
2
+ require "uri"
3
+ require "knoxcall/wrap_transport"
4
+ require "knoxcall/intercept_pipeline"
5
+
6
+ module KnoxCall
7
+ module Resources
8
+ class Wrap
9
+ # A Faraday adapter that routes a wrapped third-party SDK's requests
10
+ # through KnoxCall — the Ruby analogue of the Node SDK's +wrap.fetch()+.
11
+ # It is the TERMINAL adapter in a Faraday connection: instead of
12
+ # performing the HTTP call itself it hands each request to the shared
13
+ # {InterceptPipeline}, which sends it through {KnoxCall::Client#call}
14
+ # (route mode — the Route the intercept manifest names) or
15
+ # {KnoxCall::Client#ephemeral} (transparent mode), the same way
16
+ # {KnoxCall::BoundRoute} delegates to +call+ — no second HTTP stack.
17
+ # Direct decisions (route-around, own hosts, the kill switch, a D4
18
+ # fallback) perform the ORIGINAL request via a plain Faraday adapter.
19
+ #
20
+ # Built and wired by {KnoxCall::Resources::Wrap#faraday_connection}. For
21
+ # SDKs that build their own stack see {Wrap#faraday_middleware}; for the
22
+ # opt-in process-wide seam see {Wrap#intercept!}.
23
+ #
24
+ # This file references +Faraday+ constants at load time, so it is required
25
+ # lazily (only once the +faraday+ gem is confirmed present) — the base SDK
26
+ # never depends on Faraday.
27
+ class FaradayAdapter < Faraday::Adapter
28
+ # @param app the next app in the Faraday stack (the terminal endpoint)
29
+ # @param options [Hash] a single positional options Hash:
30
+ # - +:pipeline+ [InterceptPipeline] the shared pipeline (built by faraday_connection), or
31
+ # the {InterceptPipeline#initialize} keywords to build one (+:client+ required)
32
+ # - +:direct_adapter+ the Faraday adapter used for direct calls (default Faraday.default_adapter)
33
+ def initialize(app, options = {})
34
+ super(app)
35
+ @direct_adapter = options[:direct_adapter]
36
+ @pipeline = options[:pipeline] ||
37
+ InterceptPipeline.new(all_hosts: true, **options.reject { |k, _| %i[pipeline direct_adapter].include?(k) })
38
+ @mutex = Mutex.new
39
+ end
40
+
41
+ # The pipeline (ready / refresh / manifest / stop).
42
+ attr_reader :pipeline
43
+
44
+ def call(env)
45
+ # Capture the request BEFORE super: super installs env.response,
46
+ # after which some Faraday versions read env.body as the response body.
47
+ url = env.url.to_s
48
+ method = env.method.to_s.upcase
49
+ body = env.body
50
+ request_headers = env.request_headers
51
+ headers = {}
52
+ request_headers.each { |k, v| headers[k] = v }
53
+ super
54
+
55
+ decision = @pipeline.decide(url, method)
56
+ if decision.direct?
57
+ # Decided BEFORE sending — never "try KnoxCall then fall back",
58
+ # which would already have transited. The ORIGINAL request is
59
+ # forwarded untouched.
60
+ @pipeline.direct_decided(decision, url, method: method, headers: headers)
61
+ return direct_call(env, method, body, request_headers)
62
+ end
63
+
64
+ resp = @pipeline.send(decision, url: url, method: method, headers: headers, body: body)
65
+ return direct_call(env, method, body, request_headers) if resp == InterceptPipeline::DIRECT
66
+
67
+ finish(env, resp)
68
+ rescue KnoxCall::ConnectionTimeoutError => e
69
+ # Map KnoxCall transport failures onto Faraday's own error types so a
70
+ # wrapped SDK's retry/rescue logic (which knows Faraday, not KnoxCall)
71
+ # still fires.
72
+ raise Faraday::TimeoutError, e.message
73
+ rescue KnoxCall::NetworkError => e
74
+ raise Faraday::ConnectionFailed, e.message
75
+ end
76
+
77
+ private
78
+
79
+ # Convert the Net::HTTPResponse returned by ephemeral()/call() into a
80
+ # Faraday response and hand control back up the stack.
81
+ def finish(env, resp)
82
+ headers = {}
83
+ resp.each_header { |k, v| headers[k] = v }
84
+ save_response(env, resp.code.to_i, resp.body, headers, resp.message)
85
+ @app.call(env)
86
+ end
87
+
88
+ # Perform the ORIGINAL request against the real upstream, untouched,
89
+ # via a plain Faraday adapter — never through KnoxCall.
90
+ def direct_call(env, method, body, request_headers)
91
+ conn = @mutex.synchronize { @direct_conn ||= build_direct_connection }
92
+ resp = conn.run_request(method.downcase.to_sym, env.url, body, request_headers)
93
+ # `headers`, not `response_headers` — the latter is a Faraday::Env
94
+ # method, not a Faraday::Response one.
95
+ save_response(env, resp.status, resp.body, resp.headers, resp.reason_phrase)
96
+ @app.call(env)
97
+ end
98
+
99
+ def build_direct_connection
100
+ spec = @direct_adapter || Faraday.default_adapter
101
+ Faraday.new { |f| f.adapter(*Array(spec)) }
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ # Advanced use: reference the adapter by symbol in a hand-built Faraday stack
109
+ # (`f.adapter :knoxcall, pipeline: ...`). faraday_connection references the
110
+ # adapter CLASS directly, so this symbol registration is a convenience only.
111
+ begin
112
+ Faraday::Adapter.register_middleware(knoxcall: KnoxCall::Resources::Wrap::FaradayAdapter)
113
+ rescue StandardError
114
+ # best-effort: registration is purely for the `:knoxcall` shorthand; the
115
+ # supported entrypoint (faraday_connection) uses the class directly, so a
116
+ # register_middleware signature drift across Faraday versions must not break
117
+ # the feature.
118
+ nil
119
+ end
@@ -0,0 +1,67 @@
1
+ require "faraday"
2
+ require "knoxcall/intercept_pipeline"
3
+
4
+ module KnoxCall
5
+ module Resources
6
+ class Wrap
7
+ # A Faraday MIDDLEWARE (not an adapter) for stacks an SDK builds itself
8
+ # and lets you add middleware to: insert it anywhere above the adapter
9
+ # and a request the pipeline claims — a Route covers its host + path, or
10
+ # the host is listed — is answered from KnoxCall without ever reaching
11
+ # the SDK's own adapter; every other request continues down the stack
12
+ # untouched. Built by {Wrap#faraday_middleware}:
13
+ #
14
+ # conn = SomeSDK.connection # an SDK-built Faraday stack
15
+ # conn.builder.insert_before(Faraday::Adapter, *knox.wrap.faraday_middleware(hosts: ["api.resend.com"]))
16
+ #
17
+ # It shares {InterceptPipeline} with the adapter and the Net::HTTP seam,
18
+ # so the decisions are identical.
19
+ class FaradayMiddleware < Faraday::Middleware
20
+ # @param app the next app in the stack
21
+ # @param options [Hash] +pipeline:+ (an {InterceptPipeline}) or the
22
+ # keyword arguments to build one (+client:+ required)
23
+ def initialize(app, options = {})
24
+ super(app)
25
+ @pipeline = options[:pipeline] || InterceptPipeline.new(**options.reject { |k, _| k == :pipeline })
26
+ end
27
+
28
+ def call(env)
29
+ url = env.url.to_s
30
+ method = env.method.to_s.upcase
31
+ decision = @pipeline.decide(url, method)
32
+ headers = {}
33
+ env.request_headers.each { |k, v| headers[k] = v }
34
+ if decision.direct?
35
+ @pipeline.direct_decided(decision, url, method: method, headers: headers)
36
+ return @app.call(env)
37
+ end
38
+
39
+ resp = @pipeline.send(decision, url: url, method: method, headers: headers, body: env.body)
40
+ return @app.call(env) if resp == InterceptPipeline::DIRECT
41
+
42
+ finish(env, resp)
43
+ rescue KnoxCall::ConnectionTimeoutError => e
44
+ raise Faraday::TimeoutError, e.message
45
+ rescue KnoxCall::NetworkError => e
46
+ raise Faraday::ConnectionFailed, e.message
47
+ end
48
+
49
+ private
50
+
51
+ # Short-circuit the stack with the Net::HTTPResponse the pipeline
52
+ # returned: the same completion an adapter performs.
53
+ def finish(env, resp)
54
+ headers = {}
55
+ resp.each_header { |k, v| headers[k] = v }
56
+ env.status = resp.code.to_i
57
+ env.reason_phrase = resp.message.to_s.strip
58
+ env.body = resp.body
59
+ env.response_headers = Faraday::Utils::Headers.new.tap { |h| h.update(headers) }
60
+ response = Faraday::Response.new
61
+ env.response = response
62
+ response.finish(env)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,139 @@
1
+ require "uri"
2
+
3
+ module KnoxCall
4
+ # Pure, transport-agnostic helpers behind the Ruby wrap transport
5
+ # ({KnoxCall::Resources::Wrap#faraday_connection}) — the analogue of the Node
6
+ # SDK's +src/wrap-transport.ts+. Deliberately free of any Faraday dependency
7
+ # so they load with the base SDK and stay unit-testable without the optional
8
+ # gem.
9
+ #
10
+ # A wrapped third-party SDK keeps its own serialization, retries, idempotency
11
+ # keys and error types; only its HTTP transport is swapped for one that
12
+ # re-targets each request through KnoxCall's ephemeral proxy in transparent
13
+ # mode. The provider credential the SDK sets on its +Authorization+ header is
14
+ # LIFTED out-of-band (transit mode, the default) or replaced by a named
15
+ # escrowed credential (escrow mode) — the raw key never forwards as a header
16
+ # and is never logged.
17
+ module WrapTransport
18
+ module_function
19
+
20
+ # Built-in route-around defaults. Mirrors the SERVER's raw-PAN refusal
21
+ # (src/client-api/ephemeral-proxy.ts PAN_ENDPOINT_DENYLIST) so a wrapped
22
+ # SDK's raw-card call is sent straight to the provider instead of
23
+ # hard-failing on the server-side 403. Deliberately conservative and
24
+ # identical in spirit to the Node DEFAULT_ROUTE_AROUND.
25
+ DEFAULT_ROUTE_AROUND = [
26
+ { host: "api.stripe.com", path_prefix: "/v1/tokens",
27
+ reason: "raw-card endpoint (PCI): sent direct to the provider" },
28
+ { host: "api.stripe.com", path_prefix: "/v1/sources",
29
+ reason: "raw-card endpoint (PCI): sent direct to the provider" }
30
+ ].freeze
31
+
32
+ # Upstream headers the shim must NOT forward through ephemeral(): the
33
+ # provider Authorization is lifted out-of-band; Host/Content-Length are
34
+ # recomputed by the transport.
35
+ DROP_FORWARDED = %w[authorization host content-length].freeze
36
+
37
+ # Read a rule value tolerating both symbol and string keys, so a
38
+ # caller-supplied Hash reads naturally either way.
39
+ def rule_value(rule, key)
40
+ return nil unless rule.is_a?(Hash)
41
+
42
+ rule.key?(key) ? rule[key] : rule[key.to_s]
43
+ end
44
+
45
+ # PARITY §21's host contract: lower-case, surrounding whitespace and IPv6
46
+ # brackets stripped, a single trailing dot stripped — so a trailing-dot
47
+ # FQDN ("api.stripe.com.") can't dodge an exact-match rule. The server's
48
+ # PAN denylist and the intercept manifest normalize the same way.
49
+ def normalize_host(host)
50
+ host.to_s.strip.downcase.delete_prefix("[").delete_suffix("]").sub(/\.\z/, "")
51
+ end
52
+
53
+ # The first route-around rule matching this URL, or +nil+. A trailing-dot
54
+ # FQDN ("api.stripe.com.") resolves to the same host but would dodge an
55
+ # exact-match rule — both sides are normalized, matching the server's PAN
56
+ # denylist and the Node wrapper.
57
+ def match_route_around(url, rules)
58
+ u = begin
59
+ URI.parse(url)
60
+ rescue URI::InvalidURIError
61
+ return nil
62
+ end
63
+ host = normalize_host(u.host)
64
+ return nil if host.empty?
65
+
66
+ Array(rules).each do |r|
67
+ next if host != normalize_host(rule_value(r, :host))
68
+
69
+ prefix = rule_value(r, :path_prefix)
70
+ next if prefix && !u.path.to_s.start_with?(prefix.to_s)
71
+
72
+ return r
73
+ end
74
+ nil
75
+ end
76
+
77
+ # Validate caller-supplied route-around rules: a +host+ that isn't a bare
78
+ # DNS hostname (a scheme/port/path slipped in) can never match a parsed URL
79
+ # host and would silently disable the rule — fail loud instead. Mirrors the
80
+ # Node assertRouteAroundRules and the escrow allowed-hosts contract.
81
+ def assert_route_around_rules(rules)
82
+ Array(rules).each do |r|
83
+ h = rule_value(r, :host).to_s.strip
84
+ parsed = begin
85
+ URI.parse("https://#{h}").host.to_s
86
+ rescue URI::InvalidURIError
87
+ ""
88
+ end
89
+ next unless h.empty? || normalize_host(parsed) != normalize_host(h)
90
+
91
+ raise WrapSandboxMismatchError,
92
+ "invalid route_around host #{rule_value(r, :host).inspect}: " \
93
+ "expected a bare DNS hostname (no scheme, port, or path)."
94
+ end
95
+ end
96
+
97
+ # Both-must-agree (PARITY §18): a Stripe +sk_+/+rk_+ key's Test/Live prefix
98
+ # must match the client's sandbox flag, so a test key can never be wrapped
99
+ # by a live client (or vice versa). Publishable +pk_+ keys are rejected
100
+ # outright — they are not server credentials. Non-Stripe schemes we cannot
101
+ # classify are left alone. +authorization_value+ is the full header value,
102
+ # e.g. "Bearer sk_live_…".
103
+ def assert_key_matches_sandbox(authorization_value, sandbox)
104
+ return if authorization_value.nil? || authorization_value.to_s.empty?
105
+
106
+ sandbox = sandbox ? true : false
107
+ # Trim BEFORE stripping the scheme: a leading space would otherwise stop
108
+ # the anchored Bearer from matching, leaving the whole value in +token+
109
+ # and silently skipping the check (Node review regression #1).
110
+ token = authorization_value.to_s.strip.sub(/\ABearer\s+/i, "").strip
111
+ if token.match?(/\Apk_(?:test|live)_/)
112
+ raise WrapSandboxMismatchError,
113
+ "A Stripe publishable key (pk_…) is not a server credential and cannot be wrapped. " \
114
+ "Use a secret (sk_…) or restricted (rk_…) key."
115
+ end
116
+
117
+ m = /\A(?:sk|rk)_(test|live)_/.match(token)
118
+ return unless m # unknown / non-Stripe scheme — nothing to assert
119
+
120
+ key_is_test = m[1] == "test"
121
+ return if key_is_test == sandbox
122
+
123
+ raise WrapSandboxMismatchError,
124
+ "Provider key is a #{key_is_test ? 'TEST' : 'LIVE'} key but the KnoxCall client was " \
125
+ "constructed with sandbox=#{sandbox}. Test keys require sandbox:true, live keys require " \
126
+ "sandbox:false — construct a matching client."
127
+ end
128
+
129
+ # The upstream headers to forward (everything the SDK set except the dropped
130
+ # ones), keyed as the SDK supplied them.
131
+ def forwardable_headers(headers)
132
+ out = {}
133
+ headers.each do |k, v|
134
+ out[k] = v unless DROP_FORWARDED.include?(k.to_s.downcase)
135
+ end
136
+ out
137
+ end
138
+ end
139
+ end
data/lib/knoxcall.rb CHANGED
@@ -1 +1,45 @@
1
- raise LoadError, "knoxcall 0.0.1 is a name placeholder; the KnoxCall SDK release will replace it."
1
+ require "knoxcall/errors"
2
+ require "knoxcall/ulid"
3
+ require "knoxcall/warnings"
4
+ require "knoxcall/bootstrap"
5
+ require "knoxcall/credentials_file"
6
+ require "knoxcall/dpop"
7
+ require "knoxcall/client"
8
+ require "knoxcall/bound_route"
9
+ require "knoxcall/signup"
10
+ require "knoxcall/token_exchange"
11
+ require "knoxcall/workload_provider"
12
+ require "knoxcall/login"
13
+ require "knoxcall/wrap_transport"
14
+ require "knoxcall/intercept_resolver"
15
+ require "knoxcall/intercept_store"
16
+ require "knoxcall/egress_observations"
17
+ require "knoxcall/intercept_pipeline"
18
+ require "knoxcall/resources/unwraps_envelope"
19
+ require "knoxcall/resources/routes"
20
+ require "knoxcall/resources/secrets"
21
+ require "knoxcall/resources/webhooks"
22
+ require "knoxcall/resources/workflows"
23
+ require "knoxcall/resources/clients"
24
+ require "knoxcall/resources/oauth_clients"
25
+ require "knoxcall/resources/environments"
26
+ require "knoxcall/resources/api_keys"
27
+ require "knoxcall/resources/roles"
28
+ require "knoxcall/resources/account"
29
+ require "knoxcall/resources/audit_logs"
30
+ require "knoxcall/resources/logs"
31
+ require "knoxcall/resources/agents"
32
+ require "knoxcall/resources/crypto"
33
+ require "knoxcall/resources/pki"
34
+ require "knoxcall/resources/vaults"
35
+ require "knoxcall/resources/dynamic_db"
36
+ require "knoxcall/resources/ai_gateway"
37
+ require "knoxcall/resources/wrap"
38
+ require "knoxcall/resources/opportunities"
39
+
40
+ module KnoxCall
41
+ VERSION = "0.1.0"
42
+ SDK_VERSION = "knoxcall-ruby/#{VERSION}"
43
+ DEFAULT_API_BASE = "https://api.knoxcall.com"
44
+ DEFAULT_CLOUD_HOST = "knoxcall.com"
45
+ end
metadata CHANGED
@@ -1,27 +1,87 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knoxcall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - KnoxCall
8
- bindir: bin
8
+ autorequire:
9
+ bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-09-27 00:00:00.000000000 Z
11
12
  dependencies: []
12
- description: This name is reserved by KnoxCall. The official SDK will be published
13
- here.
14
- executables: []
13
+ description: 'Ruby client for the KnoxCall multi-tenant API gateway and secrets platform:
14
+ OAuth 2.1 + DPoP auth, route proxying, secrets, vaults, PKI, crypto, AI Gateway,
15
+ and webhook verification.'
16
+ email:
17
+ executables:
18
+ - knoxcall
15
19
  extensions: []
16
20
  extra_rdoc_files: []
17
21
  files:
22
+ - LICENSE
18
23
  - README.md
24
+ - exe/knoxcall
19
25
  - lib/knoxcall.rb
20
- homepage: https://knoxcall.com
26
+ - lib/knoxcall/bootstrap.rb
27
+ - lib/knoxcall/bound_route.rb
28
+ - lib/knoxcall/cli.rb
29
+ - lib/knoxcall/cli/ai.rb
30
+ - lib/knoxcall/cli/ai_control.rb
31
+ - lib/knoxcall/cli/common.rb
32
+ - lib/knoxcall/cli/init.rb
33
+ - lib/knoxcall/cli/login.rb
34
+ - lib/knoxcall/cli/logout.rb
35
+ - lib/knoxcall/cli/whoami.rb
36
+ - lib/knoxcall/client.rb
37
+ - lib/knoxcall/credentials_file.rb
38
+ - lib/knoxcall/dpop.rb
39
+ - lib/knoxcall/egress_observations.rb
40
+ - lib/knoxcall/errors.rb
41
+ - lib/knoxcall/intercept_patch.rb
42
+ - lib/knoxcall/intercept_pipeline.rb
43
+ - lib/knoxcall/intercept_resolver.rb
44
+ - lib/knoxcall/intercept_store.rb
45
+ - lib/knoxcall/login.rb
46
+ - lib/knoxcall/resources/account.rb
47
+ - lib/knoxcall/resources/agents.rb
48
+ - lib/knoxcall/resources/ai_gateway.rb
49
+ - lib/knoxcall/resources/api_keys.rb
50
+ - lib/knoxcall/resources/audit_logs.rb
51
+ - lib/knoxcall/resources/clients.rb
52
+ - lib/knoxcall/resources/crypto.rb
53
+ - lib/knoxcall/resources/dynamic_db.rb
54
+ - lib/knoxcall/resources/environments.rb
55
+ - lib/knoxcall/resources/logs.rb
56
+ - lib/knoxcall/resources/oauth_clients.rb
57
+ - lib/knoxcall/resources/opportunities.rb
58
+ - lib/knoxcall/resources/pki.rb
59
+ - lib/knoxcall/resources/roles.rb
60
+ - lib/knoxcall/resources/routes.rb
61
+ - lib/knoxcall/resources/secrets.rb
62
+ - lib/knoxcall/resources/unwraps_envelope.rb
63
+ - lib/knoxcall/resources/vaults.rb
64
+ - lib/knoxcall/resources/webhooks.rb
65
+ - lib/knoxcall/resources/workflows.rb
66
+ - lib/knoxcall/resources/wrap.rb
67
+ - lib/knoxcall/route_refusal.rb
68
+ - lib/knoxcall/signup.rb
69
+ - lib/knoxcall/token_exchange.rb
70
+ - lib/knoxcall/ulid.rb
71
+ - lib/knoxcall/warnings.rb
72
+ - lib/knoxcall/workload_provider.rb
73
+ - lib/knoxcall/wrap_faraday_adapter.rb
74
+ - lib/knoxcall/wrap_faraday_middleware.rb
75
+ - lib/knoxcall/wrap_transport.rb
76
+ homepage: https://docs.knoxcall.com/api-reference
21
77
  licenses:
22
78
  - Apache-2.0
23
79
  metadata:
80
+ homepage_uri: https://docs.knoxcall.com/api-reference
81
+ source_code_uri: https://github.com/knoxcall/sdk-ruby
82
+ changelog_uri: https://github.com/knoxcall/sdk-ruby/blob/main/CHANGELOG.md
24
83
  rubygems_mfa_required: 'true'
84
+ post_install_message:
25
85
  rdoc_options: []
26
86
  require_paths:
27
87
  - lib
@@ -36,7 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
36
96
  - !ruby/object:Gem::Version
37
97
  version: '0'
38
98
  requirements: []
39
- rubygems_version: 4.0.16
99
+ rubygems_version: 3.5.22
100
+ signing_key:
40
101
  specification_version: 4
41
- summary: Placeholder for the official KnoxCall Ruby SDK.
102
+ summary: Official Ruby SDK for the KnoxCall API
42
103
  test_files: []