Class: RailsAiBridge::Registry::Lockfile

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_bridge/registry/lockfile.rb

Overview

Records and verifies expected git commit SHAs for skill packs.

The lockfile is a JSON document keyed by pack name. Each entry stores the pack source, ref, and the resolved commit SHA. When verification is enabled, PackResolver compares the locked SHA against the actual HEAD of the cloned repository and fails closed on mismatch.

Defined Under Namespace

Classes: Entry

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entries) ⇒ Lockfile

Returns a new instance of Lockfile.

Parameters:

  • entries (Hash{String => Entry})

    map of pack name to lockfile entry



72
73
74
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 72

def initialize(entries)
  @entries = entries.freeze
end

Class Method Details

.generate(manifest, source_resolver) ⇒ Hash{String => Entry}

Generates lockfile entries by resolving every pack in the manifest.

Parameters:

Returns:

  • (Hash{String => Entry})


46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 46

def generate(manifest, source_resolver)
  manifest.packs.each_with_object({}) do |(name, pack_def), entries|
    base_path = source_resolver.resolve(pack_def.source, ref: pack_def.ref)
    commit_sha = source_resolver.current_commit(base_path)
    entries[name] = Entry.new(
      pack_name: name,
      source: pack_def.source,
      ref: pack_def.ref,
      commit_sha: commit_sha
    )
  end
end

.load(path) ⇒ Lockfile

Loads a lockfile from disk.

Parameters:

  • path (String, nil)

    path to the lockfile; nil means no lockfile

Returns:

  • (Lockfile)

    empty lockfile when path is nil or the file does not exist



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 23

def load(path)
  return new({}) if path.nil? || !File.exist?(path)

  raw = File.read(path)
  data = JSON.parse(raw)
  entries = data.transform_values do |entry|
    Entry.new(
      pack_name: entry['pack_name'],
      source: entry['source'],
      ref: entry['ref'],
      commit_sha: entry['commit_sha']
    )
  end
  new(entries)
rescue JSON::ParserError => error
  raise ArgumentError, "Invalid lockfile JSON at #{path}: #{error.message}"
end

.write(path, manifest, source_resolver) ⇒ void

This method returns an undefined value.

Writes a lockfile to disk for the given manifest.

Parameters:



65
66
67
68
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 65

def write(path, manifest, source_resolver)
  entries = generate(manifest, source_resolver)
  new(entries).write(path)
end

Instance Method Details

#entry(pack_name) ⇒ Entry?

Parameters:

  • pack_name (String)

Returns:



80
81
82
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 80

def entry(pack_name)
  @entries[pack_name]
end

#to_jsonString

Serializes the lockfile to JSON.

Returns:

  • (String)


87
88
89
90
91
92
93
94
95
96
97
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 87

def to_json(*)
  data = @entries.transform_values do |entry|
    {
      'pack_name' => entry.pack_name,
      'source' => entry.source,
      'ref' => entry.ref,
      'commit_sha' => entry.commit_sha
    }
  end
  JSON.pretty_generate(data)
end

#write(path) ⇒ void

This method returns an undefined value.

Writes the lockfile to disk.

Parameters:

  • path (String)


103
104
105
106
# File 'lib/rails_ai_bridge/registry/lockfile.rb', line 103

def write(path)
  FileUtils.mkdir_p(File.dirname(path))
  File.write(path, "#{to_json}\n")
end