capsium 0.2.0 → 0.3.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/CHANGELOG.md +125 -0
  4. data/README.adoc +332 -5
  5. data/capsium.gemspec +1 -0
  6. data/lib/capsium/cli/formatting.rb +27 -0
  7. data/lib/capsium/cli/package.rb +68 -6
  8. data/lib/capsium/cli/reactor.rb +9 -1
  9. data/lib/capsium/cli.rb +1 -0
  10. data/lib/capsium/package/authentication.rb +38 -0
  11. data/lib/capsium/package/authentication_config.rb +78 -0
  12. data/lib/capsium/package/cipher.rb +197 -0
  13. data/lib/capsium/package/composition.rb +77 -0
  14. data/lib/capsium/package/dependency_resolver.rb +61 -0
  15. data/lib/capsium/package/encryption_config.rb +38 -0
  16. data/lib/capsium/package/merged_view.rb +168 -0
  17. data/lib/capsium/package/preparation.rb +81 -0
  18. data/lib/capsium/package/routes_config.rb +60 -6
  19. data/lib/capsium/package/security.rb +21 -4
  20. data/lib/capsium/package/signer.rb +201 -0
  21. data/lib/capsium/package/storage_config.rb +29 -1
  22. data/lib/capsium/package/store.rb +109 -0
  23. data/lib/capsium/package/testing/config_test.rb +70 -0
  24. data/lib/capsium/package/testing/context.rb +11 -0
  25. data/lib/capsium/package/testing/data_validation_test.rb +63 -0
  26. data/lib/capsium/package/testing/file_test.rb +45 -0
  27. data/lib/capsium/package/testing/report.rb +33 -0
  28. data/lib/capsium/package/testing/route_test.rb +64 -0
  29. data/lib/capsium/package/testing/test_case.rb +60 -0
  30. data/lib/capsium/package/testing/test_suite.rb +86 -0
  31. data/lib/capsium/package/testing.rb +20 -0
  32. data/lib/capsium/package/validator.rb +14 -3
  33. data/lib/capsium/package/verification.rb +32 -0
  34. data/lib/capsium/package/version.rb +204 -0
  35. data/lib/capsium/package.rb +59 -75
  36. data/lib/capsium/packager.rb +34 -1
  37. data/lib/capsium/reactor/authenticator.rb +180 -0
  38. data/lib/capsium/reactor/deploy.rb +71 -0
  39. data/lib/capsium/reactor/htpasswd.rb +154 -0
  40. data/lib/capsium/reactor/introspection.rb +4 -1
  41. data/lib/capsium/reactor/oauth2.rb +106 -0
  42. data/lib/capsium/reactor/serving.rb +75 -0
  43. data/lib/capsium/reactor/session.rb +82 -0
  44. data/lib/capsium/reactor.rb +43 -41
  45. data/lib/capsium/thor_ext.rb +1 -1
  46. data/lib/capsium/version.rb +1 -1
  47. data/sig/capsium/package/authentication.rbs +23 -0
  48. data/sig/capsium/package/authentication_config.rbs +71 -0
  49. data/sig/capsium/package/cipher.rbs +51 -0
  50. data/sig/capsium/package/composition.rbs +20 -0
  51. data/sig/capsium/package/dependency_resolver.rbs +49 -0
  52. data/sig/capsium/package/encryption_config.rbs +35 -0
  53. data/sig/capsium/package/merged_view.rbs +46 -0
  54. data/sig/capsium/package/preparation.rbs +23 -0
  55. data/sig/capsium/package/routes_config.rbs +36 -3
  56. data/sig/capsium/package/security.rbs +9 -2
  57. data/sig/capsium/package/signer.rbs +59 -0
  58. data/sig/capsium/package/storage_config.rbs +26 -2
  59. data/sig/capsium/package/store.rbs +37 -0
  60. data/sig/capsium/package/testing/config_test.rbs +21 -0
  61. data/sig/capsium/package/testing/context.rbs +14 -0
  62. data/sig/capsium/package/testing/data_validation_test.rbs +22 -0
  63. data/sig/capsium/package/testing/file_test.rbs +17 -0
  64. data/sig/capsium/package/testing/report.rbs +20 -0
  65. data/sig/capsium/package/testing/route_test.rbs +22 -0
  66. data/sig/capsium/package/testing/test_case.rbs +41 -0
  67. data/sig/capsium/package/testing/test_suite.rbs +20 -0
  68. data/sig/capsium/package/testing.rbs +7 -0
  69. data/sig/capsium/package/verification.rbs +24 -0
  70. data/sig/capsium/package/version.rbs +39 -0
  71. data/sig/capsium/package.rbs +25 -17
  72. data/sig/capsium/packager.rbs +9 -0
  73. data/sig/capsium/reactor/authenticator.rbs +40 -0
  74. data/sig/capsium/reactor/deploy.rbs +34 -0
  75. data/sig/capsium/reactor/htpasswd.rbs +36 -0
  76. data/sig/capsium/reactor/oauth2.rbs +31 -0
  77. data/sig/capsium/reactor/serving.rbs +22 -0
  78. data/sig/capsium/reactor/session.rbs +36 -0
  79. data/sig/capsium/reactor.rbs +6 -1
  80. metadata +70 -1
@@ -0,0 +1,40 @@
1
+ module Capsium
2
+ class Reactor
3
+ # Request authentication and route authorization for the reactor
4
+ # (05x-authentication, ARCHITECTURE.md section 4b).
5
+ class Authenticator
6
+ LOGIN_PATH: String
7
+
8
+ attr_reader authentication: Package::Authentication
9
+ attr_reader deploy: Deploy
10
+
11
+ def initialize: (Package::Authentication authentication,
12
+ deploy: Deploy deploy, package_path: String package_path,
13
+ ?base_url: String? base_url,
14
+ ?state_file: String? state_file) -> void
15
+
16
+ def enabled?: () -> bool
17
+
18
+ # The paths this authenticator answers itself (OAuth2 login and
19
+ # callback), mounted by the reactor.
20
+ def endpoints: () -> Array[String]
21
+
22
+ def endpoint?: (String path) -> bool
23
+
24
+ def serve_endpoint: (untyped request, untyped response) -> untyped
25
+
26
+ # The identity for a request — from the session cookie or Basic
27
+ # credentials — or nil. An identity always carries "roles"
28
+ # (possibly empty).
29
+ def authenticate: (untyped request) -> Hash[String, untyped]?
30
+
31
+ # 401, with a Basic challenge when basicAuth is enabled.
32
+ def challenge: (untyped response) -> untyped
33
+
34
+ # :ok, :unauthenticated or :forbidden for a route's accessControl
35
+ # ({"roles": [...], "authenticationRequired": bool}).
36
+ def authorize: (Hash[String, untyped]? identity,
37
+ Hash[String, untyped]? access_control) -> (:ok | :unauthenticated | :forbidden)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ module Capsium
2
+ class Reactor
3
+ # Reactor-side deployment configuration (deploy.json): everything
4
+ # that must NOT ship in the package — OAuth2 client secrets, the
5
+ # session signing secret, role assignments, an alternate htpasswd
6
+ # file, the public base URL.
7
+ class Deploy
8
+ FILE: String
9
+ ENV_VAR: String
10
+
11
+ attr_reader config: Hash[String, untyped]
12
+
13
+ # Loads from an explicit path, an already-parsed Hash, or the
14
+ # CAPSIUM_DEPLOY environment variable; empty when unconfigured.
15
+ def self.load: (Hash[String, untyped] | String? source) -> Deploy
16
+
17
+ def initialize: (Hash[String, untyped] config) -> void
18
+
19
+ def authentication: () -> Hash[String, untyped]
20
+
21
+ def base_url: () -> String?
22
+
23
+ def client_secret: () -> String?
24
+
25
+ def session_secret: () -> String?
26
+
27
+ def passwd_file: () -> String?
28
+
29
+ # Role assignments keyed by identity name (basic-auth username,
30
+ # OAuth2 email or subject): {"alice": ["admin", "user"]}.
31
+ def roles: () -> Hash[String, Array[String]]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Capsium
2
+ class Reactor
3
+ # Apache htpasswd verification (05x-authentication). Supported hash
4
+ # formats: bcrypt ($2a$/$2b$/$2y$), Apache apr1 MD5 and md5-crypt
5
+ # ($apr1$/$1$), unsalted SHA-1 ({SHA}), and a crypt(3) fallback for
6
+ # the rest (platform-dependent).
7
+ class Htpasswd
8
+ # md5-crypt as deployed by Apache htpasswd, OpenSSL and glibc.
9
+ module Md5Crypt
10
+ ITOA64: String
11
+ DIGEST_GROUPS: Array[Array[Integer]]
12
+
13
+ def self.verify: (String hash, String password) -> bool
14
+
15
+ def self.digest: (String password, String salt, String magic) -> String
16
+
17
+ def self.initial_digest: (String password, String salt, String magic) -> String
18
+
19
+ def self.stretch_digest: (Integer iteration, String password, String salt, String final) -> String
20
+
21
+ def self.to64: (String final) -> String
22
+ end
23
+
24
+ attr_reader path: String
25
+
26
+ def initialize: (String path) -> void
27
+
28
+ def usernames: () -> Array[String]
29
+
30
+ def verify?: (String username, String password) -> bool
31
+ end
32
+
33
+ # Constant-time string comparison (length-check first).
34
+ def self.secure_compare: (String own, String theirs) -> bool
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ module Capsium
2
+ class Reactor
3
+ # OAuth2 authorization-code flow client (05x-authentication), used by
4
+ # the Authenticator. Talks to the provider over net/http; the client
5
+ # secret never comes from the package.
6
+ class OAuth2
7
+ # The token exchange or userinfo fetch failed at the provider.
8
+ class FlowError < Capsium::Error
9
+ end
10
+
11
+ GRANT_TYPE: String
12
+
13
+ attr_reader config: Package::OAuth2Config
14
+
15
+ def initialize: (Package::OAuth2Config config, client_secret: String client_secret,
16
+ session: Session session, ?base_url: String? base_url) -> void
17
+
18
+ # The provider URL the login endpoint redirects the browser to.
19
+ def authorization_url: (untyped request) -> String
20
+
21
+ def valid_state?: (String? state) -> bool
22
+
23
+ # Exchanges the authorization code and fetches the userinfo
24
+ # claims. Returns the raw userinfo hash; raises FlowError on
25
+ # provider errors.
26
+ def complete: (String? code, untyped request) -> Hash[String, untyped]
27
+
28
+ def callback_uri: (untyped request) -> String
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ module Capsium
2
+ class Reactor
3
+ # Serving of resolved routes (static files through the merged view,
4
+ # datasets, handler-route 501s), mixed into Reactor. Includes route
5
+ # inheritance processing per 05x-routing.
6
+ module Serving
7
+ private
8
+
9
+ def serve_route: (Package::Route route, untyped response) -> untyped
10
+
11
+ def serve_file: (Package::Route route, untyped response) -> untyped
12
+
13
+ def inherited_processing: (Package::Route route, String body, Hash[String, String] headers) -> [String, Hash[String, String]]
14
+
15
+ def content_type_for: (Package::Route route, String content_path) -> String
16
+
17
+ def headers_for: (Package::Route route) -> Hash[String, String]
18
+
19
+ def serve_dataset: (String dataset_name, untyped response) -> untyped
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ module Capsium
2
+ class Reactor
3
+ # HMAC-SHA256 signed session cookies (05x-authentication). The
4
+ # signing secret comes from deploy.json (sessionSecret) or is
5
+ # generated and persisted reactor-side (never in the package).
6
+ class Session
7
+ COOKIE_NAME: String
8
+ SECRET_BYTES: Integer
9
+
10
+ def self.hmac: (String secret, String data) -> String
11
+
12
+ # The persisted reactor-side secret: loaded from state_file when
13
+ # present, generated and written (mode 0600) otherwise.
14
+ def self.load_or_generate_secret: (String? state_file) -> String
15
+
16
+ attr_reader secret: String
17
+
18
+ def initialize: (?secret: String? secret, ?state_file: String? state_file) -> void
19
+
20
+ # HMAC-SHA256 of data with the session secret (hex).
21
+ def sign: (String data) -> String
22
+
23
+ def encode: (Hash[String, untyped] payload) -> String
24
+
25
+ # The verified payload, or nil when the cookie is missing or the
26
+ # signature does not match.
27
+ def decode: (String? cookie_value) -> Hash[String, untyped]?
28
+
29
+ # The identity for a request's Cookie header, or nil.
30
+ def identity_from: (untyped request) -> Hash[String, untyped]?
31
+
32
+ # A Set-Cookie value establishing the identity session.
33
+ def cookie_for: (Hash[String, untyped] identity) -> String
34
+ end
35
+ end
36
+ end
@@ -3,6 +3,8 @@ module Capsium
3
3
  # Monitoring HTTP API (ARCHITECTURE.md section 7) and reloads the
4
4
  # package on filesystem changes.
5
5
  class Reactor
6
+ include Serving
7
+
6
8
  DEFAULT_PORT: Integer
7
9
  DEFAULT_CACHE_CONTROL: String
8
10
 
@@ -14,10 +16,13 @@ module Capsium
14
16
  attr_reader server: untyped
15
17
  attr_reader server_thread: Thread?
16
18
  attr_reader introspection: Introspection
19
+ attr_reader authenticator: Authenticator
17
20
 
18
21
  def initialize: (package: Package | String package, ?port: Integer port,
19
22
  ?cache_control: String? cache_control,
20
- ?do_not_listen: bool do_not_listen) -> void
23
+ ?do_not_listen: bool do_not_listen,
24
+ ?store: (Package::Store | String)? store,
25
+ ?deploy: (Hash[String, untyped] | String)? deploy) -> void
21
26
 
22
27
  def serve: () -> untyped
23
28
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capsium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -9,6 +9,20 @@ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: bcrypt
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
12
26
  - !ruby/object:Gem::Dependency
13
27
  name: csv
14
28
  requirement: !ruby/object:Gem::Requirement
@@ -204,45 +218,100 @@ files:
204
218
  - lib/capsium.rb
205
219
  - lib/capsium/cli.rb
206
220
  - lib/capsium/cli/convert.rb
221
+ - lib/capsium/cli/formatting.rb
207
222
  - lib/capsium/cli/package.rb
208
223
  - lib/capsium/cli/reactor.rb
209
224
  - lib/capsium/converters.rb
210
225
  - lib/capsium/converters/jekyll.rb
211
226
  - lib/capsium/package.rb
227
+ - lib/capsium/package/authentication.rb
228
+ - lib/capsium/package/authentication_config.rb
229
+ - lib/capsium/package/cipher.rb
230
+ - lib/capsium/package/composition.rb
212
231
  - lib/capsium/package/dataset.rb
232
+ - lib/capsium/package/dependency_resolver.rb
233
+ - lib/capsium/package/encryption_config.rb
213
234
  - lib/capsium/package/manifest.rb
214
235
  - lib/capsium/package/manifest_config.rb
236
+ - lib/capsium/package/merged_view.rb
215
237
  - lib/capsium/package/metadata.rb
216
238
  - lib/capsium/package/metadata_config.rb
239
+ - lib/capsium/package/preparation.rb
217
240
  - lib/capsium/package/routes.rb
218
241
  - lib/capsium/package/routes_config.rb
219
242
  - lib/capsium/package/security.rb
220
243
  - lib/capsium/package/security_config.rb
244
+ - lib/capsium/package/signer.rb
221
245
  - lib/capsium/package/storage.rb
222
246
  - lib/capsium/package/storage_config.rb
247
+ - lib/capsium/package/store.rb
248
+ - lib/capsium/package/testing.rb
249
+ - lib/capsium/package/testing/config_test.rb
250
+ - lib/capsium/package/testing/context.rb
251
+ - lib/capsium/package/testing/data_validation_test.rb
252
+ - lib/capsium/package/testing/file_test.rb
253
+ - lib/capsium/package/testing/report.rb
254
+ - lib/capsium/package/testing/route_test.rb
255
+ - lib/capsium/package/testing/test_case.rb
256
+ - lib/capsium/package/testing/test_suite.rb
223
257
  - lib/capsium/package/validator.rb
258
+ - lib/capsium/package/verification.rb
259
+ - lib/capsium/package/version.rb
224
260
  - lib/capsium/packager.rb
225
261
  - lib/capsium/reactor.rb
262
+ - lib/capsium/reactor/authenticator.rb
263
+ - lib/capsium/reactor/deploy.rb
264
+ - lib/capsium/reactor/htpasswd.rb
226
265
  - lib/capsium/reactor/introspection.rb
266
+ - lib/capsium/reactor/oauth2.rb
267
+ - lib/capsium/reactor/serving.rb
268
+ - lib/capsium/reactor/session.rb
227
269
  - lib/capsium/thor_ext.rb
228
270
  - lib/capsium/version.rb
229
271
  - sig/capsium.rbs
230
272
  - sig/capsium/package.rbs
273
+ - sig/capsium/package/authentication.rbs
274
+ - sig/capsium/package/authentication_config.rbs
275
+ - sig/capsium/package/cipher.rbs
276
+ - sig/capsium/package/composition.rbs
231
277
  - sig/capsium/package/dataset.rbs
278
+ - sig/capsium/package/dependency_resolver.rbs
279
+ - sig/capsium/package/encryption_config.rbs
232
280
  - sig/capsium/package/manifest.rbs
233
281
  - sig/capsium/package/manifest_config.rbs
282
+ - sig/capsium/package/merged_view.rbs
234
283
  - sig/capsium/package/metadata.rbs
235
284
  - sig/capsium/package/metadata_config.rbs
285
+ - sig/capsium/package/preparation.rbs
236
286
  - sig/capsium/package/routes.rbs
237
287
  - sig/capsium/package/routes_config.rbs
238
288
  - sig/capsium/package/security.rbs
239
289
  - sig/capsium/package/security_config.rbs
290
+ - sig/capsium/package/signer.rbs
240
291
  - sig/capsium/package/storage.rbs
241
292
  - sig/capsium/package/storage_config.rbs
293
+ - sig/capsium/package/store.rbs
294
+ - sig/capsium/package/testing.rbs
295
+ - sig/capsium/package/testing/config_test.rbs
296
+ - sig/capsium/package/testing/context.rbs
297
+ - sig/capsium/package/testing/data_validation_test.rbs
298
+ - sig/capsium/package/testing/file_test.rbs
299
+ - sig/capsium/package/testing/report.rbs
300
+ - sig/capsium/package/testing/route_test.rbs
301
+ - sig/capsium/package/testing/test_case.rbs
302
+ - sig/capsium/package/testing/test_suite.rbs
242
303
  - sig/capsium/package/validator.rbs
304
+ - sig/capsium/package/verification.rbs
305
+ - sig/capsium/package/version.rbs
243
306
  - sig/capsium/packager.rbs
244
307
  - sig/capsium/reactor.rbs
308
+ - sig/capsium/reactor/authenticator.rbs
309
+ - sig/capsium/reactor/deploy.rbs
310
+ - sig/capsium/reactor/htpasswd.rbs
245
311
  - sig/capsium/reactor/introspection.rbs
312
+ - sig/capsium/reactor/oauth2.rbs
313
+ - sig/capsium/reactor/serving.rbs
314
+ - sig/capsium/reactor/session.rbs
246
315
  homepage: https://github.com/capsiums/capsium
247
316
  licenses:
248
317
  - MIT