Class: LocalVault::SyncState

Inherits:
Object
  • Object
show all
Defined in:
lib/localvault/sync_state.rb

Overview

Per-vault sync state tracking. Stores the checksum of secrets.enc at the time of the last successful push or pull, so the next localvault sync can determine whether local, remote, or both sides have changed.

Stored as ~/.localvault/vaults/<name>/.sync_state (YAML, mode 0600). Separate from meta.yml because meta.yml is part of the SyncBundle and including sync bookkeeping there would create a checksum feedback loop.

Constant Summary collapse

FILENAME =
".sync_state"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(vault_name) ⇒ SyncState

Returns a new instance of SyncState.



18
19
20
# File 'lib/localvault/sync_state.rb', line 18

def initialize(vault_name)
  @vault_name = vault_name
end

Instance Attribute Details

#vault_nameObject (readonly)

Returns the value of attribute vault_name.



16
17
18
# File 'lib/localvault/sync_state.rb', line 16

def vault_name
  @vault_name
end

Class Method Details

.local_checksum(store) ⇒ String?

Compute the SHA256 hex digest of a vault's local secrets.enc.

Parameters:

  • store (Store)

    vault store

Returns:

  • (String, nil)

    hex digest or nil if no secrets file



65
66
67
68
69
# File 'lib/localvault/sync_state.rb', line 65

def self.local_checksum(store)
  bytes = store.read_encrypted
  return nil if bytes.nil? || bytes.empty?
  Digest::SHA256.hexdigest(bytes)
end

Instance Method Details

#exists?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/localvault/sync_state.rb', line 26

def exists?
  File.exist?(path)
end

#last_synced_atObject



42
43
44
# File 'lib/localvault/sync_state.rb', line 42

def last_synced_at
  read&.dig("last_synced_at")
end

#last_synced_checksumObject



38
39
40
# File 'lib/localvault/sync_state.rb', line 38

def last_synced_checksum
  read&.dig("last_synced_checksum")
end

#pathObject



22
23
24
# File 'lib/localvault/sync_state.rb', line 22

def path
  File.join(Config.vaults_path, vault_name, FILENAME)
end

#readHash?

Returns parsed YAML data or nil.

Returns:

  • (Hash, nil)

    parsed YAML data or nil



31
32
33
34
35
36
# File 'lib/localvault/sync_state.rb', line 31

def read
  return nil unless exists?
  YAML.safe_load_file(path)
rescue Psych::SyntaxError
  nil
end

#write!(checksum:, direction:) ⇒ Object

Record a successful sync operation.

Parameters:

  • checksum (String)

    SHA256 hex of the local secrets.enc

  • direction (String)

    "push" or "pull"



50
51
52
53
54
55
56
57
58
59
# File 'lib/localvault/sync_state.rb', line 50

def write!(checksum:, direction:)
  FileUtils.mkdir_p(File.dirname(path), mode: 0o700)
  data = {
    "last_synced_checksum" => checksum,
    "last_synced_at"       => Time.now.utc.iso8601,
    "direction"            => direction
  }
  File.write(path, YAML.dump(data))
  File.chmod(0o600, path)
end