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.
- checksums.yaml +4 -4
- data/LICENSE +201 -0
- data/README.md +439 -2
- data/exe/knoxcall +8 -0
- data/lib/knoxcall/bootstrap.rb +70 -0
- data/lib/knoxcall/bound_route.rb +47 -0
- data/lib/knoxcall/cli/ai.rb +79 -0
- data/lib/knoxcall/cli/ai_control.rb +275 -0
- data/lib/knoxcall/cli/common.rb +96 -0
- data/lib/knoxcall/cli/init.rb +94 -0
- data/lib/knoxcall/cli/login.rb +306 -0
- data/lib/knoxcall/cli/logout.rb +41 -0
- data/lib/knoxcall/cli/whoami.rb +29 -0
- data/lib/knoxcall/cli.rb +377 -0
- data/lib/knoxcall/client.rb +1025 -0
- data/lib/knoxcall/credentials_file.rb +442 -0
- data/lib/knoxcall/dpop.rb +79 -0
- data/lib/knoxcall/egress_observations.rb +372 -0
- data/lib/knoxcall/errors.rb +304 -0
- data/lib/knoxcall/intercept_patch.rb +181 -0
- data/lib/knoxcall/intercept_pipeline.rb +455 -0
- data/lib/knoxcall/intercept_resolver.rb +140 -0
- data/lib/knoxcall/intercept_store.rb +203 -0
- data/lib/knoxcall/login.rb +144 -0
- data/lib/knoxcall/resources/account.rb +12 -0
- data/lib/knoxcall/resources/agents.rb +25 -0
- data/lib/knoxcall/resources/ai_gateway.rb +417 -0
- data/lib/knoxcall/resources/api_keys.rb +35 -0
- data/lib/knoxcall/resources/audit_logs.rb +45 -0
- data/lib/knoxcall/resources/clients.rb +39 -0
- data/lib/knoxcall/resources/crypto.rb +122 -0
- data/lib/knoxcall/resources/dynamic_db.rb +68 -0
- data/lib/knoxcall/resources/environments.rb +16 -0
- data/lib/knoxcall/resources/logs.rb +51 -0
- data/lib/knoxcall/resources/oauth_clients.rb +34 -0
- data/lib/knoxcall/resources/opportunities.rb +61 -0
- data/lib/knoxcall/resources/pki.rb +41 -0
- data/lib/knoxcall/resources/roles.rb +27 -0
- data/lib/knoxcall/resources/routes.rb +53 -0
- data/lib/knoxcall/resources/secrets.rb +98 -0
- data/lib/knoxcall/resources/unwraps_envelope.rb +90 -0
- data/lib/knoxcall/resources/vaults.rb +77 -0
- data/lib/knoxcall/resources/webhooks.rb +48 -0
- data/lib/knoxcall/resources/workflows.rb +86 -0
- data/lib/knoxcall/resources/wrap.rb +352 -0
- data/lib/knoxcall/route_refusal.rb +67 -0
- data/lib/knoxcall/signup.rb +122 -0
- data/lib/knoxcall/token_exchange.rb +169 -0
- data/lib/knoxcall/ulid.rb +19 -0
- data/lib/knoxcall/warnings.rb +63 -0
- data/lib/knoxcall/workload_provider.rb +192 -0
- data/lib/knoxcall/wrap_faraday_adapter.rb +119 -0
- data/lib/knoxcall/wrap_faraday_middleware.rb +67 -0
- data/lib/knoxcall/wrap_transport.rb +139 -0
- data/lib/knoxcall.rb +45 -1
- 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
|
-
|
|
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
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- KnoxCall
|
|
8
|
-
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-09-27 00:00:00.000000000 Z
|
|
11
12
|
dependencies: []
|
|
12
|
-
description:
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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:
|
|
99
|
+
rubygems_version: 3.5.22
|
|
100
|
+
signing_key:
|
|
40
101
|
specification_version: 4
|
|
41
|
-
summary:
|
|
102
|
+
summary: Official Ruby SDK for the KnoxCall API
|
|
42
103
|
test_files: []
|