Skip to content

Latest commit

 

History

History
415 lines (283 loc) · 11.4 KB

File metadata and controls

415 lines (283 loc) · 11.4 KB

Contributing to fz(ForgeZero)

The assembly swiss army knife — built with discipline, shipped with intent.

Thank you for considering a contribution to fz. This document establishes the standards and workflow expected of all contributors. Please read it in full before opening issues or submitting pull requests.


Table of Contents


Code of Conduct

All contributors are expected to engage professionally and constructively. Disrespectful, dismissive, or hostile behaviour will not be tolerated. We are here to build good software together.


Getting Started

Contributions are welcome in the following forms:

  • Bug reports — reproducible, well-documented issues filed via GitHub Issues
  • Feature proposals — opened as issues before any implementation begins
  • Pull requests — bug fixes, features, refactors, or documentation improvements
  • Documentation — corrections, clarifications, and examples

Before submitting

Run the following commands locally. If any of them fails, fix it before opening the PR:

go fmt ./...
go mod tidy
go test -race ./...
go vet ./...
staticcheck ./...

Development Setup

Prerequisites

Requirement Version
Go ≥ 1.21
NASM any recent
GCC + Binutils any recent
Clang (optional) for sanitizer tests

Clone

git clone https://github.com/forgezero-cli/ForgeZero.git
cd ForgeZero

Install system dependencies

# Required for assembly tests
sudo apt install nasm gcc binutils

# Optional: strict sanitizer tests
sudo apt install clang

Building and Testing

Build

go build -o fz ./cmd/fz

Run the full test suite

go test ./... -cover

Run with race detector (required before submitting a PR)

go test -race ./...

Static analysis

Install staticcheck if not already present:

go install honnef.co/go/tools/cmd/staticcheck@latest

Then run:

go vet ./...
staticcheck ./...

All checks must pass with zero warnings before a pull request is considered ready for review.


Code Standards

  • Formatting — run go fmt ./... before every commit; no exceptions

  • Functions — keep them small, focused, and with a single clear responsibility

  • Naming — use meaningful, unambiguous names; avoid abbreviations unless they are idiomatic in Go

  • Comments — omit comments where the code is self-explanatory; add them only where intent cannot be inferred from reading the code

  • Coverage — new code must not decrease the overall test coverage percentage

  • Error handling — every error must be handled explicitly; do not swallow errors silently

  • Tests must pass — no pull request will be reviewed if go test ./... fails

  • No debugging code — remove all fmt.Println, log.Print, or commented-out code before committing

  • No panic (except unrecoverable errors) — use error returns where possible

Mandatory Testing Requirements

Every pull request must include proof that all tests pass. No exceptions.

Required Test Commands

Run these commands before submitting your PR:

# Full test suite with race detection (MUST pass)
go test -race ./...

# Verbose output for clarity (MUST pass)
go test -v ./...

# Performance benchmarks (must not regress)
go test -bench=. -run=^$ ./...

If any of these commands fails, your PR will be rejected automatically.

Test Coverage for New Features

All new functionality must be placed in internal/ with the following structure:

internal/your_feature_name/
├── feature.go          # core logic
├── feature_test.go     # unit tests (MANDATORY)
└── ...                 # any auxiliary files

Rule: feature_test.go must exist. No tests = no merge.

Running Tests for a Specific Feature

# Run tests for a specific feature
go test -v ./internal/your_feature_name/...

# Run a specific test function by name
go test -v -run TestFunctionName ./internal/your_feature_name/...

or ./fz -alex

ForgeZero Test Runner (v4.8.0-dev)
────────────────────────────────────────────────────────────
  [✓] Environment Check (doctor) [PASS] (36 ms)
  [✓] Unit Tests (go test -race) [PASS] (8090 ms)
  [✓] Code Coverage [PASS] (2007 ms)
  [✓] Static Analysis (go vet) [PASS] (397 ms)
  [✓] Linter (staticcheck) [PASS] (0 ms)
  [✓] Code Formatting (go fmt) [PASS] (94 ms)
  [✓] Build Test (fz build) [PASS] (1468 ms)
  [✓] Gloria Compilation [PASS] (2 ms)
  [✓] HADES Codegen [PASS] (0 ms)
  [✓] Integration Tests [PASS] (178 ms)
  [✓] Citadel Zero-Allocations [PASS] (1748 ms)
  [✓] Race Detector (full) [PASS] (14345 ms)
  [✓] Aegis Audit [PASS] (131 ms)
────────────────────────────────────────────────────────────
STATUS: SUCCESS (13 stages passed, 28507 ms)

And if you add your new functional also make test in testrunner/

Naming Conventions (STRICT)

Functions

Every function name must clearly describe what it does.

BAD:

func v(s string)
func proc(d []byte)
func f() int

GOOD:

func PrintStringOnVGA(msg string) string
func ParseElfHeader(data []byte) (*ElfHeader, error)
func CalculateChecksum(buffer []byte) uint32

Variables

Use descriptive names. Single-letter variables are forbidden except for short loops.

BAD:

v := something...
x := process(d)
t := time.Now()

GOOD:

message := something...
result := process(data)
currentTime := time.Now()

Exception: Loop indices (i, j, k) are allowed for short, simple loops.

Packages / Feature Directories

BAD GOOD
internal/x internal/elf_parser
internal/utils internal/string_utils or internal/file_utils
internal/feature internal/watchdog

Zero Allocation Policy

ForgeZero targets performance-critical environments. Avoid allocations where possible.

Forbidden Patterns (if avoidable)

message := fmt.Sprintf("error: %s", err)

var buf bytes.Buffer
buf.WriteString(data)

tmp := []string{...}

Preferred Patterns

writeFmt(2, "error: %s\n", err)

buf := bytes.NewBuffer(make([]byte, 0, 4096))

var bufferPool = sync.Pool{
    New: func() interface{} { return make([]byte, 4096) },
}

Benchmarking Allocations

go test -bench=. -benchmem ./...

Look for 0 allocs/op in the output for performance-critical functions.

No Debug Prints

grep -r "fmt.Println\|fmt.Printf\|log.Print\|println(" internal/ cmd/ --include="*.go"

Allowed

  • writeFmt()
  • writeStderr()
  • Logging via -verbose

Forbidden

  • fmt.Println
  • log.Print (outside tests)
  • println()

PR Checklist (Copy This)

  • go test -race ./... passes
  • go test -v ./... passes
  • go test -bench=. -run=^$ ./... shows no regression
  • New features include _test.go
  • No single-letter variables (except loop indices)
  • No debug prints
  • go fmt ./... run
  • go vet ./... and staticcheck ./... clean

Attach test output to your PR.

Rules for External Contributors

To protect the project's long-term maintainability and code quality, the following rules apply:

  • No AI-generated code — code that is obviously machine-generated without human review will be rejected. We can tell.
  • Plagiarism is forbidden — copying code or documentation from other contributors (or from external sources) without attribution is grounds for immediate PR closure and a permanent ban.
  • You must build and test locally — if you cannot build fz on your machine, do not open a PR. Figure out the build process first.
  • No "drive-by" PRs — every PR must include tests and documentation (if applicable). Skeleton PRs without content will be closed.

Violations will be reported to GitHub if repeated.


Commit Convention

This project follows the Conventional Commits specification. All commit messages must conform to this format:

<type>: <short imperative summary>
Type When to use
feat A new user-facing feature
fix A bug fix
test Adding or improving tests
docs Documentation changes only
refactor Code restructuring without behaviour change
chore Tooling, CI, or dependency updates
perf Performance improvements

Examples:

feat: add --watch flag for incremental builds
fix: handle empty object files in linker stage
test: improve coverage for linker error paths
docs: document --output flag behaviour
refactor: extract runner into a standalone interface

Commit messages are part of the project's permanent history. Write them as if they will be read by someone debugging a regression two years from now — because they will be.


Pull Request Process

  1. Fork the repository and create a feature branch from main
  2. Write tests — all new behaviour must be covered; failure paths are not optional
  3. Verifygo test -race ./..., go vet ./..., and staticcheck ./... must all pass
  4. Update documentation — if your change affects behaviour visible to users, update the relevant docs
  5. Open the PR with a clear title (following commit convention) and a description that explains:
    • What changed
    • Why it was changed
    • Any relevant context or trade-offs

PRs that lack tests, break existing tests, or do not follow code standards will be returned for revision before review begins.


Proposing New Features

Open an issue before writing any code. This is not a bureaucratic step — it is a practical one. A brief discussion upfront saves everyone time by confirming the feature aligns with the project's direction before implementation begins.

A good feature proposal includes:

  • The problem being solved
  • The proposed solution or interface
  • Any known trade-offs or alternatives considered

Reporting Issues

When filing a bug report, include the following:

  • fz version — output of fz -version
  • Operating system and architecture — e.g. Linux amd64, macOS arm64
  • Steps to reproduce — minimal, complete, and unambiguous
  • Expected behaviour — what should have happened
  • Actual behaviour — what happened instead

Reports that cannot be reproduced from the information provided may be closed without action.


License

By submitting a contribution, you agree that your work will be licensed under the MIT License that covers this project.


Thank you for taking the time to contribute to fz.

(c) alexvoste