680 lines
21 KiB
Markdown
680 lines
21 KiB
Markdown
# StellaOps Engineering Code of Conduct
|
|
*Technical excellence + safe for change = best-in-class product*
|
|
|
|
---
|
|
|
|
## 0 · Mission and Values
|
|
|
|
**StellaOps** is a sovereign, self-hostable release control plane delivering reproducible, auditable, and secure software releases for non-Kubernetes container estates. We are committed to building a **best-in-class product that is safe for change** — where every contribution improves quality, maintainability, and security without regression.
|
|
|
|
### Our Engineering Pledge
|
|
|
|
We pledge to uphold:
|
|
|
|
1. **Technical Excellence** — Code that is deterministic, testable, and production-ready from day one.
|
|
2. **Safety for Change** — Comprehensive testing, minimal surprise, and zero tolerance for silent failures.
|
|
3. **Security by Design** — Input validation, least privilege, cryptographic correctness, and defense in depth.
|
|
4. **Maintainability First** — Clear contracts, minimal coupling, immutable outputs, and self-documenting code.
|
|
5. **Transparency and Auditability** — Every decision, every release, every change is traceable and reproducible.
|
|
|
|
This document codifies the **technical standards** all contributors must follow. Behavioral expectations are covered in [COMMUNITY_CONDUCT.md](./COMMUNITY_CONDUCT.md).
|
|
|
|
---
|
|
|
|
## 1 · Core Principles
|
|
|
|
### 1.1 Quality
|
|
|
|
Quality is not negotiable. Every line of code must be:
|
|
|
|
- **Correct** — Does what it claims, handles errors gracefully, fails fast when assumptions break
|
|
- **Tested** — Unit tests for logic, integration tests for contracts, E2E tests for workflows
|
|
- **Deterministic** — Same inputs always produce same outputs; no hidden state, no timing dependencies
|
|
- **Observable** — Logs structured events, emits metrics, traces execution paths
|
|
- **Documented** — Self-explanatory code; architecture decisions recorded; APIs have examples
|
|
|
|
**Why it matters**: Quality debt compounds. A shortcut today becomes a week-long incident tomorrow. We build for the long term.
|
|
|
|
---
|
|
|
|
### 1.2 Maintainability
|
|
|
|
Code is read 10x more than it's written. Optimize for the next engineer:
|
|
|
|
- **Clear intent** — Names reveal purpose; functions do one thing; classes have single responsibilities
|
|
- **Low coupling** — Modules depend on interfaces, not implementations; changes propagate predictably
|
|
- **High cohesion** — Related logic lives together; unrelated logic stays separate
|
|
- **Minimal surprise** — Standard patterns over clever tricks; explicit over implicit
|
|
- **Refactorable** — Tests enable confident changes; abstractions hide complexity without obscuring behavior
|
|
|
|
**Why it matters**: Unmaintainable code slows velocity to zero. We build systems that evolve, not calcify.
|
|
|
|
---
|
|
|
|
### 1.3 Security
|
|
|
|
Security is a design constraint, not a feature:
|
|
|
|
- **Defense in depth** — Multiple layers: input validation, authorization, cryptographic verification, audit trails
|
|
- **Least privilege** — Services run with minimal permissions; users see only what they need
|
|
- **Fail secure** — Errors deny access; missing config stops startup; invalid crypto rejects requests
|
|
- **Cryptographic correctness** — Use vetted libraries; never roll your own crypto; verify all signatures
|
|
- **Supply chain integrity** — Pin dependencies; scan for vulnerabilities; generate SBOMs; issue VEX statements
|
|
- **Auditability** — Every action logged; every release signed; every decision traceable
|
|
|
|
**Why it matters**: Security failures destroy trust. We protect our users' infrastructure and their reputation.
|
|
|
|
---
|
|
|
|
## 2 · Scope and Authority
|
|
|
|
This Code of Conduct applies to:
|
|
|
|
- All code contributions (C#, TypeScript, Angular, SQL, Dockerfiles, Helm charts, CI/CD pipelines)
|
|
- All documentation (architecture, API references, runbooks, sprint files)
|
|
- All testing artifacts (unit, integration, E2E, performance, security tests)
|
|
- All infrastructure-as-code (Terraform, Ansible, Compose, Kubernetes manifests)
|
|
|
|
**Authority**: This document supersedes informal guidance. When in conflict with external standards, StellaOps rules win. Module-specific `AGENTS.md` files may impose stricter requirements but cannot relax the rules defined here.
|
|
|
|
---
|
|
|
|
## 3 · Mandatory Reading
|
|
|
|
Before contributing to any module, you **must** read and understand:
|
|
|
|
1. **This document** — The engineering code of conduct (you're reading it now)
|
|
2. [docs/README.md](../README.md) — Project overview and navigation
|
|
3. [docs/07_HIGH_LEVEL_ARCHITECTURE.md](../07_HIGH_LEVEL_ARCHITECTURE.md) — System architecture
|
|
4. [docs/modules/platform/architecture-overview.md](../modules/platform/architecture-overview.md) — Platform design
|
|
5. [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) — Testing requirements and evidence standards
|
|
6. The relevant module's architecture dossier (`docs/modules/<module>/architecture.md`)
|
|
7. The module's `AGENTS.md` if present (e.g., `src/Scanner/AGENTS.md`)
|
|
|
|
**Enforcement**: Pull requests that violate documented architecture or module-specific constraints will be rejected with a reference to the violated document.
|
|
|
|
---
|
|
|
|
## 4 · Code Quality Standards
|
|
|
|
### 3.1 Compiler Discipline
|
|
|
|
**Rule**: All projects must enable `TreatWarningsAsErrors`.
|
|
|
|
```xml
|
|
<!-- In .csproj or Directory.Build.props -->
|
|
<PropertyGroup>
|
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
</PropertyGroup>
|
|
```
|
|
|
|
**Rationale**: Warnings mask regressions and code quality drift. Zero-warning builds are mandatory.
|
|
|
|
---
|
|
|
|
### 3.2 Determinism: Time, IDs, and Randomness
|
|
|
|
**Rule**: Never use `DateTime.UtcNow`, `DateTimeOffset.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly in production code.
|
|
|
|
**Required**: Inject `TimeProvider` and `IGuidGenerator` abstractions.
|
|
|
|
```csharp
|
|
// ❌ BAD - nondeterministic, untestable
|
|
public class BadService
|
|
{
|
|
public Record CreateRecord() => new Record
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
}
|
|
|
|
// ✅ GOOD - injectable, testable, deterministic
|
|
public class GoodService(TimeProvider timeProvider, IGuidGenerator guidGenerator)
|
|
{
|
|
public Record CreateRecord() => new Record
|
|
{
|
|
Id = guidGenerator.NewGuid(),
|
|
CreatedAt = timeProvider.GetUtcNow()
|
|
};
|
|
}
|
|
```
|
|
|
|
**Rationale**: Deterministic outputs enable reproducible builds, reliable tests, and cryptographic verification. Nondeterministic code breaks evidence chains.
|
|
|
|
---
|
|
|
|
### 3.3 Culture-Invariant Parsing and Formatting
|
|
|
|
**Rule**: Always use `CultureInfo.InvariantCulture` for parsing and formatting dates, numbers, percentages, and any string that will be persisted, hashed, or compared.
|
|
|
|
```csharp
|
|
// ❌ BAD - culture-sensitive, locale-dependent
|
|
var value = double.Parse(input);
|
|
var formatted = percentage.ToString("P2");
|
|
|
|
// ✅ GOOD - culture-invariant, deterministic
|
|
var value = double.Parse(input, CultureInfo.InvariantCulture);
|
|
var formatted = percentage.ToString("P2", CultureInfo.InvariantCulture);
|
|
```
|
|
|
|
**Rationale**: Current culture causes nondeterministic behavior across environments. All outputs must be reproducible regardless of locale.
|
|
|
|
---
|
|
|
|
### 3.4 ASCII-Only Output
|
|
|
|
**Rule**: Use ASCII-only characters in comments, output strings, and log messages. No mojibake (`ƒ?`), Unicode glyphs (`✓`, `→`, `バ`), or box-drawing characters.
|
|
|
|
```csharp
|
|
// ❌ BAD - non-ASCII glyphs
|
|
Console.WriteLine("✓ Success → proceeding");
|
|
|
|
// ✅ GOOD - ASCII only
|
|
Console.WriteLine("[OK] Success - proceeding");
|
|
```
|
|
|
|
**Exceptions**: When Unicode is **required** (e.g., internationalized user messages), use explicit escapes (`\uXXXX`) and document the rationale.
|
|
|
|
**Rationale**: Non-ASCII characters break in constrained environments (containers, SSH, logs). ASCII ensures universal readability.
|
|
|
|
---
|
|
|
|
### 3.5 Immutable Collection Returns
|
|
|
|
**Rule**: Public APIs must return `IReadOnlyList<T>`, `ImmutableArray<T>`, or defensive copies. Never expose mutable backing stores.
|
|
|
|
```csharp
|
|
// ❌ BAD - exposes mutable backing store
|
|
public class BadRegistry
|
|
{
|
|
private readonly List<string> _scopes = new();
|
|
public List<string> Scopes => _scopes; // Callers can mutate!
|
|
}
|
|
|
|
// ✅ GOOD - immutable return
|
|
public class GoodRegistry
|
|
{
|
|
private readonly List<string> _scopes = new();
|
|
public IReadOnlyList<string> Scopes => _scopes.AsReadOnly();
|
|
}
|
|
```
|
|
|
|
**Rationale**: Mutable returns create hidden coupling and race conditions. Immutability is a safety contract.
|
|
|
|
---
|
|
|
|
### 3.6 No Silent Stubs
|
|
|
|
**Rule**: Placeholder code must throw `NotImplementedException` or return an explicit error status. Never return success from unimplemented paths.
|
|
|
|
```csharp
|
|
// ❌ BAD - silent stub masks missing implementation
|
|
public async Task<Result> ProcessAsync()
|
|
{
|
|
// TODO: implement later
|
|
return Result.Success(); // Ships broken feature!
|
|
}
|
|
|
|
// ✅ GOOD - explicit failure
|
|
public async Task<Result> ProcessAsync()
|
|
{
|
|
throw new NotImplementedException("ProcessAsync not yet implemented. See SPRINT_20251218_001_BE_ReleasePromotion.md");
|
|
}
|
|
```
|
|
|
|
**Rationale**: Silent stubs ship broken features. Explicit failures prevent production incidents.
|
|
|
|
---
|
|
|
|
### 3.7 CancellationToken Propagation
|
|
|
|
**Rule**: Always propagate `CancellationToken` through async call chains. Never use `CancellationToken.None` in production code.
|
|
|
|
```csharp
|
|
// ❌ BAD - ignores cancellation
|
|
public async Task ProcessAsync(CancellationToken ct)
|
|
{
|
|
await _repository.SaveAsync(data, CancellationToken.None); // Wrong!
|
|
await Task.Delay(1000); // Missing ct
|
|
}
|
|
|
|
// ✅ GOOD - propagates cancellation
|
|
public async Task ProcessAsync(CancellationToken ct)
|
|
{
|
|
await _repository.SaveAsync(data, ct);
|
|
await Task.Delay(1000, ct);
|
|
}
|
|
```
|
|
|
|
**Rationale**: Proper cancellation prevents resource leaks and enables graceful shutdown.
|
|
|
|
---
|
|
|
|
### 3.8 HttpClient via IHttpClientFactory
|
|
|
|
**Rule**: Never instantiate `HttpClient` directly. Use `IHttpClientFactory` with configured timeouts and retry policies.
|
|
|
|
```csharp
|
|
// ❌ BAD - direct instantiation
|
|
public class BadService
|
|
{
|
|
public async Task FetchAsync()
|
|
{
|
|
using var client = new HttpClient(); // Socket exhaustion risk
|
|
await client.GetAsync(url);
|
|
}
|
|
}
|
|
|
|
// ✅ GOOD - factory with resilience
|
|
public class GoodService(IHttpClientFactory httpClientFactory)
|
|
{
|
|
public async Task FetchAsync()
|
|
{
|
|
var client = httpClientFactory.CreateClient("MyApi");
|
|
await client.GetAsync(url);
|
|
}
|
|
}
|
|
|
|
// Registration with timeout/retry
|
|
services.AddHttpClient("MyApi")
|
|
.ConfigureHttpClient(c => c.Timeout = TimeSpan.FromSeconds(30))
|
|
.AddStandardResilienceHandler();
|
|
```
|
|
|
|
**Rationale**: Direct `HttpClient` creation causes socket exhaustion. Factories enable connection pooling and resilience patterns.
|
|
|
|
---
|
|
|
|
### 3.9 Bounded Caches with Eviction
|
|
|
|
**Rule**: Do not use `ConcurrentDictionary` or `Dictionary` for caching without eviction policies.
|
|
|
|
```csharp
|
|
// ❌ BAD - unbounded growth
|
|
private readonly ConcurrentDictionary<string, CacheEntry> _cache = new();
|
|
|
|
public void Add(string key, CacheEntry entry)
|
|
{
|
|
_cache[key] = entry; // Never evicts, memory grows forever
|
|
}
|
|
|
|
// ✅ GOOD - bounded with eviction
|
|
private readonly MemoryCache _cache = new(new MemoryCacheOptions
|
|
{
|
|
SizeLimit = 10_000
|
|
});
|
|
|
|
public void Add(string key, CacheEntry entry)
|
|
{
|
|
_cache.Set(key, entry, new MemoryCacheEntryOptions
|
|
{
|
|
Size = 1,
|
|
SlidingExpiration = TimeSpan.FromMinutes(30)
|
|
});
|
|
}
|
|
```
|
|
|
|
**Rationale**: Unbounded caches cause memory exhaustion in long-running services. Bounded caches with TTL/LRU eviction are mandatory.
|
|
|
|
---
|
|
|
|
### 3.10 Options Validation at Startup
|
|
|
|
**Rule**: Use `ValidateDataAnnotations()` and `ValidateOnStart()` for all options classes. Implement `IValidateOptions<T>` for complex validation.
|
|
|
|
```csharp
|
|
// ❌ BAD - no validation until runtime failure
|
|
services.Configure<MyOptions>(config.GetSection("My"));
|
|
|
|
// ✅ GOOD - validated at startup
|
|
services.AddOptions<MyOptions>()
|
|
.Bind(config.GetSection("My"))
|
|
.ValidateDataAnnotations()
|
|
.ValidateOnStart();
|
|
```
|
|
|
|
**Rationale**: All required config must be validated at startup, not at first use. Fail fast prevents runtime surprises.
|
|
|
|
---
|
|
|
|
## 5 · Cryptographic and Security Standards
|
|
|
|
### 4.1 DSSE PAE Consistency
|
|
|
|
**Rule**: Use one spec-compliant DSSE PAE helper (`StellaOps.Attestation.DsseHelper`) across the codebase. Never reimplement PAE encoding.
|
|
|
|
```csharp
|
|
// ❌ BAD - custom PAE implementation
|
|
var pae = $"DSSEv1 {payloadType.Length} {payloadType} {payload.Length} ";
|
|
|
|
// ✅ GOOD - use shared helper
|
|
var pae = DsseHelper.ComputePreAuthenticationEncoding(payloadType, payload);
|
|
```
|
|
|
|
**Rationale**: DSSE v1 requires ASCII decimal lengths and space separators. Reimplementations introduce cryptographic vulnerabilities.
|
|
|
|
---
|
|
|
|
### 4.2 RFC 8785 JSON Canonicalization
|
|
|
|
**Rule**: Use a shared RFC 8785-compliant JSON canonicalizer for digest/signature inputs. Do not use `UnsafeRelaxedJsonEscaping` or `CamelCase` naming for canonical outputs.
|
|
|
|
```csharp
|
|
// ❌ BAD - non-canonical JSON
|
|
var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions
|
|
{
|
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
});
|
|
|
|
// ✅ GOOD - use shared canonicalizer
|
|
var canonicalJson = CanonicalJsonSerializer.Serialize(obj);
|
|
var digest = ComputeDigest(canonicalJson);
|
|
```
|
|
|
|
**Rationale**: RFC 8785 ensures deterministic JSON serialization. Non-canonical JSON breaks signature verification.
|
|
|
|
---
|
|
|
|
### 4.3 DateTimeOffset for PostgreSQL timestamptz
|
|
|
|
**Rule**: PostgreSQL `timestamptz` columns must be read via `reader.GetFieldValue<DateTimeOffset>()`, not `reader.GetDateTime()`.
|
|
|
|
```csharp
|
|
// ❌ BAD - loses offset information
|
|
var createdAt = reader.GetDateTime(reader.GetOrdinal("created_at"));
|
|
|
|
// ✅ GOOD - preserves offset
|
|
var createdAt = reader.GetFieldValue<DateTimeOffset>(reader.GetOrdinal("created_at"));
|
|
```
|
|
|
|
**Rationale**: `GetDateTime()` loses offset information and causes UTC/local confusion. All timestamps must be stored and retrieved as UTC `DateTimeOffset`.
|
|
|
|
---
|
|
|
|
### 4.4 Explicit CLI Options for Paths
|
|
|
|
**Rule**: Do not derive repository root from `AppContext.BaseDirectory` with parent directory walks. Use explicit CLI options (`--repo-root`) or environment variables.
|
|
|
|
```csharp
|
|
// ❌ BAD - fragile parent walks
|
|
var repoRoot = Path.GetFullPath(Path.Combine(
|
|
AppContext.BaseDirectory, "..", "..", "..", ".."));
|
|
|
|
// ✅ GOOD - explicit option with fallback
|
|
[Option("--repo-root", Description = "Repository root path")]
|
|
public string? RepoRoot { get; set; }
|
|
|
|
public string GetRepoRoot() =>
|
|
RepoRoot ?? Environment.GetEnvironmentVariable("STELLAOPS_REPO_ROOT")
|
|
?? throw new InvalidOperationException("Repository root not specified. Use --repo-root or set STELLAOPS_REPO_ROOT.");
|
|
```
|
|
|
|
**Rationale**: Parent walks break in containerized and CI environments. Explicit paths are mandatory.
|
|
|
|
---
|
|
|
|
## 6 · Testing Requirements
|
|
|
|
**All code contributions must include tests.** See [TESTING_PRACTICES.md](./TESTING_PRACTICES.md) for comprehensive guidance.
|
|
|
|
### 5.1 Test Project Requirements
|
|
|
|
**Rule**: All production libraries/services must have a corresponding `*.Tests` project covering:
|
|
- (a) Happy paths
|
|
- (b) Error/edge cases
|
|
- (c) Determinism
|
|
- (d) Serialization round-trips
|
|
|
|
```
|
|
src/
|
|
Scanner/
|
|
__Libraries/
|
|
StellaOps.Scanner.Core/
|
|
__Tests/
|
|
StellaOps.Scanner.Core.Tests/ <-- Required
|
|
```
|
|
|
|
---
|
|
|
|
### 5.2 Test Categorization
|
|
|
|
**Rule**: Tag tests correctly:
|
|
- `[Trait("Category", "Unit")]` for pure unit tests
|
|
- `[Trait("Category", "Integration")]` for tests requiring databases, containers, or network
|
|
|
|
```csharp
|
|
// ❌ BAD - integration test marked as unit
|
|
public class UserRepositoryTests // Uses Testcontainers/Postgres
|
|
{
|
|
[Fact] // Missing category
|
|
public async Task Save_PersistsUser() { ... }
|
|
}
|
|
|
|
// ✅ GOOD - correctly categorized
|
|
[Trait("Category", "Integration")]
|
|
public class UserRepositoryTests
|
|
{
|
|
[Fact]
|
|
public async Task Save_PersistsUser() { ... }
|
|
}
|
|
|
|
[Trait("Category", "Unit")]
|
|
public class UserValidatorTests
|
|
{
|
|
[Fact]
|
|
public void Validate_EmptyEmail_ReturnsFalse() { ... }
|
|
}
|
|
```
|
|
|
|
**Rationale**: Unit tests must run fast and offline. Integration tests require infrastructure. Mixing categories breaks CI pipelines.
|
|
|
|
---
|
|
|
|
### 5.3 Test Production Code, Not Reimplementations
|
|
|
|
**Rule**: Test helpers must call production code, not reimplement algorithms.
|
|
|
|
```csharp
|
|
// ❌ BAD - test reimplements production logic
|
|
[Fact]
|
|
public void Merkle_ComputesCorrectRoot()
|
|
{
|
|
var root = TestMerkleHelper.ComputeRoot(leaves); // Drift risk!
|
|
Assert.Equal(expected, root);
|
|
}
|
|
|
|
// ✅ GOOD - test exercises production code
|
|
[Fact]
|
|
public void Merkle_ComputesCorrectRoot()
|
|
{
|
|
var root = MerkleTreeBuilder.ComputeRoot(leaves);
|
|
Assert.Equal(expected, root);
|
|
}
|
|
```
|
|
|
|
**Rationale**: Reimplementations in tests cause test/production drift. Only mock I/O and network boundaries.
|
|
|
|
---
|
|
|
|
### 5.4 Offline and Deterministic Tests
|
|
|
|
**Rule**: All tests must run without network access. Use:
|
|
- UTC timestamps
|
|
- Fixed seeds
|
|
- `CultureInfo.InvariantCulture`
|
|
- Injected `TimeProvider` and `IGuidGenerator`
|
|
|
|
**Rationale**: Network-dependent tests are flaky and break in air-gapped environments. Deterministic tests are reproducible.
|
|
|
|
---
|
|
|
|
## 7 · Architecture and Design Principles
|
|
|
|
### 6.1 SOLID Principles
|
|
|
|
All service and library code must follow:
|
|
|
|
1. **Single Responsibility Principle (SRP)** — One class, one reason to change
|
|
2. **Open/Closed Principle (OCP)** — Open for extension, closed for modification
|
|
3. **Liskov Substitution Principle (LSP)** — Subtypes must be substitutable for base types
|
|
4. **Interface Segregation Principle (ISP)** — Clients should not depend on interfaces they don't use
|
|
5. **Dependency Inversion Principle (DIP)** — Depend on abstractions, not concretions
|
|
|
|
---
|
|
|
|
### 6.2 Directory Ownership
|
|
|
|
**Rule**: Work only inside the module's directory defined by the sprint's "Working directory". Cross-module edits require explicit approval and documentation.
|
|
|
|
**Example**:
|
|
- Sprint scope: `src/Scanner/`
|
|
- Allowed: Edits to `StellaOps.Scanner.*` projects
|
|
- Forbidden: Edits to `src/Concelier/` without explicit approval
|
|
|
|
**Rationale**: Directory boundaries enforce module isolation and prevent unintended coupling.
|
|
|
|
---
|
|
|
|
### 6.3 No Backup Files in Source
|
|
|
|
**Rule**: Add backup patterns to `.gitignore` and remove stray artifacts during code review.
|
|
|
|
```gitignore
|
|
*.Backup.tmp
|
|
*.bak
|
|
*.orig
|
|
*~
|
|
```
|
|
|
|
**Rationale**: Backup files pollute the repository and create confusion.
|
|
|
|
---
|
|
|
|
## 8 · Documentation Standards
|
|
|
|
### 7.1 Required Documentation
|
|
|
|
Every change must update:
|
|
|
|
1. **Module architecture docs** (`docs/modules/<module>/architecture.md`)
|
|
2. **API references** (`docs/api/`)
|
|
3. **Sprint files** (`docs/implplan/SPRINT_*.md`)
|
|
4. **Risk/airgap docs** if applicable (`docs/risk/`, `docs/airgap/`)
|
|
|
|
---
|
|
|
|
### 7.2 Sprint File Discipline
|
|
|
|
**Rule**: Always update task status in `docs/implplan/SPRINT_*.md`:
|
|
- `TODO` → `DOING` → `DONE` / `BLOCKED`
|
|
|
|
Sprint files are the single source of truth for project state.
|
|
|
|
---
|
|
|
|
## 9 · Security and Hardening
|
|
|
|
### 8.1 Input Validation
|
|
|
|
**Rule**: All external inputs (HTTP requests, CLI arguments, file uploads, database queries) must be validated and sanitized.
|
|
|
|
**Required**:
|
|
- Use `[Required]`, `[Range]`, `[RegularExpression]` attributes on DTOs
|
|
- Implement `IValidateOptions<T>` for complex validation
|
|
- Reject unexpected inputs with explicit error messages
|
|
|
|
---
|
|
|
|
### 8.2 Least Privilege
|
|
|
|
**Rule**: Services must run with minimal permissions:
|
|
- Database users: read-only where possible
|
|
- File system: restrict to required directories
|
|
- Network: allowlist remote hosts
|
|
|
|
---
|
|
|
|
### 8.3 Dependency Security
|
|
|
|
**Enforcement**: PRs introducing new dependencies must include:
|
|
- SBOM entry
|
|
- VEX statement if vulnerabilities exist
|
|
- Justification for the dependency
|
|
|
|
---
|
|
|
|
## 10 · Technology Stack Compliance
|
|
|
|
### 9.1 Mandatory Technologies
|
|
|
|
- **Runtime**: .NET 10 (`net10.0`) with latest C# preview features
|
|
- **Frontend**: Angular v17
|
|
- **Database**: PostgreSQL ≥16
|
|
- **Testing**: xUnit, Testcontainers, Moq
|
|
- **NuGet**: Standard feeds configured in `nuget.config`. Always strive to use latest stable verison of dependencies. Never specify versions on nugets on the csproj files. Use src/Directory.Packages.props to specify versions.
|
|
|
|
---
|
|
|
|
### 9.2 Naming Conventions
|
|
|
|
- Module projects: `StellaOps.<ModuleName>`
|
|
- Libraries: `StellaOps.<LibraryName>`
|
|
- Tests: `StellaOps.<ModuleName>.Tests`
|
|
|
|
---
|
|
|
|
## 11 · Enforcement and Compliance
|
|
|
|
### 10.1 Pull Request Requirements
|
|
|
|
All PRs must:
|
|
|
|
1. Pass all unit and integration tests
|
|
2. Pass determinism checks
|
|
3. Include test coverage for new code
|
|
4. Update relevant documentation
|
|
5. Follow sprint file discipline
|
|
6. Pass security scans (no high/critical CVEs)
|
|
|
|
---
|
|
|
|
### 10.2 Rejection Criteria
|
|
|
|
PRs will be **rejected** if they:
|
|
|
|
- Violate any rule in this document
|
|
- Introduce compiler warnings
|
|
- Fail tests
|
|
- Lack required documentation
|
|
- Contain silent stubs or nondeterministic code
|
|
|
|
---
|
|
|
|
### 10.3 Continuous Improvement
|
|
|
|
This document is a **living standard**. Contributors are encouraged to:
|
|
|
|
- Propose improvements via PRs
|
|
- Document new patterns in module-specific `AGENTS.md` files
|
|
- Share lessons learned in sprint retrospectives
|
|
|
|
---
|
|
|
|
## 12 · Attribution and License
|
|
|
|
This Code of Conduct incorporates engineering standards from:
|
|
|
|
- **AGENTS.md** — Autonomous engineering workflows
|
|
- **CLAUDE.md** — Claude Code integration guidance
|
|
- **TESTING_PRACTICES.md** — Testing and evidence standards
|
|
|
|
Copyright © 2025 StellaOps Contributors
|
|
Licensed under [AGPL-3.0-or-later](../../LICENSE)
|
|
|
|
---
|
|
|
|
**Last updated**: 2026-01-15
|
|
**Next review**: 2026-04-15
|