agentadmit 1.10.0 → 1.10.1

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: ccda6bad890712e5c6060b2c33d02df1b1245ff48918a267cede579acf3f0d84
4
- data.tar.gz: 5ef222b57006bcba2bd589c2b6276117abcfac031230263a8063ef56449cf355
3
+ metadata.gz: 305d2a2680095a277efd613bbc48dc1c0e948109f05ce01aa995dbff99c172bc
4
+ data.tar.gz: 559cae430ea15ea9c66fb7e758efdab50fa652625d67f31bf7dab06d4606842d
5
5
  SHA512:
6
- metadata.gz: a703d18e7a9a55ed4a34b07d2ed295ddfbc49fabdba0caef6b49ef0a57cb670097b78ef5a53849035e22cc3a29709977836df8b8bdd4f660fc09bb20adaac84e
7
- data.tar.gz: 06a8b43f3a18b696df4ddccb6abb0130c62addff9d4ab948b51ea6ea1d2b0e2bf2cdb11b5cd1da90734fc94d9b6f7e3512f9fae536563418d4d8a361fc058a8b
6
+ metadata.gz: 145b55beeabfec1d0860f8d2bdf772b28e2a4a8ca0926c814aac49c3f516bee31f1a66f4dd26c894803452a178bfd296083ec89143185e4c3925aa8d4ae7ac07
7
+ data.tar.gz: f1e2e43b3ea29c1f59a67d2b8791050d8058cac7210edac2cab8b9ef5f6915b35e91479d30ea3cd44709b1ccaaab16c855dc38851f8aab0ce567e1a693b7914f
data/README.md CHANGED
@@ -388,7 +388,7 @@ use AgentAdmit::Middleware, scope_for: ->(env) { SCOPES[env["PATH_INFO"]] }
388
388
  use AgentAdmit::Middleware, scope_for: "read:orders"
389
389
  ```
390
390
 
391
- `AgentAdmit::CallerConsent` never sends `scope_used` (its consent gate precedes any scope disclosure; the scope check stays local, after consent) but still reports endpoint and method. Direct client calls pass the same optional keyword arguments:
391
+ `AgentAdmit::CallerConsent` reports its configured scope too and sets the hosted `consent_first` guard automatically, so denied caller classes receive no scope-state disclosure. Direct client calls pass the same optional keyword arguments:
392
392
 
393
393
  ```ruby
394
394
  result = AgentAdmit::IntrospectionClient.new.verify(
@@ -134,21 +134,17 @@ module AgentAdmit
134
134
  token = (env["HTTP_AUTHORIZATION"] || "").sub(/\Abearer /i, "")
135
135
 
136
136
  begin
137
- # The verify body carries endpoint/method audit telemetry only.
138
- # scope_used is deliberately NOT sent from this middleware: the
139
- # hosted refusal body carries no consent verdict and no user_id, so
140
- # a hosted scope refusal here could not be consent-resolved -- and
141
- # consent must precede any scope disclosure (Patent FIG. 3). The
142
- # scope check stays local, after the consent gate, exactly as the
143
- # other AgentAdmit SDKs do.
137
+ # Declare the exact exercised scope in the same hosted round trip.
138
+ # consent_first guarantees a denied caller class cannot learn scope
139
+ # state before this middleware returns its consent 403.
144
140
  result = @client.verify(token,
141
+ scope_used: @required_scope,
145
142
  endpoint: env["PATH_INFO"],
146
- method: env["REQUEST_METHOD"])
143
+ method: env["REQUEST_METHOD"],
144
+ consent_first: true)
147
145
  rescue InsufficientScopeError
148
- # Unreachable when this middleware performs the verify (scope_used
149
- # is never sent, so the hosted service cannot refuse on scope).
150
- # Kept as a fail-closed guard that reveals no scope state to a
151
- # caller class whose consent was never evaluated.
146
+ # Hosted consent-first ordering guarantees this refusal is reachable
147
+ # only after consent was granted.
152
148
  return [403, { "Content-Type" => "application/json" },
153
149
  [{ error: "insufficient_scope",
154
150
  message: "Call refused by the authorization service." }.to_json]]
@@ -91,7 +91,7 @@ module AgentAdmit
91
91
  # @raise [IntrospectionError] if the service is unreachable
92
92
  # @raise [RateLimitError] if rate-limited and retries exhausted
93
93
  #
94
- def verify(token, scope_used: nil, endpoint: nil, method: nil)
94
+ def verify(token, scope_used: nil, endpoint: nil, method: nil, consent_first: false)
95
95
  unless token.start_with?(@config.token_prefix_access)
96
96
  raise InvalidTokenError, "Not an AgentAdmit access token"
97
97
  end
@@ -105,7 +105,8 @@ module AgentAdmit
105
105
 
106
106
  (0..max_retries).each do |attempt|
107
107
  request = build_request(uri, token, scope_used: scope_used,
108
- endpoint: endpoint, method: method)
108
+ endpoint: endpoint, method: method,
109
+ consent_first: consent_first)
109
110
 
110
111
  begin
111
112
  response = http.request(request)
@@ -371,7 +372,8 @@ module AgentAdmit
371
372
  # 20). Unknown fields are OMITTED, never sent as null or empty string --
372
373
  # the hosted audit row then honestly records "not reported".
373
374
  #
374
- def build_request(uri, token, scope_used: nil, endpoint: nil, method: nil)
375
+ def build_request(uri, token, scope_used: nil, endpoint: nil, method: nil,
376
+ consent_first: false)
375
377
  req = Net::HTTP::Post.new(uri.path)
376
378
  req["Authorization"] = "Bearer #{@config.api_key}"
377
379
  req["Content-Type"] = "application/json"
@@ -383,6 +385,7 @@ module AgentAdmit
383
385
  body[:endpoint] = path if path
384
386
  verb = presence_of(method)
385
387
  body[:method] = verb.upcase[0, 20] if verb
388
+ body[:consent_first] = true if consent_first
386
389
 
387
390
  req.body = JSON.generate(body)
388
391
  req
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentAdmit
4
- VERSION = "1.10.0"
4
+ VERSION = "1.10.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agentadmit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Emerson