overseer-testing-protocol 0.1.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 (33) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +75 -0
  4. data/SOURCE.json +6 -0
  5. data/bin/overseer-testing-conformance +53 -0
  6. data/docs/testing-control-implementation-guide.md +116 -0
  7. data/docs/testing-control-protocol.md +432 -0
  8. data/lib/overseer/testing_control/conformance/case_file.rb +120 -0
  9. data/lib/overseer/testing_control/conformance/http_transport.rb +114 -0
  10. data/lib/overseer/testing_control/conformance/report.rb +104 -0
  11. data/lib/overseer/testing_control/conformance/runner.rb +783 -0
  12. data/lib/overseer/testing_control/discovery.rb +79 -0
  13. data/lib/overseer/testing_control/json_subset_matcher.rb +120 -0
  14. data/lib/overseer/testing_control/protocol_v3.rb +298 -0
  15. data/lib/overseer/testing_control/redaction.rb +111 -0
  16. data/lib/overseer/testing_protocol.rb +9 -0
  17. data/protocol/testing-control/v3/conformance-case.schema.json +151 -0
  18. data/protocol/testing-control/v3/conformance-report.schema.json +255 -0
  19. data/protocol/testing-control/v3/fixtures/capabilities-response.json +147 -0
  20. data/protocol/testing-control/v3/fixtures/conformance-case.json +23 -0
  21. data/protocol/testing-control/v3/fixtures/conformance-report.json +88 -0
  22. data/protocol/testing-control/v3/fixtures/error-response.json +20 -0
  23. data/protocol/testing-control/v3/fixtures/manifest.json +13 -0
  24. data/protocol/testing-control/v3/fixtures/probe-request.json +20 -0
  25. data/protocol/testing-control/v3/fixtures/probe-response.json +22 -0
  26. data/protocol/testing-control/v3/fixtures/reset-response.json +15 -0
  27. data/protocol/testing-control/v3/fixtures/sink-query-request.json +26 -0
  28. data/protocol/testing-control/v3/fixtures/sink-query-response.json +39 -0
  29. data/protocol/testing-control/v3/fixtures/state-request.json +20 -0
  30. data/protocol/testing-control/v3/fixtures/state-response.json +23 -0
  31. data/protocol/testing-control/v3/openapi.yaml +343 -0
  32. data/protocol/testing-control/v3/schema.json +772 -0
  33. metadata +85 -0
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'json_schemer'
5
+
6
+ module Overseer
7
+ module TestingControl
8
+ module Conformance
9
+ module Report
10
+ SCHEMA_PATH = File.expand_path(
11
+ '../../../../protocol/testing-control/v3/conformance-report.schema.json',
12
+ __dir__
13
+ )
14
+
15
+ class Error < StandardError; end
16
+
17
+ module_function
18
+
19
+ def validate!(report)
20
+ errors = schemer.validate(report).take(5)
21
+ return report if errors.empty?
22
+
23
+ details = errors.map { |error| "#{error.fetch('data_pointer', '/')} #{error.fetch('type')}" }.join('; ')
24
+ raise Error, "Invalid testing-control conformance report: #{details}"
25
+ end
26
+
27
+ def render(report)
28
+ target = report.fetch('target')
29
+ capabilities = report['capabilities']
30
+ lines = [
31
+ "Testing-control v#{report.fetch('protocolVersion')} conformance: #{report.fetch('aggregateStatus')}",
32
+ "Target: #{target.fetch('label')}",
33
+ "Source: #{target.fetch('sourceVersion') || 'unavailable'}",
34
+ "Origin: #{target.fetch('origin') || 'unavailable'}"
35
+ ]
36
+ lines.concat(optional_provenance_lines(target['provenance']))
37
+ lines.concat(identity_lines(report['identity']))
38
+ lines.concat(capability_lines(capabilities))
39
+ lines << 'Checks:'
40
+ report.fetch('checks').each do |check|
41
+ lines << check_line(check)
42
+ end
43
+ lifecycle = report.fetch('lifecycle')
44
+ lines << "Lifecycle: #{lifecycle.fetch('ownership')}; cleanup #{lifecycle.fetch('cleanup')}"
45
+ lines << ''
46
+ lines.join("\n")
47
+ end
48
+
49
+ def optional_provenance_lines(provenance)
50
+ provenance ? provenance_lines(provenance) : []
51
+ end
52
+ private_class_method :optional_provenance_lines
53
+
54
+ def identity_lines(identity)
55
+ return [] unless identity
56
+
57
+ ["Runtime identity: #{identity.fetch('applicationId')} #{identity.fetch('applicationVersion')} " \
58
+ "(#{identity.fetch('environmentId')})"]
59
+ end
60
+ private_class_method :identity_lines
61
+
62
+ def capability_lines(capabilities)
63
+ return [] unless capabilities
64
+
65
+ ["Capabilities: #{capabilities.fetch('arrangements').length} arrangements, " \
66
+ "#{capabilities.fetch('observations').length} observations, " \
67
+ "#{capabilities.fetch('sinks').length} sinks; reset #{capabilities.fetch('resetStrategy')}"]
68
+ end
69
+ private_class_method :capability_lines
70
+
71
+ def check_line(check)
72
+ scenario = check['scenarioId'] ? " [#{check.fetch('scenarioId')}]" : ''
73
+ " #{check.fetch('status').upcase} #{check.fetch('id')}#{scenario}: #{check.fetch('message')}"
74
+ end
75
+ private_class_method :check_line
76
+
77
+ def provenance_lines(provenance)
78
+ project = provenance.fetch('project')
79
+ manifest = provenance.fetch('backendManifest')
80
+ runtime = provenance.fetch('runtime')
81
+ lines = [
82
+ "Project target: #{project.fetch('id')} revision #{project.fetch('revision')} / " \
83
+ "#{provenance.fetch('targetKey')}",
84
+ "Backend: #{provenance.dig('backend', 'applicationId')} " \
85
+ "(registry #{provenance.dig('backend', 'registryId')})",
86
+ "Manifest: v#{manifest.fetch('version')} sha256:#{manifest.fetch('sha256')}",
87
+ "Runtime: #{runtime.fetch('mode')}; profile #{runtime.fetch('profileName')} " \
88
+ "policy v#{runtime.fetch('profilePolicyVersion')}"
89
+ ]
90
+ return lines unless provenance['conformanceCase']
91
+
92
+ selected_case = provenance.fetch('conformanceCase')
93
+ lines << "Conformance case: #{selected_case.fetch('id')} sha256:#{selected_case.fetch('sha256')}"
94
+ end
95
+ private_class_method :provenance_lines
96
+
97
+ def schemer
98
+ @schemer ||= JSONSchemer.schema(JSON.parse(File.read(SCHEMA_PATH, encoding: 'UTF-8')))
99
+ end
100
+ private_class_method :schemer
101
+ end
102
+ end
103
+ end
104
+ end