Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions src/server/action_jsonschema_evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <cassert> // assert
#include <filesystem> // std::filesystem::path
#include <sstream> // std::ostringstream
#include <stdexcept> // std::runtime_error
#include <string_view> // std::string_view
#include <type_traits> // std::underlying_type_t
#include <utility> // std::move
Expand All @@ -32,7 +33,9 @@ auto trace(sourcemeta::blaze::Evaluator &evaluator,
auto locations_path{template_path.parent_path() / "locations.metapack"};
// TODO: Cache this across runs?
const auto locations{sourcemeta::one::read_json(locations_path)};
assert(locations.defines("static"));
if (!locations.is_object() || !locations.defines("static")) {
throw std::runtime_error("Failed to read schema locations metadata");
}
const auto &static_locations{locations.at("static")};

sourcemeta::core::PointerPositionTracker tracker;
Expand Down Expand Up @@ -68,7 +71,9 @@ auto trace(sourcemeta::blaze::Evaluator &evaluator,
// TODO: Can we avoid converting the weak pointer into a pointer
// here?
sourcemeta::core::to_pointer(instance_location))};
assert(instance_positions.has_value());
if (!instance_positions.has_value()) {
throw std::runtime_error("Failed to resolve instance positions");
}
step.assign(
"instancePositions",
sourcemeta::core::to_json(std::move(instance_positions).value()));
Expand All @@ -88,9 +93,17 @@ auto trace(sourcemeta::blaze::Evaluator &evaluator,
// Determine keyword vocabulary
const auto &current_location{
static_locations.at(instruction.keyword_location)};
if (!current_location.is_object() ||
!current_location.defines("baseDialect") ||
!current_location.defines("dialect")) {
throw std::runtime_error("Failed to resolve base dialect");
}

const auto base_dialect_result{sourcemeta::core::to_base_dialect(
current_location.at("baseDialect").to_string())};
assert(base_dialect_result.has_value());
if (!base_dialect_result.has_value()) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has_value() check won’t help if malformed current_location causes current_location.at("baseDialect") (and later at("dialect")) to assert/UB before to_base_dialect() is called. If these fields can be missing/invalid, consider validating presence/type without at() first.

Severity: high

Other Locations
  • src/server/action_jsonschema_evaluate.h:103

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

throw std::runtime_error("Failed to resolve base dialect");
}
const auto vocabularies{sourcemeta::core::vocabularies(
sourcemeta::core::schema_resolver, base_dialect_result.value(),
current_location.at("dialect").to_string())};
Expand Down Expand Up @@ -123,14 +136,18 @@ enum class EvaluateType { Standard, Trace };
auto evaluate(const std::filesystem::path &template_path,
const std::string &instance, const EvaluateType type)
-> sourcemeta::core::JSON {
assert(std::filesystem::exists(template_path));
if (!std::filesystem::exists(template_path)) {
throw std::runtime_error("Schema template not found");
}

// TODO: Cache this conversion across runs, potentially using the schema file
// "checksum" as the cache key. This is important as the template might be
// compressed
const auto template_json{read_json(template_path)};
const auto schema_template{sourcemeta::blaze::from_json(template_json)};
assert(schema_template.has_value());
if (!schema_template.has_value()) {
throw std::runtime_error("Failed to parse schema template");
}

sourcemeta::blaze::Evaluator evaluator;

Expand Down
11 changes: 9 additions & 2 deletions src/server/action_schema_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@
#include <cassert> // assert
#include <filesystem> // std::filesystem
#include <sstream> // std::ostringstream
#include <stdexcept> // std::runtime_error
#include <string> // std::string, std::getline
#include <string_view> // std::string_view

namespace sourcemeta::one {

static auto search(const std::filesystem::path &search_index,
const std::string_view query) -> sourcemeta::core::JSON {
assert(std::filesystem::exists(search_index));
if (!std::filesystem::exists(search_index)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this PR’s intent is to avoid debug-only enforcement, note the remaining assert(search_index.is_absolute()) below will be a no-op in release builds (potentially allowing unexpected relative paths). Consider making that invariant a runtime check too.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

throw std::runtime_error("Search index not found");
}

assert(search_index.is_absolute());

auto file{read_stream_raw(search_index)};
assert(file.has_value());
if (!file.has_value()) {
throw std::runtime_error("Failed to read search index");
}

auto result{sourcemeta::core::JSON::make_array()};
// TODO: Extend the Core JSONL iterators to be able
Expand Down
44 changes: 24 additions & 20 deletions src/shared/metapack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <functional> // std::functional
#include <ostream> // std::ostream
#include <sstream> // std::ostringstream
#include <stdexcept> // std::runtime_error
#include <utility> // std::move

// TODO: There are lots of opportunities to optimise this file
Expand Down Expand Up @@ -81,30 +82,31 @@ auto read_stream_raw(const std::filesystem::path &path)

auto stream{sourcemeta::core::read_file(path)};
auto metadata{sourcemeta::core::parse_json(stream)};
assert(metadata.is_object());
assert(metadata.defines("version"));
assert(metadata.defines("checksum"));
assert(metadata.defines("lastModified"));
assert(metadata.defines("mime"));
assert(metadata.defines("bytes"));
assert(metadata.defines("duration"));
assert(metadata.defines("encoding"));
assert(metadata.at("version").is_integer());
assert(metadata.at("version").is_positive());
assert(metadata.at("checksum").is_string());
assert(metadata.at("lastModified").is_string());
assert(metadata.at("mime").is_string());
assert(metadata.at("bytes").is_integer());
assert(metadata.at("bytes").is_positive());
assert(metadata.at("duration").is_integer());
assert(metadata.at("duration").is_positive());
assert(metadata.at("encoding").is_string());
if (!metadata.is_object() || !metadata.defines("version") ||
!metadata.defines("checksum") || !metadata.defines("lastModified") ||
!metadata.defines("mime") || !metadata.defines("bytes") ||
!metadata.defines("duration") || !metadata.defines("encoding")) {
throw std::runtime_error("The file metadata is missing required fields");
}

if (!metadata.at("version").is_integer() ||
!metadata.at("version").is_positive() ||
!metadata.at("checksum").is_string() ||
!metadata.at("lastModified").is_string() ||
!metadata.at("mime").is_string() || !metadata.at("bytes").is_integer() ||
!metadata.at("bytes").is_positive() ||
!metadata.at("duration").is_integer() ||
!metadata.at("duration").is_positive() ||
!metadata.at("encoding").is_string()) {
throw std::runtime_error(
"The file metadata has fields with unexpected types");
}

Encoding encoding{Encoding::Identity};
if (metadata.at("encoding").to_string() == "gzip") {
encoding = Encoding::GZIP;
} else if (metadata.at("encoding").to_string() != "identity") {
assert(false);
throw std::runtime_error("Failed to determine file encoding");
}

return File{
Expand Down Expand Up @@ -134,7 +136,9 @@ auto read_json_with_metadata(
const sourcemeta::core::JSON::ParseCallback &callback)
-> File<sourcemeta::core::JSON> {
auto file{read_stream_raw(path)};
assert(file.has_value());
if (!file.has_value()) {
throw std::runtime_error("Failed to read file");
}
std::ostringstream buffer;
if (file.value().encoding == Encoding::GZIP) {
sourcemeta::one::gunzip(file.value().data, buffer);
Expand Down