Development Standards for opnDossier¶
This document provides coding standards, development workflows, and technical guidelines for contributors to the opnDossier CLI tool. It focuses on practical development tasks, code quality, and maintainability. It complements the AI agent guidelines in AGENTS.md.
Table of Contents¶
- Development Environment Setup
- Code Quality Standards
- Testing Requirements
- Development Workflow
- Architecture Guidelines
- Security Standards
Development Environment Setup¶
Prerequisites¶
- Go 1.21.6+ (recommended: 1.24.5+)
- Git with conventional commit support
- Just task runner (
just --versionto verify) - Python 3.11+ (for documentation)
Initial Setup¶
# Clone and setup
git clone https://github.com/EvilBit-Labs/opnDossier.git
cd opnDossier
# Install dependencies and tools
just install
# Verify setup
just test
just lint
IDE Configuration¶
VS Code Extensions:
- Go extension (official)
- Pre-commit hooks
- YAML support
- Markdown preview
GoLand/IntelliJ:
- Enable
gofmton save - Configure
golangci-lintintegration - Set up run configurations for
justcommands
Environment Variables¶
# Development environment
export OPNDOSSIER_VERBOSE=true
# For testing
export OPNDOSSIER_TEST_MODE=true
Code Quality Standards¶
Technology Stack¶
| Component | Technology | Purpose |
|---|---|---|
| CLI Framework | cobra |
Command organization and help system |
| Configuration | spf13/viper |
Configuration management |
| CLI Enhancement | charmbracelet/fang |
Enhanced CLI experience |
| Terminal Styling | charmbracelet/lipgloss |
Colored output and styling |
| Markdown Rendering | charmbracelet/glamour |
Terminal markdown display |
| Logging | charmbracelet/log |
Structured logging |
| Data Processing | encoding/xml, encoding/json |
Standard library XML/JSON handling |
| Testing | Go's built-in testing package |
Table-driven tests with >80% coverage |
Code Style and Formatting¶
Required Tools:
gofmt- Code formatting (automatic)gofumpt- Enhanced formattinggolangci-lint- Comprehensive lintinggo vet- Static analysisgoimports- Import organizationgosec- Security scanning (via golangci-lint)
Conventions:
- Formatting: Use
gofmtwith default settings - Line Length: 80-120 characters (Go conventions)
- Indentation: Use tabs (Go standard)
- Naming:
- Packages:
snake_caseor single word, lowercase - Variables/functions:
camelCasefor private,PascalCasefor exported - Constants:
camelCasefor private,PascalCasefor exported (avoidALL_CAPS) - Types:
PascalCase - Interfaces:
PascalCase, ending with-erwhen appropriate - Receivers: Single-letter names (e.g.,
c *Config)
Error Handling Patterns¶
// Always check errors and provide context
func parseXMLConfig(filename string) (*Config, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read config file %s: %w", filename, err)
}
var config Config
if err := xml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse XML config: %w", err)
}
return &config, nil
}
// Use structured logging
logger := log.New(os.Stderr, "", log.LstdFlags)
logger.Info("processing config file", "filename", filename)
Commit Message Conventions¶
All commit messages MUST follow the Conventional Commits specification:
Format: <type>(<scope>): <description>
Types:
feat- New featuresfix- Bug fixesdocs- Documentation changesstyle- Code style changes (formatting, etc.)refactor- Code refactoringperf- Performance improvementstest- Adding or updating testsbuild- Build system changesci- CI/CD changeschore- Maintenance tasks
Scopes: (cli), (parser), (converter), (display), (config), (docs), etc.
Examples:
feat(cli): add support for custom config path
fix(parser): handle malformed XML gracefully
docs: update README with install instructions
perf(converter): optimize markdown generation
test(parser): add integration tests for XML parsing
Testing Requirements¶
Test Standards¶
Requirements:
- Coverage Target: >80% test coverage
- Test Organization: Table-driven tests with
t.Run()subtests - Performance: Individual tests \<100ms
- Integration Tests: Use build tags (
//go:build integration)
Test Structure¶
func TestParseXMLConfig(t *testing.T) {
tests := []struct {
name string
input string
expected *Config
wantErr bool
}{
{
name: "valid config",
input: `<config><system><hostname>test</hostname></system></config>`,
expected: &Config{System: System{Hostname: "test"}},
wantErr: false,
},
{
name: "invalid XML",
input: `<config><unclosed>`,
expected: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseXMLConfig(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("parseXMLConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(result, tt.expected) {
t.Errorf("parseXMLConfig() = %v, want %v", result, tt.expected)
}
})
}
}
Testing Commands¶
# Run all tests
just test
# Run with coverage
just coverage
# Run benchmarks
just bench
# Run memory benchmarks
just bench-memory
# Run race detection
go test -race ./...
Development Workflow¶
Daily Development Tasks¶
# Start development session
just dev --help # Test CLI functionality
just test # Run tests before making changes
just lint # Check code quality
# Make changes, then:
just format # Format code
just check # Run pre-commit checks
just test # Verify tests still pass
Adding New Features¶
- Create feature branch:
-
Implement feature:
-
Follow existing patterns in similar code
- Add tests for new functionality
-
Update documentation if needed
-
Quality checks:
- Commit changes:
Debugging¶
Common debugging scenarios:
# Debug CLI commands
just dev --verbose convert testdata/config.xml
# Debug with specific log level
OPNDOSSIER_VERBOSE=true just dev convert testdata/config.xml
# Profile performance
go test -bench=. -cpuprofile=cpu.prof ./internal/parser
go tool pprof cpu.prof
# Memory profiling
go test -bench=. -memprofile=mem.prof ./internal/parser
go tool pprof mem.prof
Debugging tips:
- Use
log.Debug()for temporary debugging output - Check
internal/log/for structured logging patterns - Use
go test -vfor verbose test output - Use
golangci-lint run --verbosefor detailed linting info
Performance Optimization¶
Benchmarking:
# Run benchmarks
just bench
# Compare benchmarks
go test -bench=. -benchmem ./internal/parser > old.txt
# Make changes
go test -bench=. -benchmem ./internal/parser > new.txt
benchcmp old.txt new.txt
Profiling:
# CPU profiling
go test -cpuprofile=cpu.prof -bench=. ./internal/parser
go tool pprof cpu.prof
# Memory profiling
go test -memprofile=mem.prof -bench=. ./internal/parser
go tool pprof mem.prof
Architecture Guidelines¶
Project Structure¶
opnDossier/
├── main.go # Application entry point
├── cmd/ # CLI commands
│ ├── root.go # Root command and CLI setup
│ ├── convert.go # Convert command implementation
│ ├── display.go # Display command implementation
│ ├── validate.go # Validate command implementation
│ └── *_test.go # Command tests
├── internal/ # Private application logic
│ ├── config/ # Configuration handling
│ ├── parser/ # XML parsing logic
│ ├── converter/ # Data conversion logic
│ ├── display/ # Output formatting
│ ├── export/ # File export logic
│ ├── processor/ # Configuration processing pipeline
│ ├── markdown/ # Markdown generation
│ ├── model/ # Data models
│ ├── validator/ # Validation logic
│ ├── log/ # Structured logging
│ ├── metrics/ # Performance metrics
│ ├── walker.go # XML walker utilities
│ └── *_test.go # Package tests
├── docs/ # Documentation
├── project_spec/ # Project requirements
├── testdata/ # Test data files
└── justfile # Task runner
Key Design Principles¶
- Framework-First: Use established libraries (cobra, viper, charmbracelet)
- Operator-Centric: Build for security operators' workflows
- Offline-First: No external dependencies or telemetry
- Structured Data: Versioned, portable data models
Configuration Management¶
// Using spf13/viper for configuration
type Config struct {
InputFile string `flag:"input" desc:"Input XML file path"`
OutputFile string `flag:"output" desc:"Output markdown file path"`
Verbose bool `flag:"verbose" desc:"Enable verbose output"`
}
// Configuration precedence: CLI flags > environment variables > config file > defaults
Error Handling¶
- Always wrap errors with context using
fmt.Errorfwith%w - Create domain-specific error types for better error handling
- Use
errors.Is()anderrors.As()for error type checking - Provide actionable error messages for users
Logging¶
- Use
charmbracelet/logfor structured logging - Include context in log messages (filename, operation, duration)
- Use appropriate log levels (debug, info, warn, error)
- Avoid logging sensitive information
Security Standards¶
General Security Principles¶
- No Secrets in Code: Never hardcode API keys, passwords, or sensitive data
- Environment Variables: Use environment variables with
OPNDOSSIER_prefix for configuration - Input Validation: Always validate and sanitize XML input files
- Secure Defaults: Default to secure configurations
- Error Messages: Avoid exposing sensitive information in error messages
Go-Specific Security¶
Input Validation:
// Validate XML input before processing
func validateXMLInput(data []byte) error {
if len(data) == 0 {
return errors.New("empty XML input")
}
// Check for basic XML structure
if !bytes.Contains(data, []byte("<?xml")) && !bytes.Contains(data, []byte("<opnsense")) {
return errors.New("invalid XML format: missing XML declaration or opnsense root")
}
return nil
}
Error Handling:
// Safe error messages without sensitive information
func processConfig(filename string) error {
data, err := os.ReadFile(filename)
if err != nil {
// Don't expose full file paths in error messages
return fmt.Errorf("failed to read configuration file: %w", err)
}
// Process data...
return nil
}
Operational Security¶
- Airgap Compatibility: Full functionality in isolated environments
- No Telemetry: No external data transmission
- Portable Data Exchange: Secure data bundle import/export
- Error Message Safety: No sensitive information exposure
Dependency Security¶
- Minimal Dependencies: Reduced attack surface, except for cryptography dependencies - never write your own crypto code
- Dependency Scanning: Automated vulnerability detection via
gosec - Supply Chain Security: Go module checksums and verification
- SBOM Generation: Dependency transparency for security compliance
This document serves as the development standards guide for the opnDossier CLI tool. All contributors should follow these standards to ensure code quality, maintainability, and security.