~singpolyma/dhall-ruby

2f57e3bfe6da7daf7b47b724ad0cebeea37bfe77 — Stephen Paul Weber 2 years ago ebd4b25
Implement integrity checks
M lib/dhall/ast.rb => lib/dhall/ast.rb +19 -1
@@ 974,10 974,28 @@ module Dhall
		end

		class IntegrityCheck
			def initialize(protocol, data)
			class FailureException < StandardError; end

			def initialize(protocol=:nocheck, data=nil)
				@protocol = protocol
				@data = data
			end

			def to_s
				"#{@protocol}:#{@data}"
			end

			def check(expr)
				if @protocol == :nocheck || expr.cache_key == to_s
					expr
				else
					raise FailureException, "#{expr} does not match #{self}"
				end
			end

			def as_json
				@protocol == :nocheck ? nil : [@protocol, @data]
			end
		end

		class Expression

M lib/dhall/binary.rb => lib/dhall/binary.rb +10 -1
@@ 1,6 1,7 @@
# frozen_string_literal: true

require "cbor"
require "digest/sha2"

require "dhall/ast"
require "dhall/builtins"


@@ 33,6 34,14 @@ module Dhall
		def as_cbor
			as_json
		end

		def digest(digest: Digest::SHA2.new(256))
			(digest << normalize.to_binary).freeze
		end

		def cache_key
			"sha256:#{digest.hexdigest}"
		end
	end

	class Application


@@ 180,7 189,7 @@ module Dhall
			parts[0] = Dhall.decode(parts[0]) if path_type < 2 && !parts[0].nil?

			new(
				integrity_check.nil? ? nil : IntegrityCheck.new(*integrity_check),
				IntegrityCheck.new(*integrity_check),
				IMPORT_TYPES[import_type],
				PATH_TYPES[path_type].new(*parts)
			)

M lib/dhall/resolve.rb => lib/dhall/resolve.rb +4 -2
@@ 246,8 246,10 @@ module Dhall

			def resolve(resolver)
				@expr.instance_eval do
					@path.resolve(resolver).then do |expr|
						@import_type.call(expr).resolve(resolver.child(@path))
					@path.resolve(resolver).then do |result|
						@integrity_check.check(
							@import_type.call(result)
						).resolve(resolver.child(@path))
					end
				end
			end

M test/normalization/gen => test/normalization/gen +4 -0
@@ 1,5 1,9 @@
#!/bin/sh

cp -r "$(git root)"/dhall-lang/tests/normalization/success "$(git root)"/test/normalization/standard

cd "$(git root)"/test/normalization/standard
find . -name '*.dhall' -exec "$(git root)"/test/normalization/dhall-encode '{}' \;

cd "$(git root)"/test/normalization
find . -name '*.dhallb' -exec "$(git root)"/test/normalization/dhall-hash '{}' \;

M test/test_resolve.rb => test/test_resolve.rb +25 -13
@@ 44,7 44,7 @@ class TestResolve < Minitest::Test

	def test_import_as_text
		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Text,
			Dhall::Import::RelativePath.new("text")
		)


@@ 59,7 59,7 @@ class TestResolve < Minitest::Test
		expr = Dhall::Function.of_arguments(
			Dhall::Variable["Natural"],
			body: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::RelativePath.new("var")
			)


@@ 75,7 75,7 @@ class TestResolve < Minitest::Test
		expr = Dhall::Function.of_arguments(
			Dhall::Variable["Natural"],
			body: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::RelativePath.new("import")
			)


@@ 91,7 91,7 @@ class TestResolve < Minitest::Test
		expr = Dhall::Function.of_arguments(
			Dhall::Variable["Natural"],
			body: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::RelativePath.new("self")
			)


@@ 106,7 106,7 @@ class TestResolve < Minitest::Test
		expr = Dhall::Function.of_arguments(
			Dhall::Variable["Natural"],
			body: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::RelativePath.new("a")
			)


@@ 119,7 119,7 @@ class TestResolve < Minitest::Test

	def test_two_references_no_loop
		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Expression,
			Dhall::Import::RelativePath.new("2text")
		)


@@ 135,7 135,7 @@ class TestResolve < Minitest::Test

	def test_missing
		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Expression,
			Dhall::Import::MissingImport.new
		)


@@ 145,10 145,22 @@ class TestResolve < Minitest::Test
		end
	end

	def test_integrity_check_failure
		expr = Dhall::Import.new(
			Dhall::Import::IntegrityCheck.new("sha256", "badhash"),
			Dhall::Import::Expression,
			Dhall::Import::RelativePath.new("var")
		)

		assert_raises Dhall::Import::IntegrityCheck::FailureException do
			expr.resolve(@resolver).sync
		end
	end

	def test_fallback_to_expr
		expr = Dhall::Operator::ImportFallback.new(
			lhs: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::MissingImport.new
			),


@@ 161,12 173,12 @@ class TestResolve < Minitest::Test
	def test_fallback_to_import
		expr = Dhall::Operator::ImportFallback.new(
			lhs: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::MissingImport.new
			),
			rhs: Dhall::Import.new(
				nil,
				Dhall::Import::IntegrityCheck.new,
				Dhall::Import::Expression,
				Dhall::Import::RelativePath.new("import")
			)


@@ 181,7 193,7 @@ class TestResolve < Minitest::Test
			.to_return(status: 200, body: "\x00")

		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Expression,
			Dhall::Import::RelativePath.new("using")
		)


@@ 194,7 206,7 @@ class TestResolve < Minitest::Test
			.to_return(status: 200, body: "\x00")

		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Expression,
			Dhall::Import::AbsolutePath.new("ipfs", "TESTCID")
		)


@@ 210,7 222,7 @@ class TestResolve < Minitest::Test
			.to_return(status: 200, body: "\x00")

		expr = Dhall::Import.new(
			nil,
			Dhall::Import::IntegrityCheck.new,
			Dhall::Import::Expression,
			Dhall::Import::AbsolutePath.new("ipfs", "TESTCID")
		)

M test/test_resolvers.rb => test/test_resolvers.rb +1 -0
@@ 3,6 3,7 @@
require "minitest/autorun"

require "dhall/resolve"
require "dhall/normalize"

class TestResolvers < Minitest::Test
	def test_default_resolver_path