Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a572304
docs(agents): update AGENTS.md to reflect implemented features and fu…
unclesp1d3r Feb 15, 2026
11dfbc2
docs(agents): fix inaccurate feature claims in AGENTS.md
unclesp1d3r Feb 15, 2026
72c37d0
docs(readme): update README.md with project badges for visibility
unclesp1d3r Feb 15, 2026
e6a1e16
ci: pin all GitHub Actions to SHA hashes for supply chain security
unclesp1d3r Feb 15, 2026
2873df7
ci: revert SHA pins in release.yml (managed by cargo-dist)
unclesp1d3r Feb 15, 2026
0cfab47
chore: add git-cliff changelog generation and simplify justfile
unclesp1d3r Feb 15, 2026
c6c7d08
docs: improve SECURITY.md with scope, safe harbor, and responsible di…
unclesp1d3r Feb 15, 2026
df339a2
docs: add PGP key for encrypted vulnerability reporting
unclesp1d3r Feb 15, 2026
33c6440
docs: use support@evilbitlabs.io for security contact to match PGP key
unclesp1d3r Feb 15, 2026
44c13cd
chore: commit Cargo.lock for reproducible binary builds
unclesp1d3r Feb 15, 2026
277ee65
chore: commit mise.lock for reproducible dev tool versions
unclesp1d3r Feb 15, 2026
3e075f3
docs: add code review requirements to AGENTS.md and CONTRIBUTING.md
unclesp1d3r Feb 15, 2026
06e06d8
chore: add SPDX license and copyright headers to all source files
unclesp1d3r Feb 15, 2026
62619a0
docs: add quick reference and OSSF quality standards to CLAUDE.md
unclesp1d3r Feb 15, 2026
329e912
docs: add DCO requirement to CONTRIBUTING.md
unclesp1d3r Feb 15, 2026
e5f8447
docs: add project governance model and update development guide
unclesp1d3r Feb 15, 2026
ac43bec
docs: update roadmap to match milestones and add non-goals
unclesp1d3r Feb 15, 2026
217e02d
docs: add release verification guide for signed artifacts
unclesp1d3r Feb 15, 2026
70b6ad5
docs: add security assurance case for OSSF gold criteria
unclesp1d3r Feb 15, 2026
6c4af63
docs(readme): add OpenSSF Best Practices badge
unclesp1d3r Feb 15, 2026
0840a88
docs: move OSSF standards from CLAUDE.md to AGENTS.md
unclesp1d3r Feb 15, 2026
f9068bd
docs: extract roadmap into ROADMAP.md to keep README concise
unclesp1d3r Feb 15, 2026
65cf086
docs: add project-level Claude Code skills for Rust development
unclesp1d3r Feb 15, 2026
1ff3204
chore: add Claude Code hook to enforce DCO sign-off on commits
unclesp1d3r Feb 15, 2026
82044ef
chore: add hookify rules for Rust code safety warnings
unclesp1d3r Feb 15, 2026
a3af8ea
fix: address Copilot PR review comments
unclesp1d3r Feb 15, 2026
ec9c740
fix: use portable grep pattern in DCO sign-off hook
unclesp1d3r Feb 15, 2026
b5fbfb7
docs: expand Cargo.lock rationale in .gitignore
unclesp1d3r Feb 15, 2026
fc86862
fix: address additional Copilot review comments
unclesp1d3r Feb 15, 2026
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
21 changes: 21 additions & 0 deletions .claude/hookify.warn-direct-string-slice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: warn-direct-string-slice
enabled: true
event: file
conditions:
- field: new_text
operator: regex_match
pattern: "&\\w+\\[\\d+\\.\\.\\]|&\\w+\\[\\.\\.\\d+\\]|&\\w+\\[\\d+\\.\\.]"
---

**Direct string slicing detected.**

Use `strip_prefix()` / `strip_suffix()` instead of `&str[n..]` to avoid UTF-8 boundary panics.

```rust
// Wrong: can panic on non-ASCII
let rest = &input[2..];

// Correct: safe
let rest = input.strip_prefix("0x").unwrap_or(input);
```
17 changes: 17 additions & 0 deletions .claude/hookify.warn-emoji-in-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: warn-emoji-in-code
enabled: true
event: file
conditions:
- field: new_text
operator: regex_match
pattern: "[\U0001F300-\U0001F9FF\u2600-\u26FF\u2700-\u27BF\U0001FA00-\U0001FA6F\U0001FA70-\U0001FAFF]"
---

**Emoji detected in code or documentation.**

Project guidelines prohibit emojis and non-ASCII characters in code, comments, and documentation.

**Exception:** If this code is specifically handling or processing emoji/non-ASCII characters (e.g., test cases for Unicode handling), this warning can be disregarded.

If this is not emoji-processing code, remove the emoji and use plain text instead.
26 changes: 26 additions & 0 deletions .claude/hookify.warn-panic-in-lib.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
name: warn-panic-in-lib
enabled: true
event: file
conditions:
- field: file_path
operator: regex_match
pattern: src/.*\.rs$
- field: new_text
operator: regex_match
pattern: \.unwrap\(\)|\.expect\(|panic!\(
---

**Potential panic in library code detected.**

This project uses `unwrap_used = "deny"` and `panic = "deny"` in clippy config. Use `Result<T, E>` patterns instead.

```rust
// Wrong: panics at runtime
let val = something.unwrap();

// Correct: propagate error
let val = something.ok_or(MagicError::InvalidValue)?;
```

Note: `.unwrap()` is acceptable inside `#[cfg(test)]` modules.
15 changes: 15 additions & 0 deletions .claude/hookify.warn-unsafe-code.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: warn-unsafe-code
enabled: true
event: file
conditions:
- field: new_text
operator: regex_match
pattern: unsafe\s*\{|unsafe\s+fn|unsafe\s+impl
---

**Unsafe code detected.**

This project enforces `#![forbid(unsafe_code)]` project-wide. No unsafe blocks, functions, or impls are permitted in project source code.

If you believe unsafe is absolutely necessary, stop and discuss with the user before proceeding.
17 changes: 17 additions & 0 deletions .claude/hooks/enforce-dco-signoff.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Claude Code PreToolUse hook: ensure all git commits include DCO sign-off (-s)

CMD="${CLAUDE_TOOL_INPUT_command:-}"

# Only check commands that contain "git commit" as a distinct subcommand
if ! echo "$CMD" | grep -qE '(^|[;&|] *)git commit( |$)'; then
exit 0
fi

# Allow if -s or --signoff is present anywhere in the command
if echo "$CMD" | grep -qE -- '(^| )-s( |$)|(^| )--signoff( |$)'; then
exit 0
fi

echo "BLOCK: All commits must include DCO sign-off. Add the -s flag to your git commit command."
exit 2
15 changes: 15 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/enforce-dco-signoff.sh"
}
]
}
]
}
}
226 changes: 226 additions & 0 deletions .claude/skills/api-design/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
---
name: api-design
description: Rust library API design patterns including builder pattern, error handling, trait design, type safety, and CLI design with clap.
---

# API Design Patterns (Rust Library & CLI)

## When to Activate

- Designing or modifying public library API in `lib.rs`
- Adding new public types, traits, or functions
- Reviewing API ergonomics and consistency
- Designing CLI arguments and output formats
- Planning breaking vs non-breaking changes

## Library API Design

### Builder Pattern
```rust
// For types with many optional configuration fields
pub struct EvaluationConfig {
timeout: Duration,
max_rules: usize,
follow_symlinks: bool,
}

impl EvaluationConfig {
pub fn builder() -> EvaluationConfigBuilder {
EvaluationConfigBuilder::default()
}
}

pub struct EvaluationConfigBuilder { /* ... */ }

impl EvaluationConfigBuilder {
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}

pub fn build(self) -> Result<EvaluationConfig, ConfigError> {
// Validate configuration
Ok(EvaluationConfig { /* ... */ })
}
}
```

### Error Design

#### Three-Tier Error Hierarchy
```rust
// Top-level: user-facing errors
pub enum LibmagicError {
Parse(ParseError),
Evaluation(EvaluationError),
Config(ConfigError),
Io(std::io::Error),
}

// Module-level: specific to subsystem
pub enum ParseError {
InvalidSyntax { line: usize, reason: String },
IoError(String),
}

// Always implement std::error::Error + Display
impl std::fmt::Display for LibmagicError { /* ... */ }
impl std::error::Error for LibmagicError { /* ... */ }
```

#### Error Guidelines
- Use `thiserror` for deriving Error implementations
- Errors should be actionable (include line numbers, context)
- Never expose internal paths or system details in public errors
- Implement `From` conversions for ergonomic `?` usage

### Type Safety

#### Newtype Pattern
```rust
// Wrap primitives to prevent misuse
pub struct Offset(i64);
pub struct Score(u32);
pub struct Level(u32);

// Prevents accidentally passing a score where an offset is expected
fn evaluate_at(offset: Offset, buffer: &[u8]) -> Result<Score, EvaluationError>;
```

#### Enum-Based Type Discrimination
```rust
// Use enums to make invalid states unrepresentable
pub enum OffsetSpec {
Absolute(i64),
Indirect { base: i64, pointer_type: TypeKind },
Relative(i64),
FromEnd(i64),
}
// Cannot have both Absolute and Relative -- the type system prevents it
```

### Public API Surface

#### Minimize Exposure
```rust
// Only expose what users need
pub use crate::evaluator::EvaluationResult;
pub use crate::parser::MagicRule;

// Keep internals private
pub(crate) use crate::evaluator::EvaluationContext;
```

#### Document Everything Public
```rust
/// Evaluate magic rules against a file buffer.
///
/// # Arguments
/// * `rules` - Parsed magic rules to evaluate
/// * `buffer` - File contents to identify
///
/// # Returns
/// The best matching result, or `None` if no rules match.
///
/// # Errors
/// Returns `EvaluationError` if evaluation fails due to
/// invalid offsets or corrupted rule definitions.
///
/// # Examples
/// ```
/// use libmagic_rs::MagicDatabase;
///
/// let db = MagicDatabase::default();
/// let result = db.evaluate_buffer(&[0x7f, 0x45, 0x4c, 0x46])?;
/// ```
pub fn evaluate_buffer(&self, buffer: &[u8]) -> Result<Option<EvaluationResult>, EvaluationError>;
```

### Trait Design
```rust
// Small, focused traits
pub trait SafeBufferAccess {
fn get_byte(&self, offset: usize) -> Option<u8>;
fn get_slice(&self, offset: usize, len: usize) -> Option<&[u8]>;
fn len(&self) -> usize;
}

// Implement for multiple types
impl SafeBufferAccess for FileBuffer { /* ... */ }
impl SafeBufferAccess for &[u8] { /* ... */ }
```

## CLI Design (clap)

### Argument Structure
```rust
#[derive(Parser)]
#[command(name = "rmagic", about = "Identify file types")]
struct Args {
/// Files to identify
#[arg(required = true)]
files: Vec<PathBuf>,

/// Output as JSON
#[arg(long)]
json: bool,

/// Use custom magic file
#[arg(long, value_name = "FILE")]
magic_file: Option<PathBuf>,
}
```

### CLI Conventions
- Follow GNU `file` command conventions where possible
- Short flags for common options (`-j` for JSON)
- Long flags for all options (`--json`)
- Positional arguments for files
- `--` to separate flags from file arguments
- Exit code 0 for success, 1 for errors

### Output Format Consistency
- Text output: `filename: description` (matches GNU `file`)
- JSON output: structured with `filename`, `matches`, `metadata`
- Errors to stderr, results to stdout
- Quiet mode suppresses non-essential output

## API Evolution

### Non-Breaking Changes (patch/minor version)
- Adding new enum variants (if `#[non_exhaustive]`)
- Adding new optional fields to builders
- Adding new methods to existing types
- Loosening input constraints

### Breaking Changes (major version)
- Removing or renaming public types/functions
- Changing function signatures
- Adding required fields to structs
- Tightening input constraints
- Changing error types

### Defensive Techniques
```rust
// Mark enums as non-exhaustive for future extension
#[non_exhaustive]
pub enum TypeKind {
Byte,
Short { endian: Endianness, signed: bool },
Long { endian: Endianness, signed: bool },
String { max_length: Option<usize> },
// Future: Quad, Float, Regex, etc.
}
```

## API Review Checklist

Before exposing new public API:
- [ ] All public items have rustdoc with examples
- [ ] Error types are descriptive and actionable
- [ ] Builder pattern used for types with >3 optional fields
- [ ] Types prevent invalid states at compile time
- [ ] `#[non_exhaustive]` on enums that may grow
- [ ] Consistent naming with existing API surface
- [ ] `From`/`Into` conversions for ergonomic use
- [ ] `Display` and `Debug` implemented for all public types
Loading
Loading