feat: open source vibecoding example project

This commit is contained in:
nobody 2025-09-28 11:20:25 -07:00
commit b370f462f2
Signed by: GrocerPublishAgent
GPG key ID: 43B1C298CDDE181C
34 changed files with 7744 additions and 0 deletions

View file

@ -0,0 +1,115 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use json_archive::{ArchiveReader, ReadMode};
use std::io::Write;
use tempfile::NamedTempFile;
fn create_archive_content(data: &[u8]) -> Vec<u8> {
// Start with a simple base archive
let base = r#"{"version":1,"created":"2025-01-01T00:00:00Z","initial":{"id":1}}
["observe", "obs-1", "2025-01-01T00:00:00Z", 1]
["add", "/name", "test", "obs-1"]"#;
let mut result = base.as_bytes().to_vec();
// Apply simple mutations based on fuzz input
if data.is_empty() {
return result;
}
// Keep mutations small and realistic
let max_size = 4096; // 4KB limit
for (i, &byte) in data.iter().take(16).enumerate() {
if result.len() > max_size {
break;
}
match byte % 8 {
0 => {
// Truncate at random position
let pos = (byte as usize) % result.len().max(1);
result.truncate(pos);
}
1 => {
// Insert invalid UTF-8
let pos = (byte as usize) % (result.len() + 1);
result.insert(pos, 0xFF);
}
2 => {
// Corrupt a quote
if let Some(pos) = result.iter().position(|&b| b == b'"') {
result[pos] = b'X';
}
}
3 => {
// Insert extra newline
let pos = (byte as usize) % (result.len() + 1);
result.insert(pos, b'\n');
}
4 => {
// Corrupt JSON bracket
if let Some(pos) = result.iter().position(|&b| b == b'[' || b == b'{') {
result[pos] = b'?';
}
}
5 => {
// Insert random byte
let pos = (byte as usize) % (result.len() + 1);
result.insert(pos, byte);
}
6 => {
// Remove a character
if !result.is_empty() {
let pos = (byte as usize) % result.len();
result.remove(pos);
}
}
_ => {
// Add some garbage line
let insertion = format!("\n[\"garbage\", {}]", i);
let pos = (byte as usize) % (result.len() + 1);
result.splice(pos..pos, insertion.bytes());
}
}
}
result
}
fuzz_target!(|data: &[u8]| {
let archive_content = create_archive_content(data);
if let Ok(mut temp_file) = NamedTempFile::new() {
if temp_file.write_all(&archive_content).is_ok() {
// Test both validation modes
for mode in [ReadMode::FullValidation, ReadMode::AppendSeek] {
if let Ok(reader) = ArchiveReader::new(temp_file.path(), mode) {
let result = reader.read(temp_file.path());
// Should never panic, regardless of input malformation
match result {
Ok(read_result) => {
// Basic invariants that should hold for any successful parse
let _ = &read_result.final_state;
let _ = &read_result.diagnostics;
// Observation count should be reasonable
assert!(read_result.observation_count < 100000);
// If we have diagnostics, they should be well-formed
for diagnostic in read_result.diagnostics.diagnostics() {
assert!(!diagnostic.description.is_empty());
}
},
Err(_) => {
// It's fine for the parser to reject malformed input
// Just make sure it doesn't panic
}
}
}
}
}
}
});

View file

@ -0,0 +1,22 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use json_archive::{ArchiveReader, ReadMode};
use std::io::Write;
use tempfile::NamedTempFile;
fuzz_target!(|data: &[u8]| {
// Write the random bytes to a temporary file
if let Ok(mut temp_file) = NamedTempFile::new() {
if temp_file.write_all(data).is_ok() {
// Try to read the file with both validation modes
for mode in [ReadMode::FullValidation, ReadMode::AppendSeek] {
if let Ok(reader) = ArchiveReader::new(temp_file.path(), mode) {
// The read operation should never panic, regardless of input
// It should either succeed or return an error gracefully
let _ = reader.read(temp_file.path());
}
}
}
}
});

View file

@ -0,0 +1,188 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use arbitrary::{Arbitrary, Unstructured};
use json_archive::{ArchiveReader, ReadMode};
use std::io::Write;
use tempfile::NamedTempFile;
use serde_json::{json, Value};
#[derive(Arbitrary, Debug)]
struct FuzzArchive {
header: FuzzHeader,
events: Vec<FuzzEvent>,
}
#[derive(Arbitrary, Debug)]
struct FuzzHeader {
has_type_field: bool,
has_version_field: bool,
has_created_field: bool,
has_initial_field: bool,
version_value: i32,
initial_state: FuzzValue,
}
#[derive(Arbitrary, Debug)]
enum FuzzEvent {
Observe {
id: String,
timestamp: String,
change_count: i32,
},
Add {
path: String,
value: FuzzValue,
obs_id: String,
},
Change {
path: String,
old_value: FuzzValue,
new_value: FuzzValue,
obs_id: String,
},
Remove {
path: String,
obs_id: String,
},
Move {
path: String,
moves: Vec<(i32, i32)>,
obs_id: String,
},
Snapshot {
id: String,
timestamp: String,
state: FuzzValue,
},
InvalidEvent {
event_type: String,
extra_fields: Vec<FuzzValue>,
},
}
#[derive(Arbitrary, Debug)]
enum FuzzValue {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<FuzzValue>),
Object(Vec<(String, FuzzValue)>),
}
impl FuzzValue {
fn to_json(&self) -> Value {
match self {
FuzzValue::Null => Value::Null,
FuzzValue::Bool(b) => Value::Bool(*b),
FuzzValue::Number(n) => json!(n),
FuzzValue::String(s) => Value::String(s.clone()),
FuzzValue::Array(arr) => {
Value::Array(arr.iter().map(|v| v.to_json()).collect())
}
FuzzValue::Object(obj) => {
let map: serde_json::Map<String, Value> = obj
.iter()
.map(|(k, v)| (k.clone(), v.to_json()))
.collect();
Value::Object(map)
}
}
}
}
impl FuzzArchive {
fn generate_archive(&self) -> String {
let mut lines = Vec::new();
// Generate potentially malformed header
let mut header_obj = serde_json::Map::new();
if self.header.has_type_field {
header_obj.insert("type".to_string(), json!("@peoplesgrocers/json-archive"));
}
if self.header.has_version_field {
header_obj.insert("version".to_string(), json!(self.header.version_value));
}
if self.header.has_created_field {
header_obj.insert("created".to_string(), json!("2025-01-01T00:00:00Z"));
}
if self.header.has_initial_field {
header_obj.insert("initial".to_string(), self.header.initial_state.to_json());
}
lines.push(serde_json::to_string(&Value::Object(header_obj)).unwrap());
// Generate events
for event in &self.events {
let event_json = match event {
FuzzEvent::Observe { id, timestamp, change_count } => {
json!(["observe", id, timestamp, change_count])
}
FuzzEvent::Add { path, value, obs_id } => {
json!(["add", path, value.to_json(), obs_id])
}
FuzzEvent::Change { path, old_value, new_value, obs_id } => {
json!(["change", path, old_value.to_json(), new_value.to_json(), obs_id])
}
FuzzEvent::Remove { path, obs_id } => {
json!(["remove", path, obs_id])
}
FuzzEvent::Move { path, moves, obs_id } => {
let move_array: Vec<Value> = moves
.iter()
.map(|(from, to)| json!([from, to]))
.collect();
json!(["move", path, move_array, obs_id])
}
FuzzEvent::Snapshot { id, timestamp, state } => {
json!(["snapshot", id, timestamp, state.to_json()])
}
FuzzEvent::InvalidEvent { event_type, extra_fields } => {
let mut arr = vec![json!(event_type)];
arr.extend(extra_fields.iter().map(|f| f.to_json()));
Value::Array(arr)
}
};
lines.push(serde_json::to_string(&event_json).unwrap());
}
lines.join("\n")
}
}
fuzz_target!(|data: &[u8]| {
let mut u = Unstructured::new(data);
if let Ok(archive) = FuzzArchive::arbitrary(&mut u) {
let content = archive.generate_archive();
if let Ok(mut temp_file) = NamedTempFile::new() {
if temp_file.write_all(content.as_bytes()).is_ok() {
// Test both validation modes
for mode in [ReadMode::FullValidation, ReadMode::AppendSeek] {
if let Ok(reader) = ArchiveReader::new(temp_file.path(), mode) {
let result = reader.read(temp_file.path());
// The operation should never panic
// Verify that diagnostics are properly generated for invalid structures
if let Ok(read_result) = result {
// Basic sanity checks on the result
assert!(read_result.observation_count < 10000); // Reasonable upper bound
// If there are fatal diagnostics, final state should be reasonable
if read_result.diagnostics.has_fatal() {
// Should still have some state (at least initial or null)
let _ = &read_result.final_state;
}
}
}
}
}
}
}
});