Skip to content
Open
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 src/en/01_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Rust ecosystem for secure development.
A following chapter focuses on precautions to take when choosing and using
external libraries.
Then, recommendations about the Rust language constructs are exposed.
<!-- TODO: Finally, we introduce advices for writing
tests for a project in Rust, and for using Rust fuzzing tools.-->
Finally, we introduce advices for writing
tests for a project in Rust<!-- TODO: and for using Rust fuzzing tools-->.
A summary of recommendations presented throughout the document is listed at the
end of this guide.
2 changes: 1 addition & 1 deletion src/en/02_devenv.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,4 @@ or change the program semantics in some case.
There exist other useful tools or `cargo` subcommands for enforcing program
security whether by searching for specific code patterns or by providing
convenient commands for testing or fuzzing. They are discussed in the following
chapters, according to their goals.
chapters, according to their goals.
27 changes: 19 additions & 8 deletions src/en/04_language.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ manipulations of memory pointers, the language provides the `unsafe` keyword.
> the crate root (typically `main.rs` or `lib.rs`) to generate compilation
> errors if `unsafe` is used in the code base.

> ### Information
>
>You can also obtain the same result by adding one of the two blocks below to the `Cargo.toml` file.

```toml
[lints.rust]
unsafe_code="forbid"
```

```toml
[lints.clippy]
unsafe_code = "forbid"
```
## Integer overflows

Although some verification is performed by Rust regarding potential integer
Expand Down Expand Up @@ -114,25 +127,23 @@ else { println!("{}", res); }
> specialized functions `overflowing_<op>`, `wrapping_<op>`, or the
> `Wrapping` type must be used.



## Error handling

<!-- <mark>TODO</mark>: explicit good practices in error handling. -->

The `Result` type is the preferred way of handling functions that can fail.
A `Result` object must be tested, and never ignored.

### Custom Error type implementation

> **Recommendation {{#check LANG-ERRWRAP | Implement custom `Error` type, wrapping all possible errors}}**
>
> A crate can implement its own `Error` type, wrapping all possible errors.
> It must be careful to make this type exception-safe (RFC 1236), and implement
> `Error + Send + Sync + 'static` as well as `Display`.

> **Recommendation {{#check LANG-ERRDO | Use the `?` operator and do not use the `try!` macro}}**
>
> The `?` operator should be used to improve readability of code.
> The `try!` macro should not be used.
To ensure that the above recommendation is implemented correctly, you may check
the [test implementing trait](08_testfuzz.md#implementing-a-trait) section of this guide.

### Third-party library use

Third-party crates may be used to facilitate error handling. Most of them
(notably [failure], [snafu], [thiserror]) address the creation of new custom
Expand Down
120 changes: 118 additions & 2 deletions src/en/08_testfuzz.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,126 @@

## Writing tests

<mark>TODO</mark>: good practices in writing tests.
Rust offers two types of test built in by default: internal tests and integration tests.
In this section, we will discuss these two types of test as well as a rather special type of test, which is the trait implementation test.

## Fuzzing
> Recommendation {{#check TEST-DRIVEN-DEV | Adopt a test-driven development's method}}
>
> One of the best development habits is to start development by writing the set of tests to which the functionality must respond.

### Internal

Internal tests define all the tests present in the `src/` folder of a Rust project. They have the great advantage of being able to test all the functions (even private ones) if they are placed in the same file as the project.


> ### Recommendation {{#check TEST-UNIT | Testing the critical path of your code}}
> It is important to test the entire critical path of your application.
>
> This way, if a future modification causes a side effect that alters its behavior, you will notice it much sooner.

```rust
// private function
fn my_function(){
... // Your code here
}

#[cfg(test)]
mod tests{
#[test]
fn test_my_function(){
... // Your tests here
}
}
```

> ### Recommendation {{#check TEST-IGNORE | Limit the number of ignored tests}}
>
> It is recommended to limit the number of tests that will be ignored as much as possible.

Rust has an attribute system that allows part of the code to be compiled only when necessary.
This makes it possible to define code that will only be compiled when a particular feature is requested.

One of the basic features of any project is `test`. This allows you to describe code which will only be present when the code is compiled for testing (via the `cargo test` command).

To do this, add the `#[cfg(test)]` attribute to the line above the function or module concerned:
```rust
#[cfg(test)]
mod test{

#[test]
fn test_1(){}
}
```

> ### Rules {{#check TEST-CFG | Wrap tests in a sub-module with the attribute `#[cfg(test)]`}}
>
> All internal tests must be wrapped in a sub-module with the `#[cfg(test)]` attribute. Similarly, any potential functions you may develop to help these tests must also have the `#[cfg(test)]` attribute.
>
> The use of a sub-module makes it possible to bring together all the tests and functions required for their proper execution. This makes it quick and easy to ensure that the code does not end up in the final binary or library and compromise the application's security.

### Integration

> Attention
>
> This type of test is only available for crates which are libraries.

The integration tests are the set of tests in the `tests/` folder at the root of the crate.
In this folder, each `*.rs` file will be compiled as a different crate and the library tested will be used as if an external project were using it.

For example, if we were developing a library called `example`, we could run the following integration test:
```rust
use example::method_name;

#[test]
fn test_api(){
method_name();
}
```

These tests are run at the same time as all the other tests using the following command:
```bash
cargo test
```

> ### Rule {{#check TEST-IMPL | Check that the public behavior of the API is as expected}}
>
> Integration tests must ensure that the library's behavior is as expected. These tests must cover all the solution's public functions (including the import of types, functions, enums, etc.).
>
> This also ensures that the API is user-friendly.

### Implementing a trait

The example below is used to create a test to ensure that a struct or enum implements a trait.

These tests are a little unusual. If positioned in a project, they can prevent the project from compiling if they are not valid.

Here is an example of code used to ensure that an enum has the Send and Sync traits:

```rust
enum Example {}

#[cfg(test)]
mod test{
use super::*;

fn send_sync_trait<T : Sendc + Sync>(){}

#[test]
fn test_traits_impl(){
send_sync_trait::<Exemple>();
}
}
```

> ### Recommendation {{#check TEST-TRAIT | Create tests to ensure that certain traits are implemented for structures/enums}}
>
> In certain situations, it is essential that certain struct or enum implement specific traits. This type of test is therefore highly recommended.
>
> One relevant scenario is where it is necessary to ensure that certain exposed API traits are correctly implemented. Another example, more related to the subject of this guide, concerns the validation of the implementation of the `std::hash::Hash` trait, which can be crucial in situations where data integrity is paramount.

<!-- ## Fuzzing

### cargo-fuzz

<mark>TODO</mark>: good practices in fuzzing programs or part of programs.
-->
5 changes: 2 additions & 3 deletions src/en/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
- [Memory management](05_memory.md)
- [Type system](06_typesystem.md)
- [Foreign Function Interface](07_ffi.md)
- [Test and fuzzing](08_testfuzz.md)

[Licence](LICENCE.md)

<!-- TODO - [Test and fuzzing](08_testfuzz.md) -->
[Licence](LICENCE.md)
4 changes: 2 additions & 2 deletions src/fr/01_introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,6 @@ nous proposons des recommandations concernant l'utilisation des outils de
l'écosystème Rust dans un cadre sécurisé. Ensuite, nous détaillons les
précautions à prendre durant le choix et l'utilisation de bibliothèques
externes. Ensuite, les recommandations à propos des constructions du langage
sont présentées. <!-- TODO: Enfin, nous discutons de la bonne utilisation des outils de
test et de *fuzzing* pour un projet réalisé en Rust.--> Un résumé des règles et
sont présentées. Enfin, nous discutons de la bonne utilisation des outils de
test <!-- TODO: et de *fuzzing*--> pour un projet réalisé en Rust. Un résumé des règles et
recommandations est disponible à la fin de ce guide.
4 changes: 1 addition & 3 deletions src/fr/02_devenv.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ $ rustup override list
$
```

<!-- -->

> **Règle {{#check DENV-STABLE | Utilisation de la chaîne d'outils *stable*}}**
>
> Le développement d'applications sécurisées doit être mené en utilisant la
Expand Down Expand Up @@ -284,4 +282,4 @@ la sémantique d'un programme dans certains cas.
D'autres outils ou sous-commandes `cargo` utiles pour renforcer la sécurité
d'un programme existent, par exemple, en recherchant des motifs de code
particuliers. Nous en discutons dans les chapitres suivants en fonction de leurs
portées et de leurs objectifs.
portées et de leurs objectifs.
24 changes: 20 additions & 4 deletions src/fr/04_language.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ langage fournit le mot-clé `unsafe`.
> afin de générer des erreurs de compilation dans le cas ou le mot-clé `unsafe`
> est utilisé dans le projet.

> ### Information
>
>Il est également possible d'obtenir le même résultat en rajoutant l'un des deux blocs ci-dessous au fichier `Cargo.toml`.

```toml
[lints.rust]
unsafe_code="forbid"
```

```toml
[lints.clippy]
unsafe_code = "forbid"
```
## Dépassement d'entiers

Bien que des vérifications soient effectuées par Rust en ce qui concerne les
Expand Down Expand Up @@ -124,26 +137,29 @@ else { println!("{}", res); }

## Gestion des erreurs

<!--
<mark>TODO</mark>: décrire les bonnes pratiques de gestion d'erreurs.
-->

Le type `Result` est la façon privilégiée en Rust pour décrire le type de retour
des fonctions dont le traitement peut échouer. Un objet `Result` doit être
testé et jamais ignoré.

### Implémentation d'un type d'Erreur personnalisé

> **Recommandation {{#check LANG-ERRWRAP | Mise en place d'un type `Error` personnalisé, pouvant contenir toutes les erreurs possibles}}**
>
> Une *crate* peut implanter son propre type `Error` qui peut contenir toutes
> les erreurs possibles. Des précautions supplémentaires doivent être prises :
> ce type doit être *exception-safe* (RFC 1236) et implémenter les traits
> `Error + Send + Sync + 'static` ainsi que `Display`.

Pour s'assurer que la recommandation ci-dessus soit bien implémenter, vous pouvez vous réferez à la section
concernant [les tests de bonnes implémentations](08_testfuzz.md#Implémentation-de-trait) des traits de ce guide.

> **Recommandation {{#check LANG-ERRDO | Utilisation de l'opérateur `?` et non-utilisation de la macro `try!`}}**
>
> L'opérateur `?` doit être utilisé pour améliorer la lisibilité du code.
> La macro `try!` ne doit pas être utilisée.

### Utilisation de bibliothèque tierce

Des *crates* tierces peuvent être utilisées pour faciliter la gestion d'erreurs.
La plupart ([failure], [snafu], [thiserror]) proposent la création de types
d'erreurs personnalisées qui implémentent les traits nécessaires et permettent
Expand Down
Loading