Module: Ace::Hitl::Hermes::Molecules::HermesQuarantine

Defined in:
lib/ace/hitl/hermes/molecules/hermes_quarantine.rb

Overview

Quarantine for invalid message files (spec 8wm.t.vs1 §7): the file is moved atomically into /.quarantine/ (0750) with a .reason.txt sidecar (0640). Quarantined content is never rewritten, re-validated, or delivered. Like every hermes write path, running as root is refused fail closed.

Class Method Summary collapse

Class Method Details

.move(folder, path, reason:, now: -> { Time.now }, euid_provider: -> { Process.euid }) ⇒ Object

Moves path (inside folder) into the quarantine directory and writes the reason sidecar. Returns the quarantined path.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ace/hitl/hermes/molecules/hermes_quarantine.rb', line 20

def move(folder, path, reason:, now: -> { Time.now },
  euid_provider: -> { Process.euid })
  if euid_provider.call.zero?
    raise RootUserError,
      "hermes writes without root: refusing quarantine move as euid 0 " \
      "(#{path})"
  end

  quarantine_dir = HermesContract.quarantine_path(folder)
  unless File.directory?(quarantine_dir)
    Dir.mkdir(quarantine_dir, HermesContract::QUARANTINE_DIR_MODE)
    # Modes are FORCED, not inherited from the umask (mirrors
    # HermesAtomicWriter): the pinned 0750 dir contract holds
    # under any umask.
    File.chmod(HermesContract::QUARANTINE_DIR_MODE, quarantine_dir)
  end

  base = File.basename(path)
  dest = File.join(quarantine_dir, base)
  suffix = 0
  while File.exist?(dest)
    suffix += 1
    dest = File.join(quarantine_dir, "#{base}.#{suffix}")
  end

  sidecar_path = "#{dest}#{HermesContract::REASON_EXT}"
  File.rename(path, dest)
  File.open(sidecar_path,
    File::WRONLY | File::CREAT | File::EXCL,
    HermesContract::FILE_MODE) do |sidecar|
    sidecar.write("#{now.call.utc.strftime("%Y-%m-%dT%H:%M:%SZ")} #{reason}\n")
  end
  # The open-mode is umask-sensitive; force the pinned 0640.
  File.chmod(HermesContract::FILE_MODE, sidecar_path)
  dest
end