-
Notifications
You must be signed in to change notification settings - Fork 2
Contributing
Thank you for your interest in contributing to TMI (Threat Modeling Improved)! This guide will help you understand the contribution process, code standards, and best practices.
- Getting Started
- Development Workflow
- Code Standards
- Testing Requirements
- Pull Request Process
- Code Review Guidelines
- Community Guidelines
- AI-Assisted Development
-
Read the documentation
-
Set up your development environment
# Fork and clone repository git clone https://github.com/YOUR_USERNAME/tmi.git cd tmi # Add upstream remote git remote add upstream https://github.com/ericfitz/tmi.git # Start development environment make start-dev
For the web app:
git clone https://github.com/YOUR_USERNAME/tmi-ux.git cd tmi-ux git remote add upstream https://github.com/ericfitz/tmi-ux.git pnpm install pnpm run dev -
Find something to work on
We welcome various types of contributions:
- Bug Fixes - Fix reported bugs or issues you find
- New Features - Add new functionality
- Documentation - Improve or add documentation
- Tests - Add or improve test coverage
- Performance - Optimize existing code
- Refactoring - Improve code quality
- Examples - Add usage examples or tutorials
# Update your fork
git fetch upstream
git checkout main
git merge upstream/main
# Create feature branch
git checkout -b feature/your-feature-name
# Or for bug fixes
git checkout -b fix/bug-descriptionFollow these guidelines:
# Make your changes
vim api/your_file.go
# Run linter
make lint
# Run unit tests
make test-unit
# Run integration tests
make test-integration
# Build server
make build-servercd tmi-ux
# Make your changes
vim src/app/your-component.ts
# Run linter (ESLint with auto-fix)
pnpm run lint
# Run all linters (ESLint + Stylelint for SCSS)
pnpm run lint:all
# Run unit tests (Vitest)
pnpm run test
# Run unit tests in watch mode
pnpm run test:watch
# Run E2E tests (Playwright)
pnpm run test:e2eFollow conventional commit format:
git add .
git commit -m "type(scope): description"Commit Types:
-
feat: New feature -
fix: Bug fix -
docs: Documentation only -
style: Code style changes (formatting, etc.) -
refactor: Code refactoring -
test: Adding or updating tests -
chore: Build process or auxiliary tool changes
Examples:
git commit -m "feat(api): add bulk threat creation endpoint"
git commit -m "fix(auth): correct OAuth callback URL handling"
git commit -m "docs(readme): update installation instructions"
git commit -m "test(integration): add authorization tests"TMI uses automatic semantic versioning based on conventional commit types. Commits to the main branch trigger a post-commit hook that updates the version automatically.
Version Format: MAJOR.MINOR.PATCH (optionally with a prerelease suffix, e.g. 1.4.0-rc.0)
- MAJOR: Incremented for breaking changes
-
MINOR: Incremented on
feat:commits (server only; in tmi-ux, minor bumps occur only when a release branch merges intomain) -
PATCH: Incremented on all other commits (
fix:,refactor:,docs:, etc.)
How It Works:
The post-commit hook runs only on the main branch. When you commit to main, it automatically:
- Checks whether production-relevant files were modified (Go source in
api/,auth/,cmd/server/,internal/, or files instatic/) - Reads the commit message and parses the conventional commit type
- Updates version:
feat:increments MINOR (resets PATCH), others increment PATCH - Updates
.versionfile andapi/version.go - Amends the commit with version changes
On feature branches (e.g. dev/*, feature/*, fix/*), the hook is a no-op.
Example Progression (server, on main branch):
# Starting at 1.4.0
git commit -m "fix(api): correct JWT validation" # → 1.4.1 (patch++)
git commit -m "refactor(auth): simplify login flow" # → 1.4.2 (patch++)
git commit -m "feat(api): add user deletion endpoint" # → 1.5.0 (minor++, patch=0)
git commit -m "docs: update API documentation" # → 1.5.1 (patch++)
git commit -m "feat(websocket): add heartbeat" # → 1.6.0 (minor++, patch=0)Version Storage:
-
.version- JSON file tracking current version state including major, minor, patch, and optional prerelease fields (tracked in git) -
api/version.go- Go variables set at build time via-ldflags -
package.json(tmi-ux) - Theversionfield is updated by the tmi-ux post-commit hook
Checking Version:
# View version file
cat .version
# Query running server
curl http://localhost:8080/ | jq '.service.build'
# Output: "1.4.0-abc1234"Troubleshooting:
- Hook not running? Ensure executable:
chmod +x .git/hooks/post-commit - Version not updating? Verify
jqis installed:which jq - Files out of sync? Make any commit to trigger sync:
git commit --allow-empty -m "chore: sync version files"
# Push to your fork
git push origin feature/your-feature-name- Go to https://github.com/ericfitz/tmi
- Click "New Pull Request"
- Select your fork and branch
- Fill out the PR template
# Format code
gofmt -w .
# Run linter
golangci-lint run ./...Naming Conventions:
// Good
type ThreatModel struct { }
func GetThreatModel(id string) (*ThreatModel, error) { }
var threatModelStore = NewStore[ThreatModel]()
// Bad
type threat_model struct { }
func get_threat_model(ID string) (*ThreatModel, error) { }
var ThreatModelStore = NewStore[ThreatModel]() // unexported globalsError Handling:
// Good - comprehensive error handling
func CreateThreatModel(data ThreatModel) error {
if err := validate(data); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
if err := db.Save(&data); err != nil {
return fmt.Errorf("failed to save threat model: %w", err)
}
return nil
}
// Bad - swallowing errors
func CreateThreatModel(data ThreatModel) error {
validate(data)
db.Save(&data)
return nil
}Logging:
// Use structured logging via slogging
logger := slogging.Get()
logger.Info("Created threat model",
slog.String("threat_model_id", tmID),
slog.String("user_id", userID),
)
// Not this
logger.Info("Created threat model " + tmID + " for user " + userID)# Format code
pnpm run format
# Check formatting
pnpm run format:check
# Lint
pnpm run lint:allNaming Conventions:
// Classes - PascalCase
export class ThreatModelService { }
// Interfaces - PascalCase with 'I' prefix (optional)
export interface ThreatModel { }
export interface IThreatModel { } // also acceptable
// Functions/Methods - camelCase
getThreatModels(): Observable<ThreatModel[]> { }
// Constants - UPPER_SNAKE_CASE
const MAX_THREAT_COUNT = 100;
// Properties - camelCase
private threatModels: ThreatModel[];RxJS Best Practices:
// Good - proper subscription handling
export class ThreatModelComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.apiService.getThreatModels()
.pipe(takeUntil(this.destroy$))
.subscribe(tms => this.threatModels = tms);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
// Bad - memory leaks
export class ThreatModelComponent implements OnInit {
ngOnInit() {
this.apiService.getThreatModels()
.subscribe(tms => this.threatModels = tms); // Never unsubscribed!
}
}Component Structure (Angular 21 standalone components):
@Component({
selector: 'app-threat-model',
templateUrl: './threat-model.component.html',
styleUrl: './threat-model.component.scss',
standalone: true,
imports: [CommonModule, TranslocoModule]
})
export class ThreatModelComponent implements OnInit {
// 1. Public properties
threatModels: ThreatModel[];
// 2. Private properties
private destroy$ = new Subject<void>();
// 3. Constructor (or use inject() for signal-based DI)
constructor(
private apiService: ApiService,
private logger: LoggerService
) { }
// 4. Lifecycle hooks
ngOnInit(): void {
this.loadThreatModels();
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
// 5. Public methods
loadThreatModels(): void {
// Implementation
}
// 6. Private methods
private handleError(error: Error): void {
// Implementation
}
}Go:
// ThreatModel represents a threat modeling project
// containing diagrams, threats, and security analysis.
type ThreatModel struct {
ID string `json:"id"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
}
// CreateThreatModel creates a new threat model with the given data.
// It validates the input, assigns ownership to the authenticated user,
// and persists to the database.
//
// Returns the created threat model or an error.
func CreateThreatModel(c *gin.Context) {
// Implementation
}TypeScript:
/**
* Service for managing threat model operations.
*
* Provides methods for CRUD operations on threat models
* and handles communication with the TMI API.
*/
@Injectable({providedIn: 'root'})
export class ThreatModelService {
/**
* Retrieves all threat models accessible to the current user.
*
* @returns Observable of threat model array
* @throws Error if API call fails
*/
getThreatModels(): Observable<ThreatModel[]> {
// Implementation
}
}- Keep documentation up to date with code changes
- Add code examples for new features
- Update API documentation when endpoints change
- Include migration guides for breaking changes
The TMI documentation is organized by audience and purpose across multiple repositories:
Reference Documentation (reference/):
| Directory | Contents |
|---|---|
reference/architecture/ |
overview.md, validation.md, violations.md (all resolved), service-provisioning.md, naming-conventions.md, session-management.md, autosave-data-modeling.md, dfd-change-propagation/
|
reference/libraries/ |
x6-complete-guide.md - Comprehensive X6 graph library documentation |
reference/features/ |
collaborative-editing.md, dfd-user-interaction-guide.md
|
reference/security/ |
headers.md - HTTP security header implementation |
Developer Documentation (developer/):
| Directory | Contents |
|---|---|
developer/setup/ |
environment-configuration.md, core-services.md, import-constants.md
|
developer/testing/ |
testing-utilities.md - Testing utilities and patterns |
developer/features/ |
validation-framework.md |
AI Agent Documentation (agent/):
-
collaboration-participant-list-ux-design.md- Collaboration UX design -
dfd-integration-testing-approach.md- DFD integration testing strategy -
dfd-integration-test-plan.md- DFD integration test plan -
developers-guide-antvx6-graphing-library.md- X6 developer guide -
interesting-x6-events.txt- X6 event samples -
pdf-report-diagram-rendering-design.md- PDF diagram rendering design
Supporting Files (in docs/reference/):
-
authentication-component-architecture.png- Authentication component architecture diagram -
authentication-flow.png- OAuth authentication flow diagram
-
docs/developer/- Development documentation (setup, testing, integration) -
docs/operator/- Operations documentation (deployment, database, monitoring) -
docs/reference/- Reference materials (API specs, schemas, architecture)
- Getting Started - End-user guides for threat modeling
- Deployment - Operator deployment guides
- Operation - SRE/DevOps running TMI
- Development - Contributor documentation
- API Reference - Technical API documentation
-
File Naming: Use
kebab-case.mdnaming convention (lowercase with hyphens, except README.md) - Cross-References: Maintain links between related documents
- Audience-Focused: Each section serves a specific audience (developers, operators, end-users, AI agents)
- Verification: All file references should be verified to exist before committing
- Start with
CLAUDE.mdin the repository root for AI assistant guidance and project overview - Read the Architecture-and-Design guide
- Review Service Provisioning Standards (
docs/reference/architecture/service-provisioning.md) - Check Environment Configuration (
docs/developer/setup/environment-configuration.md)
- Choose the appropriate location based on primary audience
- Use descriptive, hyphenated filenames
- Update README files in parent directories
- Add cross-references to related documents
- Verify all internal links before committing
All contributions must include appropriate tests:
Server (Go):
func TestCreateThreatModel(t *testing.T) {
// Test your function
}Web App (TypeScript):
describe('ThreatModelService', () => {
it('should create threat model', () => {
// Test your service
});
});For server changes that affect database or API:
func TestDatabaseThreatModelIntegration(t *testing.T) {
suite := SetupIntegrationTest(t)
defer suite.TeardownIntegrationTest(t)
// Test with real database
}For new endpoints, add Postman tests:
pm.test("Status code is 201", function () {
pm.response.to.have.status(201);
});For UI changes (using Playwright):
import { test, expect } from '@playwright/test';
test('should create new threat model', async ({ page }) => {
await page.goto('/threat-models');
await page.getByTestId('create-button').click();
// Test the flow
});- Aim for 80%+ code coverage on new code
- All bug fixes must include a regression test
- Test both happy path and error cases
# Server (Go)
make test-unit # Go unit tests
make test-integration # Integration tests with PostgreSQL
make test-api # Postman/Newman API tests
# Web App (Angular / Vitest / Playwright)
cd tmi-ux
pnpm run test # Unit tests (Vitest)
pnpm run test:coverage # Unit tests with coverage report
pnpm run test:e2e # E2E tests (Playwright)
pnpm run test:e2e:ui # E2E tests with Playwright UIFill out all sections of the PR template:
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] API tests pass (if applicable)
- [ ] E2E tests pass (if applicable)
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Code is commented where needed
- [ ] Documentation updated
- [ ] Tests added/updated
- [ ] All tests pass locallyEnsure your PR:
-
✅ Passes all checks
# Server make lint make test-unit make test-integration make build-server # Web App cd tmi-ux pnpm run lint:all pnpm run test pnpm run build
-
Has no merge conflicts
git fetch upstream git merge upstream/main # Resolve any conflicts -
✅ Has clear commit messages
-
✅ Includes tests
-
✅ Updates documentation
Keep PRs focused and manageable:
- Ideal: < 400 lines changed
- Maximum: < 1000 lines changed
- Large changes should be split into multiple PRs
Use draft PRs for:
- Work in progress
- Getting early feedback
- Discussing approach
Mark PR as "Draft" when creating it
Convert to "Ready for review" when complete
Responding to Feedback:
- Be open to suggestions
- Ask questions if unclear
- Make requested changes promptly
- Explain your reasoning when disagreeing
Handling Requests:
# Make requested changes
git add .
git commit -m "refactor: address review comments"
git push origin feature/your-feature-name
# Force push if rebasing/squashing
git push --force-with-lease origin feature/your-feature-nameReview Focus Areas:
- Correctness - Does it work as intended?
- Tests - Adequate test coverage?
- Design - Fits architecture?
- Performance - Any bottlenecks?
- Security - Any vulnerabilities?
- Documentation - Clear and complete?
Giving Feedback:
# Good feedback
"Consider using a map here for O(1) lookup instead of iterating the array"
"This could cause a race condition if two users update simultaneously.
Consider using a transaction or optimistic locking."
# Less helpful
"This is wrong"
"Do it differently"We follow the Contributor Covenant:
- Be respectful - Treat everyone with respect
- Be inclusive - Welcome all contributors
- Be constructive - Provide helpful feedback
- Be professional - Keep discussions on-topic
- GitHub Issues - Bug reports and feature requests
- GitHub Discussions - Questions and general discussion
- Pull Requests - Code review and technical discussions
Before asking:
- Check existing documentation
- Search closed issues
- Review pull requests
When asking:
- Provide context
- Include error messages
- Share relevant code snippets
- Describe what you've tried
Use this template:
## Bug Description
Clear description of the bug
## Steps to Reproduce
1. Go to '...'
2. Click on '...'
3. See error
## Expected Behavior
What should happen
## Actual Behavior
What actually happens
## Environment
- OS: [e.g. macOS 13.0]
- Browser: [e.g. Chrome 120]
- TMI Version: [e.g. 0.9.0]
## Additional Context
Screenshots, logs, etc.Use this template:
## Feature Description
Clear description of the feature
## Use Case
Why is this needed? Who will use it?
## Proposed Solution
How should it work?
## Alternatives Considered
What other approaches did you consider?
## Additional Context
Mockups, examples, etc.Contributors are recognized in:
- Release notes
- Contributors list
- Project README
Significant contributions may lead to:
- Maintainer status
- Core team membership
- Speaking opportunities
TMI supports AI-assisted development through detailed context documentation. The docs/agent/ directory contains context and implementation guidance for AI coding agents working on this project, including architecture proposals, implementation plans, design documents, and technical context.
The agent documentation directory includes:
Design and Planning Documents:
- collaboration-participant-list-ux-design.md - UX design for collaboration participant list feature
- pdf-report-diagram-rendering-design.md - Design document for pre-rendered diagram storage to enable full diagram inclusion in PDF reports
Testing Documentation:
- dfd-integration-testing-approach.md - Integration testing approach for DFD services
- dfd-integration-test-plan.md - Comprehensive integration test plan for DFD graph component
Implementation Guides:
- developers-guide-antvx6-graphing-library.md - Developer guide for working with the AntV X6 graphing library
Reference Information:
- interesting-x6-events.txt - Log samples of X6 graph events showing actual event data
When working with AI tools on TMI, also reference:
-
Architecture:
docs/reference/architecture/- Architecture overview, service provisioning standards, naming conventions, session management -
Developer Docs:
docs/developer/- Environment configuration, testing utilities, core services setup -
Technical References:
docs/reference/- X6 complete guide, collaborative editing implementation, security headers
When working with TMI authentication:
- Primary Flow: TMI uses OAuth 2.0 Authorization Code flow with PKCE (RFC 7636)
-
TMI Provider: Built-in development OAuth provider (
idp=tmi) for testing - JWT Tokens: Authentication uses JWT tokens with specific claim structure
- Multi-Provider: Supports Google, GitHub, and Microsoft OAuth providers
- CLAUDE.md: Project-specific instructions in the repository root
-
OpenAPI Spec:
docs/reference/apis/tmi-openapi.jsonfor API structure - Architecture Docs: Architecture-and-Design for system understanding
- Reference the OpenAPI specification for endpoint behavior
- Use structured logging with
github.com/ericfitz/tmi/internal/slogging - Follow the testing patterns in existing test files
- Always use Make targets (never run
go testorgo rundirectly)
-
Implementation Plans: Use
docs/agent/for storing implementation plans, progress tracking, and design documents - Context Documents: Store technical context and background information there
- Testing Strategies: Document testing approaches and plans
- Research Notes: Keep research findings and technical analysis there
- Update Directory Contents: AI assistants should update the directory README when adding or removing files
Need help contributing?
- Read Getting-Started-with-Development
- Check FAQ
- Ask in GitHub Discussions
- Review existing PRs for examples
# Server Development (Go 1.26.x)
make start-dev # Start dev environment (DB + Redis + server)
make test-unit # Run unit tests
make test-integration # Run integration tests (PostgreSQL)
make test-api # Run Postman/Newman API tests
make lint # Run golangci-lint
make build-server # Build binary
make status # Check status of all services
# Web App Development (Angular 21.x / Vitest 4.x / Playwright)
cd tmi-ux
pnpm run dev # Start dev server (ng serve --open)
pnpm run test # Run unit tests (Vitest)
pnpm run test:coverage # Run unit tests with coverage
pnpm run test:e2e # Run E2E tests (Playwright)
pnpm run lint:all # Run all linters (ESLint + Stylelint)
pnpm run format # Format code (Prettier)
pnpm run build # Build for production
# Git Workflow (default branch is 'main')
git checkout -b feature/name # Create branch from main
git add . # Stage changes
git commit -m "msg" # Commit
git push origin feature/name # Push- ✅ Go code formatted with
gofmt - ✅ TypeScript/HTML formatted with Prettier
- ✅ Linters pass
- ✅ Tests pass
- ✅ Documentation updated
- ✅ Commit messages follow convention
- ✅ No merge conflicts
Ready to contribute?
- Set up your development environment: Getting-Started-with-Development
- Understand the architecture: Architecture-and-Design
- Review the testing guide: Testing
- Find an issue to work on
- Create your first PR!
Thank you for contributing to TMI!
- Using TMI for Threat Modeling
- Accessing TMI
- Authentication
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Timmy AI Assistant
- Metadata and Extensions
- Planning Your Deployment
- Terraform Deployment (AWS, OCI, GCP, Azure)
- Deploying TMI Server
- OCI Container Deployment
- Certificate Automation
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Branding and Customization
- Monitoring and Health
- Cloud Logging
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks
- Getting Started with Development
- Architecture and Design
- API Integration
- Testing
- Contributing
- Extending TMI
- Dependency Upgrade Plans
- DFD Graphing Library Reference
- Migration Instructions