Skip to content

Commit 66546e6

Browse files
authored
Merge pull request hashcat#4531 from pwrbob/feat/rust-tests
Add a github action to run checks and tests for Rust code
2 parents 03c19f5 + 3b7d58c commit 66546e6

9 files changed

Lines changed: 205 additions & 53 deletions

File tree

.github/workflows/rust.yml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
name: Rust tests
2+
3+
env:
4+
RUSTFLAGS: -Dwarnings
5+
RUST_BACKTRACE: 1
6+
RUSTUP_WINDOWS_PATH_ADD_BIN: 1
7+
# Change to specific Rust release to pin
8+
rust_stable: stable
9+
rust_nightly: nightly-2025-01-25
10+
rust_edition: '2021'
11+
rust_clippy: '1.88'
12+
rust_min: '1.88'
13+
14+
on:
15+
push:
16+
branches:
17+
- "master"
18+
tags:
19+
- v*
20+
paths:
21+
- 'Rust/**'
22+
- '.github/workflows/rust.yml'
23+
pull_request:
24+
branches:
25+
- master
26+
paths:
27+
- 'Rust/**'
28+
- '.github/workflows/rust.yml'
29+
30+
jobs:
31+
# Basic actions that must pass before we kick off more expensive tests.
32+
basics:
33+
name: basic checks
34+
runs-on: ubuntu-latest
35+
needs:
36+
- fmt
37+
- minrust
38+
steps:
39+
- run: exit 0
40+
41+
# enforce standard Rust formating (rustfmt)
42+
fmt:
43+
name: fmt
44+
runs-on: ubuntu-latest
45+
steps:
46+
- uses: actions/checkout@v5
47+
- name: Install Rust ${{ env.rust_stable }}
48+
uses: dtolnay/rust-toolchain@stable
49+
with:
50+
toolchain: ${{ env.rust_stable }}
51+
components: rustfmt
52+
# Check fmt
53+
- name: "rustfmt --check"
54+
# Workaround for rust-lang/cargo#7732
55+
run: |
56+
if ! rustfmt --check --edition ${{ env.rust_edition }} $(git ls-files '*.rs'); then
57+
printf "Please run \`rustfmt --edition ${{ env.rust_edition }} \$(git ls-files '*.rs')\` to fix rustfmt errors.\nSee CONTRIBUTING.md for more details.\n" >&2
58+
exit 1
59+
fi
60+
61+
minrust:
62+
name: minrust
63+
runs-on: ubuntu-latest
64+
steps:
65+
- uses: actions/checkout@v5
66+
- name: Install Rust ${{ env.rust_min }}
67+
uses: dtolnay/rust-toolchain@stable
68+
with:
69+
toolchain: ${{ env.rust_min }}
70+
- name: "cargo check hashcat-sys"
71+
run: cargo check
72+
working-directory: Rust/hashcat-sys
73+
- name: "cargo check bridges"
74+
run: |
75+
for b in `ls`; do
76+
cd ${b}
77+
cargo check
78+
cd ..
79+
done
80+
working-directory: Rust/bridges
81+
- name: "cargo check feeds"
82+
run: |
83+
for b in `ls`; do
84+
cd ${b}
85+
cargo check
86+
cd ..
87+
done
88+
working-directory: Rust/feeds
89+
90+
# test all rust code
91+
test-rust:
92+
needs: basics
93+
name: test all Rust crates
94+
runs-on: ${{ matrix.os }}
95+
strategy:
96+
matrix:
97+
os:
98+
- ubuntu-latest
99+
- macos-latest
100+
# - windows-latest
101+
steps:
102+
- uses: actions/checkout@v5
103+
- name: Install Rust ${{ env.rust_stable }}
104+
uses: dtolnay/rust-toolchain@stable
105+
with:
106+
toolchain: ${{ env.rust_stable }}
107+
- name: test hashcat-sys
108+
run: cargo test
109+
working-directory: Rust/hashcat-sys
110+
- name: test all bridges
111+
run: |
112+
set -euxo pipefail
113+
for b in `ls`; do
114+
cd ${b}
115+
cargo test
116+
cd ..
117+
done
118+
working-directory: Rust/bridges
119+
- name: test all feeds
120+
run: |
121+
set -euxo pipefail
122+
for b in `ls`; do
123+
cd ${b}
124+
cargo test
125+
cd ..
126+
done
127+
working-directory: Rust/feeds

Rust/bridges/dynamic_hash/src/eval.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::collections::HashMap;
66

77
use crate::{DataDecoder, Expr, ExtraParams, OutputFormat};
88

9-
use base64::{Engine, prelude::BASE64_STANDARD};
9+
use base64::{prelude::BASE64_STANDARD, Engine};
1010
use hmac::{Hmac, Mac};
1111
use md2::Md2;
1212
use md4::Md4;

Rust/bridges/dynamic_hash/src/interop.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ use std::{
1313

1414
use hashcat_sys::{bridge_context_t, generic_io_t, generic_io_tmp_t, salt_t};
1515

16-
use crate::Expr;
17-
use crate::{eval::EvalContext, parse};
16+
use crate::{eval::EvalContext, parse, Expr};
1817

1918
thread_local! {
2019
static AST: OnceCell<Expr> = OnceCell::new();

Rust/bridges/dynamic_hash/src/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Author......: See docs/credits.txt
33
* License.....: MIT
44
*/
5-
use base64::{Engine, prelude::BASE64_STANDARD};
5+
use base64::{prelude::BASE64_STANDARD, Engine};
66
use std::fmt;
77

88
use crate::{DataDecoder, Expr, ExtraParams, OutputFormat};

Rust/bridges/generic_hash/Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rust/bridges/generic_hash/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
* Author......: See docs/credits.txt
33
* License.....: MIT
44
*/
5-
65
mod generic_hash;
76
mod interop;

Rust/feeds/dummy/src/lib.rs

Lines changed: 62 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,82 +6,97 @@ pub static GENERIC_PLUGIN_OPTIONS: u32 = 0;
66
#[unsafe(no_mangle)]
77
pub static GENERIC_PLUGIN_VERSION: u32 = 712;
88

9-
#[repr (C)]
10-
pub struct generic_global_ctx_t
11-
{
12-
pub quiet: bool,
9+
#[repr(C)]
10+
pub struct generic_global_ctx_t {
11+
pub quiet: bool,
1312

14-
pub workc: i32,
15-
pub workv: *mut *mut c_char,
13+
pub workc: i32,
14+
pub workv: *mut *mut c_char,
1615

17-
pub profile_dir: *mut c_char,
18-
pub cache_dir: *mut c_char,
16+
pub profile_dir: *mut c_char,
17+
pub cache_dir: *mut c_char,
1918

20-
pub error: bool,
21-
pub error_msg: [c_char; 256],
19+
pub error: bool,
20+
pub error_msg: [c_char; 256],
2221

23-
pub gbldata: *mut c_void,
22+
pub gbldata: *mut c_void,
2423
}
2524

26-
#[repr (C)]
27-
pub struct generic_thread_ctx_t
28-
{
29-
pub thrdata: *mut c_void,
25+
#[repr(C)]
26+
pub struct generic_thread_ctx_t {
27+
pub thrdata: *mut c_void,
3028
}
3129

3230
#[unsafe(no_mangle)]
33-
pub extern "C" fn global_init (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut *mut generic_thread_ctx_t, _hashcat_ctx: *mut c_void) -> bool
34-
{
35-
true
31+
pub extern "C" fn global_init(
32+
_global_ctx: *mut generic_global_ctx_t,
33+
_thread_ctx: *mut *mut generic_thread_ctx_t,
34+
_hashcat_ctx: *mut c_void,
35+
) -> bool {
36+
true
3637
}
3738

3839
#[unsafe(no_mangle)]
39-
pub extern "C" fn global_term (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut *mut generic_thread_ctx_t, _hashcat_ctx: *mut c_void)
40-
{
40+
pub extern "C" fn global_term(
41+
_global_ctx: *mut generic_global_ctx_t,
42+
_thread_ctx: *mut *mut generic_thread_ctx_t,
43+
_hashcat_ctx: *mut c_void,
44+
) {
4145
}
4246

4347
#[unsafe(no_mangle)]
44-
pub extern "C" fn global_keyspace (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut *mut generic_thread_ctx_t, _hashcat_ctx: *mut c_void) -> u64
45-
{
46-
0xffff_ffff_ffff_ffff
48+
pub extern "C" fn global_keyspace(
49+
_global_ctx: *mut generic_global_ctx_t,
50+
_thread_ctx: *mut *mut generic_thread_ctx_t,
51+
_hashcat_ctx: *mut c_void,
52+
) -> u64 {
53+
0xffff_ffff_ffff_ffff
4754
}
4855

4956
#[unsafe(no_mangle)]
50-
pub extern "C" fn thread_init (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut generic_thread_ctx_t) -> bool
51-
{
52-
unsafe
53-
{
54-
let buf: Box<[u8; 256]> = Box::new ([0; 256]);
57+
pub extern "C" fn thread_init(
58+
_global_ctx: *mut generic_global_ctx_t,
59+
_thread_ctx: *mut generic_thread_ctx_t,
60+
) -> bool {
61+
unsafe {
62+
let buf: Box<[u8; 256]> = Box::new([0; 256]);
5563

56-
(*_thread_ctx).thrdata = Box::into_raw (buf) as *mut c_void;
57-
}
64+
(*_thread_ctx).thrdata = Box::into_raw(buf) as *mut c_void;
65+
}
5866

59-
true
67+
true
6068
}
6169

6270
#[unsafe(no_mangle)]
63-
pub extern "C" fn thread_term (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut generic_thread_ctx_t)
64-
{
65-
unsafe
66-
{
67-
let ptr = (*_thread_ctx).thrdata as *mut [u8; 256];
71+
pub extern "C" fn thread_term(
72+
_global_ctx: *mut generic_global_ctx_t,
73+
_thread_ctx: *mut generic_thread_ctx_t,
74+
) {
75+
unsafe {
76+
let ptr = (*_thread_ctx).thrdata as *mut [u8; 256];
6877

69-
let _ = Box::from_raw (ptr);
78+
let _ = Box::from_raw(ptr);
7079

71-
(*_thread_ctx).thrdata = std::ptr::null_mut ();
72-
}
80+
(*_thread_ctx).thrdata = std::ptr::null_mut();
81+
}
7382
}
7483

7584
#[unsafe(no_mangle)]
76-
pub extern "C" fn thread_seek (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut generic_thread_ctx_t, _offset: u64) -> bool
77-
{
78-
true
85+
pub extern "C" fn thread_seek(
86+
_global_ctx: *mut generic_global_ctx_t,
87+
_thread_ctx: *mut generic_thread_ctx_t,
88+
_offset: u64,
89+
) -> bool {
90+
true
7991
}
8092

8193
#[unsafe(no_mangle)]
82-
pub extern "C" fn thread_next (_global_ctx: *mut generic_global_ctx_t, _thread_ctx: *mut generic_thread_ctx_t, out_buf: *mut u8) -> c_int
83-
{
84-
unsafe { std::ptr::copy_nonoverlapping(b"Password1".as_ptr(), out_buf, 9) }
85-
86-
9
94+
pub extern "C" fn thread_next(
95+
_global_ctx: *mut generic_global_ctx_t,
96+
_thread_ctx: *mut generic_thread_ctx_t,
97+
out_buf: *mut u8,
98+
) -> c_int {
99+
unsafe { std::ptr::copy_nonoverlapping(b"Password1".as_ptr(), out_buf, 9) }
100+
101+
9
87102
}

Rust/hashcat-sys/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44
non_snake_case,
55
non_upper_case_globals
66
)]
7+
#[rustfmt::skip]
78
pub mod bindings;
89

910
pub use bindings::*;
11+
12+
#[cfg(test)]
13+
mod test {
14+
use super::*;
15+
16+
/// test that bindings.rs exists by asserting some very basic things
17+
#[test]
18+
fn test_bindings_exists() {
19+
assert_eq!(bindings::INT8_MIN, -128);
20+
}
21+
}

src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ clean:
575575
$(RM) -rf kernels
576576
$(RM) -rf Rust/bridges/*/target
577577
$(RM) -rf Rust/feeds/*/target
578+
$(RM) -rf Rust/hashcat-sys/src/bindings.rs
578579

579580
.PHONY: distclean
580581
distclean: clean

0 commit comments

Comments
 (0)