This document defines the standards for contributing to AccountSafe. Read it completely before submitting code.
For API and configuration details, see the docs/ directory.
- Security Requirements
- Development Setup
- Project Structure
- Code Standards
- Testing Requirements
- Commit Guidelines
- Pull Request Process
- Issue Reporting
AccountSafe is a security product. These rules are non-negotiable.
-
No secrets in version control. API keys, passwords, tokens, and private keys must never be committed. Use environment variables exclusively.
-
Client-side encryption only. Sensitive data must be encrypted in the browser before transmission. The server must never receive plaintext credentials.
-
No
anytype in TypeScript. Use explicit types.anycircumvents the type system and introduces risk. -
No
@ts-ignoredirectives. Fix the type error - do not silence it. -
No
console.login production code. Use the structured logger infrontend/src/utils/logger.ts. Remove all debug statements before submitting. -
No
print()statements in Python. Use theloggingmodule exclusively. -
No disabled security headers. CORS, CSRF, and CSP configurations must not be weakened.
-
Strict dependency versioning. No
^or~inpackage.json. Pin all versions exactly (e.g."react": "18.3.1"). This prevents supply chain attacks via automatic upgrades. -
New dependencies require justification. Review the package's security posture and transitive dependency count before adding it.
-
Cryptographic code is off-limits without maintainer sign-off. Do not modify encryption algorithms, key derivation parameters, or cryptographic primitives without explicit approval and a security review.
The following changes require a security review before merge:
- Any change to
frontend/src/utils/encryption.ts - Any change to
backend/api/features/auth/zero_knowledge.py - Any change to
backend/api/features/security/(sessions, canary traps, health score) - Authentication or session management changes
- New API endpoints that handle sensitive data
- Changes to CORS, CSRF, or CSP policies
- Database schema changes involving encrypted fields
- Dependency updates to cryptography, JWT, or auth packages
- Changes to duress mode or canary trap logic
| Tool | Min Version | Notes |
|---|---|---|
| Python | 3.10 | Windows: use py launcher from python.org - not MSYS2 |
| Node.js | 18 | Includes npm |
| PostgreSQL | 15 | Must be running before starting the backend |
| Git | 2.40 |
Windows Python: Install from python.org and tick "Add to PATH". Always use
py -m venv venv(the Python Launcher), notpython -m venv venv. Thepythoncommand may resolve to MSYS2 or the Microsoft Store stub, both of which produce broken venvs on Windows.
# Fork on GitHub, then:
git clone https://github.com/YOUR-USERNAME/AccountSafe.git
cd AccountSafe
git remote add upstream https://github.com/pankaj-bind/AccountSafe.gitcd backendCreate and activate a virtual environment:
# Linux / macOS
python3 -m venv venv
source venv/bin/activate
# Windows - Command Prompt (recommended)
py -m venv venv
venv\Scripts\activate.bat
# Windows - PowerShell
py -m venv venv
.\venv\Scripts\Activate.ps1
# First-time only, if blocked by execution policy:
# Set-ExecutionPolicy RemoteSigned -Scope CurrentUserInstall dependencies:
pip install -r requirements-local.txtConfigure environment - create backend/.env:
DEBUG=True
SECRET_KEY=django-insecure-dev-only-key-change-in-production
DB_NAME=accountsafe
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DB_PORT=5432Run migrations and start:
python manage.py migrate
python manage.py runserver # http://localhost:8000cd frontend
npm install
npm start # http://localhost:3000# Linux / macOS
make test-backend
make test-frontend
# Windows
scripts\run_tests.bat backend
scripts\run_tests.bat frontend
# Type checking
cd frontend && npx tsc --noEmitbackend/
├── api/
│ ├── features/ # All business logic lives here
│ │ ├── auth/ # Authentication & Zero-Knowledge
│ │ │ ├── views.py # Login, register, password reset
│ │ │ ├── zero_knowledge.py # ZK auth, duress mode
│ │ │ ├── services.py # Business logic
│ │ │ ├── serializers.py # Request/response schemas
│ │ │ └── urls.py
│ │ ├── vault/ # Vault management
│ │ │ ├── views.py # Categories, organisations, profiles
│ │ │ ├── zk_views.py # Zero-knowledge vault operations
│ │ │ └── services.py
│ │ ├── security/ # Security features
│ │ │ ├── views.py # Health score, sessions, canary traps
│ │ │ └── services.py
│ │ └── shared_secret/ # Secure credential sharing
│ │ ├── views.py
│ │ └── services.py
│ ├── models.py # Database models (shared)
│ ├── tests/ # pytest test suite
│ │ ├── conftest.py
│ │ ├── test_auth.py
│ │ ├── test_vault_api.py
│ │ └── test_zero_knowledge.py
│ └── utils/ # Shared utilities
├── core/
│ ├── settings.py
│ └── urls.py
└── requirements-local.txt # Pinned dev dependencies
frontend/src/
├── components/ # Shared UI components
├── contexts/ # React context providers (Auth, Panic, Theme, ...)
├── features/ # Feature-specific components
├── hooks/ # Custom React hooks
├── pages/ # Route-level components (one per page)
├── services/ # API client layer
├── types/ # TypeScript type definitions
└── utils/ # Shared utilities (encryption, logger, formatters, ...)
Do not add new views to
backend/api/views.py. All new features belong inbackend/api/features/{module}/.
Strict mode is enabled in tsconfig.json. All of the following apply.
Requirements:
- Functional components only - no class components.
- Explicit return types on all functions.
- Interface definitions for all props and state shapes.
- Typed catch blocks:
catch (error: unknown). - No
any, no@ts-ignore. - Imports ordered: React → external libraries → internal modules → types.
- Use the structured logger (
src/utils/logger.ts), notconsole.log.
Example:
interface ProfileCardProps {
profile: Profile;
onEdit: (id: number) => void;
onDelete: (id: number) => void;
}
export const ProfileCard: React.FC<ProfileCardProps> = ({
profile,
onEdit,
onDelete,
}): JSX.Element => {
const handleEdit = (): void => {
onEdit(profile.id);
};
return (
<div className="rounded-lg border p-4">
<h3>{profile.title}</h3>
<button onClick={handleEdit}>Edit</button>
</div>
);
};PEP 8, formatted with Black (line length 88), linted with Flake8, imports sorted with isort.
Requirements:
- Type hints on all function signatures.
- Docstrings on all public functions and classes.
- Use
loggingmodule - neverprint(). - Maximum line length: 88 characters.
Example:
import logging
from typing import Optional
logger = logging.getLogger(__name__)
def encrypt_credential(plaintext: str, key: bytes) -> Optional[str]:
"""
Encrypt a credential using AES-256-GCM.
Args:
plaintext: The string to encrypt.
key: A 256-bit encryption key.
Returns:
Base64-encoded ciphertext, or None if encryption fails.
Raises:
ValueError: If plaintext is empty.
"""
if not plaintext:
raise ValueError("Plaintext cannot be empty")
# ...| Area | Minimum |
|---|---|
| Encryption utilities | 90% |
| Authentication flows | 85% |
| API endpoints | 80% |
| UI components | 70% |
Linux / macOS:
make testWindows:
scripts\run_tests.batcd backend
# Linux / macOS
source venv/bin/activate
# Windows
venv\Scripts\activate.bat
python -m pytest -v
python -m pytest -v --cov=api --cov-report=term-missing # with coveragecd frontend
npm test -- --watchAll=false # run once
npm test -- --watchAll=false --coverage # with coverage reportBackend:
- Unit tests for encryption/decryption logic
- Integration tests for API endpoints (use the Django test client, not mocks)
- Authentication flow tests - register, login, duress mode, session expiry
- Permission and access control tests
Frontend:
- Component rendering tests
- Custom hook behaviour tests
- Encryption utility tests (
src/utils/__tests__/) - Error boundary behaviour
Format: Conventional Commits.
<type>(<scope>): <subject>
<body>
<footer>
| Type | Use for |
|---|---|
feat |
New feature |
fix |
Bug fix |
security |
Security fix or hardening |
refactor |
Code restructure with no behaviour change |
perf |
Performance improvement |
test |
Adding or updating tests |
docs |
Documentation only |
chore |
Build, dependency, or tooling changes |
- Subject: imperative mood, no period, under 50 characters.
- Body: explain what and why, not how. Wrap at 72 characters.
- Reference issues in the footer:
Closes #123orFixes #456.
feat(vault): add encrypted credential export
Implement JSON export of vault credentials using the existing
AES-256-GCM encryption key. Export is always encrypted - no
plaintext export path is provided.
Closes #234
security(auth): rate-limit login endpoint per IP
Add per-IP rate limiting to prevent brute-force attacks.
5 attempts per minute; 15-minute lockout on breach.
Refs #189
- Code compiles without errors (
npx tsc --noEmit) - All tests pass (
make testorscripts\run_tests.bat) - No linting errors (
flake8 .andnpm run lint) - Commits follow Conventional Commits format
- No secrets,
.envfiles, or credentials in the diff - Documentation updated if behaviour changed
- Security-sensitive changes flagged for review
- Push your branch to your fork.
- Open a pull request against
main. - Fill out the PR template completely - incomplete PRs will not be reviewed.
- Request review from a maintainer.
Same convention as commit messages:
feat(vault): add credential search
fix(auth): resolve session timeout race condition
security(api): patch IDOR vulnerability in profile endpoint
- All CI checks must pass.
- At least one maintainer approval required.
- Security-sensitive changes require two approvals.
- Address every review comment before merge.
- Commits are squashed on merge.
Include:
- Title - specific and descriptive.
- Environment - OS, browser, Python/Node versions.
- Steps to reproduce - minimal numbered steps.
- Expected behaviour - what should happen.
- Actual behaviour - what happens instead.
- Logs / screenshots - sanitise any sensitive data before pasting.
Include:
- Problem statement - what problem does this solve?
- Proposed solution - how should it work?
- Alternatives considered - other approaches you evaluated.
- Security implications - any security considerations.
Do not open public issues for security vulnerabilities.
Follow the responsible disclosure process in SECURITY.md.
- Search existing issues and discussions first.
- Open a GitHub Discussion for general questions.
- Contact maintainers directly for security-related questions.