apollographql / apollo-rs

Spec compliant GraphQL Tools in Rust.
Apache License 2.0
577 stars 45 forks source link

graceful handling of syntax and semantic errors: `apollo-compiler` panics on syntax errors #256

Open EverlastingBugstopper opened 2 years ago

EverlastingBugstopper commented 2 years ago

if you place characters after a [Type], like [Type]oops, apollo-compiler will panic.

example valid schema:

type Person {
  id: ID!
  name: String
  appearedIn: [Film]
  directed: [Film]
}

type Film {
  id: ID!
  title: String
  actors: [Person]
  director: Person
}

type Query {
  person(id: ID!): Person
  people: [Person]
  film(id: ID!): Film!
  films: [Film]
}

example panic schema:

type Person {
  id: ID!
  name: String
  appearedIn: [Film]s
  directed: [Film]
}

type Film {
  id: ID!
  title: String
  actors: [Person]
  director: Person
}

type Query {
  person(id: ID!): Person
  people: [Person]
  film(id: ID!): Film!
  films: [Film]
}

abbreviated panic

$ rover schema lint --schema ./schema.out
Validating that --schema ./schema.out conforms to the GraphQL specification.
thread 'main' panicked at 'Field must have a type', /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:963:28
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

panic with full backtrace

$ rover schema lint --schema ./schema.out
Validating that --schema ./schema.out conforms to the GraphQL specification.
thread 'main' panicked at 'Field must have a type', /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:963:28
stack backtrace:
   0: rust_begin_unwind
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/std/src/panicking.rs:584:5
   1: core::panicking::panic_fmt
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/panicking.rs:143:14
   2: core::panicking::panic_display
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/panicking.rs:73:5
   3: core::panicking::panic_str
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/panicking.rs:56:5
   4: core::option::expect_failed
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/option.rs:1852:5
   5: core::option::Option<T>::expect
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/option.rs:715:21
   6: apollo_compiler::queries::database::field_definition
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:963:17
   7: core::ops::function::FnMut::call_mut
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:150:5
   8: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:280:13
   9: core::option::Option<T>::map
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/option.rs:906:29
  10: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/iter/adapters/map.rs:103:9
  11: alloc::vec::Vec<T,A>::extend_desugared
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/mod.rs:2649:35
  12: <alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<T,I>>::spec_extend
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/spec_extend.rs:18:9
  13: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/spec_from_iter_nested.rs:43:9
  14: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/spec_from_iter.rs:33:9
  15: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/mod.rs:2552:9
  16: core::iter::traits::iterator::Iterator::collect
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/iter/traits/iterator.rs:1778:9
  17: apollo_compiler::queries::database::fields_definition
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:949:48
  18: apollo_compiler::queries::database::object_type_definition
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:709:29
  19: apollo_compiler::queries::database::object_types::{{closure}}
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:442:22
  20: core::ops::function::impls::<impl core::ops::function::FnMut<A> for &mut F>::call_mut
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:269:13
  21: <core::slice::iter::Iter<T> as core::iter::traits::iterator::Iterator>::find_map
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/slice/iter/macros.rs:276:38
  22: <core::iter::adapters::filter_map::FilterMap<I,F> as core::iter::traits::iterator::Iterator>::next
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/iter/adapters/filter_map.rs:61:9
  23: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/spec_from_iter_nested.rs:26:32
  24: <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/spec_from_iter.rs:33:9
  25: <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/alloc/src/vec/mod.rs:2552:9
  26: core::iter::traits::iterator::Iterator::collect
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/iter/traits/iterator.rs:1778:9
  27: apollo_compiler::queries::database::object_types
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:437:19
  28: <apollo_compiler::queries::database::ObjectTypesQuery as salsa::plumbing::QueryFunction>::execute
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:50:8
  29: salsa::derived::slot::Slot<Q,MP>::read_upgrade::{{closure}}
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:218:13
  30: salsa::runtime::Runtime::execute_query_implementation
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/runtime.rs:330:21
  31: salsa::derived::slot::Slot<Q,MP>::read_upgrade
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:215:26
  32: salsa::derived::slot::Slot<Q,MP>::read
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:148:9
  33: <salsa::derived::DerivedStorage<Q,MP> as salsa::plumbing::QueryStorageOps<Q>>::try_fetch
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived.rs:170:13
  34: salsa::QueryTable<Q>::try_get
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/lib.rs:494:9
  35: salsa::QueryTable<Q>::get
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/lib.rs:490:9
  36: <DB as apollo_compiler::queries::database::SourceDatabase>::object_types::__shim
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:27:1
  37: <DB as apollo_compiler::queries::database::SourceDatabase>::object_types
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:27:1
  38: apollo_compiler::queries::database::add_object_type_id_to_schema
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:899:55
  39: apollo_compiler::queries::database::schema
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:428:21
  40: <apollo_compiler::queries::database::SchemaQuery as salsa::plumbing::QueryFunction>::execute
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:48:8
  41: salsa::derived::slot::Slot<Q,MP>::read_upgrade::{{closure}}
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:218:13
  42: salsa::runtime::Runtime::execute_query_implementation
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/runtime.rs:330:21
  43: salsa::derived::slot::Slot<Q,MP>::read_upgrade
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:215:26
  44: salsa::derived::slot::Slot<Q,MP>::read
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived/slot.rs:148:9
  45: <salsa::derived::DerivedStorage<Q,MP> as salsa::plumbing::QueryStorageOps<Q>>::try_fetch
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/derived.rs:170:13
  46: salsa::QueryTable<Q>::try_get
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/lib.rs:494:9
  47: salsa::QueryTable<Q>::get
             at /home/a/.cargo/registry/src/github.com-1ecc6299db9ec823/salsa-0.16.1/src/lib.rs:490:9
  48: <DB as apollo_compiler::queries::database::SourceDatabase>::schema::__shim
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:27:1
  49: <DB as apollo_compiler::queries::database::SourceDatabase>::schema
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/queries/database.rs:27:1
  50: apollo_compiler::validation::schema::check
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/validation/schema.rs:13:8
  51: apollo_compiler::validation::Validator::validate
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/validation/mod.rs:40:33
  52: apollo_compiler::ApolloCompiler::validate
             at /home/a/.cargo/git/checkouts/apollo-rs-c2f4fdeb51021351/2008021/crates/apollo-compiler/src/lib.rs:37:9
  53: rover::command::schema::lint::Lint::run
             at ./src/command/schema/lint.rs:28:22
  54: rover::command::schema::Schema::run
             at ./src/command/schema/mod.rs:24:39
  55: rover::cli::Rover::execute_command
             at ./src/cli.rs:189:41
  56: rover::cli::Rover::run
             at ./src/cli.rs:127:34
  57: rover::main::{{closure}}
             at ./src/bin/rover.rs:15:5
  58: rover::main
             at ./src/bin/rover.rs:5:1
  59: core::ops::function::FnOnce::call_once
             at /rustc/7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace
SimonSapin commented 2 years ago

I was gonna open an issue but it looks the same is this.

Test case: add crates/apollo-compiler/test_data/diagnostics/0050_unnamed_object_type.graphql

type {
  cat: String
}

cargo test:

thread 'tests::compiler_tests' panicked at 'Field must have a name', crates/apollo-compiler/src/database/hir_db.rs:1092:24

In general, any use of Option::expect or similar should probably be replaced by something that emits a diagnostic and continues with some kind of fallback (such as skipping ill-formed definitions in the HIR)

goto-bus-stop commented 2 years ago

Yes! I think I'll be working on this next as I'm already having to write more .expect()s changing some of our From impls to TryFrom, and it feels bad (and it is bad for untrusted user input 😇 ).

I think our first step will be to outright skip things in the HIR. If the HIR can't be generated fully, it should be because there was a parser error, which is already reported.

lrlna commented 2 years ago

ugh yea this is handled really rather terribly atm (i only say this because i am responsible >.<). would be so very good to fix this!!

there are a few overarching considerations when uniting the two types of errors here: