Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: deny unknown fields in config #287

Merged
merged 3 commits into from
Jan 6, 2025
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
4 changes: 2 additions & 2 deletions htsget-config/src/config/advanced/allow_guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait QueryAllowed {

/// A query guard represents query parameters that can be allowed to storage for a given query.
#[derive(Serialize, Clone, Debug, Deserialize, PartialEq, Eq)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct AllowGuard {
allow_reference_names: ReferenceNames,
allow_fields: Fields,
Expand All @@ -39,7 +39,7 @@ impl Default for AllowGuard {

/// Reference names that can be matched.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
pub enum ReferenceNames {
Tagged(TaggedTypeAll),
List(HashSet<String>),
Expand Down
5 changes: 3 additions & 2 deletions htsget-config/src/config/advanced/cors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const CORS_MAX_AGE: usize = 2592000;

/// Tagged allow headers for cors config, either Mirror or Any.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub enum TaggedAllowTypes {
#[serde(alias = "mirror", alias = "MIRROR")]
Mirror,
Expand All @@ -27,7 +28,7 @@ pub enum TaggedAllowTypes {

/// Allowed type for cors config which is used to configure cors behaviour.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
pub enum AllowType<T, Tagged = TaggedAllowTypes> {
Tagged(Tagged),
#[serde(bound(serialize = "T: Display", deserialize = "T: FromStr, T::Err: Display"))]
Expand Down Expand Up @@ -159,7 +160,7 @@ impl Display for HeaderValue {

/// Cors configuration for the htsget server.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct CorsConfig {
allow_credentials: bool,
allow_origins: AllowType<HeaderValue>,
Expand Down
1 change: 1 addition & 0 deletions htsget-config/src/config/advanced/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod url;

/// Determines which tracing formatting style to use.
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Default)]
#[serde(deny_unknown_fields)]
pub enum FormattingStyle {
#[default]
Full,
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/config/advanced/regex_location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};

/// A regex storage is a storage that matches ids using Regex.
#[derive(Serialize, Debug, Clone, Deserialize)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct RegexLocation {
#[serde(with = "serde_regex")]
regex: Regex,
Expand Down
1 change: 1 addition & 0 deletions htsget-config/src/config/advanced/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use serde::{Deserialize, Serialize};

/// Options for the remote URL server config.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Url {
#[serde(with = "http_serde::uri")]
url: Uri,
Expand Down
5 changes: 3 additions & 2 deletions htsget-config/src/config/data_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ use std::path::{Path, PathBuf};

/// Tagged allow headers for cors config, either Mirror or Any.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub enum DataServerTagged {
#[serde(alias = "none", alias = "NONE", alias = "null")]
None,
}

/// Whether the data server is enabled or not.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
#[allow(clippy::large_enum_variant)]
pub enum DataServerEnabled {
None(DataServerTagged),
Expand All @@ -38,7 +39,7 @@ impl DataServerEnabled {

/// Configuration for the htsget server.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct DataServerConfig {
addr: SocketAddr,
local_path: PathBuf,
Expand Down
4 changes: 2 additions & 2 deletions htsget-config/src/config/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use {crate::config::advanced::url::Url, crate::error, http::Uri};

/// The locations of data.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default, from = "LocationsOneOrMany")]
#[serde(default, deny_unknown_fields, from = "LocationsOneOrMany")]
pub struct Locations(Vec<LocationEither>);

impl Locations {
Expand Down Expand Up @@ -48,7 +48,7 @@ impl Default for Locations {

/// Either simple or regex based location
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
pub enum LocationEither {
Simple(Location),
Regex(RegexLocation),
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct Args {

/// Simplified config.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct Config {
ticket_server: TicketServerConfig,
data_server: DataServerEnabled,
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/config/service_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::collections::HashMap;

/// Service info config.
#[derive(Serialize, Debug, Clone, Default, PartialEq, Eq)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct ServiceInfo(HashMap<String, Value>);

impl ServiceInfo {
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/config/ticket_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::net::SocketAddr;

/// Configuration for the htsget ticket server.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct TicketServerConfig {
addr: SocketAddr,
#[serde(skip_serializing)]
Expand Down
1 change: 1 addition & 0 deletions htsget-config/src/storage/c4gh/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::path::PathBuf;

/// Local C4GH key storage.
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct C4GHLocal {
private: PathBuf,
public: PathBuf,
Expand Down
4 changes: 2 additions & 2 deletions htsget-config/src/storage/c4gh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod secrets_manager;

/// Config for Crypt4GH keys.
#[derive(Deserialize, Debug, Clone)]
#[serde(try_from = "C4GHKeyLocation")]
#[serde(try_from = "C4GHKeyLocation", deny_unknown_fields)]
pub struct C4GHKeys {
// Store a cloneable future so that it can be resolved outside serde.
keys: Shared<BoxFuture<'static, Result<Vec<crypt4gh::Keys>>>>,
Expand Down Expand Up @@ -74,7 +74,7 @@ impl TryFrom<C4GHKeyLocation> for C4GHKeys {

/// The location of C4GH keys.
#[derive(Deserialize, Debug, Clone)]
#[serde(tag = "kind")]
#[serde(tag = "kind", deny_unknown_fields)]
#[non_exhaustive]
pub enum C4GHKeyLocation {
#[serde(alias = "file", alias = "FILE")]
Expand Down
1 change: 1 addition & 0 deletions htsget-config/src/storage/c4gh/secrets_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use tempfile::TempDir;

/// C4GH secrets manager key storage.
#[derive(Deserialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct C4GHSecretsManager {
private: String,
public: String,
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/storage/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::str::FromStr;

/// Local file based storage.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct File {
scheme: Scheme,
#[serde(with = "http_serde::authority")]
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl ResolvedId {

/// Specify the storage backend to use as config values.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "kind")]
#[serde(tag = "kind", deny_unknown_fields)]
#[non_exhaustive]
pub enum Backend {
#[serde(alias = "file", alias = "FILE")]
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/storage/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};

/// Configuration struct for S3 storage.
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct S3 {
bucket: String,
endpoint: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/storage/url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};

/// Remote URL server storage struct.
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(try_from = "advanced::url::Url")]
#[serde(try_from = "advanced::url::Url", deny_unknown_fields)]
pub struct Url {
#[serde(with = "http_serde::uri")]
url: Uri,
Expand Down
2 changes: 1 addition & 1 deletion htsget-config/src/tls/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use serde::Deserialize;
/// A certificate and key pair used for TLS. Serialization is not implemented because there
/// is no way to convert back to a `PathBuf`.
#[derive(Deserialize, Debug, Clone, Default)]
#[serde(try_from = "RootCertStorePair")]
#[serde(try_from = "RootCertStorePair", deny_unknown_fields)]
pub struct TlsClientConfig {
cert: Option<Vec<Certificate>>,
identity: Option<Identity>,
Expand Down
4 changes: 3 additions & 1 deletion htsget-config/src/tls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub trait KeyPairScheme {
/// A certificate and key pair used for TLS. Serialization is not implemented because there
/// is no way to convert back to a `PathBuf`.
#[derive(Deserialize, Debug, Clone)]
#[serde(try_from = "CertificateKeyPairPath")]
#[serde(try_from = "CertificateKeyPairPath", deny_unknown_fields)]
pub struct TlsServerConfig {
server_config: ServerConfig,
}
Expand All @@ -49,6 +49,7 @@ impl TlsServerConfig {
/// The location of a certificate and key pair used for TLS.
/// This is the path to the PEM formatted X.509 certificate and private key.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct CertificateKeyPairPath {
cert: PathBuf,
key: PathBuf,
Expand Down Expand Up @@ -76,6 +77,7 @@ impl CertificateKeyPair {
/// The location of a certificate and key pair used for TLS.
/// This is the path to the PEM formatted X.509 certificate and private key.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub struct RootCertStorePair {
#[serde(flatten)]
key_pair: Option<CertificateKeyPairPath>,
Expand Down
17 changes: 12 additions & 5 deletions htsget-config/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub type Result<T> = result::Result<T, HtsGetError>;

/// An enumeration with all the possible formats.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all(serialize = "UPPERCASE"))]
#[serde(rename_all(serialize = "UPPERCASE"), deny_unknown_fields)]
pub enum Format {
#[serde(alias = "bam", alias = "BAM")]
Bam,
Expand Down Expand Up @@ -112,7 +112,7 @@ impl Display for Format {

/// Class component of htsget response.
#[derive(Copy, Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(rename_all(serialize = "lowercase"))]
#[serde(rename_all(serialize = "lowercase"), deny_unknown_fields)]
pub enum Class {
#[serde(alias = "header", alias = "HEADER")]
Header,
Expand All @@ -123,6 +123,7 @@ pub enum Class {
/// An interval represents the start (0-based, inclusive) and end (0-based exclusive) ranges of the
/// query.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Interval {
start: Option<u32>,
end: Option<u32>,
Expand Down Expand Up @@ -205,7 +206,7 @@ impl Interval {

/// Schemes that can be used with htsget.
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
#[serde(rename_all = "UPPERCASE", deny_unknown_fields)]
pub enum Scheme {
#[default]
#[serde(alias = "Http", alias = "http")]
Expand All @@ -225,14 +226,15 @@ impl Display for Scheme {

/// Tagged Any allow type for cors config.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
pub enum TaggedTypeAll {
#[serde(alias = "all", alias = "ALL")]
All,
}

/// Possible values for the fields parameter.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
pub enum Fields {
/// Include all fields
Tagged(TaggedTypeAll),
Expand All @@ -242,7 +244,7 @@ pub enum Fields {

/// Possible values for the tags parameter.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
#[serde(untagged, deny_unknown_fields)]
pub enum Tags {
/// Include all tags
Tagged(TaggedTypeAll),
Expand All @@ -252,6 +254,7 @@ pub enum Tags {

/// The no tags parameter.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NoTags(pub Option<HashSet<String>>);

/// A struct containing the information from the HTTP request.
Expand Down Expand Up @@ -516,6 +519,7 @@ impl From<io::Error> for HtsGetError {

/// The headers that need to be supplied when requesting data from a url.
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Headers(HashMap<String, String>);

impl Headers {
Expand Down Expand Up @@ -585,6 +589,7 @@ impl TryFrom<&HeaderMap> for Headers {

/// A url from which raw data can be retrieved.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Url {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -635,6 +640,7 @@ impl Url {

/// Wrapped json response for htsget.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct JsonResponse {
pub htsget: Response,
}
Expand All @@ -654,6 +660,7 @@ impl From<Response> for JsonResponse {

/// The response for a HtsGet query.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Response {
pub format: Format,
pub urls: Vec<Url>,
Expand Down
Loading