kessel-sdk 1.10.0 → 1.11.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: 136206dbccfc87a36252fa0b635f195d00ebc861f9d26c3a35095403257e971c
4
- data.tar.gz: 6e1366c5ed2fc78316fd7804f4ff31ac59819817e919fda84e689c7c8023f980
3
+ metadata.gz: 6f118f8d4a64bb88e16061100917338de50a57456725240592395e4e9469eb18
4
+ data.tar.gz: 0cdba6a003c929eb0e111ef832fdc602b13a0dc48dc52ea773522c096408cea8
5
5
  SHA512:
6
- metadata.gz: 2c015adbcbf6838b582f598b31d7860d31541c4adeb622c60877399b67ae797a516f603185640890f6c711311e0ff9f09ef0968153219b9dddcc070bb75acfeb
7
- data.tar.gz: 4967035e1789c864e4197e5e6ffcbf7bfe6e2d47dc24b2c1a4823b83e198171f043f0ceb0f9bee4cbbc5ae5f495882c2654b6d6e08989a4cc15fae5de3513a96
6
+ metadata.gz: d172c0dc4223a7aca090c58a14ab2c86421383ad1fc0c7931690f576fa1d88130bde656b495455f0fcd91c331d4f2dcb935963a3f9f7a5708640849102d26ddd
7
+ data.tar.gz: 1112d3a51e7c23f00371d88adf7cc17e8323e20d4d80663272f7a55c87e52c5b50374582c2c203a75d14954773b0ebb982c4df79553a067edcfc737d44721eb9
data/README.md CHANGED
@@ -58,7 +58,6 @@ lib/
58
58
  sig/ # RBS type signatures for hand-written code
59
59
  spec/ # RSpec test suite
60
60
  examples/ # Working examples with dotenv configuration
61
- docs/ # Domain-specific guidelines (see Documentation below)
62
61
  ```
63
62
 
64
63
  Files under `lib/kessel/inventory/v*/`, `lib/google/`, and `lib/buf/` are **generated** by `buf generate` and must never be hand-edited. They are automatically regenerated every 6 hours via CI.
@@ -355,16 +354,11 @@ ruby check.rb
355
354
 
356
355
  ## Documentation
357
356
 
358
- Detailed domain-specific guidelines are maintained in the `docs/` directory:
357
+ For AI-assisted development context, see [AGENTS.md](AGENTS.md). Directory-local `GUIDELINES.md` files provide detailed conventions for specific areas of the codebase:
359
358
 
360
- - **[API Contracts](docs/api-contracts-guidelines.md)** -- Protobuf code generation, module/namespace mapping, ClientBuilder API, request/response patterns, and RBS type signatures
361
- - **[Integration](docs/integration-guidelines.md)** -- gRPC client construction, authentication flows, RBAC helpers, streaming/pagination, and environment configuration
362
- - **[Security](docs/security-guidelines.md)** -- Token caching thread safety, gRPC channel security, credential validation, and secrets management
363
- - **[Performance](docs/performance-guidelines.md)** -- Token caching, gRPC client reuse, bulk vs. individual operations, consistency controls, and streaming pagination
364
- - **[Error Handling](docs/error-handling-guidelines.md)** -- Custom exception hierarchy, error wrapping conventions, and gRPC error passthrough policy
365
- - **[Testing](docs/testing-guidelines.md)** -- RSpec configuration, mocking conventions, coverage setup, and CI expectations
366
-
367
- For AI-assisted development context, see [AGENTS.md](AGENTS.md).
359
+ - **[lib/kessel/inventory/GUIDELINES.md](lib/kessel/inventory/GUIDELINES.md)** -- Inventory module: ClientBuilder, service wiring, V1beta2 API patterns, auth integration
360
+ - **[lib/kessel/rbac/GUIDELINES.md](lib/kessel/rbac/GUIDELINES.md)** -- RBAC V2 module conventions
361
+ - **[examples/GUIDELINES.md](examples/GUIDELINES.md)** -- Example script conventions
368
362
 
369
363
  ## Release Instructions
370
364
 
@@ -496,7 +490,7 @@ rake release
496
490
  4. Push to the branch (`git push origin feature/amazing-feature`)
497
491
  5. Open a Pull Request
498
492
 
499
- Please review the [domain-specific guidelines](docs/) before contributing. All specs must pass on Ruby 3.3 and 3.4. Fix RuboCop violations before merging, and update RBS type signatures in `sig/kessel/` when modifying hand-written code.
493
+ Please review [AGENTS.md](AGENTS.md) and the directory-local `GUIDELINES.md` files before contributing. All specs must pass on Ruby 3.3 and 3.4. Fix RuboCop violations before merging, and update RBS type signatures in `sig/kessel/` when modifying hand-written code.
500
494
 
501
495
  ## License
502
496
 
@@ -7,7 +7,7 @@ require 'google/protobuf'
7
7
  require 'google/protobuf/any_pb'
8
8
 
9
9
 
10
- descriptor_data = "\n\x17google/rpc/status.proto\x12\ngoogle.rpc\x1a\x19google/protobuf/any.proto\"f\n\x06Status\x12\x12\n\x04\x63ode\x18\x01 \x01(\x05R\x04\x63ode\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\x12.\n\x07\x64\x65tails\x18\x03 \x03(\x0b\x32\x14.google.protobuf.AnyR\x07\x64\x65tailsBa\n\x0e\x63om.google.rpcB\x0bStatusProtoP\x01Z7google.golang.org/genproto/googleapis/rpc/status;status\xf8\x01\x01\xa2\x02\x03RPCb\x06proto3"
10
+ descriptor_data = "\n\x17google/rpc/status.proto\x12\ngoogle.rpc\x1a\x19google/protobuf/any.proto\"f\n\x06Status\x12\x12\n\x04\x63ode\x18\x01 \x01(\x05R\x04\x63ode\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\x12.\n\x07\x64\x65tails\x18\x03 \x03(\x0b\x32\x14.google.protobuf.AnyR\x07\x64\x65tailsB^\n\x0e\x63om.google.rpcB\x0bStatusProtoP\x01Z7google.golang.org/genproto/googleapis/rpc/status;status\xa2\x02\x03RPCb\x06proto3"
11
11
 
12
12
  pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
13
  pool.add_serialized_file(descriptor_data)
@@ -0,0 +1,161 @@
1
+ # Inventory Module Guidelines
2
+
3
+ This directory contains the Kessel Inventory client module -- the `ClientBuilder` fluent API, version-specific service wiring, and generated protobuf/gRPC stubs. The `ClientBuilder` base class is defined in `../inventory.rb` (the `Kessel::Inventory` module), and each version file in this directory creates service-specific builders from it.
4
+
5
+ For repo-wide conventions (testing framework, RBS signatures, file headers, error patterns), see AGENTS.md at the repository root.
6
+
7
+ ## File Organization
8
+
9
+ ### Hand-written files (editable)
10
+
11
+ - `../inventory.rb` -- `Kessel::Inventory` module with `client_builder_for_stub` factory and `ClientBuilder` base class
12
+ - `v1.rb` -- Service wiring for `KesselInventoryHealthService::ClientBuilder` (health checks)
13
+ - `v1beta1.rb` -- Service wiring for V1beta1 typed resource/relationship services (deprecated)
14
+ - `v1beta2.rb` -- Service wiring for `KesselInventoryService::ClientBuilder` (current API)
15
+
16
+ ### Generated files (never edit)
17
+
18
+ Everything under `v1/`, `v1beta1/`, and `v1beta2/` subdirectories (`*_pb.rb`, `*_services_pb.rb`) is generated by `buf generate` and overwritten automatically every 6 hours via CI. Changes to these files must go upstream in the `.proto` definitions at `buf.build/project-kessel/inventory-api`.
19
+
20
+ ## ClientBuilder Pattern
21
+
22
+ ### Factory Function
23
+
24
+ `client_builder_for_stub(stub_class)` dynamically creates a new `Class` inheriting from `ClientBuilder` with `@stub_class` set. Each service module creates its builder as a constant:
25
+
26
+ ```ruby
27
+ ClientBuilder = ::Kessel::Inventory.client_builder_for_stub(Stub)
28
+ ```
29
+
30
+ Do not call `client_builder_for_stub` repeatedly at runtime -- the result is cached as a constant.
31
+
32
+ ### Fluent API
33
+
34
+ `ClientBuilder` uses method chaining -- all authentication methods return `self`:
35
+
36
+ ```ruby
37
+ # Insecure (local dev only)
38
+ client = KesselInventoryService::ClientBuilder.new(target).insecure.build
39
+
40
+ # OAuth2 authenticated
41
+ client = KesselInventoryService::ClientBuilder.new(target)
42
+ .oauth2_client_authenticated(oauth2_client_credentials: creds)
43
+ .build
44
+
45
+ # Custom credentials
46
+ client = KesselInventoryService::ClientBuilder.new(target)
47
+ .authenticated(call_credentials: call_creds, channel_credentials: chan_creds)
48
+ .build
49
+ ```
50
+
51
+ ### Credential Defaults and Validation
52
+
53
+ - When no channel credentials are set, `build` defaults to `GRPC::Core::ChannelCredentials.new` (TLS). This secure-by-default behavior must be preserved.
54
+ - `insecure` sets a sentinel (`:this_channel_is_insecure`) that prevents composing with call credentials.
55
+ - `validate_credentials` runs immediately on each auth method call, not deferred to `build`. This ensures invalid configurations fail at configuration time. Do not move validation to `build`.
56
+ - `build` calls `credentials.compose(@call_credentials)` when both channel and call credentials are present.
57
+
58
+ ### Build Output
59
+
60
+ `build` returns a single gRPC stub instance (not a tuple). The underlying gRPC channel manages its own HTTP/2 connection pool. Build once at application startup and reuse -- do not create a new stub per request.
61
+
62
+ ## Service Wiring Pattern
63
+
64
+ Every gRPC service module must follow this exact pattern:
65
+
66
+ ```ruby
67
+ # frozen_string_literal: true
68
+
69
+ require 'kessel/inventory'
70
+ require 'kessel/inventory/v1betaN/some_service_services_pb'
71
+
72
+ include Kessel::Inventory
73
+
74
+ module Kessel
75
+ module Inventory
76
+ module V1betaN
77
+ module KesselSomeService
78
+ ClientBuilder = ::Kessel::Inventory.client_builder_for_stub(Stub)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ ```
84
+
85
+ The `include Kessel::Inventory` at the top level is required for `client_builder_for_stub` to resolve. The `Stub` constant comes from the generated `*_services_pb.rb` file.
86
+
87
+ When adding a new service, also add the `ClientBuilder` constant declaration in `sig/kessel/inventory.rbs`.
88
+
89
+ ## Version Conventions
90
+
91
+ | Directory | Status | Service |
92
+ |---|---|---|
93
+ | `v1/` | Active | `KesselInventoryHealthService` (health checks only) |
94
+ | `v1beta2/` | Active (current) | `KesselInventoryService` (unified inventory API) |
95
+ | `v1beta1/` | Deprecated | Typed K8s resources/relationships. Do not extend. |
96
+
97
+ All new features target `v1beta2`. The unified `KesselInventoryService` uses `ReportResource`/`DeleteResource` instead of resource-specific services.
98
+
99
+ Protobuf package `kessel.inventory.v1beta2` maps to Ruby module `Kessel::Inventory::V1beta2` -- note lowercase `beta` (not `V1Beta2`). This follows the protobuf-to-Ruby naming convention from `buf generate`.
100
+
101
+ ## V1beta2 API Patterns
102
+
103
+ ### Check Operations
104
+
105
+ Check operations use a triplet: `object` (ResourceReference), `relation` (string), `subject` (SubjectReference). Use `Check` for read-path authorization and `CheckForUpdate` for strongly consistent pre-mutation checks.
106
+
107
+ `CheckSelf` omits the subject (inferred from auth context).
108
+
109
+ ### Bulk Operations
110
+
111
+ `CheckBulk` and `CheckForUpdateBulk` accept 1--1000 items per RPC. Responses use a `pairs` field where each pair contains either `item` (success) or `error` (`Google::Rpc::Status`). Always check per-item errors -- the RPC can succeed while individual items fail.
112
+
113
+ ### Resource Reporting
114
+
115
+ `ReportResourceRequest` requires `type`, `reporter_type`, `reporter_instance_id`, `representations`, and `write_visibility`. Convert Ruby hashes to protobuf `Struct` via `Google::Protobuf::Struct.decode_json(hash.to_json)`.
116
+
117
+ ### Consistency Controls
118
+
119
+ The `Consistency` message supports `minimize_latency` (default, may be stale), `at_least_as_fresh` (token from prior write), and `at_least_as_acknowledged` (waits for all acknowledged writes). `WriteVisibility` on report requests defaults to `WRITE_VISIBILITY_UNSPECIFIED` -- set `IMMEDIATE` only when the caller will immediately `Check` the newly reported resource.
120
+
121
+ ### Streaming RPCs
122
+
123
+ `StreamedListObjects` and `StreamedListSubjects` use server-side streaming with `RequestPagination` (limit + continuation_token). Iterate with `.each` for constant memory.
124
+
125
+ ### Allowed Enum
126
+
127
+ V1beta2 uses a shared top-level `Allowed` enum (`ALLOWED_TRUE`, `ALLOWED_FALSE`). V1beta1 uses per-response nested enums (`CheckResponse::Allowed`).
128
+
129
+ ### HTTP API Routes
130
+
131
+ - V1: `/api/kessel/v1/{method}`
132
+ - V1beta1: `/api/inventory/v1beta1/{domain}/{method}`
133
+ - V1beta2: `/api/kessel/v1beta2/{method}`
134
+ - RBAC V2 REST: `/api/rbac/v2/workspaces/`
135
+
136
+ ## Authentication Integration
137
+
138
+ Authentication feeds into the `ClientBuilder` through two paths:
139
+
140
+ - **gRPC path**: `Kessel::GRPC#oauth2_call_credentials(auth)` wraps an `OAuth2ClientCredentials` instance as `GRPC::Core::CallCredentials`. The proc is invoked on every RPC call, hitting the token cache fast path when the token is valid. Do not add blocking operations inside this proc.
141
+ - **HTTP path**: `Kessel::Auth#oauth2_auth_request(oauth)` returns an `OAuth2AuthRequest` implementing the `AuthRequest` interface. The `configure_request(request)` method sets the `authorization` header on `Net::HTTPRequest` objects.
142
+
143
+ The `AuthRequest` module defines an interface contract -- any class including it must implement `configure_request` or callers get `NotImplementedError`. New auth mechanisms must implement this interface and have matching RBS signatures in `sig/kessel/auth.rbs`.
144
+
145
+ ### Token Caching
146
+
147
+ `OAuth2ClientCredentials` uses double-checked locking with a `@generation` counter to coalesce concurrent refresh requests into a single SSO call. Cached tokens are frozen with `.freeze` for concurrent read safety. Use `force_refresh: true` only after receiving an explicit 401/UNAUTHENTICATED error, never preemptively.
148
+
149
+ ## Console Helper
150
+
151
+ `lib/kessel/console.rb` provides `principal_from_rh_identity` and `principal_from_rh_identity_header` for converting Red Hat identity headers into `SubjectReference` objects. It depends on `Kessel::RBAC::V2` factory helpers (specifically `principal_subject`).
152
+
153
+ The `IDENTITY_TYPE_FIELDS` constant maps identity types to their JSON field names (`'User' => 'user'`, `'ServiceAccount' => 'service_account'`). When adding a new identity type, add it to this hash.
154
+
155
+ ## Adding a New Service Version
156
+
157
+ 1. Run `buf generate` to produce stubs in `lib/kessel/inventory/<version>/`.
158
+ 2. Create `lib/kessel/inventory/<version>.rb` following the service wiring pattern above.
159
+ 3. Add the `ClientBuilder` constant declaration to `sig/kessel/inventory.rbs`.
160
+ 4. Add a corresponding example in `examples/`.
161
+ 5. Run `bundle exec rspec` and `steep check`.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/acquire_lock_request.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+
9
+
10
+ descriptor_data = "\n3kessel/inventory/v1beta2/acquire_lock_request.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\"6\n\x12\x41\x63quireLockRequest\x12 \n\x07lock_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06lockIdBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ AcquireLockRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.AcquireLockRequest").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/acquire_lock_response.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+
8
+ descriptor_data = "\n4kessel/inventory/v1beta2/acquire_lock_response.proto\x12\x18kessel.inventory.v1beta2\"4\n\x13\x41\x63quireLockResponse\x12\x1d\n\nlock_token\x18\x01 \x01(\tR\tlockTokenBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
9
+
10
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
+ pool.add_serialized_file(descriptor_data)
12
+
13
+ module Kessel
14
+ module Inventory
15
+ module V1beta2
16
+ AcquireLockResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.AcquireLockResponse").msgclass
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/create_tuples_request.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/relationship_pb'
8
+ require 'kessel/inventory/v1beta2/relation_fencing_check_pb'
9
+
10
+
11
+ descriptor_data = "\n4kessel/inventory/v1beta2/create_tuples_request.proto\x12\x18kessel.inventory.v1beta2\x1a+kessel/inventory/v1beta2/relationship.proto\x1a\x35kessel/inventory/v1beta2/relation_fencing_check.proto\"\xd9\x01\n\x13\x43reateTuplesRequest\x12\x16\n\x06upsert\x18\x01 \x01(\x08R\x06upsert\x12>\n\x06tuples\x18\x02 \x03(\x0b\x32&.kessel.inventory.v1beta2.RelationshipR\x06tuples\x12X\n\rfencing_check\x18\x03 \x01(\x0b\x32..kessel.inventory.v1beta2.RelationFencingCheckH\x00R\x0c\x66\x65ncingCheck\x88\x01\x01\x42\x10\n\x0e_fencing_checkBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
12
+
13
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
14
+ pool.add_serialized_file(descriptor_data)
15
+
16
+ module Kessel
17
+ module Inventory
18
+ module V1beta2
19
+ CreateTuplesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.CreateTuplesRequest").msgclass
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/create_tuples_response.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/consistency_token_pb'
8
+
9
+
10
+ descriptor_data = "\n5kessel/inventory/v1beta2/create_tuples_response.proto\x12\x18kessel.inventory.v1beta2\x1a\x30kessel/inventory/v1beta2/consistency_token.proto\"o\n\x14\x43reateTuplesResponse\x12W\n\x11\x63onsistency_token\x18\x01 \x01(\x0b\x32*.kessel.inventory.v1beta2.ConsistencyTokenR\x10\x63onsistencyTokenBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ CreateTuplesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.CreateTuplesResponse").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/delete_tuples_request.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+ require 'kessel/inventory/v1beta2/relation_tuple_filter_pb'
9
+ require 'kessel/inventory/v1beta2/relation_fencing_check_pb'
10
+
11
+
12
+ descriptor_data = "\n4kessel/inventory/v1beta2/delete_tuples_request.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\x1a\x34kessel/inventory/v1beta2/relation_tuple_filter.proto\x1a\x35kessel/inventory/v1beta2/relation_fencing_check.proto\"\xd0\x01\n\x13\x44\x65leteTuplesRequest\x12M\n\x06\x66ilter\x18\x01 \x01(\x0b\x32-.kessel.inventory.v1beta2.RelationTupleFilterB\x06\xbaH\x03\xc8\x01\x01R\x06\x66ilter\x12X\n\rfencing_check\x18\x02 \x01(\x0b\x32..kessel.inventory.v1beta2.RelationFencingCheckH\x00R\x0c\x66\x65ncingCheck\x88\x01\x01\x42\x10\n\x0e_fencing_checkBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
13
+
14
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
15
+ pool.add_serialized_file(descriptor_data)
16
+
17
+ module Kessel
18
+ module Inventory
19
+ module V1beta2
20
+ DeleteTuplesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.DeleteTuplesRequest").msgclass
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/delete_tuples_response.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/consistency_token_pb'
8
+
9
+
10
+ descriptor_data = "\n5kessel/inventory/v1beta2/delete_tuples_response.proto\x12\x18kessel.inventory.v1beta2\x1a\x30kessel/inventory/v1beta2/consistency_token.proto\"o\n\x14\x44\x65leteTuplesResponse\x12W\n\x11\x63onsistency_token\x18\x01 \x01(\x0b\x32*.kessel.inventory.v1beta2.ConsistencyTokenR\x10\x63onsistencyTokenBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ DeleteTuplesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.DeleteTuplesResponse").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/read_tuples_request.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+ require 'kessel/inventory/v1beta2/relation_tuple_filter_pb'
9
+ require 'kessel/inventory/v1beta2/request_pagination_pb'
10
+ require 'kessel/inventory/v1beta2/consistency_pb'
11
+
12
+
13
+ descriptor_data = "\n2kessel/inventory/v1beta2/read_tuples_request.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\x1a\x34kessel/inventory/v1beta2/relation_tuple_filter.proto\x1a\x31kessel/inventory/v1beta2/request_pagination.proto\x1a*kessel/inventory/v1beta2/consistency.proto\"\xa1\x02\n\x11ReadTuplesRequest\x12M\n\x06\x66ilter\x18\x01 \x01(\x0b\x32-.kessel.inventory.v1beta2.RelationTupleFilterB\x06\xbaH\x03\xc8\x01\x01R\x06\x66ilter\x12P\n\npagination\x18\x02 \x01(\x0b\x32+.kessel.inventory.v1beta2.RequestPaginationH\x00R\npagination\x88\x01\x01\x12L\n\x0b\x63onsistency\x18\x03 \x01(\x0b\x32%.kessel.inventory.v1beta2.ConsistencyH\x01R\x0b\x63onsistency\x88\x01\x01\x42\r\n\x0b_paginationB\x0e\n\x0c_consistencyBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
14
+
15
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
16
+ pool.add_serialized_file(descriptor_data)
17
+
18
+ module Kessel
19
+ module Inventory
20
+ module V1beta2
21
+ ReadTuplesRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.ReadTuplesRequest").msgclass
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/read_tuples_response.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/relationship_pb'
8
+ require 'kessel/inventory/v1beta2/response_pagination_pb'
9
+ require 'kessel/inventory/v1beta2/consistency_token_pb'
10
+
11
+
12
+ descriptor_data = "\n3kessel/inventory/v1beta2/read_tuples_response.proto\x12\x18kessel.inventory.v1beta2\x1a+kessel/inventory/v1beta2/relationship.proto\x1a\x32kessel/inventory/v1beta2/response_pagination.proto\x1a\x30kessel/inventory/v1beta2/consistency_token.proto\"\xf9\x01\n\x12ReadTuplesResponse\x12<\n\x05tuple\x18\x01 \x01(\x0b\x32&.kessel.inventory.v1beta2.RelationshipR\x05tuple\x12L\n\npagination\x18\x02 \x01(\x0b\x32,.kessel.inventory.v1beta2.ResponsePaginationR\npagination\x12W\n\x11\x63onsistency_token\x18\x03 \x01(\x0b\x32*.kessel.inventory.v1beta2.ConsistencyTokenR\x10\x63onsistencyTokenBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
13
+
14
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
15
+ pool.add_serialized_file(descriptor_data)
16
+
17
+ module Kessel
18
+ module Inventory
19
+ module V1beta2
20
+ ReadTuplesResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.ReadTuplesResponse").msgclass
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_fencing_check.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+
9
+
10
+ descriptor_data = "\n5kessel/inventory/v1beta2/relation_fencing_check.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\"`\n\x14RelationFencingCheck\x12 \n\x07lock_id\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x06lockId\x12&\n\nlock_token\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\tlockTokenBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ RelationFencingCheck = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationFencingCheck").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_object_reference.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+ require 'kessel/inventory/v1beta2/relation_object_type_pb'
9
+
10
+
11
+ descriptor_data = "\n8kessel/inventory/v1beta2/relation_object_reference.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\x1a\x33kessel/inventory/v1beta2/relation_object_type.proto\"|\n\x17RelationObjectReference\x12H\n\x04type\x18\x01 \x01(\x0b\x32,.kessel.inventory.v1beta2.RelationObjectTypeB\x06\xbaH\x03\xc8\x01\x01R\x04type\x12\x17\n\x02id\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x02idBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
12
+
13
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
14
+ pool.add_serialized_file(descriptor_data)
15
+
16
+ module Kessel
17
+ module Inventory
18
+ module V1beta2
19
+ RelationObjectReference = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationObjectReference").msgclass
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_object_type.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+
9
+
10
+ descriptor_data = "\n3kessel/inventory/v1beta2/relation_object_type.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\"X\n\x12RelationObjectType\x12%\n\tnamespace\x18\x01 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\tnamespace\x12\x1b\n\x04name\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x04nameBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ RelationObjectType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationObjectType").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_subject_filter.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+
8
+ descriptor_data = "\n6kessel/inventory/v1beta2/relation_subject_filter.proto\x12\x18kessel.inventory.v1beta2\"\xf9\x01\n\x15RelationSubjectFilter\x12\x30\n\x11subject_namespace\x18\x01 \x01(\tH\x00R\x10subjectNamespace\x88\x01\x01\x12&\n\x0csubject_type\x18\x02 \x01(\tH\x01R\x0bsubjectType\x88\x01\x01\x12\"\n\nsubject_id\x18\x03 \x01(\tH\x02R\tsubjectId\x88\x01\x01\x12\x1f\n\x08relation\x18\x04 \x01(\tH\x03R\x08relation\x88\x01\x01\x42\x14\n\x12_subject_namespaceB\x0f\n\r_subject_typeB\r\n\x0b_subject_idB\x0b\n\t_relationBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
9
+
10
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
11
+ pool.add_serialized_file(descriptor_data)
12
+
13
+ module Kessel
14
+ module Inventory
15
+ module V1beta2
16
+ RelationSubjectFilter = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationSubjectFilter").msgclass
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_subject_reference.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+ require 'kessel/inventory/v1beta2/relation_object_reference_pb'
9
+
10
+
11
+ descriptor_data = "\n9kessel/inventory/v1beta2/relation_subject_reference.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\x1a\x38kessel/inventory/v1beta2/relation_object_reference.proto\"\x9d\x01\n\x18RelationSubjectReference\x12\x1f\n\x08relation\x18\x01 \x01(\tH\x00R\x08relation\x88\x01\x01\x12S\n\x07subject\x18\x02 \x01(\x0b\x32\x31.kessel.inventory.v1beta2.RelationObjectReferenceB\x06\xbaH\x03\xc8\x01\x01R\x07subjectB\x0b\n\t_relationBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
12
+
13
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
14
+ pool.add_serialized_file(descriptor_data)
15
+
16
+ module Kessel
17
+ module Inventory
18
+ module V1beta2
19
+ RelationSubjectReference = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationSubjectReference").msgclass
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relation_tuple_filter.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/relation_subject_filter_pb'
8
+
9
+
10
+ descriptor_data = "\n4kessel/inventory/v1beta2/relation_tuple_filter.proto\x12\x18kessel.inventory.v1beta2\x1a\x36kessel/inventory/v1beta2/relation_subject_filter.proto\"\xf0\x02\n\x13RelationTupleFilter\x12\x32\n\x12resource_namespace\x18\x01 \x01(\tH\x00R\x11resourceNamespace\x88\x01\x01\x12(\n\rresource_type\x18\x02 \x01(\tH\x01R\x0cresourceType\x88\x01\x01\x12$\n\x0bresource_id\x18\x03 \x01(\tH\x02R\nresourceId\x88\x01\x01\x12\x1f\n\x08relation\x18\x04 \x01(\tH\x03R\x08relation\x88\x01\x01\x12[\n\x0esubject_filter\x18\x05 \x01(\x0b\x32/.kessel.inventory.v1beta2.RelationSubjectFilterH\x04R\rsubjectFilter\x88\x01\x01\x42\x15\n\x13_resource_namespaceB\x10\n\x0e_resource_typeB\x0e\n\x0c_resource_idB\x0b\n\t_relationB\x11\n\x0f_subject_filterBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
11
+
12
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
13
+ pool.add_serialized_file(descriptor_data)
14
+
15
+ module Kessel
16
+ module Inventory
17
+ module V1beta2
18
+ RelationTupleFilter = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.RelationTupleFilter").msgclass
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/relationship.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'buf/validate/validate_pb'
8
+ require 'kessel/inventory/v1beta2/relation_object_reference_pb'
9
+ require 'kessel/inventory/v1beta2/relation_subject_reference_pb'
10
+
11
+
12
+ descriptor_data = "\n+kessel/inventory/v1beta2/relationship.proto\x12\x18kessel.inventory.v1beta2\x1a\x1b\x62uf/validate/validate.proto\x1a\x38kessel/inventory/v1beta2/relation_object_reference.proto\x1a\x39kessel/inventory/v1beta2/relation_subject_reference.proto\"\xe0\x01\n\x0cRelationship\x12U\n\x08resource\x18\x01 \x01(\x0b\x32\x31.kessel.inventory.v1beta2.RelationObjectReferenceB\x06\xbaH\x03\xc8\x01\x01R\x08resource\x12#\n\x08relation\x18\x02 \x01(\tB\x07\xbaH\x04r\x02\x10\x01R\x08relation\x12T\n\x07subject\x18\x03 \x01(\x0b\x32\x32.kessel.inventory.v1beta2.RelationSubjectReferenceB\x06\xbaH\x03\xc8\x01\x01R\x07subjectBr\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
13
+
14
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
15
+ pool.add_serialized_file(descriptor_data)
16
+
17
+ module Kessel
18
+ module Inventory
19
+ module V1beta2
20
+ Relationship = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("kessel.inventory.v1beta2.Relationship").msgclass
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: kessel/inventory/v1beta2/tuple_service.proto
4
+
5
+ require 'google/protobuf'
6
+
7
+ require 'kessel/inventory/v1beta2/create_tuples_request_pb'
8
+ require 'kessel/inventory/v1beta2/create_tuples_response_pb'
9
+ require 'kessel/inventory/v1beta2/read_tuples_request_pb'
10
+ require 'kessel/inventory/v1beta2/read_tuples_response_pb'
11
+ require 'kessel/inventory/v1beta2/delete_tuples_request_pb'
12
+ require 'kessel/inventory/v1beta2/delete_tuples_response_pb'
13
+ require 'kessel/inventory/v1beta2/acquire_lock_request_pb'
14
+ require 'kessel/inventory/v1beta2/acquire_lock_response_pb'
15
+
16
+
17
+ descriptor_data = "\n,kessel/inventory/v1beta2/tuple_service.proto\x12\x18kessel.inventory.v1beta2\x1a\x34kessel/inventory/v1beta2/create_tuples_request.proto\x1a\x35kessel/inventory/v1beta2/create_tuples_response.proto\x1a\x32kessel/inventory/v1beta2/read_tuples_request.proto\x1a\x33kessel/inventory/v1beta2/read_tuples_response.proto\x1a\x34kessel/inventory/v1beta2/delete_tuples_request.proto\x1a\x35kessel/inventory/v1beta2/delete_tuples_response.proto\x1a\x33kessel/inventory/v1beta2/acquire_lock_request.proto\x1a\x34kessel/inventory/v1beta2/acquire_lock_response.proto2\xdd\x03\n\x12KesselTupleService\x12r\n\x0c\x43reateTuples\x12-.kessel.inventory.v1beta2.CreateTuplesRequest\x1a..kessel.inventory.v1beta2.CreateTuplesResponse\"\x03\x88\x02\x01\x12r\n\x0c\x44\x65leteTuples\x12-.kessel.inventory.v1beta2.DeleteTuplesRequest\x1a..kessel.inventory.v1beta2.DeleteTuplesResponse\"\x03\x88\x02\x01\x12n\n\nReadTuples\x12+.kessel.inventory.v1beta2.ReadTuplesRequest\x1a,.kessel.inventory.v1beta2.ReadTuplesResponse\"\x03\x88\x02\x01\x30\x01\x12o\n\x0b\x41\x63quireLock\x12,.kessel.inventory.v1beta2.AcquireLockRequest\x1a-.kessel.inventory.v1beta2.AcquireLockResponse\"\x03\x88\x02\x01\x42r\n(org.project_kessel.api.inventory.v1beta2P\x01ZDgithub.com/project-kessel/inventory-api/api/kessel/inventory/v1beta2b\x06proto3"
18
+
19
+ pool = ::Google::Protobuf::DescriptorPool.generated_pool
20
+ pool.add_serialized_file(descriptor_data)
21
+
22
+ module Kessel
23
+ module Inventory
24
+ module V1beta2
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # Source: kessel/inventory/v1beta2/tuple_service.proto for package 'kessel.inventory.v1beta2'
3
+
4
+ require 'grpc'
5
+ require 'kessel/inventory/v1beta2/tuple_service_pb'
6
+
7
+ module Kessel
8
+ module Inventory
9
+ module V1beta2
10
+ module KesselTupleService
11
+ # DEPRECATED: KesselTupleService provides legacy tuple-layer operations.
12
+ # This service exists only for RBAC backward compatibility and will be removed.
13
+ # All endpoints are marked deprecated. Do not add new consumers.
14
+ # Use KesselInventoryService's ReportResource for new integrations.
15
+ class Service
16
+
17
+ include ::GRPC::GenericService
18
+
19
+ self.marshal_class_method = :encode
20
+ self.unmarshal_class_method = :decode
21
+ self.service_name = 'kessel.inventory.v1beta2.KesselTupleService'
22
+
23
+ # DEPRECATED: CreateTuples creates relationship tuples.
24
+ # This endpoint exists only for RBAC backward compatibility.
25
+ # Use ReportResource instead for new code.
26
+ rpc :CreateTuples, ::Kessel::Inventory::V1beta2::CreateTuplesRequest, ::Kessel::Inventory::V1beta2::CreateTuplesResponse
27
+ # DEPRECATED: DeleteTuples deletes relationship tuples.
28
+ # This endpoint exists only for RBAC backward compatibility.
29
+ # Use DeleteResource instead for new code.
30
+ rpc :DeleteTuples, ::Kessel::Inventory::V1beta2::DeleteTuplesRequest, ::Kessel::Inventory::V1beta2::DeleteTuplesResponse
31
+ # DEPRECATED: ReadTuples reads relationship tuples.
32
+ # This endpoint exists only for RBAC backward compatibility.
33
+ # Use StreamedListObjects/StreamedListSubjects instead for new code.
34
+ rpc :ReadTuples, ::Kessel::Inventory::V1beta2::ReadTuplesRequest, stream(::Kessel::Inventory::V1beta2::ReadTuplesResponse)
35
+ # DEPRECATED: AcquireLock acquires a distributed lock.
36
+ # This endpoint exists only for RBAC backward compatibility.
37
+ rpc :AcquireLock, ::Kessel::Inventory::V1beta2::AcquireLockRequest, ::Kessel::Inventory::V1beta2::AcquireLockResponse
38
+ end
39
+
40
+ Stub = Service.rpc_stub_class
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,104 @@
1
+ # RBAC V2 Module Guidelines
2
+
3
+ ## Directory Purpose
4
+
5
+ This directory contains the hand-written RBAC convenience layer (`Kessel::RBAC::V2`) built on top of V1beta2 protobuf types. It provides workspace operations over both HTTP and gRPC, plus factory helpers for constructing protobuf resource/subject references.
6
+
7
+ ## File Organization
8
+
9
+ The module is split across three files reopening the same `Kessel::RBAC::V2` module:
10
+
11
+ - `v2.rb` -- Public API: `fetch_default_workspace`, `fetch_root_workspace`, `list_workspaces`, plus private response processing. Defines the `Workspace` struct and constants.
12
+ - `v2_helpers.rb` -- Factory methods for protobuf references: `workspace_type`, `role_type`, `principal_resource`, `role_resource`, `workspace_resource`, `principal_subject`, `subject`.
13
+ - `v2_http.rb` -- Private HTTP helpers: `run_request` (sets headers, calls auth), `check_http_client` (validates host/port match).
14
+
15
+ All three files must be required together -- `lib/kessel-sdk.rb` handles this. Do not require individual files in isolation.
16
+
17
+ ## Module Design
18
+
19
+ - `V2` is a Ruby module meant to be `include`d, not instantiated. Tests use `include Kessel::RBAC::V2` directly in the RSpec context.
20
+ - `V2` includes `Kessel::Inventory::V1beta2` to access protobuf types (`SubjectReference`, `ResourceReference`, `RepresentationType`, etc.) without full qualification.
21
+ - The `include V1beta2` appears in both `v2.rb` and `v2_helpers.rb` -- this is intentional for load-order independence.
22
+
23
+ ## Constants and Structs
24
+
25
+ - `WORKSPACE_ENDPOINT = '/api/rbac/v2/workspaces/'` -- the REST path appended to `rbac_base_endpoint`.
26
+ - `DEFAULT_PAGE_LIMIT = 1000` -- page size for `list_workspaces` auto-pagination.
27
+ - `Workspace = Struct.new(:id, :name, :type, :description)` -- keyword-argument struct returned by HTTP workspace fetches.
28
+
29
+ ## Factory Helper Conventions
30
+
31
+ All factory methods in `v2_helpers.rb` follow these rules:
32
+
33
+ - Every RBAC resource uses `reporter_type: 'rbac'` (hardcoded, not configurable).
34
+ - `principal_resource(id, domain)` formats `resource_id` as `"#{domain}/#{id}"` -- the domain comes first.
35
+ - `principal_subject(id, domain)` wraps `principal_resource` in a `SubjectReference`.
36
+ - `subject(resource_ref, relation = nil)` is a generic factory -- pass `nil` for relation to omit it.
37
+ - `workspace_type` and `role_type` return `RepresentationType` structs, not `ResourceReference`.
38
+ - Factory methods return frozen protobuf objects (protobuf default). Do not `.dup` or mutate them.
39
+
40
+ ## HTTP Workspace Operations
41
+
42
+ ### Request Pattern
43
+
44
+ - `fetch_workspace` (private) strips trailing slashes from `rbac_base_endpoint`, appends `WORKSPACE_ENDPOINT`, sets a `type` query parameter, and issues a `GET` request.
45
+ - The `x-rh-rbac-org-id` header is required on every request -- set from the `org_id` parameter in `run_request`.
46
+ - Authentication is optional: when `auth` is non-nil, `auth.configure_request(request)` is called. The `auth` object must implement the `AuthRequest` interface (i.e., `Kessel::Auth#oauth2_auth_request(oauth)` return value).
47
+
48
+ ### HTTP Client Handling
49
+
50
+ - When `http_client` is `nil`, a new `Net::HTTP` is created per call (one TCP connection per fetch).
51
+ - When `http_client` is provided, `check_http_client` validates that its `address` and `port` match the endpoint URI. Mismatches raise `RuntimeError`.
52
+ - For multiple workspace fetches, pass a pre-started `Net::HTTP` to avoid repeated TCP handshakes.
53
+
54
+ ### Response Processing
55
+
56
+ - `process_response` raises `RuntimeError` for non-success HTTP status codes.
57
+ - It expects exactly one workspace in `data[]` -- any other count raises `RuntimeError`.
58
+ - `extract_workspace` maps JSON keys to the `Workspace` struct.
59
+
60
+ ## gRPC Workspace Listing
61
+
62
+ `list_workspaces(inventory, subject, relation, continuation_token = nil, consistency: nil)` returns a lazy `Enumerator`:
63
+
64
+ - Internally calls `inventory.streamed_list_objects` with a `StreamedListObjectsRequest`.
65
+ - Auto-paginates: extracts `continuation_token` from each response's `pagination` field.
66
+ - Stops when the server returns no responses or `continuation_token` is nil/falsy.
67
+ - The `consistency` parameter is forwarded to every paginated request -- it is not modified between pages.
68
+ - Consume with `.each` for constant memory, or `.to_a` to materialize all results (use with caution on large datasets).
69
+
70
+ ## Error Handling
71
+
72
+ - Local validation and HTTP failures use bare `RuntimeError` (via `raise "message"`) -- not custom exception classes. These cover workspace fetch HTTP errors and unexpected response shapes.
73
+ - gRPC errors from `streamed_list_objects` propagate directly as `GRPC::BadStatus` subclasses -- do not wrap them.
74
+
75
+ ## RBS Type Signatures
76
+
77
+ - Signatures live in `sig/kessel/rbac.rbs`. Update this file when adding or changing public method signatures.
78
+ - The `Workspace` struct, all public methods, and `list_workspaces` return type (`Enumerator`) are declared.
79
+ - Run `steep check` after changes to verify type correctness.
80
+
81
+ ## Testing
82
+
83
+ - Tests are in `spec/kessel/rbac/v2_spec.rb`.
84
+ - The spec includes `Kessel::RBAC::V2` in the test context and calls module methods directly.
85
+ - HTTP calls are fully mocked -- `Net::HTTP`, `Net::HTTP::Get`, `URI`, and response objects.
86
+ - gRPC streaming is mocked by stubbing `inventory.streamed_list_objects` with arrays or dynamic blocks.
87
+ - Test pagination by returning different continuation tokens across multiple mock invocations.
88
+ - Assert both the exception class and a message regex for error paths.
89
+
90
+ ## RuboCop
91
+
92
+ This directory is subject to RuboCop rules (unlike generated code). Limits: method length 25, class length 150, cyclomatic complexity 10, line length 120.
93
+
94
+ ## Relationship to Kessel::Console
95
+
96
+ `lib/kessel/console.rb` depends on `v2_helpers.rb` (via `require_relative 'rbac/v2_helpers'`) and uses `principal_subject` to convert Red Hat identity headers into `SubjectReference` objects. Changes to factory helper signatures affect `Console`.
97
+
98
+ ## Adding New RBAC Operations
99
+
100
+ 1. Determine whether the operation is HTTP-based (REST) or gRPC-based (protobuf service call).
101
+ 2. Add public methods to `v2.rb`. Add factory helpers to `v2_helpers.rb`. Add HTTP plumbing to `v2_http.rb`.
102
+ 3. Update `sig/kessel/rbac.rbs` with the new method signature.
103
+ 4. Add tests in `spec/kessel/rbac/v2_spec.rb` following the existing mock patterns.
104
+ 5. Run `bundle exec rspec` and `steep check`.
@@ -14,12 +14,14 @@ module Kessel
14
14
  DEFAULT_PAGE_LIMIT = 1000
15
15
  Workspace = Struct.new(:id, :name, :type, :description)
16
16
 
17
- def fetch_default_workspace(rbac_base_endpoint, org_id, auth: nil, http_client: nil)
18
- fetch_workspace(rbac_base_endpoint, org_id, 'default', auth: auth, http_client: http_client)
17
+ def fetch_default_workspace(rbac_base_endpoint, org_id, auth: nil, http_client: nil, with_ancestry: true)
18
+ fetch_workspace(rbac_base_endpoint, org_id, 'default', auth: auth, http_client: http_client,
19
+ with_ancestry: with_ancestry)
19
20
  end
20
21
 
21
- def fetch_root_workspace(rbac_base_endpoint, org_id, auth: nil, http_client: nil)
22
- fetch_workspace(rbac_base_endpoint, org_id, 'root', auth: auth, http_client: http_client)
22
+ def fetch_root_workspace(rbac_base_endpoint, org_id, auth: nil, http_client: nil, with_ancestry: true)
23
+ fetch_workspace(rbac_base_endpoint, org_id, 'root', auth: auth, http_client: http_client,
24
+ with_ancestry: with_ancestry)
23
25
  end
24
26
 
25
27
  # Lists all workspaces that a subject has a specific relation to.
@@ -100,12 +102,12 @@ module Kessel
100
102
  )
101
103
  end
102
104
 
103
- def fetch_workspace(rbac_base_endpoint, org_id, workspace_type, auth: nil, http_client: nil)
105
+ def fetch_workspace(rbac_base_endpoint, org_id, workspace_type, auth: nil, http_client: nil,
106
+ with_ancestry: true)
104
107
  rbac_base_endpoint = rbac_base_endpoint.delete_suffix('/')
105
108
  uri = URI(rbac_base_endpoint + WORKSPACE_ENDPOINT)
106
- query = {
107
- type: workspace_type
108
- }
109
+ query = { type: workspace_type }
110
+ query[:with_ancestry] = 'true' if with_ancestry
109
111
  uri.query = URI.encode_www_form(query)
110
112
  if http_client.nil?
111
113
  http_client = Net::HTTP.new(uri.host, uri.port)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kessel
4
4
  module Inventory
5
- VERSION = '1.10.0'
5
+ VERSION = '1.11.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kessel-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Project Kessel
@@ -210,6 +210,7 @@ files:
210
210
  - lib/kessel/console.rb
211
211
  - lib/kessel/grpc.rb
212
212
  - lib/kessel/inventory.rb
213
+ - lib/kessel/inventory/GUIDELINES.md
213
214
  - lib/kessel/inventory/v1.rb
214
215
  - lib/kessel/inventory/v1/health_pb.rb
215
216
  - lib/kessel/inventory/v1/health_services_pb.rb
@@ -236,6 +237,8 @@ files:
236
237
  - lib/kessel/inventory/v1beta1/resources/reporter_data_pb.rb
237
238
  - lib/kessel/inventory/v1beta1/resources/resource_label_pb.rb
238
239
  - lib/kessel/inventory/v1beta2.rb
240
+ - lib/kessel/inventory/v1beta2/acquire_lock_request_pb.rb
241
+ - lib/kessel/inventory/v1beta2/acquire_lock_response_pb.rb
239
242
  - lib/kessel/inventory/v1beta2/allowed_pb.rb
240
243
  - lib/kessel/inventory/v1beta2/check_bulk_request_pb.rb
241
244
  - lib/kessel/inventory/v1beta2/check_bulk_response_pb.rb
@@ -251,10 +254,23 @@ files:
251
254
  - lib/kessel/inventory/v1beta2/check_self_response_pb.rb
252
255
  - lib/kessel/inventory/v1beta2/consistency_pb.rb
253
256
  - lib/kessel/inventory/v1beta2/consistency_token_pb.rb
257
+ - lib/kessel/inventory/v1beta2/create_tuples_request_pb.rb
258
+ - lib/kessel/inventory/v1beta2/create_tuples_response_pb.rb
254
259
  - lib/kessel/inventory/v1beta2/delete_resource_request_pb.rb
255
260
  - lib/kessel/inventory/v1beta2/delete_resource_response_pb.rb
261
+ - lib/kessel/inventory/v1beta2/delete_tuples_request_pb.rb
262
+ - lib/kessel/inventory/v1beta2/delete_tuples_response_pb.rb
256
263
  - lib/kessel/inventory/v1beta2/inventory_service_pb.rb
257
264
  - lib/kessel/inventory/v1beta2/inventory_service_services_pb.rb
265
+ - lib/kessel/inventory/v1beta2/read_tuples_request_pb.rb
266
+ - lib/kessel/inventory/v1beta2/read_tuples_response_pb.rb
267
+ - lib/kessel/inventory/v1beta2/relation_fencing_check_pb.rb
268
+ - lib/kessel/inventory/v1beta2/relation_object_reference_pb.rb
269
+ - lib/kessel/inventory/v1beta2/relation_object_type_pb.rb
270
+ - lib/kessel/inventory/v1beta2/relation_subject_filter_pb.rb
271
+ - lib/kessel/inventory/v1beta2/relation_subject_reference_pb.rb
272
+ - lib/kessel/inventory/v1beta2/relation_tuple_filter_pb.rb
273
+ - lib/kessel/inventory/v1beta2/relationship_pb.rb
258
274
  - lib/kessel/inventory/v1beta2/report_resource_request_pb.rb
259
275
  - lib/kessel/inventory/v1beta2/report_resource_response_pb.rb
260
276
  - lib/kessel/inventory/v1beta2/reporter_reference_pb.rb
@@ -269,7 +285,10 @@ files:
269
285
  - lib/kessel/inventory/v1beta2/streamed_list_subjects_request_pb.rb
270
286
  - lib/kessel/inventory/v1beta2/streamed_list_subjects_response_pb.rb
271
287
  - lib/kessel/inventory/v1beta2/subject_reference_pb.rb
288
+ - lib/kessel/inventory/v1beta2/tuple_service_pb.rb
289
+ - lib/kessel/inventory/v1beta2/tuple_service_services_pb.rb
272
290
  - lib/kessel/inventory/v1beta2/write_visibility_pb.rb
291
+ - lib/kessel/rbac/GUIDELINES.md
273
292
  - lib/kessel/rbac/v2.rb
274
293
  - lib/kessel/rbac/v2_helpers.rb
275
294
  - lib/kessel/rbac/v2_http.rb