Module: Mxrb::Compiler::Mda
- Defined in:
- lib/mxrb/compiler/mda.rb
Overview
Safe inspection and content-level comparison of Mendix deployment archives.
Defined Under Namespace
Classes: Difference, Entry, Inspection
Class Method Summary
collapse
Class Method Details
.build_entry(entry) ⇒ Object
58
59
60
61
62
63
64
65
66
|
# File 'lib/mxrb/compiler/mda.rb', line 58
def build_entry(entry)
path = safe_path(entry.name)
directory = entry.directory?
bytes = directory ? '' : entry.get_input_stream.read
Entry.new(
path:, size: entry.size, crc: entry.crc,
sha256: directory ? nil : Digest::SHA256.hexdigest(bytes), directory:
)
end
|
.build_inspection(path, metadata, entries) ⇒ Object
51
52
53
54
55
56
|
# File 'lib/mxrb/compiler/mda.rb', line 51
def build_inspection(path, metadata, entries)
Inspection.new(
path:, metadata:, entries: entries.sort_by(&:path),
sha256: Digest::SHA256.file(path).hexdigest
)
end
|
.compare(left, right) ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
|
# File 'lib/mxrb/compiler/mda.rb', line 32
def compare(left, right)
left_entries = entry_map(left)
right_entries = entry_map(right)
(left_entries.keys | right_entries.keys).sort.filter_map do |path|
lhs = left_entries[path]
rhs = right_entries[path]
status = difference_status(lhs, rhs)
next unless status
Difference.new(path:, status:, left_sha256: lhs&.sha256, right_sha256: rhs&.sha256)
end
end
|
.difference_status(left, right) ⇒ Object
80
81
82
83
84
85
86
|
# File 'lib/mxrb/compiler/mda.rb', line 80
def difference_status(left, right)
return :added unless left
return :removed unless right
return :changed if left.sha256 != right.sha256
nil
end
|
.entry_map(path) ⇒ Object
76
77
78
|
# File 'lib/mxrb/compiler/mda.rb', line 76
def entry_map(path)
inspect(path).files.to_h { [_1.path, _1] }
end
|
.inspect(path) ⇒ Object
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/mxrb/compiler/mda.rb', line 20
def inspect(path)
archive_path = File.expand_path(path)
entries = read_entries(archive_path)
metadata_entry = entries.find { _1.path == 'model/metadata.json' }
metadata = read_metadata(archive_path, metadata_entry)
raise CompilationError, 'MDA has no model/metadata.json' unless metadata
build_inspection(archive_path, metadata, entries)
rescue Zip::Error, JSON::ParserError => e
raise CompilationError, "invalid MDA #{archive_path}: #{e.message}"
end
|
.read_entries(archive_path) ⇒ Object
45
46
47
48
49
|
# File 'lib/mxrb/compiler/mda.rb', line 45
def read_entries(archive_path)
Zip::File.open(archive_path) do |archive|
archive.map { build_entry(_1) }
end
end
|
68
69
70
71
72
73
74
|
# File 'lib/mxrb/compiler/mda.rb', line 68
def read_metadata(archive_path, entry)
return unless entry
Zip::File.open(archive_path) do |archive|
JSON.parse(archive.get_entry(entry.path).get_input_stream.read)
end
end
|
.safe_path(path) ⇒ Object
88
89
90
91
92
93
94
95
96
|
# File 'lib/mxrb/compiler/mda.rb', line 88
def safe_path(path)
clean = path.to_s.tr('\\', '/').sub(%r{\A/+}, '')
parts = clean.split('/')
if clean.empty? || parts.include?('..') || parts.include?('.')
raise CompilationError, "unsafe MDA entry #{path.inspect}"
end
clean
end
|