vigiles 0.1.0.pre.beta7 → 0.1.0.pre.beta9
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/lib/vigiles/archive/request.rb +11 -2
- data/lib/vigiles/archive.rb +6 -58
- data/lib/vigiles/conversation_recorder.rb +17 -2
- data/lib/vigiles/conversation_recorders/application_json.rb +39 -2
- data/lib/vigiles/conversation_recorders/unknown.rb +4 -2
- data/lib/vigiles/spec.rb +5 -5
- data/lib/vigiles/version.rb +1 -1
- data/lib/vigiles.rb +6 -6
- data/sorbet/tapioca/require.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7c95b320d216c89bd72c728b2b0402cae897d984554fd6c41e66739eac544e9b
|
4
|
+
data.tar.gz: 55bd64c8191703e6d5b6aac98945c54fd9d06a65b5b094e2c338ad64c9641fb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e98f9cf83934a297eed7ac621f0200b118610690ccd1c9f51279759edce9bfa0db23bd4161adcd762a891b7a3aad6c3606d3e2d66b5ae566615c971ee3bd6460
|
7
|
+
data.tar.gz: 8b90d7d720d5104d3280aefbf6065892f24d677489ae6c096bab31a887fbc4237ac76765f0425a16ed011aaee2dba4c2828f90a6411d6cc6dff95e761eddf943
|
@@ -35,12 +35,21 @@ module Vigiles
|
|
35
35
|
const :url, T.any(URI::HTTPS, URI::HTTP)
|
36
36
|
const :id, String
|
37
37
|
|
38
|
+
sig { params(header_key: String).returns(String) }
|
39
|
+
private_class_method def self.best_effort_unfuck_http_header(header_key)
|
40
|
+
(header_key.starts_with?("HTTP_") ? T.must(header_key[5..]) : header_key)
|
41
|
+
.split(/_/)
|
42
|
+
.map(&:titlecase)
|
43
|
+
.join("-")
|
44
|
+
end
|
45
|
+
|
38
46
|
sig { params(request: ActionDispatch::Request).returns(Request) }
|
39
47
|
def self.from(request)
|
40
|
-
preferred_headers = Vigiles.
|
48
|
+
preferred_headers = Vigiles.spec.request_headers
|
41
49
|
available_headers = request.original_headers
|
42
50
|
recorded_headers = (available_headers if preferred_headers.empty?)
|
43
51
|
recorded_headers ||= preferred_headers.to_h { |h| [h, available_headers[h]] }
|
52
|
+
unfucked_headers = recorded_headers.transform_keys { best_effort_unfuck_http_header _1 }
|
44
53
|
|
45
54
|
Request.new(
|
46
55
|
content_type: request.content_type || (raise InvalidParameterError, "content_type"),
|
@@ -48,7 +57,7 @@ module Vigiles
|
|
48
57
|
timestamp: DateTime.now,
|
49
58
|
remote_ip: IPAddr.new(request.remote_ip),
|
50
59
|
protocol: request.protocol,
|
51
|
-
headers:
|
60
|
+
headers: unfucked_headers,
|
52
61
|
origin: request.origin || "unknown_origin_url",
|
53
62
|
payload: request.body.read,
|
54
63
|
http_method: Types::HttpMethod.deserialize(request.method),
|
data/lib/vigiles/archive.rb
CHANGED
@@ -18,66 +18,14 @@ module Vigiles
|
|
18
18
|
|
19
19
|
sig { params(req: ActionDispatch::Request, res: Rack::Response).returns(T.nilable(Conversation)) }
|
20
20
|
def self.record_conversation(req:, res:)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
response = Response.from(res)
|
27
|
-
metadata = Metadata.from(req.env)
|
28
|
-
request = Request.from(req)
|
29
|
-
extras = Extras.from(req.env)
|
30
|
-
|
31
|
-
case (content_type = request.content_type)
|
32
|
-
when ContentType::ApplicationJson.serialize then record_json_conversation(request:, response:, metadata:, extras:)
|
33
|
-
when ContentType::TextHtml.serialize then record_html_conversation(request:, response:, metadata:, extras:)
|
34
|
-
else record_conversation_with_unknown_content_type(request:, response:, metadata:, extras:)
|
21
|
+
content_type = req.content_type
|
22
|
+
if (recorder = Vigiles.spec.recorders[content_type]).nil?
|
23
|
+
raise \
|
24
|
+
UnrecordableRequestError,
|
25
|
+
"no recorder configured for content type: #{content_type}"
|
35
26
|
end
|
36
|
-
rescue Request::InvalidParameterError => e
|
37
|
-
raise UnrecordableRequestError, "#{e.parameter} considered invalid"
|
38
|
-
end
|
39
|
-
|
40
|
-
sig do
|
41
|
-
params(
|
42
|
-
request: Request,
|
43
|
-
response: Response,
|
44
|
-
metadata: Metadata,
|
45
|
-
extras: Extras
|
46
|
-
)
|
47
|
-
.returns(T.nilable(Conversation))
|
48
|
-
end
|
49
|
-
private_class_method def self.record_json_conversation(request:, response:, metadata:, extras:)
|
50
|
-
Conversation.create!(
|
51
|
-
request_content_type: request.content_type,
|
52
|
-
request_user_agent: request.user_agent,
|
53
|
-
request_timestamp: request.timestamp,
|
54
|
-
request_remote_ip: request.remote_ip,
|
55
|
-
request_protocol: request.protocol,
|
56
|
-
request_headers: request.headers,
|
57
|
-
request_origin: request.origin,
|
58
|
-
request_payload: request.payload,
|
59
|
-
request_method: request.http_method.serialize,
|
60
|
-
request_path: request.path,
|
61
|
-
request_url: request.url,
|
62
|
-
request_id: request.id,
|
63
|
-
response_content_type: response.content_type,
|
64
|
-
response_headers: response.headers,
|
65
|
-
response_payload: response.payload,
|
66
|
-
response_status: response.status
|
67
|
-
)
|
68
|
-
rescue => e
|
69
|
-
end
|
70
|
-
|
71
|
-
sig { params(request: Request, response: Response, metadata: Metadata, extras: Extras).returns(T.nilable(Conversation)) }
|
72
|
-
private_class_method def self.record_html_conversation(request:, response:, metadata:, extras:); end
|
73
27
|
|
74
|
-
|
75
|
-
private_class_method def self.record_conversation_with_unknown_content_type(
|
76
|
-
request:,
|
77
|
-
response:,
|
78
|
-
metadata:,
|
79
|
-
extras:
|
80
|
-
)
|
28
|
+
recorder.record(req:, res:)
|
81
29
|
end
|
82
30
|
end
|
83
31
|
end
|
@@ -3,9 +3,24 @@
|
|
3
3
|
|
4
4
|
module Vigiles
|
5
5
|
class ConversationRecorder
|
6
|
+
class MisconfiguredRecorderError < StandardError
|
7
|
+
sig { returns(String) }
|
8
|
+
attr_reader :expected
|
9
|
+
|
10
|
+
sig { returns(String) }
|
11
|
+
attr_reader :actual
|
12
|
+
|
13
|
+
sig { params(expected: String, actual: String).void }
|
14
|
+
def initialize(expected:, actual:)
|
15
|
+
@expected = expected
|
16
|
+
@actual = actual
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
6
21
|
abstract!
|
7
22
|
|
8
|
-
sig { abstract.params(
|
9
|
-
def record(
|
23
|
+
sig { abstract.params(req: ActionDispatch::Request, res: Rack::Response).returns(Archive::Conversation) }
|
24
|
+
def record(req:, res:); end
|
10
25
|
end
|
11
26
|
end
|
@@ -6,8 +6,45 @@ module Vigiles
|
|
6
6
|
class ApplicationJson < ConversationRecorder
|
7
7
|
include Singleton
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
ConversationRecorder = Vigiles::ConversationRecorder
|
10
|
+
ContentType = Vigiles::Types::ContentType
|
11
|
+
Conversation = Vigiles::Archive::Conversation
|
12
|
+
Response = Vigiles::Archive::Response
|
13
|
+
Metadata = Vigiles::Archive::Metadata
|
14
|
+
Request = Vigiles::Archive::Request
|
15
|
+
Extras = Vigiles::Archive::Extras
|
16
|
+
|
17
|
+
sig { override.params(req: ActionDispatch::Request, res: Rack::Response).returns(Archive::Conversation) }
|
18
|
+
def record(req:, res:)
|
19
|
+
unless req.content_type == ContentType::ApplicationJson.serialize
|
20
|
+
raise ConversationRecorder::MisconfiguredRecorderError.new(
|
21
|
+
expected: ContentType::ApplicationJson.serialize,
|
22
|
+
actual: req.content_type
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
response = Response.from(res)
|
27
|
+
request = Request.from(req)
|
28
|
+
|
29
|
+
Conversation.create!(
|
30
|
+
request_content_type: request.content_type,
|
31
|
+
request_user_agent: request.user_agent,
|
32
|
+
request_timestamp: request.timestamp,
|
33
|
+
request_remote_ip: request.remote_ip,
|
34
|
+
request_protocol: request.protocol,
|
35
|
+
request_headers: request.headers,
|
36
|
+
request_origin: request.origin,
|
37
|
+
request_payload: request.payload,
|
38
|
+
request_method: request.http_method.serialize,
|
39
|
+
request_path: request.path,
|
40
|
+
request_url: request.url,
|
41
|
+
request_id: request.id,
|
42
|
+
response_content_type: response.content_type,
|
43
|
+
response_headers: response.headers,
|
44
|
+
response_payload: response.payload,
|
45
|
+
response_status: response.status
|
46
|
+
)
|
47
|
+
end
|
11
48
|
end
|
12
49
|
end
|
13
50
|
end
|
@@ -4,8 +4,10 @@
|
|
4
4
|
module Vigiles
|
5
5
|
module ConversationRecorders
|
6
6
|
class Unknown < ConversationRecorder
|
7
|
-
|
8
|
-
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
sig { override.params(req: ActionDispatch::Request, res: Rack::Response).returns(Archive::Conversation) }
|
10
|
+
def record(req:, res:) = Archive::Conversation.new
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
data/lib/vigiles/spec.rb
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
|
4
4
|
module Vigiles
|
5
5
|
class Spec < T::Struct
|
6
|
-
const :
|
7
|
-
const :
|
8
|
-
const :
|
6
|
+
const :request_content_types, T::Set[String]
|
7
|
+
const :request_headers, T::Set[String]
|
8
|
+
const :recorders, T::Hash[String, ConversationRecorder]
|
9
9
|
|
10
10
|
sig { returns(Spec) }
|
11
11
|
def self.make_default_spec
|
12
12
|
Spec.new(
|
13
|
-
content_type_recorders: Constants::DEFAULT_CONTENT_TYPE_RECORDERS,
|
14
13
|
request_content_types: Constants::DEFAULT_CONTENT_TYPES,
|
15
|
-
request_headers: Set[]
|
14
|
+
request_headers: Set[].freeze,
|
15
|
+
recorders: Constants::DEFAULT_CONTENT_TYPE_RECORDERS
|
16
16
|
)
|
17
17
|
end
|
18
18
|
end
|
data/lib/vigiles/version.rb
CHANGED
data/lib/vigiles.rb
CHANGED
@@ -17,16 +17,16 @@ module Vigiles
|
|
17
17
|
extend T::Sig
|
18
18
|
|
19
19
|
sig { returns(Vigiles::Spec) }
|
20
|
-
def self.
|
21
|
-
@
|
20
|
+
def self.spec
|
21
|
+
@spec ||= T.let(
|
22
22
|
Vigiles::Spec.make_default_spec,
|
23
23
|
T.nilable(Vigiles::Spec)
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
27
|
sig { params(spec: Vigiles::Spec).returns(Vigiles::Spec) }
|
28
|
-
def self.
|
29
|
-
@
|
28
|
+
def self.spec=(spec)
|
29
|
+
@spec = spec
|
30
30
|
end
|
31
31
|
|
32
32
|
sig { params(req: ActionDispatch::Request, res: Rack::Response).returns(T.nilable(Archive::Conversation)) }
|
@@ -40,9 +40,9 @@ module Vigiles
|
|
40
40
|
|
41
41
|
sig { params(blk: T.untyped).void }
|
42
42
|
def self.configure(&blk)
|
43
|
-
blk.call(
|
43
|
+
blk.call(spec)
|
44
44
|
|
45
|
-
# TODO(yaw, 2024-06-15): ensure that the
|
45
|
+
# TODO(yaw, 2024-06-15): ensure that the spec is valid.
|
46
46
|
# ensure that for every content type a recorder is configured. otherwise
|
47
47
|
# assign the general recorder for unknown content types.
|
48
48
|
end
|
data/sorbet/tapioca/require.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
|
4
4
|
require "action_dispatch"
|
5
5
|
require "active_record"
|
6
|
+
require "logger"
|
6
7
|
require "minitest/autorun"
|
7
8
|
require "rails/generators"
|
8
9
|
require "rails/generators/active_record"
|
9
10
|
require "securerandom"
|
10
11
|
require "sorbet-runtime"
|
11
|
-
require "uri"
|
12
12
|
require "zeitwerk"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vigiles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.pre.
|
4
|
+
version: 0.1.0.pre.beta9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yaw Boakye
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-05-
|
11
|
+
date: 2024-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sorbet-runtime
|