atlas_rb 1.9.0 → 1.9.2

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: 9bfa2bcb90b5d30ebbf8a4a2612b1a6aafab5fc4eb07df8b12c3ba904ab1fb48
4
- data.tar.gz: 9afb80d4f4cecfdfa5204ad101967fe4360057a2222ca573153e00bfc3a3e281
3
+ metadata.gz: 235448544b8690ecf3a941cc259ab5f049442f609766666297c571e336ac3eae
4
+ data.tar.gz: d3dc2e59aab57397176e959eec0a28478d5a15dbc0ebe2be459c775a42ec00ce
5
5
  SHA512:
6
- metadata.gz: 2dbd56463086ce26fc3380eaee4e850dfe6c66a15d6e716c22271d8a13230fbb9db122195f368b41dad8edf96eb153540c699c567f0d43b50b96bc95e8d5c1b7
7
- data.tar.gz: cfba3517bd027ae9ff972b3316da4a3bd941e28a080961a69d16625b874bd6b6f5ececd503327d5f0b9ebc56ffc118bd36c04823e2a94ba07aa45a4179fcdc4b
6
+ metadata.gz: 786316240b620bed1a107503c2162d0add7979bbc70574a9f0d1b7cbc473e616e28001d8db9abc75edc972c544211207cbd93f1eee93e674f365d2b0cbecc5e0
7
+ data.tar.gz: aa6f59d62916ce00cb59ae8cca4e8e029ff96ff4c1fcb40041a4c4fd27d675dfcf98b7a2a04cca5a6f9876bdec846415196d09499f91ee170abb636964b22d25
data/.version CHANGED
@@ -1 +1 @@
1
- 1.9.0
1
+ 1.9.2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.2
4
+
5
+ ### Added — `read_only:` on `System::Token.mint`
6
+
7
+ `AtlasRb::System::Token.mint(nuid:, read_only: true)` mints a token Atlas
8
+ structurally restricts to read-shaped actions, independent of what `nuid`
9
+ could otherwise do — the shape to hand to a non-human caller (e.g. an Atlas
10
+ MCP client) that must never be able to mutate the repository. Omitted, mint
11
+ is unchanged (full-privilege, as before).
12
+
3
13
  ## 1.8.8
4
14
 
5
15
  ### Added — type-agnostic current MODS (`Resource.mods`)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- atlas_rb (1.9.0)
4
+ atlas_rb (1.9.2)
5
5
  faraday (~> 2.7)
6
6
  faraday-follow_redirects (~> 0.3.0)
7
7
  faraday-multipart (~> 1)
@@ -25,7 +25,7 @@ GEM
25
25
  net-http (~> 0.5)
26
26
  hashie (5.1.0)
27
27
  logger
28
- json (2.20.0)
28
+ json (2.21.1)
29
29
  jwt (2.10.3)
30
30
  base64
31
31
  logger (1.7.0)
@@ -196,11 +196,13 @@ module AtlasRb
196
196
  # Used exclusively by classes under {AtlasRb::System}.
197
197
  #
198
198
  # @param params [Hash] query-string / body params.
199
+ # @param on_behalf_of [String, nil] optional NUID sent as a plain (not
200
+ # signed) `On-Behalf-Of` header — this path is already backend-only.
199
201
  # @return [Faraday::Connection] a system-authenticated connection.
200
202
  # @raise [RuntimeError] if the credential is not configured.
201
203
  # @raise [NameError] if `Rails` is not loaded (the gem assumes a
202
204
  # Rails host for system-path calls).
203
- def system_connection(params = {})
205
+ def system_connection(params = {}, on_behalf_of: nil)
204
206
  token = Rails.application.credentials.atlas_system_token ||
205
207
  raise("atlas_rb: Rails.application.credentials.atlas_system_token not configured")
206
208
 
@@ -209,6 +211,7 @@ module AtlasRb
209
211
  "Authorization" => "Bearer #{token}",
210
212
  "User" => "NUID #{AtlasRb::System::NUID}"
211
213
  }
214
+ headers["On-Behalf-Of"] = "NUID #{on_behalf_of}" if on_behalf_of
212
215
 
213
216
  Faraday.new(
214
217
  url: ENV.fetch("ATLAS_URL", nil),
@@ -216,6 +219,10 @@ module AtlasRb
216
219
  headers: headers
217
220
  ) do |f|
218
221
  instrument(f)
222
+ # Narrowly path-scoped (see each class) — a no-op for System::User /
223
+ # System::Token, and gives System::Work the same typed errors as #connection.
224
+ f.use AtlasRb::Middleware::RaiseOnStaleResource
225
+ f.use AtlasRb::Middleware::RaiseOnResourceError
219
226
  f.response :follow_redirects
220
227
  f.adapter Faraday.default_adapter
221
228
  end
@@ -27,13 +27,21 @@ module AtlasRb
27
27
  # System-gated. The returned token authenticates as `nuid` in BYO-JWT
28
28
  # mode (Atlas resolves identity from the token's `sub`, ignores any
29
29
  # `User:` / `On-Behalf-Of` header, and refuses `:system`/`:anonymous`).
30
- # Full-privilege for that user, 1-week TTL, single-jti.
30
+ # Full-privilege for that user, 1-week TTL, single-jti — unless
31
+ # `read_only` is set, in which case Atlas structurally restricts the
32
+ # token to read-shaped actions regardless of what `nuid` could
33
+ # otherwise do. That's the shape to hand to a non-human caller (e.g.
34
+ # an MCP client) that must never be able to mutate the repository.
31
35
  #
32
36
  # @param nuid [String] the NUID the token will act as.
37
+ # @param read_only [Boolean] mint a token restricted to read-shaped
38
+ # actions only.
33
39
  # @return [String, nil] the JWT, or nil when the NUID has no Atlas User
34
40
  # row (404) — a clean "no such user" signal for the caller to surface.
35
- def self.mint(nuid:)
36
- response = system_connection.post("/nuid", { nuid: nuid }.to_json)
41
+ def self.mint(nuid:, read_only: false)
42
+ body = { nuid: nuid }
43
+ body[:read_only] = true if read_only
44
+ response = system_connection.post("/nuid", body.to_json)
37
45
  return nil if response.status == 404
38
46
 
39
47
  AtlasRb::Mash.new(JSON.parse(response.body))["token"]
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AtlasRb
4
+ module System
5
+ # Showcase publishing: link a freshly-created Work into a depositor's
6
+ # featured showcase Collection on their behalf, without granting the
7
+ # depositor themselves standing edit rights on that shared Collection.
8
+ #
9
+ # Atlas scopes this narrowly on both sides (see Atlas's `Ability`): the
10
+ # target Collection must be `featured`, and the Work must belong to the
11
+ # `on_behalf_of` NUID — never an arbitrary or private Work. Cerberus's
12
+ # `WorkDeposit#create_published` ("Publish to my community") is the one
13
+ # caller today.
14
+ #
15
+ # Always authenticates via {FaradayHelper#system_connection}, so there is
16
+ # no way to issue this as a regular user.
17
+ class Work
18
+ extend AtlasRb::FaradayHelper
19
+
20
+ # @param work_id [String] the Work ID to link.
21
+ # @param collection_id [String] the (must-be-featured) showcase
22
+ # Collection to link the Work into.
23
+ # @param on_behalf_of [String] the depositor NUID this write is
24
+ # attributed to — required (unlike the regular, human-facing
25
+ # {AtlasRb::Work.add_linked_member}), since a :system call with no
26
+ # attribution defeats the point of this path, and Atlas's Ability
27
+ # grant is itself conditioned on it matching the Work's depositor.
28
+ # @return [Array<String>] the Work's full set of linked Collection
29
+ # noids after the add.
30
+ # @raise [AtlasRb::StaleResourceError] optimistic-lock conflict.
31
+ # @raise [AtlasRb::LinkedMemberError] structural rejection (HTTP 422) —
32
+ # non-Collection target, tombstoned work/target, already a structural
33
+ # member.
34
+ # @raise [AtlasRb::ForbiddenError] Atlas refused the link (HTTP 403) —
35
+ # e.g. the target Collection isn't featured, or on_behalf_of doesn't
36
+ # own the Work.
37
+ #
38
+ # @example From Cerberus's publish-to-showcase deposit branch
39
+ # AtlasRb::System::Work.add_linked_member(work.id, showcase.id, on_behalf_of: depositor_nuid)
40
+ def self.add_linked_member(work_id, collection_id, on_behalf_of:)
41
+ JSON.parse(
42
+ system_connection({ collection_id: collection_id }, on_behalf_of: on_behalf_of)
43
+ .post("/works/#{work_id}/linked_members")&.body
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
data/lib/atlas_rb.rb CHANGED
@@ -31,6 +31,7 @@ require_relative "atlas_rb/admin/community"
31
31
  require_relative "atlas_rb/system"
32
32
  require_relative "atlas_rb/system/user"
33
33
  require_relative "atlas_rb/system/token"
34
+ require_relative "atlas_rb/system/work"
34
35
  require_relative "atlas_rb/audit_event"
35
36
 
36
37
  # Ruby client for the Atlas API — Northeastern University's institutional
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cliff
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-11 00:00:00.000000000 Z
11
+ date: 2026-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -152,6 +152,7 @@ files:
152
152
  - lib/atlas_rb/system.rb
153
153
  - lib/atlas_rb/system/token.rb
154
154
  - lib/atlas_rb/system/user.rb
155
+ - lib/atlas_rb/system/work.rb
155
156
  - lib/atlas_rb/user.rb
156
157
  - lib/atlas_rb/version.rb
157
158
  - lib/atlas_rb/work.rb