Class: Woods::Console::ResponseContext
- Inherits:
-
Object
- Object
- Woods::Console::ResponseContext
- Defined in:
- lib/woods/console/response_context.rb
Overview
Bundles the three Console response-safety layers the Server threads through every tool definition:
-
Layer 1 (TableGate) — reject tool calls that touch blocked tables.
-
Layer 2 (CredentialScanner) — redact credential-shaped substrings in the
final response tree, regardless of where they arrived. -
Layer 3 (SafeContext) — operator-configured column + EAV redaction.
Exposed as tell-don’t-ask commands: #enforce!, #redact, #scan. Callers never need to ask which layers are configured — a NullResponseContext is returned from ResponseContext.build when every layer is absent, and its commands are no-ops that return their input unchanged.
Ordering (applied in Server#send_to_bridge, after the bridge responds):
Layer 3 (columns/EAV) -> Layer 2 (credential scan) -> response emitted.
Layer 1 runs earlier, before tool dispatch.
Instance Attribute Summary collapse
-
#credential_scanner ⇒ Object
readonly
Returns the value of attribute credential_scanner.
-
#safe_ctx ⇒ Object
readonly
Returns the value of attribute safe_ctx.
-
#table_gate ⇒ Object
readonly
Returns the value of attribute table_gate.
Class Method Summary collapse
-
.build(safe_ctx: nil, table_gate: nil, credential_scanner: nil) ⇒ ResponseContext, NullResponseContext
NullResponseContext when every layer is absent so callers never receive nil.
Instance Method Summary collapse
-
#enforce!(args) ⇒ Object
Run the Layer 1 blocked-table gate against the arguments a tool was invoked with.
-
#initialize(safe_ctx:, table_gate:, credential_scanner:) ⇒ ResponseContext
constructor
A new instance of ResponseContext.
-
#present? ⇒ Boolean
True for real response contexts; false for NullResponseContext.
-
#redact(result) ⇒ Object
Apply Layer 3 (column + EAV) redaction to a result value.
-
#scan(value) ⇒ Array(Object, Hash)
Run Layer 2 (credential scanner) over a value and return the scanned form alongside any hit counts.
Constructor Details
#initialize(safe_ctx:, table_gate:, credential_scanner:) ⇒ ResponseContext
Returns a new instance of ResponseContext.
38 39 40 41 42 |
# File 'lib/woods/console/response_context.rb', line 38 def initialize(safe_ctx:, table_gate:, credential_scanner:) @safe_ctx = safe_ctx @table_gate = table_gate @credential_scanner = credential_scanner end |
Instance Attribute Details
#credential_scanner ⇒ Object (readonly)
Returns the value of attribute credential_scanner.
25 26 27 |
# File 'lib/woods/console/response_context.rb', line 25 def credential_scanner @credential_scanner end |
#safe_ctx ⇒ Object (readonly)
Returns the value of attribute safe_ctx.
25 26 27 |
# File 'lib/woods/console/response_context.rb', line 25 def safe_ctx @safe_ctx end |
#table_gate ⇒ Object (readonly)
Returns the value of attribute table_gate.
25 26 27 |
# File 'lib/woods/console/response_context.rb', line 25 def table_gate @table_gate end |
Class Method Details
.build(safe_ctx: nil, table_gate: nil, credential_scanner: nil) ⇒ ResponseContext, NullResponseContext
Returns NullResponseContext when every layer is absent so callers never receive nil.
29 30 31 32 33 34 35 36 |
# File 'lib/woods/console/response_context.rb', line 29 def self.build(safe_ctx: nil, table_gate: nil, credential_scanner: nil) gate_inactive = table_gate.nil? || !table_gate.active? if safe_ctx.nil? && gate_inactive && credential_scanner.nil? NullResponseContext.instance else new(safe_ctx: safe_ctx, table_gate: table_gate, credential_scanner: credential_scanner) end end |
Instance Method Details
#enforce!(args) ⇒ Object
Run the Layer 1 blocked-table gate against the arguments a tool was invoked with. Tools may arrive at tables through five different arg shapes — SQL string, model name, raw table, joined associations, or a single association name — so the gate checks every variant that’s present. A no-op when the gate is nil.
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/woods/console/response_context.rb', line 57 def enforce!(args) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity return unless @table_gate @table_gate.check_sql!(args[:sql]) if args[:sql] @table_gate.check_model!(args[:model]) if args[:model] @table_gate.check_table!(args[:table]) if args[:table] @table_gate.check_joins!(args[:model], args[:joins]) if args[:model] && args[:joins] return unless args[:model] && args[:association] @table_gate.check_association!(args[:model], args[:association]) end |
#present? ⇒ Boolean
True for real response contexts; false for NullResponseContext.
45 46 47 |
# File 'lib/woods/console/response_context.rb', line 45 def present? true end |
#redact(result) ⇒ Object
Apply Layer 3 (column + EAV) redaction to a result value. Shape-aware —see Woods::Console::Redactor.apply for the supported envelope keys.
74 75 76 77 78 |
# File 'lib/woods/console/response_context.rb', line 74 def redact(result) return result unless @safe_ctx Redactor.apply(result, @safe_ctx) end |
#scan(value) ⇒ Array(Object, Hash)
Run Layer 2 (credential scanner) over a value and return the scanned form alongside any hit counts. Callers decide whether to log the counts — the context deliberately does not assume access to a logger.
86 87 88 89 90 |
# File 'lib/woods/console/response_context.rb', line 86 def scan(value) return [value, {}] unless @credential_scanner @credential_scanner.scan(value) end |