Class: Rubino::CLI::TrustGate

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/cli/trust_gate.rb

Overview

The interactive folder-trust checkpoint. Asks ONCE per directory, before that directory’s AGENTS.md / project context + .rubino/skills are honored, and remembers the answer in Rubino::Trust so it’s never re-asked.

Modelled on VS Code Workspace Trust + Claude Code’s trust dialog. Declining is non-destructive (VS Code “Restricted Mode”): the session still runs, it just runs WITHOUT that directory’s project context/skills (the assembler consults Rubino::Trust.trusted? before injecting them).

Skipped entirely — no prompt, treated as allowed for the duration — when:

- the dir is already trusted,
- the dir has nothing to gate (no context file, no .rubino/skills),
- --ignore-rules was passed (project context is off regardless), or
- the run is non-interactive (-q / no TTY): we never block automation.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ui: nil, interactive: true, ignore_rules: false) ⇒ TrustGate

Returns a new instance of TrustGate.



34
35
36
37
38
# File 'lib/rubino/cli/trust_gate.rb', line 34

def initialize(ui: nil, interactive: true, ignore_rules: false)
  @ui = ui || Rubino.ui
  @interactive = interactive
  @ignore_rules = ignore_rules
end

Class Method Details

.gateworthy?(dir) ⇒ Boolean

A directory is only worth a trust decision when it actually ships something rubino auto-injects: a project-context file or a skills dir. An empty scratch dir has nothing to gate — so nothing is withheld and the “untrusted — context/skills withheld” label would be misleading. Exposed at the class level so the /dirs and /status listings can tell “user declined” (gateworthy + not trusted) from “nothing to trust here” (not gateworthy) and word the line honestly.

Returns:

  • (Boolean)


27
28
29
30
31
32
# File 'lib/rubino/cli/trust_gate.rb', line 27

def self.gateworthy?(dir)
  Context::FileDiscovery.new(base_path: dir).discover_files.any? ||
    File.directory?(File.join(dir, Skills::PromptIndex::DEFAULT_SKILL_DIR))
rescue StandardError
  false
end

Instance Method Details

#ensure_trust(dir) ⇒ Object

Ensures dir has a trust decision. Returns true when the directory’s project context/skills may be loaded, false when it must run in restricted mode. Prompts at most once, then remembers a “yes”.



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rubino/cli/trust_gate.rb', line 43

def ensure_trust(dir)
  return true if Rubino::Trust.trusted?(dir)
  return true if @ignore_rules            # context already suppressed
  return true unless gateworthy?(dir)     # nothing to gate → no ceremony

  # Non-interactive: never block. We also do NOT remember it (the user
  # never vouched), so context stays withheld this run — Restricted Mode
  # by default for automation, matching VS Code's headless behaviour.
  return false unless @interactive

  prompt(dir)
end